diff --git a/cmd/join.go b/cmd/join.go index ece3e8c..359a072 100644 --- a/cmd/join.go +++ b/cmd/join.go @@ -23,6 +23,7 @@ import ( ) func init() { + runner := &joinRunner{} cmd := commands.New(&cobra.Command{ Use: "join ", Short: "Joins a compatible server without any setup", @@ -30,14 +31,18 @@ func init() { Example: ` minepkg join demo.minepkg.host`, Aliases: []string{"i-wanna-play-on", "connect"}, Args: cobra.ExactArgs(1), - }, &joinRunner{}) + }, runner) + + cmd.Flags().IntVar(&runner.ramMiB, "ram", 0, "Overwrite the amount of RAM in MiB to use") rootCmd.AddCommand(cmd.Command) } -type joinRunner struct{} +type joinRunner struct { + ramMiB int +} -func (i *joinRunner) RunE(cmd *cobra.Command, args []string) error { +func (j *joinRunner) RunE(cmd *cobra.Command, args []string) error { var resolvedModpack *api.Release ip := "127.0.0.1" @@ -108,6 +113,7 @@ func (i *joinRunner) RunE(cmd *cobra.Command, args []string) error { opts := &instances.LaunchOptions{ JoinServer: ip + ":" + port, + RamMiB: j.ramMiB, } err = cliLauncher.Launch(opts) if err != nil { diff --git a/cmd/launch.go b/cmd/launch.go index d207658..71cd92b 100644 --- a/cmd/launch.go +++ b/cmd/launch.go @@ -151,6 +151,7 @@ func (l *launchRunner) RunE(cmd *cobra.Command, args []string) error { Server: l.serverMode, Debug: l.debugMode, Demo: l.demo, + RamMiB: l.overwrites.Ram, } launchErr := make(chan error) diff --git a/cmd/launch/cli-flags.go b/cmd/launch/cli-flags.go index c3f0680..ebe30f0 100644 --- a/cmd/launch/cli-flags.go +++ b/cmd/launch/cli-flags.go @@ -13,6 +13,7 @@ type OverwriteFlags struct { FabricVersion string ForgeVersion string MinepkgCompanion string + Ram int } func CmdOverwriteFlags(cmd *cobra.Command) *OverwriteFlags { @@ -20,6 +21,7 @@ func CmdOverwriteFlags(cmd *cobra.Command) *OverwriteFlags { cmd.Flags().StringVarP(&flags.McVersion, "minecraft", "m", "", "Overwrite the required Minecraft version") cmd.Flags().StringVar(&flags.FabricVersion, "fabricLoader", "", "Overwrite the required fabricLoader version") cmd.Flags().StringVar(&flags.MinepkgCompanion, "minepkgCompanion", "", "Overwrite the required minepkg companion version (can also be \"none\")") + cmd.Flags().IntVar(&flags.Ram, "ram", 0, "Overwrite the amount of RAM in MiB to use") return &flags } diff --git a/cmd/root.go b/cmd/root.go index d7e29e2..37a41bb 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -27,9 +27,8 @@ var Version string var nextVersion string = "0.1.0-dev-local" var ( - cfgFile string - globalDir = "/tmp" - disableColors bool + cfgFile string + globalDir = "/tmp" ) // rootCmd represents the base command when called without any subcommands @@ -97,14 +96,12 @@ func initRoot() { configPath := filepath.Join(configDir, "minepkg") // Global flags - rootCmd.PersistentFlags().BoolVarP(&disableColors, "no-color", "", false, "disable color output") rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", fmt.Sprintf("config file (default is %s/config.toml)", configPath)) rootCmd.PersistentFlags().BoolP("accept-minecraft-eula", "a", false, "Accept Minecraft's eula. See https://www.minecraft.net/en-us/eula/") rootCmd.PersistentFlags().BoolP("system-java", "", false, "Use system java instead of internal installation for launching Minecraft server or client") rootCmd.PersistentFlags().BoolP("verbose", "", false, "More verbose logging. Not really implemented yet") - rootCmd.PersistentFlags().BoolP("non-interactive", "", false, "Use default answer for all prompts") + rootCmd.PersistentFlags().BoolP("non-interactive", "", false, "Do not prompt for anything (use defaults instead)") - viper.BindPFlag("noColor", rootCmd.PersistentFlags().Lookup("no-color")) viper.BindPFlag("useSystemJava", rootCmd.PersistentFlags().Lookup("system-java")) viper.BindPFlag("acceptMinecraftEula", rootCmd.PersistentFlags().Lookup("accept-minecraft-eula")) viper.BindPFlag("verboseLogging", rootCmd.PersistentFlags().Lookup("verbose")) diff --git a/cmd/try.go b/cmd/try.go index 2a7add3..527dc46 100644 --- a/cmd/try.go +++ b/cmd/try.go @@ -163,6 +163,7 @@ func (t *tryRunner) RunE(cmd *cobra.Command, args []string) error { Server: t.serverMode, Offline: t.offlineMode, StartSave: startSave, + RamMiB: t.overwrites.Ram, } err = cliLauncher.Launch(opts) if err != nil { diff --git a/go.mod b/go.mod index 8c940c4..a45e925 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/mholt/archiver/v3 v3.5.0 github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/muesli/termenv v0.8.1 // indirect + github.com/pbnjay/memory v0.0.0-20201129165224-b12e5d931931 // indirect github.com/pelletier/go-toml v1.9.1 github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.1.3 diff --git a/go.sum b/go.sum index cabba36..d55b96a 100644 --- a/go.sum +++ b/go.sum @@ -276,6 +276,8 @@ github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7 github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pbnjay/memory v0.0.0-20201129165224-b12e5d931931 h1:EeWknjeRU+R3O4ghG7XZCpgSfJNStZyEP8aWyQwJM8s= +github.com/pbnjay/memory v0.0.0-20201129165224-b12e5d931931/go.mod h1:RMU2gJXhratVxBDTFeOdNhd540tG57lt9FIUV0YLvIQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.1 h1:a6qW1EVNZWH9WGI6CsYdD8WAylkoXBS5yv0XHlh17Tc= github.com/pelletier/go-toml v1.9.1/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= diff --git a/internals/instances/launch.go b/internals/instances/launch.go index 871b2f5..433d92d 100644 --- a/internals/instances/launch.go +++ b/internals/instances/launch.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "io/ioutil" + "math" "net/http" "net/url" "os" @@ -21,6 +22,7 @@ import ( "github.com/minepkg/minepkg/internals/minecraft" "github.com/minepkg/minepkg/internals/mojang" "github.com/minepkg/minepkg/pkg/manifest" + "github.com/pbnjay/memory" ) var ( @@ -67,6 +69,9 @@ type LaunchOptions struct { // StartSave can be a savegame name to start after startup StartSave string Debug bool + // RamMiB can be set to the amount of ram in MiB to start Minecraft with + // 0 determins the amount by modcount + available system ram + RamMiB int } // Launch will launch the minecraft instance @@ -250,6 +255,22 @@ func (i *Instance) BuildLaunchCmd(opts *LaunchOptions) (*exec.Cmd, error) { javaCpSeperator = ";" } + var maxRamMiB int + + if opts.RamMiB == 0 { + sysMemMiB := float64(memory.TotalMemory()) / 1024 / 1024 + + // 1GiB for base Minecraft + every dependency takes 25 MiB + maxRamMiB = 1024 + len(i.Lockfile.Dependencies)*25 + + // we take 1/4 of the system memory if that is more + maxRamMiB = int(math.Max(float64(maxRamMiB), sysMemMiB/4)) + // but not more than 85% of the memory + maxRamMiB = int(math.Min(float64(maxRamMiB), sysMemMiB*0.85)) + } else { + maxRamMiB = opts.RamMiB + } + cmdArgs := []string{ "-Xss128M", "-Djava.library.path=" + tmpDir, @@ -258,7 +279,7 @@ func (i *Instance) BuildLaunchCmd(opts *LaunchOptions) (*exec.Cmd, error) { "-Dminecraft.client.jar=" + mcJar, "-cp", strings.Join(cpArgs, javaCpSeperator), - // "-Xmx2G", // TODO: option! + fmt.Sprintf("-Xmx%dM", maxRamMiB), "-XX:+UnlockExperimentalVMOptions", "-XX:+UseG1GC", "-XX:G1NewSizePercent=20", @@ -269,6 +290,10 @@ func (i *Instance) BuildLaunchCmd(opts *LaunchOptions) (*exec.Cmd, error) { launchManifest.MainClass, } + if opts.RamMiB != 0 { + cmdArgs = append([]string{fmt.Sprintf("-Xms%dM", opts.RamMiB)}, cmdArgs...) + } + // HACK: prepend this so macos does not crash if runtime.GOOS == "darwin" { cmdArgs = append([]string{"-XstartOnFirstThread"}, cmdArgs...)