### Ink++ CMake Example Project Setup Source: https://github.com/jbenda/inkcpp/wiki/building This example demonstrates setting up a CMake project to use Ink++. It includes finding the installed Ink++ package, adding an executable, and linking against the Ink++ libraries. Ensure the inkcpp package is found using `find_package`. ```cmake cmake_minimum_required(VERSION 3.16) project(main) find_package(inkcpp CONFIG REQUIRED) add_executable(main main.cpp) set_property(TARGET main PROPERTY CXX_STANDARD 17) target_link_libraries(main inkcpp inkcpp_compiler) ``` -------------------------------- ### Ink++ Example: Compile and Run Story Source: https://github.com/jbenda/inkcpp/wiki/building This C++ code demonstrates how to compile an Ink file into a binary, load it as a story, register external functions, interact with the story by getting lines and choices, and make a choice. Ensure the inkcpp headers are included. ```cpp #include #include #include #include #include #include using namespace ink::runtime; int MyInkFunction( int a, int b ) { return a + b; } int main() { ink::compiler::run("test.ink.json", "test.bin"); // Load ink binary story, generated from the inkCPP compiler story* myInk = story::from_file( "test.bin" ); // Create a new thread runner thread = myInk->new_runner(); // Register external functions (glue automatically generated via templates) thread->bind( "my_ink_function", &MyInkFunction ); // Write to cout while ( thread->can_continue() ) std::cout << thread->getline(); // Iterate choices int id = 0; for ( const choice& c : *thread ) { std::cout << (id++) << ". " << c.text() << std::endl; } std::cin >> id; thread->choose(id); // Write to cout while ( thread->can_continue() ) std::cout << thread->getline(); } ``` -------------------------------- ### Unreal Engine Ink Runtime Setup Source: https://context7.com/jbenda/inkcpp/llms.txt Basic setup instructions for an Ink runtime actor in Unreal Engine. Requires an InkAsset to be assigned. ```cpp // In your level, place an AInkRuntime actor and assign an InkAsset // InkAsset is created by importing .ink or .ink.json files // Set the InkAsset property in the AInkRuntime actor details panel ``` -------------------------------- ### Install inkcpp Unreal Plugin Source: https://github.com/jbenda/inkcpp/blob/master/README.md Steps to build and install the inkcpp Unreal Engine plugin from source. Adapt paths and TargetPlatforms as needed. ```sh mkdir build cd build mkdir plugin mkdir plugin-build cmake -DINKCPP_UNREAL_TARGET_VERSION="5.5" .. cmake --install . --component unreal --prefix .\plugin # create source files for plugin \PATH\TO\UNREAL_ENGINE\Build\BatchFiles\RunUAT.bat BuildPlugin -plugin=GIT_REPO\build\plugin\inkcpp\inkcpp.uplugin -package=GIT_REPO\build\plugin-build\inkcpp -TargetPlatforms=Win64 # compile plugin move plugin-build\inkcpp UE_ENGINE\Engine\Plugins\inkcpp ``` -------------------------------- ### Install Ink++ Python Bindings with Pip Source: https://github.com/jbenda/inkcpp/blob/master/README.md Use this command to install the Python bindings for Ink++ if you have pip available. This is the easiest way to get started. ```sh pip install inkcpp_py ``` -------------------------------- ### Build and Install Ink++ with CMake Source: https://github.com/jbenda/inkcpp/wiki/building Use these commands to build and install Ink++ from source. Specify the installation prefix and component name as needed. For a debug build, set CMAKE_BUILD_TYPE to Debug. ```bash mkdir build mkdir install cd build cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../install cmake --build . --config Release cmake --install . --component ``` -------------------------------- ### Install inkcpp Command Line Tool Source: https://github.com/jbenda/inkcpp/blob/master/inkcpp_cl/CMakeLists.txt Configures the installation rules for the inkcpp command line executable. ```cmake install( TARGETS inkcpp_cl DESTINATION . COMPONENT cl EXCLUDE_FROM_ALL) ``` -------------------------------- ### Start Evaluation Stack Mode Source: https://github.com/jbenda/inkcpp/wiki/InkCPP-Commands Puts the runtime in evaluation mode. Pushed values will now go to the evaluation stack. ```Ink++ START_EVAL ``` -------------------------------- ### Example Ink++ Script with Tags Source: https://github.com/jbenda/inkcpp/blob/master/notes/TagsNotes.md This Ink++ script demonstrates how tags are applied to lines and choices, and how they are processed. ```ink # Tag1 # Tag 2 Some Text # Tag3 * A # Tag 4 * B # Tag 5 - out # Tag6 ``` -------------------------------- ### Build Ink++ from Source with Pip Source: https://github.com/jbenda/inkcpp/blob/master/README.md Clone the repository and install the Python bindings from source using pip. Ensure you use the --recurse-submodules flag to include necessary submodules. ```sh git clone --recurse-submodules https://github.com/JBenda/inkcpp.git pip install . ``` -------------------------------- ### Configure CPACK_ARCHIVE_COMPONENT_INSTALL Source: https://github.com/jbenda/inkcpp/blob/master/CMakeLists.txt Enables component installation for archives. This allows for granular installation of package components. ```cmake set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) set(CPACK_COMPONENTS_GROUPING IGNORE) ``` -------------------------------- ### Start String Mode Source: https://github.com/jbenda/inkcpp/wiki/InkCPP-Commands Puts the runner into "string mode". Any output or value commands will start appending to a new dynamically created string instead of to the game's output. ```Ink++ START_STR ``` -------------------------------- ### Unreal Engine Starting Ink Threads Source: https://context7.com/jbenda/inkcpp/llms.txt Programmatic ways to start and manage Ink++ threads from C++ in Unreal Engine, including starting at specific paths or without immediate execution. ```cpp // Get reference to InkRuntime actor in your level AInkRuntime* Runtime = /* find your runtime actor */; // Start a new thread UInkThread* Thread = Runtime->Start(UMyInkThread::StaticClass()); // Start at specific path UInkThread* Thread2 = Runtime->Start(UMyInkThread::StaticClass(), TEXT("chapter_two")); // Start without immediate execution UInkThread* Thread3 = Runtime->Start(UMyInkThread::StaticClass(), TEXT(""), false); // Start in existing allocated thread UMyInkThread* ExistingThread = NewObject(); Runtime->StartExisting(ExistingThread, TEXT("intro")); ``` -------------------------------- ### Test Python Bindings Source: https://github.com/jbenda/inkcpp/blob/master/README.md Commands to install dependencies, build the package, and run Python-based tests. ```sh python -m pip install build pytest python -m build python -m pip install dist/*.whl --user # if inklecate is not in the same directory / inside Path set INKLECATE enviroment variable export INKLECATE=$PWD/build/inklecate/linux/inklecate # linux set INKLECTATE=%CD%/build/inklecate/windows/inklecate.exe # windows python -m pytest inkcpp_python/tests ``` -------------------------------- ### Start Tag Mode Source: https://github.com/jbenda/inkcpp/wiki/InkCPP-Commands Puts the runner into "tag mode". Any output or value commands will start appending to a new dynamically created string instead of to the game's output. ```Ink++ START_TAG ``` -------------------------------- ### Complete C Example for Ink Story Source: https://context7.com/jbenda/inkcpp/llms.txt Demonstrates loading a story from a binary file, creating globals and a runner, binding external functions (with and without return values), and executing the story loop, including handling choices and tags. ```c #include #include #include #include // External function callback with return value InkValue ink_add(int argc, const InkValue argv[]) { assert(argc == 2); assert(argv[0].type == ValueTypeInt32 && argv[1].type == ValueTypeInt32); InkValue result; result.type = ValueTypeInt32; result.int32_v = argv[0].int32_v + argv[0].int32_v; return result; } // External function callback without return value void ink_log(int argc, const InkValue argv[]) { if (argc > 0 && argv[0].type == ValueTypeString) { printf("LOG: %s\n", argv[0].string_v); } } int main() { // Compile JSON to binary const char* error = NULL; ink_compile_json("story.ink.json", "story.bin", &error); if (error) { printf("Compile error: %s\n", error); return 1; } // Load story HInkStory* story = ink_story_from_file("story.bin"); // Create globals and runner HInkGlobals* globals = ink_story_new_globals(story); HInkRunner* runner = ink_story_new_runner(story, globals); // Bind external functions ink_runner_bind(runner, "add", ink_add, 1); ink_runner_bind_void(runner, "log", ink_log, 0); // Main story loop while (1) { // Print all available content while (ink_runner_can_continue(runner)) { const char* line = ink_runner_get_line(runner); printf("%s", line); // Check tags int numTags = ink_runner_num_tags(runner); for (int i = 0; i < numTags; i++) { printf(" [tag: %s]\n", ink_runner_tag(runner, i)); } } // Check for choices int numChoices = ink_runner_num_choices(runner); if (numChoices == 0) break; // Display choices for (int i = 0; i < numChoices; i++) { const HInkChoice* choice = ink_runner_get_choice(runner, i); printf("%d. %s\n", i, ink_choice_text(choice)); } // Get selection int selection; scanf("%d", &selection); ink_runner_choose(runner, selection); } // Cleanup ink_runner_delete(runner); ink_globals_delete(globals); ink_story_delete(story); return 0; } ``` -------------------------------- ### Ink++ CMake Example Build Commands Source: https://github.com/jbenda/inkcpp/wiki/building Commands to set up and build a project using Ink++ with CMake. This includes generating the build files, compiling the project, and running the executable. Ensure the `CMAKE_PREFIX_PATH` is set correctly. ```bash tree |- test.ink |- main.cpp |- CMakeListst.txt inklecat -j test.ink mkdir build; cd build cmake .. -DCMAKE_PREFIX_PATH= -DCMAKE_BUILD_TYPE=Release cmake --build . --config Release cd .. ./build/main ``` -------------------------------- ### Greetings in Various Languages Source: https://github.com/jbenda/inkcpp/blob/master/inkcpp_test/ink/UTF-8-demo.txt Provides examples of 'Hello world' greetings translated into different languages, showcasing internationalization capabilities. ```text Hello world, Καλημέρα κόσμε, コンニチハ ``` -------------------------------- ### Install Headers for Unreal Engine Source: https://github.com/jbenda/inkcpp/blob/master/shared/CMakeLists.txt Copies public and private header files to the Unreal Engine source directory structure. ```cmake # Unreal installation file(GLOB UNREAL_SOURCE_PUBLIC "public/*") foreach(SRC_FILE IN LISTS UNREAL_SOURCE_PUBLIC) get_filename_component(SRC_FILE "${SRC_FILE}" NAME) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/public/${SRC_FILE}" "${CMAKE_BINARY_DIR}/unreal/inkcpp/Source/shared/Public/${SRC_FILE}" COPYONLY) endforeach() file(GLOB UNREAL_SOURCE_PRIVATE "private/*") foreach(SRC_FILE IN LISTS UNREAL_SOURCE_PRIVATE) get_filename_component(SRC_FILE "${SRC_FILE}" NAME) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/private/${SRC_FILE}" "${CMAKE_BINARY_DIR}/unreal//inkcpp/Source/shared/Private/${SRC_FILE}" COPYONLY) endforeach() ``` -------------------------------- ### Install Python Module Target Source: https://github.com/jbenda/inkcpp/blob/master/inkcpp_python/CMakeLists.txt Specifies the installation destination for the compiled Python module. ```cmake install(TARGETS inkcpp_py DESTINATION . COMPONENT py EXCLUDE_FROM_ALL) ``` -------------------------------- ### Find Doxygen and Configure Documentation Source: https://github.com/jbenda/inkcpp/blob/master/CMakeLists.txt Finds the Doxygen executable and conditionally enables documentation generation. Requires Doxygen to be installed. ```cmake find_package(Doxygen) if(DOXYGEN_FOUND) option(INKCPP_DOC_BlueprintUE "Building doxygen documentation with BlueprintUE visualisation for unreal blueprints. \n (Requires node js)" ON) # ... other doxygen configurations ... ``` -------------------------------- ### Define inkcpp_shared Interface Library Source: https://github.com/jbenda/inkcpp/blob/master/shared/CMakeLists.txt Creates an interface library and sets include directories for build and install interfaces. ```cmake add_library(inkcpp_shared INTERFACE) target_include_directories(inkcpp_shared INTERFACE $ $ $ ) FILE(GLOB PUBLIC_HEADERS "public/*") set_target_properties(inkcpp_shared PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}") ``` -------------------------------- ### Build Project with InkCPP using CMake Source: https://context7.com/jbenda/inkcpp/llms.txt Build your project that uses InkCPP with CMake. This command sequence creates a build directory, configures the CMake project specifying the InkCPP installation path, and then builds the project. ```bash # Build with InkCPP mkdir build && cd build inkcpp_DIR=/path/to/inkcpp-lib cmake .. cmake --build . --config Release ``` -------------------------------- ### Ink Story Example Source: https://github.com/jbenda/inkcpp/wiki/building A simple Ink story demonstrating external function calls and choices. The `my_ink_function` is defined externally and called within the story. Choices are presented to the player. ```ink EXTERNAL my_ink_function(a,b) Hello world! * Hello back! Nice to hear from you! * Bye BTW 3 + 5 = {my_ink_function(3,5)} -> END ``` -------------------------------- ### Return from Tunnel Source: https://github.com/jbenda/inkcpp/wiki/InkCPP-Commands Jumps back to the original starting point of a tunnel. ```InkCPP TUNNEL_RETURN ``` -------------------------------- ### Compact Font Selection Example Source: https://github.com/jbenda/inkcpp/blob/master/inkcpp_test/ink/UTF-8-demo.txt Demonstrates a wide range of characters and symbols available for compact font rendering. This includes uppercase and lowercase alphabets, numbers, and various international characters. ```text ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789 abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi⑀₂ἠḂӥẄɐː⍎אԱა ``` -------------------------------- ### Configure Unreal Engine Plugin Options Source: https://github.com/jbenda/inkcpp/blob/master/unreal/CMakeLists.txt Defines CMake cache variables for Unreal Engine versioning, installation paths, and build options. ```cmake set(INKCPP_UNREAL_TARGET_VERSION "5.6" CACHE STRING "Unreal engine version the plugin should target (e.g: 5.6") set(INKCPP_UNREAL_RunUAT_PATH CACHE FILEPATH "Path to Unreal engine installation RunUAT file. Used to automatcally build the plugin.") option(INKCPP_UNREAL "Prepare sourcefiles for a UE Plugin (this will download " OFF) option(INKCPP_DOC_BlueprintUE "Building doxygen documentation with BlueprintUE visualisation for unreal blueprints. (Requires node js)" ON) set(INKCPP_UNREAL_TARGET_PLATFORM "Win64" CACHE STRING "Target platform for the UE Plugin one of Win64, Mac, Linux") set_property(CACHE INKCPP_UNREAL_TARGET_PLATFORM PROPERTY STRINGS "Win64" "Mac" "Linux") ``` -------------------------------- ### Integrate InkCPP into CMake Project Source: https://context7.com/jbenda/inkcpp/llms.txt Incorporate InkCPP into your CMake build system. This example shows how to find the InkCPP package and link its runtime and optional compiler libraries to your executable. ```cmake cmake_minimum_required(VERSION 3.16) project(MyInkGame) # Find InkCPP package find_package(inkcpp CONFIG REQUIRED) # Create executable add_executable(mygame main.cpp) # Link InkCPP libraries target_link_libraries(mygame inkcpp # Runtime library inkcpp_compiler # Compiler (optional, for runtime compilation) ) # For C bindings instead: # target_link_libraries(mygame inkcpp_c) ``` -------------------------------- ### Acquire Value by Type Source: https://github.com/jbenda/inkcpp/blob/master/notes/OperationNotes.md Values are acquired using `get()`, which allows for type changes without breaking existing code. ```cpp get() ``` -------------------------------- ### Testing inkcpp with Predefined Choices and Snapshots Source: https://github.com/jbenda/inkcpp/blob/master/README.md Demonstrates how to use predefined choices and create/load snapshots for testing inkcpp stories via standard input. ```sh echo 1 2 1 | inkpp-cl -p story.(ink|json|bin) ``` ```sh echo 1 2 -1 | inkcpp-cl -p story.ink ``` ```sh echo 1 | inkcpp-cl -p story.snap story.ink ``` -------------------------------- ### Create and Load Snapshot for Single Runner Source: https://github.com/jbenda/inkcpp/wiki/Using-the-InkCPP-Runtime Use this for a simple case with one runner per global state. Functions must be rebound after loading. ```cpp runner myRunner = myInk->new_runner(); snapshot* snap = myRunner->create_snapshot(); runner myRunnerAgain = myInk->new_runner_from_snapshot(*snap); // bind functions: myRunnerAgain->bind("add", [](int a, int b)->int{ return a + b; }) ``` -------------------------------- ### InkCPP Instruction Structure Source: https://github.com/jbenda/inkcpp/wiki/InkBIN-File-Structure The binary layout of an instruction, starting with a command index and flag. ```text LIST OF: ubyte CommandIndex; ubyte CommandFlag; (optional arguments depending on command) ``` -------------------------------- ### Initialize and Run Ink Story Source: https://github.com/jbenda/inkcpp/blob/master/README.md Demonstrates loading a compiled story, binding external functions, and iterating through story content and choices. ```cpp #include #include #include #include using namespace ink::runtime; int MyInkFunction(int a, int b) { return a + b; } ... // Load ink binary story, generated from the inkCPP compiler std::unique_ptr myInk{story::from_file("test.bin")}; // Create a new thread runner thread = myInk->new_runner(); // Register external functions (glue automatically generated via templates) thread->bind("my_ink_function", &MyInkFunction); // Write to cout while(thread->can_continue()) std::cout << thread->getline(); // Iterate choices for(const choice& c : *thread) { std::cout << "* " << c.text() << std::endl; } // Pick the first choice thread->choose(0); ``` -------------------------------- ### Building the Inkcpp Unreal Plugin Source: https://github.com/jbenda/inkcpp/wiki/Unreal Step-by-step instructions for building and integrating the inkcpp plugin into an Unreal Engine project. ```APIDOC ## Building the Inkcpp Unreal Plugin ### Description Follow these steps to build the inkcpp plugin for Unreal Engine and integrate it into your project. ### Steps 1. Create a new Unreal project or use an existing one, then close the Unreal Editor. 2. Note the absolute path to your Unreal project (e.g., `D:\Dokumente\Unreal Projects\InkDemo`). 3. Clone the inkcpp repository: `git clone https://github.com/JBenda/inkcpp.git` 4. Navigate into the cloned repository: `cd inkcpp` 5. Create a build directory: `mkdir build` 6. Create a plugin directory: `mkdir plugin` 7. Navigate into the build directory: `cd build` 8. Configure the build using CMake, specifying the installation prefix: `cmake -DCMAKE_INSTALL_PREFIX=../plugin ..` 9. Install the plugin components: `cmake --install . --component unreal` 10. Compile the plugin for your Unreal project: `\PATH\TO\UNREAL_ENGINE\Build\BatchFiles\RunUAT.bat BuildPlugin -plugin="PATH\TO\GIT\REPO\plugin\inkcpp\inkcpp.uplugin" -package="\PATH\TO\UNREAL_PROJECT\Plugins\inkcpp" -TargetPlatforms=Win64` *(Refer to `imgs/UnrealPath.png` for a visual guide on directory structure.)* 11. Copy the contents of `InkUnrealExample` from the inkcpp repository to `PATH\TO\UNREAL_PROJECT\Content`. 12. Start your Unreal project. 13. In the Content Drawer, select the `NewMap` level. 14. Begin the level. Use keys 1, 2, 3, and 4 to select corresponding choices. ### Usage Notes * The main world contains an `MyInkRuntime` instance that uses an `InkAsset` for the story. * `unreal_example` demonstrates various interactions between the Unreal Engine and ink. * `TheInterceptor` is a larger example story. * To create an `InkAsset`, import a `.ink` file or an inklecate-compiled `.json` file (JSON import priority may decrease in the future). ``` -------------------------------- ### Get Command Argument Count Source: https://github.com/jbenda/inkcpp/blob/master/notes/OperationNotes.md Determine the number of arguments required for a command using `command_num_args`. ```cpp size_t command_num_args(Command) ``` -------------------------------- ### Loading a Story from File Source: https://context7.com/jbenda/inkcpp/llms.txt Demonstrates how to load a compiled binary Ink story file and create a new story object for spawning runners. ```APIDOC ## Loading a Story from File ### Description Load a compiled binary story file and create a new story object for spawning runners. ### Method N/A (This is a code example for library usage) ### Endpoint N/A ### Parameters N/A ### Request Example ```cpp #include #include #include #include using namespace ink::runtime; int main() { // Load ink binary story from file std::unique_ptr myStory{story::from_file("story.bin")}; // Create a new runner (execution thread) runner thread = myStory->new_runner(); return 0; } ``` ### Response N/A (This is a code example for library usage) ### Response Example N/A ``` -------------------------------- ### Configure and Run Tests with CMake Source: https://github.com/jbenda/inkcpp/blob/master/README.md Commands to build the project with testing enabled and execute the test suite. ```sh mkdir build; cd build cmake .. -DCMAKE_BUILD_TYPE=Release -DINKCPP_TEST=ON -DINKCPP_INKLECATE=OS cmake --build . --config Release ctest -C Release ``` -------------------------------- ### Inkcpp Command Encoding Source: https://github.com/jbenda/inkcpp/wiki/InkCPP-Commands All commands in inkcpp are encoded in binary. Each command starts with two bytes: Command Type and Command Flag. ```APIDOC ## Inkcpp Command Encoding Each command begins with two bytes: * **Command Type**: An unsigned char indicating the command. * **Command Flag**: An unsigned char for modifying command behavior (often zero). Data types used: * **uint**: 4-byte unsigned integer * **int**: 4-byte signed integer * **float**: IEEE-754 encoded 4-byte floating point number * **byte**: 1-byte signed number * **ubyte**: 1-byte unsigned number **Note:** There is no handling for endianness in compiled data. Ensure matching endianness for compilation and execution. ``` -------------------------------- ### START_CONTAINER_MARKER Command Source: https://github.com/jbenda/inkcpp/wiki/InkCPP-Commands Signals the entry into a container with a specific ID. Use CONTAINER_MARKER_TRACK_VISITS to enable visit tracking for the container. ```ink START_CONTAINER_MARKER uint containerId ``` -------------------------------- ### Box Drawing Alignment Tests Source: https://github.com/jbenda/inkcpp/blob/master/inkcpp_test/ink/UTF-8-demo.txt Illustrates the use of box drawing characters for creating visual layouts and alignments. This example includes various combinations of lines and corners. ```text █ ▉ ╔══╦══╗┌──┬──┐╭──┬──╮╭──┬──╮┏━━┳━━┓┎┒┏┑ ╷╻ ┏┯┓ ┌┰┐▊ ╱╲╱╲╳╳╳ ║┌─╨─┐║│╔═╧═╗││╒═╪═╕││╓─╁─╖│┃┌─╂─┐┃┗╃╄┙╶┼╴╺╋╸┠┼┨ ┝╋┥▋ ╲╱╲╱╳╳╳ ║│╲ ╱│║│║ ║│││ │ │││║ ┃ ║│┃│ ╽ │┃┍╅╆┓ ╵╹ ┗┷┛ └┸┘▌ ╱╲╱╲╳╳╳ ╠╡ ╳ ╞╣├╢ ╟┤├┼─┼─┼┤├╫─╂─╫┤┣┿╾┼╼┿┫┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ ║│╱ ╲│║│║ ║│││ │ │││║ ┃ ║│┃│ ╽ │┃░░▒▒▓▓██ ┊┆ ╎ ╏┇ ┋ ▎ ║└─╥─┘║│╚═╤═╝││╘═╪═╛││╙─╀─╜│┃└─╂─┘┃░░▒▒▓▓██ ┊┆ ╎ ╏┇ ┋ ▏ ╚══╩══╝└──┴──┘╰──┴──╯╰──┴──╯┗━━┻━━┛▗▄▖▛▀▜ └╌╌┘ ╎ ┗╍╍┛ ┋▁▂▃▄▅▆▇█ ▀▘▙▄▟ ``` -------------------------------- ### Compile and Run Ink Story with inkcpp-cl Source: https://github.com/jbenda/inkcpp/blob/master/README.md Use the inkcpp command-line tool to compile and run Ink stories. Ensure 'inklecate.exe' is in your PATH or the same directory for '.ink' files. ```sh inkcpp_cl.exe -p myfile.json ``` ```sh inkcpp-cl -p story.json ``` ```sh inkcpp-cl -p story.ink ``` -------------------------------- ### Container Instruction Map in InkBIN Source: https://github.com/jbenda/inkcpp/wiki/InkBIN-File-Structure Maps container indices to their start and end offsets within the instruction data. It begins with the maximum container index and is terminated by a four-byte zero. ```assembly uint maxContainerIndex; LIST OF SIZE (maxContainerIndex * 2) uint instructionOffset; uint containerIndex; 0x00000000 ``` -------------------------------- ### Unreal Plugin Build Logic Source: https://github.com/jbenda/inkcpp/blob/master/unreal/CMakeLists.txt Handles conditional logic for downloading inklecate binaries, configuring plugin files, and defining the custom build target. ```cmake if (INKCPP_UNREAL) include(FetchContent) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/inkcpp/inkcpp.uplugin.in" "${CMAKE_CURRENT_BINARY_DIR}/inkcpp/inkcpp.uplugin") # download inklecate for unreal plugin FetchContent_MakeAvailable(inklecate_mac inklecate_windows inklecate_linux) set(FETCHCONTENT_QUIET OFF) set(CMAKE_TLS_VERIFY true) if(NOT inklecate_windows_SOURCE_DIR) message(WARNING "failed to download inklecate for windows, " "the unreal plugin will be unable use a .ink file as asset directly") else() set(INKLECATE_CMD_WIN "Source/ThirdParty/inklecate/windows/inklecate.exe") file(COPY "${CMAKE_BINARY_DIR}/inklecate/windows" DESTINATION "inkcpp/Source/ThirdParty/inklecate/") endif() if(NOT inklecate_mac_SOURCE_DIR) message(WARNING "failed to download inklecate for MacOS, " "the unreal plugin will be unable use a .ink file as asset directly") else() set(INKLECATE_CMD_MAC "Source/ThirdParty/inklecate/mac/inklecate") file(COPY "${CMAKE_BINARY_DIR}/inklecate/mac" DESTINATION "inkcpp/Source/ThirdParty/inklecate/") endif() if(NOT inklecate_linux_SOURCE_DIR) message(WARNING "failed to download inklecate for linux, " "the unreal plugin will be unable use a .ink file as asset directly") else() set(INKLECATE_CMD_LINUX "Source/ThirdParty/inklecate/linux/inklecate") file(COPY "${CMAKE_BINARY_DIR}/inklecate/linux" DESTINATION "inkcpp/Source/ThirdParty/inklecate/") endif() configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/inkcpp/Source/inkcpp_editor/Private/inklecate_cmd.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/inkcpp/Source/inkcpp_editor/Private/inklecate_cmd.cpp" ) file(GLOB_RECURSE SOURCE_FILES LIST_DIRECTORIES TRUE RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/inkcpp/*") list(FILTER SOURCE_FILES EXCLUDE REGEX ".*\.in$") foreach(SRC_FILE IN LISTS SOURCE_FILES) if (NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}" "${CMAKE_CURRENT_BINARY_DIR}/${SRC_FILE}" COPYONLY) endif() endforeach() install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/inkcpp/" DESTINATION "inkcpp" COMPONENT unreal EXCLUDE_FROM_ALL) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Plugins/inkcpp/") if ((NOT DEFINED INKCPP_UNREAL_RunUAT_PATH) OR (NOT "${INKCPP_UNREAL_RunUAT_PATH}" STREQUAL "")) if (NOT IS_READABLE "${INKCPP_UNREAL_RunUAT_PATH}") message(WARNING "Unable to find RunUAT script at >${INKCPP_UNREAL_RunUAT_PATH}<, will not be able to build target `unreal` set the filepath with the variable INKCPP_UNREAL_RunUAT_PATH") endif() else() message(WARNING, "To directly build the plugin with `cmake --build . --target unreal` please set INKCPP_UNREAL_RunUAT_PATH to point to unreals RunUAT script.") endif() add_custom_target(unreal "${INKCPP_UNREAL_RunUAT_PATH}" BuildPlugin "-plugin=${CMAKE_CURRENT_BINARY_DIR}/inkcpp/inkcpp.uplugin" "-package=${CMAKE_CURRENT_BINARY_DIR}/Plugins/inkcpp" "-TargetPlatforms=${INKCPP_UNREAL_TARGET_PLATFORM}" COMMENT "Compile UE Plugin.") install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Plugins/inkcpp/" DESTINATION "inkcpp" COMPONENT unreal_plugin EXCLUDE_FROM_ALL PATTERN "Intermediate/*" EXCLUDE) # TODO: update documenation endif() ``` -------------------------------- ### Loading a Story from Binary Data Source: https://context7.com/jbenda/inkcpp/llms.txt Explains how to create a story object from pre-loaded binary data in memory, suitable for embedded systems. ```APIDOC ## Loading a Story from Binary Data ### Description Create a story object from pre-loaded binary data in memory, useful for embedded scenarios. ### Method N/A (This is a code example for library usage) ### Endpoint N/A ### Parameters N/A ### Request Example ```cpp #include using namespace ink::runtime; // Binary data loaded from custom source const unsigned char* storyData = /* your binary data */; size_t dataLength = /* data length */; // Create story from binary buffer (will free buffer on destroy by default) story* myStory = story::from_binary(storyData, dataLength, true); // Set freeOnDestroy to false if you manage the memory yourself story* myStory2 = story::from_binary(storyData, dataLength, false); ``` ### Response N/A (This is a code example for library usage) ### Response Example N/A ``` -------------------------------- ### Manipulate Ink List Variables in C++ Source: https://context7.com/jbenda/inkcpp/llms.txt Demonstrates how to get, check, add, remove, and iterate over flags within Ink list variables. Ensure the 'inventory' list is defined in your Ink story. ```cpp #include #include #include #include using namespace ink::runtime; std::unique_ptr myStory{story::from_file("story.bin")}; globals store = myStory->new_globals(); runner thread = myStory->new_runner(store); // Get list variable if (auto inventory = store->get("inventory")) { list& inv = *inventory; // Check if list contains a flag if (inv.contains("sword")) { std::cout << "Has sword!" << std::endl; } // Add and remove flags inv.add("shield"); inv.remove("old_map"); // Add flag with explicit list name inv.add("Weapons.axe"); // Iterate over all flags in list for (const auto& flag : inv) { std::cout << flag.list_name << "." << flag.flag_name << std::endl; } // Iterate flags from specific list only for (auto it = inv.begin("Weapons"); it != inv.end(); ++it) { std::cout << "Weapon: " << (*it).flag_name << std::endl; } // Save modified list back store->set("inventory", inv); } ``` -------------------------------- ### Container Hash Map in InkBIN Source: https://github.com/jbenda/inkcpp/wiki/InkBIN-File-Structure Maps the hashes of named container fully qualified names to their starting instruction offsets. This is used for jumping to specific containers from code. The map is terminated by a four-byte zero. ```assembly LIST OF uint containerNameHash; uint instructionOffset; 0x00000000 ``` -------------------------------- ### Compile InkJSON to InkBIN using Command Line Source: https://github.com/jbenda/inkcpp/wiki/InkCPP-Compiler Compile an InkJSON file to InkBIN format using the `inkcpp_cl` executable. If `inklecate.exe` is available, you can also directly provide an Ink file, which will be preprocessed. ```bash inkcpp_cl -o output.bin myInkFile.json ``` ```bash inkcpp_cl -o output.bin myInkFile.ink ``` -------------------------------- ### Navigate Ink Story Paths Programmatically in C++ Source: https://context7.com/jbenda/inkcpp/llms.txt Demonstrates how to use the `move_to` function to jump to a specific knot or path within an Ink story using a hash string. Checks for the success of the navigation. ```cpp #include #include #include using namespace ink::runtime; std::unique_ptr myStory{story::from_file("story.bin")}; runner thread = myStory->new_runner(); // Move to a named knot using hash bool success = thread->move_to(ink::hash_string("chapter_two")); if (!success) { std::cerr << "Path not found!" << std::endl; } // Get current knot hash for comparison ink::hash_t currentKnot = thread->get_current_knot(); if (currentKnot == ink::hash_string("chapter_two")) { std::cout << "Now in chapter two" << std::endl; } ``` -------------------------------- ### Handling Choices Source: https://context7.com/jbenda/inkcpp/llms.txt Provides guidance on how to present choices to the user and select one to continue the story flow. ```APIDOC ## Handling Choices ### Description Present choices to the user and select one to continue the story. ### Method N/A (This is a code example for library usage) ### Endpoint N/A ### Parameters N/A ### Request Example ```cpp #include #include #include #include using namespace ink::runtime; std::unique_ptr myStory{story::from_file("story.bin")}; runner thread = myStory->new_runner(); while (true) { // Print story content while (thread->can_continue()) { std::cout << thread->getline(); } // Check for choices if (!thread->has_choices()) { break; // Story ended } // Display choices using iterator int index = 0; for (const choice& c : *thread) { std::cout << index << ". " << c.text() << std::endl; index++; } // Alternative: access choices by index size_t numChoices = thread->num_choices(); for (size_t i = 0; i < numChoices; i++) { const choice* c = thread->get_choice(i); std::cout << i << ". " << c->text() << std::endl; } // Get user selection and choose int selection; std::cin >> selection; thread->choose(selection); } ``` ### Response N/A (This is a code example for library usage) ### Response Example N/A ``` -------------------------------- ### Load Ink Story from File (C++) Source: https://context7.com/jbenda/inkcpp/llms.txt Loads a compiled binary Ink story file and creates a story object. Use this for stories stored on disk. ```cpp #include #include #include #include using namespace ink::runtime; int main() { // Load ink binary story from file std::unique_ptr myStory{story::from_file("story.bin")}; // Create a new runner (execution thread) runner thread = myStory->new_runner(); return 0; } ``` -------------------------------- ### Reconstruct Multiple Runners from Snapshot Source: https://github.com/jbenda/inkcpp/wiki/Using-the-InkCPP-Runtime For multiple runners sharing global variables, reconstruct them step-by-step. Functions must be rebound after loading. ```cpp global vars = ...; runner* runners = ...; snapshot* snap = vars.create_snapshot(); global new_vars = myInk->new_globals_from_snapshot(*snap); runner* new_runners = new runners[snap.num_runners()]; for(size_t i = 0; i < snap.num_runners(); ++i) { new_runners[i] = myInk->new_runner_from_snapshot(*snap, new_vars, i); // bind functions } ``` -------------------------------- ### Save and Load Ink Story Snapshots in C++ Source: https://context7.com/jbenda/inkcpp/llms.txt Shows how to save the current state of an Ink story, including global variables and all runners, to a file or binary data, and how to restore it later. Ensure 'savegame.snap' exists for loading. ```cpp #include #include #include #include using namespace ink::runtime; // Save game state void saveGame(runner& thread) { // Create snapshot (includes globals and all connected runners) snapshot* snap = thread->create_snapshot(); // Save to file snap->write_to_file("savegame.snap"); // Or get binary data for custom storage const unsigned char* data = snap->get_data(); size_t length = snap->get_data_len(); // ... store data somewhere ... delete snap; } // Load game state void loadGame(story* myStory) { // Load from file snapshot* snap = snapshot::from_file("savegame.snap"); // Or from binary data // snapshot* snap = snapshot::from_binary(data, length, true); // Get number of runners in snapshot size_t numRunners = snap->num_runners(); // Reconstruct globals globals store = myStory->new_globals_from_snapshot(*snap); // Reconstruct runner(s) runner thread = myStory->new_runner_from_snapshot(*snap, store, 0); // For multiple runners, specify runner_id // runner thread2 = myStory->new_runner_from_snapshot(*snap, store, 1); delete snap; } ``` -------------------------------- ### Load Ink Story from Binary Source: https://github.com/jbenda/inkcpp/wiki/Using-the-InkCPP-Runtime Loads an Ink story from a compiled InkBin file. Remember to delete the story object when it's no longer needed to free memory. ```cpp // Load ink story from an InkBin file story* myInk = story::from_file("test.bin"); ... // delete story when you're done delete myInk; myInk = nullptr; ``` -------------------------------- ### Python API: Basic Story Loading and Execution Source: https://context7.com/jbenda/inkcpp/llms.txt Load an Ink story from a compiled binary file and run it using the Python bindings. This includes handling story content, tags, and player choices. ```python import inkcpp_py # Compile JSON to binary (if needed) inkcpp_py.compile_json("story.ink.json", "story.bin") # Load story story = inkcpp_py.Story.from_file("story.bin") # Create runner runner = story.new_runner() # Main loop while True: # Print content while runner.can_continue(): line = runner.getline() print(line, end="") # Access tags for tag in runner.tags(): print(f" [tag: {tag}]") # Handle choices if runner.has_choices(): for i, choice in enumerate(runner): print(f"{i + 1}. {choice.text()}") # Choice tags for tag in choice.tags(): print(f" [{tag}]") selection = int(input("Choose: ")) - 1 runner.choose(selection) else: break print("Story complete!") ``` -------------------------------- ### Compile InkJSON to InkBIN using C++ API Source: https://github.com/jbenda/inkcpp/wiki/InkCPP-Compiler Use the `ink::compiler::run` function to compile JSON from standard input to a binary file, from a JSON file to standard output, or from a JSON file to a binary file, optionally recording compilation errors. ```cpp #include int main() { // Read json from stdin and save the binary into out.bin ink::compiler::run(std::cin, "out.bin"); // Read json from in.json and write the binary into standard out ink::compiler::run("in.json", std::cout); // Compile in.json to out.bin and record any compilation errors ink::compiler::compilation_results errors; ink::compiler::run("in.json", "out.bin"); } ``` -------------------------------- ### Set CPACK_RESOURCE_FILE_LICENSE Source: https://github.com/jbenda/inkcpp/blob/master/CMakeLists.txt Sets the license file for packaging. Ensure the LICENSE.txt file exists in the source directory. ```cmake set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") ``` -------------------------------- ### Run Story Content Line by Line (C++) Source: https://context7.com/jbenda/inkcpp/llms.txt Executes the Ink story and retrieves text output incrementally. Continues execution as long as the runner can proceed. ```cpp #include #include #include using namespace ink::runtime; std::unique_ptr myStory{story::from_file("story.bin")}; runner thread = myStory->new_runner(); // Execute until we can't continue (hit a choice or end) while (thread->can_continue()) { // Get next line of output std::string line = thread->getline(); std::cout << line; } // Alternative: get all text until next choice or end std::string allText = thread->getall(); ``` -------------------------------- ### Choice Commands Source: https://github.com/jbenda/inkcpp/wiki/InkCPP-Commands Instructions for creating choices within the story flow, including conditional logic and content management. ```APIDOC ## CHOICE ### Description Creates a new choice that leads to the given offset in the instruction data. ### Parameters #### Path Parameters - **destinationInstruction** (uint) - Required - The offset in the instruction data. ``` -------------------------------- ### Play Ink File in Command Line Source: https://github.com/jbenda/inkcpp/wiki/InkCPP-Compiler Use the `-p` flag with `inkcpp_cl` to play an Ink file directly in the command line. Choices can be selected by their index. ```bash inkcpp_cl -o -p output.bin myInkFile.ink ``` -------------------------------- ### Command Line Tool (inkcpp_cl) Source: https://context7.com/jbenda/inkcpp/llms.txt Executing and managing Ink stories via the command line interface. ```APIDOC ## inkcpp_cl Usage ### Description Command line utility for playing, compiling, and snapshotting Ink stories. ### Commands - **-p [file]**: Play a compiled JSON, binary, or .ink story. - **[file]**: Compile an ink file to binary format. - **-1 (choice)**: Create a snapshot during play. ``` -------------------------------- ### Configure NodeJS for BlueprintUE Visualization Source: https://github.com/jbenda/inkcpp/blob/master/CMakeLists.txt Configures the path to the NodeJS executable if BlueprintUE visualization is enabled. NodeJS is required for this feature. ```cmake if(INKCPP_DOC_BlueprintUE) set(NODEJS_HINT "None" CACHE PATH "Directory of NodeJS executable to use for generating BlueprintUE visualisation.") if(IS_DIRECTORY "${NODEJS_HINT}") find_program( NODEJS_PATH node HINTS ${NODEJS_HINT} DOC "NodeJS executable to build BlueprintUE visualisation in documentation.") else() find_program(NODEJS_PATH node DOC "NodeJS executable to build BlueprintUE visualisation in documentation.") endif(IS_DIRECTORY "${NODEJS_HINT}") if("${NODEJS_PATH}" STREQUAL "NODEJS-NOTFOUND") message( SEND_ERROR "NodeJS is required to build BlueprintUE visualisation. \n But it was not found. Install NodeJS set NODEJS_HINT \n to a directory containing the executable. \n Or disable building the visualisation with setting INKCPP_DOC_BlueprintUE=OFF") endif("${NODEJS_PATH}" STREQUAL "NODEJS-NOTFOUND") endif(INKCPP_DOC_BlueprintUE) ``` -------------------------------- ### Python Story Navigation Source: https://context7.com/jbenda/inkcpp/llms.txt Demonstrates navigating Ink++ stories using Python. Includes moving to specific knots and checking the current location. ```python import inkcpp_py story = inkcpp_py.Story.from_file("story.bin") runner = story.new_runner() # Move to a specific knot success = runner.move_to("chapter_two") if not success: print("Path not found!") # Get current knot hash current = runner.current_knot() chapter_two_hash = inkcpp_py.hash_string("chapter_two") if current == chapter_two_hash: print("Now in chapter two") # Continue execution while runner.can_continue(): print(runner.getline(), end="") ```