From 0f2cabd469bfeadf71181a4410cc3db5bbaa828d Mon Sep 17 00:00:00 2001 From: Dan Crosby Date: Tue, 16 Jun 2026 07:54:23 -0700 Subject: [PATCH] Build Unity protos as a Bazel DLL (#7291) --- .github/workflows/unity_build.yml | 12 ++++ scripts/build_protos.sh | 68 ++++--------------- .../eagle0/clients/unity/eagle0/BUILD.bazel | 37 ++++++++++ .../protobuf/net/eagle0/common/BUILD.bazel | 1 + .../protobuf/net/eagle0/eagle/api/BUILD.bazel | 2 + .../eagle0/eagle/api/command/util/BUILD.bazel | 1 + .../net/eagle0/eagle/common/BUILD.bazel | 1 + .../net/eagle0/eagle/views/BUILD.bazel | 1 + .../net/eagle0/shardok/api/BUILD.bazel | 1 + .../net/eagle0/shardok/common/BUILD.bazel | 1 + .../net/eagle0/shardok/storage/BUILD.bazel | 1 + 11 files changed, 73 insertions(+), 53 deletions(-) diff --git a/.github/workflows/unity_build.yml b/.github/workflows/unity_build.yml index 7570ffef99..d2e5fa1a51 100644 --- a/.github/workflows/unity_build.yml +++ b/.github/workflows/unity_build.yml @@ -104,6 +104,12 @@ jobs: - name: Clean stale files run: | git clean -ffd + UNITY_ROOT="src/main/csharp/net/eagle0/clients/unity/eagle0" + # These ignored proto outputs are mutually exclusive across proto-generation + # layouts. Clean both before regenerating to avoid stale DLL/source duplicates + # when a self-hosted runner switches between main and PR branches. + rm -rf "$UNITY_ROOT/Assets/GeneratedProtos" + rm -rf "$UNITY_ROOT/Assets/Plugins/Eagle0Protos" LIBRARY_DIR="src/main/csharp/net/eagle0/clients/unity/eagle0/Library" VERSION_CACHE="$LIBRARY_DIR/.last_unity_version" PROJECT_VERSION_FILE="src/main/csharp/net/eagle0/clients/unity/eagle0/ProjectSettings/ProjectVersion.txt" @@ -213,6 +219,12 @@ jobs: - name: Clean stale files run: | git clean -ffd + UNITY_ROOT="src/main/csharp/net/eagle0/clients/unity/eagle0" + # These ignored proto outputs are mutually exclusive across proto-generation + # layouts. Clean both before regenerating to avoid stale DLL/source duplicates + # when a self-hosted runner switches between main and PR branches. + rm -rf "$UNITY_ROOT/Assets/GeneratedProtos" + rm -rf "$UNITY_ROOT/Assets/Plugins/Eagle0Protos" LIBRARY_DIR="src/main/csharp/net/eagle0/clients/unity/eagle0/Library" VERSION_CACHE="$LIBRARY_DIR/.last_unity_version" PROJECT_VERSION_FILE="src/main/csharp/net/eagle0/clients/unity/eagle0/ProjectSettings/ProjectVersion.txt" diff --git a/scripts/build_protos.sh b/scripts/build_protos.sh index ade59aa638..ccb8face13 100755 --- a/scripts/build_protos.sh +++ b/scripts/build_protos.sh @@ -1,68 +1,30 @@ #!/bin/bash -set -euxo pipefail +set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" UNITY_ROOT="$REPO_ROOT/src/main/csharp/net/eagle0/clients/unity/eagle0" -OUTPUT_DIR="$UNITY_ROOT/Assets/GeneratedProtos" +PLUGIN_DIR="$UNITY_ROOT/Assets/Plugins/Eagle0Protos" +GENERATED_SOURCES_DIR="$UNITY_ROOT/Assets/GeneratedProtos" +PROTO_DLL_TARGET="//src/main/csharp/net/eagle0/clients/unity/eagle0:eagle0_protos" +PROTO_DLL_OUTPUT="$REPO_ROOT/bazel-bin/src/main/csharp/net/eagle0/clients/unity/eagle0/eagle0_protos/netstandard2.1" -# All C# protobuf generation targets -TARGETS=( - "//src/main/protobuf/net/eagle0/common:common_csharp_proto_srcs" - "//src/main/protobuf/net/eagle0/shardok/storage:storage_csharp_proto_srcs" - "//src/main/protobuf/net/eagle0/shardok/common:common_csharp_proto_srcs" - "//src/main/protobuf/net/eagle0/shardok/api:api_csharp_proto_srcs" - "//src/main/protobuf/net/eagle0/eagle/common:common_csharp_proto_srcs" - "//src/main/protobuf/net/eagle0/eagle/views:views_csharp_proto_srcs" - "//src/main/protobuf/net/eagle0/eagle/api:api_csharp_proto_srcs" - "//src/main/protobuf/net/eagle0/eagle/api:api_csharp_grpc_srcs" - "//src/main/protobuf/net/eagle0/eagle/api/command/util:util_csharp_proto_srcs" -) +/bin/echo "Building C# protobuf DLL..." +bazel build "$PROTO_DLL_TARGET" -# Subdirectory for each target (avoids filename collisions across packages) -SUBDIRS=( - "net/eagle0/common" - "net/eagle0/shardok/storage" - "net/eagle0/shardok/common" - "net/eagle0/shardok/api" - "net/eagle0/eagle/common" - "net/eagle0/eagle/views" - "net/eagle0/eagle/api" - "net/eagle0/eagle/api" - "net/eagle0/eagle/api/command/util" -) +/bin/echo "Syncing generated protobuf DLL to $PLUGIN_DIR..." -/bin/echo "Building C# protobuf sources..." -bazel build "${TARGETS[@]}" - -/bin/echo "Syncing generated .cs files to $OUTPUT_DIR..." - -# Stage new files in a temp directory, then rsync to preserve timestamps -# on unchanged files. This avoids triggering Unity reimport when protos -# haven't changed, saving ~7 minutes of script recompilation. STAGING_DIR=$(mktemp -d) trap "rm -rf '$STAGING_DIR'" EXIT -for i in "${!TARGETS[@]}"; do - target="${TARGETS[$i]}" - subdir="${SUBDIRS[$i]}" - - # Convert target label to bazel-bin path - # //src/main/protobuf/net/eagle0/common:common_csharp_proto_srcs - # -> bazel-bin/src/main/protobuf/net/eagle0/common/common_csharp_proto_srcs - target_path="${target#//}" - pkg="${target_path%%:*}" - name="${target_path##*:}" - bin_dir="$REPO_ROOT/bazel-bin/$pkg/$name" - - dest_dir="$STAGING_DIR/$subdir" - mkdir -p "$dest_dir" - find "$bin_dir" -name "*.cs" -exec cp {} "$dest_dir/" \; -done +cp "$PROTO_DLL_OUTPUT/Eagle0Protos.dll" "$STAGING_DIR/" +cp "$PROTO_DLL_OUTPUT/Eagle0Protos.xml" "$STAGING_DIR/" # Sync only changed files and delete removed ones; --checksum compares # content not timestamps so unchanged files keep their original mtime. -mkdir -p "$OUTPUT_DIR" -rsync -rc --delete "$STAGING_DIR/" "$OUTPUT_DIR/" +mkdir -p "$PLUGIN_DIR" +rsync -rc --delete --exclude "*.meta" "$STAGING_DIR/" "$PLUGIN_DIR/" -/bin/echo "Done. Generated C# proto sources in $OUTPUT_DIR" +rm -rf "$GENERATED_SOURCES_DIR" + +/bin/echo "Done. Generated C# proto DLL in $PLUGIN_DIR" diff --git a/src/main/csharp/net/eagle0/clients/unity/eagle0/BUILD.bazel b/src/main/csharp/net/eagle0/clients/unity/eagle0/BUILD.bazel index 79f6557c93..46c15ea3d9 100644 --- a/src/main/csharp/net/eagle0/clients/unity/eagle0/BUILD.bazel +++ b/src/main/csharp/net/eagle0/clients/unity/eagle0/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_dotnet//dotnet:defs.bzl", "csharp_library", "import_dll") + #unity3d_binary( # name = "windows", # build_command = "buildWindows64Player", @@ -13,3 +15,38 @@ genrule( outs = ["eagle0.exe"], cmd = "", ) + +# Compile against Unity's vendored package DLLs so the Bazel-built proto +# assembly references the same runtime assemblies Unity imports. +import_dll( + name = "google_protobuf_dll", + dll = "Assets/Packages/Google.Protobuf.3.27.3/lib/netstandard2.0/Google.Protobuf.dll", + version = "3.27.3", +) + +import_dll( + name = "grpc_core_api_dll", + dll = "Assets/Packages/Grpc.Core.Api.2.65.0/lib/netstandard2.1/Grpc.Core.Api.dll", + version = "2.65.0", +) + +csharp_library( + name = "eagle0_protos", + srcs = [ + "//src/main/protobuf/net/eagle0/common:common_csharp_proto_srcs", + "//src/main/protobuf/net/eagle0/eagle/api:api_csharp_grpc_srcs", + "//src/main/protobuf/net/eagle0/eagle/api:api_csharp_proto_srcs", + "//src/main/protobuf/net/eagle0/eagle/api/command/util:util_csharp_proto_srcs", + "//src/main/protobuf/net/eagle0/eagle/common:common_csharp_proto_srcs", + "//src/main/protobuf/net/eagle0/eagle/views:views_csharp_proto_srcs", + "//src/main/protobuf/net/eagle0/shardok/api:api_csharp_proto_srcs", + "//src/main/protobuf/net/eagle0/shardok/common:common_csharp_proto_srcs", + "//src/main/protobuf/net/eagle0/shardok/storage:storage_csharp_proto_srcs", + ], + out = "Eagle0Protos", + target_frameworks = ["netstandard2.1"], + deps = [ + ":google_protobuf_dll", + ":grpc_core_api_dll", + ], +) diff --git a/src/main/protobuf/net/eagle0/common/BUILD.bazel b/src/main/protobuf/net/eagle0/common/BUILD.bazel index 4eacc89184..12344a731f 100644 --- a/src/main/protobuf/net/eagle0/common/BUILD.bazel +++ b/src/main/protobuf/net/eagle0/common/BUILD.bazel @@ -227,6 +227,7 @@ csharp_proto_compile( ":tutorial_battle_config_proto", ":victory_condition_proto", ], + visibility = ["//src/main/csharp/net/eagle0/clients/unity/eagle0:__pkg__"], ) # keep: gazelle wants go_grpc_v2 and shardok_internal_interface_proto, but that breaks Go compilation diff --git a/src/main/protobuf/net/eagle0/eagle/api/BUILD.bazel b/src/main/protobuf/net/eagle0/eagle/api/BUILD.bazel index 0e72d26fad..0e9449775c 100644 --- a/src/main/protobuf/net/eagle0/eagle/api/BUILD.bazel +++ b/src/main/protobuf/net/eagle0/eagle/api/BUILD.bazel @@ -168,6 +168,7 @@ csharp_proto_compile( ":selected_command_proto", ":streaming_text_response_proto", ], + visibility = ["//src/main/csharp/net/eagle0/clients/unity/eagle0:__pkg__"], ) csharp_grpc_compile( @@ -176,6 +177,7 @@ csharp_grpc_compile( ":auth_grpc", ":eagle_grpc", ], + visibility = ["//src/main/csharp/net/eagle0/clients/unity/eagle0:__pkg__"], ) # Non-gRPC message protos diff --git a/src/main/protobuf/net/eagle0/eagle/api/command/util/BUILD.bazel b/src/main/protobuf/net/eagle0/eagle/api/command/util/BUILD.bazel index 5b3e2af519..bfaee86313 100644 --- a/src/main/protobuf/net/eagle0/eagle/api/command/util/BUILD.bazel +++ b/src/main/protobuf/net/eagle0/eagle/api/command/util/BUILD.bazel @@ -280,6 +280,7 @@ csharp_proto_compile( ":prisoner_management_type_proto", ":province_orders_proto", ], + visibility = ["//src/main/csharp/net/eagle0/clients/unity/eagle0:__pkg__"], ) go_proto_library( diff --git a/src/main/protobuf/net/eagle0/eagle/common/BUILD.bazel b/src/main/protobuf/net/eagle0/eagle/common/BUILD.bazel index 75192079f6..bcfab640b2 100644 --- a/src/main/protobuf/net/eagle0/eagle/common/BUILD.bazel +++ b/src/main/protobuf/net/eagle0/eagle/common/BUILD.bazel @@ -409,6 +409,7 @@ csharp_proto_compile( ":unaffiliated_hero_quest_proto", ":unaffiliated_hero_type_proto", ], + visibility = ["//src/main/csharp/net/eagle0/clients/unity/eagle0:__pkg__"], ) go_proto_library( diff --git a/src/main/protobuf/net/eagle0/eagle/views/BUILD.bazel b/src/main/protobuf/net/eagle0/eagle/views/BUILD.bazel index dd97be2e83..99aff08f73 100644 --- a/src/main/protobuf/net/eagle0/eagle/views/BUILD.bazel +++ b/src/main/protobuf/net/eagle0/eagle/views/BUILD.bazel @@ -269,6 +269,7 @@ csharp_proto_compile( ":shardok_battle_view_proto", ":stat_with_condition_proto", ], + visibility = ["//src/main/csharp/net/eagle0/clients/unity/eagle0:__pkg__"], ) go_proto_library( diff --git a/src/main/protobuf/net/eagle0/shardok/api/BUILD.bazel b/src/main/protobuf/net/eagle0/shardok/api/BUILD.bazel index 059165454e..d728d39b63 100644 --- a/src/main/protobuf/net/eagle0/shardok/api/BUILD.bazel +++ b/src/main/protobuf/net/eagle0/shardok/api/BUILD.bazel @@ -156,6 +156,7 @@ csharp_proto_compile( ":roll_request_proto", ":unit_view_proto", ], + visibility = ["//src/main/csharp/net/eagle0/clients/unity/eagle0:__pkg__"], ) go_proto_library( diff --git a/src/main/protobuf/net/eagle0/shardok/common/BUILD.bazel b/src/main/protobuf/net/eagle0/shardok/common/BUILD.bazel index ea11776c87..d0a2492b39 100644 --- a/src/main/protobuf/net/eagle0/shardok/common/BUILD.bazel +++ b/src/main/protobuf/net/eagle0/shardok/common/BUILD.bazel @@ -223,6 +223,7 @@ csharp_proto_compile( ":victory_condition_proto", ":weather_proto", ], + visibility = ["//src/main/csharp/net/eagle0/clients/unity/eagle0:__pkg__"], ) go_proto_library( diff --git a/src/main/protobuf/net/eagle0/shardok/storage/BUILD.bazel b/src/main/protobuf/net/eagle0/shardok/storage/BUILD.bazel index 591583899e..83fdd31833 100644 --- a/src/main/protobuf/net/eagle0/shardok/storage/BUILD.bazel +++ b/src/main/protobuf/net/eagle0/shardok/storage/BUILD.bazel @@ -69,6 +69,7 @@ csharp_proto_compile( ":action_with_resulting_state_proto", ":odds_proto", ], + visibility = ["//src/main/csharp/net/eagle0/clients/unity/eagle0:__pkg__"], ) go_proto_library(