Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Acecore build verification
on:
push:
branches: [v3.0, 'codex/**']
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: build-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-24.04
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
platform: [core, spigot]
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
persist-credentials: false
- uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: '21'
- name: Test shared core
if: matrix.platform == 'core'
run: bash gradlew -PdynmapPlatform=core :DynmapCore:test --no-daemon --console=plain
- name: Build and inspect Spigot jar
if: matrix.platform == 'spigot'
run: bash gradlew -PdynmapPlatform=spigot verifySpigotJar --no-daemon --console=plain
- name: Preserve verification reports (no plugin binaries)
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: verification-${{ matrix.platform }}-${{ github.sha }}
retention-days: 14
if-no-files-found: warn
path: |
DynmapCore/build/reports/tests/
DynmapCore/build/test-results/
build/reports/acecore/
14 changes: 0 additions & 14 deletions .github/workflows/spellcheck.yaml

This file was deleted.

4 changes: 2 additions & 2 deletions DynmapCore/src/main/java/org/dynmap/DynmapCore.java
Original file line number Diff line number Diff line change
Expand Up @@ -711,9 +711,9 @@ public void playerEvent(DynmapPlayer p) {

/* Print version info */
Log.info("version " + plugin_ver + " is enabled - core version " + version );
Log.info("For support, visit our Discord at https://discord.gg/s3rd5qn");
Log.info("Unofficial Acecore build; support: https://github.com/acecore-systems/dynmap/issues");
Log.info("For news, visit https://reddit.com/r/Dynmap or follow https://universeodon.com/@dynmap");
Log.info("To report or track bugs, visit https://github.com/webbukkit/dynmap/issues");
Log.info("Upstream Dynmap: https://github.com/webbukkit/dynmap (do not report fork-only bugs upstream)");
Log.info("If you'd like to donate, please visit https://www.patreon.com/dynmap or https://ko-fi.com/michaelprimm");

events.<Object>trigger("initialized", null);
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
> **Unofficial Acecore fork.** Support: https://github.com/acecore-systems/dynmap/issues
> Build and maintenance: [docs/acecore-maintenance.md](docs/acecore-maintenance.md).
> Not supported or endorsed by the Dynmap team. Original upstream documentation follows.

# Dynmap® - dynamic web maps for Minecraft servers

# Jump around the README
Expand Down
29 changes: 24 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ eclipse {

allprojects {
repositories {
mavenLocal()
if (providers.gradleProperty('useMavenLocal').isPresent()) { mavenLocal() }
mavenCentral()
maven { url "https://repo.mikeprimm.com" }
maven { url 'https://libraries.minecraft.net/' }
maven { url "https://oss.sonatype.org/content/repositories/releases" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
maven { url "https://repo.mikeprimm.com" }
maven { url "https://repo.maven.apache.org/maven2" }
maven { url "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" }
maven { url "https://repo.codemc.org/repository/maven-public/" }
}
Expand All @@ -46,10 +46,19 @@ allprojects {
}

class Globals {
String buildNumber = System.getenv().BUILD_NUMBER ?: "Dev"
String buildNumber
}
def gitOutput = { List<String> arguments ->
def output = new ByteArrayOutputStream()
exec { commandLine(['git'] + arguments); standardOutput = output }
output.toString('UTF-8').trim()
}
def sourceRevision = gitOutput(['rev-parse', 'HEAD'])
def sourceDirty = !gitOutput(['status', '--porcelain', '--untracked-files=normal']).isEmpty()
ext {
globals = new Globals()
acecoreRevision = sourceRevision
acecoreDirty = sourceDirty
globals = new Globals(buildNumber: 'acecore-' + sourceRevision.take(12) + (sourceDirty ? '-dirty' : ''))
}

subprojects {
Expand All @@ -62,8 +71,18 @@ subprojects {
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
tasks.withType(ProcessResources).configureEach {
inputs.property('acecoreBuildNumber', rootProject.ext.globals.buildNumber)
inputs.property('dynmapVersion', project.version.toString())
}
tasks.withType(AbstractArchiveTask).configureEach {
preserveFileTimestamps = false
reproducibleFileOrder = true
}
}

apply from: 'gradle/acecore-verification.gradle'

clean {
delete "target"
}
Expand Down
74 changes: 74 additions & 0 deletions docs/acecore-maintenance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Acecore fork のビルドと検証

このforkは非公式で、Dynmapチームによるサポート・推奨を受けていません。
不具合の窓口は [Acecore Issues](https://github.com/acecore-systems/dynmap/issues) です。
元コードは [webbukkit/dynmap](https://github.com/webbukkit/dynmap) で、著作権表示、
Apache-2.0 の LICENSE、上流 README のカスタムビルド・商標・配布方針を維持します。
現段階は特定サーバーでの検証用ソースとCI整備です。CIからJARを一般配布しません。
公開配布は上流READMEの条件と対応状況を改めて確認する別の判断です。

## ビルド

Git、JDK 21、Gradle wrapper 8.14 を使います。Windowsでは `bash gradlew` を
`gradlew.bat` に読み替えてください。

```sh
bash gradlew -PdynmapPlatform=core :DynmapCore:test --no-daemon
bash gradlew -PdynmapPlatform=spigot verifySpigotJar --no-daemon
```

プロファイル省略時は上流と同じ全モジュールを構成します。`core` は共有コア/API、
`spigot` はそれらと既存の全Bukkit helper/API/Spigotを構成します。
異なるローダーの初期化を省く仕組みであり、Forge/Fabricの検証成功を意味しません。
共有コアを上流に提案するときは、上流READMEどおり全対象プラットフォームの検証が必要です。
Minecraft 26.2 / Java 25 の候補対応は Issue #2 で別に管理します。

`mavenLocal()` は明示的な `-PuseMavenLocal` のときだけ有効です。CIは使いません。
既存の Maven Central / Minecraft / MikePrimm / Spigot / CodeMC / Sonatype / JitPack
への参照を維持し、不要なリポジトリ巡回を減らすためCentralとMikePrimmを先にします。
既存依存のバージョンは変更しません。SNAPSHOTや動的指定は残っているため、
同じソースでも将来同じ依存が取得できる保証はありません。
`build/reports/acecore/build.json` は実際に解決した依存の座標とSHA-256を記録します。
これは監査記録であり、依存ロックや脆弱性評価の代替ではありません。

版番号は `3.9-SNAPSHOT-acecore-<HEADの12桁>[-dirty]` です。
Git管理ファイルまたは未追跡ソースの変更がある場合はdirtyを付けます。
`BUILD_NUMBER` による上書きはしません。版番号をリソース処理の入力にして、
コミット後の再ビルドでも plugin.yml / core.yml が更新されるようにしています。
アーカイブ内の日時と順序を固定しますが、依存を含む完全な再現性は未保証です。

`verifySpigotJar` はコアテスト、JAR生成、Jetty/Servlet/S3/bStats/ブラウザ資材の存在、
版番号の整合を検査し、SHA256SUMS.txtとbuild.jsonを出力します。
GitHub Actions は固定SHAのアクション、contents:read、認証情報を残さないcheckoutを使い、
テスト結果と監査記録だけを14日保存します。秘密値・実サーバー設定を必要としません。
この構成は自動デプロイ、Release作成、Maven公開を行いません。

## 変更と同期

default branch `v3.0` を安定基点とし、Issueごとの `codex/*` branch/worktreeで作業します。
上流の追従候補はコミットSHAを固定して差分・依存・ライセンスをレビューし、
必要なソースだけを別PRに取り込みます。上流の生成済みJARは取り込みません。
CI成功後もdraft PRで差分と検証範囲を確認し、マージと本番反映を区別します。

| Issue | 独自差分 | 管理方法 |
| --- | --- | --- |
| #1 | R2の境界スナップショットと同一位置マーカーの更新抑制 | 独立PR、回帰テスト・隔離サーバー比較 |
| #2 | Minecraft 26.2候補、helper・モデル・Java/Gradle互換性 | 上流SHAと採否・既知制限を記録する独立PR |
| #3 | ビルド対象選択、CI、版識別、同梱検査、非公式窓口 | この文書とワークフロー |

## 段階的な稼働検証

1. 読み取り専用で稼働版、Java、設定、拡張プラグイン、エラーを確認し検証先を選ぶ。
2. 同じPaper版の隔離サーバーに新規ワールドを作り、既存地図・R2接続を持ち込まず検証する。
3. 起動、初期レンダー、実ブロック更新、ズーム、境界・スポーン・連携マーカー、停止を確認する。
4. 候補のコミット・版・SHA-256と検証証拠を揃え、本番反映の承認を得る。
5. 現行JAR・設定・連携プラグイン・必要データをバックアップし、復旧可能性を確かめる。
自動更新が候補JARを上書きしないことも実環境で確認する。
6. 選定した1台だけに反映し、予定された安全な停止/起動で有効化する。
既存タイル・ワールド・R2オブジェクトを削除しない。
7. エラー、地図更新、利用者影響、R2 originの変更を観測する。
キャッシュされたHTTP応答やLast-ModifiedだけからPUT件数・料金を断定しない。
8. 起動失敗、描画欠落、連携不具合があれば候補を外し、バックアップJAR/設定へ戻す。
ロールバック時も停止/起動の時機を確認し、地図を一括再生成しない。

ホスト名、内部パス、認証情報、実プレイヤー情報は公開PR・CI artifactに記載しません。
69 changes: 69 additions & 0 deletions gradle/acecore-verification.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import groovy.json.JsonOutput
import java.security.MessageDigest
import java.util.zip.ZipFile

def sha256 = { File file ->
def digest = MessageDigest.getInstance('SHA-256')
file.withInputStream { stream ->
byte[] buffer = new byte[65536]
int count
while ((count = stream.read(buffer)) != -1) { digest.update(buffer, 0, count) }
}
digest.digest().encodeHex().toString()
}

if (findProject(':spigot') != null) {
tasks.register('verifySpigotJar') {
dependsOn ':spigot:shadowJar', ':DynmapCore:test'
doLast {
File jar = project(':spigot').tasks.named('shadowJar').get().archiveFile.get().asFile
String expectedVersion = "${project.version}-${globals.buildNumber}"
new ZipFile(jar).withCloseable { zip ->
[
'org/dynmap/bukkit/DynmapPlugin.class',
'org/dynmap/DynmapCore.class',
'org/dynmap/jetty/server/Server.class',
'org/dynmap/jetty/servlet/ServletContextHandler.class',
'org/dynmap/javax/servlet/Servlet.class',
'org/dynmap/bstats/bukkit/Metrics.class',
'org/dynmap/s3lite/api/client/S3Client.class',
'extracted/web/js/map.js'
].each { name ->
if (zip.getEntry(name) == null) { throw new GradleException("Missing runtime entry: ${name}") }
}
['plugin.yml', 'core.yml'].each { name ->
def entry = zip.getEntry(name)
if (entry == null || !zip.getInputStream(entry).getText('UTF-8').contains('version: "' + expectedVersion + '"')) {
throw new GradleException("Unexpected ${name} version; expected ${expectedVersion}")
}
}
}
def dependencies = []
subprojects.sort { it.path }.each { p ->
['compileClasspath', 'runtimeClasspath', 'testRuntimeClasspath'].each { name ->
def config = p.configurations.findByName(name)
if (config != null && config.canBeResolved) {
config.resolvedConfiguration.resolvedArtifacts.each { artifact ->
if (artifact.id.componentIdentifier instanceof org.gradle.api.artifacts.component.ModuleComponentIdentifier) {
dependencies << [module: artifact.moduleVersion.id.toString(), file: artifact.file.name,
sha256: sha256(artifact.file)]
}
}
}
}
}
File reportDir = layout.buildDirectory.dir('reports/acecore').get().asFile
reportDir.mkdirs()
def checksum = sha256(jar)
new File(reportDir, 'SHA256SUMS.txt').text = "${checksum} ${jar.name}\n"
new File(reportDir, 'build.json').text = JsonOutput.prettyPrint(JsonOutput.toJson([
revision: acecoreRevision, dirty: acecoreDirty, version: expectedVersion,
platform: providers.gradleProperty('dynmapPlatform').getOrElse('all'),
gradle: gradle.gradleVersion, java: System.getProperty('java.version'),
jar: jar.name, sha256: checksum,
dependencies: dependencies.unique().sort { a, b -> (a.module + a.file) <=> (b.module + b.file) }
])) + '\n'
logger.lifecycle("Verified ${jar.name}: ${expectedVersion}; SHA-256 ${checksum}")
}
}
}
1 change: 1 addition & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionSha256Sum=61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa
Loading
Loading