mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
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:
@@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,3 @@ decksDir=
|
||||
# The default value (for all plaforms) is:
|
||||
# <the decksDir defined above>/constructed/
|
||||
decksConstructedDir=
|
||||
|
||||
# Forge server port. Values under 1024 won't work on Mac OSX or on the various
|
||||
# *nixes.
|
||||
serverPort=
|
||||
|
||||
@@ -53,7 +53,9 @@ btnClearImageCache=Leere Bildspeicher
|
||||
btnTokenPreviewer=Spielstein-Vorschau
|
||||
btnCopyToClipboard=In Zwischenablage kopieren
|
||||
cbpAutoUpdater=Auto-Updater
|
||||
cbpServerUPnPOption=Server UPnP
|
||||
nlAutoUpdater=Wähle aus welcher Quelle Forge aktualisiert wird
|
||||
nlServerUPnPOptions=Determines if Forge should use UPnP to attempt to automatically open the server port when hosting.
|
||||
cbpSelectLanguage=Sprache
|
||||
nlSelectLanguage=Wähle Sprache (Ist noch in Arbeit und nur teilweise umgesetzt.) (Neustart ist erforderlich.)
|
||||
cbRemoveSmall=Entferne kleine Kreaturen
|
||||
@@ -141,6 +143,9 @@ latestArtOpt=Neueste Version
|
||||
originalArtOpt=Originalbild
|
||||
Troubleshooting=Fehlerbehebung
|
||||
GeneralConfiguration=Allgemeine Einstellungen
|
||||
ServerPreferences=Server Preferences
|
||||
lblServerPort=Server Port
|
||||
nlServerPort=Sets the port number that Forge will host a server on.
|
||||
lblPlayerName=Spielername
|
||||
nlPlayerName=Name unter welchem du beim Spielen geführt wirst.
|
||||
nlCompactMainMenu=Aktiviere, um im Seitenmenü platzsparend immer nur eine Menügruppe anzeigen zu lassen. (Erfordert Neustart)
|
||||
@@ -322,7 +327,11 @@ lblRemove=Entferne
|
||||
ttlblAvatar=L-Klick: Wähle Avatar. R-Klick: Zufälliger Avatar.
|
||||
lblReady=Fertig
|
||||
lblKick=Rauswerfen
|
||||
lblReallyKick=%s wirklich rauswerfen?
|
||||
lblReallyKick=%s wirklich rauswerfen?\
|
||||
#GamePlayerUtil.java
|
||||
sOPServerPromptMessage=Please enter a preferred hosting port
|
||||
sOPServerPromptTitle =Server Hosting Port
|
||||
sOPServerPromptError=Invalid port number: {0} \n Port number needs to be a number between 1 and 65535
|
||||
#ForgeMenu.java
|
||||
lblRestart=Neustart
|
||||
lblExit=Beenden
|
||||
@@ -2940,6 +2949,15 @@ lblForgeUnableDetermineYourExternalIP=Forge konnte dein externe IP nicht ermitte
|
||||
lblServerURL=Server-URL
|
||||
lblYourConnectionToHostWasInterrupted=Deine Verbindung mit dem Host ({0}) wurde unterbrochen.
|
||||
lblConnectedIPPort=Verbunden mit {0}:{1}
|
||||
#FServerManager.java
|
||||
lblUPnPTitle=UPnP option
|
||||
lblUPnPQuestion=Attempt to open port {0} automatically?
|
||||
lblUPnPFailed=UPnP failed to open port {0}. You will need to manually create a port forward for external clients to connect.
|
||||
lblAlways=Always
|
||||
lblNotNow=Not Now
|
||||
lblNever=Never
|
||||
lblAsk=Ask
|
||||
lblJustOnce=Just Once
|
||||
#GameLobby.java
|
||||
lblRequiredLeastTwoPlayerStartGame=Es braucht mindestens zwei Spieler für ein Spiel.
|
||||
lblNotEnoughTeams=Nicht genug Teams! Bitte Teamzuordung anpassen.
|
||||
|
||||
@@ -53,7 +53,9 @@ btnClearImageCache=Clear Image Cache
|
||||
btnTokenPreviewer=Token Previewer
|
||||
btnCopyToClipboard=Copy to Clipboard
|
||||
cbpAutoUpdater=Auto updater
|
||||
cbpServerUPnPOption=Server UPnP
|
||||
nlAutoUpdater=Select the release channel to use for updating Forge
|
||||
nlServerUPnPOptions=Determines if Forge should use UPnP to attempt to automatically open the server port when hosting.
|
||||
cbpSelectLanguage=Language
|
||||
nlSelectLanguage=Select Language (Excluded Game part. Still a work in progress) (REQUIRES RESTART)
|
||||
cbRemoveSmall=Remove Small Creatures
|
||||
@@ -142,6 +144,9 @@ latestArtOpt=Latest Art
|
||||
originalArtOpt=Original Art
|
||||
Troubleshooting=Troubleshooting
|
||||
GeneralConfiguration=General Configuration
|
||||
ServerPreferences=Server Preferences
|
||||
lblServerPort=Server Port
|
||||
nlServerPort=Sets the port number that Forge will host a server on.
|
||||
lblPlayerName=Player Name
|
||||
nlPlayerName=Sets the name that you will be referred to by Forge during gameplay.
|
||||
nlCompactMainMenu=Enable for a space efficient sidebar that displays only one menu group at a time (REQUIRES RESTART).
|
||||
@@ -325,6 +330,10 @@ ttlblAvatar=L-click: Select avatar. R-click: Randomize avatar.
|
||||
lblReady=Ready
|
||||
lblKick=Kick
|
||||
lblReallyKick=Really Kick %s?
|
||||
#GamePlayerUtil.java
|
||||
sOPServerPromptMessage=Please enter a preferred hosting port
|
||||
sOPServerPromptTitle =Server Hosting Port
|
||||
sOPServerPromptError=Invalid port number: {0} \n Port number needs to be a number between 1 and 65535
|
||||
#ForgeMenu.java
|
||||
lblRestart=Restart
|
||||
lblExit=Exit
|
||||
@@ -2985,6 +2994,15 @@ lblForgeUnableDetermineYourExternalIP=Forge was unable to determine your externa
|
||||
lblServerURL=Server URL
|
||||
lblYourConnectionToHostWasInterrupted=Your connection to the host ({0}) was interrupted.
|
||||
lblConnectedIPPort=Connected to {0}:{1}
|
||||
#FServerManager.java
|
||||
lblUPnPTitle=UPnP option
|
||||
lblUPnPQuestion=Attempt to open port {0} automatically?
|
||||
lblUPnPFailed=UPnP failed to open port {0}. You will need to manually create a port forward for external clients to connect.
|
||||
lblAlways=Always
|
||||
lblNotNow=Not Now
|
||||
lblNever=Never
|
||||
lblAsk=Ask
|
||||
lblJustOnce=Just Once
|
||||
#GameLobby.java
|
||||
lblRequiredLeastTwoPlayerStartGame=At least two players are required to start a game.
|
||||
lblNotEnoughTeams=There are not enough teams! Please adjust team allocations.
|
||||
|
||||
@@ -53,7 +53,9 @@ btnClearImageCache=Limpiar caché de imágenes
|
||||
btnTokenPreviewer=Previsualizador de fichas (tokens)
|
||||
btnCopyToClipboard=Copiar al portapapeles
|
||||
cbpAutoUpdater=Actualizar Forge
|
||||
cbpServerUPnPOption=Server UPnP
|
||||
nlAutoUpdater=Selecciona la versión a utilizar para actualizar Forge
|
||||
nlServerUPnPOptions=Determines if Forge should use UPnP to attempt to automatically open the server port when hosting.
|
||||
cbpSelectLanguage=Idioma
|
||||
nlSelectLanguage=Seleccionar idioma (excepto textos en partida). Todavía un trabajo en progreso (Es necesario reiniciar Forge)
|
||||
cbRemoveSmall=Eliminar criaturas pequeñas
|
||||
@@ -142,6 +144,9 @@ latestArtOpt=Ilustración más reciente
|
||||
originalArtOpt=Ilustración original
|
||||
Troubleshooting=Solución de problemas
|
||||
GeneralConfiguration=Configuración general
|
||||
ServerPreferences=Server Preferences
|
||||
lblServerPort=Server Port
|
||||
nlServerPort=Sets the port number that Forge will host a server on.
|
||||
lblPlayerName=Nombre Jugador
|
||||
nlPlayerName=Establece el nombre al que te referirá Forge durante el juego.
|
||||
nlCompactMainMenu=Habilitar para una barra lateral eficiente en espacio que muestre solo un grupo de menús a la vez (REQUIERE REINICIAR).
|
||||
@@ -325,6 +330,10 @@ ttlblAvatar=Click izdo: Seleccionar avatar. Click dcho: aleatorizar avatar.
|
||||
lblReady=Listo
|
||||
lblKick=Quitar
|
||||
lblReallyKick=¿Quitar a %s?
|
||||
#GamePlayerUtil.java
|
||||
sOPServerPromptMessage=Please enter a preferred hosting port
|
||||
sOPServerPromptTitle =Server Hosting Port
|
||||
sOPServerPromptError=Invalid port number: {0} \n Port number needs to be a number between 1 and 65535
|
||||
#ForgeMenu.java
|
||||
lblRestart=Reiniciar
|
||||
lblExit=Salir
|
||||
@@ -2954,6 +2963,15 @@ lblForgeUnableDetermineYourExternalIP=¡Forge no pudo determinar su IP externa!\
|
||||
lblServerURL=URL del servidor
|
||||
lblYourConnectionToHostWasInterrupted=Tu conexión con el host ({0}) fue interrumpida.
|
||||
lblConnectedIPPort=Conectado a {0}: {1}
|
||||
#FServerManager.java
|
||||
lblUPnPTitle=UPnP option
|
||||
lblUPnPQuestion=Attempt to open port {0} automatically?
|
||||
lblUPnPFailed=UPnP failed to open port {0}. You will need to manually create a port forward for external clients to connect.
|
||||
lblAlways=Always
|
||||
lblNotNow=Not Now
|
||||
lblNever=Never
|
||||
lblAsk=Ask
|
||||
lblJustOnce=Just Once
|
||||
#GameLobby.java
|
||||
lblRequiredLeastTwoPlayerStartGame=Se requieren al menos dos jugadores para comenzar un juego.
|
||||
lblNotEnoughTeams=¡No hay suficientes equipos! Por favor, ajusta las asignaciones del equipo.
|
||||
|
||||
@@ -53,7 +53,9 @@ btnClearImageCache=Effacer le cache des images
|
||||
btnTokenPreviewer=Aperçu des jetons
|
||||
btnCopyToClipboard=Copier dans le presse-papiers
|
||||
cbpAutoUpdater=Mise à jour automatique
|
||||
cbpServerUPnPOption=Server UPnP
|
||||
nlAutoUpdater=Sélectionnez le canal de publication à utiliser pour mettre à jour Forge
|
||||
nlServerUPnPOptions=Determines if Forge should use UPnP to attempt to automatically open the server port when hosting.
|
||||
cbpSelectLanguage=Langue
|
||||
nlSelectLanguage=Sélectionner la langue (partie du jeu exclue. Encore un travail en cours) (NÉCESSITE UN REDÉMARRAGE)
|
||||
cbRemoveSmall=Supprimer les petites créatures
|
||||
@@ -141,6 +143,9 @@ latestArtOpt=Dernier art
|
||||
originalArtOpt=Art original
|
||||
Troubleshooting=Dépannage
|
||||
GeneralConfiguration=Configuration générale
|
||||
ServerPreferences=Server Preferences
|
||||
lblServerPort=Server Port
|
||||
nlServerPort=Sets the port number that Forge will host a server on.
|
||||
lblPlayerName=Nom du joueur
|
||||
nlPlayerName=Définit le nom auquel vous serez référé par Forge pendant le jeu.
|
||||
nlCompactMainMenu=Activer pour une barre latérale peu encombrante qui affiche un seul groupe de menus à la fois (NÉCESSITE UN REDÉMARRAGE).
|
||||
@@ -323,6 +328,10 @@ ttlblAvatar=L-clic : sélectionnez l'avatar. R-clic : randomiser l'avatar.
|
||||
lblReady=Prêt
|
||||
lblKick=Coup de pied
|
||||
lblReallyKick=Vraiment botter %s ?
|
||||
#GamePlayerUtil.java
|
||||
sOPServerPromptMessage=Please enter a preferred hosting port
|
||||
sOPServerPromptTitle =Server Hosting Port
|
||||
sOPServerPromptError=Invalid port number: {0} \n Port number needs to be a number between 1 and 65535
|
||||
#ForgeMenu.java
|
||||
lblRestart=Redémarrer
|
||||
lblExit=Quitter
|
||||
@@ -2948,6 +2957,15 @@ lblForgeUnableDetermineYourExternalIP=Forge n'a pas pu déterminer votre adresse
|
||||
lblServerURL=URL du serveur
|
||||
lblYourConnectionToHostWasInterrupted=Votre connexion à l'hôte ({0}) a été interrompue.
|
||||
lblConnectedIPPort=Connecté à {0} :{1}
|
||||
#FServerManager.java
|
||||
lblUPnPTitle=UPnP option
|
||||
lblUPnPQuestion=Attempt to open port {0} automatically?
|
||||
lblUPnPFailed=UPnP failed to open port {0}. You will need to manually create a port forward for external clients to connect.
|
||||
lblAlways=Always
|
||||
lblNotNow=Not Now
|
||||
lblNever=Never
|
||||
lblAsk=Ask
|
||||
lblJustOnce=Just Once
|
||||
#GameLobby.java
|
||||
lblRequiredLeastTwoPlayerStartGame=Au moins deux joueurs sont requis pour démarrer une partie.
|
||||
lblNotEnoughTeams=Il n'y a pas assez d'équipes ! Veuillez ajuster les allocations d'équipe.
|
||||
|
||||
@@ -52,7 +52,9 @@ btnClearImageCache=Cancella cache immagini
|
||||
btnTokenPreviewer=Visualizzatore di pedine
|
||||
btnCopyToClipboard=Copia negli appunti
|
||||
cbpAutoUpdater=Auto updater
|
||||
cbpServerUPnPOption=Server UPnP
|
||||
nlAutoUpdater=Seleziona il canale di distribuzione da usare per aggiornare Forge
|
||||
nlServerUPnPOptions=Determines if Forge should use UPnP to attempt to automatically open the server port when hosting.
|
||||
cbpSelectLanguage=Lingua
|
||||
nlSelectLanguage=Seleziona la lingua (parte di gioco esclusa. Ancora in fase di sviluppo) (RIAVVIO NECESSARIO)
|
||||
cbRemoveSmall=Rimuovi le creature piccole
|
||||
@@ -140,6 +142,9 @@ latestArtOpt=Illustrazione più recente
|
||||
originalArtOpt=Illustrazione originale
|
||||
Troubleshooting=Risoluzione dei problemi
|
||||
GeneralConfiguration=Configurazione generale
|
||||
ServerPreferences=Server Preferences
|
||||
lblServerPort=Server Port
|
||||
nlServerPort=Sets the port number that Forge will host a server on.
|
||||
lblPlayerName=Nome del giocatore
|
||||
nlPlayerName=Imposta il nome che userai in Forge durante il gioco.
|
||||
nlCompactMainMenu=Abilitare per una barra laterale efficiente in termini di spazio che visualizza solo un gruppo di menu alla volta (RIAVVIO RICHIESTO).
|
||||
@@ -322,6 +327,10 @@ ttlblAvatar=L-clic: seleziona avatar. R-clic: avatar casuale.
|
||||
lblReady=Pronto
|
||||
lblKick=Scaccia
|
||||
lblReallyKick=Vuoi davvero scacciare %s?
|
||||
#GamePlayerUtil.java
|
||||
sOPServerPromptMessage=Please enter a preferred hosting port
|
||||
sOPServerPromptTitle =Server Hosting Port
|
||||
sOPServerPromptError=Invalid port number: {0} \n Port number needs to be a number between 1 and 65535
|
||||
#ForgeMenu.java
|
||||
lblRestart=Ricomincia
|
||||
lblExit=Esci
|
||||
@@ -2946,6 +2955,15 @@ lblForgeUnableDetermineYourExternalIP=Forge non è riuscito a determinare il tuo
|
||||
lblServerURL=URL del server
|
||||
lblYourConnectionToHostWasInterrupted=La tua connessione all'host ({0}) si è interrotta.
|
||||
lblConnectedIPPort=Connesso a {0}:{1}
|
||||
#FServerManager.java
|
||||
lblUPnPTitle=UPnP option
|
||||
lblUPnPQuestion=Attempt to open port {0} automatically?
|
||||
lblUPnPFailed=UPnP failed to open port {0}. You will need to manually create a port forward for external clients to connect.
|
||||
lblAlways=Always
|
||||
lblNotNow=Not Now
|
||||
lblNever=Never
|
||||
lblAsk=Ask
|
||||
lblJustOnce=Just Once
|
||||
#GameLobby.java
|
||||
lblRequiredLeastTwoPlayerStartGame=Sono richiesti almeno due giocatori per iniziare una partita.
|
||||
lblNotEnoughTeams=Non ci sono abbastanza squadre! Correggi la ripartizione delle squadre.
|
||||
|
||||
@@ -53,7 +53,9 @@ btnClearImageCache=画像キャッシュのクリア
|
||||
btnTokenPreviewer=トークンを見る
|
||||
btnCopyToClipboard=クリップボードにコピー
|
||||
cbpAutoUpdater=自動アップデート
|
||||
cbpServerUPnPOptions=Server UPnP
|
||||
nlAutoUpdater=Forge を更新する時に使用するリリースチャネルを選択
|
||||
nlServerUPnPOptions=Determines if Forge should use UPnP to attempt to automatically open the server port when hosting.
|
||||
cbpSelectLanguage=言語
|
||||
nlSelectLanguage=言語の選択(対戦画面はまだ開発中)(再起動が必要)
|
||||
cbRemoveSmall=小さなクリーチャーを除外
|
||||
@@ -141,6 +143,9 @@ latestArtOpt=最新のアート
|
||||
originalArtOpt=オリジナルアート
|
||||
Troubleshooting=トラブルシューティング
|
||||
GeneralConfiguration=一般設定
|
||||
ServerPreferences=Server Preferences
|
||||
lblServerPort=Server Port
|
||||
nlServerPort=Sets the port number that Forge will host a server on.
|
||||
lblPlayerName=プレイヤー名
|
||||
nlPlayerName=ゲームプレイ中に Forge が参照する名前を設定します。
|
||||
nlCompactMainMenu=サイドバーに同時に一つのメニューグループだけを表示し、省スペースモードを有効にします。(再起動が必要)
|
||||
@@ -323,6 +328,10 @@ ttlblAvatar=左クリック:アバターを選択します。 右クリック
|
||||
lblReady=準備完了
|
||||
lblKick=キック
|
||||
lblReallyKick=本当に%sをキックしますか?
|
||||
#GamePlayerUtil.java
|
||||
sOPServerPromptMessage=Please enter a preferred hosting port
|
||||
sOPServerPromptTitle =Server Hosting Port
|
||||
sOPServerPromptError=Invalid port number: {0} \n Port number needs to be a number between 1 and 65535
|
||||
#ForgeMenu.java
|
||||
lblRestart=リスタート
|
||||
lblExit=終了
|
||||
@@ -2942,6 +2951,15 @@ lblForgeUnableDetermineYourExternalIP=Forge があなたの外部 IP を決め
|
||||
lblServerURL=サーバー URL
|
||||
lblYourConnectionToHostWasInterrupted=ホスト({0})へのコネクションが中断されました。
|
||||
lblConnectedIPPort={0}:{1}に繋ぎました
|
||||
#FServerManager.java
|
||||
lblUPnPTitle=UPnP option
|
||||
lblUPnPQuestion=Attempt to open port {0} automatically?
|
||||
lblUPnPFailed=UPnP failed to open port {0}. You will need to manually create a port forward for external clients to connect.
|
||||
lblAlways=Always
|
||||
lblNotNow=Not Now
|
||||
lblNever=Never
|
||||
lblAsk=Ask
|
||||
lblJustOnce=Just Once
|
||||
#GameLobby.java
|
||||
lblRequiredLeastTwoPlayerStartGame=少なくとも二人以上のプレイヤーがないとゲームを始められません。
|
||||
lblNotEnoughTeams=チーム数が足りない!チームの配分を調整してください。
|
||||
|
||||
@@ -54,7 +54,9 @@ btnClearImageCache=Limpar Cache de Imagens
|
||||
btnTokenPreviewer=Pré-visualizador de Ficha
|
||||
btnCopyToClipboard=Copiar para Área de Transferência
|
||||
cbpAutoUpdater=Atualização automática
|
||||
cbpServerUPnPOption=Server UPnP
|
||||
nlAutoUpdater=Selecione o canal de lançamento para atualizar o Forge
|
||||
nlServerUPnPOptions=Determines if Forge should use UPnP to attempt to automatically open the server port when hosting.
|
||||
cbpSelectLanguage=Idioma
|
||||
nlSelectLanguage=Selecionar Idioma (Exceto no Jogo. Tradução em andamento) (É NECESSÁRIO REINICIAR)
|
||||
cbRemoveSmall=Remover Criaturas Pequenas
|
||||
@@ -142,6 +144,9 @@ latestArtOpt=Arte mais recente
|
||||
originalArtOpt=Arte Original
|
||||
Troubleshooting=Solução de Problemas
|
||||
GeneralConfiguration=Configuração Geral
|
||||
ServerPreferences=Server Preferences
|
||||
lblServerPort=Server Port
|
||||
nlServerPort=Sets the port number that Forge will host a server on.
|
||||
lblPlayerName=Nome do Jogador
|
||||
nlPlayerName=Defina o seu nome que será utilizado pelo Forge durante o jogo.
|
||||
nlCompactMainMenu=Ative para uma barra lateral eficiente de espaço que exibe apenas um grupo de menu de cada vez (REQUER REINÍCIO).
|
||||
@@ -335,6 +340,10 @@ ttlblAvatar=Click esquerdo\: Selecionar avatar. Click direito\: Avatar aleatóri
|
||||
lblReady=Pronto
|
||||
lblKick=Expulsar
|
||||
lblReallyKick=Quer mesmo expulsar %s?
|
||||
#GamePlayerUtil.java
|
||||
sOPServerPromptMessage=Please enter a preferred hosting port
|
||||
sOPServerPromptTitle =Server Hosting Port
|
||||
sOPServerPromptError=Invalid port number: {0} \n Port number needs to be a number between 1 and 65535
|
||||
#ForgeMenu.java
|
||||
lblRestart=Reiniciar
|
||||
lblExit=Sair
|
||||
@@ -3029,6 +3038,15 @@ lblForgeUnableDetermineYourExternalIP=O Forge não pôde determinar seu IP exter
|
||||
lblServerURL=URL do Servidor
|
||||
lblYourConnectionToHostWasInterrupted=Sua conexão com o host ({0}) foi interrompida.
|
||||
lblConnectedIPPort=Conectado em {0}\:{1}
|
||||
#FServerManager.java
|
||||
lblUPnPTitle=UPnP option
|
||||
lblUPnPQuestion=Attempt to open port {0} automatically?
|
||||
lblUPnPFailed=UPnP failed to open port {0}. You will need to manually create a port forward for external clients to connect.
|
||||
lblAlways=Always
|
||||
lblNotNow=Not Now
|
||||
lblNever=Never
|
||||
lblAsk=Ask
|
||||
lblJustOnce=Just Once
|
||||
#GameLobby.java
|
||||
lblRequiredLeastTwoPlayerStartGame=Ao menos dois jogadores são requeridos em um jogo.
|
||||
lblNotEnoughTeams=Não há equipes suficientes\! Ajuste a alocação da equipe.
|
||||
|
||||
@@ -54,7 +54,9 @@ btnTokenPreviewer=衍生物预览器
|
||||
btnCopyToClipboard=复制到剪切板
|
||||
cbpSelectLanguage=语言
|
||||
cbpAutoUpdater=自动更新
|
||||
cbpServerUPnPOption=Server UPnP
|
||||
nlAutoUpdater=选择用于更新Forge的发布渠道
|
||||
nlServerUPnPOptions=Determines if Forge should use UPnP to attempt to automatically open the server port when hosting.
|
||||
nlSelectLanguage=选择语言(除了正在进行中的游戏)(需要重新启动)
|
||||
cbRemoveSmall=删除小生物
|
||||
cbCardBased=包括基于单卡生成的套牌
|
||||
@@ -142,6 +144,9 @@ latestArtOpt=最新艺术
|
||||
originalArtOpt=原创艺术
|
||||
Troubleshooting=故障排除
|
||||
GeneralConfiguration=常规配置
|
||||
ServerPreferences=Server Preferences
|
||||
lblServerPort=Server Port
|
||||
nlServerPort=Sets the port number that Forge will host a server on.
|
||||
lblPlayerName=玩家名称
|
||||
nlPlayerName=设置游戏中Forge将引用的名称
|
||||
nlCompactMainMenu=启用节省空间的侧边栏,一次只显示一个菜单组(需要重新启动)。
|
||||
@@ -325,6 +330,10 @@ ttlblAvatar=左击:选择头像,右击:随机头像
|
||||
lblReady=准备好
|
||||
lblKick=踢
|
||||
lblReallyKick=准备好踢 %s?
|
||||
#GamePlayerUtil.java
|
||||
sOPServerPromptMessage=Please enter a preferred hosting port
|
||||
sOPServerPromptTitle =Server Hosting Port
|
||||
sOPServerPromptError=Invalid port number: {0} \n Port number needs to be a number between 1 and 65535
|
||||
#ForgeMenu.java
|
||||
lblRestart=重启
|
||||
lblExit=退出
|
||||
@@ -2932,6 +2941,15 @@ lblForgeUnableDetermineYourExternalIP=Forge无法确定你的公网IP!\n\n{0}
|
||||
lblServerURL=服务器网址
|
||||
lblYourConnectionToHostWasInterrupted=你与主机的连接断开了({0})。
|
||||
lblConnectedIPPort=连接到{0}:{1}
|
||||
#FServerManager.java
|
||||
lblUPnPTitle=UPnP option
|
||||
lblUPnPQuestion=Attempt to open port {0} automatically?
|
||||
lblUPnPFailed=UPnP failed to open port {0}. You will need to manually create a port forward for external clients to connect.
|
||||
lblAlways=Always
|
||||
lblNotNow=Not Now
|
||||
lblNever=Never
|
||||
lblAsk=Ask
|
||||
lblJustOnce=Just Once
|
||||
#GameLobby.java
|
||||
lblRequiredLeastTwoPlayerStartGame=至少需要两个牌手才能开始游戏。
|
||||
lblNotEnoughTeams=没有足够的团队!请调整团队分配。
|
||||
|
||||
5
forge-gui/server.preferences.example
Normal file
5
forge-gui/server.preferences.example
Normal file
@@ -0,0 +1,5 @@
|
||||
# Forge server port. Values under 1024 won't work on Mac OSX or on the various
|
||||
# *nixes.
|
||||
NET_PORT=36743
|
||||
#This determines if Forge should attempt to open a port automatically, on supported routers, using UPnP
|
||||
UPnP=ASK # ASK, ALWAYS, NEVER
|
||||
@@ -9,6 +9,7 @@ import forge.gamemodes.net.event.MessageEvent;
|
||||
import forge.gamemodes.net.event.NetEvent;
|
||||
import forge.gamemodes.net.server.FServerManager;
|
||||
import forge.gamemodes.net.server.ServerGameLobby;
|
||||
import forge.localinstance.properties.ForgeNetPreferences;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.interfaces.IGuiGame;
|
||||
import forge.gui.interfaces.ILobbyView;
|
||||
@@ -17,12 +18,13 @@ import forge.interfaces.ILobbyListener;
|
||||
import forge.interfaces.IUpdateable;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||
import forge.localinstance.properties.ForgeProfileProperties;
|
||||
import forge.model.FModel;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.util.Localizer;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public class NetConnectUtil {
|
||||
private NetConnectUtil() { }
|
||||
|
||||
@@ -38,7 +40,7 @@ public class NetConnectUtil {
|
||||
}
|
||||
|
||||
public static ChatMessage host(final IOnlineLobby onlineLobby, final IOnlineChatInterface chatInterface) {
|
||||
final int port = ForgeProfileProperties.getServerPort();
|
||||
final int port = FModel.getNetPreferences().getPrefInt(ForgeNetPreferences.FNetPref.NET_PORT);
|
||||
final FServerManager server = FServerManager.getInstance();
|
||||
final ServerGameLobby lobby = new ServerGameLobby();
|
||||
final ILobbyView view = onlineLobby.setLobby(lobby);
|
||||
@@ -100,12 +102,12 @@ public class NetConnectUtil {
|
||||
}
|
||||
|
||||
public static void copyHostedServerUrl() {
|
||||
String internalAddress = FServerManager.getInstance().getLocalAddress();
|
||||
String externalAddress = FServerManager.getInstance().getExternalAddress();
|
||||
String internalUrl = internalAddress + ":" + ForgeProfileProperties.getServerPort();
|
||||
String internalAddress = FServerManager.getLocalAddress();
|
||||
String externalAddress = FServerManager.getExternalAddress();
|
||||
String internalUrl = internalAddress + ":" + FModel.getNetPreferences().getPrefInt(ForgeNetPreferences.FNetPref.NET_PORT);
|
||||
String externalUrl = null;
|
||||
if (externalAddress != null) {
|
||||
externalUrl = externalAddress + ":" + ForgeProfileProperties.getServerPort();
|
||||
externalUrl = externalAddress + ":" + FModel.getNetPreferences().getPrefInt(ForgeNetPreferences.FNetPref.NET_PORT);
|
||||
GuiBase.getInterface().copyToClipboard(externalUrl);
|
||||
} else {
|
||||
GuiBase.getInterface().copyToClipboard(internalAddress);
|
||||
@@ -122,7 +124,24 @@ public class NetConnectUtil {
|
||||
|
||||
public static ChatMessage join(final String url, final IOnlineLobby onlineLobby, final IOnlineChatInterface chatInterface) {
|
||||
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame();
|
||||
final FGameClient client = new FGameClient(FModel.getPreferences().getPref(FPref.PLAYER_NAME), "0", gui);
|
||||
String hostname;
|
||||
int port = ForgeConstants.DEFAULT_SERVER_CONNECTION_PORT;
|
||||
|
||||
try {
|
||||
// Check if the URL already has a protocol
|
||||
String formattedUrl = url.matches("^[a-zA-Z][a-zA-Z0-9+.-]*://.*") ? url : "http://" + url;
|
||||
// Parse the URI
|
||||
URI uri = new URI(formattedUrl);
|
||||
hostname = uri.getHost();
|
||||
if (uri.getPort() != -1) { // If a port is specified in the URL
|
||||
port = uri.getPort();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
hostname = url; // Fallback to original URL if parsing fails
|
||||
}
|
||||
|
||||
|
||||
final FGameClient client = new FGameClient(FModel.getPreferences().getPref(FPref.PLAYER_NAME), "0", gui, hostname, port);
|
||||
onlineLobby.setClient(client);
|
||||
chatInterface.setGameClient(client);
|
||||
final ClientGameLobby lobby = new ClientGameLobby();
|
||||
@@ -150,22 +169,10 @@ public class NetConnectUtil {
|
||||
});
|
||||
view.setPlayerChangeListener((index, event) -> client.send(event));
|
||||
|
||||
String hostname = url;
|
||||
int port = ForgeProfileProperties.getServerPort();
|
||||
|
||||
//see if port specified in URL
|
||||
int index = url.indexOf(':');
|
||||
if (index >= 0) {
|
||||
hostname = url.substring(0, index);
|
||||
String portStr = url.substring(index + 1);
|
||||
try {
|
||||
port = Integer.parseInt(portStr);
|
||||
}
|
||||
catch (Exception ex) {}
|
||||
}
|
||||
|
||||
try {
|
||||
client.connect(hostname, port);
|
||||
client.connect();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
//return a message to close the connection so we will not crash...
|
||||
|
||||
@@ -18,6 +18,7 @@ import forge.trackable.TrackableCollection;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.ReflectionUtil;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -171,6 +172,7 @@ public enum ProtocolMethod {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,18 +18,22 @@ import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.serialization.ClassResolvers;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class FGameClient implements IToServer {
|
||||
|
||||
private final IGuiGame clientGui;
|
||||
private final String hostname;
|
||||
private final Integer port;
|
||||
private final List<ILobbyListener> lobbyListeners = Lists.newArrayList();
|
||||
private final ReplyPool replies = new ReplyPool();
|
||||
private Channel channel;
|
||||
|
||||
public FGameClient(final String username, final String roomKey, final IGuiGame clientGui) {
|
||||
public FGameClient(String username, String roomKey, IGuiGame clientGui, String hostname, int port) {
|
||||
this.clientGui = clientGui;
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
final IGuiGame getGui() {
|
||||
@@ -39,7 +43,7 @@ public class FGameClient implements IToServer {
|
||||
return replies;
|
||||
}
|
||||
|
||||
public void connect(final String host, final int port) {
|
||||
public void connect() {
|
||||
final EventLoopGroup group = new NioEventLoopGroup();
|
||||
try {
|
||||
final Bootstrap b = new Bootstrap()
|
||||
@@ -59,18 +63,20 @@ public class FGameClient implements IToServer {
|
||||
});
|
||||
|
||||
// Start the connection attempt.
|
||||
channel = b.connect(host, port).sync().channel();
|
||||
channel = b.connect(this.hostname, this.port).sync().channel();
|
||||
final ChannelFuture ch = channel.closeFuture();
|
||||
new Thread(() -> {
|
||||
try {
|
||||
ch.sync();
|
||||
} catch (final InterruptedException e) {
|
||||
System.out.println(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
group.shutdownGracefully();
|
||||
}
|
||||
}).start();
|
||||
} catch (final InterruptedException e) {
|
||||
System.out.println(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.gamemodes.net.server;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import forge.gamemodes.match.LobbySlot;
|
||||
import forge.gamemodes.match.LobbySlotType;
|
||||
@@ -8,9 +9,14 @@ import forge.gamemodes.net.CompatibleObjectEncoder;
|
||||
import forge.gamemodes.net.event.*;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.interfaces.IGuiGame;
|
||||
import forge.gui.util.SOptionPane;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.interfaces.ILobbyListener;
|
||||
import forge.model.FModel;
|
||||
import forge.util.IterableUtil;
|
||||
import forge.util.Localizer;
|
||||
import forge.localinstance.properties.ForgeNetPreferences;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
@@ -29,22 +35,21 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class FServerManager {
|
||||
private static FServerManager instance = null;
|
||||
private final Map<Channel, RemoteClient> clients = Maps.newTreeMap();
|
||||
private byte[] externalAddress = new byte[]{8, 8, 8, 8};
|
||||
private boolean isHosting = false;
|
||||
private EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
private EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
private UpnpService upnpService = null;
|
||||
private ServerGameLobby localLobby;
|
||||
private ILobbyListener lobbyListener;
|
||||
private boolean UPnPMapped = false;
|
||||
private int port;
|
||||
private static final Localizer localizer = Localizer.getInstance();
|
||||
private final Thread shutdownHook = new Thread(() -> {
|
||||
if (isHosting()) {
|
||||
stopServer(false);
|
||||
@@ -76,6 +81,15 @@ public final class FServerManager {
|
||||
}
|
||||
|
||||
public void startServer(final int port) {
|
||||
this.port = port;
|
||||
String UPnPOption = FModel.getNetPreferences().getPref(ForgeNetPreferences.FNetPref.UPnP);
|
||||
boolean startUPnP;
|
||||
if(UPnPOption.equalsIgnoreCase("ASK")) {
|
||||
startUPnP = callUPnPDialog();
|
||||
} else {
|
||||
startUPnP = UPnPOption.equalsIgnoreCase("ALWAYS");
|
||||
}
|
||||
System.out.println("Starting Multiplayer Server");
|
||||
try {
|
||||
final ServerBootstrap b = new ServerBootstrap()
|
||||
.group(bossGroup, workerGroup)
|
||||
@@ -102,19 +116,46 @@ public final class FServerManager {
|
||||
try {
|
||||
ch.sync();
|
||||
} catch (final InterruptedException e) {
|
||||
System.out.println(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
stopServer();
|
||||
}
|
||||
}).start();
|
||||
mapNatPort(port);
|
||||
if(startUPnP) {
|
||||
mapNatPort();
|
||||
}
|
||||
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||
isHosting = true;
|
||||
} catch (final InterruptedException e) {
|
||||
System.out.println(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean callUPnPDialog() {
|
||||
switch (SOptionPane.showOptionDialog(localizer.getMessageorUseDefault("lblUPnPQuestion", String.format("Attempt to open port %d automatically?", port), port),
|
||||
localizer.getMessageorUseDefault("lblUPnPTitle", "UPnP option"),
|
||||
null,
|
||||
ImmutableList.of(localizer.getMessageorUseDefault("lblJustOnce", "Just Once"),
|
||||
localizer.getMessageorUseDefault("lblNotNow", "Not Now"),
|
||||
localizer.getMessageorUseDefault("lblAlways", "Always"),
|
||||
localizer.getMessageorUseDefault("lblNever", "Never")), 0)) {
|
||||
case 2:
|
||||
FModel.getNetPreferences().setPref(ForgeNetPreferences.FNetPref.UPnP, "ALWAYS");
|
||||
FModel.getNetPreferences().save();
|
||||
case 0:
|
||||
//case 2 falls in here
|
||||
return true;
|
||||
case 3:
|
||||
FModel.getNetPreferences().setPref(ForgeNetPreferences.FNetPref.UPnP, "NEVER");
|
||||
FModel.getNetPreferences().save();
|
||||
default:
|
||||
//case 1 defaults to here
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void stopServer() {
|
||||
stopServer(true);
|
||||
}
|
||||
@@ -213,34 +254,35 @@ public final class FServerManager {
|
||||
// inspired by:
|
||||
// https://stackoverflow.com/a/34873630
|
||||
// https://stackoverflow.com/a/901943
|
||||
private String getRoutableAddress(boolean preferIpv4, boolean preferIPv6) throws SocketException, UnknownHostException {
|
||||
try (DatagramSocket s = new DatagramSocket()) {
|
||||
s.connect(InetAddress.getByAddress(this.externalAddress), 0);
|
||||
NetworkInterface n = NetworkInterface.getByInetAddress(s.getLocalAddress());
|
||||
Enumeration<InetAddress> en = n.getInetAddresses();
|
||||
while (en.hasMoreElements()) {
|
||||
InetAddress addr = en.nextElement();
|
||||
if (addr instanceof Inet4Address) {
|
||||
if (preferIPv6) {
|
||||
continue;
|
||||
private static String getRoutableAddress(boolean preferIpv4, boolean preferIPv6) throws SocketException, UnknownHostException {
|
||||
try (DatagramSocket socket = new DatagramSocket()) {
|
||||
// Connect to a well-known external address (Google's public DNS server)
|
||||
socket.connect(InetAddress.getByName("8.8.8.8"), 12345); // Use a valid port instead of 0
|
||||
InetAddress localAddress = socket.getLocalAddress();
|
||||
|
||||
// Check if the local address belongs to a valid network interface
|
||||
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(localAddress);
|
||||
if (networkInterface != null && networkInterface.isUp()) {
|
||||
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
|
||||
while (addresses.hasMoreElements()) {
|
||||
InetAddress addr = addresses.nextElement();
|
||||
if (addr instanceof Inet4Address && preferIpv4) {
|
||||
return addr.getHostAddress();
|
||||
}
|
||||
return addr.getHostAddress();
|
||||
}
|
||||
if (addr instanceof Inet6Address) {
|
||||
if (preferIpv4) {
|
||||
continue;
|
||||
if (addr instanceof Inet6Address && preferIPv6) {
|
||||
return addr.getHostAddress();
|
||||
}
|
||||
return addr.getHostAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return "localhost";
|
||||
}
|
||||
|
||||
public String getLocalAddress() {
|
||||
public static String getLocalAddress() {
|
||||
try {
|
||||
return getRoutableAddress(true, false);
|
||||
} catch (final Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
e.printStackTrace();
|
||||
return "localhost";
|
||||
}
|
||||
@@ -254,12 +296,14 @@ public final class FServerManager {
|
||||
whatismyip.openStream()));
|
||||
return in.readLine();
|
||||
} catch (IOException e) {
|
||||
System.out.println(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
System.out.println(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -267,10 +311,9 @@ public final class FServerManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void mapNatPort(final int port) {
|
||||
private void mapNatPort() {
|
||||
final String localAddress = getLocalAddress();
|
||||
final PortMapping portMapping = new PortMapping(port, localAddress, PortMapping.Protocol.TCP, "Forge");
|
||||
|
||||
// Shutdown existing UPnP service if already running
|
||||
if (upnpService != null) {
|
||||
upnpService.shutdown();
|
||||
@@ -283,10 +326,10 @@ public final class FServerManager {
|
||||
|
||||
// Add a PortMappingListener
|
||||
upnpService.getRegistry().addListener(new PortMappingListener(portMapping));
|
||||
|
||||
// Trigger device discovery
|
||||
upnpService.getControlPoint().search();
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class ConquestPreferences extends PreferencesStore<ConquestPreferences.CQ
|
||||
/**
|
||||
* Preference identifiers, and their default values.
|
||||
*/
|
||||
public enum CQPref {
|
||||
public enum CQPref implements IPref{
|
||||
CURRENT_CONQUEST("DEFAULT"),
|
||||
|
||||
AETHER_BASE_DUPLICATE_VALUE("100"),
|
||||
@@ -61,6 +61,7 @@ public class ConquestPreferences extends PreferencesStore<ConquestPreferences.CQ
|
||||
this.strDefaultVal = s0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefault() {
|
||||
return this.strDefaultVal;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public class QuestPreferences extends PreferencesStore<QuestPreferences.QPref> i
|
||||
/**
|
||||
* Preference identifiers, and their default values.
|
||||
*/
|
||||
public enum QPref {
|
||||
public enum QPref implements IPref{
|
||||
|
||||
// if enabled, player must follow world rules in duels (allowed sets only, banned/restricted cards etc.)
|
||||
WORLD_RULES_CONFORMANCE("0"),
|
||||
@@ -211,6 +211,7 @@ public class QuestPreferences extends PreferencesStore<QuestPreferences.QPref> i
|
||||
*
|
||||
* @return {@link java.lang.String}
|
||||
*/
|
||||
@Override
|
||||
public String getDefault() {
|
||||
return this.strDefaultVal;
|
||||
}
|
||||
|
||||
@@ -19,21 +19,24 @@ package forge.localinstance.properties;
|
||||
|
||||
import forge.gui.GuiBase;
|
||||
import forge.util.FileUtil;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public final class ForgeConstants {
|
||||
public static final String GITHUB_FORGE_URL = "https://github.com/Card-Forge/forge/";
|
||||
public static final String GITHUB_RELEASES_ATOM = GITHUB_FORGE_URL + "releases.atom";
|
||||
public static final String GITHUB_COMMITS_ATOM = GITHUB_FORGE_URL + "commits/master.atom";
|
||||
public static final String GITHUB_SNAPSHOT_URL = GITHUB_FORGE_URL + "releases/download/daily-snapshots/";
|
||||
public static final String RELEASE_URL = "https://releases.cardforge.org/";
|
||||
public static final String PATH_SEPARATOR = File.separator;
|
||||
public static final String ASSETS_DIR = GuiBase.getInterface().getAssetsDir();
|
||||
public static final String PROFILE_FILE = ASSETS_DIR + "forge.profile.properties";
|
||||
public static final String PROFILE_TEMPLATE_FILE = PROFILE_FILE + ".example";
|
||||
private static final Localizer localizer = Localizer.getInstance();
|
||||
public static final String GITHUB_FORGE_URL = "https://github.com/Card-Forge/forge/";
|
||||
public static final String GITHUB_RELEASES_ATOM = GITHUB_FORGE_URL + "releases.atom";
|
||||
public static final String GITHUB_COMMITS_ATOM = GITHUB_FORGE_URL + "commits/master.atom";
|
||||
public static final String GITHUB_SNAPSHOT_URL = GITHUB_FORGE_URL + "releases/download/daily-snapshots/";
|
||||
public static final String RELEASE_URL = "https://releases.cardforge.org/";
|
||||
public static final String PATH_SEPARATOR = File.separator;
|
||||
public static final String ASSETS_DIR = GuiBase.getInterface().getAssetsDir();
|
||||
public static final String PROFILE_FILE = ASSETS_DIR + "forge.profile.properties";
|
||||
public static final String PROFILE_TEMPLATE_FILE = PROFILE_FILE + ".example";
|
||||
public static final Integer DEFAULT_SERVER_CONNECTION_PORT = 36743;
|
||||
|
||||
public static final String RES_DIR = ASSETS_DIR + "res" + PATH_SEPARATOR;
|
||||
public static final String ADVENTURE_DIR = RES_DIR + "adventure" + PATH_SEPARATOR;
|
||||
@@ -221,7 +224,6 @@ public final class ForgeConstants {
|
||||
public static final String CACHE_DIR;
|
||||
public static final String CACHE_CARD_PICS_DIR;
|
||||
public static final Map<String, String> CACHE_CARD_PICS_SUBDIR;
|
||||
public static final int SERVER_PORT_NUMBER;
|
||||
public static final String DECK_BASE_DIR;
|
||||
public static final String DECK_CONSTRUCTED_DIR;
|
||||
static {
|
||||
@@ -232,7 +234,6 @@ public final class ForgeConstants {
|
||||
CACHE_CARD_PICS_SUBDIR = Collections.unmodifiableMap(ForgeProfileProperties.getCardPicsSubDirs());
|
||||
DECK_BASE_DIR = ForgeProfileProperties.getDecksDir();
|
||||
DECK_CONSTRUCTED_DIR = ForgeProfileProperties.getDecksConstructedDir();
|
||||
SERVER_PORT_NUMBER = ForgeProfileProperties.getServerPort();
|
||||
}
|
||||
|
||||
// data that is only in the profile dirs
|
||||
@@ -266,6 +267,7 @@ public final class ForgeConstants {
|
||||
public static final String DECK_TINY_LEADERS_DIR= DECK_BASE_DIR + "tiny_leaders" + PATH_SEPARATOR;
|
||||
public static final String DECK_BRAWL_DIR = DECK_BASE_DIR + "brawl" + PATH_SEPARATOR;
|
||||
public static final String MAIN_PREFS_FILE = USER_PREFS_DIR + "forge.preferences";
|
||||
public static final String SERVER_PREFS_FILE = USER_PREFS_DIR + "server.preferences";
|
||||
public static final String CARD_PREFS_FILE = USER_PREFS_DIR + "card.preferences";
|
||||
public static final String DECK_PREFS_FILE = USER_PREFS_DIR + "deck.preferences";
|
||||
public static final String QUEST_PREFS_FILE = USER_PREFS_DIR + "quest.preferences";
|
||||
@@ -375,6 +377,14 @@ public final class ForgeConstants {
|
||||
// Supported video mode names and dimensions (currently used in Adventure Mode)
|
||||
public static final String[] VIDEO_MODES = {"720p", "768p", "900p", "1080p", "1440p", "2160p"};
|
||||
|
||||
public static Map<String, String> getUPnPPreferenceMapping() {
|
||||
return Map.of(
|
||||
localizer.getMessage("lblAsk"), "ASK",
|
||||
localizer.getMessage("lblAlways"), "ALWAYS",
|
||||
localizer.getMessage("lblNever"), "NEVER"
|
||||
);
|
||||
}
|
||||
|
||||
public enum CounterDisplayLocation {
|
||||
|
||||
TOP("Top of Card"), BOTTOM("Bottom of Card");
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.localinstance.properties;
|
||||
|
||||
|
||||
|
||||
public class ForgeNetPreferences extends PreferencesStore<ForgeNetPreferences.FNetPref> {
|
||||
|
||||
/**
|
||||
* Preference identifiers and their default values.
|
||||
*/
|
||||
public enum FNetPref implements IPref {
|
||||
NET_PORT("36743"),
|
||||
UPnP("ASK");
|
||||
|
||||
private final String strDefaultVal;
|
||||
|
||||
FNetPref(final String s0) {
|
||||
this.strDefaultVal = s0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefault() {
|
||||
return strDefaultVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/** Instantiates a ForgePreferences object. */
|
||||
public ForgeNetPreferences() {
|
||||
super(ForgeConstants.SERVER_PREFS_FILE, FNetPref.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FNetPref[] getEnumValues() {
|
||||
return FNetPref.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FNetPref valueOf(final String name) {
|
||||
try {
|
||||
return FNetPref.valueOf(name);
|
||||
}
|
||||
catch (final Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPrefDefault(final FNetPref key) {
|
||||
return key.getDefault();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
|
||||
/**
|
||||
* Preference identifiers and their default values.
|
||||
*/
|
||||
public enum FPref {
|
||||
public enum FPref implements IPref {
|
||||
PLAYER_NAME (""),
|
||||
CONSTRUCTED_P1_DECK_STATE(""),
|
||||
CONSTRUCTED_P2_DECK_STATE(""),
|
||||
@@ -290,6 +290,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
|
||||
this.strDefaultVal = s0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefault() {
|
||||
return strDefaultVal;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ public class ForgeProfileProperties {
|
||||
private static Map<String, String> cardPicsSubDirs;
|
||||
private static String decksDir;
|
||||
private static String decksConstructedDir;
|
||||
private static int serverPort;
|
||||
|
||||
private static final String USER_DIR_KEY = "userDir";
|
||||
private static final String CACHE_DIR_KEY = "cacheDir";
|
||||
@@ -51,7 +50,7 @@ public class ForgeProfileProperties {
|
||||
private static final String CARD_PICS_SUB_DIRS_KEY = "cardPicsSubDirs";
|
||||
private static final String DECKS_DIR_KEY = "decksDir";
|
||||
private static final String DECKS_CONSTRUCTED_DIR_KEY = "decksConstructedDir";
|
||||
private static final String SERVER_PORT_KEY = "serverPort";
|
||||
|
||||
|
||||
private ForgeProfileProperties() {
|
||||
//prevent initializing static class
|
||||
@@ -75,7 +74,7 @@ public class ForgeProfileProperties {
|
||||
cardPicsSubDirs = getMap(props, CARD_PICS_SUB_DIRS_KEY);
|
||||
decksDir = getDir(props, DECKS_DIR_KEY, userDir + "decks" + File.separator);
|
||||
decksConstructedDir = getDir(props, DECKS_CONSTRUCTED_DIR_KEY, decksDir + "constructed" + File.separator);
|
||||
serverPort = getInt(props, SERVER_PORT_KEY, 36743); // "Forge" using phone keypad
|
||||
|
||||
|
||||
//ensure directories exist
|
||||
FileUtil.ensureDirectoryExists(userDir);
|
||||
@@ -127,10 +126,6 @@ public class ForgeProfileProperties {
|
||||
save();
|
||||
}
|
||||
|
||||
public static int getServerPort() {
|
||||
return serverPort;
|
||||
}
|
||||
|
||||
private static Map<String, String> getMap(final Properties props, final String propertyKey) {
|
||||
final String strMap = props.getProperty(propertyKey, "").trim();
|
||||
return FileSection.parseToMap(strMap, FileSection.ARROW_KV_SEPARATOR);
|
||||
@@ -234,9 +229,6 @@ public class ForgeProfileProperties {
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
if (serverPort != 0) {
|
||||
sb.append(SERVER_PORT_KEY + "=").append(serverPort);
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
FileUtil.writeFile(ForgeConstants.PROFILE_FILE, sb.toString());
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import forge.util.TextUtil;
|
||||
* Loads preferred values when instantiated.
|
||||
* If a requested value is not present, default is returned.
|
||||
*/
|
||||
public abstract class PreferencesStore<T extends Enum<T>> {
|
||||
public abstract class PreferencesStore<T extends Enum<T> & PreferencesStore.IPref> {
|
||||
private final Map<T, String> preferenceValues;
|
||||
private final String filename;
|
||||
|
||||
@@ -174,4 +174,8 @@ public abstract class PreferencesStore<T extends Enum<T>> {
|
||||
else if (gameType.equals("Archenemy Rumble"))
|
||||
result.add(GameType.ArchenemyRumble);
|
||||
}
|
||||
|
||||
public interface IPref {
|
||||
String getDefault(); // Common method for getting the default value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ import forge.item.PaperCardPredicates;
|
||||
import forge.itemmanager.ItemManagerConfig;
|
||||
import forge.localinstance.achievements.*;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgeNetPreferences;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||
import forge.player.GamePlayerUtil;
|
||||
@@ -83,7 +84,7 @@ public final class FModel {
|
||||
private static QuestPreferences questPreferences;
|
||||
private static ConquestPreferences conquestPreferences;
|
||||
private static ForgePreferences preferences;
|
||||
|
||||
private static ForgeNetPreferences netPreferences;
|
||||
private static Map<GameType, AchievementCollection> achievements;
|
||||
|
||||
// Someone should take care of 2 gauntlets here
|
||||
@@ -230,6 +231,7 @@ public final class FModel {
|
||||
}
|
||||
questPreferences = new QuestPreferences();
|
||||
conquestPreferences = new ConquestPreferences();
|
||||
netPreferences = new ForgeNetPreferences();
|
||||
fantasyBlocks = new StorageBase<>("Custom blocks", new CardBlock.Reader(ForgeConstants.BLOCK_DATA_DIR + "fantasyblocks.txt", magicDb.getEditions()));
|
||||
themedChaosDrafts = new StorageBase<>("Themed Chaos Drafts", new ThemedChaosDraft.Reader(ForgeConstants.BLOCK_DATA_DIR + "chaosdraftthemes.txt"));
|
||||
planes = new StorageBase<>("Conquest planes", new ConquestPlane.Reader(ForgeConstants.CONQUEST_PLANES_DIR + "planes.txt"));
|
||||
@@ -478,6 +480,9 @@ public final class FModel {
|
||||
public static ForgePreferences getPreferences() {
|
||||
return preferences;
|
||||
}
|
||||
public static ForgeNetPreferences getNetPreferences() {
|
||||
return netPreferences;
|
||||
}
|
||||
|
||||
public static AchievementCollection getAchievements(GameType gameType) {
|
||||
switch (gameType) { //translate gameType to appropriate type if needed
|
||||
|
||||
@@ -6,9 +6,11 @@ import forge.ai.AiProfileUtil;
|
||||
import forge.ai.LobbyPlayerAi;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.util.SOptionPane;
|
||||
import forge.localinstance.properties.ForgeNetPreferences;
|
||||
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||
import forge.model.FModel;
|
||||
import forge.util.GuiDisplayUtil;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.MyRandom;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -16,7 +18,7 @@ import java.util.Set;
|
||||
|
||||
public final class GamePlayerUtil {
|
||||
private GamePlayerUtil() { }
|
||||
|
||||
private static Localizer localizer = Localizer.getInstance();
|
||||
private static final LobbyPlayer guiPlayer = new LobbyPlayerHuman("Human");
|
||||
public static LobbyPlayer getGuiPlayer() {
|
||||
return guiPlayer;
|
||||
@@ -117,6 +119,13 @@ public final class GamePlayerUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setServerPort() {
|
||||
final int oldPort = FModel.getNetPreferences().getPrefInt(ForgeNetPreferences.FNetPref.NET_PORT);
|
||||
int newPort = getServerPortPrompt(oldPort);
|
||||
FModel.getNetPreferences().setPref(ForgeNetPreferences.FNetPref.NET_PORT, String.valueOf(newPort));
|
||||
FModel.getNetPreferences().save();
|
||||
}
|
||||
|
||||
private static void showThankYouPrompt(final String playerName) {
|
||||
SOptionPane.showMessageDialog("Thank you, " + playerName + ". "
|
||||
+ "You will not be prompted again but you can change\n"
|
||||
@@ -140,6 +149,29 @@ public final class GamePlayerUtil {
|
||||
playerName);
|
||||
}
|
||||
|
||||
private static Integer getServerPortPrompt(final Integer serverPort) {
|
||||
String input = SOptionPane.showInputDialog(
|
||||
localizer.getMessage("sOPServerPromptMessage"),
|
||||
localizer.getMessage("sOPServerPromptTitle"),
|
||||
null,
|
||||
serverPort.toString(),
|
||||
null,
|
||||
true
|
||||
);
|
||||
Integer port;
|
||||
try {
|
||||
port = Integer.parseInt(input);
|
||||
} catch (NumberFormatException nfe) {
|
||||
SOptionPane.showErrorDialog(localizer.getMessage("sOPServerPromptError", input));
|
||||
return serverPort;
|
||||
}
|
||||
if(port < 0 || port > 65535) {
|
||||
SOptionPane.showErrorDialog(localizer.getMessage("sOPServerPromptError", input));
|
||||
return serverPort;
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
private static String getVerifiedPlayerName(String newName, final String oldName) {
|
||||
if (newName == null || !StringUtils.isAlphanumericSpace(newName)) {
|
||||
newName = (StringUtils.isBlank(oldName) ? "Human" : oldName);
|
||||
@@ -150,4 +182,6 @@ public final class GamePlayerUtil {
|
||||
}
|
||||
return newName;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="ALL">
|
||||
<Configuration status="WARN">
|
||||
<!-- Define Appenders -->
|
||||
<Appenders>
|
||||
<Console name="A1">
|
||||
<PatternLayout pattern="%-4r [%t] %-5p %c %x - %m%n" />
|
||||
<!-- Console Appender -->
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout>
|
||||
<Pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n</Pattern>
|
||||
</PatternLayout>
|
||||
</Console>
|
||||
|
||||
<!--Sentry name="Sentry" /-->
|
||||
<!-- File Appender with Rolling Policy -->
|
||||
<RollingFile name="FileLogger" fileName="logs/app.log" filePattern="logs/app-%d{yyyy-MM-dd}-%i.log.gz">
|
||||
<PatternLayout>
|
||||
<Pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n</Pattern>
|
||||
</PatternLayout>
|
||||
<Policies>
|
||||
<!-- Roll over when the file size reaches 10 MB -->
|
||||
<SizeBasedTriggeringPolicy size="10MB"/>
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="10"/>
|
||||
</RollingFile>
|
||||
</Appenders>
|
||||
|
||||
<!-- Define Loggers -->
|
||||
<Loggers>
|
||||
<Root level="ALL">
|
||||
<AppenderRef ref="A1" />
|
||||
<!-- Note that the Sentry logging threshold is overridden to the WARN level -->
|
||||
<!--AppenderRef ref="Sentry" level="WARN" /-->
|
||||
<!-- Root Logger -->
|
||||
<Root level="info">
|
||||
<AppenderRef ref="Console"/>
|
||||
<AppenderRef ref="FileLogger"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
Reference in New Issue
Block a user