mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-29 13:35:42 +00:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7b92ae927 | ||
|
|
23ab715ffc | ||
|
|
73f42d5b51 | ||
|
|
3cb61f69f4 | ||
|
|
62fff3c0ea | ||
|
|
ca86926a25 | ||
|
|
1d334c91ae | ||
|
|
64e1e46e0a | ||
|
|
4722a40384 | ||
|
|
6653a14660 | ||
|
|
056571651e | ||
|
|
d8224e7886 | ||
|
|
9cc9a65e4a | ||
|
|
025563b607 | ||
|
|
030f6b2c2e | ||
|
|
1d5dd7b971 | ||
|
|
649e80c4ac | ||
|
|
a1b4e41553 | ||
|
|
1c24474a0b | ||
|
|
26eec6cabc | ||
|
|
d134f40438 | ||
|
|
a638dd26ca | ||
|
|
5e93b0eaa0 | ||
|
|
6940312d3f | ||
|
|
243f0d43e7 | ||
|
|
1ddd015449 | ||
|
|
da85d0983a |
@@ -112,6 +112,16 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Copy update-env script to server
|
||||
uses: appleboy/scp-action@v0.1.7
|
||||
with:
|
||||
host: ${{ secrets.DO_DROPLET_IP }}
|
||||
username: deploy
|
||||
key: ${{ secrets.DO_SSH_KEY }}
|
||||
source: "deploy/update-env.sh,deploy/env.template"
|
||||
target: /opt/eagle0/
|
||||
strip_components: 1
|
||||
|
||||
- name: Deploy auth service to production
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
@@ -124,36 +134,18 @@ jobs:
|
||||
set -x
|
||||
cd /opt/eagle0
|
||||
|
||||
# Update AUTH_IMAGE in .env file (preserve other vars)
|
||||
if [ -f .env ]; then
|
||||
# Remove old AUTH_IMAGE line and add new one
|
||||
grep -v '^AUTH_IMAGE=' .env > .env.tmp || true
|
||||
echo "AUTH_IMAGE=${AUTH_IMAGE}" >> .env.tmp
|
||||
# Also update OAuth credentials
|
||||
grep -v '^DISCORD_CLIENT_ID=' .env.tmp > .env.tmp2 || true
|
||||
echo "DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID:-}" >> .env.tmp2
|
||||
grep -v '^DISCORD_CLIENT_SECRET=' .env.tmp2 > .env.tmp3 || true
|
||||
echo "DISCORD_CLIENT_SECRET=${DISCORD_CLIENT_SECRET:-}" >> .env.tmp3
|
||||
grep -v '^GOOGLE_CLIENT_ID=' .env.tmp3 > .env.tmp4 || true
|
||||
echo "GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID:-}" >> .env.tmp4
|
||||
grep -v '^GOOGLE_CLIENT_SECRET=' .env.tmp4 > .env.tmp5 || true
|
||||
echo "GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET:-}" >> .env.tmp5
|
||||
# Update JWT private key (JWK format for auth service bootstrap)
|
||||
grep -v '^JWT_PRIVATE_KEY=' .env.tmp5 > .env.tmp6 || true
|
||||
echo "JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY:-}" >> .env.tmp6
|
||||
# Update Fastmail JMAP credentials for email sending
|
||||
grep -v '^FASTMAIL_API_TOKEN=' .env.tmp6 > .env.tmp7 || true
|
||||
echo "FASTMAIL_API_TOKEN=${FASTMAIL_API_TOKEN:-}" >> .env.tmp7
|
||||
grep -v '^FASTMAIL_FROM_EMAIL=' .env.tmp7 > .env.tmp8 || true
|
||||
echo "FASTMAIL_FROM_EMAIL=${FASTMAIL_FROM_EMAIL:-}" >> .env.tmp8
|
||||
grep -v '^FASTMAIL_FROM_NAME=' .env.tmp8 > .env || true
|
||||
echo "FASTMAIL_FROM_NAME=${FASTMAIL_FROM_NAME:-}" >> .env
|
||||
rm -f .env.tmp .env.tmp2 .env.tmp3 .env.tmp4 .env.tmp5 .env.tmp6 .env.tmp7 .env.tmp8
|
||||
chmod 600 .env
|
||||
else
|
||||
echo "ERROR: .env file not found. Run main deploy first."
|
||||
exit 1
|
||||
fi
|
||||
# Update env vars using shared script (preserves vars set by other workflows)
|
||||
chmod +x update-env.sh
|
||||
./update-env.sh \
|
||||
"AUTH_IMAGE=${AUTH_IMAGE}" \
|
||||
"DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID}" \
|
||||
"DISCORD_CLIENT_SECRET=${DISCORD_CLIENT_SECRET}" \
|
||||
"GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}" \
|
||||
"GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}" \
|
||||
"JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY}" \
|
||||
"FASTMAIL_API_TOKEN=${FASTMAIL_API_TOKEN}" \
|
||||
"FASTMAIL_FROM_EMAIL=${FASTMAIL_FROM_EMAIL}" \
|
||||
"FASTMAIL_FROM_NAME=${FASTMAIL_FROM_NAME}"
|
||||
|
||||
# Login to registry
|
||||
echo "${{ secrets.DO_REGISTRY_TOKEN }}" | docker login registry.digitalocean.com -u "${{ secrets.DO_REGISTRY_TOKEN }}" --password-stdin
|
||||
|
||||
@@ -450,6 +450,9 @@ jobs:
|
||||
SHARDOK_ADDRESS: ${{ secrets.SHARDOK_ADDRESS }}
|
||||
SHARDOK_AUTH_TOKEN: ${{ secrets.SHARDOK_AUTH_TOKEN }}
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
FASTMAIL_API_TOKEN: ${{ secrets.FASTMAIL_API_TOKEN }}
|
||||
FASTMAIL_FROM_EMAIL: ${{ secrets.FASTMAIL_FROM_EMAIL }}
|
||||
FASTMAIL_FROM_NAME: ${{ secrets.FASTMAIL_FROM_NAME }}
|
||||
DO_DROPLET_IP: ${{ secrets.DO_DROPLET_IP }}
|
||||
DO_REGISTRY_TOKEN: ${{ secrets.DO_REGISTRY_TOKEN }}
|
||||
steps:
|
||||
@@ -472,12 +475,21 @@ jobs:
|
||||
- name: Copy config files to droplet
|
||||
run: |
|
||||
# Create directory structure on remote
|
||||
ssh -i ~/.ssh/deploy_key deploy@"$DO_DROPLET_IP" "mkdir -p /opt/eagle0/scripts/bin /opt/eagle0/nginx"
|
||||
# Use -p to create parents, and test write access before copying
|
||||
ssh -i ~/.ssh/deploy_key deploy@"$DO_DROPLET_IP" bash -s << 'SETUP_DIRS'
|
||||
set -e
|
||||
mkdir -p /opt/eagle0/scripts/bin /opt/eagle0/nginx /opt/eagle0/deploy
|
||||
|
||||
# Remove existing warmup binary (it may have read-only permissions from bazel)
|
||||
rm -f /opt/eagle0/scripts/bin/warmup
|
||||
SETUP_DIRS
|
||||
|
||||
# Copy files preserving structure
|
||||
scp -i ~/.ssh/deploy_key docker-compose.prod.yml deploy@"$DO_DROPLET_IP":/opt/eagle0/
|
||||
scp -i ~/.ssh/deploy_key nginx/nginx.conf deploy@"$DO_DROPLET_IP":/opt/eagle0/nginx/
|
||||
scp -i ~/.ssh/deploy_key scripts/deploy-blue-green.sh scripts/warmup-eagle.sh deploy@"$DO_DROPLET_IP":/opt/eagle0/scripts/
|
||||
scp -i ~/.ssh/deploy_key scripts/bin/warmup deploy@"$DO_DROPLET_IP":/opt/eagle0/scripts/bin/
|
||||
scp -i ~/.ssh/deploy_key deploy/env.template deploy/update-env.sh deploy@"$DO_DROPLET_IP":/opt/eagle0/deploy/
|
||||
|
||||
- name: Deploy to production droplet
|
||||
run: |
|
||||
@@ -503,6 +515,9 @@ jobs:
|
||||
SHARDOK_ADDRESS="${SHARDOK_ADDRESS}"
|
||||
SHARDOK_AUTH_TOKEN="${SHARDOK_AUTH_TOKEN}"
|
||||
SENTRY_DSN="${SENTRY_DSN}"
|
||||
FASTMAIL_API_TOKEN="${FASTMAIL_API_TOKEN}"
|
||||
FASTMAIL_FROM_EMAIL="${FASTMAIL_FROM_EMAIL}"
|
||||
FASTMAIL_FROM_NAME="${FASTMAIL_FROM_NAME}"
|
||||
DO_REGISTRY_TOKEN="${DO_REGISTRY_TOKEN}"
|
||||
|
||||
# Check Docker has IPv6 support for connecting to Hetzner Shardok
|
||||
@@ -512,35 +527,29 @@ jobs:
|
||||
echo "Run: sudo tee /etc/docker/daemon.json <<< '{\"ipv6\": true, \"ip6tables\": true, \"experimental\": true, \"fixed-cidr-v6\": \"fd00::/80\"}' && sudo systemctl restart docker"
|
||||
fi
|
||||
|
||||
# Write env vars to .env file for docker-compose
|
||||
# Preserve AUTH_IMAGE if it exists (managed by auth_build.yml)
|
||||
EXISTING_AUTH_IMAGE=""
|
||||
if [ -f .env ]; then
|
||||
EXISTING_AUTH_IMAGE=\$(grep '^AUTH_IMAGE=' .env | cut -d= -f2- || true)
|
||||
fi
|
||||
|
||||
rm -f .env 2>/dev/null || true
|
||||
cat > .env << EOF
|
||||
EAGLE_IMAGE=\${EAGLE_IMAGE}
|
||||
SHARDOK_IMAGE=\${SHARDOK_IMAGE}
|
||||
ADMIN_IMAGE=\${ADMIN_IMAGE}
|
||||
JFR_SIDECAR_IMAGE=\${JFR_SIDECAR_IMAGE}
|
||||
AUTH_IMAGE=\${EXISTING_AUTH_IMAGE:-registry.digitalocean.com/eagle0/auth-server:latest}
|
||||
OPENAI_API_KEY=\${OPENAI_API_KEY:-}
|
||||
GPT_MODEL_NAME=\${GPT_MODEL_NAME:-gpt-4o}
|
||||
EAGLE_ENABLE_S3=\${EAGLE_ENABLE_S3:-false}
|
||||
DO_SPACES_ACCESS_KEY=\${DO_SPACES_ACCESS_KEY:-}
|
||||
DO_SPACES_SECRET_KEY=\${DO_SPACES_SECRET_KEY:-}
|
||||
JWT_PRIVATE_KEY=\${JWT_PRIVATE_KEY:-}
|
||||
DISCORD_CLIENT_ID=\${DISCORD_CLIENT_ID:-}
|
||||
DISCORD_CLIENT_SECRET=\${DISCORD_CLIENT_SECRET:-}
|
||||
GOOGLE_CLIENT_ID=\${GOOGLE_CLIENT_ID:-}
|
||||
GOOGLE_CLIENT_SECRET=\${GOOGLE_CLIENT_SECRET:-}
|
||||
SHARDOK_ADDRESS=\${SHARDOK_ADDRESS:-shardok:40042}
|
||||
SHARDOK_AUTH_TOKEN=\${SHARDOK_AUTH_TOKEN:-}
|
||||
SENTRY_DSN=\${SENTRY_DSN:-}
|
||||
EOF
|
||||
chmod 600 .env
|
||||
# Update env vars using shared script (preserves vars set by other workflows)
|
||||
chmod +x update-env.sh
|
||||
./update-env.sh \
|
||||
"EAGLE_IMAGE=\${EAGLE_IMAGE}" \
|
||||
"SHARDOK_IMAGE=\${SHARDOK_IMAGE}" \
|
||||
"ADMIN_IMAGE=\${ADMIN_IMAGE}" \
|
||||
"JFR_SIDECAR_IMAGE=\${JFR_SIDECAR_IMAGE}" \
|
||||
"OPENAI_API_KEY=\${OPENAI_API_KEY}" \
|
||||
"GPT_MODEL_NAME=\${GPT_MODEL_NAME:-gpt-4o}" \
|
||||
"EAGLE_ENABLE_S3=\${EAGLE_ENABLE_S3:-false}" \
|
||||
"DO_SPACES_ACCESS_KEY=\${DO_SPACES_ACCESS_KEY}" \
|
||||
"DO_SPACES_SECRET_KEY=\${DO_SPACES_SECRET_KEY}" \
|
||||
"JWT_PRIVATE_KEY=\${JWT_PRIVATE_KEY}" \
|
||||
"DISCORD_CLIENT_ID=\${DISCORD_CLIENT_ID}" \
|
||||
"DISCORD_CLIENT_SECRET=\${DISCORD_CLIENT_SECRET}" \
|
||||
"GOOGLE_CLIENT_ID=\${GOOGLE_CLIENT_ID}" \
|
||||
"GOOGLE_CLIENT_SECRET=\${GOOGLE_CLIENT_SECRET}" \
|
||||
"SHARDOK_ADDRESS=\${SHARDOK_ADDRESS:-shardok:40042}" \
|
||||
"SHARDOK_AUTH_TOKEN=\${SHARDOK_AUTH_TOKEN}" \
|
||||
"SENTRY_DSN=\${SENTRY_DSN}" \
|
||||
"FASTMAIL_API_TOKEN=\${FASTMAIL_API_TOKEN}" \
|
||||
"FASTMAIL_FROM_EMAIL=\${FASTMAIL_FROM_EMAIL}" \
|
||||
"FASTMAIL_FROM_NAME=\${FASTMAIL_FROM_NAME}"
|
||||
|
||||
# Login to registry
|
||||
echo "\$DO_REGISTRY_TOKEN" | docker login registry.digitalocean.com -u "\$DO_REGISTRY_TOKEN" --password-stdin
|
||||
@@ -552,8 +561,16 @@ jobs:
|
||||
# Use crane to pull images (handles OCI format correctly) then load into Docker
|
||||
# This avoids digest mismatch from DO registry's OCI->Docker format conversion
|
||||
echo "Installing crane..."
|
||||
rm -f crane
|
||||
curl -sL https://github.com/google/go-containerregistry/releases/download/v0.20.2/go-containerregistry_Linux_x86_64.tar.gz | tar xzf - crane
|
||||
chmod +x crane
|
||||
if [ ! -x crane ]; then
|
||||
echo "ERROR: Failed to install crane"
|
||||
ls -la crane || true
|
||||
exit 1
|
||||
fi
|
||||
echo "Crane installed"
|
||||
ls -la crane
|
||||
|
||||
# crane uses Docker config for auth
|
||||
echo "Pulling Eagle image with crane..."
|
||||
@@ -580,7 +597,8 @@ jobs:
|
||||
docker load -i jfr-sidecar.tar
|
||||
rm jfr-sidecar.tar
|
||||
|
||||
rm ./crane
|
||||
# Keep crane for blue-green deploys (don't delete it)
|
||||
echo "Crane kept at ./crane for future blue-green deploys"
|
||||
|
||||
# Also pull other compose images
|
||||
docker pull nginx:alpine || true
|
||||
@@ -620,9 +638,6 @@ jobs:
|
||||
# (nginx caches DNS at startup, so it needs restart after eagle/shardok)
|
||||
docker compose -f docker-compose.prod.yml up -d --force-recreate nginx
|
||||
|
||||
# Cleanup orphaned containers
|
||||
docker compose -f docker-compose.prod.yml up -d --remove-orphans
|
||||
|
||||
# Wait for health checks
|
||||
sleep 10
|
||||
docker compose -f docker-compose.prod.yml ps
|
||||
@@ -631,6 +646,7 @@ jobs:
|
||||
echo "=== Verifying container image tags ==="
|
||||
docker compose -f docker-compose.prod.yml images
|
||||
|
||||
# Cleanup old images
|
||||
# Cleanup stopped containers and old images
|
||||
docker container prune -f
|
||||
docker image prune -f
|
||||
DEPLOY_SCRIPT
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
name: Mac Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- ".github/workflows/mac_build.yml"
|
||||
- "src/main/csharp/net/eagle0/clients/unity/**"
|
||||
- "src/main/proto/**"
|
||||
- "scripts/build_protos.sh"
|
||||
- "scripts/build_mac_plugin.sh"
|
||||
- "scripts/inject_sparkle.sh"
|
||||
- "scripts/codesign_mac_app.sh"
|
||||
- "scripts/notarize_mac_app.sh"
|
||||
- "ci/github_actions/build_mac.sh"
|
||||
- "ci/github_actions/build_unity_mac.sh"
|
||||
- "ci/mac/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/mac_build.yml"
|
||||
- "src/main/csharp/net/eagle0/clients/unity/**"
|
||||
- "scripts/build_mac_plugin.sh"
|
||||
- "scripts/inject_sparkle.sh"
|
||||
- "scripts/codesign_mac_app.sh"
|
||||
- "scripts/notarize_mac_app.sh"
|
||||
- "ci/github_actions/build_mac.sh"
|
||||
- "ci/github_actions/build_unity_mac.sh"
|
||||
- "ci/mac/**"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
skip_notarization:
|
||||
description: 'Skip notarization (for testing)'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: boolean
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
mac-unity:
|
||||
runs-on: self-hosted
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
lfs: true
|
||||
clean: false
|
||||
fetch-depth: 0 # For version numbering from git history
|
||||
|
||||
- name: Pull LFS files
|
||||
run: git lfs pull
|
||||
|
||||
- name: Restore Library/
|
||||
run: ./ci/github_actions/restore_library.sh
|
||||
|
||||
- name: Build Mac Unity
|
||||
run: ./ci/github_actions/build_unity_mac.sh "/tmp/eagle0/eagle0MAC"
|
||||
|
||||
- name: Persist Library/
|
||||
run: ./ci/github_actions/persist_library.sh
|
||||
|
||||
- name: Inject Sparkle Framework
|
||||
if: success()
|
||||
env:
|
||||
SPARKLE_EDDSA_PUBLIC_KEY: ${{ secrets.SPARKLE_EDDSA_PUBLIC_KEY }}
|
||||
run: |
|
||||
chmod +x ./scripts/inject_sparkle.sh
|
||||
./scripts/inject_sparkle.sh "/tmp/eagle0/eagle0MAC/eagle0.app"
|
||||
|
||||
- name: Import Code Signing Certificate
|
||||
if: success() && github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||
env:
|
||||
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
|
||||
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
|
||||
run: |
|
||||
# Generate random keychain password (only used within this workflow run)
|
||||
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
|
||||
echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> $GITHUB_ENV
|
||||
|
||||
# Decode certificate
|
||||
echo "$MACOS_CERTIFICATE" | base64 --decode > certificate.p12
|
||||
|
||||
# Create temporary keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain || true
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
# Import certificate
|
||||
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
|
||||
|
||||
# Allow codesign to access keychain
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
# Clean up
|
||||
rm certificate.p12
|
||||
|
||||
- name: Code Sign App
|
||||
if: success() && github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||
env:
|
||||
SIGNING_IDENTITY: ${{ secrets.SIGNING_IDENTITY }}
|
||||
run: |
|
||||
chmod +x ./scripts/codesign_mac_app.sh
|
||||
./scripts/codesign_mac_app.sh "/tmp/eagle0/eagle0MAC/eagle0.app" "ci/mac/eagle0.entitlements"
|
||||
|
||||
- name: Notarize App
|
||||
if: success() && github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.event.inputs.skip_notarization != 'true'
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APP_SPECIFIC_PASSWORD: ${{ secrets.APP_SPECIFIC_PASSWORD }}
|
||||
TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
run: |
|
||||
chmod +x ./scripts/notarize_mac_app.sh
|
||||
./scripts/notarize_mac_app.sh "/tmp/eagle0/eagle0MAC/eagle0.app"
|
||||
|
||||
- name: Deploy Mac Build
|
||||
if: success() && github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||
env:
|
||||
ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY_ID }}
|
||||
SECRET_KEY: ${{ secrets.SECRET_KEY }}
|
||||
SPARKLE_EDDSA_PRIVATE_KEY: ${{ secrets.SPARKLE_EDDSA_PRIVATE_KEY }}
|
||||
run: |
|
||||
# Write private key to temp file for signing
|
||||
SPARKLE_PRIVATE_KEY_PATH="/tmp/sparkle_private_key"
|
||||
echo "$SPARKLE_EDDSA_PRIVATE_KEY" > "$SPARKLE_PRIVATE_KEY_PATH"
|
||||
chmod 600 "$SPARKLE_PRIVATE_KEY_PATH"
|
||||
|
||||
VERSION=$(git describe --tags --always)
|
||||
BUILD_NUMBER=$(git rev-list --count HEAD)
|
||||
|
||||
bazel run //src/main/go/net/eagle0/build/mac_build_handler:mac_build_handler -- \
|
||||
"/tmp/eagle0/eagle0MAC/eagle0.app" \
|
||||
"$VERSION" \
|
||||
"$BUILD_NUMBER" \
|
||||
"$SPARKLE_PRIVATE_KEY_PATH"
|
||||
|
||||
rm "$SPARKLE_PRIVATE_KEY_PATH"
|
||||
|
||||
- name: Cleanup Keychain
|
||||
if: always()
|
||||
run: |
|
||||
security delete-keychain build.keychain 2>/dev/null || true
|
||||
|
||||
- name: Archive Build Log
|
||||
if: success() || failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: editor_mac.log
|
||||
path: /tmp/eagle0/editor_mac.log
|
||||
@@ -1,5 +1,19 @@
|
||||
# CLAUDE.md
|
||||
|
||||
## CRITICAL GIT RULES (NEVER VIOLATE)
|
||||
|
||||
**NEVER push directly to main/master.** No exceptions. Not for "small changes." Not for docs. Not ever.
|
||||
|
||||
**ALWAYS use this workflow:**
|
||||
1. Create a feature branch from origin/main
|
||||
2. Commit to that branch
|
||||
3. Create a PR with `gh pr create`
|
||||
4. Wait for user to merge
|
||||
|
||||
If you catch yourself about to run `git push origin main` or `git push origin <branch>:main`, STOP. You are about to violate a critical rule. Create a PR instead.
|
||||
|
||||
---
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
+12
-5
@@ -127,8 +127,8 @@ use_repo(
|
||||
#
|
||||
|
||||
bazel_dep(name = "apple_support", version = "1.21.1", repo_name = "build_bazel_apple_support")
|
||||
bazel_dep(name = "rules_apple", version = "3.16.1", repo_name = "build_bazel_rules_apple")
|
||||
bazel_dep(name = "rules_swift", version = "2.3.1", repo_name = "build_bazel_rules_swift")
|
||||
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")
|
||||
|
||||
#
|
||||
# Protocol Buffers & RPC
|
||||
@@ -294,11 +294,15 @@ http_archive(
|
||||
)
|
||||
|
||||
# Busybox static binary for Docker health checks (provides nc, wget, etc.)
|
||||
# https://busybox.net/downloads/binaries/
|
||||
# Primary: GitHub release mirror (reliable)
|
||||
# Fallback: busybox.net (can be unreliable/slow)
|
||||
http_file(
|
||||
name = "busybox_x86_64",
|
||||
sha256 = "6e123e7f3202a8c1e9b1f94d8941580a25135382b99e8d3e34fb858bba311348",
|
||||
urls = ["https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox"],
|
||||
urls = [
|
||||
"https://github.com/nolen777/eagle0/releases/download/busybox-1.35.0/busybox-1.35.0-x86_64-linux-musl",
|
||||
"https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox",
|
||||
],
|
||||
downloaded_file_path = "busybox",
|
||||
executable = True,
|
||||
)
|
||||
@@ -306,7 +310,10 @@ http_file(
|
||||
http_file(
|
||||
name = "busybox_aarch64",
|
||||
sha256 = "141adb1b625a6f44c4b114f76b4387b4ea4f7ab802b88eb40e0d2f6adcccb1c3",
|
||||
urls = ["https://busybox.net/downloads/binaries/1.35.0-aarch64-linux-musl/busybox"],
|
||||
urls = [
|
||||
# TODO: Upload aarch64 binary to GitHub release when needed
|
||||
"https://busybox.net/downloads/binaries/1.35.0-aarch64-linux-musl/busybox",
|
||||
],
|
||||
downloaded_file_path = "busybox",
|
||||
executable = True,
|
||||
)
|
||||
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
. ./ci/unity_version.sh
|
||||
|
||||
WORKSPACE=$(pwd)
|
||||
UNITY_INSTALL_PATH="/Applications/Unity/Hub/Editor"
|
||||
BUILD_DIR=$1
|
||||
LOG_PATH=$2
|
||||
|
||||
echo "Building Mac in $BUILD_DIR"
|
||||
|
||||
echo "Cleaning up $BUILD_DIR"
|
||||
/bin/rm -rf "$BUILD_DIR"
|
||||
/bin/mkdir -p "$BUILD_DIR"
|
||||
|
||||
${UNITY_INSTALL_PATH}/${UNITY_VERSION}/Unity.app/Contents/MacOS/Unity \
|
||||
-nographics \
|
||||
-batchmode \
|
||||
-quit \
|
||||
-buildOSXUniversalPlayer "$BUILD_DIR/eagle0.app" \
|
||||
-logFile "$LOG_PATH" \
|
||||
-projectPath "$WORKSPACE/src/main/csharp/net/eagle0/clients/unity/eagle0"
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
COMMIT=$(/usr/bin/git rev-parse --short HEAD)
|
||||
|
||||
/bin/echo "build protos"
|
||||
./scripts/build_protos.sh
|
||||
|
||||
/bin/echo "build Mac plugin"
|
||||
./scripts/build_mac_plugin.sh
|
||||
|
||||
git log -3
|
||||
|
||||
/bin/echo "build Mac"
|
||||
LOG_PATH="/tmp/eagle0/editor_mac.log"
|
||||
BUILD_DIR=$1
|
||||
|
||||
./ci/github_actions/build_mac.sh "$BUILD_DIR" "$LOG_PATH"
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- Allow JIT compilation (required for Mono/IL2CPP) -->
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<!-- Allow unsigned executable memory (required for Unity) -->
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<!-- Disable library validation (required for plugins) -->
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<!-- Allow outgoing network connections -->
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,40 @@
|
||||
# Environment template for production deployment
|
||||
# This file defines all env vars used by docker-compose.prod.yml
|
||||
# Workflows should update their specific vars without overwriting others
|
||||
|
||||
# Container images (managed by respective build workflows)
|
||||
EAGLE_IMAGE=registry.digitalocean.com/eagle0/eagle-server:latest
|
||||
SHARDOK_IMAGE=registry.digitalocean.com/eagle0/shardok-server:latest
|
||||
ADMIN_IMAGE=registry.digitalocean.com/eagle0/admin-server:latest
|
||||
JFR_SIDECAR_IMAGE=registry.digitalocean.com/eagle0/jfr-sidecar:latest
|
||||
AUTH_IMAGE=registry.digitalocean.com/eagle0/auth-server:latest
|
||||
|
||||
# OpenAI / LLM
|
||||
OPENAI_API_KEY=
|
||||
GPT_MODEL_NAME=gpt-4o
|
||||
|
||||
# DigitalOcean Spaces (S3-compatible storage)
|
||||
EAGLE_ENABLE_S3=false
|
||||
DO_SPACES_ACCESS_KEY=
|
||||
DO_SPACES_SECRET_KEY=
|
||||
|
||||
# JWT authentication
|
||||
JWT_PRIVATE_KEY=
|
||||
|
||||
# OAuth providers
|
||||
DISCORD_CLIENT_ID=
|
||||
DISCORD_CLIENT_SECRET=
|
||||
GOOGLE_CLIENT_ID=
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
|
||||
# Shardok connection
|
||||
SHARDOK_ADDRESS=shardok:40042
|
||||
SHARDOK_AUTH_TOKEN=
|
||||
|
||||
# Monitoring
|
||||
SENTRY_DSN=
|
||||
|
||||
# Email (Fastmail JMAP)
|
||||
FASTMAIL_API_TOKEN=
|
||||
FASTMAIL_FROM_EMAIL=
|
||||
FASTMAIL_FROM_NAME=
|
||||
@@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
# Update .env file without losing other variables
|
||||
# Usage: ./update-env.sh KEY1=value1 KEY2=value2 ...
|
||||
#
|
||||
# This script:
|
||||
# 1. Creates .env from template if it doesn't exist
|
||||
# 2. Updates only the specified KEY=value pairs
|
||||
# 3. Preserves all other existing values
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ENV_FILE="${ENV_FILE:-/opt/eagle0/.env}"
|
||||
TEMPLATE_FILE="${TEMPLATE_FILE:-$SCRIPT_DIR/env.template}"
|
||||
|
||||
# Create .env from template if it doesn't exist
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
if [ -f "$TEMPLATE_FILE" ]; then
|
||||
echo "Creating .env from template..."
|
||||
grep -v '^#' "$TEMPLATE_FILE" | grep -v '^$' > "$ENV_FILE"
|
||||
else
|
||||
echo "Creating empty .env..."
|
||||
touch "$ENV_FILE"
|
||||
fi
|
||||
chmod 600 "$ENV_FILE"
|
||||
fi
|
||||
|
||||
# Process each KEY=VALUE argument
|
||||
for arg in "$@"; do
|
||||
# Skip empty args
|
||||
[ -z "$arg" ] && continue
|
||||
|
||||
# Parse KEY=VALUE
|
||||
KEY="${arg%%=*}"
|
||||
VALUE="${arg#*=}"
|
||||
|
||||
# Skip if no key
|
||||
[ -z "$KEY" ] && continue
|
||||
|
||||
# Skip setting empty values (keeps existing value)
|
||||
if [ -z "$VALUE" ]; then
|
||||
echo "Skipping $KEY (empty value)"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Remove existing line for this key and add new one
|
||||
if grep -q "^${KEY}=" "$ENV_FILE" 2>/dev/null; then
|
||||
# Key exists, update it
|
||||
sed -i "s|^${KEY}=.*|${KEY}=${VALUE}|" "$ENV_FILE"
|
||||
echo "Updated $KEY"
|
||||
else
|
||||
# Key doesn't exist, add it
|
||||
echo "${KEY}=${VALUE}" >> "$ENV_FILE"
|
||||
echo "Added $KEY"
|
||||
fi
|
||||
done
|
||||
|
||||
chmod 600 "$ENV_FILE"
|
||||
echo "Done updating $ENV_FILE"
|
||||
@@ -108,6 +108,13 @@ http {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# Invitation landing page (proxied to Go auth service)
|
||||
location /invite/ {
|
||||
proxy_pass http://auth:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# Health check endpoint
|
||||
location /health {
|
||||
access_log off;
|
||||
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Code sign a macOS .app bundle for distribution
|
||||
# Usage: codesign_mac_app.sh <app_path> [entitlements_path]
|
||||
#
|
||||
# Environment variables:
|
||||
# SIGNING_IDENTITY - The signing identity (default: "Developer ID Application")
|
||||
# KEYCHAIN_PASSWORD - Password to unlock the build keychain (optional)
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
APP_PATH="$1"
|
||||
ENTITLEMENTS_PATH="${2:-}"
|
||||
SIGNING_IDENTITY="${SIGNING_IDENTITY:-Developer ID Application}"
|
||||
|
||||
if [ ! -d "$APP_PATH" ]; then
|
||||
echo "ERROR: App not found at $APP_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Unlock keychain if password provided
|
||||
if [ -n "${KEYCHAIN_PASSWORD:-}" ]; then
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain || true
|
||||
fi
|
||||
|
||||
echo "=== Signing nested components first ==="
|
||||
|
||||
# Sign all dylibs
|
||||
find "$APP_PATH" -name "*.dylib" -print0 | while IFS= read -r -d '' item; do
|
||||
echo "Signing dylib: $item"
|
||||
codesign --force --verify --verbose --timestamp --options runtime \
|
||||
--sign "$SIGNING_IDENTITY" "$item"
|
||||
done
|
||||
|
||||
# Sign all bundles (plugins)
|
||||
find "$APP_PATH" -name "*.bundle" -print0 | while IFS= read -r -d '' item; do
|
||||
echo "Signing bundle: $item"
|
||||
codesign --force --verify --verbose --timestamp --options runtime \
|
||||
--sign "$SIGNING_IDENTITY" "$item"
|
||||
done
|
||||
|
||||
# Sign XPC services (inside Sparkle framework)
|
||||
find "$APP_PATH" -name "*.xpc" -print0 | while IFS= read -r -d '' item; do
|
||||
echo "Signing XPC service: $item"
|
||||
codesign --force --verify --verbose --timestamp --options runtime \
|
||||
--sign "$SIGNING_IDENTITY" "$item"
|
||||
done
|
||||
|
||||
# Sign nested apps (like Sparkle's Updater.app)
|
||||
find "$APP_PATH" -path "*/Frameworks/*.app" -print0 | while IFS= read -r -d '' item; do
|
||||
echo "Signing nested app: $item"
|
||||
codesign --force --verify --verbose --timestamp --options runtime \
|
||||
--sign "$SIGNING_IDENTITY" "$item"
|
||||
done
|
||||
|
||||
# Sign standalone executables inside frameworks (like Autoupdate)
|
||||
find "$APP_PATH" -path "*/Frameworks/*/Versions/*/Autoupdate" -type f -print0 | while IFS= read -r -d '' item; do
|
||||
echo "Signing executable: $item"
|
||||
codesign --force --verify --verbose --timestamp --options runtime \
|
||||
--sign "$SIGNING_IDENTITY" "$item"
|
||||
done
|
||||
|
||||
# Sign all frameworks (after their contents are signed)
|
||||
find "$APP_PATH" -name "*.framework" -print0 | while IFS= read -r -d '' item; do
|
||||
echo "Signing framework: $item"
|
||||
codesign --force --verify --verbose --timestamp --options runtime \
|
||||
--sign "$SIGNING_IDENTITY" "$item"
|
||||
done
|
||||
|
||||
echo "=== Signing main app bundle ==="
|
||||
|
||||
if [ -n "$ENTITLEMENTS_PATH" ] && [ -f "$ENTITLEMENTS_PATH" ]; then
|
||||
echo "Using entitlements: $ENTITLEMENTS_PATH"
|
||||
codesign --force --verify --verbose --timestamp --options runtime \
|
||||
--entitlements "$ENTITLEMENTS_PATH" \
|
||||
--sign "$SIGNING_IDENTITY" "$APP_PATH"
|
||||
else
|
||||
codesign --force --verify --verbose --timestamp --options runtime \
|
||||
--sign "$SIGNING_IDENTITY" "$APP_PATH"
|
||||
fi
|
||||
|
||||
echo "=== Verifying signature ==="
|
||||
codesign --verify --verbose=4 "$APP_PATH"
|
||||
|
||||
echo "=== Checking Gatekeeper assessment ==="
|
||||
spctl --assess --type exec -v "$APP_PATH" || echo "Note: Gatekeeper may reject until notarized"
|
||||
|
||||
echo "Code signing complete: $APP_PATH"
|
||||
@@ -48,6 +48,44 @@ get_active_instance() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Pull image with retry using crane (handles OCI/Docker digest mismatch)
|
||||
pull_with_retry() {
|
||||
local image=$1
|
||||
local max_attempts=${2:-3}
|
||||
local attempt=1
|
||||
|
||||
# Use crane if available (handles OCI format correctly)
|
||||
if [ -x "${APP_DIR}/crane" ]; then
|
||||
while [ $attempt -le $max_attempts ]; do
|
||||
log_info "Pulling image with crane (attempt ${attempt}/${max_attempts})..."
|
||||
if "${APP_DIR}/crane" pull "${image}" /tmp/image.tar && docker load -i /tmp/image.tar; then
|
||||
rm -f /tmp/image.tar
|
||||
log_info "Image pulled and loaded successfully"
|
||||
return 0
|
||||
fi
|
||||
rm -f /tmp/image.tar
|
||||
log_warn "Pull failed, retrying in 5 seconds..."
|
||||
sleep 5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
else
|
||||
# Fallback to docker pull if crane not available
|
||||
log_warn "crane not found at ${APP_DIR}/crane, falling back to docker pull"
|
||||
while [ $attempt -le $max_attempts ]; do
|
||||
log_info "Pulling image (attempt ${attempt}/${max_attempts})..."
|
||||
if docker pull "${image}"; then
|
||||
log_info "Image pulled successfully"
|
||||
return 0
|
||||
fi
|
||||
log_warn "Pull failed, retrying in 5 seconds..."
|
||||
sleep 5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
fi
|
||||
log_error "Failed to pull image after ${max_attempts} attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Wait for a container to be healthy
|
||||
wait_for_healthy() {
|
||||
local container=$1
|
||||
@@ -93,9 +131,11 @@ main() {
|
||||
log_info "Active instance: eagle-${active}"
|
||||
log_info "Staging instance: eagle-${staging}"
|
||||
|
||||
# Pull the new image
|
||||
log_info "Pulling new image..."
|
||||
docker pull "${new_image}"
|
||||
# Pull the new image (with retry for intermittent registry issues)
|
||||
if ! pull_with_retry "${new_image}" 3; then
|
||||
log_error "Failed to pull new image, aborting deployment"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start staging instance with new image
|
||||
log_info "Starting eagle-${staging} with new image..."
|
||||
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Inject Sparkle framework into a macOS .app bundle for auto-updates
|
||||
# Usage: inject_sparkle.sh <app_path>
|
||||
#
|
||||
# Environment variables (required):
|
||||
# SPARKLE_EDDSA_PUBLIC_KEY - EdDSA public key for verifying updates
|
||||
#
|
||||
# Optional environment variables:
|
||||
# SPARKLE_FEED_URL - Appcast URL (default: https://assets.eagle0.net/mac/appcast.xml)
|
||||
# SPARKLE_VERSION - Sparkle version to use (default: 2.6.4)
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
APP_PATH="$1"
|
||||
SPARKLE_VERSION="${SPARKLE_VERSION:-2.6.4}"
|
||||
SPARKLE_FEED_URL="${SPARKLE_FEED_URL:-https://assets.eagle0.net/mac/appcast.xml}"
|
||||
SPARKLE_CACHE_DIR="/tmp/sparkle-cache"
|
||||
|
||||
if [ ! -d "$APP_PATH" ]; then
|
||||
echo "ERROR: App not found at $APP_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${SPARKLE_EDDSA_PUBLIC_KEY:-}" ]; then
|
||||
echo "ERROR: SPARKLE_EDDSA_PUBLIC_KEY environment variable not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Download Sparkle if not cached
|
||||
SPARKLE_DIR="$SPARKLE_CACHE_DIR/Sparkle-$SPARKLE_VERSION"
|
||||
if [ ! -d "$SPARKLE_DIR/Sparkle.framework" ]; then
|
||||
echo "=== Downloading Sparkle $SPARKLE_VERSION ==="
|
||||
mkdir -p "$SPARKLE_CACHE_DIR"
|
||||
SPARKLE_URL="https://github.com/sparkle-project/Sparkle/releases/download/${SPARKLE_VERSION}/Sparkle-${SPARKLE_VERSION}.tar.xz"
|
||||
curl -L "$SPARKLE_URL" | tar -xJ -C "$SPARKLE_CACHE_DIR"
|
||||
mv "$SPARKLE_CACHE_DIR/Sparkle-$SPARKLE_VERSION" "$SPARKLE_DIR" 2>/dev/null || true
|
||||
# If the extracted directory doesn't match version pattern, it may just be "Sparkle"
|
||||
if [ ! -d "$SPARKLE_DIR" ]; then
|
||||
mkdir -p "$SPARKLE_DIR"
|
||||
mv "$SPARKLE_CACHE_DIR/Sparkle.framework" "$SPARKLE_DIR/" 2>/dev/null || true
|
||||
mv "$SPARKLE_CACHE_DIR/bin" "$SPARKLE_DIR/" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "=== Injecting Sparkle framework ==="
|
||||
FRAMEWORKS_DIR="$APP_PATH/Contents/Frameworks"
|
||||
mkdir -p "$FRAMEWORKS_DIR"
|
||||
|
||||
# Copy Sparkle framework
|
||||
cp -R "$SPARKLE_DIR/Sparkle.framework" "$FRAMEWORKS_DIR/"
|
||||
|
||||
# Also copy the XPC services if present
|
||||
if [ -d "$SPARKLE_DIR/Sparkle.framework/Versions/B/XPCServices" ]; then
|
||||
echo "Sparkle XPC services present"
|
||||
fi
|
||||
|
||||
echo "=== Updating Info.plist ==="
|
||||
PLIST_PATH="$APP_PATH/Contents/Info.plist"
|
||||
|
||||
# Add Sparkle configuration to Info.plist
|
||||
/usr/libexec/PlistBuddy -c "Delete :SUFeedURL" "$PLIST_PATH" 2>/dev/null || true
|
||||
/usr/libexec/PlistBuddy -c "Add :SUFeedURL string '$SPARKLE_FEED_URL'" "$PLIST_PATH"
|
||||
|
||||
/usr/libexec/PlistBuddy -c "Delete :SUPublicEDKey" "$PLIST_PATH" 2>/dev/null || true
|
||||
/usr/libexec/PlistBuddy -c "Add :SUPublicEDKey string '$SPARKLE_EDDSA_PUBLIC_KEY'" "$PLIST_PATH"
|
||||
|
||||
/usr/libexec/PlistBuddy -c "Delete :SUEnableAutomaticChecks" "$PLIST_PATH" 2>/dev/null || true
|
||||
/usr/libexec/PlistBuddy -c "Add :SUEnableAutomaticChecks bool true" "$PLIST_PATH"
|
||||
|
||||
# Set bundle version from git for Sparkle version comparison
|
||||
VERSION=$(git describe --tags --always 2>/dev/null || echo "1.0.0")
|
||||
BUILD_NUMBER=$(git rev-list --count HEAD 2>/dev/null || echo "1")
|
||||
|
||||
echo "Setting version: $VERSION (build $BUILD_NUMBER)"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" "$PLIST_PATH" 2>/dev/null || \
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string '$VERSION'" "$PLIST_PATH"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" "$PLIST_PATH" 2>/dev/null || \
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleVersion string '$BUILD_NUMBER'" "$PLIST_PATH"
|
||||
|
||||
# Add URL scheme for invitation codes (eagle0://invite?code=XXXX)
|
||||
echo "=== Adding URL scheme for invitation codes ==="
|
||||
/usr/libexec/PlistBuddy -c "Delete :CFBundleURLTypes" "$PLIST_PATH" 2>/dev/null || true
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes array" "$PLIST_PATH"
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:0 dict" "$PLIST_PATH"
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:0:CFBundleURLName string 'com.Shardok-Games.eagle0'" "$PLIST_PATH"
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes array" "$PLIST_PATH"
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes:0 string 'eagle0'" "$PLIST_PATH"
|
||||
|
||||
echo "=== Sparkle injection complete ==="
|
||||
echo "App: $APP_PATH"
|
||||
echo "Feed URL: $SPARKLE_FEED_URL"
|
||||
echo "Version: $VERSION (build $BUILD_NUMBER)"
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Notarize a macOS .app bundle with Apple
|
||||
# Usage: notarize_mac_app.sh <app_path>
|
||||
#
|
||||
# Environment variables (required):
|
||||
# APPLE_ID - Apple Developer account email
|
||||
# APP_SPECIFIC_PASSWORD - App-specific password for notarytool
|
||||
# TEAM_ID - Apple Developer Team ID
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
APP_PATH="$1"
|
||||
|
||||
if [ ! -d "$APP_PATH" ]; then
|
||||
echo "ERROR: App not found at $APP_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${APPLE_ID:-}" ] || [ -z "${APP_SPECIFIC_PASSWORD:-}" ] || [ -z "${TEAM_ID:-}" ]; then
|
||||
echo "ERROR: Required environment variables not set"
|
||||
echo " APPLE_ID: ${APPLE_ID:-<not set>}"
|
||||
echo " APP_SPECIFIC_PASSWORD: ${APP_SPECIFIC_PASSWORD:+<set>}"
|
||||
echo " TEAM_ID: ${TEAM_ID:-<not set>}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create ZIP for notarization submission
|
||||
ZIP_PATH="${APP_PATH%.app}.zip"
|
||||
echo "=== Creating ZIP for notarization: $ZIP_PATH ==="
|
||||
ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
|
||||
|
||||
echo "=== Submitting to Apple for notarization ==="
|
||||
xcrun notarytool submit "$ZIP_PATH" \
|
||||
--apple-id "$APPLE_ID" \
|
||||
--password "$APP_SPECIFIC_PASSWORD" \
|
||||
--team-id "$TEAM_ID" \
|
||||
--wait
|
||||
|
||||
# Clean up the zip
|
||||
rm "$ZIP_PATH"
|
||||
|
||||
echo "=== Stapling notarization ticket to app ==="
|
||||
xcrun stapler staple "$APP_PATH"
|
||||
|
||||
echo "=== Verifying notarization ==="
|
||||
xcrun stapler validate "$APP_PATH"
|
||||
spctl --assess --type exec -v "$APP_PATH"
|
||||
|
||||
echo "Notarization complete: $APP_PATH"
|
||||
@@ -107,6 +107,23 @@ auto AIAttackerStrategySelector::BestAttackerStrategy(
|
||||
alCache,
|
||||
battalionTypeGetter,
|
||||
braveWaterCost));
|
||||
} else if (!defenderPositions.empty()) {
|
||||
// Defenders exist but none are on castles - they're scattering/fleeing.
|
||||
// Chase them down rather than holding empty castles, since eliminating
|
||||
// all defenders also wins the battle via LAST_PLAYER_STANDING.
|
||||
chosenStrategy = AttackUnitsStrategy(GenerateTargetPriorities(
|
||||
Occupants(
|
||||
*gameState->units(),
|
||||
gameState->hex_map()->row_count(),
|
||||
gameState->hex_map()->column_count()),
|
||||
gameState->hex_map(),
|
||||
defenderPositions,
|
||||
attackerPid,
|
||||
attackerUnits,
|
||||
apdCache,
|
||||
alCache,
|
||||
battalionTypeGetter,
|
||||
braveWaterCost));
|
||||
} else {
|
||||
chosenStrategy = HoldCastlesStrategy;
|
||||
}
|
||||
|
||||
+6
-1
@@ -122,8 +122,13 @@ namespace Auth {
|
||||
string localAppData =
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
return Path.Combine(localAppData, "eagle0");
|
||||
#elif UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
|
||||
// Mac: ~/Library/Application Support/eagle0
|
||||
string appSupport =
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
return Path.Combine(appSupport, "eagle0");
|
||||
#else
|
||||
// Other platforms don't use the Windows installer
|
||||
// Other platforms not yet supported
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2992,6 +2992,88 @@ MonoBehaviour:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_IsOn: 1
|
||||
--- !u!1 &16227905
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 16227909}
|
||||
- component: {fileID: 16227908}
|
||||
- component: {fileID: 16227907}
|
||||
- component: {fileID: 16227906}
|
||||
m_Layer: 0
|
||||
m_Name: TutorialManager
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &16227906
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 16227905}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 370b3269832442e196d1b432bdae2f1e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Eagle0.Tutorial.TutorialTestSetup
|
||||
EnableTestTutorials: 1
|
||||
ResetProgressOnStart: 0
|
||||
--- !u!114 &16227907
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 16227905}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 52abae862492497cb7a3f8c72f837b37, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Eagle0.Tutorial.TutorialUIManager
|
||||
ModalPanel: {fileID: 0}
|
||||
OverlayController: {fileID: 0}
|
||||
HintIndicatorPrefab: {fileID: 0}
|
||||
TutorialCanvas: {fileID: 0}
|
||||
UseFallbackUI: 1
|
||||
FallbackFont: {fileID: 12800000, guid: f0f6814ff8ef048bcbfd5002f77188ea, type: 3}
|
||||
--- !u!114 &16227908
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 16227905}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c529affa73b04d129ec5826ed0ac75e7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Eagle0.Tutorial.TutorialManager
|
||||
TutorialsEnabled: 1
|
||||
OnboardingSequence: {fileID: 0}
|
||||
UIManager: {fileID: 16227907}
|
||||
DebugLogging: 0
|
||||
--- !u!4 &16227909
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 16227905}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 2560, y: 1440, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &17277548
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -8532,10 +8614,10 @@ RectTransform:
|
||||
- {fileID: 1396438488}
|
||||
m_Father: {fileID: 2130578398}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 333.5, y: -11.255}
|
||||
m_SizeDelta: {x: 200, y: 20}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &75920627
|
||||
MonoBehaviour:
|
||||
@@ -10927,10 +11009,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 2130578398}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 218.5, y: -11.255}
|
||||
m_SizeDelta: {x: 20, y: 20}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &103511974
|
||||
MonoBehaviour:
|
||||
@@ -12298,10 +12380,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 683322975}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 306.5, y: -40}
|
||||
m_SizeDelta: {x: 51, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &114306270
|
||||
MonoBehaviour:
|
||||
@@ -15614,6 +15696,10 @@ MonoBehaviour:
|
||||
displayNameField: {fileID: 1956057658}
|
||||
setDisplayNameButton: {fileID: 700483942}
|
||||
displayNameErrorText: {fileID: 77360322}
|
||||
invitationCodePanel: {fileID: 0}
|
||||
invitationCodeField: {fileID: 0}
|
||||
submitInvitationCodeButton: {fileID: 0}
|
||||
invitationCodeErrorText: {fileID: 0}
|
||||
connectionStatusText: {fileID: 77360322}
|
||||
connectionPanel: {fileID: 596196018}
|
||||
gameSelectionPanel: {fileID: 1102342355}
|
||||
@@ -20624,10 +20710,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 256, y: -32.504997}
|
||||
m_SizeDelta: {x: 492, y: 45.01}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &171635196
|
||||
MonoBehaviour:
|
||||
@@ -29397,7 +29483,7 @@ RectTransform:
|
||||
m_Father: {fileID: 208702977}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 10, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@@ -31829,7 +31915,7 @@ RectTransform:
|
||||
m_Father: {fileID: 1396438488}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@@ -33967,6 +34053,7 @@ MonoBehaviour:
|
||||
eagleGameController: {fileID: 1965467940}
|
||||
ShardokCanvas: {fileID: 2088078267}
|
||||
connectionHandler: {fileID: 135486720}
|
||||
resetTutorialsButton: {fileID: 0}
|
||||
--- !u!1 &305665272
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -36778,10 +36865,10 @@ RectTransform:
|
||||
- {fileID: 1666727525}
|
||||
m_Father: {fileID: 2039520752}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 321, y: -11.255}
|
||||
m_SizeDelta: {x: 200, y: 20}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &329919723
|
||||
MonoBehaviour:
|
||||
@@ -47131,8 +47218,8 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1666727525}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.1, y: 0}
|
||||
m_AnchorMax: {x: 0.1, y: 1}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@@ -64015,10 +64102,10 @@ RectTransform:
|
||||
- {fileID: 1375685348}
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 256, y: -215.03}
|
||||
m_SizeDelta: {x: 492, y: 30}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &548637657
|
||||
MonoBehaviour:
|
||||
@@ -71487,10 +71574,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 10, y: -120.03}
|
||||
m_SizeDelta: {x: 0, y: 10}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &590819392
|
||||
MonoBehaviour:
|
||||
@@ -74595,6 +74682,146 @@ CanvasRenderer:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 624827069}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &625062879
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 625062880}
|
||||
- component: {fileID: 625062882}
|
||||
- component: {fileID: 625062881}
|
||||
m_Layer: 0
|
||||
m_Name: Open Resources
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &625062880
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 625062879}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 673182551}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &625062881
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 625062879}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: 'Reset Tutorials
|
||||
|
||||
'
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: ec2736df0379a45bfa7349b652fd07d6, type: 2}
|
||||
m_sharedMaterial: {fileID: 1026247389042360723, guid: ec2736df0379a45bfa7349b652fd07d6,
|
||||
type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4281479730
|
||||
m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 18
|
||||
m_fontSizeBase: 18
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!222 &625062882
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 625062879}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!1 &625252446
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -82452,6 +82679,160 @@ CanvasRenderer:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 673008387}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &673182550
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 673182551}
|
||||
- component: {fileID: 673182555}
|
||||
- component: {fileID: 673182554}
|
||||
- component: {fileID: 673182553}
|
||||
- component: {fileID: 673182552}
|
||||
m_Layer: 0
|
||||
m_Name: Reset Tutorials Button
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &673182551
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 673182550}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 625062880}
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &673182552
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 673182550}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: 30
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: 30
|
||||
m_FlexibleWidth: 1
|
||||
m_FlexibleHeight: -1
|
||||
m_LayoutPriority: 1
|
||||
--- !u!114 &673182553
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 673182550}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 673182554}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls:
|
||||
- m_Target: {fileID: 300036928}
|
||||
m_TargetAssemblyTypeName: SettingsPanelController, Assembly-CSharp
|
||||
m_MethodName: OnResetTutorialsClick
|
||||
m_Mode: 1
|
||||
m_Arguments:
|
||||
m_ObjectArgument: {fileID: 0}
|
||||
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
||||
m_IntArgument: 0
|
||||
m_FloatArgument: 0
|
||||
m_StringArgument:
|
||||
m_BoolArgument: 0
|
||||
m_CallState: 2
|
||||
--- !u!114 &673182554
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 673182550}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!222 &673182555
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 673182550}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!1 &673307124
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -83590,10 +83971,10 @@ RectTransform:
|
||||
- {fileID: 1119022577}
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 256, y: -354}
|
||||
m_SizeDelta: {x: 492, y: 40}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &683322976
|
||||
MonoBehaviour:
|
||||
@@ -93480,7 +93861,7 @@ GameObject:
|
||||
- component: {fileID: 749366808}
|
||||
- component: {fileID: 749366807}
|
||||
m_Layer: 0
|
||||
m_Name: Button
|
||||
m_Name: Open Resources Button
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
@@ -93501,10 +93882,10 @@ RectTransform:
|
||||
- {fileID: 392813076}
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 256, y: -250.03}
|
||||
m_SizeDelta: {x: 492, y: 30}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &749366807
|
||||
MonoBehaviour:
|
||||
@@ -95360,10 +95741,10 @@ RectTransform:
|
||||
- {fileID: 699949417}
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 256, y: -180.03}
|
||||
m_SizeDelta: {x: 492, y: 30}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &770361456
|
||||
MonoBehaviour:
|
||||
@@ -96170,10 +96551,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 2039520752}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 208.5, y: -11.255}
|
||||
m_SizeDelta: {x: 15, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &779503534
|
||||
MonoBehaviour:
|
||||
@@ -99264,10 +99645,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 2039520752}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 446, y: -11.255}
|
||||
m_SizeDelta: {x: 40, y: 15.01}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &806086202
|
||||
MonoBehaviour:
|
||||
@@ -99806,10 +100187,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 10, y: -313.27002}
|
||||
m_SizeDelta: {x: 0, y: 31.459991}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &808870206
|
||||
MonoBehaviour:
|
||||
@@ -105263,10 +105644,10 @@ RectTransform:
|
||||
- {fileID: 113544276}
|
||||
m_Father: {fileID: 1590704177}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 333.5, y: -11.255}
|
||||
m_SizeDelta: {x: 200, y: 20}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &858025936
|
||||
MonoBehaviour:
|
||||
@@ -121385,10 +121766,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1590704177}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 196, y: -11.255}
|
||||
m_SizeDelta: {x: 15, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &972401127
|
||||
MonoBehaviour:
|
||||
@@ -122506,7 +122887,7 @@ RectTransform:
|
||||
m_Father: {fileID: 113544276}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@@ -123520,7 +123901,7 @@ RectTransform:
|
||||
m_Father: {fileID: 1425392451}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0.1, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 10, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@@ -140643,10 +141024,10 @@ RectTransform:
|
||||
- {fileID: 717768291}
|
||||
m_Father: {fileID: 683322975}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 417, y: -20}
|
||||
m_SizeDelta: {x: 150, y: 40}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1119022578
|
||||
MonoBehaviour:
|
||||
@@ -147583,10 +147964,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 683322975}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 135.5, y: -40}
|
||||
m_SizeDelta: {x: 51, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1184808158
|
||||
MonoBehaviour:
|
||||
@@ -153109,10 +153490,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 2130578398}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 108.5, y: -11.255}
|
||||
m_SizeDelta: {x: 150, y: 22.51}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1219993393
|
||||
MonoBehaviour:
|
||||
@@ -174192,10 +174573,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 2130578398}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 196, y: -11.255}
|
||||
m_SizeDelta: {x: 15, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1390131026
|
||||
MonoBehaviour:
|
||||
@@ -178285,10 +178666,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 2039520752}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 111, y: -11.255}
|
||||
m_SizeDelta: {x: 170, y: 22.51}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1415802613
|
||||
MonoBehaviour:
|
||||
@@ -178444,10 +178825,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 2130578398}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 448.5, y: -11.255}
|
||||
m_SizeDelta: {x: 20, y: 20}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1415887397
|
||||
MonoBehaviour:
|
||||
@@ -181904,10 +182285,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1590704177}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 108.5, y: -11.255}
|
||||
m_SizeDelta: {x: 150, y: 22.51}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1448655991
|
||||
MonoBehaviour:
|
||||
@@ -196899,10 +197280,10 @@ RectTransform:
|
||||
- {fileID: 1122913432}
|
||||
m_Father: {fileID: 683322975}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 50, y: -20}
|
||||
m_SizeDelta: {x: 100, y: 40}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1557328375
|
||||
MonoBehaviour:
|
||||
@@ -198649,7 +199030,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 2147483647
|
||||
m_IsActive: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1566150938
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -198670,6 +199051,7 @@ RectTransform:
|
||||
- {fileID: 770361455}
|
||||
- {fileID: 548637656}
|
||||
- {fileID: 749366806}
|
||||
- {fileID: 673182551}
|
||||
- {fileID: 2039520752}
|
||||
- {fileID: 808870205}
|
||||
- {fileID: 683322975}
|
||||
@@ -200241,10 +200623,10 @@ RectTransform:
|
||||
- {fileID: 2123746368}
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 256, y: -98.774994}
|
||||
m_SizeDelta: {x: 492, y: 22.51}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1590704178
|
||||
MonoBehaviour:
|
||||
@@ -219035,10 +219417,10 @@ RectTransform:
|
||||
- {fileID: 543540660}
|
||||
m_Father: {fileID: 683322975}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 221, y: -20}
|
||||
m_SizeDelta: {x: 100, y: 40}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1775111780
|
||||
MonoBehaviour:
|
||||
@@ -221290,7 +221672,7 @@ RectTransform:
|
||||
m_Father: {fileID: 1110049512}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 10, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@@ -247406,10 +247788,10 @@ RectTransform:
|
||||
- {fileID: 806086201}
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 256, y: -281.285}
|
||||
m_SizeDelta: {x: 492, y: 22.51}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &2039520753
|
||||
MonoBehaviour:
|
||||
@@ -252578,10 +252960,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1590704177}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 218.5, y: -11.255}
|
||||
m_SizeDelta: {x: 20, y: 20}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &2096030393
|
||||
MonoBehaviour:
|
||||
@@ -255937,7 +256319,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
m_IsActive: 0
|
||||
--- !u!224 &2109805906
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -255957,7 +256339,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 256, y: -145.03}
|
||||
m_AnchoredPosition: {x: 256, y: -142.85143}
|
||||
m_SizeDelta: {x: 492, y: 30}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &2109805907
|
||||
@@ -257369,10 +257751,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1590704177}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 448.5, y: -11.255}
|
||||
m_SizeDelta: {x: 20, y: 20}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &2123746369
|
||||
MonoBehaviour:
|
||||
@@ -258672,10 +259054,10 @@ RectTransform:
|
||||
- {fileID: 1415887396}
|
||||
m_Father: {fileID: 1566150938}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 256, y: -71.265}
|
||||
m_SizeDelta: {x: 492, y: 22.51}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &2130578399
|
||||
MonoBehaviour:
|
||||
@@ -268781,6 +269163,7 @@ SceneRoots:
|
||||
m_Roots:
|
||||
- {fileID: 279614944}
|
||||
- {fileID: 815907755}
|
||||
- {fileID: 16227909}
|
||||
- {fileID: 122332320}
|
||||
- {fileID: 682560790}
|
||||
- {fileID: 1342510189}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using common;
|
||||
using eagle;
|
||||
using Eagle0.Tutorial;
|
||||
using Net.Eagle0.Shardok.Api;
|
||||
using Shardok;
|
||||
using TMPro;
|
||||
@@ -49,6 +50,8 @@ public class SettingsPanelController : MonoBehaviour {
|
||||
public GameObject ShardokCanvas;
|
||||
public ConnectionHandler connectionHandler;
|
||||
|
||||
public Button resetTutorialsButton;
|
||||
|
||||
void Start() {
|
||||
_active = false;
|
||||
panel.SetActive(false);
|
||||
@@ -148,6 +151,11 @@ public class SettingsPanelController : MonoBehaviour {
|
||||
Process.Start(Path.Combine(Application.persistentDataPath, "eagle0", "Resources"));
|
||||
}
|
||||
|
||||
public void OnResetTutorialsClick() {
|
||||
TutorialManager.Instance?.ResetAllProgress();
|
||||
UnityEngine.Debug.Log("Tutorial progress reset");
|
||||
}
|
||||
|
||||
private void HandleLobby() {
|
||||
eagleGameController.StopAll();
|
||||
eagleGameController.gameObject.SetActive(false);
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
# Tutorial System for Eagle0
|
||||
|
||||
## Overview
|
||||
|
||||
A modular tutorial system for the Eagle0 Unity client supporting:
|
||||
- **Onboarding**: Full guided playthrough of first several turns
|
||||
- **Contextual tutorials**: First-encounter and first-attempt triggers with subtle hints
|
||||
- **Mixed UI**: Modals for concepts, overlays for UI guidance, hint indicators
|
||||
- **Local persistence**: PlayerPrefs-based state tracking
|
||||
|
||||
---
|
||||
|
||||
## Current Status
|
||||
|
||||
### Completed
|
||||
- [x] **Phase 1: Foundation** - TutorialState, TutorialManager, TutorialStep/Sequence
|
||||
- [x] **Phase 2: UI (partial)** - IMGUI fallback modal with Stoke font
|
||||
- [x] **Phase 3: Triggers (partial)** - Basic trigger system with hooks in game controllers
|
||||
- [x] **Test setup** - TutorialTestSetup for province selection, battle entry, command triggers
|
||||
- [x] **Settings integration** - Reset Tutorials button in Settings panel
|
||||
|
||||
### Remaining
|
||||
- [ ] **Canvas UI prefabs** - Replace IMGUI fallback with styled Canvas-based modal
|
||||
- [ ] **Overlay system** - TutorialOverlayController for highlighting UI elements
|
||||
- [ ] **Hint indicators** - TutorialHintIndicator for subtle pulsing dots
|
||||
- [ ] **Real tutorial content** - Replace test tutorials with actual onboarding sequence
|
||||
- [ ] **More contextual triggers** - Diplomacy, hero recruitment, spells, terrain, etc.
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
TutorialManager (Singleton, DontDestroyOnLoad)
|
||||
├── TutorialState (PlayerPrefs persistence)
|
||||
├── TutorialTriggerRegistry
|
||||
│ ├── OnboardingTriggers
|
||||
│ └── ContextualTriggers
|
||||
└── TutorialUIManager
|
||||
├── TutorialModalPanel (TODO)
|
||||
├── TutorialOverlayController (TODO)
|
||||
├── TutorialHintIndicator (TODO)
|
||||
└── IMGUI Fallback (working)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Structure (Current)
|
||||
|
||||
```
|
||||
Assets/Tutorial/
|
||||
├── TutorialManager.cs ✓ Singleton, coordinates everything
|
||||
├── TutorialState.cs ✓ PlayerPrefs persistence
|
||||
├── TutorialTestSetup.cs ✓ Test component for validation
|
||||
├── Content/
|
||||
│ ├── TutorialStep.cs ✓ Step data structure
|
||||
│ └── TutorialSequence.cs ✓ Sequence ScriptableObject
|
||||
├── Triggers/
|
||||
│ └── TutorialTriggerRegistry.cs ✓ Event routing
|
||||
└── UI/
|
||||
├── TutorialUIManager.cs ✓ UI coordination + IMGUI fallback
|
||||
├── TutorialModalPanel.cs ✓ Stub (needs Canvas implementation)
|
||||
├── TutorialOverlayController.cs ✓ Stub
|
||||
└── TutorialHintIndicator.cs ✓ Stub
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Points (Implemented)
|
||||
|
||||
### EagleGameController.cs
|
||||
- `SetUpGame()`: Initializes TutorialManager, starts onboarding
|
||||
- `SwapModel()`: Calls `OnModelUpdated()`
|
||||
- `ProvinceWasSelected()`: Calls `OnProvinceSelected()`
|
||||
- `PostCommittedCommand()`: Calls `OnCommandIssued()`
|
||||
|
||||
### ShardokGameController.cs
|
||||
- `SetUpGame()`: Initializes TutorialManager for battle
|
||||
- `ModelUpdated()`: Calls `OnBattleAction()`
|
||||
- `OnTurnEnded()`: Calls `OnTurnEnded()`
|
||||
- Unit selection: Calls `OnUnitSelected()`
|
||||
|
||||
### SettingsPanelController.cs
|
||||
- Reset Tutorials button: Calls `TutorialManager.Instance.ResetAllProgress()`
|
||||
|
||||
---
|
||||
|
||||
## Onboarding Flow (Planned)
|
||||
|
||||
| Step | Type | Content | Completion |
|
||||
|------|------|---------|------------|
|
||||
| 1 | Modal | Welcome to Eagle0 | Button click |
|
||||
| 2 | Overlay | Map overview - "Select a province" | Province selected |
|
||||
| 3 | Overlay | Province info panel explanation | Button click |
|
||||
| 4 | Overlay | Command buttons - "Try March" | March issued |
|
||||
| 5 | Modal | Turn cycle explanation | Button click |
|
||||
| 6 | Hidden | Wait for battle available | Model update |
|
||||
| 7 | Modal | Battle introduction | Button click |
|
||||
| 8 | Overlay | "Battle!" button highlight | Battle entered |
|
||||
| 9 | Modal | Tactical combat overview | Button click |
|
||||
| 10 | Overlay | Select and move a unit | Move issued |
|
||||
| 11 | Overlay | Attack an enemy | Attack issued |
|
||||
| 12 | Overlay | End Turn button | Turn ended |
|
||||
| 13 | Modal | Onboarding complete! | Button click |
|
||||
|
||||
---
|
||||
|
||||
## Contextual Tutorials (Planned)
|
||||
|
||||
### Strategic (First Encounter)
|
||||
| ID | Trigger | Display |
|
||||
|----|---------|---------|
|
||||
| `diplomacy_offer` | First diplomacy command available | Modal |
|
||||
| `hero_recruitment` | First recruitment available | Modal |
|
||||
| `province_riot` | First riot in owned province | Modal |
|
||||
| `weather_control` | First weather command available | Overlay |
|
||||
| `prisoner_capture` | First prisoner captured | Modal |
|
||||
|
||||
### Tactical (First Encounter/Attempt)
|
||||
| ID | Trigger | Display |
|
||||
|----|---------|---------|
|
||||
| `spell_lightning` | Lightning spell available | Tooltip |
|
||||
| `spell_meteor` | Meteor spell available | Modal |
|
||||
| `spell_holywave` | Holy Wave available | Tooltip |
|
||||
| `spell_raisedead` | Raise Dead available | Modal |
|
||||
| `terrain_fire` | Fire hex encountered | Tooltip |
|
||||
| `terrain_water` | Water adjacent to unit | Tooltip |
|
||||
| `ability_charge` | Charge command available | Overlay |
|
||||
| `flanking` | Flanking opportunity | Hint |
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
1. Add `TutorialTestSetup` component to TutorialManager GameObject
|
||||
2. Assign `Stoke-Regular.ttf` to `FallbackFont` on TutorialUIManager
|
||||
3. Enable `Debug Logging` on TutorialManager for console output
|
||||
4. Play game → select province → see test tutorial modal
|
||||
5. Use Settings → Reset Tutorials to test again
|
||||
@@ -100,7 +100,7 @@ namespace Eagle0.Tutorial {
|
||||
}
|
||||
|
||||
if (OnboardingSequence == null) {
|
||||
Debug.LogWarning("TutorialManager: No onboarding sequence assigned");
|
||||
Log("StartOnboarding: No onboarding sequence assigned, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eagle0.Tutorial {
|
||||
/// <summary>
|
||||
/// Test component that sets up a simple tutorial for end-to-end testing.
|
||||
/// Attach to TutorialManager GameObject to register test tutorials on startup.
|
||||
/// Can be removed once actual tutorial content is created in the Editor.
|
||||
/// </summary>
|
||||
public class TutorialTestSetup : MonoBehaviour {
|
||||
[Header("Test Configuration")]
|
||||
[Tooltip("Enable test tutorials")]
|
||||
public bool EnableTestTutorials = true;
|
||||
|
||||
[Tooltip("Reset tutorial progress on startup (for testing)")]
|
||||
public bool ResetProgressOnStart = false;
|
||||
|
||||
private void Start() {
|
||||
if (!EnableTestTutorials) return;
|
||||
|
||||
var manager = TutorialManager.Instance;
|
||||
if (manager == null) {
|
||||
Debug.LogWarning("TutorialTestSetup: TutorialManager not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ResetProgressOnStart) { manager.ResetAllProgress(); }
|
||||
|
||||
RegisterTestTutorials(manager);
|
||||
Debug.Log("TutorialTestSetup: Test tutorials registered");
|
||||
}
|
||||
|
||||
private void RegisterTestTutorials(TutorialManager manager) {
|
||||
// Create a simple "first province selected" tutorial
|
||||
var provinceSelectedTutorial = CreateProvinceSelectedTutorial();
|
||||
manager.TriggerRegistry.RegisterTutorial(provinceSelectedTutorial, "province_selected");
|
||||
|
||||
// Create a simple "first battle" tutorial
|
||||
var firstBattleTutorial = CreateFirstBattleTutorial();
|
||||
manager.TriggerRegistry.RegisterTutorial(firstBattleTutorial, "battle_entered");
|
||||
|
||||
// Create a simple "first command" tutorial
|
||||
var firstCommandTutorial = CreateFirstCommandTutorial();
|
||||
manager.TriggerRegistry.RegisterTutorial(firstCommandTutorial, "command_issued");
|
||||
}
|
||||
|
||||
private TutorialSequence CreateProvinceSelectedTutorial() {
|
||||
var sequence = ScriptableObject.CreateInstance<TutorialSequence>();
|
||||
sequence.SequenceId = "test_province_selected";
|
||||
sequence.DisplayName = "Province Selection";
|
||||
|
||||
sequence.Steps.Add(new TutorialStep {
|
||||
StepId = "province_selected_intro",
|
||||
Title = "Province Selected!",
|
||||
Description =
|
||||
"You've selected a province. Here you can see information about the province and issue commands to your forces.\n\n(This is a test tutorial to verify the tutorial system is working.)",
|
||||
DisplayMode = TutorialDisplayMode.Modal,
|
||||
CompletionType = TutorialCompletionType.ButtonClick,
|
||||
AllowSkip = true
|
||||
});
|
||||
|
||||
return sequence;
|
||||
}
|
||||
|
||||
private TutorialSequence CreateFirstBattleTutorial() {
|
||||
var sequence = ScriptableObject.CreateInstance<TutorialSequence>();
|
||||
sequence.SequenceId = "test_first_battle";
|
||||
sequence.DisplayName = "First Battle";
|
||||
|
||||
sequence.Steps.Add(new TutorialStep {
|
||||
StepId = "battle_intro",
|
||||
Title = "Battle Begins!",
|
||||
Description =
|
||||
"You've entered tactical combat. Command your units on the hex grid to defeat the enemy.\n\n(This is a test tutorial to verify the tutorial system is working.)",
|
||||
DisplayMode = TutorialDisplayMode.Modal,
|
||||
CompletionType = TutorialCompletionType.ButtonClick,
|
||||
AllowSkip = true
|
||||
});
|
||||
|
||||
return sequence;
|
||||
}
|
||||
|
||||
private TutorialSequence CreateFirstCommandTutorial() {
|
||||
var sequence = ScriptableObject.CreateInstance<TutorialSequence>();
|
||||
sequence.SequenceId = "test_first_command";
|
||||
sequence.DisplayName = "First Command";
|
||||
|
||||
sequence.Steps.Add(new TutorialStep {
|
||||
StepId = "command_issued_intro",
|
||||
Title = "Command Issued!",
|
||||
Description =
|
||||
"You've issued your first command. Commands are processed at the end of each turn.\n\n(This is a test tutorial to verify the tutorial system is working.)",
|
||||
DisplayMode = TutorialDisplayMode.Modal,
|
||||
CompletionType = TutorialCompletionType.ButtonClick,
|
||||
AllowSkip = true
|
||||
});
|
||||
|
||||
return sequence;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 370b3269832442e196d1b432bdae2f1e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+149
-5
@@ -22,10 +22,26 @@ namespace Eagle0.Tutorial {
|
||||
[Tooltip("Canvas for tutorial UI (should be above game UI)")]
|
||||
public Canvas TutorialCanvas;
|
||||
|
||||
[Header("Fallback UI")]
|
||||
[Tooltip("Use IMGUI fallback when no ModalPanel is assigned")]
|
||||
public bool UseFallbackUI = true;
|
||||
|
||||
[Tooltip("Font for IMGUI fallback (assign Stoke-Regular)")]
|
||||
public Font FallbackFont;
|
||||
|
||||
// Active hints
|
||||
private Dictionary<string, TutorialHintIndicator> _activeHints =
|
||||
new Dictionary<string, TutorialHintIndicator>();
|
||||
|
||||
// Fallback modal state
|
||||
private bool _fallbackModalVisible;
|
||||
private TutorialStep _fallbackStep;
|
||||
private Action _fallbackOnContinue;
|
||||
private Action _fallbackOnSkip;
|
||||
private int _fallbackCurrentIndex;
|
||||
private int _fallbackTotalSteps;
|
||||
private bool _fallbackIsOnboarding;
|
||||
|
||||
private void Awake() {
|
||||
// Ensure canvas is set up correctly
|
||||
if (TutorialCanvas != null) {
|
||||
@@ -33,6 +49,132 @@ namespace Eagle0.Tutorial {
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI() {
|
||||
if (!_fallbackModalVisible || _fallbackStep == null) return;
|
||||
|
||||
// Semi-transparent background
|
||||
GUI.color = new Color(0, 0, 0, 0.7f);
|
||||
GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), Texture2D.whiteTexture);
|
||||
GUI.color = Color.white;
|
||||
|
||||
// Modal window
|
||||
float windowWidth = Mathf.Min(1200, Screen.width - 40);
|
||||
float windowHeight = 600;
|
||||
float windowX = (Screen.width - windowWidth) / 2;
|
||||
float windowY = (Screen.height - windowHeight) / 2;
|
||||
|
||||
GUIStyle windowStyle = new GUIStyle(GUI.skin.window);
|
||||
windowStyle.fontSize = 48;
|
||||
if (FallbackFont != null) windowStyle.font = FallbackFont;
|
||||
|
||||
GUI.Window(
|
||||
12345,
|
||||
new Rect(windowX, windowY, windowWidth, windowHeight),
|
||||
DrawFallbackModal,
|
||||
_fallbackStep.Title ?? "Tutorial",
|
||||
windowStyle);
|
||||
}
|
||||
|
||||
private void DrawFallbackModal(int windowId) {
|
||||
GUILayout.Space(60);
|
||||
|
||||
// Description
|
||||
GUIStyle descStyle = new GUIStyle(GUI.skin.label);
|
||||
descStyle.wordWrap = true;
|
||||
descStyle.fontSize = 40;
|
||||
if (FallbackFont != null) descStyle.font = FallbackFont;
|
||||
GUILayout.Label(
|
||||
_fallbackStep.Description ?? "",
|
||||
descStyle,
|
||||
GUILayout.ExpandHeight(true));
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// Progress
|
||||
if (_fallbackTotalSteps > 1) {
|
||||
GUIStyle progressStyle = new GUIStyle(GUI.skin.label);
|
||||
progressStyle.fontSize = 32;
|
||||
if (FallbackFont != null) progressStyle.font = FallbackFont;
|
||||
GUILayout.Label(
|
||||
$"Step {_fallbackCurrentIndex + 1} of {_fallbackTotalSteps}",
|
||||
progressStyle,
|
||||
GUILayout.ExpandWidth(true));
|
||||
}
|
||||
|
||||
GUILayout.Space(30);
|
||||
|
||||
// Button style
|
||||
GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);
|
||||
buttonStyle.fontSize = 36;
|
||||
if (FallbackFont != null) buttonStyle.font = FallbackFont;
|
||||
|
||||
// Buttons
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
if (_fallbackStep.AllowSkip) {
|
||||
if (GUILayout.Button(
|
||||
"Skip",
|
||||
buttonStyle,
|
||||
GUILayout.Width(200),
|
||||
GUILayout.Height(80))) {
|
||||
var callback = _fallbackOnSkip;
|
||||
HideFallbackModal();
|
||||
callback?.Invoke();
|
||||
}
|
||||
|
||||
if (_fallbackIsOnboarding) {
|
||||
if (GUILayout.Button(
|
||||
"Skip All",
|
||||
buttonStyle,
|
||||
GUILayout.Width(200),
|
||||
GUILayout.Height(80))) {
|
||||
HideFallbackModal();
|
||||
TutorialManager.Instance?.SkipAllOnboarding();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
string buttonText =
|
||||
_fallbackCurrentIndex >= _fallbackTotalSteps - 1 ? "Got it!" : "Continue";
|
||||
if (GUILayout.Button(
|
||||
buttonText,
|
||||
buttonStyle,
|
||||
GUILayout.Width(240),
|
||||
GUILayout.Height(80))) {
|
||||
var callback = _fallbackOnContinue;
|
||||
HideFallbackModal();
|
||||
callback?.Invoke();
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(30);
|
||||
}
|
||||
|
||||
private void ShowFallbackModal(
|
||||
TutorialStep step,
|
||||
int currentIndex,
|
||||
int totalSteps,
|
||||
Action onContinue,
|
||||
Action onSkip,
|
||||
bool isOnboarding) {
|
||||
_fallbackStep = step;
|
||||
_fallbackCurrentIndex = currentIndex;
|
||||
_fallbackTotalSteps = totalSteps;
|
||||
_fallbackOnContinue = onContinue;
|
||||
_fallbackOnSkip = onSkip;
|
||||
_fallbackIsOnboarding = isOnboarding;
|
||||
_fallbackModalVisible = true;
|
||||
}
|
||||
|
||||
private void HideFallbackModal() {
|
||||
_fallbackModalVisible = false;
|
||||
_fallbackStep = null;
|
||||
_fallbackOnContinue = null;
|
||||
_fallbackOnSkip = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows a modal dialog for a tutorial step.
|
||||
/// </summary>
|
||||
@@ -43,13 +185,14 @@ namespace Eagle0.Tutorial {
|
||||
Action onComplete,
|
||||
Action onSkip,
|
||||
bool isOnboarding) {
|
||||
if (ModalPanel == null) {
|
||||
Debug.LogWarning("TutorialUIManager: No ModalPanel assigned");
|
||||
if (ModalPanel != null) {
|
||||
ModalPanel.Show(step, currentIndex, totalSteps, onComplete, onSkip, isOnboarding);
|
||||
} else if (UseFallbackUI) {
|
||||
ShowFallbackModal(step, currentIndex, totalSteps, onComplete, onSkip, isOnboarding);
|
||||
} else {
|
||||
Debug.LogWarning("TutorialUIManager: No ModalPanel assigned and fallback disabled");
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
ModalPanel.Show(step, currentIndex, totalSteps, onComplete, onSkip, isOnboarding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -148,6 +291,7 @@ namespace Eagle0.Tutorial {
|
||||
public void HideAll() {
|
||||
ModalPanel?.Hide();
|
||||
OverlayController?.HideOverlay();
|
||||
HideFallbackModal();
|
||||
// Note: Don't hide hints automatically - they persist until dismissed
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
type InvitationHTTPHandler struct {
|
||||
invitationService *InvitationService
|
||||
installerURL string
|
||||
macInstallerURL string
|
||||
}
|
||||
|
||||
// NewInvitationHTTPHandler creates a new invitation HTTP handler
|
||||
@@ -25,9 +26,14 @@ func NewInvitationHTTPHandler(invitationService *InvitationService) *InvitationH
|
||||
if installerURL == "" {
|
||||
installerURL = "https://assets.eagle0.net/installer/EagleInstaller.exe"
|
||||
}
|
||||
macInstallerURL := os.Getenv("MAC_INSTALLER_URL")
|
||||
if macInstallerURL == "" {
|
||||
macInstallerURL = "https://assets.eagle0.net/mac/builds/eagle0-latest.zip"
|
||||
}
|
||||
return &InvitationHTTPHandler{
|
||||
invitationService: invitationService,
|
||||
installerURL: installerURL,
|
||||
macInstallerURL: macInstallerURL,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +44,7 @@ func (h *InvitationHTTPHandler) RegisterRoutes() {
|
||||
|
||||
// handleInvite routes requests to the appropriate handler
|
||||
func (h *InvitationHTTPHandler) handleInvite(w http.ResponseWriter, r *http.Request) {
|
||||
// Parse path: /invite/{code} or /invite/{code}/install.bat
|
||||
// Parse path: /invite/{code} or /invite/{code}/install.bat or /invite/{code}/install.sh
|
||||
path := strings.TrimPrefix(r.URL.Path, "/invite/")
|
||||
parts := strings.Split(path, "/")
|
||||
|
||||
@@ -51,6 +57,8 @@ func (h *InvitationHTTPHandler) handleInvite(w http.ResponseWriter, r *http.Requ
|
||||
|
||||
if len(parts) == 2 && parts[1] == "install.bat" {
|
||||
h.handleInstallBat(w, r, code)
|
||||
} else if len(parts) == 2 && parts[1] == "install.sh" {
|
||||
h.handleInstallSh(w, r, code)
|
||||
} else if len(parts) == 1 {
|
||||
h.handleLandingPage(w, r, code)
|
||||
} else {
|
||||
@@ -58,21 +66,34 @@ func (h *InvitationHTTPHandler) handleInvite(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
}
|
||||
|
||||
// isMacUserAgent returns true if the User-Agent indicates a Mac browser
|
||||
func isMacUserAgent(userAgent string) bool {
|
||||
ua := strings.ToLower(userAgent)
|
||||
return strings.Contains(ua, "macintosh") || strings.Contains(ua, "mac os x")
|
||||
}
|
||||
|
||||
// handleLandingPage serves the invitation landing page
|
||||
func (h *InvitationHTTPHandler) handleLandingPage(w http.ResponseWriter, r *http.Request, code string) {
|
||||
invitation := h.invitationService.FindByCode(code)
|
||||
isMac := isMacUserAgent(r.UserAgent())
|
||||
|
||||
data := struct {
|
||||
Valid bool
|
||||
Code string
|
||||
ExpiresAt string
|
||||
ErrorMessage string
|
||||
InstallBatURL string
|
||||
InstallerURL string
|
||||
Valid bool
|
||||
Code string
|
||||
ExpiresAt string
|
||||
ErrorMessage string
|
||||
InstallBatURL string
|
||||
InstallerURL string
|
||||
IsMac bool
|
||||
InstallShURL string
|
||||
MacInstallerURL string
|
||||
}{
|
||||
Code: code,
|
||||
InstallBatURL: fmt.Sprintf("/invite/%s/install.bat", code),
|
||||
InstallerURL: h.installerURL,
|
||||
Code: code,
|
||||
InstallBatURL: fmt.Sprintf("/invite/%s/install.bat", code),
|
||||
InstallerURL: h.installerURL,
|
||||
IsMac: isMac,
|
||||
InstallShURL: fmt.Sprintf("/invite/%s/install.sh", code),
|
||||
MacInstallerURL: h.macInstallerURL,
|
||||
}
|
||||
|
||||
if invitation == nil {
|
||||
@@ -160,6 +181,88 @@ timeout /t 5
|
||||
log.Printf("[InviteHTTP] Served install.bat for code %s...", code[:8])
|
||||
}
|
||||
|
||||
// handleInstallSh serves the Mac shell installer script
|
||||
func (h *InvitationHTTPHandler) handleInstallSh(w http.ResponseWriter, r *http.Request, code string) {
|
||||
// Validate the code exists and is valid
|
||||
if !h.invitationService.IsValidCode(code) {
|
||||
http.Error(w, "Invalid or expired invitation code", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
// Generate shell script
|
||||
script := fmt.Sprintf(`#!/bin/bash
|
||||
#
|
||||
# Eagle0 Mac Installer
|
||||
# This script downloads Eagle0 and sets up your invitation code.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
echo ""
|
||||
echo "===================================="
|
||||
echo " Eagle0 Mac Installer"
|
||||
echo "===================================="
|
||||
echo ""
|
||||
|
||||
# Create app support directory
|
||||
APP_SUPPORT_DIR="$HOME/Library/Application Support/eagle0"
|
||||
mkdir -p "$APP_SUPPORT_DIR"
|
||||
|
||||
# Write invitation code
|
||||
echo "Setting up invitation code..."
|
||||
cat > "$APP_SUPPORT_DIR/invitation.json" << 'INVITATION_EOF'
|
||||
{"invitationCode": "%s"}
|
||||
INVITATION_EOF
|
||||
|
||||
echo "Invitation code saved."
|
||||
echo ""
|
||||
|
||||
# Download location
|
||||
DOWNLOAD_DIR="$HOME/Downloads"
|
||||
ZIP_PATH="$DOWNLOAD_DIR/eagle0.zip"
|
||||
APP_PATH="/Applications/eagle0.app"
|
||||
|
||||
echo "Downloading Eagle0..."
|
||||
curl -L -o "$ZIP_PATH" "%s"
|
||||
|
||||
echo ""
|
||||
echo "Extracting to /Applications..."
|
||||
|
||||
# Remove old version if exists
|
||||
if [ -d "$APP_PATH" ]; then
|
||||
echo "Removing previous version..."
|
||||
rm -rf "$APP_PATH"
|
||||
fi
|
||||
|
||||
# Unzip to Applications
|
||||
unzip -q "$ZIP_PATH" -d /Applications/
|
||||
|
||||
# Clean up zip
|
||||
rm "$ZIP_PATH"
|
||||
|
||||
# Remove quarantine attribute (app is notarized but downloaded via curl)
|
||||
xattr -dr com.apple.quarantine "$APP_PATH" 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "===================================="
|
||||
echo " Installation Complete!"
|
||||
echo "===================================="
|
||||
echo ""
|
||||
echo "Eagle0 has been installed to /Applications/eagle0.app"
|
||||
echo "Your invitation code has been saved."
|
||||
echo ""
|
||||
echo "Starting Eagle0..."
|
||||
open "$APP_PATH"
|
||||
|
||||
`, code, h.macInstallerURL)
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-sh")
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=eagle0-install.sh")
|
||||
w.Write([]byte(script))
|
||||
|
||||
log.Printf("[InviteHTTP] Served install.sh for code %s...", code[:8])
|
||||
}
|
||||
|
||||
var landingPageTemplate = template.Must(template.New("landing").Parse(`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -277,6 +380,21 @@ var landingPageTemplate = template.Must(template.New("landing").Parse(`<!DOCTYPE
|
||||
font-size: 12px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
code {
|
||||
background: #e9ecef;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
.other-platform {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
}
|
||||
.other-platform a {
|
||||
color: #1a5f7a;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -294,17 +412,33 @@ var landingPageTemplate = template.Must(template.New("landing").Parse(`<!DOCTYPE
|
||||
<div class="content">
|
||||
<p>You've been invited to play Eagle0, a strategic turn-based game with tactical hex-based combat.</p>
|
||||
|
||||
<a href="{{.InstallBatURL}}" class="button">Download & Install</a>
|
||||
{{if .IsMac}}
|
||||
<a href="{{.InstallShURL}}" class="button">Download for Mac</a>
|
||||
|
||||
<div class="instructions">
|
||||
<h3>How to install:</h3>
|
||||
<h3>How to install on Mac:</h3>
|
||||
<ol>
|
||||
<li>Click the "Download & Install" button above</li>
|
||||
<li>Click the "Download for Mac" button above</li>
|
||||
<li>Open Terminal and navigate to your Downloads folder:<br>
|
||||
<code>cd ~/Downloads</code></li>
|
||||
<li>Run the installer script:<br>
|
||||
<code>bash eagle0-install.sh</code></li>
|
||||
<li>Eagle0 will be installed to /Applications and launched automatically</li>
|
||||
</ol>
|
||||
</div>
|
||||
{{else}}
|
||||
<a href="{{.InstallBatURL}}" class="button">Download for Windows</a>
|
||||
|
||||
<div class="instructions">
|
||||
<h3>How to install on Windows:</h3>
|
||||
<ol>
|
||||
<li>Click the "Download for Windows" button above</li>
|
||||
<li>Open the downloaded <strong>eagle0-install.bat</strong> file</li>
|
||||
<li>If Windows shows a security prompt, click "More info" then "Run anyway"</li>
|
||||
<li>The installer will download and start automatically with your invitation code</li>
|
||||
</ol>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .ExpiresAt}}
|
||||
<div class="expires">
|
||||
@@ -313,10 +447,23 @@ var landingPageTemplate = template.Must(template.New("landing").Parse(`<!DOCTYPE
|
||||
{{end}}
|
||||
|
||||
<div class="manual-section">
|
||||
{{if .IsMac}}
|
||||
<h3>Alternative: Manual Installation</h3>
|
||||
<p>If the script doesn't work, you can <a href="{{.MacInstallerURL}}">download the ZIP manually</a>, extract it to /Applications, and enter this code when prompted:</p>
|
||||
{{else}}
|
||||
<h3>Alternative: Manual Installation</h3>
|
||||
<p>If the automatic installer doesn't work, you can <a href="{{.InstallerURL}}">download the installer manually</a> and enter this code when prompted:</p>
|
||||
{{end}}
|
||||
<div class="code-box">{{.Code}}</div>
|
||||
</div>
|
||||
|
||||
<div class="other-platform">
|
||||
{{if .IsMac}}
|
||||
<p><small>Looking for Windows? <a href="{{.InstallBatURL}}">Download Windows installer</a></small></p>
|
||||
{{else}}
|
||||
<p><small>Looking for Mac? <a href="{{.InstallShURL}}">Download Mac installer</a></small></p>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="error-box">
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "mac_build_handler_lib",
|
||||
srcs = ["mac_build_handler.go"],
|
||||
importpath = "github.com/nolen777/eagle0/src/main/go/net/eagle0/build/mac_build_handler",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = ["//src/main/go/net/eagle0/util/aws"],
|
||||
)
|
||||
|
||||
go_binary(
|
||||
name = "mac_build_handler",
|
||||
embed = [":mac_build_handler_lib"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
@@ -0,0 +1,350 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"crypto/sha256"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nolen777/eagle0/src/main/go/net/eagle0/util/aws"
|
||||
)
|
||||
|
||||
var bucketName = "eagle0-windows" // Using existing bucket with /mac/ prefix
|
||||
var appcastPath = "mac/appcast.xml"
|
||||
var buildsRoot = "mac/builds/"
|
||||
|
||||
// Sparkle Appcast XML structures
|
||||
type Appcast struct {
|
||||
XMLName xml.Name `xml:"rss"`
|
||||
Version string `xml:"version,attr"`
|
||||
Xmlns string `xml:"xmlns:sparkle,attr"`
|
||||
Channel Channel `xml:"channel"`
|
||||
}
|
||||
|
||||
type Channel struct {
|
||||
Title string `xml:"title"`
|
||||
Link string `xml:"link"`
|
||||
Description string `xml:"description"`
|
||||
Language string `xml:"language"`
|
||||
Items []Item `xml:"item"`
|
||||
}
|
||||
|
||||
type Item struct {
|
||||
Title string `xml:"title"`
|
||||
PubDate string `xml:"pubDate"`
|
||||
SparkleVersion string `xml:"sparkle:version"`
|
||||
SparkleShortVersion string `xml:"sparkle:shortVersionString"`
|
||||
Description string `xml:"description,omitempty"`
|
||||
Enclosure Enclosure `xml:"enclosure"`
|
||||
}
|
||||
|
||||
type Enclosure struct {
|
||||
URL string `xml:"url,attr"`
|
||||
Length int64 `xml:"length,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
EdSig string `xml:"sparkle:edSignature,attr"`
|
||||
}
|
||||
|
||||
func zipApp(appPath string, zipPath string) error {
|
||||
zipFile, err := os.Create(zipPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create zip file: %w", err)
|
||||
}
|
||||
defer zipFile.Close()
|
||||
|
||||
zipWriter := zip.NewWriter(zipFile)
|
||||
defer zipWriter.Close()
|
||||
|
||||
appBase := filepath.Base(appPath)
|
||||
|
||||
// Use WalkDir with Lstat to properly handle symlinks
|
||||
err = filepath.WalkDir(appPath, func(path string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the relative path from the app's parent directory
|
||||
relPath, err := filepath.Rel(filepath.Dir(appPath), path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Skip if it's the root
|
||||
if relPath == appBase && d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Use Lstat to get info without following symlinks
|
||||
info, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if it's a symlink
|
||||
if info.Mode()&os.ModeSymlink != 0 {
|
||||
// Read the symlink target
|
||||
linkTarget, err := os.Readlink(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create symlink entry in zip
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header.Name = relPath
|
||||
header.Method = zip.Store
|
||||
|
||||
writer, err := zipWriter.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = writer.Write([]byte(linkTarget))
|
||||
return err
|
||||
}
|
||||
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use forward slashes and preserve the .app directory structure
|
||||
header.Name = relPath
|
||||
if info.IsDir() {
|
||||
header.Name += "/"
|
||||
} else {
|
||||
header.Method = zip.Deflate
|
||||
}
|
||||
|
||||
// Preserve executable permissions
|
||||
header.SetMode(info.Mode())
|
||||
|
||||
writer, err := zipWriter.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = io.Copy(writer, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func signWithSparkle(filePath string, privateKeyPath string) (string, error) {
|
||||
// Use Sparkle's sign_update tool
|
||||
// First, try to find it in the Sparkle cache
|
||||
sparkleSignTool := "/tmp/sparkle-cache/Sparkle-2.6.4/bin/sign_update"
|
||||
|
||||
// If not found, download Sparkle
|
||||
if _, err := os.Stat(sparkleSignTool); os.IsNotExist(err) {
|
||||
log.Println("Sparkle sign_update not found, downloading...")
|
||||
cmd := exec.Command("bash", "-c", `
|
||||
mkdir -p /tmp/sparkle-cache
|
||||
curl -sL https://github.com/sparkle-project/Sparkle/releases/download/2.6.4/Sparkle-2.6.4.tar.xz | tar -xJ -C /tmp/sparkle-cache
|
||||
`)
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return "", fmt.Errorf("failed to download Sparkle: %s: %w", output, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Sign the file
|
||||
cmd := exec.Command(sparkleSignTool, filePath, "-s", privateKeyPath)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to sign file: %w", err)
|
||||
}
|
||||
|
||||
// sign_update outputs: sparkle:edSignature="<signature>" length="<length>"
|
||||
// We need to extract just the signature
|
||||
signature := strings.TrimSpace(string(output))
|
||||
// Parse out the signature from the output
|
||||
if strings.Contains(signature, "sparkle:edSignature=\"") {
|
||||
start := strings.Index(signature, "sparkle:edSignature=\"") + len("sparkle:edSignature=\"")
|
||||
end := strings.Index(signature[start:], "\"")
|
||||
if end > 0 {
|
||||
signature = signature[start : start+end]
|
||||
}
|
||||
}
|
||||
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
func getFileSize(path string) (int64, error) {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return info.Size(), nil
|
||||
}
|
||||
|
||||
func sha256File(path string) (string, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func fetchAppcast(bb aws.BucketBasics) (*Appcast, error) {
|
||||
content, err := bb.FetchString(bucketName, appcastPath)
|
||||
if err != nil {
|
||||
// Return empty appcast if doesn't exist
|
||||
return &Appcast{
|
||||
Version: "2.0",
|
||||
Xmlns: "http://www.andymatuschak.org/xml-namespaces/sparkle",
|
||||
Channel: Channel{
|
||||
Title: "Eagle0",
|
||||
Link: "https://assets.eagle0.net/mac/appcast.xml",
|
||||
Description: "Eagle0 game updates",
|
||||
Language: "en",
|
||||
Items: []Item{},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
var appcast Appcast
|
||||
err = xml.Unmarshal([]byte(content), &appcast)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse appcast: %w", err)
|
||||
}
|
||||
|
||||
return &appcast, nil
|
||||
}
|
||||
|
||||
func uploadAppcast(bb aws.BucketBasics, appcast *Appcast) error {
|
||||
output, err := xml.MarshalIndent(appcast, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal appcast: %w", err)
|
||||
}
|
||||
|
||||
xmlContent := xml.Header + string(output)
|
||||
return bb.UploadBytesPublic(bucketName, appcastPath, []byte(xmlContent))
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 5 {
|
||||
fmt.Println("Usage: mac_build_handler <app_path> <version> <build_number> <sparkle_private_key_path>")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
appPath := os.Args[1]
|
||||
version := os.Args[2]
|
||||
buildNumber := os.Args[3]
|
||||
privateKeyPath := os.Args[4]
|
||||
|
||||
if _, err := os.Stat(appPath); os.IsNotExist(err) {
|
||||
log.Fatalf("App not found: %s", appPath)
|
||||
}
|
||||
|
||||
bb, err := aws.NewBucketBasics()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Create ZIP of the app
|
||||
zipFileName := fmt.Sprintf("eagle0-%s.zip", version)
|
||||
zipPath := filepath.Join("/tmp", zipFileName)
|
||||
|
||||
log.Printf("Creating ZIP: %s", zipPath)
|
||||
if err := zipApp(appPath, zipPath); err != nil {
|
||||
log.Fatalf("Failed to create ZIP: %v", err)
|
||||
}
|
||||
|
||||
// Get file size
|
||||
fileSize, err := getFileSize(zipPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to get file size: %v", err)
|
||||
}
|
||||
log.Printf("ZIP size: %d bytes", fileSize)
|
||||
|
||||
// Sign the ZIP with Sparkle EdDSA
|
||||
log.Println("Signing ZIP with Sparkle...")
|
||||
signature, err := signWithSparkle(zipPath, privateKeyPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to sign: %v", err)
|
||||
}
|
||||
log.Printf("Signature: %s", signature)
|
||||
|
||||
// Upload ZIP to S3
|
||||
remotePath := buildsRoot + zipFileName
|
||||
log.Printf("Uploading to S3: %s", remotePath)
|
||||
if err := bb.UploadFilePublic(bucketName, remotePath, zipPath); err != nil {
|
||||
log.Fatalf("Failed to upload: %v", err)
|
||||
}
|
||||
|
||||
// Also upload as "latest"
|
||||
latestPath := buildsRoot + "eagle0-latest.zip"
|
||||
log.Printf("Copying to: %s", latestPath)
|
||||
if err := bb.UploadFilePublic(bucketName, latestPath, zipPath); err != nil {
|
||||
log.Fatalf("Failed to upload latest: %v", err)
|
||||
}
|
||||
|
||||
// Update appcast.xml
|
||||
log.Println("Updating appcast.xml...")
|
||||
appcast, err := fetchAppcast(bb)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to fetch appcast: %v", err)
|
||||
}
|
||||
|
||||
// Create new item
|
||||
downloadURL := fmt.Sprintf("https://assets.eagle0.net/%s%s", buildsRoot, zipFileName)
|
||||
newItem := Item{
|
||||
Title: fmt.Sprintf("Version %s", version),
|
||||
PubDate: time.Now().Format(time.RFC1123Z),
|
||||
SparkleVersion: buildNumber,
|
||||
SparkleShortVersion: version,
|
||||
Description: "",
|
||||
Enclosure: Enclosure{
|
||||
URL: downloadURL,
|
||||
Length: fileSize,
|
||||
Type: "application/octet-stream",
|
||||
EdSig: signature,
|
||||
},
|
||||
}
|
||||
|
||||
// Prepend new item (most recent first)
|
||||
appcast.Channel.Items = append([]Item{newItem}, appcast.Channel.Items...)
|
||||
|
||||
// Keep only last 10 versions
|
||||
if len(appcast.Channel.Items) > 10 {
|
||||
appcast.Channel.Items = appcast.Channel.Items[:10]
|
||||
}
|
||||
|
||||
if err := uploadAppcast(bb, appcast); err != nil {
|
||||
log.Fatalf("Failed to upload appcast: %v", err)
|
||||
}
|
||||
|
||||
// Clean up local ZIP
|
||||
os.Remove(zipPath)
|
||||
|
||||
log.Printf("=== Mac build deployed successfully ===")
|
||||
log.Printf("Version: %s (build %s)", version, buildNumber)
|
||||
log.Printf("Download URL: %s", downloadURL)
|
||||
log.Printf("Appcast URL: https://assets.eagle0.net/%s", appcastPath)
|
||||
}
|
||||
@@ -136,24 +136,50 @@ func runWarmup(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to send stream game request: %w", err)
|
||||
}
|
||||
|
||||
// Wait for subscription ack
|
||||
_, err = waitForResponse(stream, func(resp *eagle.UpdateStreamResponse) bool {
|
||||
return resp.GetSubscriptionAck() != nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get subscription ack: %w", err)
|
||||
}
|
||||
log.Println(" Subscription acknowledged")
|
||||
|
||||
// Wait for initial game state with available commands
|
||||
// Note: ActionResultResponse arrives BEFORE SubscriptionAck, so we can't wait for ack first
|
||||
streamingTextCount := 0
|
||||
gotSubscriptionAck := false
|
||||
gameUpdateResp, err := waitForResponse(stream, func(resp *eagle.UpdateStreamResponse) bool {
|
||||
// Track subscription ack but don't require it before ActionResultResponse
|
||||
if resp.GetSubscriptionAck() != nil {
|
||||
gotSubscriptionAck = true
|
||||
log.Println(" Subscription acknowledged")
|
||||
}
|
||||
gu := resp.GetGameUpdate()
|
||||
if gu == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check what type of update this is
|
||||
switch {
|
||||
case gu.GetStreamingTextResponse() != nil:
|
||||
streamingTextCount++
|
||||
if streamingTextCount%100 == 0 {
|
||||
log.Printf(" Received %d streaming text updates so far...", streamingTextCount)
|
||||
}
|
||||
case gu.GetShardokActionResultResponse() != nil:
|
||||
log.Printf(" Got ShardokActionResultResponse")
|
||||
case gu.GetErrorResponse() != nil:
|
||||
log.Printf(" Got ErrorResponse: %v", gu.GetErrorResponse())
|
||||
case gu.GetActionResultResponse() != nil:
|
||||
log.Printf(" Got ActionResultResponse!")
|
||||
default:
|
||||
log.Printf(" Got GameUpdate with no recognized content")
|
||||
}
|
||||
|
||||
ar := gu.GetActionResultResponse()
|
||||
return ar != nil && ar.GetAvailableCommands() != nil
|
||||
if ar == nil {
|
||||
return false
|
||||
}
|
||||
if ar.GetAvailableCommands() == nil {
|
||||
log.Printf(" ActionResultResponse has no AvailableCommands (has %d results)", len(ar.GetActionResultViews()))
|
||||
return false
|
||||
}
|
||||
log.Printf(" Found AvailableCommands with %d provinces", len(ar.GetAvailableCommands().GetCommandsByProvince()))
|
||||
return true
|
||||
})
|
||||
log.Printf(" Total streaming text updates received: %d, got subscription ack: %v", streamingTextCount, gotSubscriptionAck)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get initial game state: %w", err)
|
||||
}
|
||||
@@ -174,12 +200,14 @@ func runWarmup(ctx context.Context) error {
|
||||
|
||||
var improveCmd *eagle.AvailableCommand
|
||||
var provinceID int32
|
||||
var actingHeroID int32
|
||||
|
||||
for pid, provCmds := range commandsByProvince {
|
||||
for _, cmd := range provCmds.GetCommands() {
|
||||
if cmd.GetImproveCommand() != nil {
|
||||
if ic := cmd.GetImproveCommand(); ic != nil {
|
||||
improveCmd = cmd
|
||||
provinceID = pid
|
||||
actingHeroID = ic.GetRecommendedHeroId()
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -200,11 +228,11 @@ func runWarmup(ctx context.Context) error {
|
||||
}
|
||||
// We'll still try to post an Improve command even if not explicitly available
|
||||
} else {
|
||||
log.Printf(" Found Improve command for province %d", provinceID)
|
||||
log.Printf(" Found Improve command for province %d with recommended hero %d", provinceID, actingHeroID)
|
||||
}
|
||||
|
||||
// Post the Improve command
|
||||
log.Println(" Posting Improve command...")
|
||||
log.Printf(" Posting Improve command with token=%d province=%d heroId=%d...", eagleToken, provinceID, actingHeroID)
|
||||
if err := stream.Send(&eagle.UpdateStreamRequest{
|
||||
RequestDetails: &eagle.UpdateStreamRequest_PostCommandRequest{
|
||||
PostCommandRequest: &eagle.PostCommandRequest{
|
||||
@@ -218,7 +246,7 @@ func runWarmup(ctx context.Context) error {
|
||||
SealedValue: &eagle.SelectedCommand_ImproveCommand{
|
||||
ImproveCommand: &eagle.ImproveSelectedCommand{
|
||||
ImprovementType: eaglecommon.ImprovementType_ECONOMY,
|
||||
ActingHeroId: 0, // Default acting hero
|
||||
ActingHeroId: actingHeroID,
|
||||
LockType: false,
|
||||
},
|
||||
},
|
||||
@@ -233,32 +261,58 @@ func runWarmup(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// Step 5: Verify we get ActionResults
|
||||
log.Println("Step 5: Waiting for command response...")
|
||||
log.Println("Step 5: Waiting for command response and collecting results...")
|
||||
|
||||
// Wait for post command response
|
||||
postResp, err := waitForResponse(stream, func(resp *eagle.UpdateStreamResponse) bool {
|
||||
return resp.GetPostCommandResponse() != nil
|
||||
// Track results while waiting for PostCommandResponse
|
||||
// ActionResultResponse arrives as GameUpdate BEFORE PostCommandResponse
|
||||
foundNewRound := false
|
||||
resultCount := 0
|
||||
commandCount := 0
|
||||
postStatus := eagle.PostCommandResponse_UNKNOWN
|
||||
|
||||
_, err = waitForResponse(stream, func(resp *eagle.UpdateStreamResponse) bool {
|
||||
if resp.GetPostCommandResponse() != nil {
|
||||
log.Printf(" Got PostCommandResponse: %v", resp.GetPostCommandResponse().GetStatus())
|
||||
postStatus = resp.GetPostCommandResponse().GetStatus()
|
||||
return true
|
||||
}
|
||||
// Process GameUpdates while waiting - they contain our action results!
|
||||
if gu := resp.GetGameUpdate(); gu != nil {
|
||||
if ar := gu.GetActionResultResponse(); ar != nil {
|
||||
for _, arv := range ar.GetActionResultViews() {
|
||||
resultCount++
|
||||
if arv.GetType() == eaglecommon.ActionResultType_NEW_ROUND_ACTION {
|
||||
foundNewRound = true
|
||||
log.Printf(" Found NEW_ROUND_ACTION (date change)!")
|
||||
}
|
||||
}
|
||||
if ar.GetAvailableCommands() != nil {
|
||||
commandCount = len(ar.GetAvailableCommands().GetCommandsByProvince())
|
||||
log.Printf(" Got %d action results, %d provinces with commands available", len(ar.GetActionResultViews()), commandCount)
|
||||
}
|
||||
}
|
||||
} else if resp.GetSubscriptionAck() != nil {
|
||||
log.Println(" (skipping late SubscriptionAck)")
|
||||
}
|
||||
return false
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get post command response: %w", err)
|
||||
}
|
||||
|
||||
if postResp.GetPostCommandResponse().GetStatus() != eagle.PostCommandResponse_SUCCESS {
|
||||
log.Printf(" Command was rejected: %v", postResp.GetPostCommandResponse().GetStatus())
|
||||
// Continue anyway - the JIT is still warming up
|
||||
} else {
|
||||
if postStatus == eagle.PostCommandResponse_SUCCESS {
|
||||
log.Println(" Command accepted!")
|
||||
} else if postStatus == eagle.PostCommandResponse_BAD_TOKEN {
|
||||
log.Printf(" Command rejected: bad token")
|
||||
} else {
|
||||
log.Printf(" Command status: %v (continuing anyway - JIT warming up)", postStatus)
|
||||
}
|
||||
|
||||
// Collect action results with a timeout
|
||||
log.Println(" Collecting action results...")
|
||||
// Continue collecting any remaining action results with a timeout
|
||||
log.Println(" Collecting any remaining action results...")
|
||||
resultCtx, resultCancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer resultCancel()
|
||||
|
||||
foundNewRound := false
|
||||
resultCount := 0
|
||||
commandCount := 0
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-resultCtx.Done():
|
||||
@@ -306,6 +360,7 @@ done:
|
||||
log.Printf(" Total action results received: %d", resultCount)
|
||||
log.Printf(" Found NEW_ROUND_ACTION (date change): %v", foundNewRound)
|
||||
log.Printf(" New commands available: %d provinces", commandCount)
|
||||
log.Printf(" Post command status: %v", postStatus)
|
||||
|
||||
// Step 6: Drop the game to clean up
|
||||
log.Println("Step 6: Dropping test game...")
|
||||
@@ -333,6 +388,9 @@ done:
|
||||
if resultCount == 0 {
|
||||
return fmt.Errorf("no action results received")
|
||||
}
|
||||
if commandCount == 0 {
|
||||
return fmt.Errorf("no new commands received after posting command")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_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")
|
||||
@@ -57,16 +56,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "hostility_swift_proto",
|
||||
protos = [":hostility_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/protobuf/net/eagle0/eagle/views:__pkg__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "hostility_scala_proto",
|
||||
visibility = [
|
||||
@@ -183,15 +172,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "victory_condition_swift_proto",
|
||||
protos = [":victory_condition_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "victory_condition_scala_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_proto_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("@rules_scala//scala_proto:scala_proto.bzl", "scala_proto_library")
|
||||
@@ -50,26 +49,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "available_command_swift_proto",
|
||||
protos = [":available_command_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:armed_battalion_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:attack_decision_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:captured_hero_option_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:control_weather_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:diplomacy_option_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:prisoner_management_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:province_orders_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:combat_unit_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:improvement_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:tribute_amount_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "available_command_scala_proto",
|
||||
visibility = [
|
||||
@@ -108,16 +87,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "command_swift_proto",
|
||||
protos = [":command_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":available_command_swift_proto",
|
||||
":selected_command_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "command_scala_proto",
|
||||
visibility = [
|
||||
@@ -153,30 +122,6 @@ proto_library(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "selected_command_swift_proto",
|
||||
protos = [":selected_command_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:armed_battalion_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:attack_decision_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:captured_hero_option_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:control_weather_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:diplomacy_option_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:prisoner_management_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:province_orders_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:combat_unit_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_status_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:improvement_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:tribute_amount_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "selected_command_scala_proto",
|
||||
visibility = [
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_proto_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("@rules_scala//scala_proto:scala_proto.bzl", "scala_proto_library")
|
||||
|
||||
swift_proto_library(
|
||||
name = "appropriate_battalions_swift_proto",
|
||||
protos = [":appropriate_battalions_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "appropriate_battalions_scala_proto",
|
||||
visibility = [
|
||||
@@ -32,16 +21,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "armed_battalion_swift_proto",
|
||||
protos = [":armed_battalion_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "armed_battalion_scala_proto",
|
||||
visibility = [
|
||||
@@ -63,16 +42,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "army_stats_swift_proto",
|
||||
protos = [":army_stats_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "army_stats_scala_proto",
|
||||
visibility = [
|
||||
@@ -93,18 +62,6 @@ proto_library(
|
||||
deps = ["//src/main/protobuf/net/eagle0/common:hostility_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "attack_decision_type_swift_proto",
|
||||
protos = [":attack_decision_type_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:tribute_amount_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "attack_decision_type_scala_proto",
|
||||
visibility = [
|
||||
@@ -127,16 +84,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "battalion_with_food_cost_swift_proto",
|
||||
protos = [":battalion_with_food_cost_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "battalion_with_food_cost_scala_proto",
|
||||
visibility = [
|
||||
@@ -158,16 +105,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "captured_hero_option_swift_proto",
|
||||
protos = [":captured_hero_option_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "captured_hero_option_scala_proto",
|
||||
visibility = [
|
||||
@@ -189,16 +126,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "control_weather_type_swift_proto",
|
||||
protos = [":control_weather_type_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "control_weather_type_scala_proto",
|
||||
visibility = [
|
||||
@@ -220,18 +147,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "diplomacy_option_swift_proto",
|
||||
protos = [":diplomacy_option_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "diplomacy_option_scala_proto",
|
||||
visibility = [
|
||||
@@ -254,19 +169,6 @@ proto_library(
|
||||
deps = ["//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "expanded_combat_unit_swift_proto",
|
||||
protos = [":expanded_combat_unit_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/views:battalion_view_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/views:hero_view_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "expanded_combat_unit_scala_proto",
|
||||
visibility = [
|
||||
@@ -292,20 +194,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "expanded_unaffiliated_hero_swift_proto",
|
||||
protos = [":expanded_unaffiliated_hero_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:unaffiliated_hero_quest_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:unaffiliated_hero_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/views:hero_view_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "expanded_unaffiliated_hero_scala_proto",
|
||||
visibility = [
|
||||
@@ -332,16 +220,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "prisoner_management_type_swift_proto",
|
||||
protos = [":prisoner_management_type_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "prisoner_management_type_scala_proto",
|
||||
visibility = [
|
||||
@@ -363,18 +241,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "province_orders_swift_proto",
|
||||
protos = [":province_orders_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_order_type_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "province_orders_scala_proto",
|
||||
visibility = [
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_proto_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("@rules_scala//scala_proto:scala_proto.bzl", "scala_proto_library")
|
||||
@@ -8,19 +7,6 @@ package(default_visibility = [
|
||||
"//src/test/scala/net/eagle0:__subpackages__",
|
||||
])
|
||||
|
||||
swift_proto_library(
|
||||
name = "action_result_notification_details_swift_proto",
|
||||
protos = [":action_result_notification_details_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":profession_swift_proto",
|
||||
":unaffiliated_hero_quest_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "action_result_notification_details_scala_proto",
|
||||
deps = [":action_result_notification_details_proto"],
|
||||
@@ -41,15 +27,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "action_result_type_swift_proto",
|
||||
protos = [":action_result_type_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "action_result_type_scala_proto",
|
||||
deps = [":action_result_type_proto"],
|
||||
@@ -65,15 +42,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "battalion_type_swift_proto",
|
||||
protos = [":battalion_type_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "battalion_type_scala_proto",
|
||||
deps = [":battalion_type_proto"],
|
||||
@@ -89,15 +57,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "beast_info_swift_proto",
|
||||
protos = [":beast_info_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "beast_info_scala_proto",
|
||||
deps = [":beast_info_proto"],
|
||||
@@ -113,16 +72,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "chronicle_entry_swift_proto",
|
||||
protos = [":chronicle_entry_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [":date_swift_proto"],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "chronicle_entry_scala_proto",
|
||||
deps = ["chronicle_entry_proto"],
|
||||
@@ -141,12 +90,18 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "combat_unit_swift_proto",
|
||||
protos = [":combat_unit_proto"],
|
||||
scala_proto_library(
|
||||
name = "command_type_scala_proto",
|
||||
deps = [":command_type_proto"],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "command_type_proto",
|
||||
srcs = [
|
||||
"command_type.proto",
|
||||
],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -166,15 +121,6 @@ proto_library(
|
||||
deps = ["@com_google_protobuf//:wrappers_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "date_swift_proto",
|
||||
protos = [":date_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "date_scala_proto",
|
||||
deps = [":date_proto"],
|
||||
@@ -190,19 +136,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "diplomacy_offer_swift_proto",
|
||||
protos = [":diplomacy_offer_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":date_swift_proto",
|
||||
":diplomacy_offer_status_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "diplomacy_offer_scala_proto",
|
||||
visibility = [
|
||||
@@ -226,15 +159,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "diplomacy_offer_status_swift_proto",
|
||||
protos = [":diplomacy_offer_status_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "diplomacy_offer_status_scala_proto",
|
||||
deps = [":diplomacy_offer_status_proto"],
|
||||
@@ -250,15 +174,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "gender_swift_proto",
|
||||
protos = [":gender_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "gender_scala_proto",
|
||||
deps = [":gender_proto"],
|
||||
@@ -272,18 +187,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "hero_backstory_version_swift_proto",
|
||||
protos = [":hero_backstory_version_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":date_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "hero_backstory_version_scala_proto",
|
||||
deps = [":hero_backstory_version_proto"],
|
||||
@@ -300,15 +203,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "improvement_type_swift_proto",
|
||||
protos = [":improvement_type_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "improvement_type_scala_proto",
|
||||
visibility = [
|
||||
@@ -330,15 +224,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "profession_swift_proto",
|
||||
protos = [":profession_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "profession_scala_proto",
|
||||
deps = [":profession_proto"],
|
||||
@@ -354,19 +239,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "province_event_swift_proto",
|
||||
protos = [":province_event_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":beast_info_swift_proto",
|
||||
":date_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "province_event_scala_proto",
|
||||
deps = [":province_event_proto"],
|
||||
@@ -386,15 +258,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "province_order_type_swift_proto",
|
||||
protos = [":province_order_type_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "province_order_type_scala_proto",
|
||||
deps = [":province_order_type_proto"],
|
||||
@@ -410,18 +273,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "recruitment_info_swift_proto",
|
||||
protos = [":recruitment_info_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":unaffiliated_hero_quest_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "recruitment_info_scala_proto",
|
||||
deps = [":recruitment_info_proto"],
|
||||
@@ -438,15 +289,6 @@ proto_library(
|
||||
deps = [":unaffiliated_hero_quest_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "round_phase_swift_proto",
|
||||
protos = [":round_phase_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "round_phase_scala_proto",
|
||||
deps = [":round_phase_proto"],
|
||||
@@ -462,15 +304,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "tribute_amount_swift_proto",
|
||||
protos = [":tribute_amount_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "tribute_amount_scala_proto",
|
||||
visibility = [
|
||||
@@ -494,16 +327,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "unaffiliated_hero_quest_swift_proto",
|
||||
protos = [":unaffiliated_hero_quest_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [":battalion_type_swift_proto"],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "unaffiliated_hero_quest_scala_proto",
|
||||
deps = [":unaffiliated_hero_quest_proto"],
|
||||
@@ -520,16 +343,6 @@ proto_library(
|
||||
deps = [":battalion_type_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "unaffiliated_hero_type_swift_proto",
|
||||
protos = [":unaffiliated_hero_type_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "unaffiliated_hero_type_scala_proto",
|
||||
deps = [":unaffiliated_hero_type_proto"],
|
||||
@@ -555,6 +368,7 @@ go_proto_library(
|
||||
":beast_info_proto",
|
||||
":chronicle_entry_proto",
|
||||
":combat_unit_proto",
|
||||
":command_type_proto",
|
||||
":date_proto",
|
||||
":diplomacy_offer_proto",
|
||||
":diplomacy_offer_status_proto",
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package net.eagle0.eagle.common.command_type;
|
||||
|
||||
option java_multiple_files = true;
|
||||
option java_package = "net.eagle0.eagle.common.command_type";
|
||||
|
||||
// Enum representing the type of a command, without any command-specific data.
|
||||
// Used to track which command type was last executed on a province.
|
||||
enum CommandType {
|
||||
COMMAND_TYPE_UNKNOWN = 0;
|
||||
COMMAND_TYPE_ALMS = 1;
|
||||
COMMAND_TYPE_APPREHEND_OUTLAW = 2;
|
||||
COMMAND_TYPE_ARM_TROOPS = 3;
|
||||
COMMAND_TYPE_ATTACK_DECISION = 4;
|
||||
COMMAND_TYPE_CONTROL_WEATHER = 5;
|
||||
COMMAND_TYPE_DECLINE_QUEST = 6;
|
||||
COMMAND_TYPE_DEFEND = 7;
|
||||
COMMAND_TYPE_DIPLOMACY = 8;
|
||||
COMMAND_TYPE_DIVINE = 9;
|
||||
COMMAND_TYPE_EXILE_VASSAL = 10;
|
||||
COMMAND_TYPE_FEAST = 11;
|
||||
COMMAND_TYPE_FREE_FOR_ALL_DECISION = 12;
|
||||
COMMAND_TYPE_HANDLE_CAPTURED_HERO = 13;
|
||||
COMMAND_TYPE_HANDLE_RIOT_CRACK_DOWN = 14;
|
||||
COMMAND_TYPE_HANDLE_RIOT_DO_NOTHING = 15;
|
||||
COMMAND_TYPE_HANDLE_RIOT_GIVE = 16;
|
||||
COMMAND_TYPE_HERO_GIFT = 17;
|
||||
COMMAND_TYPE_IMPROVE = 18;
|
||||
COMMAND_TYPE_ISSUE_ORDERS = 19;
|
||||
COMMAND_TYPE_MANAGE_PRISONERS = 20;
|
||||
COMMAND_TYPE_MARCH = 21;
|
||||
COMMAND_TYPE_ORGANIZE_TROOPS = 22;
|
||||
COMMAND_TYPE_PLEASE_RECRUIT_ME = 23;
|
||||
COMMAND_TYPE_RECON = 24;
|
||||
COMMAND_TYPE_RECRUIT_HEROES = 25;
|
||||
COMMAND_TYPE_RESOLVE_ALLIANCE_OFFER = 26;
|
||||
COMMAND_TYPE_RESOLVE_BREAK_ALLIANCE = 27;
|
||||
COMMAND_TYPE_RESOLVE_INVITATION = 28;
|
||||
COMMAND_TYPE_RESOLVE_RANSOM_OFFER = 29;
|
||||
COMMAND_TYPE_RESOLVE_TRUCE_OFFER = 30;
|
||||
COMMAND_TYPE_RESOLVE_TRIBUTE = 31;
|
||||
COMMAND_TYPE_REST = 32;
|
||||
COMMAND_TYPE_RETURN = 33;
|
||||
COMMAND_TYPE_SEND_SUPPLIES = 34;
|
||||
COMMAND_TYPE_START_EPIDEMIC = 35;
|
||||
COMMAND_TYPE_SUPPRESS_BEASTS = 36;
|
||||
COMMAND_TYPE_SWEAR_BROTHERHOOD = 37;
|
||||
COMMAND_TYPE_TRADE = 38;
|
||||
COMMAND_TYPE_TRAIN = 39;
|
||||
COMMAND_TYPE_TRAVEL = 40;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_proto_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("@rules_scala//scala_proto:scala_proto.bzl", "scala_proto_library")
|
||||
@@ -8,31 +7,6 @@ package(default_visibility = [
|
||||
"//src/test/scala/net/eagle0:__subpackages__",
|
||||
])
|
||||
|
||||
swift_proto_library(
|
||||
name = "action_result_swift_proto",
|
||||
protos = [":action_result_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":battalion_swift_proto",
|
||||
":changed_faction_swift_proto",
|
||||
":changed_hero_swift_proto",
|
||||
":changed_province_swift_proto",
|
||||
":faction_swift_proto",
|
||||
":hero_swift_proto",
|
||||
":llm_request_swift_proto",
|
||||
":llm_response_swift_proto",
|
||||
":province_swift_proto",
|
||||
":shardok_battle_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_notification_details_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:chronicle_entry_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:round_phase_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "action_result_scala_proto",
|
||||
deps = [":action_result_proto"],
|
||||
@@ -58,24 +32,13 @@ proto_library(
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:chronicle_entry_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:command_type_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:round_phase_proto",
|
||||
"@com_google_protobuf//:wrappers_proto",
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "army_swift_proto",
|
||||
protos = [":army_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":supplies_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:combat_unit_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_order_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:tribute_amount_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "army_scala_proto",
|
||||
deps = [":army_proto"],
|
||||
@@ -94,15 +57,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "battalion_swift_proto",
|
||||
protos = [":battalion_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "battalion_scala_proto",
|
||||
deps = [":battalion_proto"],
|
||||
@@ -116,12 +70,6 @@ proto_library(
|
||||
deps = ["//src/main/protobuf/net/eagle0/eagle/common:battalion_type_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "battle_revelation_swift_proto",
|
||||
protos = [":battle_revelation_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "battle_revelation_scala_proto",
|
||||
deps = [":battle_revelation_proto"],
|
||||
@@ -134,20 +82,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "changed_faction_swift_proto",
|
||||
protos = [":changed_faction_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":changed_hero_swift_proto",
|
||||
":changed_province_swift_proto",
|
||||
":faction_relationship_swift_proto",
|
||||
":faction_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/views:province_view_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "changed_faction_scala_proto",
|
||||
deps = [
|
||||
@@ -169,16 +103,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "changed_hero_swift_proto",
|
||||
protos = [":changed_hero_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":event_for_hero_backstory_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:profession_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "changed_hero_scala_proto",
|
||||
deps = ["changed_hero_proto"],
|
||||
@@ -196,23 +120,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "changed_province_swift_proto",
|
||||
protos = [":changed_province_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":deferred_change_swift_proto",
|
||||
":province_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:improvement_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_event_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_order_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:army_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:battle_revelation_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:supplies_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:unaffiliated_hero_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "changed_province_scala_proto",
|
||||
deps = ["changed_province_proto"],
|
||||
@@ -237,15 +144,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "client_text_swift_proto",
|
||||
protos = [":client_text_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:llm_request_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "client_text_scala_proto",
|
||||
deps = ["client_text_proto"],
|
||||
@@ -259,12 +157,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "deferred_change_swift_proto",
|
||||
protos = [":deferred_change_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "deferred_change_scala_proto",
|
||||
deps = [":deferred_change_proto"],
|
||||
@@ -275,15 +167,6 @@ proto_library(
|
||||
srcs = ["deferred_change.proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "event_for_chronicle_swift_proto",
|
||||
protos = [":event_for_chronicle_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "event_for_chronicle_scala_proto",
|
||||
deps = [":event_for_chronicle_proto"],
|
||||
@@ -298,19 +181,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "event_for_hero_backstory_swift_proto",
|
||||
protos = [":event_for_hero_backstory_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_status_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:profession_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:unaffiliated_hero_quest_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/views:battalion_view_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "event_for_hero_backstory_scala_proto",
|
||||
deps = [":event_for_hero_backstory_proto"],
|
||||
@@ -328,19 +198,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "faction_swift_proto",
|
||||
protos = [":faction_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":faction_relationship_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_notification_details_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/views:province_view_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "faction_scala_proto",
|
||||
deps = [":faction_proto"],
|
||||
@@ -359,15 +216,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "faction_relationship_swift_proto",
|
||||
protos = [":faction_relationship_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "faction_relationship_scala_proto",
|
||||
deps = [":faction_relationship_proto"],
|
||||
@@ -384,17 +232,6 @@ proto_library(
|
||||
deps = ["//src/main/protobuf/net/eagle0/eagle/common:date_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "game_parameters_swift_proto",
|
||||
protos = [":game_parameters_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_order_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:battalion_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "game_parameters_scala_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -413,18 +250,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "game_swift_proto",
|
||||
protos = [":game_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":action_result_swift_proto",
|
||||
":game_state_swift_proto",
|
||||
":shardok_results_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "game_scala_proto",
|
||||
deps = [":game_proto"],
|
||||
@@ -442,27 +267,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "game_state_swift_proto",
|
||||
protos = [":game_state_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":battalion_swift_proto",
|
||||
":faction_swift_proto",
|
||||
":hero_swift_proto",
|
||||
":llm_request_swift_proto",
|
||||
":llm_response_swift_proto",
|
||||
":province_swift_proto",
|
||||
":run_status_swift_proto",
|
||||
":shardok_battle_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_notification_details_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:chronicle_entry_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:round_phase_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "game_state_scala_proto",
|
||||
deps = [":game_state_proto"],
|
||||
@@ -489,18 +293,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "hero_swift_proto",
|
||||
protos = [":hero_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":event_for_hero_backstory_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:gender_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:hero_backstory_version_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:profession_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "hero_scala_proto",
|
||||
deps = [":hero_proto"],
|
||||
@@ -518,13 +310,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "llm_response_swift_proto",
|
||||
protos = [":llm_response_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [":llm_request_swift_proto"],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "llm_response_scala_proto",
|
||||
deps = [":llm_response_proto"],
|
||||
@@ -540,21 +325,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "llm_request_swift_proto",
|
||||
protos = [":llm_request_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":event_for_chronicle_swift_proto",
|
||||
":event_for_hero_backstory_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_status_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:unaffiliated_hero_quest_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:hero_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/views:battalion_view_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "llm_request_scala_proto",
|
||||
deps = [":llm_request_proto"],
|
||||
@@ -578,27 +348,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "province_swift_proto",
|
||||
protos = [":province_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":army_swift_proto",
|
||||
":battle_revelation_swift_proto",
|
||||
":deferred_change_swift_proto",
|
||||
":supplies_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:improvement_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_event_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_order_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:tribute_amount_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:unaffiliated_hero_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "province_scala_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -616,8 +365,8 @@ proto_library(
|
||||
":deferred_change_proto",
|
||||
":supplies_proto",
|
||||
":unaffiliated_hero_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:command_type_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:improvement_type_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_event_proto",
|
||||
@@ -626,13 +375,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "run_status_swift_proto",
|
||||
protos = [":run_status_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "run_status_scala_proto",
|
||||
deps = [":run_status_proto"],
|
||||
@@ -645,13 +387,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "running_games_swift_proto",
|
||||
protos = [":running_games_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "running_games_scala_proto",
|
||||
deps = [":running_games_proto"],
|
||||
@@ -662,16 +397,6 @@ proto_library(
|
||||
srcs = ["running_games.proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "shardok_battle_swift_proto",
|
||||
protos = [":shardok_battle_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":army_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/common:victory_condition_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "shardok_battle_scala_proto",
|
||||
deps = [":shardok_battle_proto"],
|
||||
@@ -688,17 +413,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "shardok_results_swift_proto",
|
||||
protos = [":shardok_results_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/shardok/api:action_result_view_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/api:command_descriptor_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/storage:action_result_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "shardok_results_scala_proto",
|
||||
deps = [":shardok_results_proto"],
|
||||
@@ -716,14 +430,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "supplies_swift_proto",
|
||||
protos = [":supplies_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "supplies_scala_proto",
|
||||
deps = [":supplies_proto"],
|
||||
@@ -737,20 +443,6 @@ proto_library(
|
||||
deps = ["@com_google_protobuf//:wrappers_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "unaffiliated_hero_swift_proto",
|
||||
protos = [":unaffiliated_hero_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:recruitment_info_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:unaffiliated_hero_type_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "unaffiliated_hero_scala_proto",
|
||||
deps = [":unaffiliated_hero_proto"],
|
||||
|
||||
@@ -12,6 +12,7 @@ import "src/main/protobuf/net/eagle0/eagle/common/action_result_notification_det
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/action_result_type.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/battalion_type.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/chronicle_entry.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/command_type.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/date.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/round_phase.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/internal/battalion.proto";
|
||||
@@ -63,7 +64,9 @@ message ActionResult {
|
||||
|
||||
.google.protobuf.Int32Value province_acted = 17;
|
||||
|
||||
.net.eagle0.eagle.api.SelectedCommand last_command_type_for_acting_province = 28;
|
||||
// Deprecated: Use last_command_type_for_acting_province instead. Kept for backwards compatibility with saved games.
|
||||
.net.eagle0.eagle.api.SelectedCommand deprecated_last_command_type_for_acting_province = 28;
|
||||
.net.eagle0.eagle.common.command_type.CommandType last_command_type_for_acting_province = 43;
|
||||
|
||||
.google.protobuf.Int32Value leader = 18;
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ syntax = "proto3";
|
||||
package net.eagle0.eagle.internal;
|
||||
|
||||
import "google/protobuf/wrappers.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/api/selected_command.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/battalion_type.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/command_type.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/date.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/improvement_type.proto";
|
||||
import "src/main/protobuf/net/eagle0/eagle/common/province_event.proto";
|
||||
@@ -104,7 +104,7 @@ message Province {
|
||||
|
||||
.net.eagle0.eagle.common.Date last_beasts_date = 25;
|
||||
.net.eagle0.eagle.common.Date last_riot_date = 35;
|
||||
.net.eagle0.eagle.api.SelectedCommand last_command = 26;
|
||||
.net.eagle0.eagle.common.command_type.CommandType last_command = 26;
|
||||
|
||||
int32 castle_count = 33;
|
||||
int32 hero_cap = 39;
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_proto_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("@rules_scala//scala_proto:scala_proto.bzl", "scala_proto_library")
|
||||
|
||||
swift_proto_library(
|
||||
name = "action_result_view_swift_proto",
|
||||
protos = [":action_result_view_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_notification_details_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "action_result_view_scala_proto",
|
||||
visibility = [
|
||||
@@ -36,15 +25,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "army_view_swift_proto",
|
||||
protos = [":army_view_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:combat_unit_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "army_view_scala_proto",
|
||||
visibility = [
|
||||
@@ -65,19 +45,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "battalion_view_swift_proto",
|
||||
protos = [":battalion_view_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:__pkg__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "battalion_view_scala_proto",
|
||||
visibility = [
|
||||
@@ -102,15 +69,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "faction_relationship_view_swift_proto",
|
||||
protos = [":faction_relationship_view_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "faction_relationship_view_scala_proto",
|
||||
visibility = [
|
||||
@@ -131,16 +89,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "faction_view_swift_proto",
|
||||
protos = [":faction_view_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":faction_relationship_view_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:diplomacy_offer_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "faction_view_scala_proto",
|
||||
visibility = [
|
||||
@@ -163,23 +111,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "game_state_view_swift_proto",
|
||||
protos = [":game_state_view_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
":battalion_view_swift_proto",
|
||||
":faction_view_swift_proto",
|
||||
":hero_view_swift_proto",
|
||||
":province_view_swift_proto",
|
||||
":shardok_battle_view_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:chronicle_entry_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:round_phase_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "game_state_view_scala_proto",
|
||||
visibility = [
|
||||
@@ -208,20 +139,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "hero_view_swift_proto",
|
||||
protos = [":hero_view_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":stat_with_condition_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:gender_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:profession_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "hero_view_scala_proto",
|
||||
visibility = [
|
||||
@@ -247,13 +164,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "incoming_army_view_swift_proto",
|
||||
protos = [":incoming_army_view_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [":battalion_view_swift_proto"],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "incoming_army_view_scala_proto",
|
||||
visibility = [
|
||||
@@ -270,27 +180,6 @@ proto_library(
|
||||
deps = [":battalion_view_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "province_view_swift_proto",
|
||||
protos = [":province_view_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":army_view_swift_proto",
|
||||
":battalion_view_swift_proto",
|
||||
":incoming_army_view_swift_proto",
|
||||
":stat_with_condition_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:date_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:profession_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_event_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_order_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:recruitment_info_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:unaffiliated_hero_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "province_view_scala_proto",
|
||||
visibility = [
|
||||
@@ -323,13 +212,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "stat_with_condition_swift_proto",
|
||||
protos = [":stat_with_condition_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "stat_with_condition_scala_proto",
|
||||
visibility = [
|
||||
@@ -349,15 +231,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "shardok_battle_view_swift_proto",
|
||||
protos = [":shardok_battle_view_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/common:hostility_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "shardok_battle_view_scala_proto",
|
||||
visibility = [
|
||||
|
||||
@@ -1,23 +1,8 @@
|
||||
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_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")
|
||||
|
||||
swift_proto_library(
|
||||
name = "action_result_view_swift_proto",
|
||||
protos = [":action_result_view_proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":game_state_view_swift_proto",
|
||||
":odds_view_swift_proto",
|
||||
":unit_view_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:action_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:coords_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:game_status_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "action_result_view_scala_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -42,18 +27,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "command_descriptor_swift_proto",
|
||||
protos = [":command_descriptor_proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":odds_view_swift_proto",
|
||||
":roll_request_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:command_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:coords_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "command_descriptor_scala_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -82,20 +55,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "game_state_view_swift_proto",
|
||||
protos = [":game_state_view_proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":unit_view_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:game_status_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:hex_map_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:player_info_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:tile_modifier_with_coords_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:weather_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "game_state_view_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -119,13 +78,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "odds_view_swift_proto",
|
||||
protos = [":odds_view_proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":unit_view_swift_proto"],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "odds_view_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -153,16 +105,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "roll_request_swift_proto",
|
||||
protos = [":roll_request_proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":odds_view_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:command_type_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "roll_request_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -179,17 +121,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "unit_view_swift_proto",
|
||||
protos = [":unit_view_proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:command_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:coords_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:hostility_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "unit_view_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_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")
|
||||
|
||||
swift_proto_library(
|
||||
name = "action_type_swift_proto",
|
||||
protos = [":action_type_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "action_type_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -26,16 +15,6 @@ proto_library(
|
||||
visibility = ["//src/main/protobuf/net/eagle0/shardok:__subpackages__"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "command_type_swift_proto",
|
||||
protos = [":command_type_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "command_type_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -48,16 +27,6 @@ proto_library(
|
||||
visibility = ["//src/main/protobuf/net/eagle0/shardok:__subpackages__"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "coords_swift_proto",
|
||||
protos = [":coords_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "coords_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -70,16 +39,6 @@ proto_library(
|
||||
visibility = ["//src/main/protobuf/net/eagle0/shardok:__subpackages__"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "game_status_swift_proto",
|
||||
protos = [":game_status_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [":victory_condition_swift_proto"],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "game_status_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -93,21 +52,6 @@ proto_library(
|
||||
deps = [":victory_condition_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "hex_map_swift_proto",
|
||||
protos = [":hex_map_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":coords_swift_proto",
|
||||
":hex_map_direction_swift_proto",
|
||||
":terrain_swift_proto",
|
||||
":tile_modifier_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "hex_map_scala_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -134,16 +78,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "hex_map_direction_swift_proto",
|
||||
protos = [":hex_map_direction_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "hex_map_direction_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -156,16 +90,6 @@ proto_library(
|
||||
visibility = ["//src/main/protobuf/net/eagle0/shardok:__subpackages__"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "hostility_swift_proto",
|
||||
protos = [":hostility_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "hostility_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -178,16 +102,6 @@ proto_library(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "player_info_swift_proto",
|
||||
protos = [":player_info_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [":victory_condition_swift_proto"],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "player_info_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -205,16 +119,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "terrain_swift_proto",
|
||||
protos = [":terrain_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [":tile_modifier_swift_proto"],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "terrain_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -234,16 +138,6 @@ proto_library(
|
||||
deps = [":tile_modifier_proto"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "tile_modifier_swift_proto",
|
||||
protos = [":tile_modifier_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "tile_modifier_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -265,19 +159,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "tile_modifier_with_coords_swift_proto",
|
||||
protos = [":tile_modifier_with_coords_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":coords_swift_proto",
|
||||
":tile_modifier_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "tile_modifier_with_coords_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -294,16 +175,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "victory_condition_swift_proto",
|
||||
protos = [":victory_condition_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "victory_condition_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -316,16 +187,6 @@ proto_library(
|
||||
visibility = ["//src/main/protobuf/net/eagle0/shardok:__subpackages__"],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "weather_swift_proto",
|
||||
protos = [":weather_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0:__subpackages__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [":hex_map_direction_swift_proto"],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "weather_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
|
||||
@@ -1,26 +1,8 @@
|
||||
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_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")
|
||||
|
||||
swift_proto_library(
|
||||
name = "action_result_swift_proto",
|
||||
protos = [":action_result_proto"],
|
||||
visibility = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:__pkg__",
|
||||
"//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":odds_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:action_type_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:coords_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:game_status_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:tile_modifier_with_coords_swift_proto",
|
||||
"//src/main/protobuf/net/eagle0/shardok/common:weather_swift_proto",
|
||||
],
|
||||
)
|
||||
|
||||
scala_proto_library(
|
||||
name = "action_result_scala_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -67,12 +49,6 @@ proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
swift_proto_library(
|
||||
name = "odds_swift_proto",
|
||||
protos = [":odds_proto"],
|
||||
visibility = ["//src/main/swift/net/eagle0/EagleGameHistoryViewer:__subpackages__"],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "odds_cc_proto",
|
||||
visibility = ["//visibility:public"],
|
||||
|
||||
@@ -154,7 +154,6 @@ scala_library(
|
||||
":ai_client_utils",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:battalion_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:command_selection",
|
||||
|
||||
@@ -17,6 +17,7 @@ scala_library(
|
||||
deps = [
|
||||
":game_history",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/views:action_result_view_scala_proto",
|
||||
@@ -44,6 +45,7 @@ scala_library(
|
||||
":round_phase_advancer",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/views:action_result_view_scala_proto",
|
||||
@@ -73,8 +75,11 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_type_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command/available:one_province_available_commands_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command/selected:selected_command_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
@@ -170,6 +175,7 @@ scala_library(
|
||||
name = "round_phase_advancer",
|
||||
srcs = ["RoundPhaseAdvancer.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:round_phase_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
|
||||
@@ -23,7 +23,10 @@ import net.eagle0.eagle.library.util.EagleRequire.internalRequire
|
||||
import net.eagle0.eagle.library.EngineImpl.{appliedResults, appliedResultsScala, withUpdateChecks}
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.proto_converters.command.available.OneProvinceAvailableCommandsConverter
|
||||
import net.eagle0.eagle.model.proto_converters.command.selected.SelectedCommandConverter
|
||||
import net.eagle0.eagle.model.proto_converters.game_state.GameStateConverter
|
||||
import net.eagle0.eagle.model.state.command.available.AvailableCommand as ScalaAvailableCommand
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.shardok_interface.{BattleResolution, BattleUpdate}
|
||||
import net.eagle0.eagle.views.action_result_view.ActionResultView
|
||||
@@ -286,34 +289,38 @@ case class EngineImpl(
|
||||
selectedProvinceId: ProvinceId,
|
||||
selectedCommand: SelectedCommand
|
||||
): EngineAndResults = {
|
||||
val maybeAvailableCommands = getAvailablePlayerCommands(factionId)
|
||||
// Get Scala commands directly from factory
|
||||
val scalaCommandsByProvince =
|
||||
availableCommandsFactory.availablePlayerCommands(currentState, factionId)
|
||||
|
||||
commandRequire(
|
||||
maybeAvailableCommands.nonEmpty,
|
||||
scalaCommandsByProvince.nonEmpty,
|
||||
s"Attempted to post a command for faction $factionId, but there are none"
|
||||
)
|
||||
|
||||
val availableCommands = maybeAvailableCommands.get
|
||||
|
||||
commandRequire(
|
||||
availableCommands.commandsByProvince.contains(selectedProvinceId),
|
||||
s"Attempted to select province $selectedProvinceId out of ${availableCommands.commandsByProvince.keys}"
|
||||
scalaCommandsByProvince.contains(selectedProvinceId),
|
||||
s"Attempted to select province $selectedProvinceId out of ${scalaCommandsByProvince.keys}"
|
||||
)
|
||||
|
||||
val availableCommandsForProvince =
|
||||
availableCommands.commandsByProvince(selectedProvinceId)
|
||||
val scalaCommandsForProvince = scalaCommandsByProvince(selectedProvinceId)
|
||||
|
||||
val availableCommandOpt = AvailableCommandTypeMap.matchingAvailableCommand(
|
||||
availableCommandsForProvince.commands,
|
||||
selectedCommand
|
||||
// Convert proto SelectedCommand to Scala
|
||||
val scalaSelectedCommand = SelectedCommandConverter.fromProto(selectedCommand)
|
||||
|
||||
// Match using CommandType
|
||||
val scalaAvailableCommandOpt = AvailableCommandTypeMap.matchingAvailableCommand(
|
||||
scalaCommandsForProvince.commands,
|
||||
scalaSelectedCommand
|
||||
)
|
||||
commandRequire(
|
||||
availableCommandOpt.isDefined,
|
||||
scalaAvailableCommandOpt.isDefined,
|
||||
s"No matching available command for selected command $selectedCommand"
|
||||
)
|
||||
val availableCommand = availableCommandOpt.get
|
||||
val scalaAvailableCommand = scalaAvailableCommandOpt.get
|
||||
|
||||
val sequencer = RandomStateSequencer(
|
||||
val commandType = scalaSelectedCommand.commandType
|
||||
val sequencer = RandomStateSequencer(
|
||||
initialState = this.currentState,
|
||||
actionResultApplier = ActionResultApplierImpl(Some(ScalaRuntimeValidator)),
|
||||
functionalRandom = SeededRandom(this.currentState.randomSeed)
|
||||
@@ -322,10 +329,10 @@ case class EngineImpl(
|
||||
commandFactory.makeTCommand(
|
||||
actingFactionId = factionId,
|
||||
gameState = gs,
|
||||
availableCommand = availableCommand,
|
||||
selectedCommand = selectedCommand
|
||||
availableCommand = scalaAvailableCommand,
|
||||
selectedCommand = scalaSelectedCommand
|
||||
),
|
||||
selectedCommand = selectedCommand
|
||||
commandType = commandType
|
||||
).withProtolessSequentialResultsAction(gs => HeroBackstoryUpdateActionGenerator(gs))
|
||||
|
||||
// Validate that the first result has an acting faction set (required for player commands)
|
||||
|
||||
@@ -54,12 +54,12 @@ scala_library(
|
||||
deps = [
|
||||
":province_update_helpers",
|
||||
":province_update_helpers2",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library:eagle_internal_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:eagle_require",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province/concrete",
|
||||
@@ -155,13 +155,13 @@ scala_library(
|
||||
":game_state_hero_extensions",
|
||||
":game_state_misc_extensions",
|
||||
":game_state_province_extensions",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_faction_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
],
|
||||
deps = [
|
||||
@@ -171,7 +171,6 @@ scala_library(
|
||||
":game_state_hero_extensions",
|
||||
":game_state_misc_extensions",
|
||||
":game_state_province_extensions",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:extra_xp_for_stat_bump_over100",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:xp_for_stat_bump",
|
||||
@@ -180,6 +179,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_hero_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
],
|
||||
)
|
||||
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
package net.eagle0.eagle.library.actions.applier
|
||||
|
||||
import net.eagle0.eagle.*
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.library.util.EagleRequire.internalRequire
|
||||
import net.eagle0.eagle.library.EagleInternalException
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.changed_province.ChangedProvinceT
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.province.concrete.ProvinceC
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
@@ -79,10 +79,10 @@ object GameStateProvinceExtensions {
|
||||
|
||||
def applyLastCommand(
|
||||
provinceId: Option[ProvinceId],
|
||||
lastCommand: Option[SelectedCommand]
|
||||
lastCommand: Option[CommandType]
|
||||
): GameState =
|
||||
provinceId
|
||||
.filter(_ => lastCommand.exists(!_.isEmpty))
|
||||
.filter(_ => lastCommand.isDefined)
|
||||
.map { pid =>
|
||||
val province = gameState.provinces(pid) match {
|
||||
case p: ProvinceC => p
|
||||
|
||||
+18
-63
@@ -7,11 +7,10 @@ import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
import net.eagle0.eagle.library.util.faction_utils.FactionUtils
|
||||
import net.eagle0.eagle.library.util.province.ProvinceUtils
|
||||
import net.eagle0.eagle.library.util.IncomingArmyUtils
|
||||
import net.eagle0.eagle.model.proto_converters.command.selected.SelectedCommandConverter
|
||||
import net.eagle0.eagle.model.state.command.available.AvailableCommand
|
||||
import net.eagle0.eagle.model.state.command.available.AvailableCommand.*
|
||||
import net.eagle0.eagle.model.state.command.available.OneProvinceAvailableCommands
|
||||
import net.eagle0.eagle.model.state.command.selected.SelectedCommand
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.model.state.province.ProvinceT
|
||||
import net.eagle0.eagle.model.state.RoundPhase
|
||||
@@ -19,66 +18,25 @@ import net.eagle0.eagle.model.state.RoundPhase.*
|
||||
|
||||
object AvailableCommandsFactory {
|
||||
|
||||
/** Command types that should not suggest a follow-up of the same type. */
|
||||
private val noFollowCommands: Set[CommandType] = Set(
|
||||
CommandType.March,
|
||||
CommandType.Diplomacy,
|
||||
CommandType.Rest,
|
||||
CommandType.Trade,
|
||||
CommandType.ArmTroops,
|
||||
CommandType.OrganizeTroops,
|
||||
CommandType.ExileVassal,
|
||||
CommandType.SwearBrotherhood
|
||||
)
|
||||
|
||||
/** Returns true if after executing `last`, the UI should suggest `next` as a follow-up. */
|
||||
def shouldFollow(
|
||||
last: SelectedCommand,
|
||||
last: CommandType,
|
||||
next: AvailableCommand
|
||||
): Boolean = (last, next) match {
|
||||
case (_: SelectedCommand.MarchSelected, _) => false
|
||||
case (_: SelectedCommand.DiplomacySelected, _) => false
|
||||
case (SelectedCommand.RestSelected, _) => false
|
||||
case (_: SelectedCommand.TradeSelected, _) => false
|
||||
case (_: SelectedCommand.ArmTroopsSelected, _) => false
|
||||
case (_: SelectedCommand.OrganizeTroopsSelected, _) => false
|
||||
case (_: SelectedCommand.ExileVassalSelected, _) => false
|
||||
case (_: SelectedCommand.SwearBrotherhoodSelected, _) => false
|
||||
case (last, next) => commandTypesMatch(last, next)
|
||||
}
|
||||
|
||||
/** Compares ordinal values to check if the selected and available commands are the same type. */
|
||||
private def commandTypesMatch(selected: SelectedCommand, available: AvailableCommand): Boolean =
|
||||
(selected, available) match {
|
||||
case (_: SelectedCommand.AlmsSelected, _: AlmsAvailable) => true
|
||||
case (_: SelectedCommand.ApprehendOutlawSelected, _: ApprehendOutlawAvailable) => true
|
||||
case (_: SelectedCommand.ArmTroopsSelected, _: ArmTroopsAvailable) => true
|
||||
case (_: SelectedCommand.AttackDecisionSelected, _: AttackDecisionAvailable) => true
|
||||
case (_: SelectedCommand.ControlWeatherSelected, _: ControlWeatherAvailable) => true
|
||||
case (_: SelectedCommand.DeclineQuestSelected, _: DeclineQuestAvailable) => true
|
||||
case (_: SelectedCommand.DefendSelected, _: DefendAvailable) => true
|
||||
case (_: SelectedCommand.DiplomacySelected, _: DiplomacyAvailable) => true
|
||||
case (_: SelectedCommand.DivineSelected, _: DivineAvailable) => true
|
||||
case (_: SelectedCommand.ExileVassalSelected, _: ExileVassalAvailable) => true
|
||||
case (SelectedCommand.FeastSelected, _: FeastAvailable) => true
|
||||
case (_: SelectedCommand.FreeForAllDecisionSelected, _: FreeForAllDecisionAvailable) => true
|
||||
case (_: SelectedCommand.HandleCapturedHeroSelected, _: HandleCapturedHeroAvailable) => true
|
||||
case (_: SelectedCommand.HandleRiotCrackDownSelected, _: HandleRiotCrackDownAvailable) => true
|
||||
case (SelectedCommand.HandleRiotDoNothingSelected, _: HandleRiotDoNothingAvailable) => true
|
||||
case (_: SelectedCommand.HandleRiotGiveSelected, _: HandleRiotGiveAvailable) => true
|
||||
case (_: SelectedCommand.HeroGiftSelected, _: HeroGiftAvailable) => true
|
||||
case (_: SelectedCommand.ImproveSelected, _: ImproveAvailable) => true
|
||||
case (_: SelectedCommand.IssueOrdersSelected, _: IssueOrdersAvailable) => true
|
||||
case (_: SelectedCommand.ManagePrisonersSelected, _: ManagePrisonersAvailable) => true
|
||||
case (_: SelectedCommand.MarchSelected, _: MarchAvailable) => true
|
||||
case (_: SelectedCommand.OrganizeTroopsSelected, _: OrganizeTroopsAvailable) => true
|
||||
case (_: SelectedCommand.PleaseRecruitMeSelected, _: PleaseRecruitMeAvailable) => true
|
||||
case (_: SelectedCommand.ReconSelected, _: ReconAvailable) => true
|
||||
case (_: SelectedCommand.RecruitHeroesSelected, _: RecruitHeroesAvailable) => true
|
||||
case (_: SelectedCommand.ResolveAllianceOfferSelected, _: ResolveAllianceOfferAvailable) => true
|
||||
case (_: SelectedCommand.ResolveBreakAllianceSelected, _: ResolveBreakAllianceAvailable) => true
|
||||
case (_: SelectedCommand.ResolveInvitationSelected, _: ResolveInvitationAvailable) => true
|
||||
case (_: SelectedCommand.ResolveRansomOfferSelected, _: ResolveRansomOfferAvailable) => true
|
||||
case (_: SelectedCommand.ResolveTruceOfferSelected, _: ResolveTruceOfferAvailable) => true
|
||||
case (_: SelectedCommand.ResolveTributeSelected, _: ResolveTributeAvailable) => true
|
||||
case (SelectedCommand.RestSelected, _: RestAvailable) => true
|
||||
case (SelectedCommand.ReturnSelected, _: ReturnAvailable) => true
|
||||
case (_: SelectedCommand.SendSuppliesSelected, _: SendSuppliesAvailable) => true
|
||||
case (_: SelectedCommand.StartEpidemicSelected, _: StartEpidemicAvailable) => true
|
||||
case (_: SelectedCommand.SuppressBeastsSelected, _: SuppressBeastsAvailable) => true
|
||||
case (_: SelectedCommand.SwearBrotherhoodSelected, _: SwearBrotherhoodAvailable) => true
|
||||
case (_: SelectedCommand.TradeSelected, _: TradeAvailable) => true
|
||||
case (_: SelectedCommand.TrainSelected, _: TrainAvailable) => true
|
||||
case _ => false
|
||||
}
|
||||
): Boolean =
|
||||
if noFollowCommands.contains(last) then false
|
||||
else last == next.commandType
|
||||
|
||||
def suggestedProvinceId(
|
||||
fid: FactionId,
|
||||
@@ -210,10 +168,7 @@ class AvailableCommandsFactory(
|
||||
): Int =
|
||||
commands.zipWithIndex.find {
|
||||
case (ac, _) =>
|
||||
province.lastCommand.forall { lastProto =>
|
||||
val last = SelectedCommandConverter.fromProto(lastProto)
|
||||
AvailableCommandsFactory.shouldFollow(last, ac)
|
||||
}
|
||||
province.lastCommand.forall(last => AvailableCommandsFactory.shouldFollow(last, ac))
|
||||
}
|
||||
.map(_._2)
|
||||
.getOrElse(0)
|
||||
|
||||
@@ -71,10 +71,9 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:incoming_army_utils",
|
||||
"//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/model/proto_converters/command/selected:selected_command_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:round_phase",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/selected",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
],
|
||||
|
||||
@@ -444,9 +444,11 @@ scala_library(
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/applier:action_result_applier",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:available_command_type_map",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:handle_riot_utils",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:t_command_factory",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:action_with_resulting_state",
|
||||
@@ -460,6 +462,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command/available:available_command_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command/selected:selected_command_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:round_phase",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
@@ -1306,11 +1309,13 @@ scala_library(
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:province_order_type_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
"//src/main/scala/net/eagle0/common:more_option",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/applier:action_result_applier",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:available_command_type_map",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:t_command_factory",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_random_sequential_results_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:t_command",
|
||||
@@ -1321,6 +1326,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command/available:available_command_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command/selected:selected_command_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
@@ -1344,9 +1350,11 @@ scala_library(
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/applier:action_result_applier",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:available_command_type_map",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:t_command_factory",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:protoless_random_sequential_results_action",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:t_command",
|
||||
@@ -1356,6 +1364,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command/available:available_command_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command/selected:selected_command_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
|
||||
+5
-4
@@ -52,11 +52,12 @@ case class EndHandleRiotsPhaseAction(
|
||||
)
|
||||
.continue {
|
||||
case (Some(cs), nextFr) =>
|
||||
val cmd = commandFactory.makeTCommand(
|
||||
actingFactionId = province.rulingFactionId.get,
|
||||
val scalaCs = cs.toScala(opac.commands)
|
||||
val cmd = commandFactory.makeTCommand(
|
||||
actingFactionId = scalaCs.actingFactionId,
|
||||
gameState = gs,
|
||||
availableCommand = cs.available,
|
||||
selectedCommand = cs.selected
|
||||
availableCommand = scalaCs.available,
|
||||
selectedCommand = scalaCs.selected
|
||||
)
|
||||
cmd match {
|
||||
case TCommand.Simple(action) =>
|
||||
|
||||
+5
-4
@@ -50,11 +50,12 @@ case class PerformVassalCommandsPhaseAction(
|
||||
sequencer.withRandomActionResults { (gs, fr) =>
|
||||
chooseCommand(gs, province.id, fr).continue {
|
||||
case (Some(cs), nextFr) =>
|
||||
val cmd = commandFactory.makeTCommand(
|
||||
actingFactionId = cs.actingFactionId,
|
||||
val scalaCs = cs.toScala(opac.commands)
|
||||
val cmd = commandFactory.makeTCommand(
|
||||
actingFactionId = scalaCs.actingFactionId,
|
||||
gameState = gs,
|
||||
availableCommand = cs.available,
|
||||
selectedCommand = cs.selected
|
||||
availableCommand = scalaCs.available,
|
||||
selectedCommand = scalaCs.selected
|
||||
)
|
||||
cmd match {
|
||||
case TCommand.Simple(action) =>
|
||||
|
||||
+5
-4
@@ -50,11 +50,12 @@ case class PerformVassalDefenseDecisionsAction(
|
||||
}
|
||||
chooseCommand(gs, province.id, protoCommands, fr).continue {
|
||||
case (Some(cs), nextFr) =>
|
||||
val cmd = commandFactory.makeTCommand(
|
||||
actingFactionId = cs.actingFactionId,
|
||||
val scalaCs = cs.toScala(opac.commands)
|
||||
val cmd = commandFactory.makeTCommand(
|
||||
actingFactionId = scalaCs.actingFactionId,
|
||||
gameState = gs,
|
||||
availableCommand = cs.available,
|
||||
selectedCommand = cs.selected
|
||||
availableCommand = scalaCs.available,
|
||||
selectedCommand = scalaCs.selected
|
||||
)
|
||||
cmd match {
|
||||
case TCommand.Simple(action) =>
|
||||
|
||||
+6
-7
@@ -1,17 +1,16 @@
|
||||
package net.eagle0.eagle.library.actions
|
||||
package impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.*
|
||||
import net.eagle0.eagle.api.selected_command.*
|
||||
import net.eagle0.eagle.model.state.command.available.AvailableCommand
|
||||
import net.eagle0.eagle.model.state.command.selected.SelectedCommand
|
||||
|
||||
object AvailableCommandTypeMap {
|
||||
def matchingAvailableCommand(
|
||||
acs: Iterable[AvailableCommand],
|
||||
sc: SelectedCommand
|
||||
availableCommands: Iterable[AvailableCommand],
|
||||
selectedCommand: SelectedCommand
|
||||
): Option[AvailableCommand] =
|
||||
acs.find(ac => matches(ac, sc))
|
||||
availableCommands.find(_.commandType == selectedCommand.commandType)
|
||||
|
||||
// This is pretty hacky but avoids a long match that has to be kept up to date.
|
||||
def matches(ac: AvailableCommand, sc: SelectedCommand): Boolean =
|
||||
ac.asMessage.sealedValue.number == sc.asMessage.sealedValue.number
|
||||
ac.commandType == sc.commandType
|
||||
}
|
||||
|
||||
@@ -9,12 +9,14 @@ scala_library(
|
||||
],
|
||||
exports = [
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:t_command",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/selected",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/common:t_command",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/selected",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
],
|
||||
)
|
||||
@@ -71,10 +73,6 @@ scala_library(
|
||||
":trade_command",
|
||||
":train_command",
|
||||
":travel_command",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:control_weather_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:province_orders_scala_proto",
|
||||
"//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:eagle_internal_exception",
|
||||
@@ -90,25 +88,14 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:action_result_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_battalion_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/concrete:changed_hero_concrete",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_type_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_type_id_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:combat_unit_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:improvement_type_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:proto_conversion_exception",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:tribute_amount_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:unaffiliated_hero_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/diplomacy_offer",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/diplomacy_offer/status",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/diplomacy_option",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/province:order_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:combat_unit",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:improvement_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:tribute_amount",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/common",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/selected",
|
||||
"//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/diplomacy_option",
|
||||
@@ -223,8 +210,8 @@ scala_library(
|
||||
"//src/test/scala/net/eagle0/eagle:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/selected",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
+307
-429
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
package net.eagle0.eagle.library.actions.impl.command
|
||||
|
||||
import net.eagle0.eagle.api.available_command.AvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.library.actions.impl.common.TCommand
|
||||
import net.eagle0.eagle.model.state.command.available.AvailableCommand
|
||||
import net.eagle0.eagle.model.state.command.selected.SelectedCommand
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import net.eagle0.eagle.FactionId
|
||||
|
||||
|
||||
+4
-4
@@ -1,7 +1,6 @@
|
||||
package net.eagle0.eagle.library.actions.random_state_sequencer
|
||||
|
||||
import net.eagle0.common.{FunctionalRandom, RandomState}
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.library.actions.applier.{ActionResultApplier, ActionResultWithResultingState}
|
||||
import net.eagle0.eagle.library.actions.impl.common.{
|
||||
ProtolessRandomSimpleAction,
|
||||
@@ -10,6 +9,7 @@ import net.eagle0.eagle.library.actions.impl.common.{
|
||||
TCommand
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.ActionResultT
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
|
||||
/**
|
||||
@@ -87,7 +87,7 @@ trait RandomStateSequencer {
|
||||
*/
|
||||
def withTCommandAndLastCommand(
|
||||
commandGen: GameState => TCommand,
|
||||
selectedCommand: SelectedCommand
|
||||
commandType: CommandType
|
||||
): RandomStateSequencer
|
||||
}
|
||||
|
||||
@@ -189,10 +189,10 @@ private case class RandomStateSequencerImpl(
|
||||
|
||||
override def withTCommandAndLastCommand(
|
||||
commandGen: GameState => TCommand,
|
||||
selectedCommand: SelectedCommand
|
||||
commandType: CommandType
|
||||
): RandomStateSequencer = {
|
||||
def wrapWithLastCommand(result: ActionResultT): ActionResultT =
|
||||
result.withLastCommandTypeForActingProvince(selectedCommand)
|
||||
result.withLastCommandTypeForActingProvince(commandType)
|
||||
|
||||
commandGen(lastState) match {
|
||||
case TCommand.Simple(action) =>
|
||||
|
||||
@@ -127,6 +127,10 @@ scala_library(
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/command:available_command_type_map",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command/selected:selected_command_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/selected",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -1,16 +1,58 @@
|
||||
package net.eagle0.eagle.library.util
|
||||
|
||||
import net.eagle0.eagle.{FactionId, ProvinceId}
|
||||
import net.eagle0.eagle.api.available_command.AvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.api.available_command.AvailableCommand as ProtoAvailableCommand
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand as ProtoSelectedCommand
|
||||
import net.eagle0.eagle.library.actions.impl.command.AvailableCommandTypeMap
|
||||
import net.eagle0.eagle.model.proto_converters.command.selected.SelectedCommandConverter
|
||||
import net.eagle0.eagle.model.state.command.available.AvailableCommand
|
||||
import net.eagle0.eagle.model.state.command.selected.SelectedCommand
|
||||
|
||||
// Proto-based command selection (legacy, for gradual migration)
|
||||
case class CommandSelection(
|
||||
actingFactionId: FactionId,
|
||||
actingProvinceId: ProvinceId,
|
||||
available: ProtoAvailableCommand,
|
||||
selected: ProtoSelectedCommand,
|
||||
reason: String
|
||||
) {
|
||||
def withReason(reason: String): CommandSelection =
|
||||
this.copy(reason = reason)
|
||||
|
||||
/**
|
||||
* Converts this proto-based CommandSelection to a ScalaCommandSelection.
|
||||
* @param scalaCommands
|
||||
* The Scala available commands to match against
|
||||
* @return
|
||||
* ScalaCommandSelection with Scala types, or throws if no matching available command found
|
||||
*/
|
||||
def toScala(scalaCommands: Vector[AvailableCommand]): ScalaCommandSelection = {
|
||||
val scalaSelected = SelectedCommandConverter.fromProto(selected)
|
||||
val scalaAvailable = AvailableCommandTypeMap
|
||||
.matchingAvailableCommand(scalaCommands, scalaSelected)
|
||||
.getOrElse(
|
||||
throw new IllegalStateException(
|
||||
s"No matching Scala available command for selected command: ${scalaSelected.commandType}"
|
||||
)
|
||||
)
|
||||
ScalaCommandSelection(
|
||||
actingFactionId = actingFactionId,
|
||||
actingProvinceId = actingProvinceId,
|
||||
available = scalaAvailable,
|
||||
selected = scalaSelected,
|
||||
reason = reason
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Scala-based command selection
|
||||
case class ScalaCommandSelection(
|
||||
actingFactionId: FactionId,
|
||||
actingProvinceId: ProvinceId,
|
||||
available: AvailableCommand,
|
||||
selected: SelectedCommand,
|
||||
reason: String
|
||||
) {
|
||||
def withReason(reason: String): CommandSelection =
|
||||
def withReason(reason: String): ScalaCommandSelection =
|
||||
this.copy(reason = reason)
|
||||
}
|
||||
|
||||
@@ -188,6 +188,7 @@ scala_library(
|
||||
":ransom_offer_helpers",
|
||||
"//src/main/protobuf/net/eagle0/common:hostility_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:armed_battalion_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:battalion_with_food_cost_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
@@ -260,7 +261,6 @@ scala_library(
|
||||
":province_gold_surplus_calculator",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:max_combat_unit_count_per_side",
|
||||
@@ -395,7 +395,6 @@ scala_library(
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:battalion_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:command_selection",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util/battalion_type_finder",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package net.eagle0.eagle.model.action_result
|
||||
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, HeroId, ProvinceId, RoundId}
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.model.action_result.changed_province.ChangedProvinceT
|
||||
import net.eagle0.eagle.model.action_result.generated_text_request.GeneratedTextRequestT
|
||||
import net.eagle0.eagle.model.action_result.types.ActionResultType
|
||||
import net.eagle0.eagle.model.state.battalion.BattalionT
|
||||
import net.eagle0.eagle.model.state.chronicle_entry.ChronicleEntry
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.faction.FactionT
|
||||
import net.eagle0.eagle.model.state.hero.HeroT
|
||||
@@ -29,7 +29,7 @@ trait ActionResultT {
|
||||
def newRoundId: Option[RoundId]
|
||||
def newDate: Option[Date]
|
||||
|
||||
def lastCommandTypeForActingProvince: Option[SelectedCommand]
|
||||
def lastCommandTypeForActingProvince: Option[CommandType]
|
||||
|
||||
def newBattle: Option[ShardokBattle]
|
||||
def resolvedBattle: Option[String]
|
||||
@@ -75,7 +75,7 @@ trait ActionResultT {
|
||||
newRoundPhase: Option[RoundPhase] = newRoundPhase,
|
||||
newRoundId: Option[RoundId] = newRoundId,
|
||||
newDate: Option[Date] = newDate,
|
||||
lastCommandTypeForActingProvince: Option[SelectedCommand] = lastCommandTypeForActingProvince,
|
||||
lastCommandTypeForActingProvince: Option[CommandType] = lastCommandTypeForActingProvince,
|
||||
newBattle: Option[ShardokBattle] = newBattle,
|
||||
resolvedBattle: Option[String] = resolvedBattle,
|
||||
// resolvedImminentBattle: Option[Int] = None,
|
||||
@@ -160,9 +160,9 @@ trait ActionResultT {
|
||||
copy(newRandomSeed = Some(seed))
|
||||
|
||||
def withLastCommandTypeForActingProvince(
|
||||
selectedCommand: SelectedCommand
|
||||
commandType: CommandType
|
||||
): ActionResultT =
|
||||
copy(lastCommandTypeForActingProvince = Some(selectedCommand))
|
||||
copy(lastCommandTypeForActingProvince = Some(commandType))
|
||||
|
||||
def update(updater: ActionResultT.ActionResultUpdater): ActionResultT =
|
||||
updater(this)
|
||||
|
||||
@@ -32,7 +32,6 @@ scala_library(
|
||||
":changed_hero_trait",
|
||||
":client_text_visibility_extension_trait",
|
||||
":notification_trait",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types",
|
||||
@@ -40,6 +39,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:round_phase",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/chronicle_entry",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
@@ -53,7 +53,6 @@ scala_library(
|
||||
":changed_hero_trait",
|
||||
":client_text_visibility_extension_trait",
|
||||
":notification_trait",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/generated_text_request",
|
||||
@@ -62,6 +61,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:round_phase",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/chronicle_entry",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.eagle0.eagle.model.action_result.concrete
|
||||
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, HeroId, ProvinceId, RoundId}
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.model.action_result.{
|
||||
ActionResultT,
|
||||
ChangedBattalionT,
|
||||
@@ -15,6 +14,7 @@ import net.eagle0.eagle.model.action_result.generated_text_request.GeneratedText
|
||||
import net.eagle0.eagle.model.action_result.types.ActionResultType
|
||||
import net.eagle0.eagle.model.state.battalion.BattalionT
|
||||
import net.eagle0.eagle.model.state.chronicle_entry.ChronicleEntry
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.faction.FactionT
|
||||
import net.eagle0.eagle.model.state.hero.HeroT
|
||||
@@ -36,7 +36,7 @@ case class ActionResultC(
|
||||
newRoundPhase: Option[RoundPhase] = None,
|
||||
newRoundId: Option[RoundId] = None,
|
||||
newDate: Option[Date] = None,
|
||||
lastCommandTypeForActingProvince: Option[SelectedCommand] = None,
|
||||
lastCommandTypeForActingProvince: Option[CommandType] = None,
|
||||
newBattle: Option[ShardokBattle] = None,
|
||||
resolvedBattle: Option[String] = None,
|
||||
newChronicleEntry: Option[ChronicleEntry] = None,
|
||||
@@ -73,7 +73,7 @@ case class ActionResultC(
|
||||
newRoundPhase: Option[RoundPhase] = newRoundPhase,
|
||||
newRoundId: Option[RoundId] = newRoundId,
|
||||
newDate: Option[Date] = newDate,
|
||||
lastCommandTypeForActingProvince: Option[SelectedCommand] = lastCommandTypeForActingProvince,
|
||||
lastCommandTypeForActingProvince: Option[CommandType] = lastCommandTypeForActingProvince,
|
||||
newBattle: Option[ShardokBattle] = newBattle,
|
||||
resolvedBattle: Option[String] = resolvedBattle,
|
||||
newChronicleEntry: Option[ChronicleEntry] = newChronicleEntry,
|
||||
|
||||
@@ -16,7 +16,6 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/types",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:changed_battalion_trait",
|
||||
@@ -31,6 +30,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:round_phase",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/chronicle_entry",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/hero",
|
||||
|
||||
+19
-6
@@ -1,8 +1,8 @@
|
||||
package net.eagle0.eagle.model.proto_converters
|
||||
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, HeroId, ProvinceId, RoundId}
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.common.action_result_type.ActionResultType as ActionResultTypeProto
|
||||
import net.eagle0.eagle.common.command_type.command_type.CommandType as CommandTypeProto
|
||||
import net.eagle0.eagle.common.round_phase.NewRoundPhase as NewRoundPhaseProto
|
||||
import net.eagle0.eagle.internal.action_result.ActionResult as ActionResultProto
|
||||
import net.eagle0.eagle.internal.generated_text_request.{
|
||||
@@ -28,6 +28,7 @@ import net.eagle0.eagle.model.action_result.generated_text_request.{
|
||||
}
|
||||
import net.eagle0.eagle.model.action_result.types.ActionResultType
|
||||
import net.eagle0.eagle.model.proto_converters.chronicle_entry.ChronicleEntryConverter
|
||||
import net.eagle0.eagle.model.proto_converters.command.selected.SelectedCommandConverter
|
||||
import net.eagle0.eagle.model.proto_converters.date.DateConverter
|
||||
import net.eagle0.eagle.model.proto_converters.faction.FactionConverter
|
||||
import net.eagle0.eagle.model.proto_converters.generated_text_request.LlmRequestConverter
|
||||
@@ -35,6 +36,7 @@ import net.eagle0.eagle.model.proto_converters.hero.{GenderConverter, HeroConver
|
||||
import net.eagle0.eagle.model.proto_converters.shardok_battle.ShardokBattleConverter
|
||||
import net.eagle0.eagle.model.state.battalion.BattalionT
|
||||
import net.eagle0.eagle.model.state.chronicle_entry.ChronicleEntry
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.faction.FactionT
|
||||
import net.eagle0.eagle.model.state.hero.HeroT
|
||||
@@ -55,7 +57,7 @@ object ActionResultProtoConverter {
|
||||
newRoundPhase: Option[RoundPhase],
|
||||
newRoundId: Option[RoundId],
|
||||
newDate: Option[Date],
|
||||
lastCommandTypeForActingProvince: Option[SelectedCommand],
|
||||
lastCommandTypeForActingProvince: Option[CommandType],
|
||||
newBattle: Option[ShardokBattle],
|
||||
resolvedBattle: Option[String],
|
||||
newChronicleEntry: Option[ChronicleEntry],
|
||||
@@ -91,7 +93,9 @@ object ActionResultProtoConverter {
|
||||
newRoundPhase = newRoundPhase.map(rp => NewRoundPhaseProto(RoundPhaseConverter.toProto(rp))),
|
||||
newRoundId = newRoundId,
|
||||
newDate = newDate.map(DateConverter.toProto),
|
||||
lastCommandTypeForActingProvince = lastCommandTypeForActingProvince.getOrElse(SelectedCommand.Empty),
|
||||
lastCommandTypeForActingProvince = lastCommandTypeForActingProvince
|
||||
.map(CommandTypeConverter.toProto)
|
||||
.getOrElse(CommandTypeProto.COMMAND_TYPE_UNKNOWN),
|
||||
newBattle = newBattle.map(ShardokBattleConverter.toProto),
|
||||
resolvedBattle = resolvedBattle,
|
||||
newChronicleEntry = newChronicleEntry.map(ChronicleEntryConverter.toProto),
|
||||
@@ -186,9 +190,18 @@ object ActionResultProtoConverter {
|
||||
newRoundPhase = proto.newRoundPhase.map(nrp => RoundPhaseConverter.fromProto(nrp.value)),
|
||||
newRoundId = proto.newRoundId,
|
||||
newDate = proto.newDate.map(d => DateConverter.fromProto(Some(d))),
|
||||
lastCommandTypeForActingProvince = Option.when(proto.lastCommandTypeForActingProvince != SelectedCommand.Empty)(
|
||||
proto.lastCommandTypeForActingProvince
|
||||
),
|
||||
lastCommandTypeForActingProvince = {
|
||||
// Backwards compatibility: first check new CommandType field, fall back to deprecated SelectedCommand field
|
||||
val fromNewField = CommandTypeConverter.fromProto(proto.lastCommandTypeForActingProvince)
|
||||
fromNewField.orElse {
|
||||
// Check if the deprecated SelectedCommand has a command set
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand as SelectedCommandProto
|
||||
val deprecatedCommand = proto.deprecatedLastCommandTypeForActingProvince
|
||||
Option.when(deprecatedCommand != SelectedCommandProto.defaultInstance) {
|
||||
SelectedCommandConverter.fromProto(deprecatedCommand).commandType
|
||||
}
|
||||
}
|
||||
},
|
||||
newBattle = proto.newBattle.map(ShardokBattleConverter.fromProto),
|
||||
resolvedBattle = proto.resolvedBattle,
|
||||
newChronicleEntry = proto.newChronicleEntry.map(ChronicleEntryConverter.fromProto),
|
||||
|
||||
@@ -24,10 +24,12 @@ scala_library(
|
||||
":changed_faction_converter",
|
||||
":changed_hero_converter",
|
||||
":changed_province_converter",
|
||||
":command_type_converter",
|
||||
":notification_converter",
|
||||
":round_phase_converter",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:action_result_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:command_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:action_result_trait",
|
||||
@@ -39,6 +41,7 @@ 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/types",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/chronicle_entry:chronicle_entry_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command/selected:selected_command_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/faction",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/hero",
|
||||
@@ -49,6 +52,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:round_phase",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/battalion",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/chronicle_entry",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//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/province",
|
||||
@@ -273,6 +277,22 @@ scala_library(
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "command_type_converter",
|
||||
srcs = ["CommandTypeConverter.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:__pkg__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/province:__pkg__",
|
||||
"//src/test/scala/net/eagle0/eagle/model/proto_converters:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":proto_conversion_exception",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:command_type_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
],
|
||||
)
|
||||
|
||||
scala_library(
|
||||
name = "combat_unit_converter",
|
||||
srcs = ["CombatUnitConverter.scala"],
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package net.eagle0.eagle.model.proto_converters
|
||||
|
||||
import net.eagle0.eagle.common.command_type.command_type.CommandType as CommandTypeProto
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
|
||||
/**
|
||||
* Converter between Scala CommandType enum and proto CommandType enum.
|
||||
*
|
||||
* Both toProto and fromProto use exhaustive pattern matching, so adding a new command type without updating this
|
||||
* converter will cause a compile error.
|
||||
*/
|
||||
object CommandTypeConverter:
|
||||
/**
|
||||
* Converts Scala CommandType to proto CommandType. Exhaustive matching ensures compile-time safety when adding new
|
||||
* command types.
|
||||
*/
|
||||
def toProto(commandType: CommandType): CommandTypeProto =
|
||||
commandType match
|
||||
case CommandType.Alms => CommandTypeProto.COMMAND_TYPE_ALMS
|
||||
case CommandType.ApprehendOutlaw => CommandTypeProto.COMMAND_TYPE_APPREHEND_OUTLAW
|
||||
case CommandType.ArmTroops => CommandTypeProto.COMMAND_TYPE_ARM_TROOPS
|
||||
case CommandType.AttackDecision => CommandTypeProto.COMMAND_TYPE_ATTACK_DECISION
|
||||
case CommandType.ControlWeather => CommandTypeProto.COMMAND_TYPE_CONTROL_WEATHER
|
||||
case CommandType.DeclineQuest => CommandTypeProto.COMMAND_TYPE_DECLINE_QUEST
|
||||
case CommandType.Defend => CommandTypeProto.COMMAND_TYPE_DEFEND
|
||||
case CommandType.Diplomacy => CommandTypeProto.COMMAND_TYPE_DIPLOMACY
|
||||
case CommandType.Divine => CommandTypeProto.COMMAND_TYPE_DIVINE
|
||||
case CommandType.ExileVassal => CommandTypeProto.COMMAND_TYPE_EXILE_VASSAL
|
||||
case CommandType.Feast => CommandTypeProto.COMMAND_TYPE_FEAST
|
||||
case CommandType.FreeForAllDecision => CommandTypeProto.COMMAND_TYPE_FREE_FOR_ALL_DECISION
|
||||
case CommandType.HandleCapturedHero => CommandTypeProto.COMMAND_TYPE_HANDLE_CAPTURED_HERO
|
||||
case CommandType.HandleRiotCrackDown => CommandTypeProto.COMMAND_TYPE_HANDLE_RIOT_CRACK_DOWN
|
||||
case CommandType.HandleRiotDoNothing => CommandTypeProto.COMMAND_TYPE_HANDLE_RIOT_DO_NOTHING
|
||||
case CommandType.HandleRiotGive => CommandTypeProto.COMMAND_TYPE_HANDLE_RIOT_GIVE
|
||||
case CommandType.HeroGift => CommandTypeProto.COMMAND_TYPE_HERO_GIFT
|
||||
case CommandType.Improve => CommandTypeProto.COMMAND_TYPE_IMPROVE
|
||||
case CommandType.IssueOrders => CommandTypeProto.COMMAND_TYPE_ISSUE_ORDERS
|
||||
case CommandType.ManagePrisoners => CommandTypeProto.COMMAND_TYPE_MANAGE_PRISONERS
|
||||
case CommandType.March => CommandTypeProto.COMMAND_TYPE_MARCH
|
||||
case CommandType.OrganizeTroops => CommandTypeProto.COMMAND_TYPE_ORGANIZE_TROOPS
|
||||
case CommandType.PleaseRecruitMe => CommandTypeProto.COMMAND_TYPE_PLEASE_RECRUIT_ME
|
||||
case CommandType.Recon => CommandTypeProto.COMMAND_TYPE_RECON
|
||||
case CommandType.RecruitHeroes => CommandTypeProto.COMMAND_TYPE_RECRUIT_HEROES
|
||||
case CommandType.ResolveAllianceOffer => CommandTypeProto.COMMAND_TYPE_RESOLVE_ALLIANCE_OFFER
|
||||
case CommandType.ResolveBreakAlliance => CommandTypeProto.COMMAND_TYPE_RESOLVE_BREAK_ALLIANCE
|
||||
case CommandType.ResolveInvitation => CommandTypeProto.COMMAND_TYPE_RESOLVE_INVITATION
|
||||
case CommandType.ResolveRansomOffer => CommandTypeProto.COMMAND_TYPE_RESOLVE_RANSOM_OFFER
|
||||
case CommandType.ResolveTruceOffer => CommandTypeProto.COMMAND_TYPE_RESOLVE_TRUCE_OFFER
|
||||
case CommandType.ResolveTribute => CommandTypeProto.COMMAND_TYPE_RESOLVE_TRIBUTE
|
||||
case CommandType.Rest => CommandTypeProto.COMMAND_TYPE_REST
|
||||
case CommandType.Return => CommandTypeProto.COMMAND_TYPE_RETURN
|
||||
case CommandType.SendSupplies => CommandTypeProto.COMMAND_TYPE_SEND_SUPPLIES
|
||||
case CommandType.StartEpidemic => CommandTypeProto.COMMAND_TYPE_START_EPIDEMIC
|
||||
case CommandType.SuppressBeasts => CommandTypeProto.COMMAND_TYPE_SUPPRESS_BEASTS
|
||||
case CommandType.SwearBrotherhood => CommandTypeProto.COMMAND_TYPE_SWEAR_BROTHERHOOD
|
||||
case CommandType.Trade => CommandTypeProto.COMMAND_TYPE_TRADE
|
||||
case CommandType.Train => CommandTypeProto.COMMAND_TYPE_TRAIN
|
||||
case CommandType.Travel => CommandTypeProto.COMMAND_TYPE_TRAVEL
|
||||
|
||||
/**
|
||||
* Converts proto CommandType to Scala CommandType. Exhaustive matching ensures compile-time safety when adding new
|
||||
* command types. Returns None for UNKNOWN.
|
||||
*/
|
||||
def fromProto(commandTypeProto: CommandTypeProto): Option[CommandType] =
|
||||
commandTypeProto match
|
||||
case CommandTypeProto.COMMAND_TYPE_ALMS => Some(CommandType.Alms)
|
||||
case CommandTypeProto.COMMAND_TYPE_APPREHEND_OUTLAW => Some(CommandType.ApprehendOutlaw)
|
||||
case CommandTypeProto.COMMAND_TYPE_ARM_TROOPS => Some(CommandType.ArmTroops)
|
||||
case CommandTypeProto.COMMAND_TYPE_ATTACK_DECISION => Some(CommandType.AttackDecision)
|
||||
case CommandTypeProto.COMMAND_TYPE_CONTROL_WEATHER => Some(CommandType.ControlWeather)
|
||||
case CommandTypeProto.COMMAND_TYPE_DECLINE_QUEST => Some(CommandType.DeclineQuest)
|
||||
case CommandTypeProto.COMMAND_TYPE_DEFEND => Some(CommandType.Defend)
|
||||
case CommandTypeProto.COMMAND_TYPE_DIPLOMACY => Some(CommandType.Diplomacy)
|
||||
case CommandTypeProto.COMMAND_TYPE_DIVINE => Some(CommandType.Divine)
|
||||
case CommandTypeProto.COMMAND_TYPE_EXILE_VASSAL => Some(CommandType.ExileVassal)
|
||||
case CommandTypeProto.COMMAND_TYPE_FEAST => Some(CommandType.Feast)
|
||||
case CommandTypeProto.COMMAND_TYPE_FREE_FOR_ALL_DECISION => Some(CommandType.FreeForAllDecision)
|
||||
case CommandTypeProto.COMMAND_TYPE_HANDLE_CAPTURED_HERO => Some(CommandType.HandleCapturedHero)
|
||||
case CommandTypeProto.COMMAND_TYPE_HANDLE_RIOT_CRACK_DOWN => Some(CommandType.HandleRiotCrackDown)
|
||||
case CommandTypeProto.COMMAND_TYPE_HANDLE_RIOT_DO_NOTHING => Some(CommandType.HandleRiotDoNothing)
|
||||
case CommandTypeProto.COMMAND_TYPE_HANDLE_RIOT_GIVE => Some(CommandType.HandleRiotGive)
|
||||
case CommandTypeProto.COMMAND_TYPE_HERO_GIFT => Some(CommandType.HeroGift)
|
||||
case CommandTypeProto.COMMAND_TYPE_IMPROVE => Some(CommandType.Improve)
|
||||
case CommandTypeProto.COMMAND_TYPE_ISSUE_ORDERS => Some(CommandType.IssueOrders)
|
||||
case CommandTypeProto.COMMAND_TYPE_MANAGE_PRISONERS => Some(CommandType.ManagePrisoners)
|
||||
case CommandTypeProto.COMMAND_TYPE_MARCH => Some(CommandType.March)
|
||||
case CommandTypeProto.COMMAND_TYPE_ORGANIZE_TROOPS => Some(CommandType.OrganizeTroops)
|
||||
case CommandTypeProto.COMMAND_TYPE_PLEASE_RECRUIT_ME => Some(CommandType.PleaseRecruitMe)
|
||||
case CommandTypeProto.COMMAND_TYPE_RECON => Some(CommandType.Recon)
|
||||
case CommandTypeProto.COMMAND_TYPE_RECRUIT_HEROES => Some(CommandType.RecruitHeroes)
|
||||
case CommandTypeProto.COMMAND_TYPE_RESOLVE_ALLIANCE_OFFER => Some(CommandType.ResolveAllianceOffer)
|
||||
case CommandTypeProto.COMMAND_TYPE_RESOLVE_BREAK_ALLIANCE => Some(CommandType.ResolveBreakAlliance)
|
||||
case CommandTypeProto.COMMAND_TYPE_RESOLVE_INVITATION => Some(CommandType.ResolveInvitation)
|
||||
case CommandTypeProto.COMMAND_TYPE_RESOLVE_RANSOM_OFFER => Some(CommandType.ResolveRansomOffer)
|
||||
case CommandTypeProto.COMMAND_TYPE_RESOLVE_TRUCE_OFFER => Some(CommandType.ResolveTruceOffer)
|
||||
case CommandTypeProto.COMMAND_TYPE_RESOLVE_TRIBUTE => Some(CommandType.ResolveTribute)
|
||||
case CommandTypeProto.COMMAND_TYPE_REST => Some(CommandType.Rest)
|
||||
case CommandTypeProto.COMMAND_TYPE_RETURN => Some(CommandType.Return)
|
||||
case CommandTypeProto.COMMAND_TYPE_SEND_SUPPLIES => Some(CommandType.SendSupplies)
|
||||
case CommandTypeProto.COMMAND_TYPE_START_EPIDEMIC => Some(CommandType.StartEpidemic)
|
||||
case CommandTypeProto.COMMAND_TYPE_SUPPRESS_BEASTS => Some(CommandType.SuppressBeasts)
|
||||
case CommandTypeProto.COMMAND_TYPE_SWEAR_BROTHERHOOD => Some(CommandType.SwearBrotherhood)
|
||||
case CommandTypeProto.COMMAND_TYPE_TRADE => Some(CommandType.Trade)
|
||||
case CommandTypeProto.COMMAND_TYPE_TRAIN => Some(CommandType.Train)
|
||||
case CommandTypeProto.COMMAND_TYPE_TRAVEL => Some(CommandType.Travel)
|
||||
case CommandTypeProto.COMMAND_TYPE_UNKNOWN => None
|
||||
case CommandTypeProto.Unrecognized(_) =>
|
||||
throw ProtoConversionException(s"Unrecognized command type: $commandTypeProto")
|
||||
end CommandTypeConverter
|
||||
+4
-1
@@ -7,6 +7,9 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/model/proto_converters:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
":available_command_converter",
|
||||
],
|
||||
deps = [
|
||||
":available_command_converter",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:command_scala_proto",
|
||||
@@ -20,7 +23,7 @@ scala_library(
|
||||
name = "available_command_converter",
|
||||
srcs = ["AvailableCommandConverter.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/service:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions/impl/action:__pkg__",
|
||||
"//src/test/scala/net/eagle0/eagle/model/proto_converters:__subpackages__",
|
||||
|
||||
@@ -4,10 +4,16 @@ scala_library(
|
||||
name = "selected_command_converter",
|
||||
srcs = ["SelectedCommandConverter.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/library:__pkg__",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:__pkg__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:__pkg__",
|
||||
"//src/main/scala/net/eagle0/eagle/service:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/model/proto_converters:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/selected",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api/command/util:armed_battalion_scala_proto",
|
||||
|
||||
@@ -23,12 +23,14 @@ scala_library(
|
||||
deps = [
|
||||
":event",
|
||||
":order_type",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:command_type_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:province_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:army_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battalion_type_id_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:battle_revelation_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:captured_hero_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:command_type_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:deferred_change_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:improvement_type_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:incoming_end_turn_action_converter",
|
||||
@@ -36,6 +38,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:supplies_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:unaffiliated_hero_converter",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province:orders",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province/concrete",
|
||||
|
||||
+9
-6
@@ -1,9 +1,8 @@
|
||||
package net.eagle0.eagle.model.proto_converters.province
|
||||
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand as SelectedCommandProto
|
||||
import net.eagle0.eagle.common.battalion_type.BattalionTypeId as BattalionTypeIdProto
|
||||
import net.eagle0.eagle.common.command_type.command_type.CommandType as CommandTypeProto
|
||||
import net.eagle0.eagle.common.date.Date as DateProto
|
||||
import net.eagle0.eagle.common.improvement_type.ImprovementType as ImprovementTypeProto
|
||||
import net.eagle0.eagle.common.province_event.ProvinceEvent as ProvinceEventProto
|
||||
@@ -30,6 +29,7 @@ import net.eagle0.eagle.model.proto_converters.{
|
||||
BattalionTypeIdConverter,
|
||||
BattleRevelationConverter,
|
||||
CapturedHeroConverter,
|
||||
CommandTypeConverter,
|
||||
DeferredChangeConverter,
|
||||
ImprovementTypeConverter,
|
||||
IncomingEndTurnActionConverter,
|
||||
@@ -48,6 +48,7 @@ import net.eagle0.eagle.model.state.{
|
||||
MovingArmy,
|
||||
MovingSupplies
|
||||
}
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.province.{
|
||||
DeferredChangeT,
|
||||
@@ -100,7 +101,7 @@ object ProvinceConverter {
|
||||
hexMapName: String,
|
||||
castleCount: Int,
|
||||
heroCap: Int,
|
||||
lastCommand: Option[SelectedCommand]
|
||||
lastCommand: Option[CommandType]
|
||||
) =>
|
||||
ProvinceProto(
|
||||
id = id,
|
||||
@@ -131,7 +132,9 @@ object ProvinceConverter {
|
||||
activeEvents = activeEvents.map(ProvinceEventConverter.toProto),
|
||||
lastBeastsDate = lastBeastsDate.map(DateConverter.toProto),
|
||||
lastRiotDate = lastRiotDate.map(DateConverter.toProto),
|
||||
lastCommand = lastCommand.getOrElse(SelectedCommand.Empty),
|
||||
lastCommand = lastCommand
|
||||
.map(CommandTypeConverter.toProto)
|
||||
.getOrElse(CommandTypeProto.COMMAND_TYPE_UNKNOWN),
|
||||
incomingArmies = incomingArmies.map(ArmyConverter.toProto),
|
||||
hostileArmies = hostileArmies.map(ArmyConverter.toProto),
|
||||
defendingArmy = defendingArmy.map(ArmyConverter.toProto),
|
||||
@@ -182,7 +185,7 @@ object ProvinceConverter {
|
||||
activeEvents: Seq[ProvinceEventProto],
|
||||
lastBeastsDate: Option[DateProto],
|
||||
lastRiotDate: Option[DateProto],
|
||||
lastCommand: SelectedCommandProto,
|
||||
lastCommand: CommandTypeProto,
|
||||
castleCount: Int,
|
||||
heroCap: Int,
|
||||
deferredChanges: Seq[DeferredChangeProto],
|
||||
@@ -220,7 +223,7 @@ object ProvinceConverter {
|
||||
activeEvents = activeEvents.map(ProvinceEventConverter.fromProto).toVector,
|
||||
lastBeastsDate = lastBeastsDate.map(date => DateConverter.fromProto(Some(date))),
|
||||
lastRiotDate = lastRiotDate.map(date => DateConverter.fromProto(Some(date))),
|
||||
lastCommand = Option.when(!lastCommand.isEmpty)(lastCommand),
|
||||
lastCommand = CommandTypeConverter.fromProto(lastCommand),
|
||||
incomingArmies = incomingArmies.map(ArmyConverter.fromProto).toVector,
|
||||
hostileArmies = hostileArmies.map(ArmyConverter.fromProto).toVector,
|
||||
defendingArmy = defendingArmy.map(ArmyConverter.fromProto),
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
load("@rules_scala//scala:scala.bzl", "scala_library")
|
||||
|
||||
scala_library(
|
||||
name = "command_type",
|
||||
srcs = ["CommandType.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle:__subpackages__",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
package net.eagle0.eagle.model.state.command
|
||||
|
||||
/**
|
||||
* Enum representing the type of a command, without any command-specific data.
|
||||
*
|
||||
* This is used to track which command type was last executed on a province, without needing to serialize the full
|
||||
* SelectedCommand with all its parameters.
|
||||
*
|
||||
* Both SelectedCommand and AvailableCommand have a `toCommandType` method that converts to this enum using exhaustive
|
||||
* pattern matching. Adding a new command variant without updating the `toCommandType` method will cause a compile
|
||||
* error.
|
||||
*/
|
||||
enum CommandType:
|
||||
case Alms
|
||||
case ApprehendOutlaw
|
||||
case ArmTroops
|
||||
case AttackDecision
|
||||
case ControlWeather
|
||||
case DeclineQuest
|
||||
case Defend
|
||||
case Diplomacy
|
||||
case Divine
|
||||
case ExileVassal
|
||||
case Feast
|
||||
case FreeForAllDecision
|
||||
case HandleCapturedHero
|
||||
case HandleRiotCrackDown
|
||||
case HandleRiotDoNothing
|
||||
case HandleRiotGive
|
||||
case HeroGift
|
||||
case Improve
|
||||
case IssueOrders
|
||||
case ManagePrisoners
|
||||
case March
|
||||
case OrganizeTroops
|
||||
case PleaseRecruitMe
|
||||
case Recon
|
||||
case RecruitHeroes
|
||||
case ResolveAllianceOffer
|
||||
case ResolveBreakAlliance
|
||||
case ResolveInvitation
|
||||
case ResolveRansomOffer
|
||||
case ResolveTruceOffer
|
||||
case ResolveTribute
|
||||
case Rest
|
||||
case Return
|
||||
case SendSupplies
|
||||
case StartEpidemic
|
||||
case SuppressBeasts
|
||||
case SwearBrotherhood
|
||||
case Trade
|
||||
case Train
|
||||
case Travel
|
||||
end CommandType
|
||||
+48
-36
@@ -3,44 +3,50 @@ package net.eagle0.eagle.model.state.command.available
|
||||
import net.eagle0.common.hostility.Hostility
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.model.state.command.common.*
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.Status
|
||||
import AvailableCommand.*
|
||||
|
||||
/** Scala 3 enum representing available command options for a player. */
|
||||
enum AvailableCommand:
|
||||
/**
|
||||
* Scala 3 enum representing available command options for a player.
|
||||
*
|
||||
* Each case must provide a CommandType via the enum parameter, ensuring compile-time safety: adding a new command
|
||||
* variant without specifying its CommandType will cause a compile error.
|
||||
*/
|
||||
enum AvailableCommand(val commandType: CommandType):
|
||||
case AlmsAvailable(
|
||||
foodAvailable: Int,
|
||||
actingProvinceId: ProvinceId,
|
||||
availableHeroIds: Vector[HeroId]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.Alms)
|
||||
case ApprehendOutlawAvailable(
|
||||
outlaws: Vector[ResidentOutlaw],
|
||||
availableBattalionIds: Vector[BattalionId],
|
||||
actingProvinceId: ProvinceId,
|
||||
availableHeroIds: Vector[HeroId]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.ApprehendOutlaw)
|
||||
case ArmTroopsAvailable(
|
||||
armamentCosts: Vector[ArmamentCost],
|
||||
availableBattalions: Vector[BattalionId],
|
||||
maxArmament: Int,
|
||||
actingProvinceId: ProvinceId,
|
||||
availableBattalionTypeIds: Vector[Int]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.ArmTroops)
|
||||
case AttackDecisionAvailable(
|
||||
armies: Vector[ArmyStats],
|
||||
actingUnits: Vector[ExpandedCombatUnit],
|
||||
availableDecisions: Vector[AttackDecisionType],
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.AttackDecision)
|
||||
case ControlWeatherAvailable(
|
||||
options: Vector[TargetProvinceOptions],
|
||||
actingProvinceId: ProvinceId,
|
||||
availableHeroIds: Vector[HeroId]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.ControlWeather)
|
||||
case DeclineQuestAvailable(
|
||||
actingProvinceId: ProvinceId,
|
||||
declinableHeroes: Vector[ExpandedUnaffiliatedHero]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.DeclineQuest)
|
||||
case DefendAvailable(
|
||||
suitableBattalionsForHeroes: Map[HeroId, SuitableBattalions],
|
||||
availableFleeProvinceIds: Vector[ProvinceId],
|
||||
@@ -51,138 +57,144 @@ enum AvailableCommand:
|
||||
hostileFactionIds: Vector[FactionId],
|
||||
hostileHeroCount: Int,
|
||||
hostileTroopCount: Int
|
||||
)
|
||||
) extends AvailableCommand(CommandType.Defend)
|
||||
case DiplomacyAvailable(
|
||||
options: Vector[DiplomacyOption],
|
||||
availableHeroIds: Vector[HeroId],
|
||||
actingProvinceId: ProvinceId,
|
||||
recommendedHeroId: HeroId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.Diplomacy)
|
||||
case DivineAvailable(
|
||||
costPerHero: Int,
|
||||
divinableHeroes: Vector[ExpandedUnaffiliatedHero],
|
||||
unavailableHeroes: Vector[ExpandedUnaffiliatedHero],
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.Divine)
|
||||
case ExileVassalAvailable(
|
||||
actingProvinceId: ProvinceId,
|
||||
exilableHeroIds: Vector[HeroId]
|
||||
)
|
||||
case FeastAvailable(goldCost: Int, actingProvinceId: ProvinceId)
|
||||
) extends AvailableCommand(CommandType.ExileVassal)
|
||||
case FeastAvailable(goldCost: Int, actingProvinceId: ProvinceId) extends AvailableCommand(CommandType.Feast)
|
||||
case FreeForAllDecisionAvailable(
|
||||
provinceId: ProvinceId,
|
||||
armies: Vector[ArmyStats],
|
||||
actingUnits: Vector[ExpandedCombatUnit],
|
||||
availableDecisions: Vector[AttackDecisionType]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.FreeForAllDecision)
|
||||
case HandleCapturedHeroAvailable(
|
||||
availableHeroes: Vector[ExpandedCapturedHero],
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.HandleCapturedHero)
|
||||
case HandleRiotCrackDownAvailable(
|
||||
availableHeroIds: Vector[HeroId],
|
||||
battalionIdsAvailable: Vector[BattalionId],
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.HandleRiotCrackDown)
|
||||
case HandleRiotDoNothingAvailable(actingProvinceId: ProvinceId)
|
||||
extends AvailableCommand(CommandType.HandleRiotDoNothing)
|
||||
case HandleRiotGiveAvailable(
|
||||
foodAvailable: Int,
|
||||
goldAvailable: Int,
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.HandleRiotGive)
|
||||
case HeroGiftAvailable(
|
||||
eligibleGifts: Vector[EligibleGift],
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.HeroGift)
|
||||
case ImproveAvailable(
|
||||
availableTypes: Vector[ImprovementType],
|
||||
availableHeroIds: Vector[HeroId],
|
||||
recommendedHeroId: HeroId,
|
||||
actingProvinceId: ProvinceId,
|
||||
lockedType: Option[ImprovementType]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.Improve)
|
||||
case IssueOrdersAvailable(
|
||||
currentOrders: Vector[ProvinceOrders],
|
||||
availableOrders: Vector[ProvinceOrderType],
|
||||
availableFocusProvinces: Vector[ProvinceId],
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.IssueOrders)
|
||||
case ManagePrisonersAvailable(
|
||||
actingProvinceId: ProvinceId,
|
||||
prisoners: Vector[PrisonerToManage]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.ManagePrisoners)
|
||||
case MarchAvailable(
|
||||
oneProvinceCommands: Vector[MarchCommandFromOneProvince],
|
||||
actingProvinceId: ProvinceId,
|
||||
availableTypes: Vector[BattalionType]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.March)
|
||||
case OrganizeTroopsAvailable(
|
||||
troopCosts: Vector[TroopCost],
|
||||
existingBattalions: Vector[BattalionId],
|
||||
maxBattalions: Int,
|
||||
actingProvinceId: ProvinceId,
|
||||
availableBattalionTypes: Vector[BattalionTypeStatus]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.OrganizeTroops)
|
||||
case PleaseRecruitMeAvailable(
|
||||
availableProvinces: Vector[OneProvincePleaseRecruitMe],
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.PleaseRecruitMe)
|
||||
case ReconAvailable(
|
||||
availableTargetProvinces: Vector[ProvinceId],
|
||||
actingProvinceId: ProvinceId,
|
||||
availableHeroIds: Vector[HeroId]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.Recon)
|
||||
case RecruitHeroesAvailable(
|
||||
availableHeroes: Vector[ExpandedUnaffiliatedHero],
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.RecruitHeroes)
|
||||
case ResolveAllianceOfferAvailable(offers: Vector[DiplomacyOfferInfo])
|
||||
extends AvailableCommand(CommandType.ResolveAllianceOffer)
|
||||
case ResolveBreakAllianceAvailable(offers: Vector[DiplomacyOfferInfo])
|
||||
extends AvailableCommand(CommandType.ResolveBreakAlliance)
|
||||
case ResolveInvitationAvailable(invitations: Vector[DiplomacyOfferInfo])
|
||||
extends AvailableCommand(CommandType.ResolveInvitation)
|
||||
case ResolveRansomOfferAvailable(offers: Vector[DiplomacyOfferInfo])
|
||||
extends AvailableCommand(CommandType.ResolveRansomOffer)
|
||||
case ResolveTruceOfferAvailable(offers: Vector[DiplomacyOfferInfo])
|
||||
extends AvailableCommand(CommandType.ResolveTruceOffer)
|
||||
case ResolveTributeAvailable(
|
||||
demands: Vector[TributeAndFaction],
|
||||
availableGold: Int,
|
||||
availableFood: Int,
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
case RestAvailable(actingProvinceId: ProvinceId)
|
||||
case ReturnAvailable(actingProvinceId: ProvinceId)
|
||||
) extends AvailableCommand(CommandType.ResolveTribute)
|
||||
case RestAvailable(actingProvinceId: ProvinceId) extends AvailableCommand(CommandType.Rest)
|
||||
case ReturnAvailable(actingProvinceId: ProvinceId) extends AvailableCommand(CommandType.Return)
|
||||
case SendSuppliesAvailable(
|
||||
goldAvailable: Int,
|
||||
foodAvailable: Int,
|
||||
availableDestinationProvinceIds: Vector[ProvinceId],
|
||||
actingProvinceId: ProvinceId,
|
||||
availableHeroIds: Vector[HeroId]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.SendSupplies)
|
||||
case StartEpidemicAvailable(
|
||||
options: Vector[StartEpidemicOptions],
|
||||
actingProvinceId: ProvinceId,
|
||||
availableHeroIds: Vector[HeroId]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.StartEpidemic)
|
||||
case SuppressBeastsAvailable(
|
||||
availableHeroIds: Vector[HeroId],
|
||||
availableBattalionIds: Vector[BattalionId],
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.SuppressBeasts)
|
||||
case SwearBrotherhoodAvailable(
|
||||
actingProvinceId: ProvinceId,
|
||||
availableHeroes: Vector[HeroAndBackstory]
|
||||
)
|
||||
) extends AvailableCommand(CommandType.SwearBrotherhood)
|
||||
case TradeAvailable(
|
||||
foodAvailable: Int,
|
||||
goldAvailable: Int,
|
||||
foodBuyPrice: Double,
|
||||
foodSellPrice: Double,
|
||||
actingProvinceId: ProvinceId
|
||||
)
|
||||
) extends AvailableCommand(CommandType.Trade)
|
||||
case TrainAvailable(
|
||||
actingProvinceId: ProvinceId,
|
||||
availableHeroIds: Vector[HeroId],
|
||||
recommendedHeroId: HeroId
|
||||
)
|
||||
case TravelAvailable(actingProvinceId: ProvinceId)
|
||||
) extends AvailableCommand(CommandType.Train)
|
||||
case TravelAvailable(actingProvinceId: ProvinceId) extends AvailableCommand(CommandType.Travel)
|
||||
end AvailableCommand
|
||||
|
||||
/** Supporting types for AvailableCommand. */
|
||||
|
||||
@@ -9,20 +9,21 @@ scala_library(
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/ai:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:__pkg__",
|
||||
"//src/test/scala/net/eagle0/eagle/ai:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/model/proto_converters:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle/model/state/command:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
"//src/main/protobuf/net/eagle0/common:hostility_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/common:hostility_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/common",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
],
|
||||
|
||||
@@ -4,13 +4,18 @@ scala_library(
|
||||
name = "selected",
|
||||
srcs = ["SelectedCommand.scala"],
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/library:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/command:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:__pkg__",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:__subpackages__",
|
||||
"//src/test/scala/net/eagle0/eagle:__subpackages__",
|
||||
],
|
||||
exports = [
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/common",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",
|
||||
],
|
||||
|
||||
+48
-29
@@ -2,87 +2,106 @@ package net.eagle0.eagle.model.state.command.selected
|
||||
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.model.state.command.common.*
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.diplomacy_offer.status.Status
|
||||
|
||||
/** Scala 3 enum representing a player's selected command. */
|
||||
enum SelectedCommand:
|
||||
case AlmsSelected(amount: Int, actingHeroId: HeroId)
|
||||
/**
|
||||
* Scala 3 enum representing a player's selected command.
|
||||
*
|
||||
* Each case must provide a CommandType via the enum parameter, ensuring compile-time safety: adding a new command
|
||||
* variant without specifying its CommandType will cause a compile error.
|
||||
*/
|
||||
enum SelectedCommand(val commandType: CommandType):
|
||||
case AlmsSelected(amount: Int, actingHeroId: HeroId) extends SelectedCommand(CommandType.Alms)
|
||||
case ApprehendOutlawSelected(
|
||||
heroIdToApprehend: HeroId,
|
||||
battalionId: Option[BattalionId],
|
||||
actingHeroId: HeroId
|
||||
)
|
||||
case ArmTroopsSelected(armedBattalions: Vector[ArmedBattalion])
|
||||
case AttackDecisionSelected(decision: AttackDecisionType)
|
||||
) extends SelectedCommand(CommandType.ApprehendOutlaw)
|
||||
case ArmTroopsSelected(armedBattalions: Vector[ArmedBattalion]) extends SelectedCommand(CommandType.ArmTroops)
|
||||
case AttackDecisionSelected(decision: AttackDecisionType) extends SelectedCommand(CommandType.AttackDecision)
|
||||
case ControlWeatherSelected(
|
||||
selectedType: ControlWeatherType,
|
||||
selectedProvinceId: ProvinceId,
|
||||
actingHeroId: HeroId
|
||||
)
|
||||
case DeclineQuestSelected(heroId: HeroId)
|
||||
) extends SelectedCommand(CommandType.ControlWeather)
|
||||
case DeclineQuestSelected(heroId: HeroId) extends SelectedCommand(CommandType.DeclineQuest)
|
||||
case DefendSelected(
|
||||
fleeProvinceId: Option[ProvinceId],
|
||||
defendingUnits: Vector[CombatUnit]
|
||||
)
|
||||
) extends SelectedCommand(CommandType.Defend)
|
||||
case DiplomacySelected(
|
||||
selectedOption: DiplomacyOptionType,
|
||||
targetFactionId: FactionId,
|
||||
sentHeroId: HeroId
|
||||
)
|
||||
case DivineSelected(heroIds: Vector[HeroId])
|
||||
case ExileVassalSelected(exiledHeroId: HeroId)
|
||||
case FeastSelected
|
||||
) extends SelectedCommand(CommandType.Diplomacy)
|
||||
case DivineSelected(heroIds: Vector[HeroId]) extends SelectedCommand(CommandType.Divine)
|
||||
case ExileVassalSelected(exiledHeroId: HeroId) extends SelectedCommand(CommandType.ExileVassal)
|
||||
case FeastSelected extends SelectedCommand(CommandType.Feast)
|
||||
case FreeForAllDecisionSelected(provinceId: ProvinceId, decision: AttackDecisionType)
|
||||
extends SelectedCommand(CommandType.FreeForAllDecision)
|
||||
case HandleCapturedHeroSelected(heroId: HeroId, selectedOption: CapturedHeroOption)
|
||||
extends SelectedCommand(CommandType.HandleCapturedHero)
|
||||
case HandleRiotCrackDownSelected(
|
||||
heroId: HeroId,
|
||||
battalionId: Option[BattalionId],
|
||||
actingHeroId: HeroId
|
||||
)
|
||||
case HandleRiotDoNothingSelected
|
||||
case HandleRiotGiveSelected(foodAmount: Int, goldAmount: Int)
|
||||
case HeroGiftSelected(recipientHeroId: HeroId, amount: Int)
|
||||
) extends SelectedCommand(CommandType.HandleRiotCrackDown)
|
||||
case HandleRiotDoNothingSelected extends SelectedCommand(CommandType.HandleRiotDoNothing)
|
||||
case HandleRiotGiveSelected(foodAmount: Int, goldAmount: Int) extends SelectedCommand(CommandType.HandleRiotGive)
|
||||
case HeroGiftSelected(recipientHeroId: HeroId, amount: Int) extends SelectedCommand(CommandType.HeroGift)
|
||||
case ImproveSelected(improvementType: ImprovementType, actingHeroId: HeroId, lockType: Boolean)
|
||||
extends SelectedCommand(CommandType.Improve)
|
||||
case IssueOrdersSelected(newOrders: Vector[ProvinceOrder], newFocusProvince: Option[ProvinceId])
|
||||
extends SelectedCommand(CommandType.IssueOrders)
|
||||
case ManagePrisonersSelected(prisonerHeroId: HeroId, chosenOption: PrisonerManagementOption)
|
||||
extends SelectedCommand(CommandType.ManagePrisoners)
|
||||
case MarchSelected(
|
||||
gold: Int,
|
||||
food: Int,
|
||||
originProvince: ProvinceId,
|
||||
destinationProvinceId: ProvinceId,
|
||||
marchingUnits: Vector[CombatUnit]
|
||||
)
|
||||
) extends SelectedCommand(CommandType.March)
|
||||
case OrganizeTroopsSelected(
|
||||
changedBattalions: Vector[ChangedBattalion],
|
||||
newBattalions: Vector[NewBattalion]
|
||||
)
|
||||
) extends SelectedCommand(CommandType.OrganizeTroops)
|
||||
case PleaseRecruitMeSelected(provinceId: ProvinceId, heroId: HeroId, accept: Boolean)
|
||||
case ReconSelected(actingHeroId: HeroId, targetProvinceId: ProvinceId)
|
||||
case RecruitHeroesSelected(heroIds: Vector[HeroId])
|
||||
extends SelectedCommand(CommandType.PleaseRecruitMe)
|
||||
case ReconSelected(actingHeroId: HeroId, targetProvinceId: ProvinceId) extends SelectedCommand(CommandType.Recon)
|
||||
case RecruitHeroesSelected(heroIds: Vector[HeroId]) extends SelectedCommand(CommandType.RecruitHeroes)
|
||||
case ResolveAllianceOfferSelected(originatingFactionId: FactionId, resolution: Status)
|
||||
extends SelectedCommand(CommandType.ResolveAllianceOffer)
|
||||
case ResolveBreakAllianceSelected(originatingFactionId: FactionId, resolution: Status)
|
||||
extends SelectedCommand(CommandType.ResolveBreakAlliance)
|
||||
case ResolveInvitationSelected(originatingFactionId: FactionId, resolution: Status)
|
||||
extends SelectedCommand(CommandType.ResolveInvitation)
|
||||
case ResolveRansomOfferSelected(
|
||||
offeringFactionId: FactionId,
|
||||
prisonerHeroId: HeroId,
|
||||
resolution: Status
|
||||
)
|
||||
) extends SelectedCommand(CommandType.ResolveRansomOffer)
|
||||
case ResolveTruceOfferSelected(originatingFactionId: FactionId, resolution: Status)
|
||||
extends SelectedCommand(CommandType.ResolveTruceOffer)
|
||||
case ResolveTributeSelected(demandingFactionId: FactionId, paid: Boolean)
|
||||
case RestSelected
|
||||
case ReturnSelected
|
||||
extends SelectedCommand(CommandType.ResolveTribute)
|
||||
case RestSelected extends SelectedCommand(CommandType.Rest)
|
||||
case ReturnSelected extends SelectedCommand(CommandType.Return)
|
||||
case SendSuppliesSelected(
|
||||
gold: Int,
|
||||
food: Int,
|
||||
actingHeroId: HeroId,
|
||||
destinationProvinceId: ProvinceId
|
||||
)
|
||||
) extends SelectedCommand(CommandType.SendSupplies)
|
||||
case StartEpidemicSelected(selectedProvinceId: ProvinceId, actingHeroId: HeroId)
|
||||
extends SelectedCommand(CommandType.StartEpidemic)
|
||||
case SuppressBeastsSelected(heroId: HeroId, battalionId: Option[BattalionId])
|
||||
case SwearBrotherhoodSelected(newBrotherHeroId: HeroId)
|
||||
case TradeSelected(tradeType: TradeType, amount: Int)
|
||||
case TrainSelected(actingHeroId: HeroId)
|
||||
case TravelSelected
|
||||
extends SelectedCommand(CommandType.SuppressBeasts)
|
||||
case SwearBrotherhoodSelected(newBrotherHeroId: HeroId) extends SelectedCommand(CommandType.SwearBrotherhood)
|
||||
case TradeSelected(tradeType: TradeType, amount: Int) extends SelectedCommand(CommandType.Trade)
|
||||
case TrainSelected(actingHeroId: HeroId) extends SelectedCommand(CommandType.Train)
|
||||
case TravelSelected extends SelectedCommand(CommandType.Travel)
|
||||
end SelectedCommand
|
||||
|
||||
// Supporting enums specific to SelectedCommand
|
||||
|
||||
@@ -65,13 +65,13 @@ scala_library(
|
||||
":event",
|
||||
":incoming_end_turn_action",
|
||||
":orders",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:army",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battalion_type_id",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battle_revelation",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:captured_hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:improvement_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/date",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/quest",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/unaffiliated_hero",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.eagle0.eagle.model.state.province
|
||||
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.model.state.{
|
||||
Army,
|
||||
BattalionTypeId,
|
||||
@@ -12,6 +11,7 @@ import net.eagle0.eagle.model.state.{
|
||||
MovingArmy,
|
||||
MovingSupplies
|
||||
}
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.unaffiliated_hero.UnaffiliatedHeroT
|
||||
|
||||
@@ -87,7 +87,7 @@ trait ProvinceT {
|
||||
def castleCount: Int
|
||||
def heroCap: Int
|
||||
|
||||
def lastCommand: Option[SelectedCommand]
|
||||
def lastCommand: Option[CommandType]
|
||||
|
||||
def updateWith(
|
||||
name: String = name,
|
||||
@@ -126,7 +126,7 @@ trait ProvinceT {
|
||||
hexMapName: String = hexMapName,
|
||||
castleCount: Int = castleCount,
|
||||
heroCap: Int = heroCap,
|
||||
lastCommand: Option[SelectedCommand] = lastCommand
|
||||
lastCommand: Option[CommandType] = lastCommand
|
||||
): ProvinceT
|
||||
|
||||
def withRulingFactionId(rulingFactionId: FactionId): ProvinceT =
|
||||
|
||||
@@ -21,12 +21,12 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/province:orders",
|
||||
],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:army",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:battle_revelation",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:captured_hero",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state:improvement_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//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:deferred_change_trait",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.eagle0.eagle.model.state.province.concrete
|
||||
|
||||
import net.eagle0.eagle.{BattalionId, FactionId, HeroId, ProvinceId}
|
||||
import net.eagle0.eagle.api.selected_command.SelectedCommand
|
||||
import net.eagle0.eagle.model.state.{
|
||||
Army,
|
||||
BattalionTypeId,
|
||||
@@ -12,6 +11,7 @@ import net.eagle0.eagle.model.state.{
|
||||
MovingArmy,
|
||||
MovingSupplies
|
||||
}
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.date.Date
|
||||
import net.eagle0.eagle.model.state.province.{
|
||||
DeferredChangeT,
|
||||
@@ -62,7 +62,7 @@ case class ProvinceC(
|
||||
hexMapName: String = "",
|
||||
castleCount: Int = 0,
|
||||
heroCap: Int = 0,
|
||||
lastCommand: Option[SelectedCommand] = None
|
||||
lastCommand: Option[CommandType] = None
|
||||
) extends ProvinceT {
|
||||
override def updateWith(
|
||||
name: String = name,
|
||||
@@ -101,7 +101,7 @@ case class ProvinceC(
|
||||
hexMapName: String = hexMapName,
|
||||
castleCount: Int = castleCount,
|
||||
heroCap: Int = heroCap,
|
||||
lastCommand: Option[SelectedCommand] = lastCommand
|
||||
lastCommand: Option[CommandType] = lastCommand
|
||||
): ProvinceT =
|
||||
ProvinceC(
|
||||
id = this.id,
|
||||
|
||||
@@ -51,12 +51,19 @@ class AuthorizationInterceptor(jwtService: Option[JwtService] = None) extends Se
|
||||
Option(headers.get(IMPERSONATE_USER_KEY))
|
||||
.filter(_.nonEmpty)
|
||||
|
||||
private def isLocalhost[ReqT, RespT](call: ServerCall[ReqT, RespT]): Boolean = {
|
||||
// Check if the connection is from a trusted local source (localhost or Docker bridge network).
|
||||
// This is used to allow warmup/testing without JWT authentication.
|
||||
private def isLocalOrDocker[ReqT, RespT](call: ServerCall[ReqT, RespT]): Boolean = {
|
||||
val remoteAddr = call.getAttributes.get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR)
|
||||
remoteAddr match {
|
||||
case inet: InetSocketAddress =>
|
||||
val addr = inet.getAddress
|
||||
addr != null && (addr.isLoopbackAddress || addr.getHostAddress == "127.0.0.1" || addr.getHostAddress == "::1")
|
||||
addr != null && (
|
||||
addr.isLoopbackAddress || // 127.0.0.1, ::1
|
||||
addr.getHostAddress == "127.0.0.1" ||
|
||||
addr.getHostAddress == "::1" ||
|
||||
addr.isSiteLocalAddress // 10.x.x.x, 172.16-31.x.x, 192.168.x.x (Docker bridge networks)
|
||||
)
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
@@ -116,10 +123,10 @@ class AuthorizationInterceptor(jwtService: Option[JwtService] = None) extends Se
|
||||
Contexts.interceptCall(effectiveContext, call, headers, next)
|
||||
|
||||
case None =>
|
||||
// No valid JWT token - check for warmup user header (localhost only)
|
||||
// No valid JWT token - check for warmup user header (localhost or Docker bridge only)
|
||||
Option(headers.get(WARMUP_USER_KEY)).filter(_.nonEmpty) match {
|
||||
case Some(warmupUser) if isLocalhost(call) =>
|
||||
// Warmup/test user from localhost - set a simple context without JWT
|
||||
case Some(warmupUser) if isLocalOrDocker(call) =>
|
||||
// Warmup/test user from localhost or Docker bridge - set a simple context without JWT
|
||||
val warmupContext = AuthorizationUtils.contextWithJwtClaims(
|
||||
userId = s"warmup-$warmupUser",
|
||||
displayName = warmupUser,
|
||||
@@ -127,10 +134,10 @@ class AuthorizationInterceptor(jwtService: Option[JwtService] = None) extends Se
|
||||
accessToken = ""
|
||||
)
|
||||
Contexts.interceptCall(warmupContext, call, headers, next)
|
||||
case Some(_) =>
|
||||
// X-Warmup-User from non-localhost - ignore it, treat as unauthenticated
|
||||
case Some(_) =>
|
||||
// X-Warmup-User from non-local network - ignore it, treat as unauthenticated
|
||||
next.startCall(call, headers)
|
||||
case None =>
|
||||
case None =>
|
||||
// No auth at all - let endpoint handle unauthenticated request
|
||||
next.startCall(call, headers)
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ class EagleServiceImpl(
|
||||
case UniversalCommand.Empty =>
|
||||
throw new EagleClientException("Must include a command")
|
||||
}
|
||||
}.map(_ => PostCommandResponse())
|
||||
}.map(_ => PostCommandResponse(status = PostCommandResponse.Status.SUCCESS))
|
||||
|
||||
private class SyncStreamObserver(
|
||||
responseObserver: SyncResponseObserver
|
||||
@@ -626,14 +626,14 @@ class EagleServiceImpl(
|
||||
|
||||
val players = gameState.factions.map {
|
||||
case (factionId, faction) =>
|
||||
val leader = gameState.heroes(faction.factionHeadId)
|
||||
val leader = gameState.heroes.get(faction.factionHeadId)
|
||||
val userName = controller.userNameToFactionId.find { case (_, fid) => fid == factionId }
|
||||
.map(_._1)
|
||||
|
||||
RunningGamePlayerInfo(
|
||||
factionId = factionId,
|
||||
factionName = faction.name,
|
||||
leaderName = leader.nameTextId,
|
||||
factionName = Option(faction.name).filter(_.nonEmpty).getOrElse("[MISSING FACTION NAME]"),
|
||||
leaderName = leader.map(_.nameTextId).flatMap(Option(_)).filter(_.nonEmpty).getOrElse("[MISSING LEADER]"),
|
||||
isHuman = userName.isDefined,
|
||||
userName = userName.getOrElse("")
|
||||
)
|
||||
|
||||
@@ -112,6 +112,7 @@ scala_library(
|
||||
":loaded_hero_conversion",
|
||||
":start_date",
|
||||
":start_game_action_result_utils",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:chronicle_entry_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:action_result_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:battalion_scala_proto",
|
||||
|
||||
@@ -104,16 +104,42 @@ TEST_F(AIAttackerStrategySelectorTest,
|
||||
.strategyType);
|
||||
}
|
||||
|
||||
TEST_F(AIAttackerStrategySelectorTest,
|
||||
CanClaimCastles_castlesAvailable_returnsHoldCastlesStrategy) {
|
||||
TEST_F(AIAttackerStrategySelectorTest, DefenderNotOnCastle_returnsAttackUnitsStrategy) {
|
||||
CoordsSet criticalTileCoords(6, 6);
|
||||
criticalTileCoords.AddIndex(0);
|
||||
criticalTileCoords.AddIndex(1);
|
||||
// 2 critical tiles, 3 attackers
|
||||
|
||||
// defender not in critical tile
|
||||
// defender not in critical tile - they're scattering, so chase them
|
||||
defender->mutable_location() = Coords(2, 2);
|
||||
|
||||
EXPECT_EQ(
|
||||
AIStrategy::STRATEGY_ATTACK_UNITS,
|
||||
AIAttackerStrategySelector::BestAttackerStrategy(
|
||||
0,
|
||||
gameState,
|
||||
criticalTileCoords,
|
||||
GetGameSettings()->GetGetter().Backing().max_rounds(),
|
||||
apdCache,
|
||||
alCache,
|
||||
[](BattalionTypeId typeId) {
|
||||
return GetGameSettings()->GetGetter().GetBattalionType(typeId);
|
||||
},
|
||||
GetGameSettings()->GetGetter().Backing().brave_water_action_point_cost(),
|
||||
*waterCrossingCommandChooser,
|
||||
{})
|
||||
.strategyType);
|
||||
}
|
||||
|
||||
TEST_F(AIAttackerStrategySelectorTest, NoDefendersRemaining_returnsHoldCastlesStrategy) {
|
||||
CoordsSet criticalTileCoords(6, 6);
|
||||
criticalTileCoords.AddIndex(0);
|
||||
criticalTileCoords.AddIndex(1);
|
||||
// 2 critical tiles, 3 attackers
|
||||
|
||||
// defender has fled - no defenders remaining
|
||||
defender->mutate_status(net::eagle0::shardok::storage::fb::UnitStatus_FLED_UNIT);
|
||||
|
||||
EXPECT_EQ(
|
||||
AIStrategy::STRATEGY_HOLD_CASTLES,
|
||||
AIAttackerStrategySelector::BestAttackerStrategy(
|
||||
|
||||
+5
-13
@@ -1,7 +1,6 @@
|
||||
package net.eagle0.eagle.library.actions.availability
|
||||
|
||||
import net.eagle0.eagle.api.available_command.*
|
||||
import net.eagle0.eagle.api.selected_command.{ImproveSelectedCommand, MarchSelectedCommand, TrainSelectedCommand}
|
||||
import net.eagle0.eagle.common.combat_unit.CombatUnit
|
||||
import net.eagle0.eagle.common.improvement_type.ImprovementType.AGRICULTURE
|
||||
import net.eagle0.eagle.common.province_event.ImminentRiotEvent
|
||||
@@ -18,7 +17,7 @@ import net.eagle0.eagle.model.proto_converters.game_state.GameStateConverter
|
||||
import net.eagle0.eagle.model.state.command.available.AvailableCommand as ScalaAvailableCommand
|
||||
import net.eagle0.eagle.model.state.command.available.OneProvinceAvailableCommands
|
||||
import net.eagle0.eagle.model.state.command.common.ImprovementType
|
||||
import net.eagle0.eagle.model.state.command.selected.SelectedCommand as ScalaSelectedCommand
|
||||
import net.eagle0.eagle.model.state.command.CommandType
|
||||
import net.eagle0.eagle.model.state.game_state.GameState
|
||||
import org.scalamock.scalatest.MockFactory
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
@@ -706,7 +705,7 @@ class AvailableCommandsFactoryTest extends AnyFlatSpec with Matchers with MockFa
|
||||
|
||||
"shouldFollow" should "return true for train after train" in {
|
||||
AvailableCommandsFactory.shouldFollow(
|
||||
ScalaSelectedCommand.TrainSelected(actingHeroId = 4),
|
||||
CommandType.Train,
|
||||
ScalaAvailableCommand.TrainAvailable(
|
||||
actingProvinceId = 1,
|
||||
availableHeroIds = Vector(3, 4, 5),
|
||||
@@ -717,13 +716,7 @@ class AvailableCommandsFactoryTest extends AnyFlatSpec with Matchers with MockFa
|
||||
|
||||
it should "return false for march after march" in {
|
||||
AvailableCommandsFactory.shouldFollow(
|
||||
ScalaSelectedCommand.MarchSelected(
|
||||
gold = 10,
|
||||
food = 20,
|
||||
originProvince = 3,
|
||||
destinationProvinceId = 15,
|
||||
marchingUnits = Vector.empty
|
||||
),
|
||||
CommandType.March,
|
||||
ScalaAvailableCommand.MarchAvailable(
|
||||
oneProvinceCommands = Vector.empty,
|
||||
actingProvinceId = 17,
|
||||
@@ -734,8 +727,7 @@ class AvailableCommandsFactoryTest extends AnyFlatSpec with Matchers with MockFa
|
||||
|
||||
it should "return true for improve after improve" in {
|
||||
AvailableCommandsFactory.shouldFollow(
|
||||
ScalaSelectedCommand
|
||||
.ImproveSelected(improvementType = ImprovementType.Agriculture, actingHeroId = 3, lockType = false),
|
||||
CommandType.Improve,
|
||||
ScalaAvailableCommand.ImproveAvailable(
|
||||
availableTypes = Vector(ImprovementType.Agriculture),
|
||||
availableHeroIds = Vector.empty,
|
||||
@@ -748,7 +740,7 @@ class AvailableCommandsFactoryTest extends AnyFlatSpec with Matchers with MockFa
|
||||
|
||||
it should "return false for improve after train" in {
|
||||
AvailableCommandsFactory.shouldFollow(
|
||||
ScalaSelectedCommand.TrainSelected(actingHeroId = 3),
|
||||
CommandType.Train,
|
||||
ScalaAvailableCommand.ImproveAvailable(
|
||||
availableTypes = Vector(ImprovementType.Agriculture),
|
||||
availableHeroIds = Vector.empty,
|
||||
|
||||
@@ -78,9 +78,9 @@ scala_test(
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:riot_max_gold",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:idable",
|
||||
"//src/main/scala/net/eagle0/eagle/model/proto_converters/game_state",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command:command_type",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/common",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/command/selected",
|
||||
"//src/main/scala/net/eagle0/eagle/model/state/game_state",
|
||||
"@maven//:org_scalamock_scalamock_3",
|
||||
],
|
||||
|
||||
@@ -202,6 +202,7 @@ scala_test(
|
||||
name = "end_handle_riots_phase_action_test",
|
||||
srcs = ["EndHandleRiotsPhaseActionTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/applier:action_result_applier_impl",
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/impl/action:end_handle_riots_phase_action",
|
||||
|
||||
@@ -209,6 +209,7 @@ scala_test(
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/common:hostility_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:available_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/api:selected_command_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/common:round_phase_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:game_state_scala_proto",
|
||||
"//src/main/scala/net/eagle0/common:functional_random",
|
||||
|
||||
Reference in New Issue
Block a user