mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-29 14:10:41 +00:00
Compare commits
67
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
deb0e33c5a | ||
|
|
0191455d5d | ||
|
|
98ed70c2e0 | ||
|
|
7aee0ee789 | ||
|
|
961a7c81b2 | ||
|
|
d675758a9e | ||
|
|
2864bae977 | ||
|
|
b41b937662 | ||
|
|
201fa30acd | ||
|
|
df1923f076 | ||
|
|
721382a9e9 | ||
|
|
f006618060 | ||
|
|
93760dbfb4 | ||
|
|
59a0632af2 | ||
|
|
3c17e89f02 | ||
|
|
0dc5435b9a | ||
|
|
b55df7cf3e | ||
|
|
19a76d3015 | ||
|
|
a50bfe36b0 | ||
|
|
73ba9a3acc | ||
|
|
2332626198 | ||
|
|
cc463700d9 | ||
|
|
0788f9a155 | ||
|
|
44f9eba77f | ||
|
|
22f68fc3df | ||
|
|
b08c1755ac | ||
|
|
1b0ede178c | ||
|
|
258f739d02 | ||
|
|
f125c8f5f6 | ||
|
|
22b0bc00cc | ||
|
|
45942688a9 | ||
|
|
a7b7b0e444 | ||
|
|
76be41d841 | ||
|
|
8ee4e1475c | ||
|
|
c583e216d3 | ||
|
|
f3dea0306d | ||
|
|
acf57f3c96 | ||
|
|
9cb7cadcdf | ||
|
|
1bbdd18f9f | ||
|
|
aad241ed77 | ||
|
|
4ff93ac8fc | ||
|
|
e3b88215aa | ||
|
|
c89a4ef51b | ||
|
|
7d07bd97ad | ||
|
|
5a80fcf765 | ||
|
|
8a2bc8d984 | ||
|
|
50c632a8ea | ||
|
|
ac11292778 | ||
|
|
de01fc1451 | ||
|
|
fde8ccf675 | ||
|
|
1033a4b730 | ||
|
|
f3959c8c79 | ||
|
|
f7b76bb30d | ||
|
|
eaae3089de | ||
|
|
eb2e954c2c | ||
|
|
95b4201819 | ||
|
|
5ba1948c8e | ||
|
|
2f6ce2d0b7 | ||
|
|
df916f9c29 | ||
|
|
ddbc960945 | ||
|
|
e020a0f66c | ||
|
|
d60a9f79ec | ||
|
|
6b55be9457 | ||
|
|
716dd97f75 | ||
|
|
413f70a3b3 | ||
|
|
f2e08cdb5d | ||
|
|
056127c614 |
@@ -29,13 +29,17 @@ common --javacopt="-Xlint:-options"
|
||||
# Use host_linkopt for macOS-specific flags to avoid passing them to Linux cross-compilation
|
||||
common:macos --host_linkopt=-Wl,-no_warn_duplicate_libraries
|
||||
|
||||
# Workaround for grpc cf_event_engine build error on macOS with Bazel 7.x
|
||||
# See: https://github.com/grpc/grpc/issues/37619
|
||||
common:macos --features=-module_maps
|
||||
|
||||
# Fix Xcode version caching issue - avoids need for `bazel clean --expunge` after Xcode updates
|
||||
common:macos --repo_env=DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
|
||||
|
||||
common --java_language_version=17
|
||||
common --java_runtime_version=remotejdk_17
|
||||
common --tool_java_language_version=17
|
||||
common --tool_java_runtime_version=remotejdk_17
|
||||
common --java_language_version=25
|
||||
common --java_runtime_version=remotejdk_25
|
||||
common --tool_java_language_version=25
|
||||
common --tool_java_runtime_version=remotejdk_25
|
||||
|
||||
# Workspace status for build stamping (git commit, timestamp)
|
||||
common --workspace_status_command=tools/workspace_status.sh
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
7.6.1
|
||||
8.5.1
|
||||
|
||||
@@ -11,6 +11,7 @@ on:
|
||||
- 'src/main/protobuf/net/eagle0/eagle/internal/auth_internal.proto'
|
||||
- 'src/main/resources/net/eagle0/attributions.json'
|
||||
- 'ci/BUILD.bazel'
|
||||
- '.bazelrc'
|
||||
- '.github/workflows/auth_build.yml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -77,8 +78,14 @@ jobs:
|
||||
# Build the push target to get crane in runfiles
|
||||
bazel build //ci:auth_server_push
|
||||
|
||||
# Use crane directly for push
|
||||
CRANE="bazel-bin/ci/push_auth_server_push.sh.runfiles/rules_oci~~oci~oci_crane_darwin_arm64/crane"
|
||||
# Find crane binary in runfiles (path varies by Bazel version)
|
||||
RUNFILES="bazel-bin/ci/push_auth_server_push.sh.runfiles"
|
||||
CRANE=$(find "$RUNFILES" -path "*darwin*" -name crane 2>/dev/null | head -1)
|
||||
if [ -z "$CRANE" ] || [ ! -x "$CRANE" ]; then
|
||||
echo "ERROR: crane not found in runfiles"
|
||||
find "$RUNFILES" -name crane 2>/dev/null || echo "No crane found at all"
|
||||
exit 1
|
||||
fi
|
||||
echo "Using crane: $CRANE"
|
||||
|
||||
# Push with SHA tag
|
||||
|
||||
@@ -8,6 +8,7 @@ on:
|
||||
- 'WORKSPACE'
|
||||
- 'MODULE.bazel'
|
||||
- 'BUILD.bazel'
|
||||
- '.bazelrc'
|
||||
- '.github/workflows/bazel_test.yml'
|
||||
- '!src/main/csharp/**'
|
||||
- '!src/test/csharp/**'
|
||||
@@ -17,6 +18,7 @@ on:
|
||||
- 'WORKSPACE'
|
||||
- 'MODULE.bazel'
|
||||
- 'BUILD.bazel'
|
||||
- '.bazelrc'
|
||||
- '.github/workflows/bazel_test.yml'
|
||||
- '!src/main/csharp/**'
|
||||
- '!src/test/csharp/**'
|
||||
|
||||
@@ -19,6 +19,7 @@ on:
|
||||
- 'src/main/resources/**'
|
||||
- 'ci/BUILD.bazel'
|
||||
- 'MODULE.bazel'
|
||||
- '.bazelrc'
|
||||
- 'docker-compose.prod.yml'
|
||||
- 'nginx/**'
|
||||
- '.github/workflows/docker_build.yml'
|
||||
@@ -111,16 +112,12 @@ jobs:
|
||||
|
||||
# Get crane from push target runfiles
|
||||
bazel build //ci:eagle_server_push
|
||||
CRANE="bazel-bin/ci/push_eagle_server_push.sh.runfiles/rules_oci~~oci~oci_crane_darwin_arm64/crane"
|
||||
RUNFILES="bazel-bin/ci/push_eagle_server_push.sh.runfiles"
|
||||
CRANE=$(find "$RUNFILES" -path "*darwin*" -name crane 2>/dev/null | head -1)
|
||||
|
||||
if [ ! -e "$CRANE" ]; then
|
||||
# Fallback: find any Darwin crane
|
||||
RUNFILES="bazel-bin/ci/push_eagle_server_push.sh.runfiles"
|
||||
CRANE=$(find "$RUNFILES" -path "*darwin*" -name crane 2>/dev/null | head -1)
|
||||
fi
|
||||
|
||||
if [ -z "$CRANE" ] || [ ! -e "$CRANE" ]; then
|
||||
echo "ERROR: crane not found"
|
||||
if [ -z "$CRANE" ] || [ ! -x "$CRANE" ]; then
|
||||
echo "ERROR: crane not found in runfiles"
|
||||
find "$RUNFILES" -name crane 2>/dev/null || echo "No crane found at all"
|
||||
exit 1
|
||||
fi
|
||||
echo "Using crane: $CRANE"
|
||||
@@ -167,6 +164,9 @@ jobs:
|
||||
EAGLE_ENABLE_S3: ${{ secrets.EAGLE_ENABLE_S3 }}
|
||||
DO_SPACES_ACCESS_KEY: ${{ secrets.DO_SPACES_ACCESS_KEY }}
|
||||
DO_SPACES_SECRET_KEY: ${{ secrets.DO_SPACES_SECRET_KEY }}
|
||||
# Admin server uses different credentials (for eagle0-assets bucket)
|
||||
ADMIN_S3_ACCESS_KEY: ${{ secrets.ACCESS_KEY_ID }}
|
||||
ADMIN_S3_SECRET_KEY: ${{ secrets.SECRET_KEY }}
|
||||
JWT_PRIVATE_KEY: ${{ secrets.JWT_PRIVATE_KEY }}
|
||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||
DISCORD_CLIENT_SECRET: ${{ secrets.DISCORD_CLIENT_SECRET }}
|
||||
@@ -288,6 +288,8 @@ jobs:
|
||||
export EAGLE_ENABLE_S3="${EAGLE_ENABLE_S3:-false}"
|
||||
export DO_SPACES_ACCESS_KEY="${DO_SPACES_ACCESS_KEY}"
|
||||
export DO_SPACES_SECRET_KEY="${DO_SPACES_SECRET_KEY}"
|
||||
export ADMIN_S3_ACCESS_KEY="${ADMIN_S3_ACCESS_KEY}"
|
||||
export ADMIN_S3_SECRET_KEY="${ADMIN_S3_SECRET_KEY}"
|
||||
export JWT_PRIVATE_KEY="${JWT_PRIVATE_KEY}"
|
||||
export DISCORD_CLIENT_ID="${DISCORD_CLIENT_ID}"
|
||||
export DISCORD_CLIENT_SECRET="${DISCORD_CLIENT_SECRET}"
|
||||
@@ -401,7 +403,9 @@ jobs:
|
||||
fi
|
||||
echo "Admin image verification passed"
|
||||
|
||||
# Cleanup
|
||||
# Cleanup - remove old images to prevent disk full
|
||||
docker container prune -f
|
||||
docker image prune -f
|
||||
# Remove images older than 24h (keeps recent images for rollback)
|
||||
docker image prune -a -f --filter "until=24h" || true
|
||||
DEPLOY_SCRIPT
|
||||
|
||||
@@ -10,6 +10,7 @@ on:
|
||||
- 'WORKSPACE'
|
||||
- 'MODULE.bazel'
|
||||
- 'BUILD.bazel'
|
||||
- '.bazelrc'
|
||||
- '.github/workflows/eagle_build.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
@@ -19,6 +20,7 @@ on:
|
||||
- 'WORKSPACE'
|
||||
- 'MODULE.bazel'
|
||||
- 'BUILD.bazel'
|
||||
- '.bazelrc'
|
||||
- '.github/workflows/eagle_build.yml'
|
||||
|
||||
permissions:
|
||||
|
||||
@@ -10,6 +10,7 @@ on:
|
||||
- 'src/main/resources/net/eagle0/shardok/**'
|
||||
- 'ci/BUILD.bazel'
|
||||
- 'MODULE.bazel'
|
||||
- '.bazelrc'
|
||||
- '.github/workflows/shardok_arm64_build.yml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
|
||||
@@ -11,6 +11,7 @@ on:
|
||||
- 'WORKSPACE'
|
||||
- 'MODULE.bazel'
|
||||
- 'BUILD.bazel'
|
||||
- '.bazelrc'
|
||||
- '.github/workflows/shardok_build.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
@@ -21,6 +22,7 @@ on:
|
||||
- 'WORKSPACE'
|
||||
- 'MODULE.bazel'
|
||||
- 'BUILD.bazel'
|
||||
- '.bazelrc'
|
||||
- '.github/workflows/shardok_build.yml'
|
||||
|
||||
permissions:
|
||||
|
||||
@@ -110,6 +110,10 @@ bazel run gazelle # Update Go build files
|
||||
1. **If you modified any BUILD.bazel file:** Run `bazel run gazelle` and stage any changes it makes
|
||||
2. **If you modified C++ or C# files:** Run `clang-format -i` on the modified files
|
||||
3. **If you modified Scala files:** scalafmt will run automatically via pre-commit hook
|
||||
4. **ALWAYS run the full test suite for your language changes before pushing:**
|
||||
- For Scala changes: `bazel test //src/test/scala/...`
|
||||
- For C++ changes: `bazel test //src/test/cpp/...`
|
||||
- This catches exhaustive pattern match errors and other compile-time failures that single-target builds miss
|
||||
|
||||
The pre-commit hook runs gazelle but only checks if it succeeds - it does NOT verify the BUILD files are in canonical format. The `gazelle_test` will fail if deps are not alphabetically sorted. **Always run gazelle manually after BUILD file changes.**
|
||||
|
||||
|
||||
+113
-28
@@ -1,9 +1,9 @@
|
||||
module(name = "net_eagle0")
|
||||
|
||||
# Version constants
|
||||
SCALA_VERSION = "3.7.2"
|
||||
SCALA_VERSION = "3.7.4"
|
||||
|
||||
NETTY_VERSION = "4.1.110.Final"
|
||||
NETTY_VERSION = "4.1.127.Final"
|
||||
|
||||
SCALAPB_VERSION = "1.0.0-alpha.1"
|
||||
|
||||
@@ -14,13 +14,14 @@ AWS_SDK_VERSION = "2.41.18"
|
||||
#
|
||||
|
||||
bazel_dep(name = "bazel_skylib", version = "1.9.0")
|
||||
bazel_dep(name = "platforms", version = "1.0.0")
|
||||
bazel_dep(name = "rules_pkg", version = "1.2.0")
|
||||
|
||||
#
|
||||
# Language Support - Scala
|
||||
#
|
||||
|
||||
bazel_dep(name = "rules_scala", version = "7.1.1")
|
||||
bazel_dep(name = "rules_scala", version = "7.2.1")
|
||||
|
||||
scala_config = use_extension(
|
||||
"@rules_scala//scala/extensions:config.bzl",
|
||||
@@ -128,10 +129,22 @@ use_repo(
|
||||
#
|
||||
# Platform Support - Apple/iOS
|
||||
#
|
||||
# Note: rules_apple is NOT included in the main workspace due to rules_swift
|
||||
# version conflicts with grpc. SparklePlugin (which needs rules_apple) is built
|
||||
# in a separate workspace at sparkle_workspace/ to isolate the conflict.
|
||||
#
|
||||
|
||||
bazel_dep(name = "apple_support", version = "1.21.1", repo_name = "build_bazel_apple_support")
|
||||
bazel_dep(name = "rules_apple", version = "4.3.3", repo_name = "build_bazel_rules_apple")
|
||||
bazel_dep(name = "rules_swift", version = "2.4.0", repo_name = "build_bazel_rules_swift")
|
||||
bazel_dep(name = "apple_support", version = "1.23.1", repo_name = "build_bazel_apple_support")
|
||||
|
||||
# rules_swift is a transitive dep of grpc and flatbuffers with conflicting versions:
|
||||
# - grpc 1.76.0.bcr.1 requires rules_swift 3.x (compatibility level 3)
|
||||
# - flatbuffers requires rules_swift 2.x (compatibility level 2)
|
||||
# We don't use Swift directly, but we need to force a single version.
|
||||
# Force 3.x since grpc is more complex and harder to downgrade.
|
||||
single_version_override(
|
||||
module_name = "rules_swift",
|
||||
version = "3.1.2",
|
||||
)
|
||||
|
||||
# Register Apple CC toolchain for Objective-C compilation
|
||||
apple_cc_configure = use_extension(
|
||||
@@ -144,10 +157,12 @@ use_repo(apple_cc_configure, "local_config_apple_cc")
|
||||
# Protocol Buffers & RPC
|
||||
#
|
||||
|
||||
bazel_dep(name = "protobuf", version = "29.2", repo_name = "com_google_protobuf")
|
||||
bazel_dep(name = "grpc", version = "1.71.0")
|
||||
bazel_dep(name = "grpc-java", version = "1.71.0")
|
||||
bazel_dep(name = "flatbuffers", version = "25.9.23")
|
||||
bazel_dep(name = "protobuf", version = "33.5", repo_name = "com_google_protobuf")
|
||||
bazel_dep(name = "rules_proto", version = "7.1.0")
|
||||
bazel_dep(name = "rules_cc", version = "0.2.14")
|
||||
bazel_dep(name = "grpc", version = "1.74.0")
|
||||
bazel_dep(name = "grpc-java", version = "1.78.0")
|
||||
bazel_dep(name = "flatbuffers", version = "25.12.19")
|
||||
|
||||
#
|
||||
# Testing
|
||||
@@ -160,16 +175,24 @@ bazel_dep(name = "googletest", version = "1.17.0")
|
||||
#
|
||||
|
||||
bazel_dep(name = "rules_oci", version = "2.2.7")
|
||||
bazel_dep(name = "aspect_bazel_lib", version = "2.22.4")
|
||||
bazel_dep(name = "aspect_bazel_lib", version = "2.22.5")
|
||||
|
||||
oci = use_extension("@rules_oci//oci:extensions.bzl", "oci")
|
||||
|
||||
# Base image for Eagle (Java 17 JDK - includes jcmd for JFR dumps)
|
||||
# Base image for Eagle (Java 25 JRE - smaller runtime, no dev tools needed)
|
||||
oci.pull(
|
||||
name = "eclipse_temurin_17",
|
||||
name = "eclipse_temurin_25_jre",
|
||||
image = "docker.io/library/eclipse-temurin",
|
||||
platforms = ["linux/amd64"],
|
||||
tag = "17-jdk",
|
||||
tag = "25-jre",
|
||||
)
|
||||
|
||||
# Base image for JFR sidecar (Java 25 JDK - includes jcmd for JFR dumps)
|
||||
oci.pull(
|
||||
name = "eclipse_temurin_25_jdk",
|
||||
image = "docker.io/library/eclipse-temurin",
|
||||
platforms = ["linux/amd64"],
|
||||
tag = "25-jdk",
|
||||
)
|
||||
|
||||
# Base image for Shardok (Ubuntu 24.04 for C++ runtime)
|
||||
@@ -190,13 +213,14 @@ oci.pull(
|
||||
platforms = ["linux/amd64"],
|
||||
tag = "3.21",
|
||||
)
|
||||
use_repo(oci, "alpine_linux", "alpine_linux_linux_amd64", "eclipse_temurin_17", "eclipse_temurin_17_linux_amd64", "ubuntu_24_04", "ubuntu_24_04_linux_amd64", "ubuntu_24_04_linux_arm64_v8")
|
||||
use_repo(oci, "alpine_linux", "alpine_linux_linux_amd64", "eclipse_temurin_25_jdk", "eclipse_temurin_25_jdk_linux_amd64", "eclipse_temurin_25_jre", "eclipse_temurin_25_jre_linux_amd64", "ubuntu_24_04", "ubuntu_24_04_linux_amd64", "ubuntu_24_04_linux_arm64_v8")
|
||||
|
||||
#
|
||||
# Java/Scala Dependencies
|
||||
#
|
||||
|
||||
bazel_dep(name = "rules_jvm_external", version = "6.9")
|
||||
bazel_dep(name = "rules_java", version = "9.3.0")
|
||||
bazel_dep(name = "rules_jvm_external", version = "6.10")
|
||||
|
||||
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
|
||||
maven.install(
|
||||
@@ -267,6 +291,27 @@ maven.install(
|
||||
"https://repo1.maven.org/maven2",
|
||||
],
|
||||
)
|
||||
|
||||
# Force specific versions for dependencies with conflicts between grpc-java and protobuf
|
||||
maven.artifact(
|
||||
artifact = "gson",
|
||||
force_version = True,
|
||||
group = "com.google.code.gson",
|
||||
version = "2.11.0",
|
||||
)
|
||||
maven.artifact(
|
||||
artifact = "error_prone_annotations",
|
||||
force_version = True,
|
||||
group = "com.google.errorprone",
|
||||
version = "2.30.0",
|
||||
)
|
||||
maven.artifact(
|
||||
artifact = "guava",
|
||||
force_version = True,
|
||||
group = "com.google.guava",
|
||||
version = "33.3.1-android",
|
||||
)
|
||||
|
||||
use_repo(maven, "maven", "unpinned_maven")
|
||||
|
||||
#
|
||||
@@ -283,7 +328,14 @@ GTL_SHA = "1969c45dd76eac0dd87e9e2b65cffe358617f4fe1bcd203f72f427742537913a"
|
||||
|
||||
http_archive(
|
||||
name = "gtl",
|
||||
build_file = "@//external:BUILD.gtl",
|
||||
build_file_content = """
|
||||
cc_library(
|
||||
name = "gtl",
|
||||
hdrs = glob(["include/gtl/*.hpp"]),
|
||||
includes = ["include"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = GTL_SHA,
|
||||
strip_prefix = "gtl-%s" % GTL_VERSION,
|
||||
url = "https://github.com/greg7mdp/gtl/archive/refs/tags/v%s.zip" % GTL_VERSION,
|
||||
@@ -303,16 +355,8 @@ http_archive(
|
||||
],
|
||||
)
|
||||
|
||||
# Sparkle framework for macOS auto-updates
|
||||
SPARKLE_VERSION = "2.6.4"
|
||||
|
||||
http_archive(
|
||||
name = "sparkle",
|
||||
build_file = "@//external:BUILD.sparkle",
|
||||
sha256 = "50612a06038abc931f16011d7903b8326a362c1074dabccb718404ce8e585f0b",
|
||||
strip_prefix = "",
|
||||
url = "https://github.com/sparkle-project/Sparkle/releases/download/%s/Sparkle-%s.tar.xz" % (SPARKLE_VERSION, SPARKLE_VERSION),
|
||||
)
|
||||
# Note: Sparkle framework is defined in sparkle_workspace/MODULE.bazel
|
||||
# (not in main workspace due to rules_swift version conflicts)
|
||||
|
||||
# Busybox static binary for Docker health checks (provides nc, wget, etc.)
|
||||
# Primary: DigitalOcean Spaces (public, reliable)
|
||||
@@ -346,7 +390,48 @@ LLVM_MINGW_VERSION = "20250305"
|
||||
|
||||
http_archive(
|
||||
name = "llvm_mingw",
|
||||
build_file = "@//external:BUILD.llvm_mingw",
|
||||
build_file_content = """
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
filegroup(
|
||||
name = "all_files",
|
||||
srcs = glob(["**/*"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "compiler_files",
|
||||
srcs = glob([
|
||||
"bin/x86_64-w64-mingw32-*",
|
||||
"bin/clang*",
|
||||
"bin/llvm-*",
|
||||
"bin/lld*",
|
||||
]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "windows_x86_64_sysroot",
|
||||
srcs = glob([
|
||||
"x86_64-w64-mingw32/**/*",
|
||||
"generic-w64-mingw32/include/**/*",
|
||||
]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "linker_files",
|
||||
srcs = glob([
|
||||
"bin/x86_64-w64-mingw32-*",
|
||||
"bin/lld*",
|
||||
"bin/ld.lld*",
|
||||
"lib/**/*",
|
||||
"x86_64-w64-mingw32/lib/**/*",
|
||||
]),
|
||||
)
|
||||
|
||||
exports_files([
|
||||
"bin/x86_64-w64-mingw32-clang",
|
||||
"bin/x86_64-w64-mingw32-clang++",
|
||||
])
|
||||
""",
|
||||
sha256 = "32c24fc62fc8b9f8a900bf2c730b78b36767688f816f9d21e97a168289ff44e0",
|
||||
strip_prefix = "llvm-mingw-%s-ucrt-macos-14.4.1-universal" % LLVM_MINGW_VERSION,
|
||||
urls = ["https://github.com/fathonix/llvm-mingw-arm64ec-macos/releases/download/%s/llvm-mingw-%s-ucrt-macos-14.4.1-universal.tar.xz" % (LLVM_MINGW_VERSION, LLVM_MINGW_VERSION)],
|
||||
|
||||
Generated
+1074
-4432
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -73,7 +73,7 @@ pkg_tar(
|
||||
|
||||
oci_image(
|
||||
name = "eagle_server_image",
|
||||
base = "@eclipse_temurin_17_linux_amd64",
|
||||
base = "@eclipse_temurin_25_jre_linux_amd64",
|
||||
entrypoint = [
|
||||
"java",
|
||||
"-Xmx2g",
|
||||
@@ -288,7 +288,7 @@ pkg_tar(
|
||||
oci_image(
|
||||
name = "jfr_sidecar_image",
|
||||
# Use JDK base image - we need jcmd to dump JFR recordings
|
||||
base = "@eclipse_temurin_17_linux_amd64",
|
||||
base = "@eclipse_temurin_25_jdk_linux_amd64",
|
||||
entrypoint = ["/app/jfr_server_linux_amd64"],
|
||||
exposed_ports = ["8081/tcp"],
|
||||
tars = [
|
||||
|
||||
@@ -211,10 +211,10 @@ services:
|
||||
environment:
|
||||
# Secret for CI to authenticate client update notifications
|
||||
NOTIFY_SECRET: "${NOTIFY_SECRET:-}"
|
||||
# S3/Spaces credentials for What's New storage
|
||||
# S3/Spaces credentials for What's New storage (uses eagle0-assets bucket)
|
||||
DO_SPACES_ENDPOINT: "${DO_SPACES_ENDPOINT:-https://sfo3.digitaloceanspaces.com}"
|
||||
DO_SPACES_ACCESS_KEY: "${DO_SPACES_ACCESS_KEY:-}"
|
||||
DO_SPACES_SECRET_KEY: "${DO_SPACES_SECRET_KEY:-}"
|
||||
DO_SPACES_ACCESS_KEY: "${ADMIN_S3_ACCESS_KEY:-}"
|
||||
DO_SPACES_SECRET_KEY: "${ADMIN_S3_SECRET_KEY:-}"
|
||||
# No external port - accessed via nginx at admin.eagle0.net
|
||||
depends_on:
|
||||
- auth
|
||||
|
||||
@@ -12,7 +12,14 @@ When adding new quest types, use a three-PR strategy to ensure clients never see
|
||||
|
||||
3. **PR 3 - Quest Generation (Server)**: Add the actual quest creation logic to `QuestCreationUtils.scala`.
|
||||
|
||||
This order ensures that when the server starts generating the new quest type, all clients already know how to display it.
|
||||
**PR Dependencies:**
|
||||
```
|
||||
PR 1 (types)
|
||||
├── PR 2 (client)
|
||||
└── PR 3 (generation)
|
||||
```
|
||||
|
||||
PR 2 and PR 3 both depend on PR 1, but are independent of each other. They can be developed in parallel after PR 1 is merged, and merged in either order. The key constraint is that PR 3 should not be deployed before PR 2, so clients understand the quest type before the server starts generating it.
|
||||
|
||||
## Files to Modify
|
||||
|
||||
|
||||
+5
-2
@@ -182,11 +182,14 @@ All 26 tracks have CC licenses with proper attribution:
|
||||
- `failure_horn.mp3` - licensing issue, no replacement found in purchased assets
|
||||
- ~~`runaway.mp3`~~ - **REPLACED** (2026-01-27) with `MedievalArmyRunningLoop.mp3` from Freesound (CC BY 4.0)
|
||||
|
||||
**Presumed from Unity Asset Store purchases (31 files):**
|
||||
**Verified from [Medieval Combat Sounds](https://assetstore.unity.com/packages/audio/sound-fx/medieval-combat-sounds-100465) (Unity Asset Store):**
|
||||
- `duel_challenged.wav` - **REPLACED** (2026-02-03) with `Weapon Draw Metal 1.wav` from Medieval Combat Sounds
|
||||
|
||||
**Presumed from Unity Asset Store purchases (30 files):**
|
||||
Owner believes these are from: Fantasy Interface Sounds, Medieval Combat Sounds, Magic Spells Sound Effects LITE, and/or Medieval Battle Sound Pack.
|
||||
- `archery.mp3`, `battle_shout.mp3`, `boo.mp3`, `braved_water.mp3`
|
||||
- `build_bridge.mp3`, `build_bridge_failure.mp3`, `charge.mp3`
|
||||
- `dismiss_unit.mp3`, `duel_challenged.mp3`, `failure_horn.mp3`, `fear.mp3`, `fear_failed.mp3`
|
||||
- `dismiss_unit.mp3`, `failure_horn.mp3`, `fear.mp3`, `fear_failed.mp3`
|
||||
- `fire_extinguish.mp3`, `fire_spread.mp3`, `fire_start.mp3`, `fire_start_failure.mp3`
|
||||
- `freeze.mp3`, `holy_wave.mp3`, `holy_wave_damage.mp3`, `jail_door.mp3`, `lightning.mp3`
|
||||
- `melee.mp3`, `meteor.mp3`, `mind_control.mp3`, `move.mp3`, `move 1.mp3`
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
# rules_apple Workspace Separation
|
||||
|
||||
This document explains why `rules_apple` is built in a separate Bazel workspace (`sparkle_workspace/`) and what conditions need to be met before it can be reintegrated into the main workspace.
|
||||
|
||||
## Background
|
||||
|
||||
The main workspace cannot include `rules_apple` due to transitive dependency conflicts with `rules_swift`. Multiple dependencies require different major versions of `rules_swift`:
|
||||
|
||||
| Dependency | rules_swift Version | Compatibility Level |
|
||||
|------------|---------------------|---------------------|
|
||||
| grpc | 3.x | 3 |
|
||||
| flatbuffers | 2.x | 2 |
|
||||
| rules_apple | 2.x | 2 |
|
||||
|
||||
Bzlmod's `single_version_override` can force a single version, but compatibility levels 2 and 3 are incompatible. Forcing `rules_swift` 3.x (required for grpc) breaks `rules_apple` and `flatbuffers`.
|
||||
|
||||
## Current Solution
|
||||
|
||||
The `SparklePlugin` (the only component requiring `rules_apple`) is built in an isolated workspace:
|
||||
|
||||
```
|
||||
sparkle_workspace/
|
||||
├── MODULE.bazel # Minimal deps: apple_support, rules_apple, sparkle
|
||||
├── BUILD.bazel # Builds SparklePlugin.bundle
|
||||
├── SparklePlugin.m # Objective-C source
|
||||
├── Info.plist # Bundle metadata
|
||||
└── external/
|
||||
└── BUILD.sparkle # Build file for Sparkle framework
|
||||
```
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Build script**: `scripts/build_sparkle_plugin.sh` builds the plugin from the separate workspace
|
||||
2. **Output**: The built `SparklePlugin.bundle` is placed in `Assets/Plugins/macOS/`
|
||||
3. **CI integration**: `mac_build.yml` calls `inject_sparkle.sh` to embed Sparkle into the Mac app
|
||||
|
||||
The main workspace uses `single_version_override` for `rules_swift` 3.x to satisfy grpc, and includes a comment noting that `rules_apple` is intentionally excluded.
|
||||
|
||||
## What SparklePlugin Does
|
||||
|
||||
SparklePlugin is a native macOS library that:
|
||||
- Initializes the [Sparkle](https://sparkle-project.org/) auto-update framework
|
||||
- Exposes C functions for Unity to call via P/Invoke:
|
||||
- `SparklePlugin_Initialize`
|
||||
- `SparklePlugin_CheckForUpdates`
|
||||
- `SparklePlugin_CheckForUpdatesInBackground`
|
||||
- `SparklePlugin_IsCheckingForUpdates`
|
||||
- `SparklePlugin_GetAutomaticallyChecksForUpdates`
|
||||
- `SparklePlugin_SetAutomaticallyChecksForUpdates`
|
||||
- `SparklePlugin_IsRunningFromReadOnlyVolume`
|
||||
- `SparklePlugin_ShowDMGWarning`
|
||||
|
||||
## Conditions for Reintegration
|
||||
|
||||
To move `rules_apple` back into the main workspace, **all** of the following must be true:
|
||||
|
||||
### 1. rules_swift Version Alignment
|
||||
|
||||
Check if grpc, flatbuffers, and rules_apple all support the same `rules_swift` major version:
|
||||
|
||||
```bash
|
||||
# Check what rules_swift version each dependency requires
|
||||
bazel mod graph 2>&1 | grep -A2 "rules_swift"
|
||||
```
|
||||
|
||||
Or check BCR directly:
|
||||
- https://registry.bazel.build/modules/grpc
|
||||
- https://registry.bazel.build/modules/flatbuffers
|
||||
- https://registry.bazel.build/modules/rules_apple
|
||||
|
||||
**Test**: After updating versions, verify you can add this to MODULE.bazel without errors:
|
||||
```python
|
||||
bazel_dep(name = "rules_apple", version = "X.Y.Z")
|
||||
```
|
||||
|
||||
### 2. Build Test
|
||||
|
||||
If the dependency can be added, test that both the main build and SparklePlugin work:
|
||||
|
||||
```bash
|
||||
# Main workspace builds
|
||||
bazel build //src/main/scala/net/eagle0/eagle:eagle_server
|
||||
bazel build //src/main/cpp/net/eagle0/shardok:shardok-server
|
||||
bazel build //ci:eagle_server_image
|
||||
|
||||
# SparklePlugin builds (would move to main workspace)
|
||||
bazel build //sparkle:SparklePlugin # After moving files
|
||||
```
|
||||
|
||||
### 3. Files to Move
|
||||
|
||||
When reintegrating, move these from `sparkle_workspace/` to the main workspace:
|
||||
|
||||
| Source | Destination |
|
||||
|--------|-------------|
|
||||
| `sparkle_workspace/SparklePlugin.m` | `src/main/objc/net/eagle0/sparkle/SparklePlugin.m` |
|
||||
| `sparkle_workspace/Info.plist` | `src/main/objc/net/eagle0/sparkle/Info.plist` |
|
||||
| `sparkle_workspace/BUILD.bazel` | `src/main/objc/net/eagle0/sparkle/BUILD.bazel` |
|
||||
| `sparkle_workspace/external/BUILD.sparkle` | (inline into MODULE.bazel http_archive) |
|
||||
|
||||
### 4. MODULE.bazel Changes
|
||||
|
||||
Add to the main MODULE.bazel:
|
||||
|
||||
```python
|
||||
bazel_dep(name = "rules_apple", version = "X.Y.Z", repo_name = "build_bazel_rules_apple")
|
||||
|
||||
# Sparkle framework
|
||||
http_archive(
|
||||
name = "sparkle",
|
||||
build_file_content = """...""", # Contents from external/BUILD.sparkle
|
||||
sha256 = "...",
|
||||
url = "https://github.com/sparkle-project/Sparkle/releases/download/...",
|
||||
)
|
||||
```
|
||||
|
||||
Remove the `single_version_override` for `rules_swift` if no longer needed.
|
||||
|
||||
### 5. Update Build Scripts
|
||||
|
||||
- Update `scripts/build_sparkle_plugin.sh` to build from main workspace
|
||||
- Update `scripts/build_plugins.sh` if it references the separate workspace
|
||||
- Verify `mac_build.yml` still works
|
||||
|
||||
### 6. Cleanup
|
||||
|
||||
After successful integration:
|
||||
```bash
|
||||
rm -rf sparkle_workspace/
|
||||
```
|
||||
|
||||
Update comments in MODULE.bazel that reference the separate workspace.
|
||||
|
||||
## Version History
|
||||
|
||||
| Date | Event |
|
||||
|------|-------|
|
||||
| 2026-02-04 | Separated sparkle_workspace (PR #5882) to enable Bazel 8 upgrade |
|
||||
| 2026-02-05 | Upgraded to Bazel 8.5.1 (PR #5883) |
|
||||
|
||||
## Monitoring
|
||||
|
||||
Periodically check if the upstream dependencies have aligned:
|
||||
|
||||
1. **grpc releases**: https://github.com/grpc/grpc/releases
|
||||
2. **flatbuffers releases**: https://github.com/google/flatbuffers/releases
|
||||
3. **rules_apple releases**: https://github.com/bazelbuild/rules_apple/releases
|
||||
4. **BCR updates**: https://registry.bazel.build/
|
||||
|
||||
When a new version of any of these is released, check if the `rules_swift` requirements have converged.
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
# Export BUILD files for use with http_archive build_file attribute
|
||||
exports_files([
|
||||
"BUILD.gtl",
|
||||
"BUILD.llvm_mingw",
|
||||
])
|
||||
|
||||
+343
-75
@@ -1,21 +1,226 @@
|
||||
{
|
||||
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
|
||||
"__INPUT_ARTIFACTS_HASH": 434250008,
|
||||
"__RESOLVED_ARTIFACTS_HASH": -824975294,
|
||||
"__INPUT_ARTIFACTS_HASH": {
|
||||
"com.amazonaws:aws-lambda-java-core": -2008008480,
|
||||
"com.amazonaws:aws-lambda-java-events": 904769795,
|
||||
"com.google.android:annotations": 1910180409,
|
||||
"com.google.api.grpc:proto-google-common-protos": -2106826238,
|
||||
"com.google.auth:google-auth-library-credentials": 1149797254,
|
||||
"com.google.auth:google-auth-library-oauth2-http": -2102758232,
|
||||
"com.google.auto.value:auto-value": 1146221104,
|
||||
"com.google.auto.value:auto-value-annotations": -1101276935,
|
||||
"com.google.code.findbugs:jsr305": 495355163,
|
||||
"com.google.code.gson:gson": 1675696798,
|
||||
"com.google.errorprone:error_prone_annotations": 692295270,
|
||||
"com.google.guava:failureaccess": 1582410452,
|
||||
"com.google.guava:guava": 174556251,
|
||||
"com.google.j2objc:j2objc-annotations": 2003271689,
|
||||
"com.google.protobuf:protobuf-java": -1795397632,
|
||||
"com.google.protobuf:protobuf-java-util": -1033086717,
|
||||
"com.google.re2j:re2j": 1525409503,
|
||||
"com.google.s2a.proto.v2:s2a-proto": 898932763,
|
||||
"com.google.truth:truth": 1696781452,
|
||||
"com.nimbusds:nimbus-jose-jwt": 200797458,
|
||||
"com.squareup.okhttp3:okhttp": 916942239,
|
||||
"com.squareup.okhttp3:okhttp-sse": 1714840279,
|
||||
"com.squareup.okhttp:okhttp": -1467174407,
|
||||
"com.squareup.okio:okio": 795722926,
|
||||
"com.thesamet.scalapb:compilerplugin_3": -756207945,
|
||||
"com.thesamet.scalapb:lenses_3": 1060875741,
|
||||
"com.thesamet.scalapb:protoc-bridge_3": -1260006911,
|
||||
"com.thesamet.scalapb:scalapb-json4s_3": -772830803,
|
||||
"com.thesamet.scalapb:scalapb-runtime-grpc_3": 908736225,
|
||||
"com.thesamet.scalapb:scalapb-runtime_3": 1652882204,
|
||||
"io.netty:netty-buffer": -36891658,
|
||||
"io.netty:netty-codec": -1968637428,
|
||||
"io.netty:netty-codec-http": 2069139895,
|
||||
"io.netty:netty-codec-http2": 980426895,
|
||||
"io.netty:netty-codec-socks": -1802651606,
|
||||
"io.netty:netty-common": -644663253,
|
||||
"io.netty:netty-handler": 1555108312,
|
||||
"io.netty:netty-handler-proxy": -964658153,
|
||||
"io.netty:netty-resolver": -1317606544,
|
||||
"io.netty:netty-tcnative-boringssl-static": 2033070843,
|
||||
"io.netty:netty-tcnative-classes": 2023773715,
|
||||
"io.netty:netty-transport": 1563151065,
|
||||
"io.netty:netty-transport-native-epoll": -1215800119,
|
||||
"io.netty:netty-transport-native-unix-common": -818773192,
|
||||
"io.opencensus:opencensus-api": 2042364617,
|
||||
"io.opencensus:opencensus-contrib-grpc-metrics": 317094357,
|
||||
"io.perfmark:perfmark-api": 1019157794,
|
||||
"io.sentry:sentry": -947045362,
|
||||
"javax.xml.bind:jaxb-api": -1735500680,
|
||||
"junit:junit": -744267592,
|
||||
"org.checkerframework:checker-qual": -819031361,
|
||||
"org.codehaus.mojo:animal-sniffer-annotations": -1634689353,
|
||||
"org.json4s:json4s-ast_3": 687176866,
|
||||
"org.json4s:json4s-core_3": 977579605,
|
||||
"org.json4s:json4s-native_3": -123383795,
|
||||
"org.reactivestreams:reactive-streams": 509083534,
|
||||
"org.scalamock:scalamock_3": -610483078,
|
||||
"org.slf4j:slf4j-api": 1609745898,
|
||||
"org.slf4j:slf4j-simple": 1319506696,
|
||||
"repositories": -1949687017,
|
||||
"software.amazon.awssdk:aws-core": 1764800397,
|
||||
"software.amazon.awssdk:http-client-spi": 1697477859,
|
||||
"software.amazon.awssdk:regions": -663595789,
|
||||
"software.amazon.awssdk:s3": -544649668,
|
||||
"software.amazon.awssdk:s3-transfer-manager": -1414083014,
|
||||
"software.amazon.awssdk:sdk-core": -1921023350,
|
||||
"software.amazon.awssdk:utils": 1323800129
|
||||
},
|
||||
"__RESOLVED_ARTIFACTS_HASH": {
|
||||
"com.amazonaws:aws-lambda-java-core": 930138565,
|
||||
"com.amazonaws:aws-lambda-java-events": 582075020,
|
||||
"com.fasterxml.jackson.core:jackson-annotations": 1276887193,
|
||||
"com.fasterxml.jackson.core:jackson-core": 439118590,
|
||||
"com.fasterxml.jackson.core:jackson-databind": 1897319963,
|
||||
"com.github.stephenc.jcip:jcip-annotations": 2084352561,
|
||||
"com.google.android:annotations": 2096496032,
|
||||
"com.google.api.grpc:proto-google-common-protos": 2069379049,
|
||||
"com.google.api:api-common": -597713164,
|
||||
"com.google.auth:google-auth-library-credentials": -366937256,
|
||||
"com.google.auth:google-auth-library-oauth2-http": -472658017,
|
||||
"com.google.auto.value:auto-value": 1110951021,
|
||||
"com.google.auto.value:auto-value-annotations": 641018093,
|
||||
"com.google.code.findbugs:jsr305": 870839855,
|
||||
"com.google.code.gson:gson": 614185888,
|
||||
"com.google.errorprone:error_prone_annotations": -1097264484,
|
||||
"com.google.guava:failureaccess": -718864417,
|
||||
"com.google.guava:guava": 631608943,
|
||||
"com.google.guava:listenablefuture": 1079558157,
|
||||
"com.google.http-client:google-http-client": 418651909,
|
||||
"com.google.http-client:google-http-client-gson": -48153131,
|
||||
"com.google.j2objc:j2objc-annotations": -404209759,
|
||||
"com.google.protobuf:protobuf-java": 1668417350,
|
||||
"com.google.protobuf:protobuf-java-util": 1986864820,
|
||||
"com.google.re2j:re2j": -1688126233,
|
||||
"com.google.s2a.proto.v2:s2a-proto": 1518288545,
|
||||
"com.google.truth:truth": -1338076935,
|
||||
"com.nimbusds:nimbus-jose-jwt": -1437437976,
|
||||
"com.squareup.okhttp3:okhttp": 1262276211,
|
||||
"com.squareup.okhttp3:okhttp-sse": 505395183,
|
||||
"com.squareup.okhttp:okhttp": -1958498367,
|
||||
"com.squareup.okio:okio": -993505667,
|
||||
"com.squareup.okio:okio-jvm": 2073967287,
|
||||
"com.thesamet.scalapb:compilerplugin_3": -1711749067,
|
||||
"com.thesamet.scalapb:lenses_3": 81185934,
|
||||
"com.thesamet.scalapb:protoc-bridge_2.13": -1602581734,
|
||||
"com.thesamet.scalapb:protoc-bridge_3": -350123056,
|
||||
"com.thesamet.scalapb:protoc-gen_2.13": -1004483995,
|
||||
"com.thesamet.scalapb:scalapb-json4s_3": -1395179337,
|
||||
"com.thesamet.scalapb:scalapb-runtime-grpc_3": 1440887312,
|
||||
"com.thesamet.scalapb:scalapb-runtime_3": -298320448,
|
||||
"commons-codec:commons-codec": 1208138832,
|
||||
"commons-logging:commons-logging": 1248790901,
|
||||
"dev.dirs:directories": 513669062,
|
||||
"io.grpc:grpc-api": 1519481799,
|
||||
"io.grpc:grpc-context": 1273832094,
|
||||
"io.grpc:grpc-protobuf": -1491986464,
|
||||
"io.grpc:grpc-protobuf-lite": 1996390382,
|
||||
"io.grpc:grpc-stub": 206724158,
|
||||
"io.netty:netty-buffer": 1883825690,
|
||||
"io.netty:netty-codec": 1759679007,
|
||||
"io.netty:netty-codec-http": -965628835,
|
||||
"io.netty:netty-codec-http2": -631439859,
|
||||
"io.netty:netty-codec-socks": 1385966058,
|
||||
"io.netty:netty-common": -1574327641,
|
||||
"io.netty:netty-handler": 1812678974,
|
||||
"io.netty:netty-handler-proxy": 452260541,
|
||||
"io.netty:netty-resolver": -656912885,
|
||||
"io.netty:netty-tcnative-boringssl-static": -1618728145,
|
||||
"io.netty:netty-tcnative-boringssl-static:jar:linux-aarch_64": -46670590,
|
||||
"io.netty:netty-tcnative-boringssl-static:jar:linux-x86_64": -323938727,
|
||||
"io.netty:netty-tcnative-boringssl-static:jar:osx-aarch_64": 1027623299,
|
||||
"io.netty:netty-tcnative-boringssl-static:jar:osx-x86_64": -322798677,
|
||||
"io.netty:netty-tcnative-boringssl-static:jar:windows-x86_64": 1803328375,
|
||||
"io.netty:netty-tcnative-classes": -498572591,
|
||||
"io.netty:netty-transport": 764254626,
|
||||
"io.netty:netty-transport-classes-epoll": 1006952729,
|
||||
"io.netty:netty-transport-native-epoll:jar:linux-x86_64": -737288378,
|
||||
"io.netty:netty-transport-native-unix-common": -1442019057,
|
||||
"io.opencensus:opencensus-api": 516564413,
|
||||
"io.opencensus:opencensus-contrib-grpc-metrics": -412818674,
|
||||
"io.opencensus:opencensus-contrib-http-util": 1093902672,
|
||||
"io.perfmark:perfmark-api": -1795841558,
|
||||
"io.sentry:sentry": 1818358364,
|
||||
"javax.activation:javax.activation-api": 1384047725,
|
||||
"javax.annotation:javax.annotation-api": -1009230154,
|
||||
"javax.xml.bind:jaxb-api": 238614541,
|
||||
"joda-time:joda-time": -926621536,
|
||||
"junit:junit": -1256429642,
|
||||
"org.apache.httpcomponents:httpclient": 546847276,
|
||||
"org.apache.httpcomponents:httpcore": 67453319,
|
||||
"org.checkerframework:checker-qual": 1860567376,
|
||||
"org.codehaus.mojo:animal-sniffer-annotations": -1201443841,
|
||||
"org.hamcrest:hamcrest-core": 649657847,
|
||||
"org.jetbrains.kotlin:kotlin-stdlib": -879725260,
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-common": 393704220,
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-jdk7": 1242909803,
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-jdk8": -597817274,
|
||||
"org.jetbrains:annotations": 554168982,
|
||||
"org.json4s:json4s-ast_3": -1000402007,
|
||||
"org.json4s:json4s-core_3": -1662557228,
|
||||
"org.json4s:json4s-jackson-core_3": -1868355082,
|
||||
"org.json4s:json4s-native-core_3": 227547325,
|
||||
"org.json4s:json4s-native_3": 1646180259,
|
||||
"org.jspecify:jspecify": 117231129,
|
||||
"org.ow2.asm:asm": 611381606,
|
||||
"org.reactivestreams:reactive-streams": 1281941191,
|
||||
"org.scala-lang.modules:scala-collection-compat_3": 1599811889,
|
||||
"org.scala-lang:scala-library": -1079389784,
|
||||
"org.scala-lang:scala3-library_3": -212752345,
|
||||
"org.scalamock:scalamock_3": -1778657085,
|
||||
"org.slf4j:slf4j-api": -771685699,
|
||||
"org.slf4j:slf4j-simple": -776509812,
|
||||
"software.amazon.awssdk:annotations": -324257201,
|
||||
"software.amazon.awssdk:apache-client": 2066024214,
|
||||
"software.amazon.awssdk:arns": -1240703529,
|
||||
"software.amazon.awssdk:auth": 1612047768,
|
||||
"software.amazon.awssdk:aws-core": -62367447,
|
||||
"software.amazon.awssdk:aws-query-protocol": 570551548,
|
||||
"software.amazon.awssdk:aws-xml-protocol": -1850136736,
|
||||
"software.amazon.awssdk:checksums": -238416593,
|
||||
"software.amazon.awssdk:checksums-spi": 807336878,
|
||||
"software.amazon.awssdk:crt-core": 280528066,
|
||||
"software.amazon.awssdk:endpoints-spi": -241689351,
|
||||
"software.amazon.awssdk:http-auth": 236194098,
|
||||
"software.amazon.awssdk:http-auth-aws": -385949349,
|
||||
"software.amazon.awssdk:http-auth-aws-eventstream": -408169305,
|
||||
"software.amazon.awssdk:http-auth-spi": 211732368,
|
||||
"software.amazon.awssdk:http-client-spi": -1646055035,
|
||||
"software.amazon.awssdk:identity-spi": 90960913,
|
||||
"software.amazon.awssdk:json-utils": 740192539,
|
||||
"software.amazon.awssdk:metrics-spi": 692846272,
|
||||
"software.amazon.awssdk:netty-nio-client": 94159754,
|
||||
"software.amazon.awssdk:profiles": 1441805445,
|
||||
"software.amazon.awssdk:protocol-core": 204998161,
|
||||
"software.amazon.awssdk:regions": 407633714,
|
||||
"software.amazon.awssdk:retries": 1892797724,
|
||||
"software.amazon.awssdk:retries-spi": -2126209698,
|
||||
"software.amazon.awssdk:s3": -829433125,
|
||||
"software.amazon.awssdk:s3-transfer-manager": 761695256,
|
||||
"software.amazon.awssdk:sdk-core": 78965981,
|
||||
"software.amazon.awssdk:third-party-jackson-core": 24776375,
|
||||
"software.amazon.awssdk:utils": -1896886996,
|
||||
"software.amazon.awssdk:utils-lite": -446744113,
|
||||
"software.amazon.eventstream:eventstream": 666815114
|
||||
},
|
||||
"conflict_resolution": {
|
||||
"com.google.guava:failureaccess:1.0.1": "com.google.guava:failureaccess:1.0.2",
|
||||
"com.google.j2objc:j2objc-annotations:2.8": "com.google.j2objc:j2objc-annotations:3.0.0",
|
||||
"com.google.protobuf:protobuf-java:4.27.2": "com.google.protobuf:protobuf-java:4.28.2",
|
||||
"com.squareup.okio:okio:2.10.0": "com.squareup.okio:okio:3.6.0",
|
||||
"io.netty:netty-buffer:4.1.110.Final": "io.netty:netty-buffer:4.1.130.Final",
|
||||
"io.netty:netty-codec-http2:4.1.110.Final": "io.netty:netty-codec-http2:4.1.130.Final",
|
||||
"io.netty:netty-codec-http:4.1.110.Final": "io.netty:netty-codec-http:4.1.130.Final",
|
||||
"io.netty:netty-codec:4.1.110.Final": "io.netty:netty-codec:4.1.130.Final",
|
||||
"io.netty:netty-common:4.1.110.Final": "io.netty:netty-common:4.1.130.Final",
|
||||
"io.netty:netty-handler:4.1.110.Final": "io.netty:netty-handler:4.1.130.Final",
|
||||
"io.netty:netty-resolver:4.1.110.Final": "io.netty:netty-resolver:4.1.130.Final",
|
||||
"io.netty:netty-transport-native-unix-common:4.1.110.Final": "io.netty:netty-transport-native-unix-common:4.1.130.Final",
|
||||
"io.netty:netty-transport:4.1.110.Final": "io.netty:netty-transport:4.1.130.Final",
|
||||
"io.opencensus:opencensus-api:0.31.0": "io.opencensus:opencensus-api:0.31.1",
|
||||
"org.checkerframework:checker-qual:3.12.0": "org.checkerframework:checker-qual:3.43.0"
|
||||
"io.netty:netty-buffer:4.1.127.Final": "io.netty:netty-buffer:4.1.130.Final",
|
||||
"io.netty:netty-codec-http2:4.1.127.Final": "io.netty:netty-codec-http2:4.1.130.Final",
|
||||
"io.netty:netty-codec-http:4.1.127.Final": "io.netty:netty-codec-http:4.1.130.Final",
|
||||
"io.netty:netty-codec:4.1.127.Final": "io.netty:netty-codec:4.1.130.Final",
|
||||
"io.netty:netty-common:4.1.127.Final": "io.netty:netty-common:4.1.130.Final",
|
||||
"io.netty:netty-handler:4.1.127.Final": "io.netty:netty-handler:4.1.130.Final",
|
||||
"io.netty:netty-resolver:4.1.127.Final": "io.netty:netty-resolver:4.1.130.Final",
|
||||
"io.netty:netty-transport-native-unix-common:4.1.127.Final": "io.netty:netty-transport-native-unix-common:4.1.130.Final",
|
||||
"io.netty:netty-transport:4.1.127.Final": "io.netty:netty-transport:4.1.130.Final",
|
||||
"io.opencensus:opencensus-api:0.31.0": "io.opencensus:opencensus-api:0.31.1"
|
||||
},
|
||||
"artifacts": {
|
||||
"com.amazonaws:aws-lambda-java-core": {
|
||||
@@ -62,21 +267,27 @@
|
||||
},
|
||||
"com.google.api.grpc:proto-google-common-protos": {
|
||||
"shasums": {
|
||||
"jar": "0b27938f3d28ccd6884945d7e4f75f4e26a677bbf3cd39bbcb694f130f782aa9"
|
||||
"jar": "352ffc769f4d17e2d6227b6893ec368f4f07fbb069dd7aaa644b16949369f8b7"
|
||||
},
|
||||
"version": "2.51.0"
|
||||
"version": "2.63.1"
|
||||
},
|
||||
"com.google.api:api-common": {
|
||||
"shasums": {
|
||||
"jar": "f7073fb389c2aa329981ee65241db7947e8744c988e6c4d975f18bf2748b935a"
|
||||
},
|
||||
"version": "2.53.0"
|
||||
},
|
||||
"com.google.auth:google-auth-library-credentials": {
|
||||
"shasums": {
|
||||
"jar": "5dbf1207d14e093f67995f457cb69c3cf49bed1364150b23465e09acada65d96"
|
||||
"jar": "dd7e39b8f5c366b09f8c2d400b7b63c925499df813b0f0d78044abd72098e159"
|
||||
},
|
||||
"version": "1.24.1"
|
||||
"version": "1.40.0"
|
||||
},
|
||||
"com.google.auth:google-auth-library-oauth2-http": {
|
||||
"shasums": {
|
||||
"jar": "88a75cd4448ea2f3b46e48a89497a6cf0985a5fa4e21274af4940e07f59f6eaf"
|
||||
"jar": "67fe2c9df9780d8725c1dff61d2ffbbcb93fdcf15e91c44a5e610a4a69afd151"
|
||||
},
|
||||
"version": "1.24.1"
|
||||
"version": "1.40.0"
|
||||
},
|
||||
"com.google.auto.value:auto-value": {
|
||||
"shasums": {
|
||||
@@ -128,15 +339,15 @@
|
||||
},
|
||||
"com.google.http-client:google-http-client": {
|
||||
"shasums": {
|
||||
"jar": "390618d7b51704240b8fd28e1230fa35d220f93f4b4ba80f63e38db00dacb09e"
|
||||
"jar": "97a0666340956dbc96893bc8cf843a5b57367543f218feddad3ff433fbfdaa68"
|
||||
},
|
||||
"version": "1.44.2"
|
||||
"version": "2.0.2"
|
||||
},
|
||||
"com.google.http-client:google-http-client-gson": {
|
||||
"shasums": {
|
||||
"jar": "1119b66685195310375b717de2215d6c5d14fa8ed9f57e07b4fecd461e7b9db7"
|
||||
"jar": "37c8fd5c7869bc4abf3b3219c7e79cb566afa745559772e969c21595199600cd"
|
||||
},
|
||||
"version": "1.44.2"
|
||||
"version": "2.0.2"
|
||||
},
|
||||
"com.google.j2objc:j2objc-annotations": {
|
||||
"shasums": {
|
||||
@@ -150,17 +361,29 @@
|
||||
},
|
||||
"version": "4.28.2"
|
||||
},
|
||||
"com.google.protobuf:protobuf-java-util": {
|
||||
"shasums": {
|
||||
"jar": "a2665294d3e4675482bde593df8283f8c965f0207785e8e9b223f790644f5b08"
|
||||
},
|
||||
"version": "4.27.2"
|
||||
},
|
||||
"com.google.re2j:re2j": {
|
||||
"shasums": {
|
||||
"jar": "7b52c72156dd7f98b3237a5b35c1d34fba381b21048c89208913ad80a45dfbd7"
|
||||
},
|
||||
"version": "1.8"
|
||||
},
|
||||
"com.google.s2a.proto.v2:s2a-proto": {
|
||||
"shasums": {
|
||||
"jar": "3205a05a82003067fbbd28ec0381d4c75258c25eb772d37be62e8b12d0402936"
|
||||
},
|
||||
"version": "0.1.3"
|
||||
},
|
||||
"com.google.truth:truth": {
|
||||
"shasums": {
|
||||
"jar": "14c297bc64ca8bc15b6baf67f160627e4562ec91624797e312e907b431113508"
|
||||
"jar": "a6409e90fdd6b31f239b0c02065c43b53e1b09c72f2e08c3a86d04fe5910cf4b"
|
||||
},
|
||||
"version": "1.4.2"
|
||||
"version": "1.4.5"
|
||||
},
|
||||
"com.nimbusds:nimbus-jose-jwt": {
|
||||
"shasums": {
|
||||
@@ -266,33 +489,33 @@
|
||||
},
|
||||
"io.grpc:grpc-api": {
|
||||
"shasums": {
|
||||
"jar": "b5120a11da5ce5ddfab019bbb69f5868529c9b5def1ba5b283251cc95fb3ba91"
|
||||
"jar": "45faf2ac1bf2791e8fdabce53684a86b62c99b84cba26fb13a5ba3f4abf80d6c"
|
||||
},
|
||||
"version": "1.68.0"
|
||||
"version": "1.70.0"
|
||||
},
|
||||
"io.grpc:grpc-context": {
|
||||
"shasums": {
|
||||
"jar": "4ab6efb9cbadc88f8dc723ada3a61785da367697373d4432aef5222312aa70f6"
|
||||
"jar": "eb2824831c0ac03e741efda86b141aa863a481ebc4aaf5a5c1f13a481dbb40ff"
|
||||
},
|
||||
"version": "1.60.1"
|
||||
"version": "1.70.0"
|
||||
},
|
||||
"io.grpc:grpc-protobuf": {
|
||||
"shasums": {
|
||||
"jar": "79704cf169ee27151fce4375a4d91fe828d276d921eef5a7f497d020b0a5d345"
|
||||
"jar": "9b98039ed826604c46d6ac8f8a182d413d348ec6abe26467736b05aa92e7e1d3"
|
||||
},
|
||||
"version": "1.68.0"
|
||||
"version": "1.70.0"
|
||||
},
|
||||
"io.grpc:grpc-protobuf-lite": {
|
||||
"shasums": {
|
||||
"jar": "60e92e148b4f86c06885afa79a86beb74bffcdcba47f8b65dc7010ba6701fa80"
|
||||
"jar": "e7cc2ca8981672851cbebf83a24bfb93c1b2b058e75c1a817a757b914f33403d"
|
||||
},
|
||||
"version": "1.68.0"
|
||||
"version": "1.70.0"
|
||||
},
|
||||
"io.grpc:grpc-stub": {
|
||||
"shasums": {
|
||||
"jar": "7c4090509cd6ea0432305f9397da21127b691905bdcf163a306bedb1c6f4ead7"
|
||||
"jar": "5adaa1ec1f744b67ae14a8dbc39c9589c010fad0fd557b0a02966202e4d23a18"
|
||||
},
|
||||
"version": "1.68.0"
|
||||
"version": "1.70.0"
|
||||
},
|
||||
"io.netty:netty-buffer": {
|
||||
"shasums": {
|
||||
@@ -320,9 +543,9 @@
|
||||
},
|
||||
"io.netty:netty-codec-socks": {
|
||||
"shasums": {
|
||||
"jar": "976052a3c9bb280bc6d99f3a29e6404677cf958c3de05b205093d38c006b880c"
|
||||
"jar": "d3d251f9239951a845f22e39191f95471fb2eb7951b9878ea4555ccac99529fb"
|
||||
},
|
||||
"version": "4.1.110.Final"
|
||||
"version": "4.1.127.Final"
|
||||
},
|
||||
"io.netty:netty-common": {
|
||||
"shasums": {
|
||||
@@ -338,9 +561,9 @@
|
||||
},
|
||||
"io.netty:netty-handler-proxy": {
|
||||
"shasums": {
|
||||
"jar": "ad54ab4fe9c47ef3e723d71251126db53e8db543871adb9eafc94446539eff52"
|
||||
"jar": "2c0c8046e5d737e08f40a7c2907526648860d0434e125bd51de3c2cf390453fb"
|
||||
},
|
||||
"version": "4.1.110.Final"
|
||||
"version": "4.1.127.Final"
|
||||
},
|
||||
"io.netty:netty-resolver": {
|
||||
"shasums": {
|
||||
@@ -350,20 +573,20 @@
|
||||
},
|
||||
"io.netty:netty-tcnative-boringssl-static": {
|
||||
"shasums": {
|
||||
"jar": "3f7b4c3a51737965cd5b53777782c125784420458d96513cfac7412e4d1fa0c3",
|
||||
"linux-aarch_64": "523c43f67ad9040d70f9494fc28eebf711d8c54e2aa30e3fd1a199c38740f53b",
|
||||
"linux-x86_64": "3d773aac73fe40f5d04de37ce14a1f7abd27caf0b3bd8275884f5d2968b3e254",
|
||||
"osx-aarch_64": "0454c53e65da6e253b2104d1ae26ecc79df4faf999e8924b659846b5bf41e996",
|
||||
"osx-x86_64": "9c6a23335f296689fb3538bc49e4e280ff163675212c6fe01c9cf2a9273ee19a",
|
||||
"windows-x86_64": "b3e3e0559df29a5624bcf529cb8e2bd9375c6d68164dda338e841677586a14c4"
|
||||
"jar": "ec3b14ceff74c5d7e24a378e64074744cc5e7035c49cf6ca0a4e23dff9713d1f",
|
||||
"linux-aarch_64": "11dfee82cfcb5c4f596271fe1d56a70fe77b4034e54162d0bd211623b540857f",
|
||||
"linux-x86_64": "39ac6b1eb4ffc18d5fe9412cc6253a8954bafc8e3ca10109bc370490f73a3673",
|
||||
"osx-aarch_64": "eef3fc7cdc5e2dc8c5cb50bae11443052bf1ee2f6e8b64378565746d1529f05e",
|
||||
"osx-x86_64": "e3beaa3ebdb136569528c59aa826d771efadc0ac9db484c6c0e457fa5efd0f07",
|
||||
"windows-x86_64": "5458b4b502763d49cd2e16c434312687178afac9c164cabf75c4a8bcecf7ac50"
|
||||
},
|
||||
"version": "2.0.70.Final"
|
||||
"version": "2.0.74.Final"
|
||||
},
|
||||
"io.netty:netty-tcnative-classes": {
|
||||
"shasums": {
|
||||
"jar": "a79c1579313d4ad48a3ecc1d01a25da06d22d6449c3bcc369c2318749bcf55bc"
|
||||
"jar": "194874cf723794dd409fd1e728cd91ffbcff0584d73b4d8a1ad0d69d04acf9b3"
|
||||
},
|
||||
"version": "2.0.70.Final"
|
||||
"version": "2.0.74.Final"
|
||||
},
|
||||
"io.netty:netty-transport": {
|
||||
"shasums": {
|
||||
@@ -379,9 +602,9 @@
|
||||
},
|
||||
"io.netty:netty-transport-native-epoll": {
|
||||
"shasums": {
|
||||
"linux-x86_64": "dcd60c6b3076af307ab877201a136e1f1066c9be809aaed827391a23909f9135"
|
||||
"linux-x86_64": "3d03f27eea1cd23357a56a96e1eeedfeb3d74fa0ba4d5c36a862bd035056275b"
|
||||
},
|
||||
"version": "4.1.110.Final"
|
||||
"version": "4.1.127.Final"
|
||||
},
|
||||
"io.netty:netty-transport-native-unix-common": {
|
||||
"shasums": {
|
||||
@@ -425,6 +648,12 @@
|
||||
},
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"javax.annotation:javax.annotation-api": {
|
||||
"shasums": {
|
||||
"jar": "e04ba5195bcd555dc95650f7cc614d151e4bcd52d29a10b8aa2197f3ab89ab9b"
|
||||
},
|
||||
"version": "1.3.2"
|
||||
},
|
||||
"javax.xml.bind:jaxb-api": {
|
||||
"shasums": {
|
||||
"jar": "88b955a0df57880a26a74708bc34f74dcaf8ebf4e78843a28b50eae945732b06"
|
||||
@@ -455,23 +684,17 @@
|
||||
},
|
||||
"version": "4.4.16"
|
||||
},
|
||||
"org.apache.tomcat:annotations-api": {
|
||||
"shasums": {
|
||||
"jar": "253829d3c12b7381d1044fc22c6436cff025fe0d459e4a329413e560a7d0dd13"
|
||||
},
|
||||
"version": "6.0.53"
|
||||
},
|
||||
"org.checkerframework:checker-qual": {
|
||||
"shasums": {
|
||||
"jar": "3fbc2e98f05854c3df16df9abaa955b91b15b3ecac33623208ed6424640ef0f6"
|
||||
"jar": "508c83c62c344f6f7ee28f47b88a8797d6116d043bfd1ca0576c828dd1df2880"
|
||||
},
|
||||
"version": "3.43.0"
|
||||
"version": "3.49.5"
|
||||
},
|
||||
"org.codehaus.mojo:animal-sniffer-annotations": {
|
||||
"shasums": {
|
||||
"jar": "c720e6e5bcbe6b2f48ded75a47bccdb763eede79d14330102e0d352e3d89ed92"
|
||||
"jar": "342f4d815eae69bb980620d0a622862709be37d38f47577675b42c739a962da9"
|
||||
},
|
||||
"version": "1.24"
|
||||
"version": "1.26"
|
||||
},
|
||||
"org.hamcrest:hamcrest-core": {
|
||||
"shasums": {
|
||||
@@ -539,11 +762,17 @@
|
||||
},
|
||||
"version": "4.1.0-M8"
|
||||
},
|
||||
"org.jspecify:jspecify": {
|
||||
"shasums": {
|
||||
"jar": "1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"org.ow2.asm:asm": {
|
||||
"shasums": {
|
||||
"jar": "3c6fac2424db3d4a853b669f4e3d1d9c3c552235e19a319673f887083c2303a1"
|
||||
"jar": "876eab6a83daecad5ca67eb9fcabb063c97b5aeb8cf1fca7a989ecde17522051"
|
||||
},
|
||||
"version": "9.6"
|
||||
"version": "9.8"
|
||||
},
|
||||
"org.reactivestreams:reactive-streams": {
|
||||
"shasums": {
|
||||
@@ -791,10 +1020,19 @@
|
||||
"com.google.api.grpc:proto-google-common-protos": [
|
||||
"com.google.protobuf:protobuf-java"
|
||||
],
|
||||
"com.google.api:api-common": [
|
||||
"com.google.auto.value:auto-value-annotations",
|
||||
"com.google.code.findbugs:jsr305",
|
||||
"com.google.errorprone:error_prone_annotations",
|
||||
"com.google.j2objc:j2objc-annotations",
|
||||
"javax.annotation:javax.annotation-api"
|
||||
],
|
||||
"com.google.auth:google-auth-library-oauth2-http": [
|
||||
"com.google.api:api-common",
|
||||
"com.google.auth:google-auth-library-credentials",
|
||||
"com.google.auto.value:auto-value-annotations",
|
||||
"com.google.code.findbugs:jsr305",
|
||||
"com.google.code.gson:gson",
|
||||
"com.google.errorprone:error_prone_annotations",
|
||||
"com.google.guava:guava",
|
||||
"com.google.http-client:google-http-client",
|
||||
@@ -826,12 +1064,24 @@
|
||||
"com.google.code.gson:gson",
|
||||
"com.google.http-client:google-http-client"
|
||||
],
|
||||
"com.google.protobuf:protobuf-java-util": [
|
||||
"com.google.code.findbugs:jsr305",
|
||||
"com.google.code.gson:gson",
|
||||
"com.google.errorprone:error_prone_annotations",
|
||||
"com.google.guava:guava",
|
||||
"com.google.j2objc:j2objc-annotations",
|
||||
"com.google.protobuf:protobuf-java"
|
||||
],
|
||||
"com.google.s2a.proto.v2:s2a-proto": [
|
||||
"io.grpc:grpc-protobuf",
|
||||
"io.grpc:grpc-stub"
|
||||
],
|
||||
"com.google.truth:truth": [
|
||||
"com.google.auto.value:auto-value-annotations",
|
||||
"com.google.errorprone:error_prone_annotations",
|
||||
"com.google.guava:guava",
|
||||
"junit:junit",
|
||||
"org.checkerframework:checker-qual",
|
||||
"org.jspecify:jspecify",
|
||||
"org.ow2.asm:asm"
|
||||
],
|
||||
"com.nimbusds:nimbus-jose-jwt": [
|
||||
@@ -919,7 +1169,8 @@
|
||||
"io.grpc:grpc-stub": [
|
||||
"com.google.errorprone:error_prone_annotations",
|
||||
"com.google.guava:guava",
|
||||
"io.grpc:grpc-api"
|
||||
"io.grpc:grpc-api",
|
||||
"org.codehaus.mojo:animal-sniffer-annotations"
|
||||
],
|
||||
"io.netty:netty-buffer": [
|
||||
"io.netty:netty-common"
|
||||
@@ -1409,11 +1660,17 @@
|
||||
"com.google.shopping.type",
|
||||
"com.google.type"
|
||||
],
|
||||
"com.google.api:api-common": [
|
||||
"com.google.api.core",
|
||||
"com.google.api.pathtemplate",
|
||||
"com.google.api.resourcenames"
|
||||
],
|
||||
"com.google.auth:google-auth-library-credentials": [
|
||||
"com.google.auth"
|
||||
],
|
||||
"com.google.auth:google-auth-library-oauth2-http": [
|
||||
"com.google.auth.http",
|
||||
"com.google.auth.mtls",
|
||||
"com.google.auth.oauth2"
|
||||
],
|
||||
"com.google.auto.value:auto-value": [
|
||||
@@ -1531,9 +1788,15 @@
|
||||
"com.google.protobuf",
|
||||
"com.google.protobuf.compiler"
|
||||
],
|
||||
"com.google.protobuf:protobuf-java-util": [
|
||||
"com.google.protobuf.util"
|
||||
],
|
||||
"com.google.re2j:re2j": [
|
||||
"com.google.re2j"
|
||||
],
|
||||
"com.google.s2a.proto.v2:s2a-proto": [
|
||||
"com.google.s2a.proto.v2"
|
||||
],
|
||||
"com.google.truth:truth": [
|
||||
"com.google.common.truth"
|
||||
],
|
||||
@@ -1841,6 +2104,11 @@
|
||||
"javax.activation:javax.activation-api": [
|
||||
"javax.activation"
|
||||
],
|
||||
"javax.annotation:javax.annotation-api": [
|
||||
"javax.annotation",
|
||||
"javax.annotation.security",
|
||||
"javax.annotation.sql"
|
||||
],
|
||||
"javax.xml.bind:jaxb-api": [
|
||||
"javax.xml.bind",
|
||||
"javax.xml.bind.annotation",
|
||||
@@ -1937,13 +2205,6 @@
|
||||
"org.apache.http.ssl",
|
||||
"org.apache.http.util"
|
||||
],
|
||||
"org.apache.tomcat:annotations-api": [
|
||||
"javax.annotation",
|
||||
"javax.annotation.security",
|
||||
"javax.ejb",
|
||||
"javax.persistence",
|
||||
"javax.xml.ws"
|
||||
],
|
||||
"org.checkerframework:checker-qual": [
|
||||
"org.checkerframework.checker.builder.qual",
|
||||
"org.checkerframework.checker.calledmethods.qual",
|
||||
@@ -1958,12 +2219,14 @@
|
||||
"org.checkerframework.checker.interning.qual",
|
||||
"org.checkerframework.checker.lock.qual",
|
||||
"org.checkerframework.checker.mustcall.qual",
|
||||
"org.checkerframework.checker.nonempty.qual",
|
||||
"org.checkerframework.checker.nullness.qual",
|
||||
"org.checkerframework.checker.optional.qual",
|
||||
"org.checkerframework.checker.propkey.qual",
|
||||
"org.checkerframework.checker.regex.qual",
|
||||
"org.checkerframework.checker.signature.qual",
|
||||
"org.checkerframework.checker.signedness.qual",
|
||||
"org.checkerframework.checker.sqlquotes.qual",
|
||||
"org.checkerframework.checker.tainting.qual",
|
||||
"org.checkerframework.checker.units.qual",
|
||||
"org.checkerframework.common.aliasing.qual",
|
||||
@@ -2051,6 +2314,9 @@
|
||||
"org.json4s:json4s-native_3": [
|
||||
"org.json4s.native"
|
||||
],
|
||||
"org.jspecify:jspecify": [
|
||||
"org.jspecify.annotations"
|
||||
],
|
||||
"org.ow2.asm:asm": [
|
||||
"org.objectweb.asm",
|
||||
"org.objectweb.asm.signature"
|
||||
@@ -2089,7 +2355,6 @@
|
||||
"scala.reflect",
|
||||
"scala.reflect.macros.internal",
|
||||
"scala.runtime",
|
||||
"scala.runtime.java8",
|
||||
"scala.sys",
|
||||
"scala.sys.process",
|
||||
"scala.util",
|
||||
@@ -2102,7 +2367,6 @@
|
||||
"scala.annotation",
|
||||
"scala.annotation.internal",
|
||||
"scala.annotation.unchecked",
|
||||
"scala.compiletime",
|
||||
"scala.compiletime.ops",
|
||||
"scala.compiletime.testing",
|
||||
"scala.deriving",
|
||||
@@ -2455,6 +2719,7 @@
|
||||
"com.github.stephenc.jcip:jcip-annotations",
|
||||
"com.google.android:annotations",
|
||||
"com.google.api.grpc:proto-google-common-protos",
|
||||
"com.google.api:api-common",
|
||||
"com.google.auth:google-auth-library-credentials",
|
||||
"com.google.auth:google-auth-library-oauth2-http",
|
||||
"com.google.auto.value:auto-value",
|
||||
@@ -2469,7 +2734,9 @@
|
||||
"com.google.http-client:google-http-client-gson",
|
||||
"com.google.j2objc:j2objc-annotations",
|
||||
"com.google.protobuf:protobuf-java",
|
||||
"com.google.protobuf:protobuf-java-util",
|
||||
"com.google.re2j:re2j",
|
||||
"com.google.s2a.proto.v2:s2a-proto",
|
||||
"com.google.truth:truth",
|
||||
"com.nimbusds:nimbus-jose-jwt",
|
||||
"com.squareup.okhttp3:okhttp",
|
||||
@@ -2519,12 +2786,12 @@
|
||||
"io.perfmark:perfmark-api",
|
||||
"io.sentry:sentry",
|
||||
"javax.activation:javax.activation-api",
|
||||
"javax.annotation:javax.annotation-api",
|
||||
"javax.xml.bind:jaxb-api",
|
||||
"joda-time:joda-time",
|
||||
"junit:junit",
|
||||
"org.apache.httpcomponents:httpclient",
|
||||
"org.apache.httpcomponents:httpcore",
|
||||
"org.apache.tomcat:annotations-api",
|
||||
"org.checkerframework:checker-qual",
|
||||
"org.codehaus.mojo:animal-sniffer-annotations",
|
||||
"org.hamcrest:hamcrest-core",
|
||||
@@ -2538,6 +2805,7 @@
|
||||
"org.json4s:json4s-jackson-core_3",
|
||||
"org.json4s:json4s-native-core_3",
|
||||
"org.json4s:json4s-native_3",
|
||||
"org.jspecify:jspecify",
|
||||
"org.ow2.asm:asm",
|
||||
"org.reactivestreams:reactive-streams",
|
||||
"org.scala-lang.modules:scala-collection-compat_3",
|
||||
@@ -2638,5 +2906,5 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "2"
|
||||
"version": "3"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
#
|
||||
# Build the SparklePlugin native library for Unity using Bazel
|
||||
#
|
||||
# The SparklePlugin is built in a separate Bazel workspace (sparkle_workspace/)
|
||||
# to avoid rules_swift version conflicts between grpc and rules_apple.
|
||||
#
|
||||
# Usage: build_sparkle_plugin.sh [output_dir]
|
||||
|
||||
set -euo pipefail
|
||||
@@ -11,12 +14,14 @@ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
OUTPUT_DIR="${1:-$PROJECT_ROOT/src/main/csharp/net/eagle0/clients/unity/eagle0/Assets/Plugins/macOS}"
|
||||
|
||||
echo "=== Building SparklePlugin with Bazel ==="
|
||||
echo "=== Building SparklePlugin with Bazel (from sparkle_workspace) ==="
|
||||
|
||||
bazel build --config=mactools //src/main/objc/net/eagle0/sparkle:SparklePlugin
|
||||
# Build in the separate sparkle_workspace to avoid dependency conflicts
|
||||
cd "$PROJECT_ROOT/sparkle_workspace"
|
||||
bazel build //:SparklePlugin
|
||||
|
||||
# Get the zip path from bazel
|
||||
ZIP_PATH=$(bazel cquery --config=mactools --output=files //src/main/objc/net/eagle0/sparkle:SparklePlugin 2>/dev/null)
|
||||
ZIP_PATH=$(bazel cquery --output=files //:SparklePlugin 2>/dev/null)
|
||||
|
||||
echo "=== Extracting SparklePlugin.bundle ==="
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
7.7.1
|
||||
@@ -0,0 +1,2 @@
|
||||
# Bazel symlinks
|
||||
bazel-*
|
||||
@@ -0,0 +1,28 @@
|
||||
module(name = "sparkle_workspace")
|
||||
|
||||
# Minimal dependencies for building SparklePlugin
|
||||
# This workspace is isolated from the main workspace to avoid
|
||||
# rules_swift version conflicts between grpc and rules_apple
|
||||
|
||||
bazel_dep(name = "apple_support", version = "1.21.1", repo_name = "build_bazel_apple_support")
|
||||
bazel_dep(name = "rules_apple", version = "4.3.3", repo_name = "build_bazel_rules_apple")
|
||||
|
||||
# Register Apple CC toolchain for Objective-C compilation
|
||||
apple_cc_configure = use_extension(
|
||||
"@build_bazel_apple_support//crosstool:setup.bzl",
|
||||
"apple_cc_configure_extension",
|
||||
)
|
||||
use_repo(apple_cc_configure, "local_config_apple_cc")
|
||||
|
||||
# Sparkle framework for macOS auto-updates
|
||||
http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
SPARKLE_VERSION = "2.6.4"
|
||||
|
||||
http_archive(
|
||||
name = "sparkle",
|
||||
build_file = "//:external/BUILD.sparkle",
|
||||
sha256 = "50612a06038abc931f16011d7903b8326a362c1074dabccb718404ce8e585f0b",
|
||||
strip_prefix = "",
|
||||
url = "https://github.com/sparkle-project/Sparkle/releases/download/%s/Sparkle-%s.tar.xz" % (SPARKLE_VERSION, SPARKLE_VERSION),
|
||||
)
|
||||
Generated
+451
@@ -0,0 +1,451 @@
|
||||
{
|
||||
"lockFileVersion": 13,
|
||||
"registryFileHashes": {
|
||||
"https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da",
|
||||
"https://bcr.bazel.build/modules/apple_support/1.11.1/MODULE.bazel": "1843d7cd8a58369a444fc6000e7304425fba600ff641592161d9f15b179fb896",
|
||||
"https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85",
|
||||
"https://bcr.bazel.build/modules/apple_support/1.21.1/MODULE.bazel": "5809fa3efab15d1f3c3c635af6974044bac8a4919c62238cce06acee8a8c11f1",
|
||||
"https://bcr.bazel.build/modules/apple_support/1.23.1/MODULE.bazel": "53763fed456a968cf919b3240427cf3a9d5481ec5466abc9d5dc51bc70087442",
|
||||
"https://bcr.bazel.build/modules/apple_support/1.23.1/source.json": "d888b44312eb0ad2c21a91d026753f330caa48a25c9b2102fae75eb2b0dcfdd2",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953",
|
||||
"https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
|
||||
"https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
|
||||
"https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb",
|
||||
"https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
|
||||
"https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6",
|
||||
"https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4",
|
||||
"https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
|
||||
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075",
|
||||
"https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d",
|
||||
"https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902",
|
||||
"https://bcr.bazel.build/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74",
|
||||
"https://bcr.bazel.build/modules/nlohmann_json/3.6.1/source.json": "f448c6e8963fdfa7eb831457df83ad63d3d6355018f6574fb017e8169deb43a9",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc",
|
||||
"https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7",
|
||||
"https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c",
|
||||
"https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df",
|
||||
"https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92",
|
||||
"https://bcr.bazel.build/modules/protobuf/29.0-rc3/source.json": "c16a6488fb279ef578da7098e605082d72ed85fc8d843eaae81e7d27d0f4625d",
|
||||
"https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0",
|
||||
"https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858",
|
||||
"https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e",
|
||||
"https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022",
|
||||
"https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206",
|
||||
"https://bcr.bazel.build/modules/re2/2023-09-01/source.json": "e044ce89c2883cd957a2969a43e79f7752f9656f6b20050b62f90ede21ec6eb4",
|
||||
"https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8",
|
||||
"https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e",
|
||||
"https://bcr.bazel.build/modules/rules_apple/4.3.3/MODULE.bazel": "c5c2c4adeeac5f3f2f9b7f16abfa8be7ffefa596171d0d92bed4cae9ade0a498",
|
||||
"https://bcr.bazel.build/modules/rules_apple/4.3.3/source.json": "3cb1d69c8243ffcc42ecbf84ae8b9cccd7b1e2f091b0aee5a3e9c9a45267f312",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.11/MODULE.bazel": "9f249c5624a4788067b96b8b896be10c7e8b4375dc46f6d8e1e51100113e0992",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.1.2/MODULE.bazel": "557ddc3a96858ec0d465a87c0a931054d7dcfd6583af2c7ed3baf494407fd8d0",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.1.2/source.json": "53fcb09b5816c83ca60d9d7493faf3bfaf410dfc2f15deb52d6ddd146b8d43f0",
|
||||
"https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
|
||||
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
|
||||
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e",
|
||||
"https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74",
|
||||
"https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86",
|
||||
"https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31",
|
||||
"https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a",
|
||||
"https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6",
|
||||
"https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab",
|
||||
"https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe",
|
||||
"https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1",
|
||||
"https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017",
|
||||
"https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939",
|
||||
"https://bcr.bazel.build/modules/rules_java/8.5.1/source.json": "db1a77d81b059e0f84985db67a22f3f579a529a86b7997605be3d214a0abe38e",
|
||||
"https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7",
|
||||
"https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909",
|
||||
"https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036",
|
||||
"https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0",
|
||||
"https://bcr.bazel.build/modules/rules_jvm_external/6.3/source.json": "6f5f5a5a4419ae4e37c35a5bb0a6ae657ed40b7abc5a5189111b47fcebe43197",
|
||||
"https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3",
|
||||
"https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5",
|
||||
"https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0",
|
||||
"https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d",
|
||||
"https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c",
|
||||
"https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb",
|
||||
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
|
||||
"https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff",
|
||||
"https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a",
|
||||
"https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06",
|
||||
"https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7",
|
||||
"https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73",
|
||||
"https://bcr.bazel.build/modules/rules_proto/6.0.2/source.json": "17a2e195f56cb28d6bbf763e49973d13890487c6945311ed141e196fb660426d",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.3.0/MODULE.bazel": "8361d57eafb67c09b75bf4bbe6be360e1b8f4f18118ab48037f2bd50aa2ccb13",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.3.0/source.json": "25932f917cd279c7baefa6cb1d3fa8750a7a29de522024449b19af6eab51f4a0",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.3.0/source.json": "c55ed591aa5009401ddf80ded9762ac32c358d2517ee7820be981e2de9756cf3",
|
||||
"https://bcr.bazel.build/modules/rules_swift/1.16.0/MODULE.bazel": "4a09f199545a60d09895e8281362b1ff3bb08bbde69c6fc87aff5b92fcc916ca",
|
||||
"https://bcr.bazel.build/modules/rules_swift/2.4.0/MODULE.bazel": "1639617eb1ede28d774d967a738b4a68b0accb40650beadb57c21846beab5efd",
|
||||
"https://bcr.bazel.build/modules/rules_swift/2.4.0/source.json": "a6577f57f9febbdc015a01f2a8f3487422032f134d6c61d18ed8e8ca3b9acc7c",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216",
|
||||
"https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91",
|
||||
"https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/source.json": "32bd87e5f4d7acc57c5b2ff7c325ae3061d5e242c0c4c214ae87e0f1c13e54cb",
|
||||
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
|
||||
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
|
||||
"https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198"
|
||||
},
|
||||
"selectedYankedVersions": {},
|
||||
"moduleExtensions": {
|
||||
"@@rules_java~//java:rules_java_deps.bzl%compatibility_proxy": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "C4xqrMy1wN4iuTN6Z2eCm94S5XingHhD6uwrIXvCxVI=",
|
||||
"usagesDigest": "pwHZ+26iLgQdwvdZeA5wnAjKnNI3y6XO2VbhOTeo5h8=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"compatibility_proxy": {
|
||||
"bzlFile": "@@rules_java~//java:rules_java_deps.bzl",
|
||||
"ruleClassName": "_compatibility_proxy_repo_rule",
|
||||
"attributes": {}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": [
|
||||
[
|
||||
"rules_java~",
|
||||
"bazel_tools",
|
||||
"bazel_tools"
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"@@rules_kotlin~//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "eecmTsmdIQveoA97hPtH3/Ej/kugbdCI24bhXIXaly8=",
|
||||
"usagesDigest": "aJF6fLy82rR95Ff5CZPAqxNoFgOMLMN5ImfBS0nhnkg=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"com_github_jetbrains_kotlin_git": {
|
||||
"bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl",
|
||||
"ruleClassName": "kotlin_compiler_git_repository",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip"
|
||||
],
|
||||
"sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88"
|
||||
}
|
||||
},
|
||||
"com_github_jetbrains_kotlin": {
|
||||
"bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl",
|
||||
"ruleClassName": "kotlin_capabilities_repository",
|
||||
"attributes": {
|
||||
"git_repository_name": "com_github_jetbrains_kotlin_git",
|
||||
"compiler_version": "1.9.23"
|
||||
}
|
||||
},
|
||||
"com_github_google_ksp": {
|
||||
"bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:ksp.bzl",
|
||||
"ruleClassName": "ksp_compiler_plugin_repository",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip"
|
||||
],
|
||||
"sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d",
|
||||
"strip_version": "1.9.23-1.0.20"
|
||||
}
|
||||
},
|
||||
"com_github_pinterest_ktlint": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_file",
|
||||
"attributes": {
|
||||
"sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985",
|
||||
"urls": [
|
||||
"https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint"
|
||||
],
|
||||
"executable": true
|
||||
}
|
||||
},
|
||||
"rules_android": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806",
|
||||
"strip_prefix": "rules_android-0.1.1",
|
||||
"urls": [
|
||||
"https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": [
|
||||
[
|
||||
"rules_kotlin~",
|
||||
"bazel_tools",
|
||||
"bazel_tools"
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"@@rules_python~//python/uv:uv.bzl%uv": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "Xpqjnjzy6zZ90Es9Wa888ZLHhn7IsNGbph/e6qoxzw8=",
|
||||
"usagesDigest": "qI5PVlIum/YAnGJg5oXGHzDkMFWt2aNSUZY4G8PBbic=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"uv": {
|
||||
"bzlFile": "@@rules_python~//python/uv/private:uv_toolchains_repo.bzl",
|
||||
"ruleClassName": "uv_toolchains_repo",
|
||||
"attributes": {
|
||||
"toolchain_type": "'@@rules_python~//python/uv:uv_toolchain_type'",
|
||||
"toolchain_names": [
|
||||
"none"
|
||||
],
|
||||
"toolchain_implementations": {
|
||||
"none": "'@@rules_python~//python:none'"
|
||||
},
|
||||
"toolchain_compatible_with": {
|
||||
"none": [
|
||||
"@platforms//:incompatible"
|
||||
]
|
||||
},
|
||||
"toolchain_target_settings": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": [
|
||||
[
|
||||
"rules_python~",
|
||||
"platforms",
|
||||
"platforms"
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"@@rules_swift~//swift:extensions.bzl%non_module_deps": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "l+Zu+SMObRQy3DG2LEw0eGVPkYRnyVj+M1QyR5AAFmM=",
|
||||
"usagesDigest": "l2vIL7SL4tJqHIVLWd78Y/ym+r0II64lmvoX8o+0Bb0=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"com_github_apple_swift_protobuf": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/apple/swift-protobuf/archive/1.20.2.tar.gz"
|
||||
],
|
||||
"sha256": "3fb50bd4d293337f202d917b6ada22f9548a0a0aed9d9a4d791e6fbd8a246ebb",
|
||||
"strip_prefix": "swift-protobuf-1.20.2/",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_apple_swift_protobuf/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"com_github_grpc_grpc_swift": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/grpc/grpc-swift/archive/1.16.0.tar.gz"
|
||||
],
|
||||
"sha256": "58b60431d0064969f9679411264b82e40a217ae6bd34e17096d92cc4e47556a5",
|
||||
"strip_prefix": "grpc-swift-1.16.0/",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_grpc_grpc_swift/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"com_github_apple_swift_docc_symbolkit": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/apple/swift-docc-symbolkit/archive/refs/tags/swift-5.10-RELEASE.tar.gz"
|
||||
],
|
||||
"sha256": "de1d4b6940468ddb53b89df7aa1a81323b9712775b0e33e8254fa0f6f7469a97",
|
||||
"strip_prefix": "swift-docc-symbolkit-swift-5.10-RELEASE",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_apple_swift_docc_symbolkit/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"com_github_apple_swift_nio": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/apple/swift-nio/archive/2.42.0.tar.gz"
|
||||
],
|
||||
"sha256": "e3304bc3fb53aea74a3e54bd005ede11f6dc357117d9b1db642d03aea87194a0",
|
||||
"strip_prefix": "swift-nio-2.42.0/",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"com_github_apple_swift_nio_http2": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/apple/swift-nio-http2/archive/1.26.0.tar.gz"
|
||||
],
|
||||
"sha256": "f0edfc9d6a7be1d587e5b403f2d04264bdfae59aac1d74f7d974a9022c6d2b25",
|
||||
"strip_prefix": "swift-nio-http2-1.26.0/",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_http2/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"com_github_apple_swift_nio_transport_services": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/apple/swift-nio-transport-services/archive/1.15.0.tar.gz"
|
||||
],
|
||||
"sha256": "f3498dafa633751a52b9b7f741f7ac30c42bcbeb3b9edca6d447e0da8e693262",
|
||||
"strip_prefix": "swift-nio-transport-services-1.15.0/",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_transport_services/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"com_github_apple_swift_nio_extras": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/apple/swift-nio-extras/archive/1.4.0.tar.gz"
|
||||
],
|
||||
"sha256": "4684b52951d9d9937bb3e8ccd6b5daedd777021ef2519ea2f18c4c922843b52b",
|
||||
"strip_prefix": "swift-nio-extras-1.4.0/",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_extras/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"com_github_apple_swift_log": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/apple/swift-log/archive/1.4.4.tar.gz"
|
||||
],
|
||||
"sha256": "48fe66426c784c0c20031f15dc17faf9f4c9037c192bfac2f643f65cb2321ba0",
|
||||
"strip_prefix": "swift-log-1.4.4/",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_apple_swift_log/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"com_github_apple_swift_nio_ssl": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/apple/swift-nio-ssl/archive/2.23.0.tar.gz"
|
||||
],
|
||||
"sha256": "4787c63f61dd04d99e498adc3d1a628193387e41efddf8de19b8db04544d016d",
|
||||
"strip_prefix": "swift-nio-ssl-2.23.0/",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_ssl/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"com_github_apple_swift_collections": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/apple/swift-collections/archive/1.0.4.tar.gz"
|
||||
],
|
||||
"sha256": "d9e4c8a91c60fb9c92a04caccbb10ded42f4cb47b26a212bc6b39cc390a4b096",
|
||||
"strip_prefix": "swift-collections-1.0.4/",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_apple_swift_collections/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"com_github_apple_swift_atomics": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"urls": [
|
||||
"https://github.com/apple/swift-atomics/archive/1.1.0.tar.gz"
|
||||
],
|
||||
"sha256": "1bee7f469f7e8dc49f11cfa4da07182fbc79eab000ec2c17bfdce468c5d276fb",
|
||||
"strip_prefix": "swift-atomics-1.1.0/",
|
||||
"build_file": "@@rules_swift~//third_party:com_github_apple_swift_atomics/BUILD.overlay"
|
||||
}
|
||||
},
|
||||
"build_bazel_rules_swift_index_import": {
|
||||
"bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
|
||||
"ruleClassName": "http_archive",
|
||||
"attributes": {
|
||||
"build_file": "@@rules_swift~//third_party:build_bazel_rules_swift_index_import/BUILD.overlay",
|
||||
"canonical_id": "index-import-5.8",
|
||||
"urls": [
|
||||
"https://github.com/MobileNativeFoundation/index-import/releases/download/5.8.0.1/index-import.tar.gz"
|
||||
],
|
||||
"sha256": "28c1ffa39d99e74ed70623899b207b41f79214c498c603915aef55972a851a15"
|
||||
}
|
||||
},
|
||||
"build_bazel_rules_swift_local_config": {
|
||||
"bzlFile": "@@rules_swift~//swift/internal:swift_autoconfiguration.bzl",
|
||||
"ruleClassName": "swift_autoconfiguration",
|
||||
"attributes": {}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": [
|
||||
[
|
||||
"rules_swift~",
|
||||
"bazel_tools",
|
||||
"bazel_tools"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# This file marks sparkle_workspace as a separate Bazel workspace.
|
||||
# It prevents Bazel from looking up to the parent directory's workspace.
|
||||
# The actual dependencies are defined in MODULE.bazel (bzlmod).
|
||||
@@ -1,4 +1,3 @@
|
||||
load("@build_bazel_rules_apple//apple:macos.bzl", "macos_command_line_application")
|
||||
load("//tools:copts.bzl", "COPTS")
|
||||
|
||||
cc_library(
|
||||
@@ -82,11 +81,3 @@ cc_binary(
|
||||
":fixed_action_point_distances_timer",
|
||||
],
|
||||
)
|
||||
|
||||
macos_command_line_application(
|
||||
name = "fixed_action_point_distances_timer_macos_app",
|
||||
minimum_os_version = "10.15",
|
||||
deps = [
|
||||
":fixed_action_point_distances_timer",
|
||||
],
|
||||
)
|
||||
|
||||
+26
-30
@@ -45,14 +45,9 @@ namespace eagle {
|
||||
public Toggle demandTributeToggle;
|
||||
public Toggle withdrawToggle;
|
||||
public Toggle safePassageToggle;
|
||||
public ToggleGroup decisionToggleGroup;
|
||||
|
||||
public GameObject advanceImage;
|
||||
public GameObject demandTributeImage;
|
||||
public GameObject withdrawImage;
|
||||
public GameObject safePassageImage;
|
||||
|
||||
public Image goldIcon;
|
||||
public Image foodIcon;
|
||||
public GameObject tributeContainer;
|
||||
public Slider goldSlider;
|
||||
public Slider foodSlider;
|
||||
public TMP_Text goldLabel;
|
||||
@@ -140,21 +135,10 @@ namespace eagle {
|
||||
}
|
||||
}
|
||||
|
||||
advanceToggle.enabled = enableAttack;
|
||||
advanceToggle.gameObject.SetActive(enableAttack);
|
||||
advanceImage.SetActive(enableAttack);
|
||||
|
||||
withdrawToggle.enabled = enableWithdraw;
|
||||
withdrawToggle.gameObject.SetActive(enableWithdraw);
|
||||
withdrawImage.SetActive(enableWithdraw);
|
||||
|
||||
demandTributeToggle.enabled = enableDemandTribute;
|
||||
demandTributeToggle.gameObject.SetActive(enableDemandTribute);
|
||||
demandTributeImage.SetActive(enableDemandTribute);
|
||||
|
||||
safePassageToggle.enabled = enableSafePassage;
|
||||
safePassageToggle.gameObject.SetActive(enableSafePassage);
|
||||
safePassageImage.SetActive(enableSafePassage);
|
||||
ConfigureToggle(advanceToggle, enableAttack);
|
||||
ConfigureToggle(withdrawToggle, enableWithdraw);
|
||||
ConfigureToggle(demandTributeToggle, enableDemandTribute);
|
||||
ConfigureToggle(safePassageToggle, enableSafePassage);
|
||||
|
||||
goldSlider.minValue = 0;
|
||||
goldSlider.maxValue = maxGoldTribute;
|
||||
@@ -202,14 +186,7 @@ namespace eagle {
|
||||
foodLabel.text = ((int)newValue).ToString();
|
||||
}
|
||||
|
||||
private void EnableSliders(bool newEnabled) {
|
||||
goldIcon.gameObject.SetActive(newEnabled);
|
||||
foodIcon.gameObject.SetActive(newEnabled);
|
||||
goldSlider.gameObject.SetActive(newEnabled);
|
||||
foodSlider.gameObject.SetActive(newEnabled);
|
||||
goldLabel.gameObject.SetActive(newEnabled);
|
||||
foodLabel.gameObject.SetActive(newEnabled);
|
||||
}
|
||||
private void EnableSliders(bool newEnabled) { tributeContainer.SetActive(newEnabled); }
|
||||
|
||||
public void ToggleChanged(bool value) {
|
||||
bool enableSliders =
|
||||
@@ -218,5 +195,24 @@ namespace eagle {
|
||||
|
||||
EnableSliders(enableSliders);
|
||||
}
|
||||
|
||||
private const float DisabledAlpha = 0.35f;
|
||||
|
||||
private void ConfigureToggle(Toggle toggle, bool available) {
|
||||
if (toggle == null) return;
|
||||
|
||||
toggle.gameObject.SetActive(true);
|
||||
toggle.interactable = available;
|
||||
|
||||
if (!available) { toggle.isOn = false; }
|
||||
|
||||
toggle.group = available ? decisionToggleGroup : null;
|
||||
|
||||
var canvasGroup = toggle.GetComponent<CanvasGroup>();
|
||||
if (canvasGroup == null) {
|
||||
canvasGroup = toggle.gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
canvasGroup.alpha = available ? 1f : DisabledAlpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-3
@@ -23,6 +23,7 @@ namespace eagle {
|
||||
|
||||
public Toggle AdvanceToggle;
|
||||
public Toggle WithdrawToggle;
|
||||
public ToggleGroup decisionToggleGroup;
|
||||
|
||||
private FreeForAllDecisionAvailableCommand FreeForAllDecisionCommand =>
|
||||
_availableCommand.FreeForAllDecisionCommand;
|
||||
@@ -63,10 +64,32 @@ namespace eagle {
|
||||
row.Origin = _model.Provinces[army.OriginProvinceId].Name;
|
||||
});
|
||||
|
||||
AdvanceToggle.isOn = true;
|
||||
AdvanceToggle.enabled = true;
|
||||
WithdrawToggle.enabled = FreeForAllDecisionCommand.AvailableDecisions.Any(
|
||||
bool withdrawAvailable = FreeForAllDecisionCommand.AvailableDecisions.Any(
|
||||
x => x.SealedValueCase == AttackDecisionType.SealedValueOneofCase.Withdraw);
|
||||
|
||||
ConfigureToggle(AdvanceToggle, true);
|
||||
ConfigureToggle(WithdrawToggle, withdrawAvailable);
|
||||
|
||||
AdvanceToggle.isOn = true;
|
||||
}
|
||||
|
||||
private const float DisabledAlpha = 0.35f;
|
||||
|
||||
private void ConfigureToggle(Toggle toggle, bool available) {
|
||||
if (toggle == null) return;
|
||||
|
||||
toggle.gameObject.SetActive(true);
|
||||
toggle.interactable = available;
|
||||
|
||||
if (!available) { toggle.isOn = false; }
|
||||
|
||||
toggle.group = available ? decisionToggleGroup : null;
|
||||
|
||||
var canvasGroup = toggle.GetComponent<CanvasGroup>();
|
||||
if (canvasGroup == null) {
|
||||
canvasGroup = toggle.gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
canvasGroup.alpha = available ? 1f : DisabledAlpha;
|
||||
}
|
||||
|
||||
// Use this for initialization
|
||||
|
||||
+41
-43
@@ -15,12 +15,7 @@ namespace eagle {
|
||||
public Toggle ExileToggle;
|
||||
public Toggle ExecuteToggle;
|
||||
public Toggle ReturnToggle;
|
||||
|
||||
public RawImage RecruitIcon;
|
||||
public RawImage ImprisonIcon;
|
||||
public RawImage ExileIcon;
|
||||
public RawImage ExecuteIcon;
|
||||
public RawImage ReturnIcon;
|
||||
public ToggleGroup decisionToggleGroup;
|
||||
|
||||
public HeroDetailsController heroDetails;
|
||||
|
||||
@@ -95,51 +90,54 @@ namespace eagle {
|
||||
|
||||
messageUpdater.TextId = SelectedHeroWithOptions.MessageId;
|
||||
|
||||
// The order here is important: the last available toggle in this list
|
||||
// will be on by default
|
||||
ConditionallyEnable(
|
||||
ExecuteToggle,
|
||||
ExecuteIcon,
|
||||
CapturedHeroOption.ExecuteCapturedHeroOption);
|
||||
ConditionallyEnable(ExileToggle, ExileIcon, CapturedHeroOption.ExileCapturedHeroOption);
|
||||
ConditionallyEnable(
|
||||
ReturnToggle,
|
||||
ReturnIcon,
|
||||
CapturedHeroOption.ReturnCapturedHeroOption);
|
||||
ConditionallyEnable(
|
||||
ImprisonToggle,
|
||||
ImprisonIcon,
|
||||
CapturedHeroOption.ImprisonCapturedHeroOption);
|
||||
ConditionallyEnable(
|
||||
var options = SelectedHeroWithOptions.Options;
|
||||
ConfigureToggle(
|
||||
RecruitToggle,
|
||||
RecruitIcon,
|
||||
CapturedHeroOption.RecruitCapturedHeroOption);
|
||||
options.Contains(CapturedHeroOption.RecruitCapturedHeroOption));
|
||||
ConfigureToggle(
|
||||
ImprisonToggle,
|
||||
options.Contains(CapturedHeroOption.ImprisonCapturedHeroOption));
|
||||
ConfigureToggle(
|
||||
ExileToggle,
|
||||
options.Contains(CapturedHeroOption.ExileCapturedHeroOption));
|
||||
ConfigureToggle(
|
||||
ExecuteToggle,
|
||||
options.Contains(CapturedHeroOption.ExecuteCapturedHeroOption));
|
||||
ConfigureToggle(
|
||||
ReturnToggle,
|
||||
options.Contains(CapturedHeroOption.ReturnCapturedHeroOption));
|
||||
|
||||
// Select first available option (priority order: Recruit > Imprison > Exile > Execute >
|
||||
// Return)
|
||||
if (options.Contains(CapturedHeroOption.RecruitCapturedHeroOption))
|
||||
RecruitToggle.isOn = true;
|
||||
else if (options.Contains(CapturedHeroOption.ImprisonCapturedHeroOption))
|
||||
ImprisonToggle.isOn = true;
|
||||
else if (options.Contains(CapturedHeroOption.ExileCapturedHeroOption))
|
||||
ExileToggle.isOn = true;
|
||||
else if (options.Contains(CapturedHeroOption.ExecuteCapturedHeroOption))
|
||||
ExecuteToggle.isOn = true;
|
||||
else if (options.Contains(CapturedHeroOption.ReturnCapturedHeroOption))
|
||||
ReturnToggle.isOn = true;
|
||||
}
|
||||
|
||||
private bool ConditionallyEnable(Toggle toggle, CapturedHeroOption option) {
|
||||
bool enable = SelectedHeroWithOptions.Options.Contains(option);
|
||||
toggle.gameObject.SetActive(enable);
|
||||
private const float DisabledAlpha = 0.35f;
|
||||
|
||||
if (enable) {
|
||||
ExecuteToggle.isOn = false;
|
||||
ExileToggle.isOn = false;
|
||||
ImprisonToggle.isOn = false;
|
||||
RecruitToggle.isOn = false;
|
||||
ReturnToggle.isOn = false;
|
||||
private void ConfigureToggle(Toggle toggle, bool available) {
|
||||
if (toggle == null) return;
|
||||
|
||||
toggle.isOn = true;
|
||||
} else
|
||||
toggle.isOn = false;
|
||||
toggle.gameObject.SetActive(true);
|
||||
toggle.interactable = available;
|
||||
|
||||
return enable;
|
||||
}
|
||||
if (!available) { toggle.isOn = false; }
|
||||
|
||||
private void ConditionallyEnable(Toggle toggle, RawImage img, CapturedHeroOption option) {
|
||||
bool enable = ConditionallyEnable(toggle, option);
|
||||
toggle.group = available ? decisionToggleGroup : null;
|
||||
|
||||
Color color = img.color;
|
||||
color.a = enable ? 1.0f : 0.25f;
|
||||
img.color = color;
|
||||
var canvasGroup = toggle.GetComponent<CanvasGroup>();
|
||||
if (canvasGroup == null) {
|
||||
canvasGroup = toggle.gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
canvasGroup.alpha = available ? 1f : DisabledAlpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+50
-53
@@ -21,12 +21,7 @@ namespace eagle {
|
||||
public Toggle ExileToggle;
|
||||
public Toggle ExecuteToggle;
|
||||
public Toggle ReturnToggle;
|
||||
|
||||
public RawImage ReleaseIcon;
|
||||
public RawImage MoveIcon;
|
||||
public RawImage ExileIcon;
|
||||
public RawImage ExecuteIcon;
|
||||
public RawImage ReturnIcon;
|
||||
public ToggleGroup decisionToggleGroup;
|
||||
|
||||
public TMP_Dropdown moveToDropdown;
|
||||
|
||||
@@ -143,28 +138,43 @@ namespace eagle {
|
||||
|
||||
MessageText.text = GetQuestMessagesForPrisoner(SelectedHero.Id);
|
||||
|
||||
// The order here is important: the last available toggle in this list
|
||||
// will be on by default
|
||||
ConditionallyEnable(
|
||||
ExecuteToggle,
|
||||
ExecuteIcon,
|
||||
PrisonerManagementOption.SealedValueOneofCase.Execute);
|
||||
ConditionallyEnable(
|
||||
ExileToggle,
|
||||
ExileIcon,
|
||||
PrisonerManagementOption.SealedValueOneofCase.Exile);
|
||||
ConditionallyEnable(
|
||||
ReturnToggle,
|
||||
ReturnIcon,
|
||||
PrisonerManagementOption.SealedValueOneofCase.Return);
|
||||
ConditionallyEnable(
|
||||
MoveToggle,
|
||||
MoveIcon,
|
||||
PrisonerManagementOption.SealedValueOneofCase.Move);
|
||||
ConditionallyEnable(
|
||||
ReleaseToggle,
|
||||
ReleaseIcon,
|
||||
PrisonerManagementOption.SealedValueOneofCase.Release);
|
||||
var options = SelectedPrisonerToManage.AvailableOptions;
|
||||
bool hasRelease = options.Any(
|
||||
opt => opt.SealedValueCase ==
|
||||
PrisonerManagementOption.SealedValueOneofCase.Release);
|
||||
bool hasMove = options.Any(
|
||||
opt => opt.SealedValueCase ==
|
||||
PrisonerManagementOption.SealedValueOneofCase.Move);
|
||||
bool hasExile = options.Any(
|
||||
opt => opt.SealedValueCase ==
|
||||
PrisonerManagementOption.SealedValueOneofCase.Exile);
|
||||
bool hasExecute = options.Any(
|
||||
opt => opt.SealedValueCase ==
|
||||
PrisonerManagementOption.SealedValueOneofCase.Execute);
|
||||
bool hasReturn = options.Any(
|
||||
opt => opt.SealedValueCase ==
|
||||
PrisonerManagementOption.SealedValueOneofCase.Return);
|
||||
|
||||
ConfigureToggle(ReleaseToggle, hasRelease);
|
||||
ConfigureToggle(MoveToggle, hasMove);
|
||||
ConfigureToggle(ExileToggle, hasExile);
|
||||
ConfigureToggle(ExecuteToggle, hasExecute);
|
||||
ConfigureToggle(ReturnToggle, hasReturn);
|
||||
|
||||
// Select first available option (priority order: Release > Move > Exile > Execute >
|
||||
// Return)
|
||||
if (hasRelease) ReleaseToggle.isOn = true;
|
||||
else if (hasMove)
|
||||
MoveToggle.isOn = true;
|
||||
else if (hasExile)
|
||||
ExileToggle.isOn = true;
|
||||
else if (hasExecute)
|
||||
ExecuteToggle.isOn = true;
|
||||
else if (hasReturn)
|
||||
ReturnToggle.isOn = true;
|
||||
|
||||
// Update dropdown visibility based on selected toggle
|
||||
moveToDropdown.gameObject.SetActive(MoveToggle.isOn);
|
||||
}
|
||||
|
||||
private string GetQuestMessagesForPrisoner(HeroId prisonerId) {
|
||||
@@ -225,36 +235,23 @@ namespace eagle {
|
||||
: "A free hero";
|
||||
}
|
||||
|
||||
private bool ConditionallyEnable(
|
||||
Toggle toggle,
|
||||
PrisonerManagementOption.SealedValueOneofCase option) {
|
||||
bool enable = SelectedPrisonerToManage.AvailableOptions.Any(
|
||||
opt => opt.SealedValueCase == option);
|
||||
toggle.gameObject.SetActive(enable);
|
||||
private const float DisabledAlpha = 0.35f;
|
||||
|
||||
if (enable) {
|
||||
ExecuteToggle.isOn = false;
|
||||
ExileToggle.isOn = false;
|
||||
MoveToggle.isOn = false;
|
||||
ReleaseToggle.isOn = false;
|
||||
ReturnToggle.isOn = false;
|
||||
private void ConfigureToggle(Toggle toggle, bool available) {
|
||||
if (toggle == null) return;
|
||||
|
||||
toggle.isOn = true;
|
||||
} else
|
||||
toggle.isOn = false;
|
||||
toggle.gameObject.SetActive(true);
|
||||
toggle.interactable = available;
|
||||
|
||||
return enable;
|
||||
}
|
||||
if (!available) { toggle.isOn = false; }
|
||||
|
||||
private void ConditionallyEnable(
|
||||
Toggle toggle,
|
||||
RawImage img,
|
||||
PrisonerManagementOption.SealedValueOneofCase option) {
|
||||
bool enable = ConditionallyEnable(toggle, option);
|
||||
toggle.group = available ? decisionToggleGroup : null;
|
||||
|
||||
Color color = img.color;
|
||||
color.a = enable ? 1.0f : 0.25f;
|
||||
img.color = color;
|
||||
var canvasGroup = toggle.GetComponent<CanvasGroup>();
|
||||
if (canvasGroup == null) {
|
||||
canvasGroup = toggle.gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
canvasGroup.alpha = available ? 1f : DisabledAlpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,6 +165,24 @@ namespace eagle {
|
||||
case SealedValueOneofCase.FightBeastsAloneQuest: return "Fight Beasts Alone";
|
||||
case SealedValueOneofCase.DevelopProvincesQuest: return "Develop Provinces";
|
||||
case SealedValueOneofCase.MobilizeProvincesQuest: return "Mobilize Provinces";
|
||||
case SealedValueOneofCase.BattalionDiversityQuest: return "Battalion Diversity";
|
||||
case SealedValueOneofCase.ReleaseAllPrisonersQuest: return "Release All Prisoners";
|
||||
case SealedValueOneofCase.SwearBrotherhoodWithHeroQuest: return "Swear Brotherhood";
|
||||
case SealedValueOneofCase.BetrayAllyQuest: return "Betray Ally";
|
||||
case SealedValueOneofCase.BorderSecurityQuest: return "Border Security";
|
||||
case SealedValueOneofCase.WinBattleOutnumberedQuest:
|
||||
return "Win Battle Outnumbered";
|
||||
case SealedValueOneofCase.WinBattlesQuest: return "Win Battles";
|
||||
case SealedValueOneofCase.ApprehendOutlawQuest: return "Apprehend Outlaw";
|
||||
case SealedValueOneofCase.StartBlizzardQuest: return "Start Blizzard";
|
||||
case SealedValueOneofCase.StartEpidemicQuest: return "Start Epidemic";
|
||||
case SealedValueOneofCase.SpendOnFeastsQuest: return "Host Feasts";
|
||||
case SealedValueOneofCase.SendSuppliesQuest: return "Send Supplies";
|
||||
case SealedValueOneofCase.RestProvinceQuest: return "Rest Province";
|
||||
case SealedValueOneofCase.ReconProvincesQuest: return "Recon Provinces";
|
||||
case SealedValueOneofCase.RepairDevastationQuest: return "Repair Devastation";
|
||||
case SealedValueOneofCase.ReconSpecificProvincesQuest:
|
||||
return "Recon Specific Provinces";
|
||||
}
|
||||
|
||||
throw new ArgumentException($"unknown quest {quest}");
|
||||
|
||||
+40
-10
@@ -1064,13 +1064,12 @@ namespace eagle {
|
||||
|
||||
private async void HandleStreamingCall() {
|
||||
LogFlow("HandleStreamingCall STARTED");
|
||||
// Capture thread token outside try block so it's accessible in catch blocks
|
||||
CancellationToken threadToken;
|
||||
lock (this) { threadToken = _currentThreadToken; }
|
||||
try {
|
||||
AsyncDuplexStreamingCall<UpdateStreamRequest, UpdateStreamResponse> sc;
|
||||
CancellationToken threadToken;
|
||||
lock (this) {
|
||||
sc = _streamingCall;
|
||||
threadToken = _currentThreadToken;
|
||||
}
|
||||
lock (this) { sc = _streamingCall; }
|
||||
|
||||
var waitStartTime = DateTime.UtcNow;
|
||||
while (sc != null && !_currentThreadToken.IsCancellationRequested &&
|
||||
@@ -1256,10 +1255,14 @@ namespace eagle {
|
||||
case StatusCode.Cancelled:
|
||||
LogConnectionEvent("disconnect", "Cancelled", StatusCode.Cancelled);
|
||||
_remoteEagleClientLogger.LogLine($"Got exception {e}");
|
||||
// Only check the main cancellation token, not the thread-specific one
|
||||
// The thread token gets cancelled during normal reconnection and
|
||||
// shouldn't prevent it
|
||||
// If main app is shutting down, don't reconnect
|
||||
if (_cancellationToken.IsCancellationRequested) { return; }
|
||||
// If thread token was cancelled, something else (Connect() or
|
||||
// CheckForIdleTimeout) already initiated reconnect
|
||||
if (threadToken.IsCancellationRequested) {
|
||||
LogFlow("Cancelled: skipping reconnect (thread token cancelled)");
|
||||
return;
|
||||
}
|
||||
|
||||
ScheduleReconnect("Cancelled");
|
||||
|
||||
@@ -1308,6 +1311,13 @@ namespace eagle {
|
||||
MarkAllShardokGamesForResync();
|
||||
CancelAllPendingSubscriptionAcks();
|
||||
|
||||
// If thread token was cancelled, something else (like CheckForIdleTimeout)
|
||||
// already disposed the call and initiated reconnect. Don't schedule another.
|
||||
if (threadToken.IsCancellationRequested) {
|
||||
LogFlow("ObjectDisposed: skipping reconnect (thread token cancelled)");
|
||||
return;
|
||||
}
|
||||
|
||||
ScheduleReconnect("ObjectDisposed");
|
||||
} catch (Exception e) {
|
||||
// Catch-all for any unexpected exceptions. Without this, exceptions in an
|
||||
@@ -1321,6 +1331,12 @@ namespace eagle {
|
||||
MarkAllShardokGamesForResync();
|
||||
CancelAllPendingSubscriptionAcks();
|
||||
|
||||
// If thread token was cancelled, something else already initiated reconnect
|
||||
if (threadToken.IsCancellationRequested) {
|
||||
LogFlow($"UnexpectedException: skipping reconnect (thread token cancelled)");
|
||||
return;
|
||||
}
|
||||
|
||||
ScheduleReconnect($"UnexpectedException-{e.GetType().Name}");
|
||||
}
|
||||
|
||||
@@ -1342,11 +1358,18 @@ namespace eagle {
|
||||
/// Called when connection drops to unblock any waiting subscription tasks.
|
||||
/// </summary>
|
||||
private void CancelAllPendingSubscriptionAcks() {
|
||||
List<TaskCompletionSource<SubscriptionAck>> tcsList;
|
||||
lock (_pendingSubscriptionAcks) {
|
||||
foreach (var tcs in _pendingSubscriptionAcks.Values) { tcs.TrySetCanceled(); }
|
||||
|
||||
// Snapshot values and clear dictionary BEFORE cancelling to avoid
|
||||
// "Collection was modified" exception. TrySetCanceled() can trigger
|
||||
// synchronous continuations that re-enter this lock (reentrant) and
|
||||
// call Remove() while we're still iterating.
|
||||
tcsList = _pendingSubscriptionAcks.Values.ToList();
|
||||
_pendingSubscriptionAcks.Clear();
|
||||
}
|
||||
|
||||
// Cancel outside lock to avoid reentrancy issues
|
||||
foreach (var tcs in tcsList) { tcs.TrySetCanceled(); }
|
||||
}
|
||||
|
||||
private void StartIdleCheckTimer() {
|
||||
@@ -1406,6 +1429,13 @@ namespace eagle {
|
||||
$"[IDLE_TIMEOUT] No messages received in {idleTime:F1}s (max={MaxIdleSeconds}s), forcing reconnect");
|
||||
LogConnectionEvent("idle_timeout", $"idle_time={idleTime:F1}s");
|
||||
|
||||
// Cancel thread token BEFORE disposing the call. This prevents
|
||||
// HandleStreamingCall from scheduling its own reconnect when it
|
||||
// catches the ObjectDisposedException from the disposed call.
|
||||
// Without this, we get a race: both CheckForIdleTimeout and
|
||||
// HandleStreamingCall try to reconnect, leading to state confusion.
|
||||
lock (this) { _threadCancellationTokenSource?.Cancel(); }
|
||||
|
||||
var toCancel = _streamingCall;
|
||||
if (toCancel != null) {
|
||||
toCancel.Dispose();
|
||||
|
||||
+117
-6
@@ -147,6 +147,24 @@ namespace eagle {
|
||||
model);
|
||||
break;
|
||||
|
||||
case SealedValueOneofCase.SwearBrotherhoodWithHeroQuest:
|
||||
var brotherhoodDetails = quest.Details.SwearBrotherhoodWithHeroQuest;
|
||||
SetDynamicHeroQuestText(
|
||||
brotherhoodDetails.TargetHeroId,
|
||||
(heroName) => $"Swear brotherhood with {heroName}",
|
||||
"Swear brotherhood with a hero",
|
||||
model);
|
||||
break;
|
||||
|
||||
case SealedValueOneofCase.ApprehendOutlawQuest:
|
||||
var apprehendDetails = quest.Details.ApprehendOutlawQuest;
|
||||
SetDynamicHeroQuestText(
|
||||
apprehendDetails.OutlawHeroId,
|
||||
(heroName) => $"Apprehend the outlaw {heroName}",
|
||||
"Apprehend an outlaw",
|
||||
model);
|
||||
break;
|
||||
|
||||
default:
|
||||
// For all other quests, use the static method
|
||||
questLabel.text = ShortQuestString(quest, model);
|
||||
@@ -327,18 +345,111 @@ namespace eagle {
|
||||
var details = quest.Details.DevelopProvincesQuest;
|
||||
var targetMonths = quest.ComponentCount;
|
||||
var currentMonths = quest.ComponentsFulfilled;
|
||||
var progressText =
|
||||
currentMonths > 0 ? $" ({currentMonths}/{targetMonths} months)" : "";
|
||||
return $"Maintain {details.TargetProvinceCount} provinces with Develop orders for {targetMonths} months{progressText}";
|
||||
var currentProvinces =
|
||||
model.PlayerId.HasValue
|
||||
? model.ProvincesForFaction(model.PlayerId.Value)
|
||||
.Count(pid => model.Provinces[pid]
|
||||
.FullInfo?.ProvinceOrders ==
|
||||
ProvinceOrderType.Develop)
|
||||
: 0;
|
||||
return $"Maintain {details.TargetProvinceCount} provinces with Develop orders for {targetMonths} months ({currentProvinces}/{details.TargetProvinceCount} provinces, {currentMonths}/{targetMonths} months)";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.MobilizeProvincesQuest: {
|
||||
var details = quest.Details.MobilizeProvincesQuest;
|
||||
var targetMonths = quest.ComponentCount;
|
||||
var currentMonths = quest.ComponentsFulfilled;
|
||||
var progressText =
|
||||
currentMonths > 0 ? $" ({currentMonths}/{targetMonths} months)" : "";
|
||||
return $"Maintain {details.TargetProvinceCount} provinces with Mobilize orders for {targetMonths} months{progressText}";
|
||||
var currentProvinces =
|
||||
model.PlayerId.HasValue
|
||||
? model.ProvincesForFaction(model.PlayerId.Value)
|
||||
.Count(pid => model.Provinces[pid]
|
||||
.FullInfo?.ProvinceOrders ==
|
||||
ProvinceOrderType.Mobilize)
|
||||
: 0;
|
||||
return $"Maintain {details.TargetProvinceCount} provinces with Mobilize orders for {targetMonths} months ({currentProvinces}/{details.TargetProvinceCount} provinces, {currentMonths}/{targetMonths} months)";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.BattalionDiversityQuest:
|
||||
return "Have 3 different battalion types, each near full strength";
|
||||
|
||||
case SealedValueOneofCase.ReleaseAllPrisonersQuest:
|
||||
return "Release all prisoners (don't execute, move, or trade them)";
|
||||
|
||||
case SealedValueOneofCase.SwearBrotherhoodWithHeroQuest:
|
||||
return "Swear brotherhood with a hero";
|
||||
|
||||
case SealedValueOneofCase.BetrayAllyQuest: {
|
||||
var details = quest.Details.BetrayAllyQuest;
|
||||
return $"Break alliance with {model.FactionName(details.TargetFactionId)}";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.BorderSecurityQuest: {
|
||||
var details = quest.Details.BorderSecurityQuest;
|
||||
var provinceName = model.Provinces[details.TargetProvinceId].Name;
|
||||
return $"Control all provinces bordering {provinceName}";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.WinBattleOutnumberedQuest:
|
||||
return "Win a battle while outnumbered";
|
||||
|
||||
case SealedValueOneofCase.WinBattlesQuest: {
|
||||
var targetBattles = quest.ComponentCount;
|
||||
var wonBattles = quest.ComponentsFulfilled;
|
||||
return $"Win {targetBattles} battles ({wonBattles}/{targetBattles})";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.ApprehendOutlawQuest: {
|
||||
// This case is handled by SetQuestText with dynamic updates, this is fallback
|
||||
// only
|
||||
var details = quest.Details.ApprehendOutlawQuest;
|
||||
var heroName = GetHeroName(model, details.OutlawHeroId);
|
||||
return $"Apprehend the outlaw {heroName}";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.StartBlizzardQuest: {
|
||||
var details = quest.Details.StartBlizzardQuest;
|
||||
var provinceName = model.Provinces[details.ProvinceId].Name;
|
||||
return $"Start a blizzard in {provinceName}";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.StartEpidemicQuest: {
|
||||
var details = quest.Details.StartEpidemicQuest;
|
||||
var provinceName = model.Provinces[details.ProvinceId].Name;
|
||||
return $"Start an epidemic in {provinceName}";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.SpendOnFeastsQuest: {
|
||||
var details = quest.Details.SpendOnFeastsQuest;
|
||||
return $"Host feasts costing {details.TotalGold} gold ({quest.ComponentsFulfilled}/{quest.ComponentCount})";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.SendSuppliesQuest: {
|
||||
var details = quest.Details.SendSuppliesQuest;
|
||||
var provinceName = model.Provinces[details.TargetProvinceId].Name;
|
||||
return $"Send {details.TotalFood} food to {provinceName} ({quest.ComponentsFulfilled}/{quest.ComponentCount})";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.RestProvinceQuest: {
|
||||
var details = quest.Details.RestProvinceQuest;
|
||||
var provinceName = model.Provinces[details.TargetProvinceId].Name;
|
||||
return $"Keep {provinceName} at rest for {quest.ComponentCount} months ({quest.ComponentsFulfilled}/{quest.ComponentCount})";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.ReconProvincesQuest: {
|
||||
var details = quest.Details.ReconProvincesQuest;
|
||||
return $"Recon {details.TargetProvinceCount} provinces ({quest.ComponentsFulfilled}/{quest.ComponentCount})";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.ReconSpecificProvincesQuest: {
|
||||
var details = quest.Details.ReconSpecificProvincesQuest;
|
||||
var provinceNames =
|
||||
details.TargetProvinceIds.Select(pid => model.Provinces[pid].Name);
|
||||
return $"Recon {string.Join(", ", provinceNames)} ({quest.ComponentsFulfilled}/{quest.ComponentCount})";
|
||||
}
|
||||
|
||||
case SealedValueOneofCase.RepairDevastationQuest: {
|
||||
var details = quest.Details.RepairDevastationQuest;
|
||||
return $"Repair {details.TargetDevastationRepaired} devastation ({quest.ComponentsFulfilled}/{quest.ComponentCount})";
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -239,6 +239,8 @@ public class SettingsPanelController : MonoBehaviour {
|
||||
bugReportPanel.Configure(
|
||||
gameModelProvider: () => eagleGameController?.GameModel,
|
||||
gameIdProvider: () => eagleGameController?.ModelUpdater?.GameId);
|
||||
// Pass settings panel reference so it can be hidden during screenshot capture
|
||||
bugReportPanel.settingsPanel = panel;
|
||||
bugReportPanel.Show();
|
||||
}
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+4
-3
@@ -1,19 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e41d0485129e4d0da6d21b966709f4b
|
||||
guid: 744385d5812c6480f89b169c3604104f
|
||||
AudioImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 6
|
||||
serializedVersion: 8
|
||||
defaultSettings:
|
||||
serializedVersion: 2
|
||||
loadType: 0
|
||||
sampleRateSetting: 0
|
||||
sampleRateOverride: 44100
|
||||
compressionFormat: 1
|
||||
quality: 1
|
||||
conversionMode: 0
|
||||
preloadAudioData: 0
|
||||
platformSettingOverrides: {}
|
||||
forceToMono: 0
|
||||
normalize: 1
|
||||
preloadAudioData: 1
|
||||
loadInBackground: 0
|
||||
ambisonic: 0
|
||||
3D: 1
|
||||
+36
-9
File diff suppressed because one or more lines are too long
+2
-1
@@ -562,7 +562,8 @@ namespace Eagle0.Tutorial {
|
||||
"command_issue_orders",
|
||||
"Issue Orders",
|
||||
"Set standing orders for your provinces.\n\n" +
|
||||
"Orders determine how provinces behave each turn - prioritize military, economy, or defense. You can also designate a Focus Province for special attention.");
|
||||
"Orders determine how provinces behave each turn - prioritize military, economy, or defense.\n\n" +
|
||||
"You can also designate a <b>Focus Province</b> where your vassals will send excess supplies.");
|
||||
registry.RegisterTutorial(issueOrders, "command_panel_IssueOrdersCommand");
|
||||
|
||||
// Control Weather command
|
||||
|
||||
+118
-8
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using eagle;
|
||||
using Newtonsoft.Json;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
@@ -24,6 +26,13 @@ namespace common.GUIUtils {
|
||||
public Button cancelButton;
|
||||
public TextMeshProUGUI statusText;
|
||||
|
||||
[Header("Screenshot")]
|
||||
public Button screenshotButton;
|
||||
public TextMeshProUGUI screenshotStatusText;
|
||||
public GameObject screenshotPreviewContainer; // Container with LayoutElement
|
||||
public RawImage screenshotPreview;
|
||||
public GameObject settingsPanel;
|
||||
|
||||
// Optional reference to game model for state capture
|
||||
private Func<IGameModel> _gameModelProvider;
|
||||
private Func<long?> _gameIdProvider;
|
||||
@@ -32,6 +41,8 @@ namespace common.GUIUtils {
|
||||
private const string WebhookUrlKey = "bugReportWebhookUrl";
|
||||
|
||||
private bool _isSubmitting = false;
|
||||
private bool _hasPrePopulatedException = false;
|
||||
private byte[] _capturedScreenshot;
|
||||
|
||||
void Awake() {
|
||||
panel.SetActive(false);
|
||||
@@ -43,9 +54,11 @@ namespace common.GUIUtils {
|
||||
if (blockerButton == null) { blockerButton = modalBlocker.AddComponent<Button>(); }
|
||||
blockerButton.onClick.AddListener(Hide);
|
||||
}
|
||||
|
||||
submitButton.onClick.AddListener(OnSubmitClicked);
|
||||
cancelButton.onClick.AddListener(OnCancelClicked);
|
||||
|
||||
if (screenshotButton != null)
|
||||
screenshotButton.onClick.AddListener(OnScreenshotButtonClicked);
|
||||
}
|
||||
|
||||
void Update() {
|
||||
@@ -75,17 +88,47 @@ namespace common.GUIUtils {
|
||||
public static string GetWebhookUrl() { return PlayerPrefs.GetString(WebhookUrlKey, ""); }
|
||||
|
||||
public void Show() {
|
||||
descriptionInput.text = "";
|
||||
// Auto-include recent exceptions (unless already pre-populated from error popup)
|
||||
string prePopulated = null;
|
||||
if (!_hasPrePopulatedException &&
|
||||
ErrorHandler.Instance?.HasRecentExceptions(TimeSpan.FromMinutes(5)) == true) {
|
||||
var exceptionText = ErrorHandler.Instance.GetRecentExceptionsText();
|
||||
prePopulated = $"Recent errors:\n\n{exceptionText}\n\nDescription:\n";
|
||||
}
|
||||
_hasPrePopulatedException = false; // Reset for next time
|
||||
|
||||
ShowMainPanel(prePopulated);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the bug report panel with pre-populated exception info.
|
||||
/// Used when clicking "Report Bug" from the error popup.
|
||||
/// </summary>
|
||||
public void ShowWithExceptionInfo(string exceptionInfo) {
|
||||
_hasPrePopulatedException = true; // Skip auto-include since we have specific exception
|
||||
ShowMainPanel($"Exception occurred:\n\n{exceptionInfo}\n\nAdditional details:\n");
|
||||
}
|
||||
|
||||
private void ShowMainPanel(string prePopulatedText = null) {
|
||||
if (!string.IsNullOrEmpty(prePopulatedText)) {
|
||||
descriptionInput.text = prePopulatedText;
|
||||
} else {
|
||||
descriptionInput.text = "";
|
||||
}
|
||||
statusText.text = "";
|
||||
_isSubmitting = false;
|
||||
_capturedScreenshot = null;
|
||||
if (screenshotStatusText != null) screenshotStatusText.text = "";
|
||||
if (screenshotPreviewContainer != null) screenshotPreviewContainer.SetActive(false);
|
||||
UpdateButtonState();
|
||||
|
||||
panel.SetActive(true);
|
||||
modalBlocker.SetActive(true);
|
||||
|
||||
// Focus the input field
|
||||
// Focus the input field and move caret to end
|
||||
descriptionInput.Select();
|
||||
descriptionInput.ActivateInputField();
|
||||
descriptionInput.caretPosition = descriptionInput.text.Length;
|
||||
}
|
||||
|
||||
public void Hide() {
|
||||
@@ -95,6 +138,47 @@ namespace common.GUIUtils {
|
||||
|
||||
private void OnCancelClicked() { Hide(); }
|
||||
|
||||
public void OnScreenshotButtonClicked() { StartCoroutine(CaptureScreenshotCoroutine()); }
|
||||
|
||||
private IEnumerator CaptureScreenshotCoroutine() {
|
||||
if (screenshotStatusText != null) screenshotStatusText.text = "Capturing...";
|
||||
|
||||
// Hide ALL UI that might be overlaying the game
|
||||
panel.SetActive(false);
|
||||
modalBlocker.SetActive(false);
|
||||
if (settingsPanel != null) settingsPanel.SetActive(false);
|
||||
|
||||
// Wait for render to complete without UI
|
||||
yield return new WaitForEndOfFrame();
|
||||
|
||||
// Capture
|
||||
Texture2D screenshot =
|
||||
new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
|
||||
screenshot.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
|
||||
screenshot.Apply();
|
||||
|
||||
// Use PNG to avoid compression artifacts
|
||||
_capturedScreenshot = screenshot.EncodeToPNG();
|
||||
Destroy(screenshot);
|
||||
|
||||
// Restore UI
|
||||
if (settingsPanel != null) settingsPanel.SetActive(true);
|
||||
panel.SetActive(true);
|
||||
modalBlocker.SetActive(true);
|
||||
|
||||
if (screenshotStatusText != null)
|
||||
screenshotStatusText.text =
|
||||
$"Screenshot captured ({_capturedScreenshot.Length / 1024}KB)";
|
||||
|
||||
// Show preview thumbnail
|
||||
if (screenshotPreview != null) {
|
||||
var previewTex = new Texture2D(2, 2);
|
||||
previewTex.LoadImage(_capturedScreenshot);
|
||||
screenshotPreview.texture = previewTex;
|
||||
if (screenshotPreviewContainer != null) screenshotPreviewContainer.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnSubmitClicked() {
|
||||
if (_isSubmitting) return;
|
||||
|
||||
@@ -212,6 +296,11 @@ namespace common.GUIUtils {
|
||||
webhookUrl.Contains("discord.com") || webhookUrl.Contains("discordapp.com");
|
||||
bool isSlack = webhookUrl.Contains("slack.com");
|
||||
|
||||
// Use multipart form for Discord with screenshot
|
||||
if (isDiscord && _capturedScreenshot != null) {
|
||||
return await SendDiscordWithScreenshot(webhookUrl, report, _capturedScreenshot);
|
||||
}
|
||||
|
||||
string json;
|
||||
if (isDiscord) {
|
||||
json = BuildDiscordPayload(report);
|
||||
@@ -241,6 +330,29 @@ namespace common.GUIUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool>
|
||||
SendDiscordWithScreenshot(string webhookUrl, BugReport report, byte[] screenshot) {
|
||||
var form = new List<IMultipartFormSection>();
|
||||
form.Add(new MultipartFormFileSection(
|
||||
"file",
|
||||
screenshot,
|
||||
"screenshot.png",
|
||||
"image/png"));
|
||||
form.Add(new MultipartFormDataSection("payload_json", BuildDiscordPayload(report)));
|
||||
|
||||
using var request = UnityWebRequest.Post(webhookUrl, form);
|
||||
var operation = request.SendWebRequest();
|
||||
|
||||
while (!operation.isDone) { await Task.Yield(); }
|
||||
|
||||
if (request.result != UnityWebRequest.Result.Success) {
|
||||
Debug.LogError($"Discord screenshot upload failed: {request.error}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string BuildDiscordPayload(BugReport report) {
|
||||
// Discord webhook format with embeds for nice formatting
|
||||
var truncatedLogs = TruncateForDiscord(report.RecentLogs, 1000);
|
||||
@@ -342,11 +454,9 @@ namespace common.GUIUtils {
|
||||
|
||||
private string EscapeJson(string text) {
|
||||
if (string.IsNullOrEmpty(text)) return "";
|
||||
return text.Replace("\\", "\\\\")
|
||||
.Replace("\"", "\\\"")
|
||||
.Replace("\n", "\\n")
|
||||
.Replace("\r", "\\r")
|
||||
.Replace("\t", "\\t");
|
||||
// JsonConvert.ToString returns "escaped string" with quotes, so strip them
|
||||
var serialized = JsonConvert.ToString(text);
|
||||
return serialized.Substring(1, serialized.Length - 2);
|
||||
}
|
||||
|
||||
private class BugReport {
|
||||
|
||||
+30
-1
@@ -8,11 +8,15 @@ using UnityEngine.UI;
|
||||
|
||||
namespace common.GUIUtils {
|
||||
public class ErrorHandler : MonoBehaviour {
|
||||
public static ErrorHandler Instance { get; private set; }
|
||||
|
||||
public GameObject panel;
|
||||
public TextMeshProUGUI errorTextField;
|
||||
public TextMeshProUGUI title;
|
||||
public Button dismissButton;
|
||||
public Button copyButton;
|
||||
public Button reportBugButton;
|
||||
public BugReportPanelController bugReportPanel;
|
||||
|
||||
private readonly int _maxErrors = 5;
|
||||
|
||||
@@ -83,7 +87,10 @@ namespace common.GUIUtils {
|
||||
}
|
||||
|
||||
// Register for log messages as early as possible
|
||||
void Awake() { Application.logMessageReceivedThreaded += HandleLog; }
|
||||
void Awake() {
|
||||
Instance = this;
|
||||
Application.logMessageReceivedThreaded += HandleLog;
|
||||
}
|
||||
|
||||
void Update() {
|
||||
// Handle errors that occurred before MainQueue was ready
|
||||
@@ -112,5 +119,27 @@ namespace common.GUIUtils {
|
||||
editor.SelectAll();
|
||||
editor.Copy();
|
||||
}
|
||||
|
||||
public void ReportBugClicked() {
|
||||
if (bugReportPanel != null) { bugReportPanel.ShowWithExceptionInfo(AllMessageText); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if there are any exceptions within the specified time window.
|
||||
/// </summary>
|
||||
public bool HasRecentExceptions(TimeSpan maxAge) {
|
||||
lock (_messages) { return _messages.Any(m => DateTime.UtcNow - m.Time < maxAge); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get formatted text of recent exceptions within the last 5 minutes.
|
||||
/// </summary>
|
||||
public string GetRecentExceptionsText() {
|
||||
lock (_messages) {
|
||||
var recent =
|
||||
_messages.Where(m => DateTime.UtcNow - m.Time < TimeSpan.FromMinutes(5));
|
||||
return string.Join("\n\n", recent.Select(m => m.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
-2
@@ -2,16 +2,56 @@
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
public class GeneralClickDetector : MonoBehaviour, IPointerClickHandler {
|
||||
public class GeneralClickDetector : MonoBehaviour,
|
||||
IPointerClickHandler,
|
||||
IPointerDownHandler,
|
||||
IPointerUpHandler {
|
||||
public UnityEvent<Vector2> onLeftClick;
|
||||
public UnityEvent<Vector2> onRightClick;
|
||||
|
||||
private const float LongPressSeconds = 0.5f;
|
||||
private const float MovementTolerancePixels = 10f;
|
||||
|
||||
private float? _pointerDownTime;
|
||||
private Vector2 _pointerDownPosition;
|
||||
private bool _longPressTriggered;
|
||||
|
||||
public void Start() {}
|
||||
|
||||
public void Update() {
|
||||
if (_pointerDownTime is {} downTime && !_longPressTriggered) {
|
||||
var elapsed = Time.time - downTime;
|
||||
var moved = Vector2.Distance(Input.mousePosition, _pointerDownPosition);
|
||||
|
||||
if (moved > MovementTolerancePixels) {
|
||||
// Finger moved too much, cancel long-press detection
|
||||
_pointerDownTime = null;
|
||||
} else if (elapsed > LongPressSeconds) {
|
||||
// Long-press detected - trigger right-click
|
||||
_longPressTriggered = true;
|
||||
onRightClick.Invoke(_pointerDownPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerDown(PointerEventData eventData) {
|
||||
// Only track long-press for touch input (pointerId >= 0)
|
||||
// Mouse has negative pointerIds (-1 left, -2 right, -3 middle)
|
||||
if (eventData.button == PointerEventData.InputButton.Left && eventData.pointerId >= 0) {
|
||||
_pointerDownTime = Time.time;
|
||||
_pointerDownPosition = eventData.position;
|
||||
_longPressTriggered = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerUp(PointerEventData eventData) { _pointerDownTime = null; }
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData) {
|
||||
var position = eventData.position;
|
||||
if (eventData.button == PointerEventData.InputButton.Left) {
|
||||
onLeftClick.Invoke(position);
|
||||
// Don't trigger left-click if we already triggered a long-press
|
||||
if (!_longPressTriggered) { onLeftClick.Invoke(position); }
|
||||
_longPressTriggered = false;
|
||||
} else if (eventData.button == PointerEventData.InputButton.Right) {
|
||||
onRightClick.Invoke(position);
|
||||
}
|
||||
|
||||
@@ -3172,23 +3172,29 @@ type WhatsNewPageData struct {
|
||||
Error string
|
||||
}
|
||||
|
||||
// fetchWhatsNewData fetches the what's-new JSON from S3
|
||||
// whatsNewPublicURL is the public URL for the what's-new JSON (read via HTTP, no credentials needed)
|
||||
const whatsNewPublicURL = "https://assets.eagle0.net/whats-new.json"
|
||||
|
||||
// fetchWhatsNewData fetches the what's-new JSON via public HTTP URL
|
||||
func fetchWhatsNewData() (*WhatsNewData, error) {
|
||||
bb, err := aws.NewBucketBasics()
|
||||
resp, err := http.Get(whatsNewPublicURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create S3 client: %w", err)
|
||||
return nil, fmt.Errorf("failed to fetch what's-new data: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
log.Printf("whats-new.json not found, returning empty data")
|
||||
return &WhatsNewData{Entries: []WhatsNewEntry{}}, nil
|
||||
}
|
||||
|
||||
data, err := bb.FetchBytes(whatsNewBucket, whatsNewKey)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("failed to fetch what's-new data: HTTP %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
// Check if it's a "not found" error - only then return empty data
|
||||
if strings.Contains(err.Error(), "NoSuchKey") {
|
||||
log.Printf("whats-new.json not found in S3, returning empty data")
|
||||
return &WhatsNewData{Entries: []WhatsNewEntry{}}, nil
|
||||
}
|
||||
// For any other error, return it so we can see what's wrong
|
||||
log.Printf("Failed to fetch whats-new.json: %v", err)
|
||||
return nil, fmt.Errorf("failed to fetch what's-new data: %w", err)
|
||||
return nil, fmt.Errorf("failed to read what's-new data: %w", err)
|
||||
}
|
||||
|
||||
var whatsNew WhatsNewData
|
||||
@@ -3196,7 +3202,7 @@ func fetchWhatsNewData() (*WhatsNewData, error) {
|
||||
return nil, fmt.Errorf("failed to parse what's-new JSON: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("Fetched %d what's-new entries from S3", len(whatsNew.Entries))
|
||||
log.Printf("Fetched %d what's-new entries", len(whatsNew.Entries))
|
||||
return &whatsNew, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -53,18 +53,29 @@ func ReadAwsConfig() aws.Config {
|
||||
configMap, err := readConfig()
|
||||
var key string
|
||||
var secret string
|
||||
var endpoint string
|
||||
if err == nil {
|
||||
key = configMap["access_key"]
|
||||
secret = configMap["secret_key"]
|
||||
}
|
||||
if err != nil {
|
||||
if key == "" || secret == "" {
|
||||
// Try DO_SPACES_* env vars (used in docker-compose)
|
||||
key = os.Getenv("DO_SPACES_ACCESS_KEY")
|
||||
secret = os.Getenv("DO_SPACES_SECRET_KEY")
|
||||
endpoint = os.Getenv("DO_SPACES_ENDPOINT")
|
||||
}
|
||||
if key == "" || secret == "" {
|
||||
// Fall back to ACCESS_KEY_ID/SECRET_KEY (used by some CI workflows)
|
||||
key = os.Getenv("ACCESS_KEY_ID")
|
||||
secret = os.Getenv("SECRET_KEY")
|
||||
}
|
||||
if endpoint == "" {
|
||||
endpoint = "https://sfo3.digitaloceanspaces.com"
|
||||
}
|
||||
|
||||
sdkConfig := aws.Config{
|
||||
Credentials: credentials.NewStaticCredentialsProvider(key, secret, ""),
|
||||
BaseEndpoint: aws.String("https://sfo3.digitaloceanspaces.com"),
|
||||
BaseEndpoint: aws.String(endpoint),
|
||||
Region: "us-east-1",
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")
|
||||
load("@grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("@rules_scala//scala_proto:scala_proto.bzl", "scala_proto_library")
|
||||
|
||||
|
||||
@@ -45,6 +45,22 @@ message QuestDetails {
|
||||
FightBeastsAloneQuest fight_beasts_alone_quest = 28;
|
||||
DevelopProvincesQuest develop_provinces_quest = 29;
|
||||
MobilizeProvincesQuest mobilize_provinces_quest = 30;
|
||||
BattalionDiversityQuest battalion_diversity_quest = 31;
|
||||
ReleaseAllPrisonersQuest release_all_prisoners_quest = 32;
|
||||
SwearBrotherhoodWithHeroQuest swear_brotherhood_with_hero_quest = 33;
|
||||
BetrayAllyQuest betray_ally_quest = 34;
|
||||
BorderSecurityQuest border_security_quest = 35;
|
||||
WinBattleOutnumberedQuest win_battle_outnumbered_quest = 36;
|
||||
WinBattlesQuest win_battles_quest = 37;
|
||||
ApprehendOutlawQuest apprehend_outlaw_quest = 38;
|
||||
StartBlizzardQuest start_blizzard_quest = 39;
|
||||
StartEpidemicQuest start_epidemic_quest = 40;
|
||||
SpendOnFeastsQuest spend_on_feasts_quest = 41;
|
||||
SendSuppliesQuest send_supplies_quest = 42;
|
||||
RestProvinceQuest rest_province_quest = 43;
|
||||
ReconProvincesQuest recon_provinces_quest = 44;
|
||||
RepairDevastationQuest repair_devastation_quest = 45;
|
||||
ReconSpecificProvincesQuest recon_specific_provinces_quest = 46;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,4 +183,65 @@ message DevelopProvincesQuest {
|
||||
|
||||
message MobilizeProvincesQuest {
|
||||
int32 target_province_count = 1;
|
||||
}
|
||||
|
||||
message BattalionDiversityQuest {
|
||||
}
|
||||
|
||||
message ReleaseAllPrisonersQuest {
|
||||
}
|
||||
|
||||
message SwearBrotherhoodWithHeroQuest {
|
||||
int32 target_hero_id = 1;
|
||||
}
|
||||
|
||||
message BetrayAllyQuest {
|
||||
int32 target_faction_id = 1;
|
||||
}
|
||||
|
||||
message BorderSecurityQuest {
|
||||
int32 target_province_id = 1;
|
||||
}
|
||||
|
||||
message WinBattleOutnumberedQuest {
|
||||
}
|
||||
|
||||
message WinBattlesQuest {
|
||||
}
|
||||
|
||||
message ApprehendOutlawQuest {
|
||||
int32 outlaw_hero_id = 1;
|
||||
}
|
||||
|
||||
message StartBlizzardQuest {
|
||||
int32 province_id = 1;
|
||||
}
|
||||
|
||||
message StartEpidemicQuest {
|
||||
int32 province_id = 1;
|
||||
}
|
||||
|
||||
message SpendOnFeastsQuest {
|
||||
int32 total_gold = 1;
|
||||
}
|
||||
|
||||
message SendSuppliesQuest {
|
||||
int32 target_province_id = 1;
|
||||
int32 total_food = 2;
|
||||
}
|
||||
|
||||
message RestProvinceQuest {
|
||||
int32 target_province_id = 1;
|
||||
}
|
||||
|
||||
message ReconProvincesQuest {
|
||||
int32 target_province_count = 1;
|
||||
}
|
||||
|
||||
message RepairDevastationQuest {
|
||||
int32 target_devastation_repaired = 1;
|
||||
}
|
||||
|
||||
message ReconSpecificProvincesQuest {
|
||||
repeated int32 target_province_ids = 1;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
|
||||
cc_proto_library(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("@rules_scala//scala_proto:scala_proto.bzl", "scala_proto_library")
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("@rules_scala//scala_proto:scala_proto.bzl", "scala_proto_library")
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("@rules_scala//scala_proto:scala_proto.bzl", "scala_proto_library")
|
||||
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
load("@rules_scala//scala:scala.bzl", "scala_binary", "scala_library")
|
||||
|
||||
filegroup(
|
||||
name = "api_keys_data",
|
||||
srcs = glob(["*_keys.txt"]),
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "api_keys",
|
||||
srcs = ["ApiKeys.scala"],
|
||||
data = [":api_keys_data"],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ object ClaudeServiceImpl {
|
||||
val model: String = "claude-sonnet-4-20250514"
|
||||
val maxTokens = 2048
|
||||
|
||||
private val apiKey = ApiKeys.anthropic
|
||||
private val baseURL = new URL("https://api.anthropic.com/v1/messages")
|
||||
private val apiKey = ApiKeys.anthropic
|
||||
private val baseURL: URL = URI.create("https://api.anthropic.com/v1/messages").toURL
|
||||
private def dictionaryFor(
|
||||
modelName: String
|
||||
): Map[String, Any] = Map(
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ object OpenAIChatCompletionsServiceImpl {
|
||||
val gpt5: String = "gpt-5.1"
|
||||
|
||||
private val apiKey = ApiKeys.openAI
|
||||
private val baseURL = new URL("https://api.openai.com/v1/chat/completions")
|
||||
private val baseURL: URL = URI.create("https://api.openai.com/v1/chat/completions").toURL
|
||||
private val temperature: Double = 1.0
|
||||
|
||||
// Non-reasoning models have -mini or -nano suffix; all others support reasoning_effort
|
||||
|
||||
@@ -26,7 +26,7 @@ object OpenAIResponsesServiceImpl {
|
||||
val gpt5: String = "gpt-5.1"
|
||||
|
||||
private val apiKey = ApiKeys.openAI
|
||||
private val baseURL = new URL("https://api.openai.com/v1/responses")
|
||||
private val baseURL: URL = URI.create("https://api.openai.com/v1/responses").toURL
|
||||
private val temperature: Double = 1.0
|
||||
|
||||
private def baseRequest(timeoutSeconds: Int): HttpRequest.Builder =
|
||||
|
||||
+53
-1
@@ -6,9 +6,14 @@ import net.eagle0.eagle.library.util.faction_utils.FactionUtils
|
||||
import net.eagle0.eagle.library.util.quest_fulfillment.QuestFulfillmentUtils
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.faction.FactionRelationship.RelationshipLevel.Ally
|
||||
import net.eagle0.eagle.model.state.faction.FactionT
|
||||
import net.eagle0.eagle.model.state.hero.HeroT
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.model.state.quest.{
|
||||
ApprehendOutlawQuest,
|
||||
BetrayAllyQuest,
|
||||
BorderSecurityQuest,
|
||||
DefeatFactionQuest,
|
||||
DevelopProvincesQuest,
|
||||
DismissSpecificVassalQuest,
|
||||
@@ -18,11 +23,16 @@ import net.eagle0.eagle.model.state.quest.{
|
||||
Quest,
|
||||
ReleasePrisonerQuest,
|
||||
RescueImprisonedLeaderQuest,
|
||||
RestProvinceQuest,
|
||||
ReturnPrisonerQuest,
|
||||
SendSuppliesQuest,
|
||||
StartBlizzardQuest,
|
||||
StartEpidemicQuest,
|
||||
SwearBrotherhoodWithHeroQuest,
|
||||
TruceCountQuest,
|
||||
TruceWithFactionQuest
|
||||
}
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroType.Prisoner
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroType.{Outlaw, Prisoner}
|
||||
|
||||
case class CheckForFailedQuestsAction(
|
||||
gameId: GameId,
|
||||
@@ -30,6 +40,7 @@ case class CheckForFailedQuestsAction(
|
||||
currentRoundId: RoundId,
|
||||
provinces: Vector[ProvinceT],
|
||||
factions: Vector[FactionT],
|
||||
heroes: Map[HeroId, HeroT],
|
||||
heroBackstoryTextIdLookup: HeroId => String
|
||||
) extends ProtolessSequentialResultsAction {
|
||||
override def results: Vector[ActionResultT] =
|
||||
@@ -139,6 +150,47 @@ case class CheckForFailedQuestsAction(
|
||||
// Fails if the faction has fewer provinces than the target count
|
||||
val factionProvinceCount = provinces.count(_.rulingFactionId == province.rulingFactionId)
|
||||
factionProvinceCount < q.targetProvinceCount
|
||||
case SwearBrotherhoodWithHeroQuest(targetHeroId) =>
|
||||
// Fails if the target hero is no longer in the faction
|
||||
!FactionUtils.heroIsInFaction(targetHeroId, province.rulingFactionId.get, heroes)
|
||||
case BetrayAllyQuest(targetFactionId) =>
|
||||
// Fails if the target faction no longer exists or is no longer an ally
|
||||
!factions.exists(_.id == targetFactionId) ||
|
||||
!factions
|
||||
.find(_.id == province.rulingFactionId.get)
|
||||
.exists(
|
||||
_.factionRelationships.exists(r => r.targetFactionId == targetFactionId && r.relationshipLevel == Ally)
|
||||
)
|
||||
case BorderSecurityQuest(targetProvinceId) =>
|
||||
// Fails if the target province is no longer controlled by the faction
|
||||
!provinces
|
||||
.find(_.id == targetProvinceId)
|
||||
.exists(_.rulingFactionId == province.rulingFactionId)
|
||||
case ApprehendOutlawQuest(outlawHeroId) =>
|
||||
// Fails if the hero is no longer an outlaw anywhere (e.g., apprehended by someone else)
|
||||
// Moving to a different province is fine - quest remains valid
|
||||
!provinces.exists(
|
||||
_.unaffiliatedHeroes.exists(uh => uh.heroId == outlawHeroId && uh.unaffiliatedHeroType == Outlaw)
|
||||
)
|
||||
case _: StartBlizzardQuest =>
|
||||
// Never fails - if a blizzard already exists, quest creation should not offer this
|
||||
false
|
||||
case _: StartEpidemicQuest =>
|
||||
// Never fails - if an epidemic already exists, quest creation should not offer this
|
||||
false
|
||||
case SendSuppliesQuest(_, _, targetProvinceId, _) =>
|
||||
// Fails if target province is no longer owned by an enemy faction
|
||||
val targetProvince = provinces.find(_.id == targetProvinceId)
|
||||
targetProvince.forall(tp =>
|
||||
tp.rulingFactionId.isEmpty ||
|
||||
tp.rulingFactionId == province.rulingFactionId
|
||||
)
|
||||
case RestProvinceQuest(_, _, targetProvinceId) =>
|
||||
// Fails if we no longer own the target province
|
||||
!provinces.exists(p =>
|
||||
p.id == targetProvinceId &&
|
||||
p.rulingFactionId == province.rulingFactionId
|
||||
)
|
||||
case _ => false
|
||||
}
|
||||
|
||||
|
||||
+54
-1
@@ -17,6 +17,10 @@ import net.eagle0.eagle.model.state.province.ProvinceOrderType
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.model.state.quest.{
|
||||
AllianceQuest,
|
||||
ApprehendOutlawQuest,
|
||||
BattalionDiversityQuest,
|
||||
BetrayAllyQuest,
|
||||
BorderSecurityQuest,
|
||||
ComponentQuest,
|
||||
DefeatFactionQuest,
|
||||
DevelopProvincesQuest,
|
||||
@@ -31,17 +35,23 @@ import net.eagle0.eagle.model.state.quest.{
|
||||
ImproveInfrastructureQuest,
|
||||
MobilizeProvincesQuest,
|
||||
Quest,
|
||||
ReleaseAllPrisonersQuest,
|
||||
ReleasePrisonerQuest,
|
||||
RescueImprisonedLeaderQuest,
|
||||
ReturnPrisonerQuest,
|
||||
SpecificExpansionQuest,
|
||||
StartBlizzardQuest,
|
||||
StartEpidemicQuest,
|
||||
SuppressRiotByForceQuest,
|
||||
SwearBrotherhoodWithHeroQuest,
|
||||
TotalDevelopmentQuest,
|
||||
TruceCountQuest,
|
||||
TruceWithFactionQuest,
|
||||
UpgradeBattalionQuest,
|
||||
WealthQuest
|
||||
WealthQuest,
|
||||
WinBattleOutnumberedQuest
|
||||
}
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroType.{MovingPrisoner, Prisoner}
|
||||
import net.eagle0.eagle.model.state.BattalionType
|
||||
import net.eagle0.eagle.model.state.BattalionTypeId
|
||||
|
||||
@@ -126,6 +136,17 @@ case class CheckForFulfilledQuestsAction(
|
||||
battalionTypeId
|
||||
).capacity
|
||||
)
|
||||
case BattalionDiversityQuest =>
|
||||
// Fulfilled when province has 3+ different battalion types, each at near-full capacity (80%)
|
||||
val provinceBattalions = province.battalionIds.flatMap(battalionWithId)
|
||||
val typesAtNearFullCapacity = provinceBattalions
|
||||
.groupBy(_.typeId)
|
||||
.count {
|
||||
case (typeId, batts) =>
|
||||
val capacity = battalionType(typeId).capacity
|
||||
batts.exists(_.size >= 0.8 * capacity)
|
||||
}
|
||||
typesAtNearFullCapacity >= 3
|
||||
case GrandArmyQuest(totalTroopCount) =>
|
||||
province.battalionIds
|
||||
.flatMap(battalionWithId)
|
||||
@@ -170,6 +191,38 @@ case class CheckForFulfilledQuestsAction(
|
||||
false // action quests
|
||||
case FightBeastsAloneQuest =>
|
||||
false // action quest - fulfilled in SuppressBeastsCommand
|
||||
case ReleaseAllPrisonersQuest =>
|
||||
// Fulfilled when there are no prisoners or moving prisoners in faction's provinces
|
||||
val factionProvinces = provinces.filter(_.rulingFactionId == province.rulingFactionId)
|
||||
!factionProvinces.exists(
|
||||
_.unaffiliatedHeroes.exists(uh =>
|
||||
uh.unaffiliatedHeroType == Prisoner || uh.unaffiliatedHeroType == MovingPrisoner
|
||||
)
|
||||
)
|
||||
case _: SwearBrotherhoodWithHeroQuest =>
|
||||
false // action quest - fulfilled in SwearBrotherhoodCommand
|
||||
case _: BetrayAllyQuest =>
|
||||
false // action quest - fulfilled in BreakAllianceResolutionHelpers
|
||||
case BorderSecurityQuest(targetProvinceId) =>
|
||||
// Fulfilled when all neighbors of the target province are controlled by the faction
|
||||
provinceWithId(targetProvinceId).exists { targetProvince =>
|
||||
targetProvince.neighbors.forall { neighbor =>
|
||||
provinceWithId(neighbor.provinceId).exists { neighborProvince =>
|
||||
neighborProvince.rulingFactionId == province.rulingFactionId
|
||||
}
|
||||
}
|
||||
}
|
||||
case WinBattleOutnumberedQuest =>
|
||||
false // action quest - fulfilled in ResolveBattleAction
|
||||
case _: StartBlizzardQuest =>
|
||||
false // action quest - fulfilled in ControlWeatherCommand
|
||||
case _: StartEpidemicQuest =>
|
||||
false // action quest - fulfilled in ControlWeatherCommand
|
||||
// Note: WinBattlesQuest is handled by ComponentQuest case above
|
||||
// Note: SpendOnFeastsQuest, SendSuppliesQuest, RestProvinceQuest,
|
||||
// ReconProvincesQuest, ReconSpecificProvincesQuest, RepairDevastationQuest are ComponentQuests
|
||||
case _: ApprehendOutlawQuest =>
|
||||
false // action quest - fulfilled in ApprehendOutlawCommand
|
||||
}
|
||||
|
||||
private def incrementProvinceOrderQuestProgress(
|
||||
|
||||
+6
-4
@@ -27,6 +27,7 @@ import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.hero.HeroT
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.model.state.RoundPhase.ReconResolution
|
||||
import net.eagle0.eagle.GameId
|
||||
|
||||
case class EndDiplomacyResolutionPhaseAction(
|
||||
gameState: GameState,
|
||||
@@ -220,7 +221,7 @@ private object EndDiplomacyResolutionPhaseActionHelpers {
|
||||
(ba: BreakAlliance, fr: FunctionalRandom) => {
|
||||
val provinces = currentGameState.provinces.values.toVector
|
||||
val currentDate = currentGameState.currentDate.get
|
||||
resultsForBreakAlliance(ba, fr, provinces, factions, currentDate)
|
||||
resultsForBreakAlliance(ba, fr, provinces, factions, currentDate, currentGameState.gameId)
|
||||
},
|
||||
functionalRandom
|
||||
)(factions)
|
||||
@@ -414,7 +415,8 @@ private object EndDiplomacyResolutionPhaseActionHelpers {
|
||||
functionalRandom: FunctionalRandom,
|
||||
provinces: Vector[ProvinceT],
|
||||
factions: Vector[FactionT],
|
||||
currentDate: Date
|
||||
currentDate: Date,
|
||||
gameId: GameId
|
||||
): RandomState[Vector[ActionResultT]] =
|
||||
breakAllianceOffer.status match {
|
||||
case Accepted =>
|
||||
@@ -424,9 +426,9 @@ private object EndDiplomacyResolutionPhaseActionHelpers {
|
||||
currentDate = currentDate,
|
||||
provinces = provinces,
|
||||
factions = factions,
|
||||
functionalRandom = functionalRandom
|
||||
functionalRandom = functionalRandom,
|
||||
gameId = gameId
|
||||
)
|
||||
.map(Vector(_))
|
||||
case Rejected =>
|
||||
// This one shouldn't be possible, but we'll resolve in the helper
|
||||
BreakAllianceResolutionHelpers
|
||||
|
||||
+2
-1
@@ -74,7 +74,8 @@ case class EndVassalCommandsPhaseAction(
|
||||
currentRoundId = gs.currentRoundId,
|
||||
provinces = gs.provinces.values.toVector,
|
||||
factions = gs.factions.values.toVector,
|
||||
hid => gs.heroes(hid).backstoryTextId
|
||||
heroes = gs.heroes,
|
||||
heroBackstoryTextIdLookup = hid => gs.heroes(hid).backstoryTextId
|
||||
).results
|
||||
)
|
||||
.withRandomActionResults((gs, fr) =>
|
||||
|
||||
+80
-4
@@ -21,7 +21,7 @@ import net.eagle0.eagle.model.state.battalion.{BattalionT, EventForBattalionBack
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.hero.{EventForHeroBackstory, EventForHeroBackstoryT, HeroT}
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.model.state.quest.{DefeatFactionQuest, Quest}
|
||||
import net.eagle0.eagle.model.state.quest.{DefeatFactionQuest, Quest, WinBattleOutnumberedQuest, WinBattlesQuest}
|
||||
import net.eagle0.eagle.model.state.shardok_battle.{BattleType, ShardokBattle, ShardokPlayer}
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.{RecruitmentInfo, UnaffiliatedHeroType}
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.concrete.UnaffiliatedHeroC
|
||||
@@ -148,15 +148,81 @@ case class ResolveBattleAction(
|
||||
case _ => false
|
||||
}
|
||||
|
||||
private def winBattleOutnumberedQuestCheck(
|
||||
wasOutnumbered: Boolean
|
||||
): (Quest, ProvinceT) => Boolean =
|
||||
(q, _: ProvinceT) =>
|
||||
q match {
|
||||
case WinBattleOutnumberedQuest => wasOutnumbered
|
||||
case _ => false
|
||||
}
|
||||
|
||||
private def winBattlesQuestIncrementResults(
|
||||
startingState: GameState,
|
||||
winningFids: Set[FactionId]
|
||||
): Vector[ActionResultT] = {
|
||||
val changedProvinces = winningFids.toVector
|
||||
.flatMap(fid => FactionUtils.provinces(fid, startingState.provinces.values.toVector))
|
||||
.flatMap { province =>
|
||||
QuestFulfillmentUtils.counterIncrementedCP(
|
||||
province = province,
|
||||
incrementAmount = 1,
|
||||
check = (uh, _) =>
|
||||
uh.quest.exists {
|
||||
case q: WinBattlesQuest => q.componentsFulfilled < q.componentCount
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Option
|
||||
.when(changedProvinces.nonEmpty) {
|
||||
ActionResultC(
|
||||
actionResultType = BattleEnded,
|
||||
changedProvinces = changedProvinces
|
||||
)
|
||||
}
|
||||
.toVector
|
||||
}
|
||||
|
||||
private def playerTroopCount(
|
||||
player: ShardokPlayer,
|
||||
battalions: Map[BattalionId, BattalionT]
|
||||
): Int =
|
||||
player.armyGroup.toVector
|
||||
.flatMap(_.armies)
|
||||
.flatMap(_.army.units)
|
||||
.flatMap(_.battalionId)
|
||||
.flatMap(bid => battalions.get(bid))
|
||||
.map(_.size)
|
||||
.sum
|
||||
|
||||
private def winnersFulfilledQuestActionResults(
|
||||
startingState: GameState,
|
||||
battle: ShardokBattle,
|
||||
battleResolution: BattleResolution
|
||||
): Vector[ActionResultT] =
|
||||
): Vector[ActionResultT] = {
|
||||
val battalionsMap = startingState.battalions
|
||||
|
||||
battleResolution.resolvedPlayers.toVector.partition(
|
||||
_.endGameCondition.isVictory
|
||||
) match {
|
||||
case (winners, losers) =>
|
||||
winners
|
||||
// Calculate total troop counts for winners and losers at the start of the battle
|
||||
val winningFids = winners.map(_.eagleFid).toSet
|
||||
val winningPlayers = battle.players.filter(p => winningFids.contains(p.eagleFid))
|
||||
val losingPlayers = battle.players.filterNot(p => winningFids.contains(p.eagleFid))
|
||||
|
||||
val winnerTroopCount = winningPlayers.map(p => playerTroopCount(p, battalionsMap)).sum
|
||||
val loserTroopCount = losingPlayers.map(p => playerTroopCount(p, battalionsMap)).sum
|
||||
|
||||
val wasOutnumbered = winnerTroopCount < loserTroopCount && winners.nonEmpty
|
||||
|
||||
// Increment WinBattlesQuest counters for all winners
|
||||
val winBattlesIncrementResults = winBattlesQuestIncrementResults(startingState, winningFids)
|
||||
|
||||
// Check for quest fulfillments
|
||||
val questFulfillmentResults = winners
|
||||
.flatMap(rsp => FactionUtils.provinces(rsp.eagleFid, startingState.provinces.values.toVector))
|
||||
.flatMap(p =>
|
||||
QuestFulfillmentUtils.fulfilledQuestResults(
|
||||
@@ -164,9 +230,18 @@ case class ResolveBattleAction(
|
||||
isFulfilled = defeatLoserQuestCompletionCheck(losers.map(_.eagleFid)),
|
||||
gameId = startingState.gameId,
|
||||
currentDate = startingState.currentDate.get
|
||||
)
|
||||
) ++
|
||||
QuestFulfillmentUtils.fulfilledQuestResults(
|
||||
province = p,
|
||||
isFulfilled = winBattleOutnumberedQuestCheck(wasOutnumbered),
|
||||
gameId = startingState.gameId,
|
||||
currentDate = startingState.currentDate.get
|
||||
)
|
||||
)
|
||||
|
||||
winBattlesIncrementResults ++ questFulfillmentResults
|
||||
}
|
||||
}
|
||||
|
||||
private def verifyHidsOutMatchHidsIn(
|
||||
battle: ShardokBattle,
|
||||
@@ -267,6 +342,7 @@ case class ResolveBattleAction(
|
||||
destroyedBattalionIds = destroyedBattalionIds(battleResolution)
|
||||
) +: winnersFulfilledQuestActionResults(
|
||||
startingState = startingState,
|
||||
battle = battle,
|
||||
battleResolution = battleResolution
|
||||
)
|
||||
}
|
||||
|
||||
+4
@@ -61,6 +61,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:returning_heroes",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/faction_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/province",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/quest_fulfillment:quest_fulfillment_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_faction_trait",
|
||||
@@ -74,10 +75,13 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:client_text_visibility_extension_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero:gender",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/quest",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/unaffiliated_hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/unaffiliated_hero/concrete",
|
||||
],
|
||||
|
||||
+25
-4
@@ -1,6 +1,7 @@
|
||||
package net.eagle0.eagle.library.actions.impl.action.diplomacy_helpers
|
||||
|
||||
import net.eagle0.common.{FunctionalRandom, RandomState}
|
||||
import net.eagle0.eagle.{FactionId, GameId}
|
||||
import net.eagle0.eagle.library.settings.{
|
||||
BreakAllianceCharismaXp,
|
||||
BreakAllianceWisdomXp,
|
||||
@@ -12,6 +13,7 @@ import net.eagle0.eagle.library.settings.{
|
||||
import net.eagle0.eagle.library.util.faction_utils.FactionUtils
|
||||
import net.eagle0.eagle.library.util.faction_utils.FactionUtils.*
|
||||
import net.eagle0.eagle.library.util.province.ProvinceUtils
|
||||
import net.eagle0.eagle.library.util.quest_fulfillment.QuestFulfillmentChecker
|
||||
import net.eagle0.eagle.library.util.ReturningHeroes
|
||||
import net.eagle0.eagle.library.EagleInternalException
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
@@ -29,10 +31,10 @@ import net.eagle0.eagle.model.state.faction.FactionRelationship.RelationshipLeve
|
||||
import net.eagle0.eagle.model.state.faction.FactionT
|
||||
import net.eagle0.eagle.model.state.hero.EventForHeroBackstory
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.model.state.quest.{BetrayAllyQuest, Quest}
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.{RecruitmentInfo, UnaffiliatedHeroT}
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.concrete.UnaffiliatedHeroC
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroType.Prisoner
|
||||
import net.eagle0.eagle.FactionId
|
||||
|
||||
object BreakAllianceResolutionHelpers {
|
||||
private def returningHeroesForOffer(
|
||||
@@ -51,13 +53,19 @@ object BreakAllianceResolutionHelpers {
|
||||
functionalRandom = functionalRandom
|
||||
)
|
||||
|
||||
private def betrayAllyQuestMatch(quest: Quest, betrayedFactionId: FactionId): Boolean = quest match {
|
||||
case BetrayAllyQuest(targetFactionId) => targetFactionId == betrayedFactionId
|
||||
case _ => false
|
||||
}
|
||||
|
||||
def acceptedResult(
|
||||
breakAllianceOffer: BreakAlliance,
|
||||
currentDate: Date,
|
||||
provinces: Vector[ProvinceT],
|
||||
factions: Vector[FactionT],
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomState[ActionResultT] =
|
||||
functionalRandom: FunctionalRandom,
|
||||
gameId: GameId
|
||||
): RandomState[Vector[ActionResultT]] =
|
||||
returningHeroesForOffer(breakAllianceOffer, provinces, functionalRandom).map { returningHeroes =>
|
||||
val backstoryEvent = EventForHeroBackstory.BreakAllianceAmbassador(
|
||||
date = currentDate,
|
||||
@@ -66,7 +74,7 @@ object BreakAllianceResolutionHelpers {
|
||||
outcome = Accepted
|
||||
)
|
||||
|
||||
ActionResultC(
|
||||
val mainResult = ActionResultC(
|
||||
actionResultType = BreakAllianceAccepted,
|
||||
actingFactionId = Some(breakAllianceOffer.targetFactionId),
|
||||
changedHeroes = Vector(
|
||||
@@ -117,6 +125,19 @@ object BreakAllianceResolutionHelpers {
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Check for BetrayAllyQuest fulfillment for the ORIGINATING faction (the one who broke the alliance)
|
||||
val questFulfillmentChecker = new QuestFulfillmentChecker(gameId, currentDate)
|
||||
val questFulfillmentResults = provinces
|
||||
.filter(_.rulingFactionId.contains(breakAllianceOffer.originatingFactionId))
|
||||
.flatMap { checkedProvince =>
|
||||
questFulfillmentChecker.fulfilledQuestResults(
|
||||
province = checkedProvince,
|
||||
isFulfilled = (quest, _) => betrayAllyQuestMatch(quest, breakAllianceOffer.targetFactionId)
|
||||
)
|
||||
}
|
||||
|
||||
mainResult +: questFulfillmentResults
|
||||
}
|
||||
|
||||
def rejectedResult(
|
||||
|
||||
+6
@@ -171,6 +171,9 @@ object RansomResolutionHelpers {
|
||||
) ++ questFulfillmentChecker.fulfilledQuestResults(
|
||||
province = questCheckProvince,
|
||||
isFulfilled = (quest, _ /*questHolderProvince*/ ) => matcher.returnPrisonerQuestMatch(quest)
|
||||
) ++ questFulfillmentChecker.failedQuestResults(
|
||||
province = questCheckProvince,
|
||||
isFailed = (quest, _ /*questHolderProvince*/ ) => matcher.releaseAllPrisonersQuestMatch(quest)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -194,6 +197,9 @@ object RansomResolutionHelpers {
|
||||
) ++ questFulfillmentChecker.failedQuestResults(
|
||||
province = questCheckProvince,
|
||||
isFailed = (quest, _ /*questHolderProvince*/ ) => matcher.returnPrisonerQuestMatch(quest)
|
||||
) ++ questFulfillmentChecker.failedQuestResults(
|
||||
province = questCheckProvince,
|
||||
isFailed = (quest, _ /*questHolderProvince*/ ) => matcher.releaseAllPrisonersQuestMatch(quest)
|
||||
)
|
||||
|
||||
ActionResultC(
|
||||
|
||||
+33
-8
@@ -1,8 +1,9 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId}
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSequentialResultsAction
|
||||
import net.eagle0.eagle.library.settings.{ApprehendOutlawVigorCost, FactionBiasFromImprisonment}
|
||||
import net.eagle0.eagle.library.util.quest_fulfillment.QuestFulfillmentChecker
|
||||
import net.eagle0.eagle.library.util.EagleRequire.clientRequire
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.concrete.{ActionResultC, ChangedHeroC, NotificationC, StatDelta}
|
||||
@@ -12,6 +13,7 @@ import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.action_result.NotificationDetails.OutlawApprehended
|
||||
import net.eagle0.eagle.model.action_result.NotificationT
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.model.state.quest.{ApprehendOutlawQuest, Quest}
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.{RecruitmentInfo, UnaffiliatedHeroType}
|
||||
|
||||
object ApprehendOutlawCommand {
|
||||
@@ -22,8 +24,10 @@ object ApprehendOutlawCommand {
|
||||
outlawHeroIds: Vector[HeroId],
|
||||
actingHeroId: HeroId,
|
||||
heroIdToApprehend: HeroId,
|
||||
actingProvince: ProvinceT
|
||||
): ProtolessSimpleAction = {
|
||||
actingProvince: ProvinceT,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
questFulfillmentChecker: QuestFulfillmentChecker
|
||||
): ProtolessSequentialResultsAction = {
|
||||
clientRequire(
|
||||
availableHeroIds.contains(actingHeroId),
|
||||
s"Selected hid $actingHeroId was not among $availableHeroIds"
|
||||
@@ -40,7 +44,9 @@ object ApprehendOutlawCommand {
|
||||
gameId = gameId,
|
||||
province = actingProvince,
|
||||
actingHeroId = actingHeroId,
|
||||
targetedHeroId = heroIdToApprehend
|
||||
targetedHeroId = heroIdToApprehend,
|
||||
allProvinces = allProvinces,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
}
|
||||
|
||||
@@ -49,10 +55,17 @@ object ApprehendOutlawCommand {
|
||||
gameId: GameId,
|
||||
province: ProvinceT,
|
||||
actingHeroId: HeroId,
|
||||
targetedHeroId: HeroId
|
||||
) extends ProtolessSimpleAction {
|
||||
targetedHeroId: HeroId,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
questFulfillmentChecker: QuestFulfillmentChecker
|
||||
) extends ProtolessSequentialResultsAction {
|
||||
|
||||
override def immediateExecute: ActionResultT = {
|
||||
private def apprehendOutlawQuestMatch(quest: Quest): Boolean = quest match {
|
||||
case ApprehendOutlawQuest(outlawHeroId) => outlawHeroId == targetedHeroId
|
||||
case _ => false
|
||||
}
|
||||
|
||||
override def results: Vector[ActionResultT] = {
|
||||
val requestId = s"outlaw_apprehended_${targetedHeroId}_${province.id}"
|
||||
|
||||
val llmRequest = LlmRequestT.OutlawApprehendedMessage(
|
||||
@@ -78,7 +91,7 @@ object ApprehendOutlawCommand {
|
||||
deferred = true
|
||||
)
|
||||
|
||||
ActionResultC(
|
||||
val mainResult = ActionResultC(
|
||||
actionResultType = ActionResultType.OutlawApprehended,
|
||||
actingFactionId = Some(factionId),
|
||||
provinceId = Some(province.id),
|
||||
@@ -112,6 +125,18 @@ object ApprehendOutlawCommand {
|
||||
newNotifications = Vector(notification),
|
||||
newGeneratedTextRequests = Vector(llmRequest)
|
||||
)
|
||||
|
||||
// Check for quest fulfillment - only in provinces ruled by the acting faction
|
||||
val questFulfillmentResults = allProvinces
|
||||
.filter(_.rulingFactionId.contains(factionId))
|
||||
.flatMap { checkedProvince =>
|
||||
questFulfillmentChecker.fulfilledQuestResults(
|
||||
province = checkedProvince,
|
||||
isFulfilled = (quest, _) => apprehendOutlawQuestMatch(quest)
|
||||
)
|
||||
}
|
||||
|
||||
mainResult +: questFulfillmentResults
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,10 +122,11 @@ scala_library(
|
||||
],
|
||||
deps = [
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_sequential_results_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:apprehend_outlaw_vigor_cost",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:faction_bias_from_imprisonment",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/quest_fulfillment:quest_fulfillment_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_component_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
@@ -140,6 +141,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero:gender",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/quest",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/unaffiliated_hero",
|
||||
],
|
||||
)
|
||||
@@ -1285,10 +1287,11 @@ scala_library(
|
||||
],
|
||||
deps = [
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_sequential_results_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:accept_brotherhood_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:swear_brotherhood_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/quest_fulfillment:quest_fulfillment_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
@@ -1301,6 +1304,8 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/quest",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -115,7 +115,9 @@ class CommandFactory extends TCommandFactory {
|
||||
availableHeroIds = ac.availableHeroIds,
|
||||
outlawHeroIds = ac.outlaws.map(_.heroId),
|
||||
actingHeroId = sc.actingHeroId,
|
||||
heroIdToApprehend = sc.heroIdToApprehend
|
||||
heroIdToApprehend = sc.heroIdToApprehend,
|
||||
allProvinces = gameState.provinces.values.toVector,
|
||||
questFulfillmentChecker = questFulfillmentChecker(gameState)
|
||||
)
|
||||
case (ac: ArmTroopsAvailable, sc: ArmTroopsSelected) =>
|
||||
ArmTroopsCommand.make(
|
||||
@@ -703,7 +705,9 @@ class CommandFactory extends TCommandFactory {
|
||||
factionHeadHeroId = gameState.factions(actingFactionId).factionHeadId,
|
||||
currentDate = gameState.currentDate.get,
|
||||
currentRoundId = gameState.currentRoundId,
|
||||
gameId = gameState.gameId
|
||||
gameId = gameState.gameId,
|
||||
allProvinces = allProvinces(gameState),
|
||||
questFulfillmentChecker = questFulfillmentChecker(gameState)
|
||||
)
|
||||
|
||||
case (ac: TradeAvailable, sc: TradeSelected) =>
|
||||
|
||||
@@ -23,7 +23,11 @@ import net.eagle0.eagle.model.state.quest.{
|
||||
AlmsToProvinceQuest,
|
||||
DefeatFactionQuest,
|
||||
GiveToHeroesInProvinceQuest,
|
||||
ImproveAgricultureQuest,
|
||||
ImproveEconomyQuest,
|
||||
ImproveInfrastructureQuest,
|
||||
SpecificExpansionQuest,
|
||||
StartBlizzardQuest,
|
||||
TruceWithFactionQuest
|
||||
}
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroT
|
||||
@@ -142,13 +146,19 @@ object DivineCommand {
|
||||
case (updatedUH, llmRequest) =>
|
||||
val updatedProvinceIds: Vector[ProvinceId] =
|
||||
updatedUH.quest.collect {
|
||||
case SpecificExpansionQuest(provinceId) =>
|
||||
case SpecificExpansionQuest(provinceId) =>
|
||||
Vector(provinceId)
|
||||
case DefeatFactionQuest(targetFactionId) =>
|
||||
case ImproveAgricultureQuest(provinceId, _) =>
|
||||
Vector(provinceId)
|
||||
case ImproveEconomyQuest(provinceId, _) =>
|
||||
Vector(provinceId)
|
||||
case ImproveInfrastructureQuest(provinceId, _) =>
|
||||
Vector(provinceId)
|
||||
case DefeatFactionQuest(targetFactionId) =>
|
||||
FactionUtils
|
||||
.provinces(targetFactionId, allProvinces)
|
||||
.map(_.id)
|
||||
case TruceWithFactionQuest(targetFactionId) =>
|
||||
case TruceWithFactionQuest(targetFactionId) =>
|
||||
FactionUtils
|
||||
.provinces(targetFactionId, allProvinces)
|
||||
.map(_.id)
|
||||
@@ -166,6 +176,8 @@ object DivineCommand {
|
||||
_ /* totalGold */
|
||||
) =>
|
||||
Vector(provinceId)
|
||||
case StartBlizzardQuest(provinceId) =>
|
||||
Vector(provinceId)
|
||||
}
|
||||
.getOrElse(Vector())
|
||||
|
||||
|
||||
+6
@@ -271,6 +271,9 @@ object ManagePrisonersCommand {
|
||||
) ++ questFulfillmentChecker.failedQuestResults(
|
||||
province = checkedProvince,
|
||||
isFailed = (quest, _ /*questHolderProvince*/ ) => returnPrisonerQuestMatch(quest)
|
||||
) ++ questFulfillmentChecker.failedQuestResults(
|
||||
province = checkedProvince,
|
||||
isFailed = (quest, _ /*questHolderProvince*/ ) => releaseAllPrisonersQuestMatch(quest)
|
||||
)
|
||||
}
|
||||
case Execute =>
|
||||
@@ -321,6 +324,9 @@ object ManagePrisonersCommand {
|
||||
) ++ questFulfillmentChecker.failedQuestResults(
|
||||
province = checkedProvince,
|
||||
isFailed = (quest, _ /*questHolderProvince*/ ) => returnPrisonerQuestMatch(quest)
|
||||
) ++ questFulfillmentChecker.failedQuestResults(
|
||||
province = checkedProvince,
|
||||
isFailed = (quest, _ /*questHolderProvince*/ ) => releaseAllPrisonersQuestMatch(quest)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+42
-14
@@ -1,8 +1,9 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId, ProvinceId, RoundId}
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSequentialResultsAction
|
||||
import net.eagle0.eagle.library.settings.{AcceptBrotherhoodCharismaXp, SwearBrotherhoodCharismaXp}
|
||||
import net.eagle0.eagle.library.util.quest_fulfillment.QuestFulfillmentChecker
|
||||
import net.eagle0.eagle.library.util.EagleRequire.commandRequire
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.action_result.concrete.{ActionResultC, ChangedFactionC, ChangedHeroC, NotificationC}
|
||||
@@ -11,6 +12,8 @@ import net.eagle0.eagle.model.action_result.types.ActionResultType.{FailedSwearB
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.hero.EventForHeroBackstory
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.model.state.quest.{Quest, SwearBrotherhoodWithHeroQuest}
|
||||
|
||||
object SwearBrotherhoodCommand {
|
||||
def accepts(
|
||||
@@ -34,8 +37,10 @@ object SwearBrotherhoodCommand {
|
||||
factionHeadHeroId: HeroId,
|
||||
currentDate: Date,
|
||||
currentRoundId: RoundId,
|
||||
gameId: GameId
|
||||
): ProtolessSimpleAction = {
|
||||
gameId: GameId,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
questFulfillmentChecker: QuestFulfillmentChecker
|
||||
): ProtolessSequentialResultsAction = {
|
||||
commandRequire(
|
||||
availableHeroIds.contains(newBrotherHeroId),
|
||||
s"Tried to swear brotherhood with $newBrotherHeroId, but options were $availableHeroIds"
|
||||
@@ -48,7 +53,9 @@ object SwearBrotherhoodCommand {
|
||||
factionHeadHeroId = factionHeadHeroId,
|
||||
currentDate = currentDate,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
gameId = gameId,
|
||||
allProvinces = allProvinces,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
}
|
||||
|
||||
@@ -59,9 +66,16 @@ object SwearBrotherhoodCommand {
|
||||
factionHeadHeroId: HeroId,
|
||||
currentDate: Date,
|
||||
currentRoundId: RoundId,
|
||||
gameId: GameId
|
||||
) extends ProtolessSimpleAction {
|
||||
override def immediateExecute: ActionResultT =
|
||||
gameId: GameId,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
questFulfillmentChecker: QuestFulfillmentChecker
|
||||
) extends ProtolessSequentialResultsAction {
|
||||
private def swearBrotherhoodQuestMatch(quest: Quest): Boolean = quest match {
|
||||
case SwearBrotherhoodWithHeroQuest(targetHeroId) => targetHeroId == newBrotherId
|
||||
case _ => false
|
||||
}
|
||||
|
||||
override def results: Vector[ActionResultT] =
|
||||
if accepts(newBrotherId, factionId) then {
|
||||
val notificationLlmId =
|
||||
s"$currentRoundId swear brotherhood $newBrotherId"
|
||||
@@ -72,7 +86,7 @@ object SwearBrotherhoodCommand {
|
||||
sworeInProvinceId = provinceId
|
||||
)
|
||||
|
||||
ActionResultC(
|
||||
val mainResult = ActionResultC(
|
||||
actionResultType = SwearBrotherhood,
|
||||
actingFactionId = Some(factionId),
|
||||
actingHeroId = Some(newBrotherId),
|
||||
@@ -116,13 +130,27 @@ object SwearBrotherhoodCommand {
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Check for SwearBrotherhoodWithHeroQuest fulfillment
|
||||
val questFulfillmentResults = allProvinces
|
||||
.filter(_.rulingFactionId.contains(factionId))
|
||||
.flatMap { checkedProvince =>
|
||||
questFulfillmentChecker.fulfilledQuestResults(
|
||||
province = checkedProvince,
|
||||
isFulfilled = (quest, _) => swearBrotherhoodQuestMatch(quest)
|
||||
)
|
||||
}
|
||||
|
||||
mainResult +: questFulfillmentResults
|
||||
} else
|
||||
ActionResultC(
|
||||
actionResultType = FailedSwearBrotherhood,
|
||||
actingFactionId = Some(factionId),
|
||||
actingHeroId = Some(newBrotherId),
|
||||
provinceId = Some(provinceId),
|
||||
provinceIdActed = Some(provinceId)
|
||||
Vector(
|
||||
ActionResultC(
|
||||
actionResultType = FailedSwearBrotherhood,
|
||||
actingFactionId = Some(factionId),
|
||||
actingHeroId = Some(newBrotherId),
|
||||
provinceId = Some(provinceId),
|
||||
provinceIdActed = Some(provinceId)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -12,9 +12,9 @@ case class BattalionBackstoryUpdatePromptGenerator(
|
||||
gameState: GameState,
|
||||
clientTextStore: ClientTextStore
|
||||
) extends LLMPromptGenerator {
|
||||
private val normalGrowthRate = 20
|
||||
private val normalGrowthRate = 50
|
||||
private val slowGrowthRate = 5
|
||||
private val softCap = 150 // approximately 900 characters
|
||||
private val softCap = 300 // approximately 1800 characters
|
||||
|
||||
private val battalion = gameState.battalions.getOrElse(
|
||||
updateRequest.battalionId,
|
||||
|
||||
+1
-1
@@ -35,5 +35,5 @@ case class BattalionInitialBackstoryPromptGenerator(
|
||||
|
|
||||
|The backstory should be consistent with the setting and the commander's character.
|
||||
|
|
||||
|${GeneratorUtilities.limitations(wordCount = 50)}""".stripMargin
|
||||
|${GeneratorUtilities.limitations(wordCount = 100)}""".stripMargin
|
||||
}
|
||||
|
||||
+101
@@ -249,6 +249,107 @@ case class DivineMessagePromptGenerator(
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants ${faction.name} to maintain at least $targetProvinceCount provinces with Mobilize orders for a cumulative $targetMonths months. Mobilize orders direct vassals to organize, train, and arm troops for war."
|
||||
)
|
||||
|
||||
case BattalionDiversityQuest =>
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants to see a diverse army in ${province.name}, with three different types of battalion, each near full strength."
|
||||
)
|
||||
|
||||
case ReleaseAllPrisonersQuest =>
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants ${faction.name} to release all prisoners held in their provinces. ${subjectPronoun(divinedHero.pronounGender)} will be displeased if any prisoners are executed, moved, or traded away in ransom."
|
||||
)
|
||||
|
||||
case SwearBrotherhoodWithHeroQuest(targetHeroId) =>
|
||||
val targetHero = gameState.heroes(targetHeroId)
|
||||
for {
|
||||
targetHeroName <- clientTextStore.getText(targetHero.nameTextId)
|
||||
targetHeroDescription <- descriptionWithoutFaction(
|
||||
hero = targetHero,
|
||||
alive = true,
|
||||
clientTextStore = clientTextStore
|
||||
)
|
||||
} yield s"""$divinedHeroName wants $actingHeroName to swear brotherhood with $targetHeroName, making them a faction leader alongside the current leaders.
|
||||
|$targetHeroDescription""".stripMargin
|
||||
|
||||
case BetrayAllyQuest(targetFactionId) =>
|
||||
val targetFaction = FactionInfoUtilities.getFaction(targetFactionId, gameState)
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants ${faction.name} to betray their ally ${targetFaction.name} by breaking the alliance."
|
||||
)
|
||||
|
||||
case BorderSecurityQuest(targetProvinceId) =>
|
||||
val targetProvince = gameState.provinces(targetProvinceId)
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants ${faction.name} to secure the borders around ${targetProvince.name} by controlling all adjacent provinces."
|
||||
)
|
||||
|
||||
case WinBattleOutnumberedQuest =>
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants to see ${faction.name} prove their valor by winning a battle while outnumbered."
|
||||
)
|
||||
|
||||
case q: WinBattlesQuest =>
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants to see ${faction.name} prove their military prowess by winning ${q.componentCount} battles."
|
||||
)
|
||||
|
||||
case ApprehendOutlawQuest(outlawHeroId) =>
|
||||
val outlawHero = gameState.heroes(outlawHeroId)
|
||||
for {
|
||||
outlawHeroName <- clientTextStore.getText(outlawHero.nameTextId)
|
||||
outlawHeroDescription <- descriptionWithoutFaction(
|
||||
hero = outlawHero,
|
||||
alive = true,
|
||||
clientTextStore = clientTextStore
|
||||
)
|
||||
} yield s"""$divinedHeroName wants $actingHeroName to apprehend the outlaw $outlawHeroName.
|
||||
|$outlawHeroDescription""".stripMargin
|
||||
|
||||
case StartBlizzardQuest(targetProvinceId) =>
|
||||
val targetProvince = gameState.provinces(targetProvinceId)
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants to see a magical blizzard unleashed upon ${targetProvince.name}."
|
||||
)
|
||||
|
||||
case StartEpidemicQuest(targetProvinceId) =>
|
||||
val targetProvince = gameState.provinces(targetProvinceId)
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants to see a magical epidemic unleashed upon ${targetProvince.name}."
|
||||
)
|
||||
|
||||
case SpendOnFeastsQuest(componentCount, _, totalGold) =>
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants $actingHeroName to host lavish feasts spending $totalGold gold over $componentCount months."
|
||||
)
|
||||
|
||||
case SendSuppliesQuest(componentCount, _, targetProvinceId, totalFood) =>
|
||||
val targetProvince = gameState.provinces(targetProvinceId)
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants $actingHeroName to send $totalFood food to ${targetProvince.name} over $componentCount months."
|
||||
)
|
||||
|
||||
case RestProvinceQuest(componentCount, _, targetProvinceId) =>
|
||||
val targetProvince = gameState.provinces(targetProvinceId)
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants to see ${targetProvince.name} kept at rest for $componentCount months."
|
||||
)
|
||||
|
||||
case ReconProvincesQuest(componentCount, _, targetProvinceCount) =>
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants $actingHeroName to recon $targetProvinceCount provinces."
|
||||
)
|
||||
|
||||
case ReconSpecificProvincesQuest(componentCount, _, targetProvinceIds) =>
|
||||
val provinceNames = targetProvinceIds.map(pid => gameState.provinces(pid).name)
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants $actingHeroName to recon the following provinces: ${provinceNames.mkString(", ")}."
|
||||
)
|
||||
|
||||
case RepairDevastationQuest(_, _, targetDevastationRepaired) =>
|
||||
TextGenerationSuccess(
|
||||
s"$divinedHeroName wants to see $targetDevastationRepaired devastation repaired across the realm."
|
||||
)
|
||||
}
|
||||
|
||||
override def generate: TextGenerationResult = for {
|
||||
|
||||
+103
@@ -255,6 +255,109 @@ object QuestEndedGeneratorUtilities {
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted ${faction.name} to maintain at least $targetProvinceCount provinces with Mobilize orders (directing vassals to organize, train, and arm troops for war) for a cumulative $targetMonths months."
|
||||
|
||||
case BattalionDiversityQuest =>
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted to see a diverse army in ${province.name}, with three different types of battalion, each near full strength."
|
||||
|
||||
case ReleaseAllPrisonersQuest =>
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted ${faction.name} to release all prisoners held in their provinces, without executing, moving, or trading any away in ransom."
|
||||
|
||||
case SwearBrotherhoodWithHeroQuest(targetHeroId) =>
|
||||
val targetHero = HeroInfoUtilities.getHero(targetHeroId, gameState)
|
||||
for {
|
||||
targetHeroDescription <- description(
|
||||
heroId = targetHeroId,
|
||||
gameState = gameState,
|
||||
clientTextStore = clientTextStore
|
||||
)
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
targetHeroName <- clientTextStore.getText(targetHero.nameTextId)
|
||||
} yield s"""$unaffiliatedHeroName wanted ${faction.name} to swear brotherhood with $targetHeroName.
|
||||
|$targetHeroDescription""".stripMargin
|
||||
|
||||
case BetrayAllyQuest(targetFactionId) =>
|
||||
val targetFaction = FactionInfoUtilities.getFaction(targetFactionId, gameState)
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted ${faction.name} to betray their ally ${targetFaction.name} by breaking the alliance."
|
||||
|
||||
case BorderSecurityQuest(targetProvinceId) =>
|
||||
val targetProvince = gameState.provinces(targetProvinceId)
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted ${faction.name} to secure the borders around ${targetProvince.name} by controlling all adjacent provinces."
|
||||
|
||||
case WinBattleOutnumberedQuest =>
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted ${faction.name} to prove their valor by winning a battle while outnumbered."
|
||||
|
||||
case q: WinBattlesQuest =>
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted ${faction.name} to prove their military prowess by winning ${q.componentCount} battles."
|
||||
|
||||
case ApprehendOutlawQuest(outlawHeroId) =>
|
||||
val outlawHero = HeroInfoUtilities.getHero(outlawHeroId, gameState)
|
||||
for {
|
||||
outlawHeroDescription <- description(
|
||||
heroId = outlawHeroId,
|
||||
gameState = gameState,
|
||||
clientTextStore = clientTextStore
|
||||
)
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
outlawHeroName <- clientTextStore.getText(outlawHero.nameTextId)
|
||||
} yield s"""$unaffiliatedHeroName wanted ${faction.name} to apprehend the outlaw $outlawHeroName.
|
||||
|$outlawHeroDescription""".stripMargin
|
||||
|
||||
case StartBlizzardQuest(targetProvinceId) =>
|
||||
val targetProvince = gameState.provinces(targetProvinceId)
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted to see a magical blizzard unleashed upon ${targetProvince.name}."
|
||||
|
||||
case StartEpidemicQuest(targetProvinceId) =>
|
||||
val targetProvince = gameState.provinces(targetProvinceId)
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted to see a magical epidemic unleashed upon ${targetProvince.name}."
|
||||
|
||||
case SpendOnFeastsQuest(componentCount, _, totalGold) =>
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted ${faction.name} to host lavish feasts spending $totalGold gold over $componentCount months."
|
||||
|
||||
case SendSuppliesQuest(componentCount, _, targetProvinceId, totalFood) =>
|
||||
val targetProvince = gameState.provinces(targetProvinceId)
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted ${faction.name} to send $totalFood food to ${targetProvince.name} over $componentCount months."
|
||||
|
||||
case RestProvinceQuest(componentCount, _, targetProvinceId) =>
|
||||
val targetProvince = gameState.provinces(targetProvinceId)
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted to see ${targetProvince.name} kept at rest for $componentCount months."
|
||||
|
||||
case ReconProvincesQuest(componentCount, _, targetProvinceCount) =>
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted ${faction.name} to recon $targetProvinceCount provinces."
|
||||
|
||||
case ReconSpecificProvincesQuest(componentCount, _, targetProvinceIds) =>
|
||||
val provinceNames = targetProvinceIds.map(pid => gameState.provinces(pid).name)
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted ${faction.name} to recon the following provinces: ${provinceNames.mkString(", ")}."
|
||||
|
||||
case RepairDevastationQuest(_, _, targetDevastationRepaired) =>
|
||||
for {
|
||||
unaffiliatedHeroName <- unaffiliatedHeroNameResult
|
||||
} yield s"$unaffiliatedHeroName wanted to see $targetDevastationRepaired devastation repaired across the realm."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:hostility",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction:faction_relationship",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -4,10 +4,39 @@ import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.library.settings.{MinSupportForTaxes, PrestigePerSupportedProvince}
|
||||
import net.eagle0.eagle.model.state.faction.{FactionRelationship, FactionT}
|
||||
import net.eagle0.eagle.model.state.faction.FactionRelationship.RelationshipLevel.Ally
|
||||
import net.eagle0.eagle.model.state.hero.HeroT
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.model.state.Hostility
|
||||
|
||||
object FactionUtils {
|
||||
|
||||
/**
|
||||
* Check if a hero belongs to a faction.
|
||||
*
|
||||
* This checks the hero's factionId field, which is the authoritative source for faction membership. Heroes retain
|
||||
* their factionId when:
|
||||
* - In a province (rulingFactionHeroIds)
|
||||
* - In a moving army
|
||||
* - Imprisoned (as an UnaffiliatedHero)
|
||||
*
|
||||
* Heroes lose their factionId when:
|
||||
* - Exiled
|
||||
* - Become outlaws
|
||||
* - Depart due to low loyalty
|
||||
* - Killed
|
||||
*/
|
||||
def heroIsInFaction(heroId: HeroId, factionId: FactionId, heroes: Map[HeroId, HeroT]): Boolean =
|
||||
heroes.get(heroId).exists(_.factionId.contains(factionId))
|
||||
|
||||
/**
|
||||
* Get all hero IDs that belong to a faction.
|
||||
*
|
||||
* This includes heroes in provinces, moving armies, and imprisoned heroes. See heroIsInFaction for details on what
|
||||
* constitutes faction membership.
|
||||
*/
|
||||
def heroIdsInFaction(factionId: FactionId, heroes: Iterable[HeroT]): Set[HeroId] =
|
||||
heroes.filter(_.factionId.contains(factionId)).map(_.id).toSet
|
||||
|
||||
// Curly quotes and straight quotes: " " " ' ' '
|
||||
private val sortIgnoredChars: Set[Char] = Set('"', '\u201c', '\u201d', '\'', '\u2018', '\u2019')
|
||||
|
||||
|
||||
+239
-3
@@ -32,6 +32,10 @@ import net.eagle0.eagle.model.state.quest.{
|
||||
AllianceQuest,
|
||||
AlmsAcrossRealmQuest,
|
||||
AlmsToProvinceQuest,
|
||||
ApprehendOutlawQuest,
|
||||
BattalionDiversityQuest,
|
||||
BetrayAllyQuest,
|
||||
BorderSecurityQuest,
|
||||
DefeatFactionQuest,
|
||||
DevelopProvincesQuest,
|
||||
DismissSpecificVassalQuest,
|
||||
@@ -47,18 +51,26 @@ import net.eagle0.eagle.model.state.quest.{
|
||||
ImproveInfrastructureQuest,
|
||||
MobilizeProvincesQuest,
|
||||
Quest,
|
||||
ReleaseAllPrisonersQuest,
|
||||
ReleasePrisonerQuest,
|
||||
RescueImprisonedLeaderQuest,
|
||||
RestProvinceQuest,
|
||||
ReturnPrisonerQuest,
|
||||
SendSuppliesQuest,
|
||||
SpecificExpansionQuest,
|
||||
StartBlizzardQuest,
|
||||
StartEpidemicQuest,
|
||||
SuppressRiotByForceQuest,
|
||||
SwearBrotherhoodWithHeroQuest,
|
||||
TotalDevelopmentQuest,
|
||||
TruceWithFactionQuest,
|
||||
UpgradeBattalionQuest,
|
||||
WealthQuest
|
||||
WealthQuest,
|
||||
WinBattleOutnumberedQuest,
|
||||
WinBattlesQuest
|
||||
}
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroT
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroType.Prisoner
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroType.{Outlaw, Prisoner}
|
||||
import net.eagle0.eagle.model.state.BattalionTypeId
|
||||
|
||||
object QuestCreationUtils {
|
||||
@@ -130,7 +142,19 @@ object QuestCreationUtils {
|
||||
QuestCreatorFrom(suppressRiotByForceQuests),
|
||||
QuestCreatorFrom(fightBeastsAloneQuests),
|
||||
developProvincesQuests,
|
||||
mobilizeProvincesQuests
|
||||
mobilizeProvincesQuests,
|
||||
battalionDiversityQuests,
|
||||
releaseAllPrisonersQuests,
|
||||
swearBrotherhoodWithHeroQuests,
|
||||
QuestCreatorFrom(betrayAllyQuests),
|
||||
QuestCreatorFrom(borderSecurityQuests),
|
||||
QuestCreatorFrom(winBattleOutnumberedQuests),
|
||||
winBattlesQuests,
|
||||
QuestCreatorFrom(apprehendOutlawQuests),
|
||||
QuestCreatorFrom(startBlizzardQuests),
|
||||
QuestCreatorFrom(startEpidemicQuests),
|
||||
sendSuppliesQuests,
|
||||
restProvinceQuests
|
||||
)
|
||||
) {
|
||||
case (questCreator, fr) =>
|
||||
@@ -228,6 +252,34 @@ object QuestCreationUtils {
|
||||
functionalRandom
|
||||
)
|
||||
|
||||
private def swearBrotherhoodWithHeroQuests(
|
||||
province: ProvinceT,
|
||||
@unused allProvinces: Vector[ProvinceT],
|
||||
factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT],
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomState[Vector[Quest]] = RandomState(
|
||||
// Target heroes who are vassals (not leaders) - same as dismiss quest candidates
|
||||
province.rulingFactionHeroIds
|
||||
.filterNot(hid => FactionUtils.isFactionLeader(hid, factions))
|
||||
.map(hid => SwearBrotherhoodWithHeroQuest(targetHeroId = hid)),
|
||||
functionalRandom
|
||||
)
|
||||
|
||||
private def betrayAllyQuests(
|
||||
province: ProvinceT,
|
||||
@unused allProvinces: Vector[ProvinceT],
|
||||
factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT]
|
||||
): Vector[Quest] =
|
||||
// One quest per ally
|
||||
factions
|
||||
.find(_.id == province.rulingFactionId.get)
|
||||
.toVector
|
||||
.flatMap(_.factionRelationships)
|
||||
.filter(_.relationshipLevel == Ally)
|
||||
.map(relationship => BetrayAllyQuest(targetFactionId = relationship.targetFactionId))
|
||||
|
||||
private def prisonersInProvince(
|
||||
province: ProvinceT,
|
||||
@unused allProvinces: Vector[ProvinceT],
|
||||
@@ -770,4 +822,188 @@ object QuestCreationUtils {
|
||||
}
|
||||
end if
|
||||
}
|
||||
|
||||
private def battalionDiversityQuests(
|
||||
province: ProvinceT,
|
||||
@unused allProvinces: Vector[ProvinceT],
|
||||
@unused factions: Vector[FactionT],
|
||||
battalions: Vector[BattalionT],
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomState[Vector[Quest]] = {
|
||||
// Only available if province currently has 1-2 battalion types
|
||||
val currentBattalionTypes = province.battalionIds
|
||||
.flatMap(bid => battalions.find(_.id == bid))
|
||||
.map(_.typeId)
|
||||
.distinct
|
||||
.size
|
||||
|
||||
if currentBattalionTypes >= 1 && currentBattalionTypes <= 2 then
|
||||
RandomState(Vector(BattalionDiversityQuest), functionalRandom)
|
||||
else RandomState(Vector(), functionalRandom)
|
||||
}
|
||||
|
||||
private def releaseAllPrisonersQuests(
|
||||
province: ProvinceT,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT],
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomState[Vector[Quest]] = {
|
||||
// Only available if faction's provinces have at least 3 prisoners
|
||||
val factionPrisonerCount = prisonersOfFaction(province.getRulingFactionId, allProvinces, factions).size
|
||||
|
||||
if factionPrisonerCount >= 3 then RandomState(Vector(ReleaseAllPrisonersQuest), functionalRandom)
|
||||
else RandomState(Vector(), functionalRandom)
|
||||
}
|
||||
|
||||
private def borderSecurityQuests(
|
||||
province: ProvinceT,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
@unused factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT]
|
||||
): Vector[Quest] =
|
||||
// Create a quest for each province that has neighbors controlled by other factions
|
||||
FactionUtils
|
||||
.provinces(province.getRulingFactionId, allProvinces)
|
||||
.filter { factionProvince =>
|
||||
factionProvince.neighbors.exists { neighbor =>
|
||||
allProvinces
|
||||
.find(_.id == neighbor.provinceId)
|
||||
.exists(_.rulingFactionId != province.rulingFactionId)
|
||||
}
|
||||
}
|
||||
.map(borderProvince => BorderSecurityQuest(targetProvinceId = borderProvince.id))
|
||||
|
||||
private def winBattleOutnumberedQuests(
|
||||
@unused province: ProvinceT,
|
||||
@unused allProvinces: Vector[ProvinceT],
|
||||
@unused factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT]
|
||||
): Vector[Quest] =
|
||||
Vector(WinBattleOutnumberedQuest)
|
||||
|
||||
private def winBattlesQuests(
|
||||
@unused province: ProvinceT,
|
||||
@unused allProvinces: Vector[ProvinceT],
|
||||
@unused factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT],
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomState[Vector[Quest]] =
|
||||
functionalRandom.nextIntInclusive(2, 4).map { targetBattles =>
|
||||
Vector(
|
||||
WinBattlesQuest(
|
||||
componentCount = targetBattles,
|
||||
componentsFulfilled = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private def apprehendOutlawQuests(
|
||||
province: ProvinceT,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
@unused factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT]
|
||||
): Vector[Quest] =
|
||||
// Find all outlaws in the faction's territory
|
||||
FactionUtils
|
||||
.provinces(province.getRulingFactionId, allProvinces)
|
||||
.flatMap(_.unaffiliatedHeroes)
|
||||
.filter(_.unaffiliatedHeroType == Outlaw)
|
||||
.map(outlaw => ApprehendOutlawQuest(outlawHeroId = outlaw.heroId))
|
||||
|
||||
private def startBlizzardQuests(
|
||||
province: ProvinceT,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
@unused factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT]
|
||||
): Vector[Quest] = {
|
||||
// Target provinces in the faction's territory or adjacent to it that don't have a blizzard
|
||||
val factionProvinces = FactionUtils.provinces(province.getRulingFactionId, allProvinces)
|
||||
|
||||
// Get provinces reachable by Control Weather: faction provinces + neighbors of faction provinces
|
||||
val reachableProvinceIds = factionProvinces.flatMap { fp =>
|
||||
fp.id +: fp.neighbors.map(_.provinceId)
|
||||
}.distinct
|
||||
|
||||
reachableProvinceIds
|
||||
.flatMap(pid => allProvinces.find(_.id == pid))
|
||||
.filterNot(ProvinceUtils.hasBlizzard)
|
||||
.map(targetProvince => StartBlizzardQuest(provinceId = targetProvince.id))
|
||||
}
|
||||
|
||||
private def startEpidemicQuests(
|
||||
province: ProvinceT,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
@unused factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT]
|
||||
): Vector[Quest] = {
|
||||
// Target provinces in the faction's territory or adjacent to it that don't have an epidemic
|
||||
val factionProvinces = FactionUtils.provinces(province.getRulingFactionId, allProvinces)
|
||||
|
||||
// Include faction provinces and their neighbors as potential targets
|
||||
val targetProvinceIds = factionProvinces.flatMap { fp =>
|
||||
fp.id +: fp.neighbors.map(_.provinceId)
|
||||
}.distinct
|
||||
|
||||
targetProvinceIds
|
||||
.flatMap(pid => allProvinces.find(_.id == pid))
|
||||
.filterNot(ProvinceUtils.hasEpidemic)
|
||||
.map(targetProvince => StartEpidemicQuest(provinceId = targetProvince.id))
|
||||
}
|
||||
|
||||
private def sendSuppliesQuests(
|
||||
province: ProvinceT,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
@unused factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT],
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomState[Vector[Quest]] = {
|
||||
// Find other provinces owned by the same faction (excluding the current province)
|
||||
val otherFactionProvinces = FactionUtils
|
||||
.provinces(province.getRulingFactionId, allProvinces)
|
||||
.filterNot(_.id == province.id)
|
||||
|
||||
// Only available if faction has at least 2 provinces
|
||||
if otherFactionProvinces.isEmpty then RandomState(Vector(), functionalRandom)
|
||||
else {
|
||||
val minFood = 1000
|
||||
val maxFood = 3000
|
||||
|
||||
functionalRandom.nextIntInclusive(minFood, maxFood).map { totalFood =>
|
||||
otherFactionProvinces.map { targetProvince =>
|
||||
SendSuppliesQuest(
|
||||
componentCount = totalFood,
|
||||
componentsFulfilled = 0,
|
||||
targetProvinceId = targetProvince.id,
|
||||
totalFood = totalFood
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
end if
|
||||
}
|
||||
|
||||
private def restProvinceQuests(
|
||||
province: ProvinceT,
|
||||
allProvinces: Vector[ProvinceT],
|
||||
@unused factions: Vector[FactionT],
|
||||
@unused battalions: Vector[BattalionT],
|
||||
functionalRandom: FunctionalRandom
|
||||
): RandomState[Vector[Quest]] = {
|
||||
// Get all faction provinces as potential targets
|
||||
val factionProvinces = FactionUtils.provinces(province.getRulingFactionId, allProvinces)
|
||||
|
||||
val minMonths = 2
|
||||
val maxMonths = 4
|
||||
|
||||
functionalRandom.nextIntInclusive(minMonths, maxMonths).map { targetMonths =>
|
||||
factionProvinces.map { targetProvince =>
|
||||
RestProvinceQuest(
|
||||
componentCount = targetMonths,
|
||||
componentsFulfilled = 0,
|
||||
targetProvinceId = targetProvince.id
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ scala_library(
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/action/diplomacy_helpers:__pkg__",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:__pkg__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl/action:__pkg__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl/action/diplomacy_helpers:__pkg__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl/command:__pkg__",
|
||||
|
||||
+7
@@ -5,6 +5,7 @@ import net.eagle0.eagle.model.state.quest.{
|
||||
ExecutePrisonerQuest,
|
||||
ExilePrisonerQuest,
|
||||
Quest,
|
||||
ReleaseAllPrisonersQuest,
|
||||
ReleasePrisonerQuest,
|
||||
ReturnPrisonerQuest
|
||||
}
|
||||
@@ -44,4 +45,10 @@ class PrisonerManagementQuestMatchers(
|
||||
prisonerHeroId == questPrisonerHeroId && prisonerProvinceId == questPrisonerProvinceId
|
||||
case _ => false
|
||||
}
|
||||
|
||||
def releaseAllPrisonersQuestMatch(quest: Quest): Boolean =
|
||||
quest match {
|
||||
case ReleaseAllPrisonersQuest => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ import net.eagle0.eagle.common.unaffiliated_hero_quest.{
|
||||
AllianceQuest as AllianceQuestProto,
|
||||
AlmsAcrossRealmQuest as AlmsAcrossRealmQuestProto,
|
||||
AlmsToProvinceQuest as AlmsToProvinceQuestProto,
|
||||
ApprehendOutlawQuest as ApprehendOutlawQuestProto,
|
||||
BattalionDiversityQuest as BattalionDiversityQuestProto,
|
||||
BetrayAllyQuest as BetrayAllyQuestProto,
|
||||
BorderSecurityQuest as BorderSecurityQuestProto,
|
||||
DefeatFactionQuest as DefeatFactionQuestProto,
|
||||
DevelopProvincesQuest as DevelopProvincesQuestProto,
|
||||
DismissSpecificVassalQuest as DismissSpecificVassalQuestProto,
|
||||
@@ -21,31 +25,43 @@ import net.eagle0.eagle.common.unaffiliated_hero_quest.{
|
||||
MobilizeProvincesQuest as MobilizeProvincesQuestProto,
|
||||
Quest as QuestProto,
|
||||
QuestDetails as QuestDetailsProto,
|
||||
ReconProvincesQuest as ReconProvincesQuestProto,
|
||||
ReconSpecificProvincesQuest as ReconSpecificProvincesQuestProto,
|
||||
ReleaseAllPrisonersQuest as ReleaseAllPrisonersQuestProto,
|
||||
ReleasePrisonerQuest as ReleasePrisonerQuestProto,
|
||||
RepairDevastationQuest as RepairDevastationQuestProto,
|
||||
RescueImprisonedLeaderQuest as RescueImprisonedLeaderQuestProto,
|
||||
RestProvinceQuest as RestProvinceQuestProto,
|
||||
ReturnPrisonerQuest as ReturnPrisonerQuestProto,
|
||||
SendSuppliesQuest as SendSuppliesQuestProto,
|
||||
SpecificExpansionQuest as SpecificExpansionQuestProto,
|
||||
SpendOnFeastsQuest as SpendOnFeastsQuestProto,
|
||||
StartBlizzardQuest as StartBlizzardQuestProto,
|
||||
StartEpidemicQuest as StartEpidemicQuestProto,
|
||||
SuppressRiotByForceQuest as SuppressRiotByForceQuestProto,
|
||||
SwearBrotherhoodWithHeroQuest as SwearBrotherhoodWithHeroQuestProto,
|
||||
TotalDevelopmentQuest as TotalDevelopmentQuestProto,
|
||||
TruceCountQuest as TruceCountQuestProto,
|
||||
TruceWithFactionQuest as TruceWithFactionQuestProto,
|
||||
UpgradeBattalionQuest as UpgradeBattalionQuestProto,
|
||||
WealthQuest as WealthQuestProto
|
||||
WealthQuest as WealthQuestProto,
|
||||
WinBattleOutnumberedQuest as WinBattleOutnumberedQuestProto,
|
||||
WinBattlesQuest as WinBattlesQuestProto
|
||||
}
|
||||
import net.eagle0.eagle.model.state.quest.*
|
||||
import net.eagle0.eagle.model.state.BattalionTypeId
|
||||
|
||||
object QuestConverter {
|
||||
def toProto(quest: Quest): QuestProto = quest match {
|
||||
case AllianceQuest =>
|
||||
case AllianceQuest =>
|
||||
QuestProto(details = AllianceQuestProto())
|
||||
case q: AlmsAcrossRealmQuest =>
|
||||
case q: AlmsAcrossRealmQuest =>
|
||||
QuestProto(
|
||||
details = AlmsAcrossRealmQuestProto(q.totalFood),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: AlmsToProvinceQuest =>
|
||||
case q: AlmsToProvinceQuest =>
|
||||
QuestProto(
|
||||
details = AlmsToProvinceQuestProto(
|
||||
provinceId = q.provinceId,
|
||||
@@ -54,46 +70,46 @@ object QuestConverter {
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: DefeatFactionQuest =>
|
||||
case q: DefeatFactionQuest =>
|
||||
QuestProto(details = DefeatFactionQuestProto(q.targetFactionId))
|
||||
case q: DismissSpecificVassalQuest =>
|
||||
case q: DismissSpecificVassalQuest =>
|
||||
QuestProto(details = DismissSpecificVassalQuestProto(q.targetHeroId))
|
||||
case q: ExecutePrisonerQuest =>
|
||||
case q: ExecutePrisonerQuest =>
|
||||
QuestProto(
|
||||
details = ExecutePrisonerQuestProto(
|
||||
prisonerHeroId = q.prisonerHeroId,
|
||||
provinceId = q.prisonerProvinceId
|
||||
)
|
||||
)
|
||||
case q: ExpandToProvincesQuest =>
|
||||
case q: ExpandToProvincesQuest =>
|
||||
QuestProto(
|
||||
details = ExpandToProvincesQuestProto(
|
||||
targetProvinceCount = q.targetProvinceCount
|
||||
)
|
||||
)
|
||||
case FightBeastsAloneQuest =>
|
||||
case FightBeastsAloneQuest =>
|
||||
QuestProto(details = FightBeastsAloneQuestProto())
|
||||
case q: ExilePrisonerQuest =>
|
||||
case q: ExilePrisonerQuest =>
|
||||
QuestProto(
|
||||
details = ExilePrisonerQuestProto(
|
||||
prisonerHeroId = q.prisonerHeroId,
|
||||
provinceId = q.prisonerProvinceId
|
||||
)
|
||||
)
|
||||
case q: ReleasePrisonerQuest =>
|
||||
case q: ReleasePrisonerQuest =>
|
||||
QuestProto(
|
||||
details = ReleasePrisonerQuestProto(
|
||||
prisonerHeroId = q.prisonerHeroId,
|
||||
provinceId = q.prisonerProvinceId
|
||||
)
|
||||
)
|
||||
case q: GiveToHeroesAcrossRealmQuest =>
|
||||
case q: GiveToHeroesAcrossRealmQuest =>
|
||||
QuestProto(
|
||||
details = GiveToHeroesAcrossRealmQuestProto(q.totalGold),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: GiveToHeroesInProvinceQuest =>
|
||||
case q: GiveToHeroesInProvinceQuest =>
|
||||
QuestProto(
|
||||
details = GiveToHeroesInProvinceQuestProto(
|
||||
provinceId = q.provinceId,
|
||||
@@ -102,37 +118,37 @@ object QuestConverter {
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: GrandArmyQuest =>
|
||||
case q: GrandArmyQuest =>
|
||||
QuestProto(details = GrandArmyQuestProto(q.totalTroopCount))
|
||||
case q: ImproveAgricultureQuest =>
|
||||
case q: ImproveAgricultureQuest =>
|
||||
QuestProto(
|
||||
details = ImproveAgricultureQuestProto(
|
||||
provinceId = q.provinceId,
|
||||
desiredValue = q.desiredValue
|
||||
)
|
||||
)
|
||||
case q: ImproveEconomyQuest =>
|
||||
case q: ImproveEconomyQuest =>
|
||||
QuestProto(
|
||||
details = ImproveEconomyQuestProto(
|
||||
provinceId = q.provinceId,
|
||||
desiredValue = q.desiredValue
|
||||
)
|
||||
)
|
||||
case q: ImproveInfrastructureQuest =>
|
||||
case q: ImproveInfrastructureQuest =>
|
||||
QuestProto(
|
||||
details = ImproveInfrastructureQuestProto(
|
||||
provinceId = q.provinceId,
|
||||
desiredValue = q.desiredValue
|
||||
)
|
||||
)
|
||||
case q: RescueImprisonedLeaderQuest =>
|
||||
case q: RescueImprisonedLeaderQuest =>
|
||||
QuestProto(
|
||||
details = RescueImprisonedLeaderQuestProto(
|
||||
imprisonedHeroId = q.imprisonedHeroId,
|
||||
imprisoningFactionId = q.imprisoningFactionId
|
||||
)
|
||||
)
|
||||
case q: ReturnPrisonerQuest =>
|
||||
case q: ReturnPrisonerQuest =>
|
||||
QuestProto(
|
||||
details = ReturnPrisonerQuestProto(
|
||||
prisonerHeroId = q.prisonerHeroId,
|
||||
@@ -140,20 +156,20 @@ object QuestConverter {
|
||||
toFactionId = q.toFactionId
|
||||
)
|
||||
)
|
||||
case q: SpecificExpansionQuest =>
|
||||
case q: SpecificExpansionQuest =>
|
||||
QuestProto(details = SpecificExpansionQuestProto(q.provinceId))
|
||||
case q: TotalDevelopmentQuest =>
|
||||
case q: TotalDevelopmentQuest =>
|
||||
QuestProto(
|
||||
details = TotalDevelopmentQuestProto(
|
||||
provinceId = q.provinceId,
|
||||
desiredTotalDevelopment = q.desiredTotalDevelopment
|
||||
)
|
||||
)
|
||||
case q: TruceCountQuest =>
|
||||
case q: TruceCountQuest =>
|
||||
QuestProto(details = TruceCountQuestProto(q.truceCount))
|
||||
case q: TruceWithFactionQuest =>
|
||||
case q: TruceWithFactionQuest =>
|
||||
QuestProto(details = TruceWithFactionQuestProto(q.targetFactionId))
|
||||
case q: UpgradeBattalionQuest =>
|
||||
case q: UpgradeBattalionQuest =>
|
||||
QuestProto(
|
||||
details = UpgradeBattalionQuestProto(
|
||||
provinceId = q.provinceId,
|
||||
@@ -162,22 +178,85 @@ object QuestConverter {
|
||||
minimumTraining = q.minimumTraining
|
||||
)
|
||||
)
|
||||
case q: WealthQuest =>
|
||||
case q: WealthQuest =>
|
||||
QuestProto(details = WealthQuestProto(q.gold, q.food))
|
||||
case SuppressRiotByForceQuest =>
|
||||
case SuppressRiotByForceQuest =>
|
||||
QuestProto(details = SuppressRiotByForceQuestProto())
|
||||
case q: DevelopProvincesQuest =>
|
||||
case q: DevelopProvincesQuest =>
|
||||
QuestProto(
|
||||
details = DevelopProvincesQuestProto(q.targetProvinceCount),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: MobilizeProvincesQuest =>
|
||||
case q: MobilizeProvincesQuest =>
|
||||
QuestProto(
|
||||
details = MobilizeProvincesQuestProto(q.targetProvinceCount),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case BattalionDiversityQuest =>
|
||||
QuestProto(details = BattalionDiversityQuestProto())
|
||||
case ReleaseAllPrisonersQuest =>
|
||||
QuestProto(details = ReleaseAllPrisonersQuestProto())
|
||||
case q: SwearBrotherhoodWithHeroQuest =>
|
||||
QuestProto(details = SwearBrotherhoodWithHeroQuestProto(q.targetHeroId))
|
||||
case q: BetrayAllyQuest =>
|
||||
QuestProto(details = BetrayAllyQuestProto(q.targetFactionId))
|
||||
case q: BorderSecurityQuest =>
|
||||
QuestProto(details = BorderSecurityQuestProto(q.targetProvinceId))
|
||||
case WinBattleOutnumberedQuest =>
|
||||
QuestProto(details = WinBattleOutnumberedQuestProto())
|
||||
case q: WinBattlesQuest =>
|
||||
QuestProto(
|
||||
details = WinBattlesQuestProto(),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: ApprehendOutlawQuest =>
|
||||
QuestProto(details = ApprehendOutlawQuestProto(q.outlawHeroId))
|
||||
case q: StartBlizzardQuest =>
|
||||
QuestProto(details = StartBlizzardQuestProto(q.provinceId))
|
||||
case q: StartEpidemicQuest =>
|
||||
QuestProto(details = StartEpidemicQuestProto(q.provinceId))
|
||||
case q: SpendOnFeastsQuest =>
|
||||
QuestProto(
|
||||
details = SpendOnFeastsQuestProto(q.totalGold),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: SendSuppliesQuest =>
|
||||
QuestProto(
|
||||
details = SendSuppliesQuestProto(
|
||||
targetProvinceId = q.targetProvinceId,
|
||||
totalFood = q.totalFood
|
||||
),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: RestProvinceQuest =>
|
||||
QuestProto(
|
||||
details = RestProvinceQuestProto(q.targetProvinceId),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: ReconProvincesQuest =>
|
||||
QuestProto(
|
||||
details = ReconProvincesQuestProto(q.targetProvinceCount),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: ReconSpecificProvincesQuest =>
|
||||
QuestProto(
|
||||
details = ReconSpecificProvincesQuestProto(q.targetProvinceIds),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
case q: RepairDevastationQuest =>
|
||||
QuestProto(
|
||||
details = RepairDevastationQuestProto(q.targetDevastationRepaired),
|
||||
componentCount = q.componentCount,
|
||||
componentsFulfilled = q.componentsFulfilled
|
||||
)
|
||||
}
|
||||
|
||||
def fromProto(questProto: QuestProto): Quest =
|
||||
@@ -336,6 +415,94 @@ object QuestConverter {
|
||||
componentsFulfilled = questProto.componentsFulfilled,
|
||||
targetProvinceCount = targetProvinceCount
|
||||
)
|
||||
case BattalionDiversityQuestProto(_ /* unknownFieldSet */ ) =>
|
||||
BattalionDiversityQuest
|
||||
case ReleaseAllPrisonersQuestProto(_ /* unknownFieldSet */ ) =>
|
||||
ReleaseAllPrisonersQuest
|
||||
case SwearBrotherhoodWithHeroQuestProto(
|
||||
targetHeroId,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
SwearBrotherhoodWithHeroQuest(targetHeroId)
|
||||
case BetrayAllyQuestProto(
|
||||
targetFactionId,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
BetrayAllyQuest(targetFactionId)
|
||||
case BorderSecurityQuestProto(
|
||||
targetProvinceId,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
BorderSecurityQuest(targetProvinceId)
|
||||
case WinBattleOutnumberedQuestProto(_ /* unknownFieldSet */ ) =>
|
||||
WinBattleOutnumberedQuest
|
||||
case WinBattlesQuestProto(_ /* unknownFieldSet */ ) =>
|
||||
WinBattlesQuest(
|
||||
componentCount = questProto.componentCount,
|
||||
componentsFulfilled = questProto.componentsFulfilled
|
||||
)
|
||||
case ApprehendOutlawQuestProto(
|
||||
outlawHeroId,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
ApprehendOutlawQuest(outlawHeroId)
|
||||
case StartBlizzardQuestProto(provinceId, _ /* unknownFieldSet */ ) =>
|
||||
StartBlizzardQuest(provinceId)
|
||||
case StartEpidemicQuestProto(provinceId, _ /* unknownFieldSet */ ) =>
|
||||
StartEpidemicQuest(provinceId)
|
||||
case SpendOnFeastsQuestProto(totalGold, _ /* unknownFieldSet */ ) =>
|
||||
SpendOnFeastsQuest(
|
||||
componentCount = questProto.componentCount,
|
||||
componentsFulfilled = questProto.componentsFulfilled,
|
||||
totalGold = totalGold
|
||||
)
|
||||
case SendSuppliesQuestProto(
|
||||
targetProvinceId,
|
||||
totalFood,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
SendSuppliesQuest(
|
||||
componentCount = questProto.componentCount,
|
||||
componentsFulfilled = questProto.componentsFulfilled,
|
||||
targetProvinceId = targetProvinceId,
|
||||
totalFood = totalFood
|
||||
)
|
||||
case RestProvinceQuestProto(
|
||||
targetProvinceId,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
RestProvinceQuest(
|
||||
componentCount = questProto.componentCount,
|
||||
componentsFulfilled = questProto.componentsFulfilled,
|
||||
targetProvinceId = targetProvinceId
|
||||
)
|
||||
case ReconProvincesQuestProto(
|
||||
targetProvinceCount,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
ReconProvincesQuest(
|
||||
componentCount = questProto.componentCount,
|
||||
componentsFulfilled = questProto.componentsFulfilled,
|
||||
targetProvinceCount = targetProvinceCount
|
||||
)
|
||||
case ReconSpecificProvincesQuestProto(
|
||||
targetProvinceIds,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
ReconSpecificProvincesQuest(
|
||||
componentCount = questProto.componentCount,
|
||||
componentsFulfilled = questProto.componentsFulfilled,
|
||||
targetProvinceIds = targetProvinceIds.toVector
|
||||
)
|
||||
case RepairDevastationQuestProto(
|
||||
targetDevastationRepaired,
|
||||
_ /* unknownFieldSet */
|
||||
) =>
|
||||
RepairDevastationQuest(
|
||||
componentCount = questProto.componentCount,
|
||||
componentsFulfilled = questProto.componentsFulfilled,
|
||||
targetDevastationRepaired = targetDevastationRepaired
|
||||
)
|
||||
case QuestDetailsProto.Empty =>
|
||||
throw new IllegalArgumentException("Empty quest details")
|
||||
}
|
||||
|
||||
@@ -146,3 +146,84 @@ case class MobilizeProvincesQuest(
|
||||
override def withComponentsFulfilled(componentsFulfilled: Int): Quest =
|
||||
this.copy(componentsFulfilled = componentsFulfilled)
|
||||
}
|
||||
|
||||
case object BattalionDiversityQuest extends Quest
|
||||
|
||||
case object ReleaseAllPrisonersQuest extends Quest
|
||||
|
||||
case class SwearBrotherhoodWithHeroQuest(targetHeroId: HeroId) extends Quest
|
||||
|
||||
case class BetrayAllyQuest(targetFactionId: FactionId) extends Quest
|
||||
|
||||
case class BorderSecurityQuest(targetProvinceId: ProvinceId) extends Quest
|
||||
|
||||
case object WinBattleOutnumberedQuest extends Quest
|
||||
|
||||
case class WinBattlesQuest(
|
||||
override val componentCount: Int,
|
||||
override val componentsFulfilled: Int
|
||||
) extends ComponentQuest {
|
||||
override def withComponentsFulfilled(componentsFulfilled: Int): Quest =
|
||||
this.copy(componentsFulfilled = componentsFulfilled)
|
||||
}
|
||||
|
||||
case class ApprehendOutlawQuest(outlawHeroId: HeroId) extends Quest
|
||||
|
||||
case class StartBlizzardQuest(provinceId: ProvinceId) extends Quest
|
||||
|
||||
case class StartEpidemicQuest(provinceId: ProvinceId) extends Quest
|
||||
|
||||
case class SpendOnFeastsQuest(
|
||||
override val componentCount: Int,
|
||||
override val componentsFulfilled: Int,
|
||||
totalGold: Int
|
||||
) extends ComponentQuest {
|
||||
override def withComponentsFulfilled(componentsFulfilled: Int): Quest =
|
||||
this.copy(componentsFulfilled = componentsFulfilled)
|
||||
}
|
||||
|
||||
case class SendSuppliesQuest(
|
||||
override val componentCount: Int,
|
||||
override val componentsFulfilled: Int,
|
||||
targetProvinceId: ProvinceId,
|
||||
totalFood: Int
|
||||
) extends ComponentQuest {
|
||||
override def withComponentsFulfilled(componentsFulfilled: Int): Quest =
|
||||
this.copy(componentsFulfilled = componentsFulfilled)
|
||||
}
|
||||
|
||||
case class RestProvinceQuest(
|
||||
override val componentCount: Int,
|
||||
override val componentsFulfilled: Int,
|
||||
targetProvinceId: ProvinceId
|
||||
) extends ComponentQuest {
|
||||
override def withComponentsFulfilled(componentsFulfilled: Int): Quest =
|
||||
this.copy(componentsFulfilled = componentsFulfilled)
|
||||
}
|
||||
|
||||
case class ReconProvincesQuest(
|
||||
override val componentCount: Int,
|
||||
override val componentsFulfilled: Int,
|
||||
targetProvinceCount: Int
|
||||
) extends ComponentQuest {
|
||||
override def withComponentsFulfilled(componentsFulfilled: Int): Quest =
|
||||
this.copy(componentsFulfilled = componentsFulfilled)
|
||||
}
|
||||
|
||||
case class ReconSpecificProvincesQuest(
|
||||
override val componentCount: Int,
|
||||
override val componentsFulfilled: Int,
|
||||
targetProvinceIds: Vector[ProvinceId]
|
||||
) extends ComponentQuest {
|
||||
override def withComponentsFulfilled(componentsFulfilled: Int): Quest =
|
||||
this.copy(componentsFulfilled = componentsFulfilled)
|
||||
}
|
||||
|
||||
case class RepairDevastationQuest(
|
||||
override val componentCount: Int,
|
||||
override val componentsFulfilled: Int,
|
||||
targetDevastationRepaired: Int
|
||||
) extends ComponentQuest {
|
||||
override def withComponentsFulfilled(componentsFulfilled: Int): Quest =
|
||||
this.copy(componentsFulfilled = componentsFulfilled)
|
||||
}
|
||||
|
||||
@@ -15,11 +15,13 @@ cc_library(
|
||||
)
|
||||
|
||||
# Test for AbstractMCTSAI algorithm
|
||||
# Disabled: MCTS is not currently in use
|
||||
cc_test(
|
||||
name = "abstract_mcts_ai_test",
|
||||
srcs = ["AbstractMCTSAI_test.cpp"],
|
||||
copts = TEST_COPTS,
|
||||
linkstatic = True,
|
||||
tags = ["manual"],
|
||||
deps = [
|
||||
":mock_tictactoe",
|
||||
"//src/main/cpp/net/eagle0/common/mcts/abstract:abstract_mcts_ai",
|
||||
@@ -61,7 +63,6 @@ cc_test(
|
||||
test_suite(
|
||||
name = "all_abstract_tests",
|
||||
tests = [
|
||||
":abstract_mcts_ai_test",
|
||||
":mcts_integration_test",
|
||||
":mcts_node_test",
|
||||
],
|
||||
|
||||
@@ -24,6 +24,7 @@ cc_test(
|
||||
"//src/main/resources/net/eagle0/shardok:settings",
|
||||
"//src/main/resources/net/eagle0/shardok/maps",
|
||||
],
|
||||
flaky = True, # MCTS has non-deterministic behavior
|
||||
linkstatic = True,
|
||||
deps = [
|
||||
"//src/main/cpp/net/eagle0/common:filesystem_utils",
|
||||
|
||||
+52
-26
@@ -52,7 +52,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provinces,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(defeatFactionQuest, province) shouldBe true
|
||||
}
|
||||
@@ -87,7 +88,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provinces,
|
||||
factions = factionsWithTruce,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(defeatFactionQuest, province) shouldBe true
|
||||
}
|
||||
@@ -122,7 +124,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provinces,
|
||||
factions = factionsWithoutTruce,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(defeatFactionQuest, province) shouldBe false
|
||||
}
|
||||
@@ -138,7 +141,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provinces,
|
||||
factions = factionsWithoutTarget,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(truceWithFactionQuest, province) shouldBe true
|
||||
}
|
||||
@@ -157,7 +161,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provinces,
|
||||
factions = factionsWithTarget,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(truceWithFactionQuest, province) shouldBe false
|
||||
}
|
||||
@@ -179,7 +184,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provinces,
|
||||
factions = threeFactions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(truceCountQuest, province) shouldBe true
|
||||
}
|
||||
@@ -208,7 +214,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provinces,
|
||||
factions = fourFactions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(truceCountQuest, province) shouldBe false
|
||||
}
|
||||
@@ -231,7 +238,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provinces,
|
||||
factions = factionsWithTargetALeader,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(dismissVassalQuest, province) shouldBe true
|
||||
}
|
||||
@@ -249,7 +257,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provinces,
|
||||
factions = factionsWithTargetNotALeader,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(dismissVassalQuest, province) shouldBe false
|
||||
}
|
||||
@@ -281,7 +290,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(returnPrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -304,7 +314,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(returnPrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -327,7 +338,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(returnPrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -350,7 +362,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = Vector(actingFaction),
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(returnPrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -373,7 +386,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(returnPrisonerQuest, province) shouldBe false
|
||||
}
|
||||
@@ -402,7 +416,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(releasePrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -425,7 +440,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(releasePrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -448,7 +464,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(releasePrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -471,7 +488,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(releasePrisonerQuest, province) shouldBe false
|
||||
}
|
||||
@@ -500,7 +518,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(exilePrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -523,7 +542,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(exilePrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -546,7 +566,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(exilePrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -569,7 +590,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(exilePrisonerQuest, province) shouldBe false
|
||||
}
|
||||
@@ -598,7 +620,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(executePrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -621,7 +644,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(executePrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -644,7 +668,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(executePrisonerQuest, province) shouldBe true
|
||||
}
|
||||
@@ -667,7 +692,8 @@ class CheckForFailedQuestsActionTest extends AnyFlatSpec with Matchers {
|
||||
currentRoundId = roundId,
|
||||
provinces = provincesWithPrisoner,
|
||||
factions = factions,
|
||||
hid => s"backstory $hid"
|
||||
heroes = Map.empty,
|
||||
heroBackstoryTextIdLookup = hid => s"backstory $hid"
|
||||
)
|
||||
.isQuestFailed(executePrisonerQuest, province) shouldBe false
|
||||
}
|
||||
|
||||
+20
-6
@@ -28,6 +28,7 @@ import net.eagle0.eagle.model.state.province.ProvinceOrderType.Entrust
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.concrete.UnaffiliatedHeroC
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.RecruitmentInfo
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroType.Prisoner
|
||||
import net.eagle0.eagle.GameId
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
@@ -38,6 +39,7 @@ import org.scalatest.LoneElement.convertToCollectionLoneElementWrapper
|
||||
class BreakAllianceResolutionHelpersTest extends AnyFlatSpec with BeforeAndAfterEach with Matchers {
|
||||
val breakingFactionId = 7
|
||||
val actingFactionId = 4
|
||||
val gameId: GameId = 0xcafe
|
||||
|
||||
private val breakAllianceOffer: BreakAlliance = BreakAlliance(
|
||||
originatingFactionId = breakingFactionId,
|
||||
@@ -104,9 +106,11 @@ class BreakAllianceResolutionHelpersTest extends AnyFlatSpec with BeforeAndAfter
|
||||
currentDate = currentDate,
|
||||
provinces = provinces,
|
||||
factions = factions,
|
||||
functionalRandom = functionalRandom
|
||||
functionalRandom = functionalRandom,
|
||||
gameId = gameId
|
||||
)
|
||||
.newValue
|
||||
.head
|
||||
.actionResultType shouldBe BreakAllianceAccepted
|
||||
}
|
||||
|
||||
@@ -118,9 +122,11 @@ class BreakAllianceResolutionHelpersTest extends AnyFlatSpec with BeforeAndAfter
|
||||
currentDate = currentDate,
|
||||
provinces = provinces,
|
||||
factions = factions,
|
||||
functionalRandom = functionalRandom
|
||||
functionalRandom = functionalRandom,
|
||||
gameId = gameId
|
||||
)
|
||||
.newValue
|
||||
.head
|
||||
) { result =>
|
||||
forExactly(1, result.changedFactions) {
|
||||
case changedFaction: ChangedFactionC =>
|
||||
@@ -137,9 +143,11 @@ class BreakAllianceResolutionHelpersTest extends AnyFlatSpec with BeforeAndAfter
|
||||
currentDate = currentDate,
|
||||
provinces = provinces,
|
||||
factions = factions,
|
||||
functionalRandom = functionalRandom
|
||||
functionalRandom = functionalRandom,
|
||||
gameId = gameId
|
||||
)
|
||||
.newValue
|
||||
.head
|
||||
) { result =>
|
||||
forExactly(1, result.changedFactions) {
|
||||
case changedFaction: ChangedFactionC =>
|
||||
@@ -161,9 +169,11 @@ class BreakAllianceResolutionHelpersTest extends AnyFlatSpec with BeforeAndAfter
|
||||
currentDate = currentDate,
|
||||
provinces = provinces,
|
||||
factions = factions,
|
||||
functionalRandom = functionalRandom
|
||||
functionalRandom = functionalRandom,
|
||||
gameId = gameId
|
||||
)
|
||||
.newValue
|
||||
.head
|
||||
) { result =>
|
||||
forExactly(1, result.changedFactions) {
|
||||
case changedFaction: ChangedFactionC =>
|
||||
@@ -185,9 +195,11 @@ class BreakAllianceResolutionHelpersTest extends AnyFlatSpec with BeforeAndAfter
|
||||
currentDate = currentDate,
|
||||
provinces = provinces,
|
||||
factions = factions,
|
||||
functionalRandom = functionalRandom
|
||||
functionalRandom = functionalRandom,
|
||||
gameId = gameId
|
||||
)
|
||||
.newValue
|
||||
.head
|
||||
) { result =>
|
||||
forExactly(1, result.changedProvinces) {
|
||||
case changedProvince: ChangedProvinceC =>
|
||||
@@ -204,9 +216,11 @@ class BreakAllianceResolutionHelpersTest extends AnyFlatSpec with BeforeAndAfter
|
||||
currentDate = currentDate,
|
||||
provinces = provinces,
|
||||
factions = factions,
|
||||
functionalRandom = functionalRandom
|
||||
functionalRandom = functionalRandom,
|
||||
gameId = gameId
|
||||
)
|
||||
.newValue
|
||||
.head
|
||||
) { result =>
|
||||
forExactly(1, result.changedHeroes) {
|
||||
case hero: ChangedHeroC =>
|
||||
|
||||
+48
-20
@@ -2,11 +2,13 @@ package net.eagle0.eagle
|
||||
package library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.library.settings.{ApprehendOutlawVigorCost, FactionBiasFromImprisonment}
|
||||
import net.eagle0.eagle.library.util.quest_fulfillment.QuestFulfillmentChecker
|
||||
import net.eagle0.eagle.library.EagleClientException
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.concrete.{ChangedHeroC, StatDelta}
|
||||
import net.eagle0.eagle.model.action_result.types.ActionResultType.OutlawApprehended
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.province.concrete.ProvinceC
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.{RecruitmentInfo, UnaffiliatedHeroType}
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.concrete.UnaffiliatedHeroC
|
||||
@@ -26,11 +28,13 @@ class ApprehendOutlawCommandTest extends AnyFlatSpec with Matchers with BeforeAn
|
||||
|
||||
behavior of "ApprehendOutlawCommandTest"
|
||||
|
||||
private val fid = 17
|
||||
private val pid = 4
|
||||
private val fid = 17
|
||||
private val pid = 4
|
||||
private val currentDate = Date(year = 1500, month = Date.Month.January)
|
||||
|
||||
private val actingProvince = ProvinceC(
|
||||
id = pid,
|
||||
rulingFactionId = Some(fid),
|
||||
unaffiliatedHeroes = Vector(
|
||||
UnaffiliatedHeroC(
|
||||
heroId = 10,
|
||||
@@ -52,9 +56,11 @@ class ApprehendOutlawCommandTest extends AnyFlatSpec with Matchers with BeforeAn
|
||||
private val availableHeroIds = Vector(3, 4, 5)
|
||||
private val outlawHeroIds = Vector(10, 20)
|
||||
|
||||
private val heroIdToApprehend = 20
|
||||
private val actingHeroId = 3
|
||||
private val gameId = 123L
|
||||
private val heroIdToApprehend = 20
|
||||
private val actingHeroId = 3
|
||||
private val gameId = 123L
|
||||
private val questFulfillmentChecker = new QuestFulfillmentChecker(gameId, currentDate)
|
||||
private val allProvinces = Vector(actingProvince)
|
||||
|
||||
"make" should "throw if the selected actor was not in available" in {
|
||||
val ex = the[EagleClientException] thrownBy
|
||||
@@ -65,7 +71,9 @@ class ApprehendOutlawCommandTest extends AnyFlatSpec with Matchers with BeforeAn
|
||||
outlawHeroIds = outlawHeroIds,
|
||||
actingHeroId = 6,
|
||||
heroIdToApprehend = heroIdToApprehend,
|
||||
actingProvince = actingProvince
|
||||
actingProvince = actingProvince,
|
||||
allProvinces = allProvinces,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
ex.getMessage shouldBe "requirement failed: Selected hid 6 was not among Vector(3, 4, 5)"
|
||||
}
|
||||
@@ -79,13 +87,15 @@ class ApprehendOutlawCommandTest extends AnyFlatSpec with Matchers with BeforeAn
|
||||
outlawHeroIds = outlawHeroIds,
|
||||
actingHeroId = actingHeroId,
|
||||
heroIdToApprehend = 30,
|
||||
actingProvince = actingProvince
|
||||
actingProvince = actingProvince,
|
||||
allProvinces = allProvinces,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Selected target hid 30 was not among Vector(10, 20)"
|
||||
}
|
||||
|
||||
"immediateExecute" should "set the basics" in {
|
||||
"results" should "set the basics" in {
|
||||
val result = ApprehendOutlawCommand
|
||||
.make(
|
||||
actingFactionId = fid,
|
||||
@@ -94,9 +104,12 @@ class ApprehendOutlawCommandTest extends AnyFlatSpec with Matchers with BeforeAn
|
||||
outlawHeroIds = outlawHeroIds,
|
||||
actingHeroId = actingHeroId,
|
||||
heroIdToApprehend = heroIdToApprehend,
|
||||
actingProvince = actingProvince
|
||||
actingProvince = actingProvince,
|
||||
allProvinces = allProvinces,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
.immediateExecute
|
||||
.results
|
||||
.head
|
||||
|
||||
result.actionResultType shouldBe OutlawApprehended
|
||||
result.actingFactionId shouldBe Some(fid)
|
||||
@@ -112,9 +125,12 @@ class ApprehendOutlawCommandTest extends AnyFlatSpec with Matchers with BeforeAn
|
||||
outlawHeroIds = outlawHeroIds,
|
||||
actingHeroId = actingHeroId,
|
||||
heroIdToApprehend = heroIdToApprehend,
|
||||
actingProvince = actingProvince
|
||||
actingProvince = actingProvince,
|
||||
allProvinces = allProvinces,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
.immediateExecute
|
||||
.results
|
||||
.head
|
||||
|
||||
inside(result.changedHeroes.head) {
|
||||
case ch: ChangedHeroC =>
|
||||
@@ -131,9 +147,12 @@ class ApprehendOutlawCommandTest extends AnyFlatSpec with Matchers with BeforeAn
|
||||
outlawHeroIds = outlawHeroIds,
|
||||
actingHeroId = actingHeroId,
|
||||
heroIdToApprehend = heroIdToApprehend,
|
||||
actingProvince = actingProvince
|
||||
actingProvince = actingProvince,
|
||||
allProvinces = allProvinces,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
.immediateExecute
|
||||
.results
|
||||
.head
|
||||
|
||||
inside(result.changedProvinces.head) {
|
||||
case cp: ChangedProvinceC =>
|
||||
@@ -150,9 +169,12 @@ class ApprehendOutlawCommandTest extends AnyFlatSpec with Matchers with BeforeAn
|
||||
outlawHeroIds = outlawHeroIds,
|
||||
actingHeroId = actingHeroId,
|
||||
heroIdToApprehend = heroIdToApprehend,
|
||||
actingProvince = actingProvince
|
||||
actingProvince = actingProvince,
|
||||
allProvinces = allProvinces,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
.immediateExecute
|
||||
.results
|
||||
.head
|
||||
|
||||
inside(result.changedProvinces.head) {
|
||||
case cp: ChangedProvinceC =>
|
||||
@@ -178,9 +200,12 @@ class ApprehendOutlawCommandTest extends AnyFlatSpec with Matchers with BeforeAn
|
||||
outlawHeroIds = outlawHeroIds,
|
||||
actingHeroId = actingHeroId,
|
||||
heroIdToApprehend = heroIdToApprehend,
|
||||
actingProvince = actingProvince
|
||||
actingProvince = actingProvince,
|
||||
allProvinces = allProvinces,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
.immediateExecute
|
||||
.results
|
||||
.head
|
||||
|
||||
forExactly(1, result.newNotifications) { (note: NotificationT) =>
|
||||
inside(note.details) {
|
||||
@@ -202,9 +227,12 @@ class ApprehendOutlawCommandTest extends AnyFlatSpec with Matchers with BeforeAn
|
||||
outlawHeroIds = outlawHeroIds,
|
||||
actingHeroId = actingHeroId,
|
||||
heroIdToApprehend = heroIdToApprehend,
|
||||
actingProvince = actingProvince
|
||||
actingProvince = actingProvince,
|
||||
allProvinces = allProvinces,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
.immediateExecute
|
||||
.results
|
||||
.head
|
||||
|
||||
result.provinceIdActed should contain(pid)
|
||||
}
|
||||
|
||||
@@ -7,9 +7,10 @@ scala_test(
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:apprehend_outlaw_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_sequential_results_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:apprehend_outlaw_vigor_cost",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:faction_bias_from_imprisonment",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/quest_fulfillment:quest_fulfillment_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_component_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
@@ -18,6 +19,7 @@ scala_test(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/unaffiliated_hero",
|
||||
@@ -1013,9 +1015,10 @@ scala_test(
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_client_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:swear_brotherhood_command",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_simple_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_sequential_results_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:accept_brotherhood_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:swear_brotherhood_charisma_xp",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/quest_fulfillment:quest_fulfillment_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
|
||||
+22
-12
@@ -1,8 +1,9 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.{FactionId, GameId, HeroId, ProvinceId, RoundId}
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSimpleAction
|
||||
import net.eagle0.eagle.library.actions.impl.common.ProtolessSequentialResultsAction
|
||||
import net.eagle0.eagle.library.settings.{AcceptBrotherhoodCharismaXp, SwearBrotherhoodCharismaXp}
|
||||
import net.eagle0.eagle.library.util.quest_fulfillment.QuestFulfillmentChecker
|
||||
import net.eagle0.eagle.library.EagleCommandException
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.action_result.concrete.{ActionResultC, ChangedFactionC, ChangedHeroC, NotificationC}
|
||||
@@ -29,6 +30,7 @@ class SwearBrotherhoodCommandTest extends AnyFlatSpec with Matchers with BeforeA
|
||||
private val currentDate = Date(year = 1500, month = Date.Month.January)
|
||||
private val currentRoundId: RoundId = 0
|
||||
private val gameId: GameId = 0xcafe
|
||||
private val questFulfillmentChecker = new QuestFulfillmentChecker(gameId, currentDate)
|
||||
|
||||
"make" should "throw if the selected brother is not among the options" in {
|
||||
val invalidBrotherHeroId: HeroId = 9
|
||||
@@ -42,14 +44,16 @@ class SwearBrotherhoodCommandTest extends AnyFlatSpec with Matchers with BeforeA
|
||||
factionHeadHeroId = factionHeadHeroId,
|
||||
currentDate = currentDate,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
gameId = gameId,
|
||||
allProvinces = Vector.empty,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
|
||||
ex.getMessage shouldBe "requirement failed: Tried to swear brotherhood with 9, but options were Vector(5, 6, 7)"
|
||||
}
|
||||
|
||||
"immediateExecute" should "set the basic action result fields" in {
|
||||
val action: ProtolessSimpleAction = SwearBrotherhoodCommand.make(
|
||||
"results" should "set the basic action result fields" in {
|
||||
val action: ProtolessSequentialResultsAction = SwearBrotherhoodCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = actingProvinceId,
|
||||
newBrotherHeroId = newBrotherHeroId,
|
||||
@@ -57,9 +61,11 @@ class SwearBrotherhoodCommandTest extends AnyFlatSpec with Matchers with BeforeA
|
||||
factionHeadHeroId = factionHeadHeroId,
|
||||
currentDate = currentDate,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
gameId = gameId,
|
||||
allProvinces = Vector.empty,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
val result = action.immediateExecute
|
||||
val result = action.results.head
|
||||
|
||||
result.shouldBe(a[ActionResultC])
|
||||
val actionResult = result.asInstanceOf[ActionResultC]
|
||||
@@ -71,7 +77,7 @@ class SwearBrotherhoodCommandTest extends AnyFlatSpec with Matchers with BeforeA
|
||||
}
|
||||
|
||||
it should "add the new brother to faction leaders and give charisma XP" in {
|
||||
val action: ProtolessSimpleAction = SwearBrotherhoodCommand.make(
|
||||
val action: ProtolessSequentialResultsAction = SwearBrotherhoodCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = actingProvinceId,
|
||||
newBrotherHeroId = newBrotherHeroId,
|
||||
@@ -79,9 +85,11 @@ class SwearBrotherhoodCommandTest extends AnyFlatSpec with Matchers with BeforeA
|
||||
factionHeadHeroId = factionHeadHeroId,
|
||||
currentDate = currentDate,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
gameId = gameId,
|
||||
allProvinces = Vector.empty,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
val result = action.immediateExecute
|
||||
val result = action.results.head
|
||||
|
||||
result.shouldBe(a[ActionResultC])
|
||||
val actionResult = result.asInstanceOf[ActionResultC]
|
||||
@@ -117,7 +125,7 @@ class SwearBrotherhoodCommandTest extends AnyFlatSpec with Matchers with BeforeA
|
||||
}
|
||||
|
||||
it should "create notification and LLM request for the brotherhood event" in {
|
||||
val action: ProtolessSimpleAction = SwearBrotherhoodCommand.make(
|
||||
val action: ProtolessSequentialResultsAction = SwearBrotherhoodCommand.make(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = actingProvinceId,
|
||||
newBrotherHeroId = newBrotherHeroId,
|
||||
@@ -125,9 +133,11 @@ class SwearBrotherhoodCommandTest extends AnyFlatSpec with Matchers with BeforeA
|
||||
factionHeadHeroId = factionHeadHeroId,
|
||||
currentDate = currentDate,
|
||||
currentRoundId = currentRoundId,
|
||||
gameId = gameId
|
||||
gameId = gameId,
|
||||
allProvinces = Vector.empty,
|
||||
questFulfillmentChecker = questFulfillmentChecker
|
||||
)
|
||||
val result = action.immediateExecute
|
||||
val result = action.results.head
|
||||
|
||||
result.shouldBe(a[ActionResultC])
|
||||
val actionResult = result.asInstanceOf[ActionResultC]
|
||||
|
||||
@@ -8,6 +8,7 @@ scala_test(
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/faction_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction:faction_relationship",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province/concrete",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -3,12 +3,142 @@ package net.eagle0.eagle.library.util.faction_utils
|
||||
import net.eagle0.eagle.{FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.model.state.faction.concrete.FactionC
|
||||
import net.eagle0.eagle.model.state.faction.FactionRelationship
|
||||
import net.eagle0.eagle.model.state.hero.concrete.HeroC
|
||||
import net.eagle0.eagle.model.state.province.concrete.ProvinceC
|
||||
import net.eagle0.eagle.model.state.province.Neighbor
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
||||
class FactionUtilsTest extends AnyFlatSpec with Matchers {
|
||||
|
||||
// Tests for heroIsInFaction
|
||||
"heroIsInFaction" should "return true when hero's factionId matches" in {
|
||||
val factionId: FactionId = 1
|
||||
val heroId: HeroId = 10
|
||||
val heroes = Map(
|
||||
heroId -> HeroC(id = heroId, factionId = Some(factionId))
|
||||
)
|
||||
|
||||
FactionUtils.heroIsInFaction(heroId, factionId, heroes) shouldBe true
|
||||
}
|
||||
|
||||
it should "return false when hero's factionId does not match" in {
|
||||
val heroes = Map(
|
||||
10 -> HeroC(id = 10, factionId = Some(1))
|
||||
)
|
||||
|
||||
FactionUtils.heroIsInFaction(10, factionId = 2, heroes) shouldBe false
|
||||
}
|
||||
|
||||
it should "return false when hero has no factionId (exiled/outlaw)" in {
|
||||
val heroes = Map(
|
||||
10 -> HeroC(id = 10, factionId = None)
|
||||
)
|
||||
|
||||
FactionUtils.heroIsInFaction(10, factionId = 1, heroes) shouldBe false
|
||||
}
|
||||
|
||||
it should "return false when hero does not exist in the map" in {
|
||||
val heroes = Map(
|
||||
10 -> HeroC(id = 10, factionId = Some(1))
|
||||
)
|
||||
|
||||
FactionUtils.heroIsInFaction(heroId = 99, factionId = 1, heroes) shouldBe false
|
||||
}
|
||||
|
||||
it should "return true for imprisoned hero (prisoners retain factionId)" in {
|
||||
// Prisoners keep their factionId even when in UnaffiliatedHero state
|
||||
val factionId: FactionId = 1
|
||||
val heroId: HeroId = 10
|
||||
val heroes = Map(
|
||||
heroId -> HeroC(id = heroId, factionId = Some(factionId))
|
||||
)
|
||||
|
||||
// Even if this hero is in an enemy province as a prisoner,
|
||||
// their factionId in the hero object remains set
|
||||
FactionUtils.heroIsInFaction(heroId, factionId, heroes) shouldBe true
|
||||
}
|
||||
|
||||
it should "return true for hero in moving army (they retain factionId)" in {
|
||||
// Heroes in moving armies keep their factionId
|
||||
val factionId: FactionId = 1
|
||||
val heroId: HeroId = 10
|
||||
val heroes = Map(
|
||||
heroId -> HeroC(id = heroId, factionId = Some(factionId))
|
||||
)
|
||||
|
||||
FactionUtils.heroIsInFaction(heroId, factionId, heroes) shouldBe true
|
||||
}
|
||||
|
||||
// Tests for heroIdsInFaction
|
||||
"heroIdsInFaction" should "return all hero IDs belonging to a faction" in {
|
||||
val factionId: FactionId = 1
|
||||
val heroes = Vector(
|
||||
HeroC(id = 10, factionId = Some(factionId)),
|
||||
HeroC(id = 20, factionId = Some(factionId)),
|
||||
HeroC(id = 30, factionId = Some(2)),
|
||||
HeroC(id = 40, factionId = None)
|
||||
)
|
||||
|
||||
FactionUtils.heroIdsInFaction(factionId, heroes) shouldBe Set(10, 20)
|
||||
}
|
||||
|
||||
it should "return empty set when no heroes belong to faction" in {
|
||||
val heroes = Vector(
|
||||
HeroC(id = 10, factionId = Some(2)),
|
||||
HeroC(id = 20, factionId = None)
|
||||
)
|
||||
|
||||
FactionUtils.heroIdsInFaction(factionId = 1, heroes) shouldBe empty
|
||||
}
|
||||
|
||||
it should "return empty set for empty heroes collection" in {
|
||||
FactionUtils.heroIdsInFaction(factionId = 1, Vector.empty[HeroC]) shouldBe empty
|
||||
}
|
||||
|
||||
it should "include imprisoned heroes (they retain factionId)" in {
|
||||
val factionId: FactionId = 1
|
||||
val heroes = Vector(
|
||||
HeroC(id = 10, factionId = Some(factionId)), // Normal hero in province
|
||||
HeroC(id = 20, factionId = Some(factionId)), // Imprisoned hero
|
||||
HeroC(id = 30, factionId = Some(factionId)) // Hero in moving army
|
||||
)
|
||||
|
||||
// All three should be included
|
||||
FactionUtils.heroIdsInFaction(factionId, heroes) shouldBe Set(10, 20, 30)
|
||||
}
|
||||
|
||||
it should "exclude exiled heroes (factionId cleared)" in {
|
||||
val factionId: FactionId = 1
|
||||
val heroes = Vector(
|
||||
HeroC(id = 10, factionId = Some(factionId)),
|
||||
HeroC(id = 20, factionId = None) // Exiled - factionId was cleared
|
||||
)
|
||||
|
||||
FactionUtils.heroIdsInFaction(factionId, heroes) shouldBe Set(10)
|
||||
}
|
||||
|
||||
it should "exclude outlaws (factionId cleared)" in {
|
||||
val factionId: FactionId = 1
|
||||
val heroes = Vector(
|
||||
HeroC(id = 10, factionId = Some(factionId)),
|
||||
HeroC(id = 20, factionId = None) // Outlaw - factionId was cleared
|
||||
)
|
||||
|
||||
FactionUtils.heroIdsInFaction(factionId, heroes) shouldBe Set(10)
|
||||
}
|
||||
|
||||
it should "work with Map values" in {
|
||||
val factionId: FactionId = 1
|
||||
val heroes = Map(
|
||||
10 -> HeroC(id = 10, factionId = Some(factionId)),
|
||||
20 -> HeroC(id = 20, factionId = Some(factionId)),
|
||||
30 -> HeroC(id = 30, factionId = Some(2))
|
||||
)
|
||||
|
||||
FactionUtils.heroIdsInFaction(factionId, heroes.values) shouldBe Set(10, 20)
|
||||
}
|
||||
|
||||
"hasTruce" should "return true if there is a truce" in {
|
||||
val factions = Vector(
|
||||
FactionC(
|
||||
|
||||
+1
-1
@@ -511,7 +511,7 @@ class QuestCreationUtilsTest extends AnyFlatSpec with Matchers with BeforeAndAft
|
||||
forAtLeast(1, quests) { q =>
|
||||
inside(q) {
|
||||
case GrandArmyQuest(totalTroopCount) =>
|
||||
totalTroopCount should be > 3200 + 2500
|
||||
totalTroopCount should be >= 3200 + 2500
|
||||
totalTroopCount should be < 3200 + 5000
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ scala_toolchain(
|
||||
# Also suppress duplicate flag warnings caused by rules_scala test_reporter
|
||||
# Suppress warnings from external deps, generated code, and some stylistic warnings
|
||||
# Suppress "unused value" warnings in test code since ScalaTest assertions work via side effects
|
||||
"-Wconf:src=external/rules_scala~/.*:silent,src=external/protobuf~/.*:silent,msg=Flag.*set repeatedly:silent,msg=Compiler synthesis of Manifest:silent,src=.*_scalac/.*:silent,msg=interpolation uses toString:silent,msg=unused value of type org.scalatest:silent,msg=Could not verify that the method argument is transitively initialized:silent,msg=Problematic object instantiation:silent,msg=may cause initialization errors:silent",
|
||||
"-Wconf:src=external/rules_scala.*/.*:silent,src=external/protobuf.*/.*:silent,msg=Flag.*set repeatedly:silent,msg=Compiler synthesis of Manifest:silent,src=.*_scalac/.*:silent,msg=interpolation uses toString:silent,msg=unused value of type org.scalatest:silent,msg=Could not verify that the method argument is transitively initialized:silent,msg=Problematic object instantiation:silent,msg=may cause initialization errors:silent",
|
||||
# Enable all warnings including exhaustive pattern matching checks
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
COPTS = ["--std=c++23", "-Werror", "-Wall", "-Wextra", "-Wdeprecated"]
|
||||
# Suppress -Wdeprecated-copy-with-dtor after -Wdeprecated due to protobuf 32.x warning
|
||||
COPTS = ["--std=c++23", "-Werror", "-Wall", "-Wextra", "-Wdeprecated", "-Wno-deprecated-copy-with-dtor"]
|
||||
|
||||
TEST_COPTS = COPTS + ["-Iexternal/gtest/include"]
|
||||
|
||||
Reference in New Issue
Block a user