Feature/network improvements (#7365)

* Initial commit of network improvements
Seperated server properties into their own file, this will eventually help facilitate a headless server.
Fixed the localhost ip mapping to give the correct IP Address instead of failing and defaulting to "localhost"
Fixed UPnP as well as added some additional options and choices regarding UPnP
Added localization strings to all language files. (Translators will need to translate these, but the current English string is there for easy reference so they dont have to search the en-US file)

* Initial commit of network improvements
Seperated server properties into their own file, this will eventually help facilitate a headless server.
Fixed the localhost ip mapping to give the correct IP Address instead of failing and defaulting to "localhost"
Fixed UPnP as well as added some additional options and choices regarding UPnP
Added localization strings to all language files. (Translators will need to translate these, but the current English string is there for easy reference so they dont have to search the en-US file)

* Fixed properties file reference

* Refactored server address parsing logic to use the Java URI class for improved readability and robustness.
Extracted reusable code into separate functions to enhance modularity and maintainability.
General code cleanup to improve structure and readability.

* Fixed a potential issue if a protocol was already specified in the connection url.

* Removed logger implementation as changing loggers is out of scope for this PR
Reverted to JUPnP as its implementation is fixed in #7367
Made some of the new localization strings generic as they can be used elsewhere
Added a server.preferences.example file
removed the server port from the old location (forge.progile.properties.example)
Added a server port back into ForgeConstants as it doesnt make sense for the prefered hosting port of the user to override the default Forge connection port.

* resolve conflicts between this branch and master

* Implemented a parent class for all preference Enums so they can be passed into a function regardless of type using IPref, necessary since I separated server settings into its own FNetPref file
Added server preferences section to the preferences Desktop GUI
Added a port preference setting and a UPnP preference setting to the aforementioned server preferences section
Added a localizedComboBox and localizedComboBoxListener so that localized strings can be used in combobox dropdowns in the server preferences section.

TODO: (In scope)
The new server preferences section needs to be added to Android and IOS perhaps?

TODO: (out of scope)
GamePlayerUtil has a bunch on non localized english strings that should be converted to localized

* Fixed unused import

* Resolved merge conflicts
Added server settings to the reset to defaults function
This commit is contained in:
matthias8422
2025-04-15 17:32:32 -07:00
committed by GitHub
parent e7becacd57
commit 366ed643a7
26 changed files with 557 additions and 95 deletions

View File

@@ -13,8 +13,10 @@ import forge.gui.UiCommand;
import forge.gui.framework.FScreen;
import forge.gui.framework.ICDoc;
import forge.localinstance.properties.ForgeConstants;
import forge.localinstance.properties.ForgeNetPreferences;
import forge.localinstance.properties.ForgePreferences;
import forge.localinstance.properties.ForgePreferences.FPref;
import forge.localinstance.properties.PreferencesStore;
import forge.model.FModel;
import forge.player.GamePlayerUtil;
import forge.screens.deckeditor.CDeckEditorUI;
@@ -35,6 +37,7 @@ import java.awt.event.ItemEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Controls the preferences submenu in the home UI.
@@ -50,6 +53,7 @@ public enum CSubmenuPreferences implements ICDoc {
private VSubmenuPreferences view;
private ForgePreferences prefs;
private ForgeNetPreferences netPrefs;
private boolean updating;
private final List<Pair<JCheckBox, FPref>> lstControls = new ArrayList<>();
@@ -67,6 +71,7 @@ public enum CSubmenuPreferences implements ICDoc {
this.view = VSubmenuPreferences.SINGLETON_INSTANCE;
this.prefs = FModel.getPreferences();
this.netPrefs = FModel.getNetPreferences();
// This updates variable right now and is not standard
view.getCbDevMode().addItemListener(arg0 -> {
@@ -206,6 +211,7 @@ public enum CSubmenuPreferences implements ICDoc {
initializeCardArtFormatComboBox();
initializeCardArtPreference();
initializeAutoUpdaterComboBox();
initializeServerUPnPComboBox();
initializeMulliganRuleComboBox();
initializeAiProfilesComboBox();
initializeAiSideboardingModeComboBox();
@@ -221,6 +227,7 @@ public enum CSubmenuPreferences implements ICDoc {
initializeCounterDisplayLocationComboBox();
initializeGraveyardOrderingComboBox();
initializePlayerNameButton();
initializeServerPortButton();
initializeDefaultLanguageComboBox();
disableLazyLoading();
@@ -256,7 +263,9 @@ public enum CSubmenuPreferences implements ICDoc {
if (FOptionPane.showConfirmDialog(userPrompt, localizer.getMessage("TresetForgeSettingsToDefault"))) {
final ForgePreferences prefs = FModel.getPreferences();
prefs.reset();
netPrefs.reset();
prefs.save();
netPrefs.save();
update();
Singletons.getControl().restartForge();
}
@@ -371,6 +380,31 @@ public enum CSubmenuPreferences implements ICDoc {
panel.setComboBox(comboBox, selectedItem);
}
private void initializeServerUPnPComboBox() {
// Step 1: Define the localized strings and mappings
final Map<String, String> upnpPreferenceMapping = ForgeConstants.getUPnPPreferenceMapping();
final String[] localizedOptions = upnpPreferenceMapping.keySet().toArray(new String[0]); // Localized strings
// Step 2: Get the preference key
final ForgeNetPreferences.FNetPref uPnPPreference = ForgeNetPreferences.FNetPref.UPnP;
// Step 3: Create the combo box with localized strings
final FComboBoxPanel<String> panel = this.view.getCbpServerUPnPOption();
final FComboBox<String> comboBox = createLocalizedComboBox(localizedOptions, uPnPPreference, upnpPreferenceMapping);
// Step 4: Pre-select the localized value based on the saved internal value
final String savedInternalValue = this.netPrefs.getPref(uPnPPreference);
final String selectedLocalizedValue = upnpPreferenceMapping.entrySet()
.stream()
.filter(entry -> entry.getValue().equals(savedInternalValue))
.map(Map.Entry::getKey)
.findFirst()
.orElse(localizer.getMessage("lblAsk")); // Default value
panel.setComboBox(comboBox, selectedLocalizedValue);
}
private void initializeMulliganRuleComboBox() {
final String [] choices = MulliganDefs.getMulliganRuleNames();
final FPref userSetting = FPref.MULLIGAN_RULE;
@@ -578,20 +612,74 @@ public enum CSubmenuPreferences implements ICDoc {
}
private <E> FComboBox<E> createComboBox(final E[] items, final ForgePreferences.FPref setting) {
private <E> FComboBox<E> createComboBox(final E[] items, final PreferencesStore.IPref setting) {
final FComboBox<E> comboBox = new FComboBox<>(items);
addComboBoxListener(comboBox, setting);
return comboBox;
}
private <E> void addComboBoxListener(final FComboBox<E> comboBox, final ForgePreferences.FPref setting) {
private <E> FComboBox<E> createLocalizedComboBox(
final E[] localizedItems,
final PreferencesStore.IPref setting,
final Map<E, String> mapping) {
//Step 1: Create the combo box
final FComboBox<E> comboBox = new FComboBox<>(localizedItems);
//Step 2: Add a listener using the localized to internal mappings to save internal values based on localized selection
addLocalizedComboBoxListener(comboBox, setting, mapping);
return comboBox;
}
private <E> void addComboBoxListener(final FComboBox<E> comboBox, final PreferencesStore.IPref setting) {
comboBox.addItemListener(e -> {
final E selectedType = comboBox.getSelectedItem();
CSubmenuPreferences.this.prefs.setPref(setting, selectedType.toString());
if (setting instanceof ForgePreferences.FPref) {
// Cast setting to ForgePreferences.FPref
CSubmenuPreferences.this.prefs.setPref((ForgePreferences.FPref) setting, selectedType.toString());
} else if (setting instanceof ForgeNetPreferences.FNetPref) {
// Cast setting to ForgeNetPreferences.FNetPref
CSubmenuPreferences.this.netPrefs.setPref((ForgeNetPreferences.FNetPref) setting, selectedType.toString());
}
CSubmenuPreferences.this.prefs.save();
});
}
private <E> void addLocalizedComboBoxListener(
final FComboBox<E> comboBox,
final PreferencesStore.IPref setting,
final Map<E, String> mapping) {
comboBox.addItemListener(e -> {
if (e.getStateChange() == ItemEvent.SELECTED) {
final E selectedLocalized = comboBox.getSelectedItem(); // Localized string
final String internalValue = mapping.get(selectedLocalized); // Map localized string to internal value
// Save the mapped internal value to the correct preferences
if (setting instanceof ForgePreferences.FPref) {
CSubmenuPreferences.this.prefs.setPref((ForgePreferences.FPref) setting, internalValue);
CSubmenuPreferences.this.prefs.save();
} else if (setting instanceof ForgeNetPreferences.FNetPref) {
CSubmenuPreferences.this.netPrefs.setPref((ForgeNetPreferences.FNetPref) setting, internalValue);
CSubmenuPreferences.this.netPrefs.save();
}
}
});
}
private void initializeServerPortButton() {
final FLabel btn = view.getBtnServerPort();
setServerPortButtonText();
btn.setCommand(getServerPortButtonCommand());
}
private void setServerPortButtonText() {
final FLabel btn = view.getBtnServerPort();
final int port = netPrefs.getPrefInt(ForgeNetPreferences.FNetPref.NET_PORT);
btn.setText(Integer.toString(port));
}
private void initializePlayerNameButton() {
final FLabel btn = view.getBtnPlayerName();
setPlayerNameButtonText();
@@ -617,4 +705,11 @@ public enum CSubmenuPreferences implements ICDoc {
setPlayerNameButtonText();
};
}
private UiCommand getServerPortButtonCommand() {
return () -> {
GamePlayerUtil.setServerPort();
setServerPortButtonText();
};
}
}

View File

@@ -60,6 +60,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final FLabel btnTokenPreviewer = new FLabel.Builder().opaque(true).hoverable(true).text(localizer.getMessage("btnTokenPreviewer")).build();
private final FLabel btnPlayerName = new FLabel.Builder().opaque(true).hoverable(true).text("").build();
private final FLabel btnServerPort = new FLabel.Builder().opaque(true).hoverable(true).text("").build();
private final JCheckBox cbRemoveSmall = new OptionsCheckBox(localizer.getMessage("cbRemoveSmall"));
private final JCheckBox cbCardBased = new OptionsCheckBox(localizer.getMessage("cbCardBased"));
@@ -146,6 +147,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final FComboBoxPanel<String> cbpDefaultLanguage = new FComboBoxPanel<>(localizer.getMessage("cbpSelectLanguage")+":");
private final FComboBoxPanel<String> cbpAutoUpdater = new FComboBoxPanel<>(localizer.getMessage("cbpAutoUpdater")+":");
private final FComboBoxPanel<String> cbpSwitchStates = new FComboBoxPanel<>(localizer.getMessage("cbpSwitchStates")+":");
private final FComboBoxPanel<String> cbpServerUPnPOption = new FComboBoxPanel<>(localizer.getMessage("cbpServerUPnPOption")+":");
/**
* Constructor.
@@ -281,6 +283,15 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(cbpAutoYieldMode, comboBoxConstraints);
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlpAutoYieldMode")), descriptionConstraints);
//Server Preferences
pnlPrefs.add(new SectionLabel(localizer.getMessage("ServerPreferences")), sectionConstraints);
pnlPrefs.add(cbpServerUPnPOption, comboBoxConstraints);
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlServerUPnPOptions")), descriptionConstraints);
pnlPrefs.add(getServerPortPanel(), titleConstraints + ", h 26px!");
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlServerPort")), descriptionConstraints);
// Deck building options
pnlPrefs.add(new SectionLabel(localizer.getMessage("RandomDeckGeneration")), sectionConstraints);
@@ -619,6 +630,17 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
}
}
//Server Preference Panel Components
//###################################################################
public final FComboBoxPanel<String> getCbpServerUPnPOption() {
return cbpServerUPnPOption;
}
public FLabel getBtnServerPort() {
return btnServerPort;
}
//###################################################################
public final FComboBoxPanel<String> getCbpAutoUpdater() {
return cbpAutoUpdater;
}
@@ -1053,4 +1075,13 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
p.add(btnPlayerName, "aligny top, h 100%, w 200px!");
return p;
}
private JPanel getServerPortPanel() {
JPanel p = new JPanel(new MigLayout("insets 0, gap 0!"));
p.setOpaque(false);
FLabel lbl = new FLabel.Builder().text(localizer.getMessage("lblServerPort") +": ").fontSize(12).fontStyle(Font.BOLD).build();
p.add(lbl, "aligny top, h 100%, gap 4px 0 0 0");
p.add(btnServerPort, "aligny top, h 100%, w 200px!");
return p;
}
}