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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,11 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Setup TinyGo
uses: acifani/setup-tinygo@v2
with:
tinygo-version: '0.39.0'

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.25'

- name: Build with TinyGo
run: |
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} tinygo build -o mcrun-${{ matrix.goos }}-${{ matrix.goarch }}-tinygo .

- name: Build with Go
run: |
CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -ldflags="-s -w" -o mcrun-${{ matrix.goos }}-${{ matrix.goarch }} .
Expand All @@ -53,4 +44,21 @@ jobs:
run: |
$env:CGO_ENABLED="0"
$env:GOARCH="${{ matrix.goarch }}"
go build -ldflags="-s -w" -o mcrun-windows-${{ matrix.goarch }}.exe .
go build -ldflags="-s -w" -o mcrun-windows-${{ matrix.goarch }}.exe .

test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.25'

- name: Vet
run: go vet ./...

- name: Test
run: go test ./...
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ Install or manage Java versions.
mcrun install java [flags]

Flags:
--version int Java version to install (8, 11, 17, 21)
--version int Java version to install (8, 11, 17, 21, 25)
--system Install system-wide (requires root/admin)
--list List installed Java versions
--set-default Set as system default after install
Expand Down Expand Up @@ -180,7 +180,7 @@ mcrun install java --version=21 --set-default
-m, --mod string Server type: vanilla, paper, forge, fabric, waterfall, velocity, bungeecord, spigot, craftbukkit, cauldron
--mod-version string Mod-specific version (e.g., Paper build number)
--version string Minecraft version (e.g., 1.20.4)
--java int Java version override (8, 11, 17, 21)
--java int Java version override (8, 11, 17, 21, 25)
--java-path string Custom Java binary path
-V, --verbose Enable verbose output
```
Expand Down Expand Up @@ -211,14 +211,18 @@ mcrun install java --version=21 --set-default

## Java Version Requirements

mcrun automatically selects the correct Java version based on Minecraft version:
mcrun automatically selects a recommended Java version: it starts from the requirement
in Mojang's version metadata when available and rounds it up to the nearest available
LTS release (e.g. Minecraft 1.17 reports Java 16, mcrun uses Java 17). When Mojang
metadata is unavailable, this fallback table is used:

| Minecraft Version | Required Java |
|-------------------|---------------|
| Minecraft Version | Recommended Java |
|-------------------|------------------|
| 26.2+ (year-based versions) | Java 25 |
| 1.21+ | Java 21 |
| 1.20.5 - 1.20.6 | Java 21 |
| 1.18 - 1.20.4 | Java 17 |
| 1.17 - 1.17.1 | Java 16+ |
| 1.17 - 1.17.1 | Java 17 |
| 1.16.5 and older | Java 8 |

**Proxy servers** (Waterfall, Velocity, Bungeecord) require **Java 17**.
Expand Down
8 changes: 4 additions & 4 deletions cmd/mcrun/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var installJavaCmd = &cobra.Command{
Short: "Install or manage Java",
Long: `Install Java from Eclipse Adoptium or list installed Java versions.

Available LTS versions: 8, 11, 17, 21
Available LTS versions: 8, 11, 17, 21, 25

Examples:
mcrun install java # Install latest LTS Java
Expand All @@ -55,7 +55,7 @@ Examples:
// Install mode
version := installJavaVersion
if version == 0 {
version = 21 // Default to latest LTS
version = 25 // Default to latest LTS
}

fmt.Printf("Installing Java %d...\n", version)
Expand Down Expand Up @@ -92,7 +92,7 @@ func listInstalledJava(manager *java.Manager) error {
if len(installations) == 0 {
fmt.Println("[WARNING] No Java installations found.")
fmt.Println("\nInstall Java with:")
fmt.Println(" mcrun install java --version=21")
fmt.Println(" mcrun install java --version=25")
return nil
}

Expand Down Expand Up @@ -136,7 +136,7 @@ func init() {
rootCmd.AddCommand(installCmd)
installCmd.AddCommand(installJavaCmd)

installJavaCmd.Flags().IntVar(&installJavaVersion, "version", 0, "Java version to install (8, 11, 17, 21)")
installJavaCmd.Flags().IntVar(&installJavaVersion, "version", 0, "Java version to install (8, 11, 17, 21, 25)")
installJavaCmd.Flags().BoolVar(&installSystemWide, "system", false, "install system-wide (requires root/admin)")
installJavaCmd.Flags().BoolVar(&installListJava, "list", false, "list installed Java versions")
installJavaCmd.Flags().BoolVar(&installSetDefault, "set-default", false, "set as system default after install")
Expand Down
7 changes: 4 additions & 3 deletions cmd/mcrun/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ var rootCmd = &cobra.Command{
Cross-platform CLI tool to download and run Minecraft servers
with integrated Java management.

Supported server types: vanilla, paper, forge, fabric, spigot, craftbukkit, cauldron`,
Supported server types: vanilla, paper, forge, fabric, spigot, craftbukkit, cauldron,
waterfall, velocity, bungeecord`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
var err error
cfg, err = config.Load(cfgFile, serverDir)
Expand Down Expand Up @@ -85,9 +86,9 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default: ~/.mcrun/config.yaml)")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "V", false, "enable verbose output")
rootCmd.PersistentFlags().StringVar(&mcVersion, "version", "", "Minecraft version (e.g., 1.20.4)")
rootCmd.PersistentFlags().StringVarP(&mod, "mod", "m", "vanilla", "server mod type (vanilla, paper, forge, fabric, spigot, craftbukkit, cauldron)")
rootCmd.PersistentFlags().StringVarP(&mod, "mod", "m", "vanilla", "server mod type (vanilla, paper, forge, fabric, spigot, craftbukkit, cauldron, waterfall, velocity, bungeecord)")
rootCmd.PersistentFlags().StringVar(&modVersion, "mod-version", "", "mod-specific version")
rootCmd.PersistentFlags().IntVar(&javaVersion, "java", 0, "Java version override (8, 11, 17, 21)")
rootCmd.PersistentFlags().IntVar(&javaVersion, "java", 0, "Java version override (8, 11, 17, 21, 25)")
rootCmd.PersistentFlags().StringVar(&javaPath, "java-path", "", "custom Java binary path")
rootCmd.PersistentFlags().StringVarP(&serverDir, "dir", "d", ".", "server working directory")
}
35 changes: 1 addition & 34 deletions internal/java/detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
// Installation represents a detected Java installation
type Installation struct {
Path string // Full path to java binary
Version int // Major version (8, 11, 17, 21)
Version int // Major version (8, 11, 17, 21, 25)
FullVersion string // e.g., "21.0.9+10-LTS"
Vendor string // e.g., "Eclipse Adoptium"
IsSystem bool // System-wide vs user/bundled
Expand Down Expand Up @@ -71,39 +71,6 @@ func (d *Detector) DetectAll() ([]Installation, error) {
return installations, nil
}

// FindForVersion finds a Java installation suitable for a Minecraft version
func (d *Detector) FindForVersion(mcVersion string) (*Installation, error) {
required := GetRequiredJavaVersion(mcVersion)
installations, err := d.DetectAll()
if err != nil {
return nil, err
}

// First try to find exact match
for _, inst := range installations {
if inst.Version == required {
return &inst, nil
}
}

// Then find any compatible version (higher is ok)
var best *Installation
for i := range installations {
inst := &installations[i]
if inst.Version >= required {
if best == nil || inst.Version < best.Version {
best = inst
}
}
}

if best != nil {
return best, nil
}

return nil, fmt.Errorf("no compatible Java found (need Java %d or higher)", required)
}

// getSearchPaths returns paths to search for Java installations
func (d *Detector) getSearchPaths() []string {
home, _ := os.UserHomeDir()
Expand Down
30 changes: 0 additions & 30 deletions internal/java/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,6 @@ func NewManager(cfg *config.Config) *Manager {
}
}

// GetForMinecraftVersion finds or installs Java suitable for a Minecraft version
func (m *Manager) GetForMinecraftVersion(ctx context.Context, mcVersion string, autoInstall bool) (*Installation, error) {
required := GetRequiredJavaVersion(mcVersion)

// Check config for custom path
if m.config != nil && m.config.Java.Paths != nil {
if customPath, ok := m.config.Java.Paths[required]; ok && customPath != "" {
inst, err := m.detector.getInstallationInfo(customPath)
if err == nil && inst.Version >= required {
return inst, nil
}
}
}

// Try to find existing installation
inst, err := m.detector.FindForVersion(mcVersion)
if err == nil {
return inst, nil
}

// Auto-install if enabled
if autoInstall || (m.config != nil && m.config.Java.AutoInstall) {
fmt.Printf("Java %d not found. Installing...\n", required)
return m.installer.Install(ctx, required, InstallOptions{})
}

return nil, fmt.Errorf("Java %d required for Minecraft %s but not found. Run 'mcrun install java --version=%d' to install",
required, mcVersion, required)
}

// GetByVersion finds or installs a specific Java version
func (m *Manager) GetByVersion(ctx context.Context, version int, autoInstall bool) (*Installation, error) {
// Check config for custom path
Expand Down
60 changes: 0 additions & 60 deletions internal/java/version_map.go

This file was deleted.

2 changes: 1 addition & 1 deletion internal/providers/bungeecord.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,6 @@ func (p *BungeecordProvider) PostDownload(ctx context.Context, jarPath string, j
}

// GetRecommendedJavaVersion returns Java 17 for modern Bungeecord
func (p *BungeecordProvider) GetRecommendedJavaVersion(_ string) int {
func (p *BungeecordProvider) GetRecommendedJavaVersion(_ context.Context, _ string) int {
return 17
}
2 changes: 1 addition & 1 deletion internal/providers/cauldron.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (p *CauldronProvider) PostDownload(ctx context.Context, jarPath string, jav
}

// GetRecommendedJavaVersion returns the recommended Java version
func (p *CauldronProvider) GetRecommendedJavaVersion(mcVersion string) int {
func (p *CauldronProvider) GetRecommendedJavaVersion(_ context.Context, _ string) int {
// Cauldron is old and requires Java 8
return 8
}
7 changes: 4 additions & 3 deletions internal/providers/craftbukkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ func (p *CraftBukkitProvider) printPaperSuggestion() {
fmt.Println("\n[WARNING] CraftBukkit requires BuildTools compilation which is slow and complex.")
fmt.Println(" Suggestion: Use Paper instead - it's a modern fork of CraftBukkit/Spigot")
fmt.Println(" that's directly downloadable and offers better performance.")
fmt.Println(" Run: mcrun run --mod=paper --version=<version>\n")
fmt.Println(" Run: mcrun run --mod=paper --version=<version>")
fmt.Println()
}

// ListVersions returns available Minecraft versions
Expand Down Expand Up @@ -60,6 +61,6 @@ func (p *CraftBukkitProvider) PostDownload(ctx context.Context, jarPath string,
}

// GetRecommendedJavaVersion returns the recommended Java version
func (p *CraftBukkitProvider) GetRecommendedJavaVersion(mcVersion string) int {
return GetRecommendedJavaVersion(mcVersion)
func (p *CraftBukkitProvider) GetRecommendedJavaVersion(ctx context.Context, mcVersion string) int {
return GetRecommendedJavaVersion(ctx, mcVersion)
}
4 changes: 2 additions & 2 deletions internal/providers/fabric.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,6 @@ func (p *FabricProvider) PostDownload(ctx context.Context, jarPath string, javaP
}

// GetRecommendedJavaVersion returns the recommended Java version
func (p *FabricProvider) GetRecommendedJavaVersion(mcVersion string) int {
return GetRecommendedJavaVersion(mcVersion)
func (p *FabricProvider) GetRecommendedJavaVersion(ctx context.Context, mcVersion string) int {
return GetRecommendedJavaVersion(ctx, mcVersion)
}
4 changes: 2 additions & 2 deletions internal/providers/forge.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ func (p *ForgeProvider) PostDownload(ctx context.Context, jarPath string, javaPa
}

// GetRecommendedJavaVersion returns the recommended Java version
func (p *ForgeProvider) GetRecommendedJavaVersion(mcVersion string) int {
return GetRecommendedJavaVersion(mcVersion)
func (p *ForgeProvider) GetRecommendedJavaVersion(ctx context.Context, mcVersion string) int {
return GetRecommendedJavaVersion(ctx, mcVersion)
}

// compareVersions compares two version strings
Expand Down
Loading
Loading