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

121
addon-templates/README.md Normal file
View file

@ -0,0 +1,121 @@
# AUTISM Client Addon Templates
These are the official addon templates for AUTISM Client.
Put these in the same repo as the client source. They are standalone Fabric mod projects, but they depend on the AUTISM Client API being published to your local Maven repo first.
This is not some magical separate SDK. Build the client API locally, then build your addon.
## Templates
- `minimal/` - This is the one you should probably start with.
It gives you the clean basic setup without throwing the entire client architecture at your face. It includes:
one module
one simple macro action
one simple wait condition
the beginner-friendly API setup
It is intentionally small. You can actually read it without needing to reverse engineer the entire client.
- `advanced/` - This is the full reference template.
Use this when you want to see how the bigger stuff is supposed to be wired. It includes:
modules
macro actions
macro conditions
presets
commands
HUD elements
events
a mixin
Addon presets are fully supported. They show up in the macro editor `Presets` picker under your addon's
own category, the same way addon modules/actions/conditions do.
Category names are intentionally simple: your addon name is the public category. If an API lets you pass a
custom category label, treat that as local organization only. The user-facing UI still groups your stuff under
the addon name so the menu does not turn into a junk drawer.
Use this when you want to see how everything works together, or when the minimal template stops being enough.
## Build Flow
From the main AUTISM Client folder, publish the API locally:
.\gradlew.bat publishToMavenLocal --no-daemon
Then build the template you want.
Minimal:
cd addon-templates\minimal
.\gradlew.bat build --no-daemon
Advanced:
cd addon-templates\advanced
.\gradlew.bat build --no-daemon
Your addon jar will be in:
build/libs/
That is the file you load as the addon.
## Toolkit
There is a toolkit script because renaming addon projects by hand is where people start creating cursed broken projects.
Run it from the main client folder:
.\addon-templates\addon-toolkit.ps1
Direct commands:
.\addon-templates\addon-toolkit.ps1 -Action Setup -Template minimal -OutputPath ..\MyAddon
.\addon-templates\addon-toolkit.ps1 -Action Scan -ProjectPath ..\MyAddon
.\addon-templates\addon-toolkit.ps1 -Action BuildAll
Setup asks for:
addon name
output folder
version
author
If you leave the version blank, it bumps the current template version by one.
It also generates the annoying stuff automatically:
addon id
package name
Maven group
jar name
description
Fabric entrypoints
mixin references
This matters because half renaming a mod is one of the easiest ways to make Gradle look like it hates you personally.
If you want to set every value yourself, use:
.\addon-templates\addon-toolkit.ps1 -Action Setup -Template advanced -Advanced
Do that only if you actually need control over everything. Or edit the files directly.
## Public Repo Rule
Commit the source, Gradle wrapper files, and config files.
Do not commit:
.gradle/
build/
They are already ignored by the root .gitignore.
If it is generated trash from your machine, it probably does not belong in the repo.

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
}

View file

@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4
[*.{json,yml,yaml}]
indent_size = 2
[*.md]
trim_trailing_whitespace = false

View file

@ -0,0 +1,45 @@
name: Build
on:
push:
pull_request:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 25
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
# NOTE: the build needs the AUTISM Client API artifact (com.autismclient:autism) to be resolvable.
# mavenLocal() is empty on a fresh CI runner, so make it available one of these ways:
# - publish AUTISM to a maven repo your build.gradle.kts lists (GitHub Packages, a maven server), or
# - commit the AUTISM jar into a `libs/` folder and add `flatDir { dirs("libs") }` to repositories.
- name: Build
run: ./gradlew build --stacktrace
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: addon-jar
path: build/libs/*.jar
- name: Release dev build
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: softprops/action-gh-release@v2
with:
tag_name: dev
name: Dev Build
prerelease: true
files: build/libs/*.jar

4
addon-templates/advanced/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
.gradle/
build/
run/
*.log

View file

@ -0,0 +1,93 @@
# AUTISM Advanced Addon Template
A standalone reference addon for AUTISM Client. It registers one of each supported extension point, so
you can copy it when you need the full API surface.
Start small: keep `ExampleModule`, build once, then add macro actions, commands, HUD elements, events,
or mixins as needed.
## What It Demonstrates
| Extension point | File |
| --- | --- |
| Addon lifecycle | `ExampleAddon` |
| Module | `modules/ExampleModule` |
| Macro action | `macro/ExampleSayAction` |
| Macro condition | `macro/ExampleHeightCondition` + `macro/ExampleCondition` |
| Macro preset | `macro/ExamplePresets` |
| Command | `commands/ExampleCommand` |
| HUD element | `hud/ExampleHud` |
| Event hooks | `events/ExampleEvents` |
| Mixin | `mixin/ExampleMixin` + `autism-advanced-addon-template.mixins.json` |
Presets are first-class addon entries. `ExamplePresets` appears in the macro editor `Presets` picker
under this addon's category, and it can insert any normal stack of macro actions.
Your modules, macro actions, conditions and presets automatically group under a category named after
your addon from `fabric.mod.json`. Custom categories are scoped under your addon so they cannot collide
with built-ins or another addon.
## Build
1. In the AUTISM Client project, publish the API to your local Maven repo:
```sh
./gradlew publishToMavenLocal
```
2. Make sure the `autism` version in `gradle/libs.versions.toml` matches what you published.
3. Build this addon:
```sh
./gradlew build
```
The addon jar lands in `build/libs/`.
## Run
Drop both jars into your `mods/` folder:
- the AUTISM Client jar;
- this addon's jar from `build/libs/`.
## Make It Yours
Recommended:
```powershell
..\addon-toolkit.ps1 -Action Setup -Template advanced -OutputPath ..\..\..\MyAdvancedAddon
```
The toolkit asks for the addon name, output folder, version, and author. Blank version bumps the current
template version by one patch step. It derives the boring stuff and rewrites Gradle files, package paths,
`fabric.mod.json`, entrypoints, and the mixin config in one shot.
Manual path:
1. Rename the package `com.example.addon`.
2. Change `ExampleAddon.ID`.
3. Update `src/main/resources/fabric.mod.json`: `id`, `name`, `entrypoints`, `mixins`, and `autism:color`.
4. Rename `autism-advanced-addon-template.mixins.json` and update its `package`.
5. Keep `apiVersion()` and the `autism` dependency range honest for the client version you target.
## Project Structure
```text
addon-templates/advanced/
|-- gradle/
|-- src/main/java/com/example/addon/
| |-- ExampleAddon.java
| |-- ExampleInit.java
| |-- modules/ExampleModule.java
| |-- macro/ExampleSayAction.java
| |-- macro/ExampleHeightCondition.java
| |-- macro/ExampleCondition.java
| |-- macro/ExamplePresets.java
| |-- commands/ExampleCommand.java
| |-- hud/ExampleHud.java
| |-- events/ExampleEvents.java
| `-- mixin/ExampleMixin.java
|-- src/main/resources/
| |-- fabric.mod.json
| `-- autism-advanced-addon-template.mixins.json
|-- build.gradle.kts
`-- gradle.properties
```

View file

@ -0,0 +1,65 @@
plugins {
alias(libs.plugins.fabric.loom)
}
base {
archivesName = properties["archives_base_name"] as String
version = libs.versions.mod.version.get()
group = properties["maven_group"] as String
}
repositories {
// AUTISM Client is consumed from your local Maven repo. In the AUTISM project run:
// ./gradlew publishToMavenLocal
mavenLocal()
maven("https://maven.fabricmc.net/") { name = "Fabric" }
mavenCentral()
}
dependencies {
// Mirrors the AUTISM Client build: official Mojang mappings are implicit for 26.1.2, so there is no
// explicit `mappings(...)` line and dependencies use plain `implementation`.
minecraft(libs.minecraft)
implementation(libs.fabric.loader)
implementation(libs.fabric.api)
// The AUTISM Client API (published to mavenLocal from the AUTISM project).
implementation(libs.autism)
}
// Turns an exact Minecraft version (e.g. "26.1.2") into a patch-compatible range ("~26.1") so the addon
// keeps loading across patch releases instead of pinning one exact build.
fun toMinecraftCompat(version: String): String {
val m = Regex("""^(\d+)\.(\d+)(?:\.(\d+))?$""").matchEntire(version)
?: return version
val (year, drop, _) = m.destructured
return "~$year.$drop"
}
tasks {
processResources {
val propertyMap = mapOf(
"version" to project.version,
"mc_version" to libs.versions.minecraft.get(),
"mc_compat" to toMinecraftCompat(libs.versions.minecraft.get())
)
inputs.properties(propertyMap)
filteringCharset = "UTF-8"
filesMatching("fabric.mod.json") {
expand(propertyMap)
}
}
java {
sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_25
toolchain {
languageVersion.set(JavaLanguageVersion.of(25))
}
}
withType<JavaCompile> {
options.encoding = "UTF-8"
options.release.set(25)
}
}

View file

@ -0,0 +1,7 @@
org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=false
maven_group=com.example.addon
archives_base_name=autism-advanced-addon-template

View file

@ -0,0 +1,19 @@
# Mirror these versions with the AUTISM Client release you are building against.
[versions]
mod-version = "1.0.0"
minecraft = "26.1.2"
fabric-loader = "0.18.4"
fabric-api = "0.147.0+26.1.2"
autism = "2.3"
loom = "1.16-SNAPSHOT"
[libraries]
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" }
fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" }
autism = { module = "com.autismclient:autism", version.ref = "autism" }
[plugins]
fabric-loom = { id = "net.fabricmc.fabric-loom", version.ref = "loom" }

Binary file not shown.

View file

@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

248
addon-templates/advanced/gradlew vendored Normal file
View file

@ -0,0 +1,248 @@
#!/bin/sh
#
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

93
addon-templates/advanced/gradlew.bat vendored Normal file
View file

@ -0,0 +1,93 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View file

@ -0,0 +1,9 @@
pluginManagement {
repositories {
maven("https://maven.fabricmc.net/") { name = "Fabric" }
mavenCentral()
gradlePluginPortal()
}
}
rootProject.name = "autism-advanced-addon-template"

View file

@ -0,0 +1,53 @@
package com.example.addon;
import autismclient.api.AutismAddon;
import autismclient.api.AutismAddons;
import autismclient.api.ApiVersion;
import autismclient.api.macro.MacroActionEntry;
import com.example.addon.commands.ExampleCommand;
import com.example.addon.events.ExampleEvents;
import com.example.addon.hud.ExampleHud;
import com.example.addon.macro.ExampleHeightCondition;
import com.example.addon.macro.ExamplePresets;
import com.example.addon.macro.ExampleSayAction;
import com.example.addon.modules.ExampleModule;
// Addon entrypoint (the "autism" entrypoint in fabric.mod.json). Start small:
// register only ExampleModule first, launch the client, then add macro/actions/HUD/events as needed.
// Modules, actions, conditions and presets all auto-group under a category named after this addon.
public final class ExampleAddon extends AutismAddon {
public static final String ID = "autism-advanced-addon-template";
@Override
public int apiVersion() {
return ApiVersion.CURRENT;
}
@Override
public void onInitialize() {
AutismAddons.modules().register(new ExampleModule());
// Action: appears in the "add action" picker.
AutismAddons.macroActions().register(MacroActionEntry.local("say", ExampleSayAction::new)
.picker("Say", "Send a chat message.")
.build());
// Condition: appears in the "add condition" picker (it waits).
AutismAddons.macroActions().register(MacroActionEntry.local("wait-height", ExampleHeightCondition::new)
.condition("Wait Height", "Wait until the player is at or above a Y level.")
.build());
AutismAddons.presets().register("Reach Height", "Wait for Y 80, then say.",
ExamplePresets::reachHeightThenSay);
AutismAddons.commands().register(new ExampleCommand());
AutismAddons.hud().register(new ExampleHud());
ExampleEvents.register();
}
@Override
public String getPackage() {
return "com.example.addon";
}
}

View file

@ -0,0 +1,9 @@
package com.example.addon;
import net.fabricmc.api.ClientModInitializer;
// Fabric's required client entrypoint. The addon's real work is in ExampleAddon.
public final class ExampleInit implements ClientModInitializer {
@Override
public void onInitializeClient() {}
}

View file

@ -0,0 +1,29 @@
package com.example.addon.commands;
import autismclient.commands.AutismCommandSource;
import autismclient.commands.Command;
import autismclient.util.AutismClientMessaging;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
// A Brigadier command. Users run it with the command prefix, e.g. .example or .example hi.
public final class ExampleCommand extends Command {
public ExampleCommand() {
super("example", "Example addon command.");
}
@Override
public void build(LiteralArgumentBuilder<AutismCommandSource> root) {
root.executes(ctx -> {
AutismClientMessaging.sendPrefixed("\u00a7dExample addon command works!");
return SUCCESS;
});
root.then(RequiredArgumentBuilder.<AutismCommandSource, String>argument("text", StringArgumentType.greedyString())
.executes(ctx -> {
AutismClientMessaging.sendPrefixed("\u00a7dYou said: \u00a7f" + StringArgumentType.getString(ctx, "text"));
return SUCCESS;
}));
}
}

View file

@ -0,0 +1,15 @@
package com.example.addon.events;
import autismclient.api.AutismAddons;
import autismclient.util.AutismClientMessaging;
// Event hooks. Register listeners once in onInitialize().
// Available: onTick, onPacketSend (return true to cancel), onPacketReceive, onGameJoin, onGameLeft.
public final class ExampleEvents {
private ExampleEvents() {}
public static void register() {
AutismAddons.events().onGameJoin(() ->
AutismClientMessaging.sendPrefixed("\u00a7a[Example] joined a world!"));
}
}

View file

@ -0,0 +1,43 @@
package com.example.addon.hud;
import com.example.addon.ExampleAddon;
import autismclient.api.hud.HudElementProvider;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphicsExtractor;
// A HUD element. Report your size via width()/height(); draw in render() with the GuiGraphicsExtractor
// (ctx.text / ctx.fill). The defaultX/Y/anchor/enabled are used until the user moves it in the HUD editor.
public final class ExampleHud implements HudElementProvider {
private static final int MIN_WIDTH = 94;
private static final int TEXT_PAD = 2;
@Override public String id() { return ExampleAddon.ID + ":clock"; }
@Override public String label() { return "Example Clock"; }
@Override public String description() { return "Shows the in-game tick."; }
@Override
public int width() {
Font font = Minecraft.getInstance().font;
String text = text();
int textWidth = font != null ? font.width(text) : text.length() * 6;
return Math.max(MIN_WIDTH, textWidth + TEXT_PAD * 2);
}
@Override public int height() { return 10; }
@Override
public void render(GuiGraphicsExtractor ctx, Font font, int x, int y, float alpha) {
ctx.text(font, text(), x + TEXT_PAD, y, 0xFFFFD7FF);
}
private static String text() {
long tick = Minecraft.getInstance().level != null ? Minecraft.getInstance().level.getGameTime() : 0L;
return "Addon tick: " + tick;
}
@Override public boolean defaultEnabled() { return false; }
@Override public String defaultAnchor() { return "TOP_LEFT"; }
@Override public int defaultX() { return 4; }
@Override public int defaultY() { return 120; }
}

View file

@ -0,0 +1,18 @@
package com.example.addon.macro;
import autismclient.api.macro.AddonCondition;
import net.minecraft.client.Minecraft;
// A reusable predicate: implement check(). A waiting step blocks on it via ctx.awaitCondition(...).
public final class ExampleCondition extends AddonCondition {
private final double minY;
public ExampleCondition(double minY) {
this.minY = minY;
}
@Override
public boolean check(Minecraft mc) {
return mc.player != null && mc.player.getY() >= minY;
}
}

View file

@ -0,0 +1,50 @@
package com.example.addon.macro;
import com.example.addon.ExampleAddon;
import autismclient.api.macro.ActionSchema;
import autismclient.api.macro.AddonContextAction;
import autismclient.api.macro.MacroExecutionContext;
import net.minecraft.nbt.CompoundTag;
// A macro condition: a step that waits. Extend AddonContextAction and block in run(), e.g. with
// ctx.awaitCondition(...). Register it with .condition(...) so it lands in the condition picker.
public final class ExampleHeightCondition extends AddonContextAction {
public static final String TYPE_ID = ExampleAddon.ID + ":wait-height";
public double minY = 64.0;
public ExampleHeightCondition() {
super(TYPE_ID);
}
@Override
public void run(MacroExecutionContext ctx) throws InterruptedException {
ctx.setStatus("Waiting until Y >= " + minY);
ctx.awaitCondition(new ExampleCondition(minY));
}
@Override
protected void save(CompoundTag tag) {
putDouble(tag, "minY", minY);
}
@Override
protected void load(CompoundTag tag) {
minY = getDouble(tag, "minY", minY);
}
@Override
protected ActionSchema schema() {
return ActionSchema.builder().decimal("minY", "Min Y").decRange(-64, 320).build();
}
@Override
public String getDisplayName() {
return "Wait until Y >= " + minY;
}
@Override
public String getIcon() {
return "Y";
}
}

View file

@ -0,0 +1,26 @@
package com.example.addon.macro;
import autismclient.util.macro.MacroAction;
import java.util.ArrayList;
import java.util.List;
// Presets insert a ready-made stack of steps. Return a fresh list each call; don't reuse instances.
public final class ExamplePresets {
private ExamplePresets() {}
// Wait until the player is high up, then announce it.
public static List<MacroAction> reachHeightThenSay() {
List<MacroAction> stack = new ArrayList<>();
ExampleHeightCondition waitForHeight = new ExampleHeightCondition();
waitForHeight.minY = 80.0;
stack.add(waitForHeight);
ExampleSayAction say = new ExampleSayAction();
say.message = "Reached Y 80!";
stack.add(say);
return stack;
}
}

View file

@ -0,0 +1,50 @@
package com.example.addon.macro;
import com.example.addon.ExampleAddon;
import autismclient.api.macro.ActionSchema;
import autismclient.api.macro.AddonAction;
import autismclient.util.AutismClientMessaging;
import net.minecraft.client.Minecraft;
import net.minecraft.nbt.CompoundTag;
// A macro action: runs once when the step is reached. Extend AddonAction and pass a namespaced id.
public final class ExampleSayAction extends AddonAction {
public static final String TYPE_ID = ExampleAddon.ID + ":say";
public String message = "Hello from an addon!";
public ExampleSayAction() {
super(TYPE_ID);
}
@Override
protected void run(Minecraft mc) {
AutismClientMessaging.sendPrefixed("\u00a7d[Example] " + message);
}
// Field keys here, in load(), and in the schema must match.
@Override
protected void save(CompoundTag tag) {
putString(tag, "message", message);
}
@Override
protected void load(CompoundTag tag) {
message = getString(tag, "message", message);
}
@Override
protected ActionSchema schema() {
return ActionSchema.builder().text("message", "Say").build();
}
@Override
public String getDisplayName() {
return "Say: " + message;
}
@Override
public String getIcon() {
return "S";
}
}

View file

@ -0,0 +1,19 @@
package com.example.addon.mixin;
import com.example.addon.ExampleAddon;
import net.minecraft.client.Minecraft;
import net.minecraft.client.main.GameConfig;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
// Example mixin. List your mixin classes in autism-advanced-addon-template.mixins.json (referenced from
// fabric.mod.json). An @Inject handler matches the target method's params, then CallbackInfo.
@Mixin(Minecraft.class)
public abstract class ExampleMixin {
@Inject(method = "<init>", at = @At("TAIL"))
private void onClientInit(GameConfig gameConfig, CallbackInfo ci) {
org.slf4j.LoggerFactory.getLogger(ExampleAddon.ID).info("Hello from ExampleMixin!");
}
}

View file

@ -0,0 +1,28 @@
package com.example.addon.modules;
import com.example.addon.ExampleAddon;
import autismclient.modules.PackModule;
import autismclient.modules.PackModuleOption;
import autismclient.util.AutismClientMessaging;
// A toggleable module. With no category it auto-lands under a menu column named after your addon.
// Read option values with bool/integer/decimal/choice/text/list(id). Group options with .group("...").
public final class ExampleModule extends PackModule {
public ExampleModule() {
super(ExampleAddon.ID + ":example", "Example", "Demonstrates an AUTISM addon module.");
option(PackModuleOption.bool("greet", "Greet on enable", true).group("General"));
option(PackModuleOption.integer("amount", "Amount", 3, 1, 10, 1).group("General"));
option(PackModuleOption.enumChoice("style", "Style", "Friendly", "Friendly", "Loud").group("Display"));
option(PackModuleOption.bool("shout", "Shout in caps", false).group("Display"));
}
@Override
public void onEnable() {
if (bool("greet")) {
String msg = "[Example] enabled - amount " + integer("amount") + ", style " + choice("style");
if (bool("shout")) msg = msg.toUpperCase(java.util.Locale.ROOT);
AutismClientMessaging.sendPrefixed("\u00a7b" + msg);
}
}
}

View file

@ -0,0 +1,11 @@
{
"required": true,
"package": "com.example.addon.mixin",
"compatibilityLevel": "JAVA_25",
"client": [
"ExampleMixin"
],
"injectors": {
"defaultRequire": 1
}
}

View file

@ -0,0 +1,37 @@
{
"schemaVersion": 1,
"id": "autism-advanced-addon-template",
"version": "${version}",
"name": "AUTISM Advanced",
"description": "Reference addon for AUTISM Client: a module, macro action, preset, condition, command, HUD element, and event hook.",
"authors": [
"You"
],
"custom": {
"autism:color": "255,80,80",
"modmenu": {
"parent": {
"id": "autism"
}
}
},
"environment": "client",
"entrypoints": {
"client": [
"com.example.addon.ExampleInit"
],
"autism": [
"com.example.addon.ExampleAddon"
]
},
"mixins": [
"autism-advanced-addon-template.mixins.json"
],
"depends": {
"java": ">=25",
"minecraft": "${mc_compat}",
"fabricloader": ">=0.18.4",
"fabric-api": "*",
"autism": ">=2.3"
}
}

View file

@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4
[*.{json,yml,yaml}]
indent_size = 2
[*.md]
trim_trailing_whitespace = false

4
addon-templates/minimal/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
.gradle/
build/
run/
*.log

View file

@ -0,0 +1,42 @@
# AUTISM Minimal Addon Template
Smallest useful AUTISM addon example:
- one module;
- one macro action;
- one macro condition.
This template uses the easy API (`SimpleAddon`, `SimpleModule`, `simpleAction`, `simpleCondition`).
Use `../advanced` when you need commands, HUD elements, events, raw custom macro serialization, or mixins.
## Build
1. From the AUTISM Client project, publish the API locally:
```powershell
.\gradlew.bat publishToMavenLocal --no-daemon
```
2. From this folder, build the addon:
```powershell
.\gradlew.bat build --no-daemon
```
The jar lands in `build/libs/`.
## Customize
Recommended:
```powershell
..\addon-toolkit.ps1 -Action Setup -Template minimal -OutputPath ..\..\..\MyAddon
```
The toolkit asks for the addon name, output folder, version, and author. Blank version bumps the current
template version by one patch step. It derives the boring stuff and rewrites Gradle files, package paths,
`fabric.mod.json`, and entrypoints in one shot.
Manual path:
1. Rename package `com.example.minimal`.
2. Change `MinimalAddon.ID`.
3. Update `src/main/resources/fabric.mod.json`.
4. Change names/descriptions in `MinimalAddon`.

View file

@ -0,0 +1,65 @@
plugins {
alias(libs.plugins.fabric.loom)
}
base {
archivesName = properties["archives_base_name"] as String
version = libs.versions.mod.version.get()
group = properties["maven_group"] as String
}
repositories {
// AUTISM Client is consumed from your local Maven repo. In the AUTISM project run:
// ./gradlew publishToMavenLocal
mavenLocal()
maven("https://maven.fabricmc.net/") { name = "Fabric" }
mavenCentral()
}
dependencies {
// Mirrors the AUTISM Client build: official Mojang mappings are implicit for 26.1.2, so there is no
// explicit `mappings(...)` line and dependencies use plain `implementation`.
minecraft(libs.minecraft)
implementation(libs.fabric.loader)
implementation(libs.fabric.api)
// The AUTISM Client API (published to mavenLocal from the AUTISM project).
implementation(libs.autism)
}
// Turns an exact Minecraft version (e.g. "26.1.2") into a patch-compatible range ("~26.1") so the addon
// keeps loading across patch releases instead of pinning one exact build.
fun toMinecraftCompat(version: String): String {
val m = Regex("""^(\d+)\.(\d+)(?:\.(\d+))?$""").matchEntire(version)
?: return version
val (year, drop, _) = m.destructured
return "~$year.$drop"
}
tasks {
processResources {
val propertyMap = mapOf(
"version" to project.version,
"mc_version" to libs.versions.minecraft.get(),
"mc_compat" to toMinecraftCompat(libs.versions.minecraft.get())
)
inputs.properties(propertyMap)
filteringCharset = "UTF-8"
filesMatching("fabric.mod.json") {
expand(propertyMap)
}
}
java {
sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_25
toolchain {
languageVersion.set(JavaLanguageVersion.of(25))
}
}
withType<JavaCompile> {
options.encoding = "UTF-8"
options.release.set(25)
}
}

View file

@ -0,0 +1,7 @@
org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=false
maven_group=com.example.addon
archives_base_name=autism-minimal-addon-template

View file

@ -0,0 +1,19 @@
# Mirror these versions with the AUTISM Client release you are building against.
[versions]
mod-version = "1.0.0"
minecraft = "26.1.2"
fabric-loader = "0.18.4"
fabric-api = "0.147.0+26.1.2"
autism = "2.3"
loom = "1.16-SNAPSHOT"
[libraries]
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" }
fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" }
autism = { module = "com.autismclient:autism", version.ref = "autism" }
[plugins]
fabric-loom = { id = "net.fabricmc.fabric-loom", version.ref = "loom" }

Binary file not shown.

View file

@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

248
addon-templates/minimal/gradlew vendored Normal file
View file

@ -0,0 +1,248 @@
#!/bin/sh
#
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

93
addon-templates/minimal/gradlew.bat vendored Normal file
View file

@ -0,0 +1,93 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View file

@ -0,0 +1,9 @@
pluginManagement {
repositories {
maven("https://maven.fabricmc.net/") { name = "Fabric" }
mavenCentral()
gradlePluginPortal()
}
}
rootProject.name = "autism-minimal-addon-template"

View file

@ -0,0 +1,35 @@
package com.example.minimal;
import autismclient.api.ApiVersion;
import autismclient.api.SimpleAddon;
import autismclient.api.macro.MacroActionEntry;
import autismclient.api.module.SimpleModule;
import autismclient.util.AutismClientMessaging;
public final class MinimalAddon extends SimpleAddon {
public static final String ID = "autism-minimal-addon-template";
public MinimalAddon() {
super(ApiVersion.CURRENT, "com.example.minimal");
}
@Override
protected void initialize() {
SimpleModule module = new SimpleModule("hello-module", "Hello Module", "Tiny example addon module.")
.addBool("greet", "Greet On Enable", true)
.addText("message", "Message", "Hello from my addon")
.onEnabled(self -> {
if (self.getBool("greet")) {
AutismClientMessaging.sendPrefixed("\u00a7a" + self.getText("message"));
}
});
registerModule(module);
registerAction(simpleAction("say-hello", "Say Hello", "Send a short addon message.", "S", mc ->
AutismClientMessaging.sendPrefixed("\u00a7aHello from the minimal addon!")));
MacroActionEntry condition = simpleCondition("wait-player", "Wait Player", "Wait until the local player exists.",
"Waiting for player", "P", mc -> mc.player != null);
registerAction(condition);
}
}

View file

@ -0,0 +1,8 @@
package com.example.minimal;
import net.fabricmc.api.ClientModInitializer;
public final class MinimalInit implements ClientModInitializer {
@Override
public void onInitializeClient() {}
}

View file

@ -0,0 +1,34 @@
{
"schemaVersion": 1,
"id": "autism-minimal-addon-template",
"version": "${version}",
"name": "AUTISM Minimal Addon Template",
"description": "Small AUTISM Client addon example: one module, one macro action, and one macro condition.",
"authors": [
"You"
],
"custom": {
"autism:color": "80,220,120",
"modmenu": {
"parent": {
"id": "autism"
}
}
},
"environment": "client",
"entrypoints": {
"client": [
"com.example.minimal.MinimalInit"
],
"autism": [
"com.example.minimal.MinimalAddon"
]
},
"depends": {
"java": ">=25",
"minecraft": "${mc_compat}",
"fabricloader": ">=0.18.4",
"fabric-api": "*",
"autism": ">=2.3"
}
}