# mtgodot GDExtension — registers Metin2Model / Metin2AnimPlayer, links libgr2. # libgr2 is added at the top-level CMakeLists (vendored under ../libgr2), so here # we just consume the xrender::libgr2 target. # --- godot-cpp (submodule pinned at 101ae38034304346a46ea9ea84ae156d3e860496) --- # The parent gitlink is the source-of-truth; .gitmodules intentionally has no # moving branch. The selected bundle targets Godot 4.7's extension API. set(GODOTCPP_API_VERSION "4.7" CACHE STRING "Target Godot API version" FORCE) add_subdirectory(godot-cpp) # --- vendored native deps: libsodium / libzstd / miniLZO --- # Built from source (pinned submodules + vendored miniLZO) so the same tree # compiles on the Android NDK and iOS SDK, which have no Homebrew. Exposes the # aliases mt3p::sodium / mt3p::zstd / mt3p::minilzo. See docs/THIRD-PARTY.md. add_subdirectory(third_party) # --- mtnet: Metin2 net protocol core (no godot-cpp dep; libsodium only) --- add_library(mtnet STATIC src/net/text_codec.cpp src/net/secure_cipher.cpp src/net/net_stream.cpp src/net/entity_store.cpp src/net/mark_image.cpp src/net/classic/classic_stream.cpp # MT_PROTOCOL=classic (40250) src/net/classic/classic_parser.cpp src/net/classic/classic_session.cpp src/net/classic/classic_cipher.cpp ) target_include_directories(mtnet PUBLIC src/net) target_link_libraries(mtnet PUBLIC mt3p::sodium mt3p::minilzo mt3p::cryptopp) # macOS ships iconv as a system library rather than libc. Linux/glibc and # Windows use the platform implementation without this extra link item. find_library(MT_ICONV_LIBRARY NAMES iconv) if(MT_ICONV_LIBRARY) target_link_libraries(mtnet PUBLIC ${MT_ICONV_LIBRARY}) endif() target_compile_features(mtnet PUBLIC cxx_std_20) # §1.5: non-EUROPE CG_CLIENT_VERSION timestamp, in C __TIMESTAMP__ form # ("Www Mmm dd hh:mm:ss yyyy"); regenerated on each CMake configure. string(TIMESTAMP MT_BUILD_TS "%a %b %d %H:%M:%S %Y") target_compile_definitions(mtnet PRIVATE MT_BUILD_TIMESTAMP="${MT_BUILD_TS}") # --- mtpack: m2dev-fork asset pack reader/writer (libsodium + zstd) --- add_library(mtpack STATIC src/pack/eterpack.cpp src/pack/pack_mount.cpp src/pack/asset_source.cpp ) target_include_directories(mtpack PUBLIC src/pack) target_link_libraries(mtpack PUBLIC mt3p::sodium mt3p::zstd xrender::formats) target_compile_features(mtpack PUBLIC cxx_std_20) # --- mtproto: item_proto / mob_proto reader, 40250 format (CLZO/TEA from port_platform) --- add_library(mtproto STATIC src/proto/proto.cpp) target_include_directories(mtproto PUBLIC src/proto) target_link_libraries(mtproto PUBLIC port_platform) target_compile_features(mtproto PUBLIC cxx_std_20) # --- port_logic + port_platform: 40250 mirror (extension/src/port) and its platform layer # (extension/src/platform), docs/PORT-PLAN.md --- add_subdirectory(src/port) # Host-only CLIs + tests: they run on the build machine, so skip them entirely # when cross-compiling the extension for a device. set(MT_HOST_BUILD FALSE) if(CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME) set(MT_HOST_BUILD TRUE) endif() if(MT_HOST_BUILD) add_executable(packtool tools/packtool.cpp) target_link_libraries(packtool PRIVATE mtpack) # net_probe: connect to an auth server, run the handshake + CG_LOGIN3, report. add_executable(net_probe tools/net_probe.cpp) target_link_libraries(net_probe PRIVATE mtnet) # net_e2e: full auth -> game -> char list -> select -> PHASE_GAME against a # real server; dumps entities / points / inventory. Live integration check. add_executable(net_e2e tools/net_e2e.cpp) target_link_libraries(net_e2e PRIVATE mtnet) # net_classic_e2e: live 40250 classic handshake -> login -> char select -> PHASE_GAME probe. add_executable(net_classic_e2e tools/net_classic_e2e.cpp) target_link_libraries(net_classic_e2e PRIVATE mtnet) endif() if(BUILD_TESTING AND MT_HOST_BUILD) add_executable(net_cipher_test tests/net_cipher_test.cpp) target_link_libraries(net_cipher_test PRIVATE mtnet) add_test(NAME net.cipher_roundtrip COMMAND $) add_executable(net_loopback_test tests/net_loopback_test.cpp) target_link_libraries(net_loopback_test PRIVATE mtnet) add_test(NAME net.loopback_flow COMMAND $) add_executable(net_entity_test tests/net_entity_test.cpp) target_link_libraries(net_entity_test PRIVATE mtnet) add_test(NAME net.entity_store COMMAND $) add_executable(net_state_queue_test tests/net_state_queue_test.cpp) target_link_libraries(net_state_queue_test PRIVATE mtnet) add_test(NAME net.state_queue COMMAND $) # 40250 "classic" backend (MT_PROTOCOL=classic). add_executable(net_classic_wire_test tests/net_classic_wire_test.cpp) target_include_directories(net_classic_wire_test PRIVATE src/net) target_compile_features(net_classic_wire_test PRIVATE cxx_std_20) add_test(NAME net.classic_wire COMMAND $) add_executable(net_classic_stream_test tests/net_classic_stream_test.cpp) target_link_libraries(net_classic_stream_test PRIVATE mtnet) add_test(NAME net.classic_stream COMMAND $) add_executable(net_classic_session_test tests/net_classic_session_test.cpp) target_link_libraries(net_classic_session_test PRIVATE mtnet) add_test(NAME net.classic_session COMMAND $) add_executable(net_classic_cipher_test tests/net_classic_cipher_test.cpp) target_link_libraries(net_classic_cipher_test PRIVATE mtnet) add_test(NAME net.classic_cipher COMMAND $) add_executable(net_classic_encstream_test tests/net_classic_encstream_test.cpp) target_link_libraries(net_classic_encstream_test PRIVATE mtnet) add_test(NAME net.classic_encstream COMMAND $) add_executable(net_classic_mark_test tests/net_classic_mark_test.cpp) target_link_libraries(net_classic_mark_test PRIVATE mtnet) add_test(NAME net.classic_mark COMMAND $) add_executable(net_text_codec_test tests/net_text_codec_test.cpp) target_link_libraries(net_text_codec_test PRIVATE mtnet) add_test(NAME net.text_codec COMMAND $) add_executable(net_bounds_test tests/net_bounds_test.cpp) target_link_libraries(net_bounds_test PRIVATE mtnet) add_test(NAME net.bounds COMMAND $) add_executable(net_mark_test tests/net_mark_test.cpp) target_link_libraries(net_mark_test PRIVATE mtnet mt3p::minilzo) add_test(NAME net.guild_mark COMMAND $) add_executable(pack_roundtrip_test tests/pack_roundtrip_test.cpp) target_link_libraries(pack_roundtrip_test PRIVATE mtpack) add_test(NAME pack.roundtrip COMMAND $) add_executable(proto_test tests/proto_test.cpp) target_link_libraries(proto_test PRIVATE mtproto) # MT_40250_CLIENT comes from src/port/CMakeLists.txt; skipped (77) without the client, failed under # MT_ASSETS_STRICT=1. add_test(NAME proto.item_mob COMMAND $ ${MT_40250_CLIENT}) set_tests_properties(proto.item_mob PROPERTIES SKIP_RETURN_CODE 77) add_executable(proto_item_layout_test tests/proto_item_layout_test.cpp) target_link_libraries(proto_item_layout_test PRIVATE mtproto) add_test(NAME proto.item_layout COMMAND $) # The embedded interpreter, when third_party built it (-DMTGODOT_EMBED_PYTHON=ON). if(TARGET mtpython) add_executable(py_embed_test tests/py_embed_test.cpp) target_link_libraries(py_embed_test PRIVATE mtpython) add_dependencies(py_embed_test mtpython_stdlib) # The stdlib exactly as the host ships it: python27.zip, read through zipimport (批次 2P step 3). add_test(NAME python.embed COMMAND $ "${MT_PYTHON_STDLIB_ZIP}") endif() endif() # --- the extension library --- # macOS/Android: SHARED (Godot dlopen()s it). iOS: STATIC — the platform forbids # loading dynamic libraries, so the archive is linked into the app at export time # (see docs/PLATFORMS.md for the remaining F1 export/sign steps). if(CMAKE_SYSTEM_NAME STREQUAL "iOS") set(MT_LIB_KIND STATIC) set(MT_PLAT_TAG "ios") elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") set(MT_LIB_KIND SHARED) set(MT_PLAT_TAG "android") else() set(MT_LIB_KIND SHARED) set(MT_PLAT_TAG "macos") endif() add_library(mtgodot ${MT_LIB_KIND} src/register_types.cpp src/metin2_model.cpp src/metin2_anim.cpp src/metin2_world.cpp src/terrain_splat.cpp src/static_object.cpp src/tree_placeholder.cpp src/environment_builder.cpp src/water_builder.cpp src/gr2_bridge.cpp src/m2_material.cpp src/dxt.cpp src/asset_io.cpp src/texture_util.cpp src/net/m2_client.cpp src/proto/proto_node.cpp src/pack40250_node.cpp src/python_stdlib.cpp src/python_host_node.cpp ) target_compile_features(mtgodot PRIVATE cxx_std_20) target_link_libraries(mtgodot PRIVATE godot::cpp xrender::libgr2 xrender::formats mtnet mtproto port_platform) # The embedded interpreter's standard library (批次 2P step 3c). python27.zip and its digest are # copied next to project.godot so the exporter packs them into the APK/IPA (the export presets' # include_filter lists them); src/python_stdlib.cpp stages them out of the PCK at runtime. if(TARGET mtpython_stdlib) target_compile_definitions(mtgodot PRIVATE MTGODOT_HAVE_PYTHON) # A target rather than a custom command on the two files: the command that produces them lives in # third_party/, and a Makefile generator only resolves a generated-file dependency inside the # directory that declared it. copy_if_different keeps the no-op build a compare. add_custom_target(mtpython_stdlib_project ALL COMMAND ${CMAKE_COMMAND} -E copy_if_different "${MT_PYTHON_STDLIB_ZIP}" "${CMAKE_SOURCE_DIR}/project/python27.zip" COMMAND ${CMAKE_COMMAND} -E copy_if_different "${MT_PYTHON_STDLIB_SHA}" "${CMAKE_SOURCE_DIR}/project/python27.zip.sha256" COMMENT "Copying python27.zip into project/ (res://)") add_dependencies(mtpython_stdlib_project mtpython_stdlib) add_dependencies(mtgodot mtpython_stdlib_project) endif() # Godot's .gdextension expects, per platform: # project/bin/libmtgodot.macos.template_{debug,release}.dylib # project/bin/libmtgodot.ios.template_{debug,release}.a # project/bin/libmtgodot.android.template_{debug,release}..so set(MT_CFG_TAG "$,template_release,template_debug>") if(CMAKE_SYSTEM_NAME STREQUAL "Android") # godot_arch_name-style suffix; OnePlus 13 = arm64. set(MT_ARCH_SUFFIX ".${CMAKE_ANDROID_ARCH_ABI}") string(REPLACE "arm64-v8a" "arm64" MT_ARCH_SUFFIX "${MT_ARCH_SUFFIX}") else() set(MT_ARCH_SUFFIX "") endif() set_target_properties(mtgodot PROPERTIES PREFIX "lib" OUTPUT_NAME "mtgodot.${MT_PLAT_TAG}.${MT_CFG_TAG}${MT_ARCH_SUFFIX}" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/project/bin" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/project/bin" )