Skip to content

Commit 9782d2a

Browse files
committed
ci: release dev merges through Actions
1 parent 4965a83 commit 9782d2a

7 files changed

Lines changed: 180 additions & 65 deletions

File tree

.github/dependabot.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ version: 2
22
updates:
33
- package-ecosystem: "gradle"
44
directory: "/"
5+
target-branch: "dev"
56
schedule:
67
interval: "weekly"
78
day: "monday"
@@ -22,6 +23,7 @@ updates:
2223

2324
- package-ecosystem: "github-actions"
2425
directory: "/"
26+
target-branch: "dev"
2527
schedule:
2628
interval: "weekly"
2729
day: "monday"

.github/workflows/build.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ name: Build
33
on:
44
push:
55
branches:
6-
- main
76
- dev
87
pull_request:
8+
branches:
9+
- main
10+
- dev
911
workflow_dispatch:
1012

1113
jobs:

.github/workflows/release.yml

Lines changed: 140 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,104 @@
11
name: Release
22

33
on:
4-
push:
5-
tags:
6-
- "v*"
4+
pull_request:
5+
branches:
6+
- main
7+
types:
8+
- closed
79
workflow_dispatch:
810
inputs:
911
tag:
1012
description: "Existing tag to publish a release for (e.g. v0.9.1-beta.1)"
1113
required: true
14+
type: string
15+
16+
concurrency:
17+
group: release-main
18+
queue: max
1219

1320
permissions:
14-
contents: write
21+
contents: read
1522

1623
jobs:
24+
prepare-release:
25+
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main' && github.event.pull_request.head.ref == 'dev' && github.event.pull_request.head.repo.full_name == github.repository)
26+
runs-on: ubuntu-latest
27+
outputs:
28+
prerelease: ${{ steps.metadata.outputs.prerelease }}
29+
source_sha: ${{ steps.metadata.outputs.source_sha }}
30+
tag: ${{ steps.metadata.outputs.tag }}
31+
version: ${{ steps.metadata.outputs.version }}
32+
33+
steps:
34+
- name: Checkout release source
35+
uses: actions/checkout@v7
36+
with:
37+
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.event.pull_request.merge_commit_sha }}
38+
fetch-depth: 0
39+
40+
- name: Resolve and validate release metadata
41+
id: metadata
42+
shell: bash
43+
env:
44+
REQUESTED_TAG: ${{ inputs.tag }}
45+
run: |
46+
set -euo pipefail
47+
48+
SOURCE_SHA="$(git rev-parse HEAD)"
49+
BUILD_VERSION="$(sed -n 's/^version = "\([^"]*\)"/\1/p' build.gradle.kts | head -n 1)"
50+
if [[ ! "$BUILD_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
51+
echo "::error::build.gradle.kts has an invalid release version: $BUILD_VERSION"
52+
exit 1
53+
fi
54+
if [[ "$BUILD_VERSION" == *SNAPSHOT* ]]; then
55+
echo "::error::Snapshot versions cannot be released: $BUILD_VERSION"
56+
exit 1
57+
fi
58+
59+
TAG="v$BUILD_VERSION"
60+
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
61+
if [[ ! "$REQUESTED_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
62+
echo "::error::Invalid release tag: $REQUESTED_TAG"
63+
exit 1
64+
fi
65+
if [[ "$REQUESTED_TAG" != "$TAG" ]]; then
66+
echo "::error::Requested tag $REQUESTED_TAG does not match build.gradle.kts version $BUILD_VERSION"
67+
exit 1
68+
fi
69+
fi
70+
71+
if [[ ! -f CHANGELOG.md ]] || ! grep -Eq "^## ${BUILD_VERSION//./\\.}([[:space:]]|$)" CHANGELOG.md; then
72+
echo "::error::CHANGELOG.md has no section for $BUILD_VERSION"
73+
exit 1
74+
fi
75+
76+
REMOTE_TAG_SHA="$(git ls-remote --tags origin "refs/tags/$TAG^{}" | awk 'NR == 1 { print $1 }')"
77+
if [[ -z "$REMOTE_TAG_SHA" ]]; then
78+
REMOTE_TAG_SHA="$(git ls-remote --tags origin "refs/tags/$TAG" | awk 'NR == 1 { print $1 }')"
79+
fi
80+
81+
if [[ -n "$REMOTE_TAG_SHA" && "$REMOTE_TAG_SHA" != "$SOURCE_SHA" ]]; then
82+
echo "::error::$TAG already points to $REMOTE_TAG_SHA instead of release source $SOURCE_SHA"
83+
exit 1
84+
fi
85+
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" && -z "$REMOTE_TAG_SHA" ]]; then
86+
echo "::error::Manual recovery requires an existing tag: $TAG"
87+
exit 1
88+
fi
89+
90+
if [[ "$BUILD_VERSION" == *-* ]]; then
91+
PRERELEASE=true
92+
else
93+
PRERELEASE=false
94+
fi
95+
echo "prerelease=$PRERELEASE" >> "$GITHUB_OUTPUT"
96+
echo "source_sha=$SOURCE_SHA" >> "$GITHUB_OUTPUT"
97+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
98+
echo "version=$BUILD_VERSION" >> "$GITHUB_OUTPUT"
99+
17100
build-platform:
101+
needs: prepare-release
18102
strategy:
19103
fail-fast: false
20104
matrix:
@@ -41,7 +125,7 @@ jobs:
41125
- name: Checkout
42126
uses: actions/checkout@v7
43127
with:
44-
ref: ${{ github.event.inputs.tag || github.ref }}
128+
ref: ${{ needs.prepare-release.outputs.source_sha }}
45129

46130
- name: Set up Windows native toolchain
47131
if: runner.os == 'Windows'
@@ -124,6 +208,7 @@ jobs:
124208
with:
125209
name: mahjong-paper-jar-${{ matrix.artifact }}
126210
path: build/libs/*.jar
211+
if-no-files-found: error
127212

128213
package-universal:
129214
needs: build-platform
@@ -200,69 +285,64 @@ jobs:
200285
with:
201286
name: mahjong-paper-jars
202287
path: build/universal/*.jar
288+
if-no-files-found: error
203289

204290
release:
205-
needs: package-universal
291+
needs:
292+
- prepare-release
293+
- package-universal
294+
permissions:
295+
contents: write
206296
runs-on: ubuntu-latest
207297

208298
steps:
209299
- name: Checkout
210300
uses: actions/checkout@v7
211301
with:
212-
ref: ${{ github.event.inputs.tag || github.ref }}
213-
# Need the full history so the fast-forward step can verify ancestry between main and the tag commit.
302+
ref: ${{ needs.prepare-release.outputs.source_sha }}
214303
fetch-depth: 0
215304

216-
- name: Resolve release tag
217-
id: tag
218-
shell: bash
219-
run: |
220-
set -euo pipefail
221-
if [[ -n "${{ github.event.inputs.tag }}" ]]; then
222-
TAG="${{ github.event.inputs.tag }}"
223-
else
224-
TAG="${GITHUB_REF#refs/tags/}"
225-
fi
226-
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
227-
if [[ "$TAG" == *-beta* || "$TAG" == *-alpha* || "$TAG" == *-rc* ]]; then
228-
echo "prerelease=true" >> "$GITHUB_OUTPUT"
229-
else
230-
echo "prerelease=false" >> "$GITHUB_OUTPUT"
231-
fi
232-
233305
- name: Extract changelog notes
234306
id: notes
235307
shell: bash
308+
env:
309+
RELEASE_TAG: ${{ needs.prepare-release.outputs.tag }}
236310
run: |
237311
set -euo pipefail
238-
VERSION="${{ steps.tag.outputs.tag }}"
312+
VERSION="$RELEASE_TAG"
239313
VERSION="${VERSION#v}"
240314
NOTES_FILE="release-notes.md"
241315
if [[ -f CHANGELOG.md ]]; then
242316
awk -v ver="$VERSION" '
243-
$0 ~ "^## " ver " " { capture=1; next }
317+
$1 == "##" && $2 == ver { capture=1; next }
244318
capture && /^## / { exit }
245319
capture { print }
246320
' CHANGELOG.md > "$NOTES_FILE"
247321
fi
248322
if [[ ! -s "$NOTES_FILE" ]]; then
249-
echo "Release ${{ steps.tag.outputs.tag }}" > "$NOTES_FILE"
323+
echo "Release $RELEASE_TAG" > "$NOTES_FILE"
250324
fi
251325
echo "file=$NOTES_FILE" >> "$GITHUB_OUTPUT"
252326
253-
- name: Verify release version metadata
327+
- name: Revalidate release source metadata
254328
shell: bash
329+
env:
330+
RELEASE_TAG: ${{ needs.prepare-release.outputs.tag }}
331+
RELEASE_VERSION: ${{ needs.prepare-release.outputs.version }}
332+
SOURCE_SHA: ${{ needs.prepare-release.outputs.source_sha }}
255333
run: |
256334
set -euo pipefail
257-
VERSION="${{ steps.tag.outputs.tag }}"
258-
VERSION="${VERSION#v}"
335+
if [[ "$(git rev-parse HEAD)" != "$SOURCE_SHA" ]]; then
336+
echo "::error::Checked out source does not match prepared release commit $SOURCE_SHA"
337+
exit 1
338+
fi
259339
BUILD_VERSION="$(sed -n 's/^version = "\([^"]*\)"/\1/p' build.gradle.kts | head -n 1)"
260-
if [[ -z "$BUILD_VERSION" || "$BUILD_VERSION" != "$VERSION" ]]; then
261-
echo "::error::Release tag version $VERSION does not match build.gradle.kts version $BUILD_VERSION"
340+
if [[ -z "$BUILD_VERSION" || "$BUILD_VERSION" != "$RELEASE_VERSION" || "$RELEASE_TAG" != "v$BUILD_VERSION" ]]; then
341+
echo "::error::Release metadata changed after preparation"
262342
exit 1
263343
fi
264-
if [[ ! -f CHANGELOG.md ]] || ! grep -Eq "^## ${VERSION//./\\.}([[:space:]]|$)" CHANGELOG.md; then
265-
echo "::error::CHANGELOG.md has no section for $VERSION"
344+
if [[ ! -f CHANGELOG.md ]] || ! grep -Eq "^## ${BUILD_VERSION//./\\.}([[:space:]]|$)" CHANGELOG.md; then
345+
echo "::error::CHANGELOG.md has no section for $BUILD_VERSION"
266346
exit 1
267347
fi
268348
@@ -272,34 +352,33 @@ jobs:
272352
name: mahjong-paper-jars
273353
path: release-artifacts
274354

275-
- name: Publish GitHub Release
276-
uses: softprops/action-gh-release@v3
277-
with:
278-
tag_name: ${{ steps.tag.outputs.tag }}
279-
name: ${{ steps.tag.outputs.tag }}
280-
body_path: ${{ steps.notes.outputs.file }}
281-
prerelease: ${{ steps.tag.outputs.prerelease }}
282-
files: release-artifacts/*.jar
283-
284-
- name: Fast-forward main to released tag
285-
if: steps.tag.outputs.prerelease == 'false'
355+
- name: Create release tag
286356
shell: bash
287357
env:
288-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
358+
RELEASE_TAG: ${{ needs.prepare-release.outputs.tag }}
359+
SOURCE_SHA: ${{ needs.prepare-release.outputs.source_sha }}
289360
run: |
290361
set -euo pipefail
291-
TAG="${{ steps.tag.outputs.tag }}"
292-
TAG_SHA="$(git rev-parse "$TAG"^{commit})"
293-
echo "Tag $TAG resolves to commit $TAG_SHA"
294-
git fetch origin main:refs/remotes/origin/main
295-
MAIN_SHA="$(git rev-parse origin/main)"
296-
if [[ "$MAIN_SHA" == "$TAG_SHA" ]]; then
297-
echo "main is already at $TAG_SHA, nothing to do."
298-
exit 0
299-
fi
300-
if ! git merge-base --is-ancestor "$MAIN_SHA" "$TAG_SHA"; then
301-
echo "::warning::main ($MAIN_SHA) is not an ancestor of $TAG ($TAG_SHA); skipping fast-forward."
302-
exit 0
362+
git fetch origin --tags --force
363+
if git rev-parse --verify --quiet "refs/tags/$RELEASE_TAG" >/dev/null; then
364+
EXISTING_SHA="$(git rev-list -n 1 "$RELEASE_TAG")"
365+
if [[ "$EXISTING_SHA" != "$SOURCE_SHA" ]]; then
366+
echo "::error::$RELEASE_TAG moved to $EXISTING_SHA after preparation; expected $SOURCE_SHA"
367+
exit 1
368+
fi
369+
echo "$RELEASE_TAG already points to $SOURCE_SHA; reusing it."
370+
else
371+
git config user.name "github-actions[bot]"
372+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
373+
git tag -a "$RELEASE_TAG" "$SOURCE_SHA" -m "Release $RELEASE_TAG"
374+
git push origin "refs/tags/$RELEASE_TAG"
303375
fi
304-
git push "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "$TAG_SHA:refs/heads/main"
305-
echo "Fast-forwarded main to $TAG_SHA"
376+
377+
- name: Publish GitHub Release
378+
uses: softprops/action-gh-release@v3
379+
with:
380+
tag_name: ${{ needs.prepare-release.outputs.tag }}
381+
name: ${{ needs.prepare-release.outputs.tag }}
382+
body_path: ${{ steps.notes.outputs.file }}
383+
prerelease: ${{ needs.prepare-release.outputs.prerelease }}
384+
files: release-artifacts/*.jar

.github/workflows/test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ name: Test
33
on:
44
push:
55
branches:
6-
- main
76
- dev
87
pull_request:
8+
branches:
9+
- main
10+
- dev
911
workflow_dispatch:
1012

1113
jobs:

CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,35 @@
11
# Changelog
22

3+
## 1.5.0 - 2026-07-16
4+
5+
Feature release for table interaction, river viewing, rules accuracy, storage integration, runtime compatibility, and performance.
6+
7+
中文更新日志:
8+
9+
- **升级要求**:发行包改用 Java 21 字节码,并要求 CraftEngine 26.7 或更高版本。更换 MahjongPaper、CraftEngine 或 InvSync 后必须完整重启服务器。
10+
- **牌河俯视与操作恢复**:新增无需客户端 Mod 的平滑客户端俯视镜头。按 Shift 返回座位后会按当前实时状态恢复定缺、吃碰杠、出牌等操作;俯视期间 ActionBar 倒计时继续运行,超时操作仍会正常执行。
11+
- **倒计时与托管**:连续自动出牌后的下一次时限依次为 60、30、15、10 秒,之后保持 10 秒;玩家手动出牌后恢复 60 秒。只有实际离座或掉线才会交给机器人托管,快速按 Shift 或切换俯视镜头不再夺走玩家控制权。
12+
- **射线交互与隐藏信息**:麻将牌和扁平文字改由精确服务端射线盒决定操作,并仅向相关观察者发送必要的客户端代理,修复加入、定缺、吃碰和出牌偶发无法点击的问题。自己的手牌保持明牌,其他玩家手牌和牌墙只发送未知牌面。
13+
- **牌桌显示与反馈**:修复牌墙上层失去下层支撑后仍悬空、牌面和交互区域不一致、提示文字重叠等布局问题,并统一 ActionBar、聊天提示、牌桌音效和玩家操作反馈。
14+
- **三种玩法校正**:GB 模式对齐 144 张牌、花牌、8 个非花番门槛、单和与固定 16 局流程;立直模式修正鸣牌优先级、振听、杠宝牌时机、流局与延长赛边界;四川模式对齐 T/TFMJ 的直接定缺、无换三张、三番封顶、血战到底、杠分转移和查叫流程。
15+
- **段位与服务器集成**:新增可选 InvSync 2.x 玩家段位存储,并在 InvSync 缺失或不兼容时仅向已启用且健康的 SQL 后端回退。当前自动段位与统计更新仍只适用于四名真人完成的立直对局。
16+
- **资源与本地化**:加入 GB、立直和四川模式对应的摸牌、出牌、鸣牌、流局与和牌音效;新增完整日语游戏消息、安装文档和三种玩法说明。
17+
- **性能与稳定性**:减少牌桌区域更新、展示实体复用、观察者集合和 GB Bot 决策热路径中的排序、装箱及临时分配;缓存调度器反射解析,并加入 GitHub Actions 配对 A/B 性能回归门禁。
18+
- **分发说明**:发行 JAR 现在内嵌并重定位 Sparrow Reflection 与 ASM。第三方声明和运行软件分发条款已更新,重新分发时应保留对应许可证与源码义务说明。
19+
20+
English Release Notes:
21+
22+
- **Upgrade requirements**: Release artifacts now use Java 21 bytecode and require CraftEngine 26.7 or newer. Fully restart the server after replacing MahjongPaper, CraftEngine, or InvSync.
23+
- **River view and control restoration**: Added a smooth client-only overhead camera that requires no client mod. Returning with Shift rebuilds ding-que, reaction, and discard controls from live game state. ActionBar deadlines continue running while viewing the river, and expired decisions still resolve normally.
24+
- **Deadlines and bot ownership**: Consecutive automatic discards shorten the next turn from 60 to 30, 15, and then 10 seconds; later automatic turns remain at 10 seconds. A manual discard restores 60 seconds. Bot control now begins only after a real dismount or disconnect, not a quick Shift press or camera transition.
25+
- **Ray interaction and hidden information**: Mahjong tiles and flat text now use exact server-side ray geometry, backed only by the per-viewer client proxies needed to make vanilla clients report a click. This fixes intermittent join, ding-que, reaction, and discard input failures. Owners receive their visible hand while other hands and wall tiles use unknown faces.
26+
- **Table rendering and feedback**: Fixed unsupported upper wall tiles remaining suspended, mismatched visual and interaction geometry, overlapping controls, and inconsistent ActionBar, chat, sound, and table feedback.
27+
- **Rules corrections**: GB now follows the 144-tile flower flow, eight non-flower-fan floor, single-ron priority, and fixed 16-hand profile. Riichi fixes cover reaction priority, furiten, kan-dora timing, draws, and match extensions. Sichuan now follows the documented T/TFMJ direct ding-que, no exchange-three, three-fan cap, Bloody Battle, kong-transfer, and cha-jiao flow.
28+
- **Rank and server integrations**: Added optional InvSync 2.x player-rank storage, with fallback only to an enabled and healthy SQL backend. Automatic rank and personal-stat updates remain limited to completed four-human Riichi matches.
29+
- **Assets and localization**: Added mode-specific draw, discard, reaction, draw-result, and win sounds for GB, Riichi, and Sichuan, plus complete Japanese game messages and player documentation.
30+
- **Performance and reliability**: Reduced sorting, boxing, and temporary allocations in region updates, display reconciliation, viewer membership handling, and GB bot decisions; cached scheduler reflection resolution and added paired GitHub Actions A/B performance gates.
31+
- **Distribution notice**: Release jars now embed and relocate Sparrow Reflection and ASM. Third-party notices and runnable-distribution terms were updated; redistributors must preserve the applicable license and source-obligation notices.
32+
333
## 1.4.1 - 2026-06-18
434

535
Hotfix for game room exit countdown behavior.

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ plugins {
1616
}
1717

1818
group = "top.ellan"
19-
version = "1.4.1"
19+
version = "1.5.0"
2020
val minimumPaperDevBundleVersion = "1.20.1-R0.1-SNAPSHOT"
2121
val paperDevBundleVersion =
2222
providers

docs/performance-testing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ python perf/live/download_locked.py `
414414
--destination build/live-cache/craft-engine-paper-plugin-26.7.3.jar
415415
python perf/live/run_server.py `
416416
--paper-jar build/live-cache/server.jar `
417-
--plugin-jar build/libs/mahjong-paper-1.4.1.jar `
417+
--plugin-jar build/libs/mahjong-paper-1.5.0.jar `
418418
--craftengine-jar build/live-cache/craft-engine-paper-plugin-26.7.3.jar `
419419
--required-plugin MahjongPaper `
420420
--scenario-name majsoul-hanchan-four-bot-spectator `

0 commit comments

Comments
 (0)