Merge pull request #190 from limbonaut/dev-setup

Improved dev setup for GDExtension
This commit is contained in:
Serhii Snitsaruk 2024-08-10 11:06:43 +02:00 committed by GitHub
commit 02af29f2fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 337 additions and 278 deletions

View File

@ -15,7 +15,7 @@ runs:
echo "GDEXTENSION_VERSION=${GDEXTENSION_VERSION}" >> "$GITHUB_ENV"
cd ../limboai
cd ..
echo "LIMBOAI_VERSION=$( (git describe --tags --exact-match HEAD || git rev-parse --short HEAD) | sed 's/\(.*\)-\(.*\)/\1.\2/g' )" >> "$GITHUB_ENV"
- name: Set NAME_PREFIX

View File

@ -167,6 +167,12 @@ jobs:
BIN: liblimboai.${{matrix.opts.platform}}.${{matrix.opts.target}}.${{matrix.opts.arch}}
steps:
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
fetch-tags: true
ref: ${{ inputs.limboai-ref }}
- name: Clone godot-cpp
uses: actions/checkout@v4
with:
@ -175,15 +181,8 @@ jobs:
path: godot-cpp
ref: ${{ inputs.godot-cpp-ref }}
- name: Clone LimboAI module
uses: actions/checkout@v4
with:
path: limboai
fetch-tags: true
ref: ${{ inputs.limboai-ref }}
# Inits GDEXTENSION_VERSION, LIMBOAI_VERSION and NAME_PREFIX environment variables.
- uses: ./limboai/.github/actions/init-version-gdext
- uses: ./.github/actions/init-version-gdext
- name: Output NAME_PREFIX
id: output-name-prefix
@ -191,7 +190,7 @@ jobs:
- name: Setup Linux toolchain
if: matrix.opts.platform == 'linux'
uses: ./limboai/.github/actions/setup-linux-toolchain
uses: ./.github/actions/setup-linux-toolchain
with:
arch: ${{matrix.opts.arch}}
@ -257,15 +256,6 @@ jobs:
${{env.BIN}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}
${{env.BIN}}-${{inputs.godot-cpp-ref}}
- name: Setup project structure for GDExtension
shell: bash
run: |
bash ./limboai/gdextension/setup_gdextension.sh --copy-all
echo "---"
ls -l
echo "---"
ls -l -R ./demo/
- name: Compilation
shell: bash
env:
@ -279,9 +269,9 @@ jobs:
run: |
mkdir out
mv demo/addons/ out/
cp limboai/{README,LICENSE,LOGO_LICENSE}.md out/addons/limboai/
cp -R limboai/demo/demo/ out/demo/
cp limboai/demo/LICENSE_ASSETS.md out/demo/
cp {README,LICENSE,LOGO_LICENSE}.md out/addons/limboai/
cp -R demo/demo/ out/demo/
cp demo/LICENSE_ASSETS.md out/demo/
rm -f out/addons/limboai/bin/*.{exp,lib,pdb}
echo "${LIMBOAI_VERSION}" > out/addons/limboai/version.txt
echo "---"

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
demo/addons/
demo/script_templates/
icons/*.import
godot-cpp
# Godot auto generated files
*.gen.*

View File

@ -93,13 +93,19 @@ LimboAI can be used as either a C++ module or as a GDExtension shared library. G
### Compiling from source
>**🛈 For GDExtension:** Refer to comments in [setup_gdextension.sh](./gdextension/setup_gdextension.sh) file.
- Download the Godot Engine source code and put this module source into the `modules/limboai` directory.
- Consult the Godot Engine documentation for instructions on [how to build from source code](https://docs.godotengine.org/en/stable/contributing/development/compiling/index.html).
- If you plan to export a game utilizing the LimboAI module, you'll also need to build export templates.
- To execute unit tests, compile the engine with `tests=yes` and run it with `--test --tc="*[LimboAI]*"`.
#### For GDExtension
- You'll need SCons build tool and a C++ compiler. See also [Compiling](https://docs.godotengine.org/en/stable/contributing/development/compiling/index.html).
- Run `scons target=editor` to build the plugin library for your current platform.
- SCons will automatically clone the godot-cpp/ repository if it doesn't already exist in the `limboai/godot-cpp` directory.
- By default, built targets are placed in the demo project: `demo/addons/limboai/bin/`
- Check `scons -h` for other options and targets.
## Using the plugin
- [Online Documentation](https://limboai.readthedocs.io/en/latest/index.html)

160
SConstruct Normal file
View File

@ -0,0 +1,160 @@
#!/usr/bin/env python
"""
This is SConstruct file for building GDExtension variant using SCons build system.
For module variant, see SCsub file.
Use --project=DIR to customize output path for built targets.
- Built targets are placed into "DIR/addons/limboai/bin".
- For example: scons --project="../my_project"
- built targets will be placed into "../my_project/addons/limboai/bin".
- If not specified, built targets are put into the demo/ project.
"""
import os
import sys
import subprocess
from limboai_version import generate_module_version_header, godot_cpp_ref
sys.path.append("gdextension")
from update_icon_entries import update_icon_entries
from fix_icon_imports import fix_icon_imports
# Check if godot-cpp/ exists
if not os.path.exists("godot-cpp"):
print("Directory godot-cpp/ not found. Cloning repository...")
result = subprocess.run(
["git", "clone", "-b", godot_cpp_ref, "https://github.com/godotengine/godot-cpp.git"],
check=True,
# capture_output=True
)
if result.returncode != 0:
print("Error: Cloning godot-cpp repository failed.")
Exit(1)
print("Finished cloning godot-cpp repository.")
AddOption(
"--project",
dest="project",
type="string",
nargs=1,
action="store",
metavar="DIR",
default="demo",
help="Specify project directory",
)
help_text = """
Options:
--project=DIR Specify project directory (default: "demo");
built targets will be placed in DIR/addons/limboai/bin
"""
Help(help_text)
project_dir = GetOption("project")
if not os.path.isdir(project_dir):
print("Project directory not found: " + project_dir)
Exit(2)
# Parse LimboAI-specific variables.
vars = Variables()
vars.AddVariables(
BoolVariable("deploy_manifest", help="Deploy limboai.gdextension into PROJECT/addons/limboai/bin", default=True),
BoolVariable("deploy_icons", help="Deploy icons into PROJECT/addons/limboai/icons", default=True),
)
env = Environment(tools=["default"], PLATFORM="", variables=vars)
Help(vars.GenerateHelpText(env))
# Read LimboAI-specific variables.
deploy_manifest = env["deploy_manifest"]
deploy_icons = env["deploy_icons"]
# Remove processed variables from ARGUMENTS to avoid godot-cpp warnings.
for o in vars.options:
if o.key in ARGUMENTS:
del ARGUMENTS[o.key]
# For reference:
# - CCFLAGS are compilation flags shared between C and C++
# - CFLAGS are for C-specific compilation flags
# - CXXFLAGS are for C++-specific compilation flags
# - CPPFLAGS are for pre-processor flags
# - CPPDEFINES are for pre-processor defines
# - LINKFLAGS are for linking flags
env = SConscript("godot-cpp/SConstruct")
# Generate version header.
print("Generating LimboAI version header...")
generate_module_version_header()
# Update icon entries in limboai.gdextension file.
# Note: This will remove everything after [icons] section, and rebuild it with generated icon entries.
print("Updating LimboAI icon entries...")
update_icon_entries(silent=True)
# Fix icon imports in the PROJECT/addons/limboai/icons/.
# Enables scaling and color conversion in the editor for imported SVG icons.
try:
fix_icon_imports(project_dir)
except FileNotFoundError as e:
print(e)
except Exception as e:
print("Unknown error: " + str(e))
# Tweak this if you want to use different folders, or more folders, to store your source code in.
env.Append(CPPDEFINES=["LIMBOAI_GDEXTENSION"])
sources = Glob("*.cpp")
sources += Glob("blackboard/*.cpp")
sources += Glob("blackboard/bb_param/*.cpp")
sources += Glob("bt/*.cpp")
sources += Glob("bt/tasks/*.cpp")
sources += Glob("bt/tasks/blackboard/*.cpp")
sources += Glob("bt/tasks/composites/*.cpp")
sources += Glob("bt/tasks/decorators/*.cpp")
sources += Glob("bt/tasks/scene/*.cpp")
sources += Glob("bt/tasks/utility/*.cpp")
sources += Glob("gdextension/*.cpp")
sources += Glob("editor/debugger/*.cpp")
sources += Glob("editor/*.cpp")
sources += Glob("hsm/*.cpp")
sources += Glob("util/*.cpp")
# Generate documentation header.
if env["target"] in ["editor", "template_debug"]:
doc_data = env.GodotCPPDocData("gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml"))
sources.append(doc_data)
# Build library.
if env["platform"] == "macos":
library = env.SharedLibrary(
project_dir
+ "/addons/limboai/bin/liblimboai.{}.{}.framework/liblimboai.{}.{}".format(
env["platform"], env["target"], env["platform"], env["target"]
),
source=sources,
)
else:
library = env.SharedLibrary(
project_dir + "/addons/limboai/bin/liblimboai{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
source=sources,
)
Default(library)
# Deploy icons into PROJECT/addons/limboai/icons.
if deploy_icons:
cmd_deploy_icons = env.Command(
project_dir + "/addons/limboai/icons/",
"icons/",
Copy("$TARGET", "$SOURCE"),
)
Default(cmd_deploy_icons)
# Deploy limboai.gdextension into PROJECT/addons/limboai/bin.
if deploy_manifest:
cmd_deploy_manifest = env.Command(
project_dir + "/addons/limboai/bin/limboai.gdextension",
"gdextension/limboai.gdextension",
Copy("$TARGET", "$SOURCE"),
)
Default(cmd_deploy_manifest)

View File

@ -1,61 +0,0 @@
#!/usr/bin/env python
import os
import sys
env = SConscript("godot-cpp/SConstruct")
# For reference:
# - CCFLAGS are compilation flags shared between C and C++
# - CFLAGS are for C-specific compilation flags
# - CXXFLAGS are for C++-specific compilation flags
# - CPPFLAGS are for pre-processor flags
# - CPPDEFINES are for pre-processor defines
# - LINKFLAGS are for linking flags
# Generate version header.
sys.path.append("./limboai")
import limboai_version
os.chdir("./limboai")
limboai_version.generate_module_version_header()
os.chdir("..")
sys.path.remove("./limboai")
# Tweak this if you want to use different folders, or more folders, to store your source code in.
env.Append(CPPPATH=["limboai/"])
env.Append(CPPDEFINES=["LIMBOAI_GDEXTENSION"])
sources = Glob("limboai/*.cpp")
sources += Glob("limboai/blackboard/*.cpp")
sources += Glob("limboai/blackboard/bb_param/*.cpp")
sources += Glob("limboai/bt/*.cpp")
sources += Glob("limboai/bt/tasks/*.cpp")
sources += Glob("limboai/bt/tasks/blackboard/*.cpp")
sources += Glob("limboai/bt/tasks/composites/*.cpp")
sources += Glob("limboai/bt/tasks/decorators/*.cpp")
sources += Glob("limboai/bt/tasks/scene/*.cpp")
sources += Glob("limboai/bt/tasks/utility/*.cpp")
sources += Glob("limboai/gdextension/*.cpp")
sources += Glob("limboai/editor/debugger/*.cpp")
sources += Glob("limboai/editor/*.cpp")
sources += Glob("limboai/hsm/*.cpp")
sources += Glob("limboai/util/*.cpp")
# Generate documentation header.
if env["target"] in ["editor", "template_debug"]:
doc_data = env.GodotCPPDocData("limboai/gen/doc_data.gen.cpp", source=Glob("limboai/doc_classes/*.xml"))
sources.append(doc_data)
if env["platform"] == "macos":
library = env.SharedLibrary(
"demo/addons/limboai/bin/liblimboai.{}.{}.framework/liblimboai.{}.{}".format(
env["platform"], env["target"], env["platform"], env["target"]
),
source=sources,
)
else:
library = env.SharedLibrary(
"demo/addons/limboai/bin/liblimboai{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
source=sources,
)
Default(library)

114
gdextension/fix_icon_imports.py Executable file
View File

@ -0,0 +1,114 @@
#!/usr/bin/python
"""
Usage: fix_icon_imports.py [--silent] PROJECT_DIR
Fix icon imports in PROJECT_DIR/addons/limboai/icons/.
Options:
-s, --silent Don't print anything.
-h, --help Print this message.
Dependencies: python3.
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
"""
import os
import glob
import sys
import getopt
def usage():
print(__doc__.strip())
def get_limboai_icon_import_files(project_path="demo/"):
if not os.path.isdir(project_path):
raise FileNotFoundError("Project directory not found: " + project_path)
icons_path = os.path.join(project_path, "addons/limboai/icons/")
if not os.path.isdir(icons_path):
raise FileNotFoundError("Icons directory not found: " + icons_path)
return glob.glob(icons_path + "*.import")
def fix_import_file(file_path):
if not os.path.isfile(file_path):
raise FileNotFoundError("File not found: " + file_path)
old_lines = []
new_lines = []
file = open(file_path, "r")
old_lines = file.readlines()
file.close()
for line in old_lines:
line = line.replace("editor/scale_with_editor_scale=false", "editor/scale_with_editor_scale=true")
line = line.replace(
"editor/convert_colors_with_editor_theme=false", "editor/convert_colors_with_editor_theme=true"
)
new_lines.append(line)
if old_lines != new_lines:
file = open(file_path, "w")
for line in new_lines:
file.write(line)
file.close()
return True
return False
def fix_icon_imports(project_path="demo/", silent=False):
if not silent:
print("Checking icon import files...")
project_import_files = get_limboai_icon_import_files(project_path)
for import_file in project_import_files:
changed = fix_import_file(import_file)
if changed and not silent:
print("Updated icon import file: " + import_file)
if __name__ == "__main__":
silent = False
project_path = "demo/"
try:
opts, args = getopt.getopt(sys.argv[1:], "s", ["silent"])
except getopt.GetoptError as e:
print(
"%s: %s!\n"
% (
os.path.basename(__file__),
e.msg,
)
)
usage()
sys.exit(2)
if len(args) > 1:
usage()
sys.exit(2)
elif len(args) == 1:
project_path = args[0]
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit(0)
elif opt in ("-s", "--silent"):
silent = True
try:
fix_icon_imports(project_path, silent)
except FileNotFoundError as e:
print(e)
exit(1)
if not silent:
print("Done!")

View File

@ -1,156 +0,0 @@
#!/bin/bash
## This script creates project structure needed for LimboAI development using GDExtension.
## Works only on Unix-likes. You can still use the directory layout below, if you are on Windows.
##
## Instructions:
## 1) Create the project root directory, name doesn't matter.
## 2) Inside the project root directory, clone the limboai repository:
## git clone https://github.com/limbonaut/limboai
## 3) From the project root directory, run:
## bash ./limboai/gdextension/setup_gdextension.sh
##
## Directory layout:
## project/ -- call this script from here, directory name doesn't matter.
## project/limboai/ -- LimboAI repository should be here after you clone it.
## project/godot-cpp/ -- will be created by this script, unless cloned manually.
## project/demo/ -- symbolic link (leads to limboai/demo).
## project/demo/addons/limboai/limboai.gdextension -- symbolid link (leads to limboai/gdextension/limboai.gdextension).
## project/demo/addons/limboai/icons/ -- symbolic link (leads to icons/).
## project/SConstruct -- symbolic link (leads to limboai/gdextension/SContruct).
##
## Note: Symbolic links will be created by this script.
##
## Dependencies: bash, git, python3.
# Script Settings
GODOT_CPP_VERSION=4.2
PYTHON=python
# Colors
HIGHLIGHT_COLOR='\033[1;36m' # Light Cyan
NC='\033[0m' # No Color
ERROR_COLOR="\033[0;31m" # Red
usage() { echo "Usage: $0 [--copy-demo] [--copy-all] [--trash-old]"; }
msg () { echo -e "$@"; }
highlight() { echo -e "${HIGHLIGHT_COLOR}$@${NC}"; }
error () { echo -e "${ERROR_COLOR}$@${NC}" >&2; }
if [ ! -d "${PWD}/limboai/" ]; then
error Aborting: \"limboai\" subdirectory is not found.
msg Tip: Run this script from the project root directory with limboai repository cloned into \"limboai\" subdirectory.
msg Command: bash ./limboai/gdextension/setup_gdextension.sh
exit 1
fi
# Interrupt execution and exit on Ctrl-C
trap exit SIGINT
set -e
copy_demo=0
copy_all=0
trash_old=0
# Parsing arguments
for i in "$@"
do
case "${i}" in
--copy-demo)
copy_demo=1
shift
;;
--copy-all)
copy_demo=1
copy_all=1
shift
;;
--trash-old)
trash_old=1
shift
;;
*)
usage
exit 1
;;
esac
done
highlight Setup started.
${PYTHON} limboai/gdextension/update_icons.py --silent
highlight -- Icon declarations updated.
transfer="ln -s"
transfer_word="Linked"
if [ ${copy_all} == 1 ]; then
transfer="cp -R"
transfer_word="Copied"
fi
if [ ${trash_old} == 1 ]; then
if ! command -v trash &> /dev/null; then
error trash command not available. Aborting.
exit 1
fi
trash SConstruct limboai/demo/addons demo || /bin/true
highlight -- Trashed old setup.
fi
if [ ! -d "${PWD}/godot-cpp/" ]; then
highlight -- Cloning godot-cpp...
git clone -b ${GODOT_CPP_VERSION} https://github.com/godotengine/godot-cpp
highlight -- Finished cloning godot-cpp.
else
highlight -- Skipping \"godot-cpp\". Directory already exists!
fi
if [ ! -f "${PWD}/SConstruct" ]; then
${transfer} limboai/gdextension/SConstruct SConstruct
highlight -- ${transfer_word} SConstruct.
else
highlight -- Skipping \"SConstruct\". File already exists!
fi
if [ ! -e "${PWD}/demo" ]; then
if [ ${copy_demo} == 1 ]; then
cp -R limboai/demo demo
highlight -- Copied demo.
else
ln -s limboai/demo demo
highlight -- Linked demo project.
fi
else
highlight -- Skipping \"demo\". File already exists!
fi
if [ ! -e "${PWD}/demo/addons/limboai/bin/limboai.gdextension" ]; then
mkdir -p ./demo/addons/limboai/bin/
cd ./demo/addons/limboai/bin/
if [ -f "../../../../gdextension/limboai.gdextension" ]; then
${transfer} ../../../../gdextension/limboai.gdextension limboai.gdextension
else
${transfer} ../../../../limboai/gdextension/limboai.gdextension limboai.gdextension
fi
cd -
highlight -- ${transfer_word} limboai.gdextension.
else
highlight -- Skipping limboai.gdextension. File already exists!
fi
if [ ! -e "${PWD}/demo/addons/limboai/icons/" ]; then
cd ./demo/addons/limboai/
if [ -d "../../../icons" ]; then
${transfer} ../../../icons icons
else
${transfer} ../../../limboai/icons icons
fi
cd -
highlight -- ${transfer_word} icons.
else
highlight -- Skipping icons. File already exists!
fi
highlight Setup complete.

View File

@ -1,7 +1,7 @@
#!/usr/bin/python
"""
Usage: update_icons.py [--silent]
Update icon declarations in limboai.gdextension file.
Usage: update_icon_entries.py [--silent]
Update icon entries in limboai.gdextension file.
Options:
-s, --silent Don't print anything.
@ -28,7 +28,44 @@ def get_script_dir():
return os.path.dirname(os.path.realpath(__file__))
def main():
def update_icon_entries(silent=False):
config_dir = get_script_dir()
config_path = os.path.join(config_dir, "limboai.gdextension")
content = ""
new_content = ""
f = open(config_path, "r")
for line in f:
content += line
f.close()
index = content.find("[icons]")
new_content = content[0:index]
new_content += "[icons]\n\n"
icon_files = []
icons_dir = os.path.join(config_dir, "../icons/")
for icon_file in glob.glob(icons_dir + "/*.svg"):
icon_file = os.path.basename(icon_file)
icon_files.append(icon_file)
icon_files.sort()
for icon_file in icon_files:
new_content += os.path.splitext(icon_file)[0] + ' = "res://addons/limboai/icons/' + icon_file + '"\n'
if new_content != content:
f = open(config_path, "w")
f.write(new_content)
f.close()
if not silent:
print(new_content)
print("=== Icon entries updated ===")
else:
if not silent:
print("=== No update needed for icon entries ===")
if __name__ == "__main__":
silent = False
try:
opts, args = getopt.getopt(sys.argv[1:], "s", ["silent"])
@ -50,37 +87,4 @@ def main():
elif opt in ("-s", "--silent"):
silent = True
config_dir = get_script_dir()
config_path = os.path.join(config_dir, "limboai.gdextension")
content = ""
f = open(config_path, "r")
for line in f:
if line.startswith("[icons]"):
break
content += line
f.close()
content += "[icons]\n\n"
icon_files = []
icons_dir = os.path.join(config_dir, "../icons/")
for icon_file in glob.glob(icons_dir + "/*.svg"):
icon_file = os.path.basename(icon_file)
icon_files.append(icon_file)
icon_files.sort()
for icon_file in icon_files:
content += os.path.splitext(icon_file)[0] + ' = "res://addons/limboai/icons/' + icon_file + '"\n'
f = open(config_path, "w")
f.write(content)
f.close()
if not silent:
print(content)
print("======= Icon declarations updated =======")
if __name__ == "__main__":
main()
update_icon_entries(silent)

View File

@ -5,6 +5,7 @@ minor = 2
patch = 0
status = "dev"
doc_branch = "latest"
godot_cpp_ref = "master"
# Code that generates version header