Fix Mod Loader Version not being changed during creation of instance (#781)

* fix: Connect setLoaderVersion to loaderVersionsDropDown

Unconnected method slipped through testing.

Fixes #780

* fix: Prevent race runaway in VanillaPacksTab by filtering action events

The issue is that java swing is not designed for any real concurrency,
 thus we need to filter the action events to only be ones produced by
 the user.

* Update CHANGELOG.md
This commit is contained in:
Doomsdayrs 2023-07-11 00:14:02 -04:00 committed by GitHub
parent 548394bea2
commit 493c9ae723
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 30 deletions

View file

@ -11,6 +11,7 @@ This changelog only contains the changes that are unreleased. For changes for in
- Add missing server_run analytics event - Add missing server_run analytics event
- Run analytics only on version specified in config - Run analytics only on version specified in config
- Importing packs from CurseForge with distribution disabled not prompting to download - Importing packs from CurseForge with distribution disabled not prompting to download
- Fix loader version always being the recommended one in VanillaPacksTab [#781]
### Misc ### Misc
- Upgrade to Gradle 8.2 - Upgrade to Gradle 8.2

View file

@ -26,7 +26,6 @@ import java.awt.FlowLayout;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
import java.util.List; import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.swing.Box; import javax.swing.Box;
@ -63,8 +62,6 @@ import com.atlauncher.utils.ComboItem;
import com.atlauncher.viewmodel.base.IVanillaPacksViewModel; import com.atlauncher.viewmodel.base.IVanillaPacksViewModel;
import com.atlauncher.viewmodel.impl.VanillaPacksViewModel; import com.atlauncher.viewmodel.impl.VanillaPacksViewModel;
import io.reactivex.rxjava3.disposables.Disposable;
public class VanillaPacksTab extends JPanel implements Tab, RelocalizationListener { public class VanillaPacksTab extends JPanel implements Tab, RelocalizationListener {
private final JTextField nameField = new JTextField(32); private final JTextField nameField = new JTextField(32);
private final JTextArea descriptionField = new JTextArea(2, 40); private final JTextArea descriptionField = new JTextArea(2, 40);
@ -79,15 +76,20 @@ public class VanillaPacksTab extends JPanel implements Tab, RelocalizationListen
private final JRadioButton loaderTypeForgeRadioButton = new JRadioButton("Forge"); private final JRadioButton loaderTypeForgeRadioButton = new JRadioButton("Forge");
private final JRadioButton loaderTypeLegacyFabricRadioButton = new JRadioButton("Legacy Fabric"); private final JRadioButton loaderTypeLegacyFabricRadioButton = new JRadioButton("Legacy Fabric");
private final JRadioButton loaderTypeQuiltRadioButton = new JRadioButton("Quilt"); private final JRadioButton loaderTypeQuiltRadioButton = new JRadioButton("Quilt");
private final JComboBox<ComboItem<Optional<LoaderVersion>>> loaderVersionsDropDown = new JComboBox<>(); private final JComboBox<ComboItem<LoaderVersion>> loaderVersionsDropDown = new JComboBox<>();
private final JButton createServerButton = new JButton(getCreateServerText()); private final JButton createServerButton = new JButton(getCreateServerText());
private final JButton createInstanceButton = new JButton(getCreateInstanceText()); private final JButton createInstanceButton = new JButton(getCreateInstanceText());
private final IVanillaPacksViewModel viewModel = new VanillaPacksViewModel(); private final IVanillaPacksViewModel viewModel = new VanillaPacksViewModel();
/**
* Last time the loaderVersion has been changed.
* <p>
* Used to prevent an infinite changes from occuring.
*/
private long loaderVersionLastChange = System.currentTimeMillis();
@Nullable @Nullable
private JTable minecraftVersionTable = null; private JTable minecraftVersionTable = null;
@Nullable @Nullable
private DefaultTableModel minecraftVersionTableModel = null; private DefaultTableModel minecraftVersionTableModel = null;
private Disposable selectionDisposable;
public VanillaPacksTab() { public VanillaPacksTab() {
super(new BorderLayout()); super(new BorderLayout());
@ -250,10 +252,6 @@ public class VanillaPacksTab extends JPanel implements Tab, RelocalizationListen
viewModel.loaderVersionsDropDownEnabled().subscribe(loaderVersionsDropDown::setEnabled); viewModel.loaderVersionsDropDownEnabled().subscribe(loaderVersionsDropDown::setEnabled);
viewModel.loaderVersions().subscribe((loaderVersionsOptional) -> { viewModel.loaderVersions().subscribe((loaderVersionsOptional) -> {
if (selectionDisposable != null) {
selectionDisposable.dispose();
selectionDisposable = null;
}
loaderVersionsDropDown.removeAllItems(); loaderVersionsDropDown.removeAllItems();
if (!loaderVersionsOptional.isPresent()) { if (!loaderVersionsOptional.isPresent()) {
setEmpty(); setEmpty();
@ -279,12 +277,29 @@ public class VanillaPacksTab extends JPanel implements Tab, RelocalizationListen
loaderVersionLength = min(400, loaderVersionLength); loaderVersionLength = min(400, loaderVersionLength);
loaderVersionsDropDown.setPreferredSize(new Dimension(loaderVersionLength, 23)); loaderVersionsDropDown.setPreferredSize(new Dimension(loaderVersionLength, 23));
selectionDisposable = viewModel.selectedLoaderVersion().subscribe((it) -> {
it.ifPresent(loaderVersion -> loaderVersionsDropDown
.setSelectedIndex(loaderVersions.indexOf(loaderVersion)));
});
} }
}); });
viewModel.selectedLoaderVersionIndex().subscribe((index) -> {
if (loaderVersionsDropDown.getItemAt(index) != null) {
loaderVersionLastChange = System.currentTimeMillis();
loaderVersionsDropDown.setSelectedIndex(index);
}
});
loaderVersionsDropDown.addActionListener((e) -> {
// A user cannot change the loader version in under 100 ms. It is physically impossible.
if (e.getWhen() > (loaderVersionLastChange + 100)) {
ComboItem<LoaderVersion> comboItem =
(ComboItem<LoaderVersion>) loaderVersionsDropDown.getSelectedItem();
if (comboItem != null) {
LoaderVersion version = comboItem.getValue();
if (version != null) {
viewModel.setLoaderVersion(version);
}
}
}
});
viewModel.loaderLoading().subscribe((it) -> { viewModel.loaderLoading().subscribe((it) -> {
loaderVersionsDropDown.removeAllItems(); loaderVersionsDropDown.removeAllItems();
if (it) { if (it) {

View file

@ -328,7 +328,7 @@ public interface IVanillaPacksViewModel {
/** /**
* Set the selected loader version * Set the selected loader version
*/ */
void setLoaderVersion(@NotNull String loaderVersion); void setLoaderVersion(@NotNull LoaderVersion loaderVersion);
/** /**
* Is the loader versions drop down enabled * Is the loader versions drop down enabled
@ -346,7 +346,7 @@ public interface IVanillaPacksViewModel {
* The selected mod loader version * The selected mod loader version
*/ */
@NotNull @NotNull
Observable<Optional<LoaderVersion>> selectedLoaderVersion(); Observable<Integer> selectedLoaderVersionIndex();
/** /**
* Is the loader loading. * Is the loader loading.

View file

@ -136,6 +136,26 @@ public class VanillaPacksViewModel implements SettingsListener, IVanillaPacksVie
true); true);
// was lazy // was lazy
public final Boolean showQuiltOption = ConfigManager.getConfigItem("loaders.quilt.enabled", false); public final Boolean showQuiltOption = ConfigManager.getConfigItem("loaders.quilt.enabled", false);
public final Observable<Integer> selectedLoaderVersionIndex = combineLatest(
loaderVersions,
selectedLoaderVersion,
(versionsOptional, selectedOptional) -> {
int index = -1;
if (versionsOptional.isPresent()) {
List<LoaderVersion> versions = versionsOptional.get();
for (int i = 0; i < versions.size(); i++) {
if (Objects.equals(versions.get(i), selectedOptional.orElse(null))) {
index = i;
break;
}
}
}
if (index == -1)
return 0;
return index;
}).subscribeOn(Schedulers.computation());
/** /**
* Filters applied to the version table * Filters applied to the version table
*/ */
@ -428,11 +448,6 @@ public class VanillaPacksViewModel implements SettingsListener, IVanillaPacksVie
return description.observeOn(SwingSchedulers.edt()); return description.observeOn(SwingSchedulers.edt());
} }
@Override
public Observable<Optional<LoaderVersion>> selectedLoaderVersion() {
return selectedLoaderVersion.observeOn(SwingSchedulers.edt());
}
@Override @Override
public Observable<Boolean> loaderLoading() { public Observable<Boolean> loaderLoading() {
return loaderLoading.observeOn(SwingSchedulers.edt()); return loaderLoading.observeOn(SwingSchedulers.edt());
@ -759,17 +774,19 @@ public class VanillaPacksViewModel implements SettingsListener, IVanillaPacksVie
selectedLoaderType.onNext(Optional.ofNullable(loader)); selectedLoaderType.onNext(Optional.ofNullable(loader));
} }
public void setLoaderVersion(String loaderVersion) { public void setLoaderVersion(@Nonnull LoaderVersion loaderVersion) {
Optional<List<LoaderVersion>> versions = loaderVersions.getValue(); Optional<LoaderVersion> currentOptional = selectedLoaderVersion.getValue();
// Do not push two of the same?
if (versions.isPresent()) { if (currentOptional.isPresent()) {
for (LoaderVersion version : versions.get()) { if (currentOptional.get() == loaderVersion)
if (version.version.equals(loaderVersion)) { return;
selectedLoaderVersion.onNext(Optional.of(version));
break;
}
}
} }
selectedLoaderVersion.onNext(Optional.of(loaderVersion));
}
@Override
public Observable<Integer> selectedLoaderVersionIndex() {
return selectedLoaderVersionIndex.observeOn(SwingSchedulers.edt());
} }
public void createServer() { public void createServer() {