Initial release

This commit is contained in:
simeonvartik 2026-06-15 06:11:26 +02:00
commit e2f3f4759d
679 changed files with 156544 additions and 0 deletions

View file

@ -0,0 +1,908 @@
param(
[ValidateSet("Menu", "Setup", "Scan", "Validate", "PublishApi", "Build", "BuildAll", "Clean")]
[string] $Action = "Menu",
[ValidateSet("minimal", "advanced")]
[string] $Template = "minimal",
[string] $ProjectPath,
[string] $OutputPath,
[string] $AddonId,
[string] $AddonName,
[string] $AddonVersion,
[string] $Package,
[string] $Author,
[string] $Description,
[string] $MavenGroup,
[string] $ArchiveName,
[switch] $Advanced,
[switch] $DebugStack,
[switch] $NoPublish,
[switch] $Yes,
[switch] $NonInteractive
)
$ErrorActionPreference = "Stop"
$RepoRoot = Split-Path -Parent $PSScriptRoot
function Write-Info([string] $Message) {
Write-Host "[AUTISM] $Message" -ForegroundColor DarkGray
}
function Write-Ok([string] $Message) {
Write-Host "[OK] $Message" -ForegroundColor Green
}
function Write-Warn([string] $Message) {
Write-Host "[WARN] $Message" -ForegroundColor DarkYellow
}
function Write-Bad([string] $Message) {
Write-Host "[FAIL] $Message" -ForegroundColor White -BackgroundColor Red
}
function Write-PathLine([string] $Label, [string] $Path) {
Write-Host "${Label}:" -ForegroundColor DarkGray
Write-Host $Path -ForegroundColor White
}
function Write-FailureItem([string] $Message) {
if ($Message -match "^[A-Za-z]:[\\/]" -or $Message -match "^/" -or $Message -match "^[.]{1,2}[\\/]") {
Write-PathLine "Path" $Message
} else {
Write-Bad " - $Message"
}
}
function Resolve-FullPath([string] $Path) {
if ([string]::IsNullOrWhiteSpace($Path)) {
return $null
}
if ([System.IO.Path]::IsPathRooted($Path)) {
return [System.IO.Path]::GetFullPath($Path)
}
return [System.IO.Path]::GetFullPath((Join-Path $RepoRoot $Path))
}
function Test-ShippedTemplatePath([string] $Path) {
if ([string]::IsNullOrWhiteSpace($Path)) {
return $false
}
$full = [System.IO.Path]::GetFullPath($Path).TrimEnd("\", "/")
foreach ($templateName in @("minimal", "advanced")) {
$templatePath = [System.IO.Path]::GetFullPath((Join-Path $RepoRoot "addon-templates/$templateName")).TrimEnd("\", "/")
if ([string]::Equals($full, $templatePath, [System.StringComparison]::OrdinalIgnoreCase)) {
return $true
}
}
return $false
}
function ConvertTo-FolderName([string] $Name) {
if ([string]::IsNullOrWhiteSpace($Name)) {
return "MyAddon"
}
$parts = [regex]::Matches($Name, "[A-Za-z0-9]+") | ForEach-Object { $_.Value }
if (-not $parts -or $parts.Count -eq 0) {
return "MyAddon"
}
$folder = (($parts | ForEach-Object {
if ($_.Length -eq 1) {
$_.ToUpperInvariant()
} else {
$_.Substring(0, 1).ToUpperInvariant() + $_.Substring(1)
}
}) -join "")
if ($folder.Length -gt 48) {
$folder = $folder.Substring(0, 48)
}
return $folder
}
function ConvertTo-PackageSegment([string] $Value) {
$segment = $Value.ToLowerInvariant() -replace "[^a-z0-9]+", ""
if ([string]::IsNullOrWhiteSpace($segment)) {
$segment = "myaddon"
}
if ($segment[0] -notmatch "[a-z]") {
$segment = "addon$segment"
}
return $segment
}
function Get-DefaultAuthor {
if (-not [string]::IsNullOrWhiteSpace($env:USERNAME)) {
return $env:USERNAME
}
return "You"
}
function Get-DefaultAddonOutputPath([string] $TemplateName, [string] $Name) {
$baseName = if ([string]::IsNullOrWhiteSpace($Name)) {
if ($TemplateName -eq "advanced") { "MyAdvancedAddon" } else { "MyAddon" }
} else {
ConvertTo-FolderName $Name
}
return Resolve-FullPath (Join-Path ".." $baseName)
}
function Read-Value([string] $Prompt, [string] $Default, [scriptblock] $Validator) {
while ($true) {
$suffix = if ([string]::IsNullOrWhiteSpace($Default)) { "" } else { " [$Default]" }
$value = Read-Host "$Prompt$suffix"
if ([string]::IsNullOrWhiteSpace($value)) {
$value = $Default
}
if ($null -eq $Validator -or (& $Validator $value)) {
return $value
}
Write-Warn "Bad value. Fix it."
}
}
function Read-VersionValue([string] $Current) {
$base = if ([string]::IsNullOrWhiteSpace($Current)) { "1.0.0" } else { $Current }
$next = Step-Version $base
while ($true) {
$value = Read-Host "Version current $base, blank = $next"
if ([string]::IsNullOrWhiteSpace($value)) {
return $next
}
if (Test-Version $value) {
return $value
}
Write-Warn "Bad version. Fix it."
}
}
function Test-ModId([string] $Value) {
return $Value -match "^[a-z][a-z0-9_-]{1,63}$"
}
function Test-JavaPackage([string] $Value) {
return $Value -match "^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)+$"
}
function Test-Version([string] $Value) {
return $Value -match "^[0-9A-Za-z][0-9A-Za-z._+-]*$"
}
function Step-Version([string] $Version) {
if ([string]::IsNullOrWhiteSpace($Version)) {
return "1.0.0"
}
$match = [regex]::Match($Version, "^(.*?)(\d+)(\D*)$")
if (-not $match.Success) {
return "$Version.1"
}
$prefix = $match.Groups[1].Value
$digits = $match.Groups[2].Value
$suffix = $match.Groups[3].Value
$next = ([int64] $digits) + 1
$nextText = [string] $next
if ($digits.Length -gt 1 -and $nextText.Length -lt $digits.Length) {
$nextText = $nextText.PadLeft($digits.Length, "0")
}
return "$prefix$nextText$suffix"
}
function ConvertTo-ModId([string] $Name) {
$id = $Name.ToLowerInvariant() -replace "[^a-z0-9_-]+", "-"
$id = $id.Trim("-_")
if ([string]::IsNullOrWhiteSpace($id)) {
return "my-autism-addon"
}
if ($id[0] -notmatch "[a-z]") {
$id = "addon-$id"
}
if ($id.Length -gt 64) {
$id = $id.Substring(0, 64).Trim("-_")
}
return $id
}
function Get-TextFile([string] $Path) {
return Get-Content -LiteralPath $Path -Raw
}
function Set-TextFile([string] $Path, [string] $Text) {
$fullPath = if (Test-Path -LiteralPath $Path) {
(Resolve-Path -LiteralPath $Path).Path
} else {
[System.IO.Path]::GetFullPath($Path)
}
$encoding = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($fullPath, $Text, $encoding)
}
function Get-JsonFile([string] $Path) {
return Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json
}
function Save-JsonFile([string] $Path, $Json) {
$text = $Json | ConvertTo-Json -Depth 64
$text = $text.Replace("\u003c", "<").Replace("\u003e", ">").Replace("\u0026", "&")
Set-TextFile $Path ($text + [Environment]::NewLine)
}
function Get-TomlVersion([string] $Path, [string] $Key) {
$text = Get-TextFile $Path
$match = [regex]::Match($text, "(?m)^\s*$([regex]::Escape($Key))\s*=\s*`"([^`"]+)`"")
if ($match.Success) {
return $match.Groups[1].Value
}
return ""
}
function Set-TomlVersion([string] $Path, [string] $Key, [string] $Value) {
$text = Get-TextFile $Path
$pattern = "(?m)^(\s*$([regex]::Escape($Key))\s*=\s*)`"[^`"]*`""
if ($text -match $pattern) {
$text = [regex]::Replace($text, $pattern, "`${1}`"$Value`"")
} else {
$text += [Environment]::NewLine + "$Key = `"$Value`"" + [Environment]::NewLine
}
Set-TextFile $Path $text
}
function Set-PropertiesValue([string] $Path, [string] $Key, [string] $Value) {
$text = Get-TextFile $Path
$pattern = "(?m)^$([regex]::Escape($Key))=.*$"
if ($text -match $pattern) {
$text = [regex]::Replace($text, $pattern, "$Key=$Value")
} else {
$text += [Environment]::NewLine + "$Key=$Value" + [Environment]::NewLine
}
Set-TextFile $Path $text
}
function Set-RootProjectName([string] $Path, [string] $Name) {
$text = Get-TextFile $Path
$pattern = "(?m)^(rootProject\.name\s*=\s*)`"[^`"]*`""
if ($text -match $pattern) {
$text = [regex]::Replace($text, $pattern, "`${1}`"$Name`"")
} else {
$text += [Environment]::NewLine + "rootProject.name = `"$Name`"" + [Environment]::NewLine
}
Set-TextFile $Path $text
}
function Get-FirstJavaPackage([string] $Project) {
$entry = Join-Path $Project "src/main/resources/fabric.mod.json"
if (Test-Path -LiteralPath $entry -PathType Leaf) {
$json = Get-JsonFile $entry
$classes = @()
if ($json.entrypoints.client) { $classes += @($json.entrypoints.client) }
if ($json.entrypoints.autism) { $classes += @($json.entrypoints.autism) }
foreach ($class in $classes) {
if ($class -match "^(.+)\.[^.]+$") {
return $matches[1]
}
}
}
$java = Get-ChildItem -LiteralPath (Join-Path $Project "src/main/java") -Recurse -Filter *.java -ErrorAction SilentlyContinue | Select-Object -First 1
if ($java) {
$match = [regex]::Match((Get-TextFile $java.FullName), "(?m)^\s*package\s+([^;]+);")
if ($match.Success) {
return $match.Groups[1].Value.Trim()
}
}
return "com.example.addon"
}
function Get-ClassSimpleName([string] $ClassName, [string] $Fallback) {
if ($ClassName -match "\.([^.]+)$") {
return $matches[1]
}
return $Fallback
}
function Replace-InProjectFiles([string] $Project, [string] $Old, [string] $New) {
if ([string]::IsNullOrWhiteSpace($Old) -or $Old -eq $New) {
return
}
$extensions = @(".java", ".json", ".kts", ".toml", ".properties", ".md", ".yml", ".yaml")
$files = Get-ChildItem -LiteralPath $Project -Recurse -File -Force | Where-Object {
$_.FullName -notmatch "\\(build|\.gradle)\\" -and $extensions -contains $_.Extension
}
foreach ($file in $files) {
$text = Get-TextFile $file.FullName
if ($text.Contains($Old)) {
Set-TextFile $file.FullName ($text.Replace($Old, $New))
}
}
}
function Move-JavaPackage([string] $Project, [string] $OldPackage, [string] $NewPackage) {
if ($OldPackage -eq $NewPackage) {
return
}
$srcRoot = Join-Path $Project "src/main/java"
$oldPath = Join-Path $srcRoot ($OldPackage.Replace(".", [System.IO.Path]::DirectorySeparatorChar))
$newPath = Join-Path $srcRoot ($NewPackage.Replace(".", [System.IO.Path]::DirectorySeparatorChar))
if (-not (Test-Path -LiteralPath $oldPath -PathType Container)) {
return
}
if (Test-Path -LiteralPath $newPath) {
Write-Warn "Package path already exists. Not moving files."
Write-PathLine "Path" $newPath
return
}
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $newPath) | Out-Null
Move-Item -LiteralPath $oldPath -Destination $newPath
$cursor = Split-Path -Parent $oldPath
while ($cursor -and $cursor.StartsWith($srcRoot) -and $cursor -ne $srcRoot) {
$children = Get-ChildItem -LiteralPath $cursor -Force
if ($children.Count -gt 0) {
break
}
$next = Split-Path -Parent $cursor
Remove-Item -LiteralPath $cursor
$cursor = $next
}
}
function Copy-AddonTemplate([string] $TemplateName, [string] $TargetPath) {
$source = Join-Path $RepoRoot "addon-templates/$TemplateName"
if (-not (Test-Path -LiteralPath $source -PathType Container)) {
Write-PathLine "Missing template" $source
throw "Template not found."
}
if (Test-Path -LiteralPath $TargetPath) {
Write-Warn "Output already exists. Editing it in place."
Write-PathLine "Path" $TargetPath
return
}
New-Item -ItemType Directory -Force -Path $TargetPath | Out-Null
$sourceFull = [System.IO.Path]::GetFullPath($source)
$targetFull = [System.IO.Path]::GetFullPath($TargetPath)
Get-ChildItem -LiteralPath $sourceFull -Recurse -Force | Where-Object {
$_.FullName -notmatch "\\(build|\.gradle)($|\\)"
} | ForEach-Object {
$relative = $_.FullName.Substring($sourceFull.Length).TrimStart("\", "/")
$destination = Join-Path $targetFull $relative
if ($_.PSIsContainer) {
New-Item -ItemType Directory -Force -Path $destination | Out-Null
} else {
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $destination) | Out-Null
Copy-Item -LiteralPath $_.FullName -Destination $destination -Force
}
}
}
function Get-AddonProjectPath {
if (-not [string]::IsNullOrWhiteSpace($ProjectPath)) {
return Resolve-FullPath $ProjectPath
}
if (-not [string]::IsNullOrWhiteSpace($OutputPath)) {
$target = Resolve-FullPath $OutputPath
Copy-AddonTemplate $Template $target
return $target
}
return Join-Path $RepoRoot "addon-templates/$Template"
}
function Get-SetupProjectPath([string] $NameForOutput) {
if (-not [string]::IsNullOrWhiteSpace($ProjectPath)) {
$project = Resolve-FullPath $ProjectPath
if (Test-ShippedTemplatePath $project) {
throw "No. The shipped templates stay clean. Use -OutputPath to copy one, or pick a real addon folder."
}
return $project
}
if ([string]::IsNullOrWhiteSpace($OutputPath)) {
$OutputPath = Read-Value "Output folder" (Get-DefaultAddonOutputPath $Template $NameForOutput) { param($v) -not [string]::IsNullOrWhiteSpace($v) }
}
$target = Resolve-FullPath $OutputPath
if (Test-ShippedTemplatePath $target) {
throw "No. The shipped templates stay clean. Pick a different output folder."
}
Copy-AddonTemplate $Template $target
return $target
}
function Configure-Addon {
if ([string]::IsNullOrWhiteSpace($AddonName)) {
$defaultName = if ($Template -eq "advanced") { "My Advanced Addon" } else { "My Addon" }
$AddonName = Read-Value "Addon name" $defaultName { param($v) -not [string]::IsNullOrWhiteSpace($v) }
}
$project = Get-SetupProjectPath $AddonName
if (-not (Test-Path -LiteralPath $project -PathType Container)) {
Write-PathLine "Missing addon folder" $project
throw "Addon project not found."
}
$fabricPath = Join-Path $project "src/main/resources/fabric.mod.json"
$versionsPath = Join-Path $project "gradle/libs.versions.toml"
$propertiesPath = Join-Path $project "gradle.properties"
$settingsPath = Join-Path $project "settings.gradle.kts"
foreach ($required in @($fabricPath, $versionsPath, $propertiesPath, $settingsPath)) {
if (-not (Test-Path -LiteralPath $required -PathType Leaf)) {
Write-PathLine "Missing file" $required
throw "Missing required addon file."
}
}
$fabric = Get-JsonFile $fabricPath
$oldId = [string] $fabric.id
$oldName = [string] $fabric.name
$oldPackage = Get-FirstJavaPackage $project
$oldVersion = Get-TomlVersion $versionsPath "mod-version"
$oldClientClass = if ($fabric.entrypoints.client) { [string] @($fabric.entrypoints.client)[0] } else { "$oldPackage.Init" }
$oldAddonClass = if ($fabric.entrypoints.autism) { [string] @($fabric.entrypoints.autism)[0] } else { "$oldPackage.Addon" }
$originalMixinName = if ($fabric.mixins -and @($fabric.mixins).Count -gt 0) { [string] @($fabric.mixins)[0] } else { "" }
$clientSimple = Get-ClassSimpleName $oldClientClass "Init"
$addonSimple = Get-ClassSimpleName $oldAddonClass "Addon"
if ([string]::IsNullOrWhiteSpace($AddonId)) {
$suggestedId = if ($oldId -match "template") { ConvertTo-ModId $AddonName } else { $oldId }
if ($Advanced) {
$AddonId = Read-Value "Addon id" $suggestedId { param($v) Test-ModId $v }
} else {
$AddonId = $suggestedId
}
}
if ([string]::IsNullOrWhiteSpace($AddonVersion)) {
$suggestedVersion = if ([string]::IsNullOrWhiteSpace($oldVersion)) { "1.0.0" } else { $oldVersion }
$AddonVersion = Read-VersionValue $suggestedVersion
}
if ([string]::IsNullOrWhiteSpace($Package)) {
$suggestedPackage = "com.$(ConvertTo-PackageSegment $AddonId).addon"
if ($Advanced) {
$Package = Read-Value "Java package" $suggestedPackage { param($v) Test-JavaPackage $v }
} else {
$Package = $suggestedPackage
}
}
if ([string]::IsNullOrWhiteSpace($MavenGroup)) {
if ($Advanced) {
$MavenGroup = Read-Value "Maven group" $Package { param($v) Test-JavaPackage $v }
} else {
$MavenGroup = $Package
}
}
if ([string]::IsNullOrWhiteSpace($ArchiveName)) {
if ($Advanced) {
$ArchiveName = Read-Value "Jar/archive base name" $AddonId { param($v) Test-ModId $v }
} else {
$ArchiveName = $AddonId
}
}
if ([string]::IsNullOrWhiteSpace($Author)) {
$Author = Read-Value "Author" (Get-DefaultAuthor) { param($v) -not [string]::IsNullOrWhiteSpace($v) }
}
if ([string]::IsNullOrWhiteSpace($Description)) {
$suggestedDescription = "$AddonName addon for AUTISM Client."
if ($Advanced) {
$Description = Read-Value "Description" $suggestedDescription { param($v) -not [string]::IsNullOrWhiteSpace($v) }
} else {
$Description = $suggestedDescription
}
}
Replace-InProjectFiles $project $oldPackage $Package
Replace-InProjectFiles $project $oldId $AddonId
Move-JavaPackage $project $oldPackage $Package
$fabric = Get-JsonFile $fabricPath
$fabric.id = $AddonId
$fabric.name = $AddonName
$fabric.version = '${version}'
$fabric.description = $Description
$fabric.authors = @($Author)
if (-not $fabric.entrypoints) {
$fabric | Add-Member -MemberType NoteProperty -Name entrypoints -Value ([pscustomobject]@{})
}
$fabric.entrypoints.client = @("$Package.$clientSimple")
$fabric.entrypoints.autism = @("$Package.$addonSimple")
if ($fabric.mixins -and @($fabric.mixins).Count -gt 0) {
$oldMixinName = if ([string]::IsNullOrWhiteSpace($originalMixinName)) { [string] @($fabric.mixins)[0] } else { $originalMixinName }
$newMixinName = "$AddonId.mixins.json"
$resourceDir = Join-Path $project "src/main/resources"
$oldMixinPath = Join-Path $resourceDir $oldMixinName
$newMixinPath = Join-Path $resourceDir $newMixinName
if ((Test-Path -LiteralPath $oldMixinPath -PathType Leaf) -and $oldMixinPath -ne $newMixinPath) {
Move-Item -LiteralPath $oldMixinPath -Destination $newMixinPath -Force
}
if (Test-Path -LiteralPath $newMixinPath -PathType Leaf) {
$mixinJson = Get-JsonFile $newMixinPath
$mixinJson.package = "$Package.mixin"
Save-JsonFile $newMixinPath $mixinJson
}
$fabric.mixins = @($newMixinName)
}
Save-JsonFile $fabricPath $fabric
Set-TomlVersion $versionsPath "mod-version" $AddonVersion
Set-PropertiesValue $propertiesPath "maven_group" $MavenGroup
Set-PropertiesValue $propertiesPath "archives_base_name" $ArchiveName
Set-RootProjectName $settingsPath $AddonId
Write-Ok "Addon rewritten."
Write-PathLine "Addon folder" $project
Write-Host " id: $AddonId"
Write-Host " name: $AddonName"
Write-Host " version: $AddonVersion"
Write-Host " package: $Package"
Write-Host ""
Write-Host "Next:" -ForegroundColor Red
Write-Host ".\addon-templates\addon-toolkit.ps1 -Action Build -ProjectPath `"$project`"" -ForegroundColor White
Write-PathLine "Jar folder" (Join-Path $project "build\libs")
$script:LastConfiguredProject = $project
}
function Add-Failure([System.Collections.Generic.List[string]] $Failures, [string] $Message) {
$Failures.Add($Message) | Out-Null
}
function Add-Warning([System.Collections.Generic.List[string]] $Warnings, [string] $Message) {
$Warnings.Add($Message) | Out-Null
}
function Test-AddonProject([string] $Project, [switch] $AllowTemplateNames) {
$failures = New-Object System.Collections.Generic.List[string]
$warnings = New-Object System.Collections.Generic.List[string]
if (-not (Test-Path -LiteralPath $Project -PathType Container)) {
Add-Failure $failures "Project folder does not exist."
Add-Failure $failures $Project
return [pscustomobject]@{ Failures = $failures; Warnings = $warnings }
}
$required = @(
"build.gradle.kts",
"settings.gradle.kts",
"gradle.properties",
"gradle/libs.versions.toml",
"gradlew.bat",
"src/main/resources/fabric.mod.json"
)
foreach ($item in $required) {
if (-not (Test-Path -LiteralPath (Join-Path $Project $item) -PathType Leaf)) {
Add-Failure $failures "Missing $item"
}
}
$fabricPath = Join-Path $Project "src/main/resources/fabric.mod.json"
if (Test-Path -LiteralPath $fabricPath -PathType Leaf) {
try {
$fabric = Get-JsonFile $fabricPath
if (-not (Test-ModId ([string] $fabric.id))) {
Add-Failure $failures "fabric.mod.json id is invalid: $($fabric.id)"
}
if ([string]::IsNullOrWhiteSpace([string] $fabric.name)) {
Add-Failure $failures "fabric.mod.json name is empty."
}
if (-not $fabric.entrypoints.autism) {
Add-Failure $failures "Missing autism entrypoint in fabric.mod.json."
} else {
foreach ($entry in @($fabric.entrypoints.autism)) {
$path = Join-Path $Project ("src/main/java/" + ([string] $entry).Replace(".", "/") + ".java")
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
Add-Failure $failures "Autism entrypoint class file is missing: $entry"
}
}
}
if (-not $fabric.depends.autism) {
Add-Failure $failures "fabric.mod.json must depend on autism."
}
if (-not $AllowTemplateNames) {
if ([string] $fabric.id -match "template|example") {
Add-Warning $warnings "Addon id still looks like a template/example."
}
if ([string] $fabric.name -match "Template|Example") {
Add-Warning $warnings "Addon name still looks like a template/example."
}
if (@($fabric.authors) -contains "You") {
Add-Warning $warnings "Author is still 'You'."
}
}
} catch {
Add-Failure $failures "fabric.mod.json is not valid JSON: $($_.Exception.Message)"
}
}
$versionsPath = Join-Path $Project "gradle/libs.versions.toml"
if (Test-Path -LiteralPath $versionsPath -PathType Leaf) {
$addonVersion = Get-TomlVersion $versionsPath "mod-version"
$hostVersion = Get-TomlVersion $versionsPath "autism"
if (-not (Test-Version $addonVersion)) {
Add-Failure $failures "Addon mod-version is missing or invalid."
}
if ([string]::IsNullOrWhiteSpace($hostVersion)) {
Add-Failure $failures "AUTISM dependency version is missing from gradle/libs.versions.toml."
}
}
if (Test-Path -LiteralPath (Join-Path $Project ".gradle")) {
Add-Warning $warnings ".gradle cache exists locally. Ignored; do not upload it."
}
if (Test-Path -LiteralPath (Join-Path $Project "build")) {
Add-Warning $warnings "build output exists locally. Ignored; do not upload it."
}
if (Test-Path -LiteralPath (Join-Path $Project ".github")) {
Add-Warning $warnings ".github exists inside this addon project. Fine for a copied template, but it is not root repo CI unless you move it."
}
$files = Get-ChildItem -LiteralPath $Project -Recurse -File -Force | Where-Object {
$_.FullName -notmatch "\\(build|\.gradle)\\" -and
$_.Extension -in @(".java", ".json", ".md", ".kts", ".toml", ".properties", ".yml", ".yaml")
}
$templateLeftovers = @(
"autism-minimal-addon-template",
"autism-advanced-addon-template",
"AUTISM Minimal Addon Template",
"AUTISM Advanced Addon Template"
)
foreach ($file in $files) {
$text = Get-TextFile $file.FullName
if ($text -match "[\u00C2\u00C3\u00E2]") {
Add-Warning $warnings "Mojibake-looking text in $($file.FullName)"
}
if (-not $AllowTemplateNames) {
foreach ($leftover in $templateLeftovers) {
if ($text.Contains($leftover)) {
Add-Warning $warnings "Template leftover '$leftover' in $($file.FullName)"
break
}
}
}
}
return [pscustomobject]@{ Failures = $failures; Warnings = $warnings }
}
function Scan-Addon {
$project = Get-AddonProjectPath
$result = Test-AddonProject $project
Write-Info "Scanned addon project."
Write-PathLine "Addon folder" $project
foreach ($warning in $result.Warnings) {
Write-Warn "Heads up: $warning"
}
if ($result.Failures.Count -gt 0) {
Write-Bad "Scan found broken stuff:"
foreach ($failure in $result.Failures) {
Write-FailureItem $failure
}
throw "Scan failed."
}
Write-Ok "Scan clean."
}
function Validate-AddonSystem {
$failures = New-Object System.Collections.Generic.List[string]
$warnings = New-Object System.Collections.Generic.List[string]
$rootRequired = @(
"src/main/java/autismclient/addons/AddonManager.java",
"src/main/java/autismclient/api/AutismAddon.java",
"src/main/java/autismclient/api/SimpleAddon.java",
"src/main/java/autismclient/api/AutismAddons.java",
"src/main/java/autismclient/api/ApiVersion.java",
"src/main/java/autismclient/api/module/SimpleModule.java",
"src/main/java/autismclient/api/macro/SimpleAction.java",
"src/main/java/autismclient/api/macro/SimpleCondition.java",
"src/main/java/autismclient/api/macro/MacroActionRegistry.java",
"src/main/java/autismclient/api/macro/MacroPresetRegistry.java",
"src/main/java/autismclient/api/hud/HudElements.java",
"src/main/java/autismclient/api/event/AddonEvents.java",
"src/main/java/autismclient/gui/screen/AutismAddonsScreen.java",
"src/main/java/autismclient/util/macro/MissingAddonAction.java",
"addon-templates/README.md",
"addon-templates/addon-toolkit.ps1"
)
foreach ($file in $rootRequired) {
if (-not (Test-Path -LiteralPath (Join-Path $RepoRoot $file) -PathType Leaf)) {
Add-Failure $failures "Missing $file"
}
}
$gitignore = Join-Path $RepoRoot ".gitignore"
if (Test-Path -LiteralPath $gitignore -PathType Leaf) {
$ignoreText = Get-TextFile $gitignore
foreach ($pattern in @("!/src/", "!/addon-templates/", "!/addon-templates/**", "/addon-templates/**/build/", "/addon-templates/**/.gradle/", "/mc-src*/")) {
if (-not $ignoreText.Contains($pattern)) {
Add-Failure $failures ".gitignore is missing $pattern"
}
}
} else {
Add-Failure $failures "Missing .gitignore"
}
$mainVersion = Get-TomlVersion (Join-Path $RepoRoot "gradle/libs.versions.toml") "mod-version"
foreach ($templateName in @("minimal", "advanced")) {
$project = Join-Path $RepoRoot "addon-templates/$templateName"
$result = Test-AddonProject $project -AllowTemplateNames
foreach ($failure in $result.Failures) {
Add-Failure $failures "$templateName template: $failure"
}
foreach ($warning in $result.Warnings) {
Add-Warning $warnings "$templateName template: $warning"
}
$targetVersion = Get-TomlVersion (Join-Path $project "gradle/libs.versions.toml") "autism"
if ($mainVersion -and $targetVersion -and $mainVersion -ne $targetVersion) {
Add-Failure $failures "$templateName template targets AUTISM $targetVersion, main client is $mainVersion."
}
}
foreach ($warning in $warnings) {
Write-Warn "Heads up: $warning"
}
if ($failures.Count -gt 0) {
Write-Bad "Addon system is broken:"
foreach ($failure in $failures) {
Write-FailureItem $failure
}
throw "Addon system validation failed."
}
Write-Ok "Addon system clean."
}
function Invoke-Gradle([string] $Project, [string[]] $GradleArgs) {
$gradlew = Join-Path $Project "gradlew.bat"
if (-not (Test-Path -LiteralPath $gradlew -PathType Leaf)) {
Write-PathLine "Missing Gradle wrapper" $gradlew
throw "Missing Gradle wrapper."
}
Push-Location $Project
try {
& $gradlew @GradleArgs
if ($LASTEXITCODE -ne 0) {
Write-PathLine "Gradle project" $Project
throw "Gradle failed with exit code $LASTEXITCODE."
}
} finally {
Pop-Location
}
}
function Publish-Api {
Write-Info "Publishing client API to Maven Local."
Invoke-Gradle $RepoRoot @("publishToMavenLocal", "--no-daemon")
Write-Ok "Client API published."
}
function Build-Addon {
$project = Get-AddonProjectPath
if (-not (Test-Path -LiteralPath $project -PathType Container)) {
Write-PathLine "Addon folder" $project
throw "Wrong addon folder."
}
$gradlew = [System.IO.Path]::Combine($project, "gradlew.bat")
if (-not (Test-Path -LiteralPath $gradlew -PathType Leaf)) {
Write-PathLine "Addon folder" $project
throw "No Gradle wrapper there. Wrong addon folder."
}
if (-not $NoPublish) {
Publish-Api
}
Write-Info "Building addon."
Write-PathLine "Addon folder" $project
Invoke-Gradle $project @("build", "--no-daemon")
Write-Ok "Addon built."
Write-PathLine "Addon folder" $project
Write-PathLine "Jar folder" (Join-Path $project "build\libs")
}
function Build-AllTemplates {
if (-not $NoPublish) {
Publish-Api
}
foreach ($templateName in @("minimal", "advanced")) {
$project = Join-Path $RepoRoot "addon-templates/$templateName"
Write-Info "Building $templateName template."
Invoke-Gradle $project @("build", "--no-daemon")
Write-Ok "$templateName template built."
}
}
function Clean-Addon {
$project = Get-AddonProjectPath
foreach ($folder in @(".gradle", "build")) {
$path = Join-Path $project $folder
if (Test-Path -LiteralPath $path) {
if ($Yes -or ((Read-Host "Remove $path ? Type YES") -eq "YES")) {
Remove-Item -LiteralPath $path -Recurse -Force
Write-Ok "Deleted local build junk."
Write-PathLine "Path" $path
}
}
}
}
function Invoke-MenuChoice([scriptblock] $Body) {
try {
& $Body
} catch {
Write-Bad $_.Exception.Message
if ($DebugStack -and $_.ScriptStackTrace) {
Write-Warn $_.ScriptStackTrace
}
[void] (Read-Host "Press Enter. The error stays here until you do")
}
}
function Show-Menu {
$script:LastAddonPath = ""
while ($true) {
Write-Host ""
Write-Host "AUTISM ADDON KIT" -ForegroundColor Red
Write-Host "1. New addon"
Write-Host "2. Build addon"
Write-Host "3. Scan addon"
Write-Host "4. Test shipped templates"
Write-Host "5. Publish client API"
Write-Host "6. Delete local build junk"
Write-Host "0. Leave"
$choice = Read-Host ">"
switch ($choice) {
"1" {
Invoke-MenuChoice {
$script:Template = Read-Value "Template minimal/advanced" $Template { param($v) $v -in @("minimal", "advanced") }
$script:ProjectPath = ""
$script:OutputPath = ""
Configure-Addon
$script:LastAddonPath = $script:LastConfiguredProject
}
}
"2" {
Invoke-MenuChoice {
$defaultPath = if ([string]::IsNullOrWhiteSpace($script:LastAddonPath)) { Get-DefaultAddonOutputPath $Template "" } else { $script:LastAddonPath }
$script:ProjectPath = Read-Value "Addon folder" $defaultPath { param($v) -not [string]::IsNullOrWhiteSpace($v) }
Build-Addon
}
}
"3" {
Invoke-MenuChoice {
$defaultPath = if ([string]::IsNullOrWhiteSpace($script:LastAddonPath)) { Get-DefaultAddonOutputPath $Template "" } else { $script:LastAddonPath }
$script:ProjectPath = Read-Value "Addon folder" $defaultPath { param($v) -not [string]::IsNullOrWhiteSpace($v) }
Scan-Addon
}
}
"4" { Invoke-MenuChoice { Validate-AddonSystem; Build-AllTemplates } }
"5" { Invoke-MenuChoice { Publish-Api } }
"6" {
Invoke-MenuChoice {
$defaultPath = if ([string]::IsNullOrWhiteSpace($script:LastAddonPath)) { Get-DefaultAddonOutputPath $Template "" } else { $script:LastAddonPath }
$script:ProjectPath = Read-Value "Addon folder" $defaultPath { param($v) -not [string]::IsNullOrWhiteSpace($v) }
Clean-Addon
}
}
"0" { return }
default { Write-Warn "Bad choice." }
}
}
}
function Invoke-RequestedAction {
switch ($Action) {
"Menu" { Show-Menu }
"Setup" { Configure-Addon }
"Scan" { Scan-Addon }
"Validate" { Validate-AddonSystem }
"PublishApi" { Publish-Api }
"Build" { Build-Addon }
"BuildAll" { Build-AllTemplates }
"Clean" { Clean-Addon }
}
}
try {
Invoke-RequestedAction
} catch {
Write-Bad $_.Exception.Message
if ($DebugStack -and $_.ScriptStackTrace) {
Write-Warn $_.ScriptStackTrace
}
if ($Action -eq "Menu" -or (-not $NonInteractive -and -not $env:CI)) {
[void] (Read-Host "Press Enter. The error stays here until you do")
}
exit 1
}