Skip to content

Commit 97beec7

Browse files
committed
Release hardening for Tensa 3.0.0
1 parent acffeb3 commit 97beec7

50 files changed

Lines changed: 2206 additions & 711 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/maven.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: TENSA
1+
name: Tensa
22

33
permissions:
44
contents: write
@@ -14,16 +14,16 @@ jobs:
1414
runs-on: ubuntu-latest
1515

1616
steps:
17-
- uses: actions/checkout@v3
17+
- uses: actions/checkout@v4
1818

1919
- name: Create Tag
2020
id: create_tag
2121
run: echo "RELEASE_TAG=$(date +'%Y-%m-%d-%H-%M')" >> $GITHUB_ENV
2222

23-
- name: Set up JDK 17
24-
uses: actions/setup-java@v3
23+
- name: Set up JDK 21
24+
uses: actions/setup-java@v4
2525
with:
26-
java-version: '17'
26+
java-version: '21'
2727
distribution: 'temurin'
2828
cache: maven
2929

@@ -36,13 +36,13 @@ jobs:
3636
- name: Find JAR File
3737
id: find_jar
3838
run: |
39-
FILE="target/TENSA.jar"
39+
FILE="target/Tensa.jar"
4040
echo "JAR_PATH=$FILE" >> $GITHUB_ENV
4141
4242
- name: Upload Artifacts
4343
uses: actions/upload-artifact@v4
4444
with:
45-
name: TENSA
45+
name: Tensa
4646
path: ${{ env.JAR_PATH }}
4747

4848
- name: Create Release
@@ -65,5 +65,5 @@ jobs:
6565
with:
6666
upload_url: ${{ steps.create_release.outputs.upload_url }}
6767
asset_path: ${{ env.JAR_PATH }}
68-
asset_name: TENSA.jar
68+
asset_name: Tensa.jar
6969
asset_content_type: application/java-archive

.run/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
velocity/

.run/TensaDevVelocity.run.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="Tensa Dev Velocity" type="ShConfigurationType" singleton="false">
3+
<option name="INDEPENDENT_SCRIPT_PATH" value="false" />
4+
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/.run/run-velocity.cmd" />
5+
<option name="SCRIPT_OPTIONS" value="" />
6+
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
7+
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
8+
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
9+
<option name="INTERPRETER_PATH" value="" />
10+
<option name="INTERPRETER_OPTIONS" value="" />
11+
<option name="EXECUTE_IN_TERMINAL" value="true" />
12+
<envs />
13+
<method v="2" />
14+
</configuration>
15+
</component>

.run/run-velocity.cmd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@echo off
2+
where pwsh >nul 2>&1
3+
if %errorlevel%==0 (
4+
pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0run-velocity.ps1" %*
5+
) else (
6+
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0run-velocity.ps1" %*
7+
)

.run/run-velocity.ps1

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
param(
2+
[switch]$SkipBuild,
3+
[switch]$WithTests,
4+
[string]$VelocityVersion,
5+
[int]$Port = 25577
6+
)
7+
8+
$ErrorActionPreference = "Stop"
9+
$ProgressPreference = "SilentlyContinue"
10+
11+
$projectRoot = Split-Path $PSScriptRoot -Parent
12+
$runtimeRoot = Join-Path $projectRoot ".run\velocity"
13+
$pluginsDir = Join-Path $runtimeRoot "plugins"
14+
$resolvedJava = Get-Command java.exe -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty Source
15+
$javaCmd = if ($env:JAVA_HOME) {
16+
Join-Path $env:JAVA_HOME "bin\java.exe"
17+
} elseif ($resolvedJava) {
18+
$resolvedJava
19+
} else {
20+
"java"
21+
}
22+
23+
function Get-ProjectMetadata {
24+
[xml]$pom = Get-Content (Join-Path $projectRoot "pom.xml")
25+
$finalName = $pom.project.build.finalName
26+
if ([string]::IsNullOrWhiteSpace($finalName)) {
27+
$finalName = $pom.project.artifactId
28+
}
29+
30+
[pscustomobject]@{
31+
FinalName = $finalName
32+
JavaVersion = [int]$pom.project.properties.'java.version'
33+
VelocityVersion = [string]$pom.project.properties.'velocity.api.version'
34+
}
35+
}
36+
37+
$project = Get-ProjectMetadata
38+
$pluginJar = Join-Path $projectRoot ("target\" + $project.FinalName + ".jar")
39+
40+
function Invoke-Build {
41+
$args = @("package")
42+
if (-not $WithTests) {
43+
$args = @("-Pskip-tests", "package")
44+
}
45+
46+
Write-Host "Building plugin..."
47+
& mvn @args
48+
if ($LASTEXITCODE -ne 0) {
49+
throw "Build failed."
50+
}
51+
}
52+
53+
function Get-LatestVelocityBuild {
54+
param(
55+
[string]$RequestedVersion
56+
)
57+
58+
$headers = @{ "User-Agent" = "Tensa-DevRunner/1.0" }
59+
$projectInfo = Invoke-RestMethod -Headers $headers -Uri "https://fill.papermc.io/v3/projects/velocity"
60+
[string[]]$availableVersions = $projectInfo.versions.'3.0.0'
61+
62+
if (-not $availableVersions -or $availableVersions.Count -eq 0) {
63+
throw "Fill v3 did not return any Velocity 3.x versions."
64+
}
65+
66+
$version = if ($RequestedVersion -and $availableVersions -contains $RequestedVersion) {
67+
$RequestedVersion
68+
} else {
69+
if ($RequestedVersion) {
70+
Write-Warning "Velocity version '$RequestedVersion' is not published via Fill v3. Falling back to the latest available Velocity 3.x build."
71+
}
72+
$availableVersions[0]
73+
}
74+
75+
$builds = Invoke-RestMethod -Headers $headers -Uri "https://fill.papermc.io/v3/projects/velocity/versions/$([uri]::EscapeDataString($version))/builds"
76+
if (-not $builds -or $builds.Count -eq 0) {
77+
throw "No Velocity builds found for version $version."
78+
}
79+
80+
$stableBuilds = @($builds | Where-Object { $_.channel -eq "STABLE" })
81+
$build = if ($stableBuilds.Count -gt 0) {
82+
$stableBuilds | Sort-Object id | Select-Object -Last 1
83+
} else {
84+
$builds | Sort-Object id | Select-Object -Last 1
85+
}
86+
87+
$download = $build.downloads.'server:default'
88+
if (-not $download) {
89+
throw "Velocity build $($build.id) for version $version does not expose a server:default download."
90+
}
91+
92+
return [pscustomobject]@{
93+
Version = $version
94+
Build = [int]$build.id
95+
FileName = [string]$download.name
96+
Sha256 = [string]$download.checksums.sha256
97+
Url = [string]$download.url
98+
}
99+
}
100+
101+
function Ensure-FileHash {
102+
param(
103+
[string]$Path,
104+
[string]$ExpectedSha256
105+
)
106+
107+
if (-not (Test-Path $Path)) {
108+
return $false
109+
}
110+
111+
$actual = (Get-FileHash -Algorithm SHA256 -Path $Path).Hash.ToLowerInvariant()
112+
return $actual -eq $ExpectedSha256.ToLowerInvariant()
113+
}
114+
115+
function Ensure-VelocityRuntime {
116+
New-Item -ItemType Directory -Force -Path $runtimeRoot | Out-Null
117+
New-Item -ItemType Directory -Force -Path $pluginsDir | Out-Null
118+
119+
$buildInfo = Get-LatestVelocityBuild -RequestedVersion $VelocityVersion
120+
$serverJar = Join-Path $runtimeRoot $buildInfo.FileName
121+
122+
if (-not (Ensure-FileHash -Path $serverJar -ExpectedSha256 $buildInfo.Sha256)) {
123+
Write-Host "Downloading Velocity $($buildInfo.Version) build $($buildInfo.Build)..."
124+
Invoke-WebRequest -Uri $buildInfo.Url -OutFile $serverJar
125+
if (-not (Ensure-FileHash -Path $serverJar -ExpectedSha256 $buildInfo.Sha256)) {
126+
throw "Downloaded Velocity jar failed SHA256 verification."
127+
}
128+
}
129+
130+
return $serverJar
131+
}
132+
133+
function Ensure-DevConfig {
134+
$velocityToml = Join-Path $runtimeRoot "velocity.toml"
135+
$forwardingSecret = Join-Path $runtimeRoot "forwarding.secret"
136+
137+
if (-not (Test-Path $forwardingSecret)) {
138+
[guid]::NewGuid().ToString("N") | Set-Content -Path $forwardingSecret -NoNewline -Encoding UTF8
139+
}
140+
141+
if (-not (Test-Path $velocityToml)) {
142+
@"
143+
config-version = "2.7"
144+
bind = "127.0.0.1:$Port"
145+
motd = "<green>Tensa Dev Proxy</green>"
146+
show-max-players = 100
147+
online-mode = false
148+
force-key-authentication = false
149+
player-info-forwarding-mode = "none"
150+
forwarding-secret-file = "forwarding.secret"
151+
announce-forge = false
152+
kick-existing-players = false
153+
ping-passthrough = "disabled"
154+
log-command-executions = true
155+
log-player-connections = true
156+
try = [ "lobby" ]
157+
158+
[servers]
159+
lobby = "127.0.0.1:25566"
160+
"@ | Set-Content -Path $velocityToml -Encoding UTF8
161+
}
162+
}
163+
164+
function Sync-PluginJar {
165+
param(
166+
[string]$SourceJar
167+
)
168+
169+
$destinationJar = Join-Path $pluginsDir ($project.FinalName + ".jar")
170+
$legacyJar = Join-Path $pluginsDir "TENSA.jar"
171+
172+
if ((Test-Path $legacyJar) -and ($legacyJar -ne $destinationJar)) {
173+
Remove-Item -Path $legacyJar -Force
174+
}
175+
176+
Copy-Item -Path $SourceJar -Destination $destinationJar -Force
177+
return $destinationJar
178+
}
179+
180+
function Test-JavaVersion {
181+
$stdoutPath = [System.IO.Path]::GetTempFileName()
182+
$stderrPath = [System.IO.Path]::GetTempFileName()
183+
try {
184+
$process = Start-Process -FilePath $javaCmd `
185+
-ArgumentList "-version" `
186+
-NoNewWindow `
187+
-Wait `
188+
-PassThru `
189+
-RedirectStandardOutput $stdoutPath `
190+
-RedirectStandardError $stderrPath
191+
192+
$versionLines = @()
193+
if (Test-Path $stdoutPath) {
194+
$versionLines += Get-Content $stdoutPath
195+
}
196+
if (Test-Path $stderrPath) {
197+
$versionLines += Get-Content $stderrPath
198+
}
199+
200+
$versionOutput = $versionLines | Select-Object -First 1
201+
$javaExitCode = $process.ExitCode
202+
} finally {
203+
Remove-Item $stdoutPath, $stderrPath -ErrorAction SilentlyContinue
204+
}
205+
206+
if ($javaExitCode -ne 0 -or [string]::IsNullOrWhiteSpace($versionOutput)) {
207+
throw "Unable to start Java from '$javaCmd'."
208+
}
209+
210+
if ($versionOutput -match 'version "(\d+)(?:\.(\d+))?') {
211+
$detected = [int]$matches[1]
212+
if ($detected -lt $project.JavaVersion) {
213+
throw "Java $($project.JavaVersion)+ is required, but '$versionOutput' was detected."
214+
}
215+
}
216+
}
217+
218+
if (-not $SkipBuild) {
219+
Invoke-Build
220+
}
221+
222+
if (-not (Test-Path $pluginJar)) {
223+
throw "Built plugin jar not found at $pluginJar."
224+
}
225+
226+
Test-JavaVersion
227+
$requestedVelocityVersion = if ($VelocityVersion) { $VelocityVersion } else { $project.VelocityVersion }
228+
$serverJar = Ensure-VelocityRuntime -RequestedVersion $requestedVelocityVersion
229+
Ensure-DevConfig
230+
$installedPluginJar = Sync-PluginJar -SourceJar $pluginJar
231+
232+
Push-Location $runtimeRoot
233+
try {
234+
Write-Host "Starting Velocity from $serverJar with plugin $installedPluginJar"
235+
& $javaCmd "-jar" $serverJar
236+
exit $LASTEXITCODE
237+
} finally {
238+
Pop-Location
239+
}

README.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
11

2-
# TENSA Plugin
2+
# Tensa Plugin
33

4-
TENSA Velocity Plugin - This one offers a variety of modules for detailed server management and monitoring. Each module can be turned on or off as needed. The plugin is designed to be as flexible as possible, allowing you to customize your server's functionality to your specific needs.
4+
Tensa Velocity Plugin - This one offers a variety of modules for detailed server management and monitoring. Each module can be turned on or off as needed. The plugin is designed to be as flexible as possible, allowing you to customize your server's functionality to your specific needs.
5+
6+
## Dev Server
7+
- Run the local Velocity dev server from the project root with `.\.run\run-velocity.cmd`.
8+
- The script builds `target/Tensa.jar`, downloads the matching Velocity runtime from Fill v3, copies the plugin into `.run/velocity/plugins/`, and starts the proxy.
9+
- Optional flags:
10+
- `.\.run\run-velocity.cmd -WithTests` to build and run tests before launch
11+
- `.\.run\run-velocity.cmd -SkipBuild` to restart the proxy with the already-built jar
12+
- `.\.run\run-velocity.cmd -VelocityVersion 3.5.0-SNAPSHOT` to pin a specific runtime version
13+
14+
## Velocity Log Cleanup
15+
You can let the plugin clean old Velocity logs on startup through `config.yml`:
16+
17+
```yaml
18+
velocity:
19+
log_cleanup:
20+
enable: true
21+
latest_log: false
22+
rotated_logs: true
23+
compressed_logs: true
24+
```
25+
26+
- `latest_log` is best-effort only. On Windows, Velocity may still hold the file handle, so truncation can fail while rotated `.log` and `.log.gz` files are cleaned normally.
527

628
## Config Models
729
- Typed config classes with annotations live under `ua.co.tensa.config.model`.

TENSA.iml renamed to Tensa.iml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<module version="4">
3-
<component name="AdditionalModuleElements">
4-
<content url="file://$MODULE_DIR$" dumb="true">
5-
<excludeFolder url="file://$MODULE_DIR$/src/test" />
6-
</content>
7-
</component>
83
<component name="FacetManager">
94
<facet type="minecraft" name="Minecraft">
105
<configuration>
116
<autoDetectTypes>
127
<platformType>VELOCITY</platformType>
8+
<platformType>ADVENTURE</platformType>
139
</autoDetectTypes>
1410
<projectReimportVersion>1</projectReimportVersion>
1511
</configuration>

0 commit comments

Comments
 (0)