Merge branch 'master' into render

# Conflicts:
#	src/main/java/de/bixilon/minosoft/data/mappings/versions/VersionMapping.java
#	src/main/java/de/bixilon/minosoft/util/ChunkUtil.java
This commit is contained in:
Bixilon 2020-11-27 14:24:53 +01:00
commit d9e2bf100b
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
40 changed files with 702 additions and 587 deletions

6
.idea/cssdialects.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CssDialectMappings">
<file url="file://$PROJECT_DIR$/src/main/resources/layout/style.css" dialect="JavaFX" />
</component>
</project>

View File

@ -1,4 +1,3 @@
# Minosoft
Minosoft is an open source minecraft client, written from scratch in java. It aims to bring more functionality and stability.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

After

Width:  |  Height:  |  Size: 125 KiB

View File

@ -139,6 +139,11 @@
<version>16-ea+4</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.jfoenix</groupId>
<artifactId>jfoenix</artifactId>
<version>9.0.10</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>

View File

@ -75,16 +75,16 @@ public final class Minosoft {
Launcher.exit();
Platform.runLater(() -> {
Dialog<Boolean> dialog = new Dialog<>();
GUITools.initializePane(dialog.getDialogPane());
// Do not translate this, translations might fail to load...
dialog.setTitle("Critical Error");
dialog.setHeaderText("An error occurred while starting Minosoft");
TextArea text = new TextArea(exception.getClass().getCanonicalName() + ": " + exception.getLocalizedMessage());
TextArea text = new TextArea(exception.getClass().getCanonicalName() + ": " + exception.getMessage());
text.setEditable(false);
text.setWrapText(true);
dialog.getDialogPane().setContent(text);
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
stage.getIcons().add(GUITools.logo);
stage.setAlwaysOnTop(true);
stage.toFront();
stage.setOnCloseRequest(dialogEvent -> {

View File

@ -20,6 +20,7 @@ import java.io.File;
public class StaticConfiguration {
public static final boolean DEBUG_MODE = false; // if true, additional checks will be made to validate data, ... Decreases performance
public static final boolean DEBUG_SLOW_LOADING = false; // if true, many Thread.sleep will be executed and the start will be delayed (by a lot)
public static String CONFIG_FILENAME = "config.json"; // Filename of minosoft's base configuration (located in AppData/Minosoft/config)
public static boolean SKIP_MOJANG_AUTHENTICATION = false; // disables all connections to mojang
public static boolean COLORED_LOG = true; // the log should be colored with ANSI (does not affect base components)

View File

@ -111,6 +111,9 @@ public class AssetsManager {
try {
String hash = assets.get(filename);
boolean compressed = (source == AssetsSource.MOJANG);
if (StaticConfiguration.DEBUG_SLOW_LOADING) {
Thread.sleep(100L);
}
if (!verifyAssetHash(hash, compressed)) {
AssetsManager.downloadAsset(source, hash);
}

View File

@ -110,7 +110,11 @@ public class InventorySlots {
@Override
public int getId(int versionId) {
return valueMap.get(versionId);
Integer value = valueMap.get(versionId);
if (value == null) {
return Integer.MIN_VALUE;
}
return value;
}
}

View File

@ -87,5 +87,7 @@ public enum Strings {
BUTTON_LOGIN,
BUTTON_SAVE,
BUTTON_ADD,
VERSION_AUTOMATIC
VERSION_AUTOMATIC,
SERVER_ADDRESS_INPUT_REQUIRED
}

View File

@ -191,22 +191,22 @@ public enum BlockProperties {
FIRE_AGE_LEVEL_25,
// noteblock
NOTBLOCK_INSTRUMENT_HARP,
NOTBLOCK_INSTRUMENT_BASEDRUM,
NOTBLOCK_INSTRUMENT_SNARE,
NOTBLOCK_INSTRUMENT_HAT,
NOTBLOCK_INSTRUMENT_BASS,
NOTBLOCK_INSTRUMENT_FLUTE,
NOTBLOCK_INSTRUMENT_BELL,
NOTBLOCK_INSTRUMENT_GUITAR,
NOTBLOCK_INSTRUMENT_CHIME,
NOTBLOCK_INSTRUMENT_XYLOPHONE,
NOTBLOCK_INSTRUMENT_IRON_XYLOPHONE("instrument", "iron_xylophone"),
NOTBLOCK_INSTRUMENT_COW_BELL("instrument", "cow_bell"),
NOTBLOCK_INSTRUMENT_DIDGERIDOO,
NOTBLOCK_INSTRUMENT_BIT,
NOTBLOCK_INSTRUMENT_BANJO,
NOTBLOCK_INSTRUMENT_PLING,
NOTEBLOCK_INSTRUMENT_HARP,
NOTEBLOCK_INSTRUMENT_BASEDRUM,
NOTEBLOCK_INSTRUMENT_SNARE,
NOTEBLOCK_INSTRUMENT_HAT,
NOTEBLOCK_INSTRUMENT_BASS,
NOTEBLOCK_INSTRUMENT_FLUTE,
NOTEBLOCK_INSTRUMENT_BELL,
NOTEBLOCK_INSTRUMENT_GUITAR,
NOTEBLOCK_INSTRUMENT_CHIME,
NOTEBLOCK_INSTRUMENT_XYLOPHONE,
NOTEBLOCK_INSTRUMENT_IRON_XYLOPHONE("instrument", "iron_xylophone"),
NOTEBLOCK_INSTRUMENT_COW_BELL("instrument", "cow_bell"),
NOTEBLOCK_INSTRUMENT_DIDGERIDOO,
NOTEBLOCK_INSTRUMENT_BIT,
NOTEBLOCK_INSTRUMENT_BANJO,
NOTEBLOCK_INSTRUMENT_PLING,
NOTEBLOCK_NOTE_LEVEL_0,
NOTEBLOCK_NOTE_LEVEL_1,

View File

@ -43,23 +43,23 @@ public class VersionMapping {
private final HashSet<Mappings> loaded = new HashSet<>();
private Version version;
private VersionMapping parentMapping;
private HashBiMap<String, Motive> motiveIdentifierMap;
private HashBiMap<String, Particle> particleIdentifierMap;
private HashBiMap<String, Statistic> statisticIdentifierMap;
private HashBiMap<Integer, Item> itemMap;
private HashBiMap<Integer, Motive> motiveIdMap;
private HashBiMap<Integer, MobEffect> mobEffectMap;
private HashBiMap<Integer, Dimension> dimensionMap;
private final HashBiMap<Class<? extends Entity>, EntityInformation> entityInformationMap = HashBiMap.create();
private final HashMap<EntityMetaDataFields, Integer> entityMetaIndexMap = new HashMap<>();
private final HashMap<String, Pair<String, Integer>> entityMetaIndexOffsetParentMapping = new HashMap<>();
private final HashBiMap<Integer, Class<? extends Entity>> entityIdClassMap = HashBiMap.create();
private HashBiMap<String, Motive> motiveIdentifierMap = HashBiMap.create();
private HashBiMap<String, Particle> particleIdentifierMap = HashBiMap.create();
private HashBiMap<String, Statistic> statisticIdentifierMap = HashBiMap.create();
private HashMap<String, HashBiMap<String, Dimension>> dimensionIdentifierMap = new HashMap<>();
private HashBiMap<Integer, Block> blockMap;
private HashBiMap<Integer, BlockId> blockIdMap;
private HashBiMap<Integer, Enchantment> enchantmentMap;
private HashBiMap<Integer, Particle> particleIdMap;
private HashBiMap<Integer, Statistic> statisticIdMap;
private HashBiMap<Class<? extends Entity>, EntityInformation> entityInformationMap;
private HashMap<EntityMetaDataFields, Integer> entityMetaIndexMap;
private HashMap<String, Pair<String, Integer>> entityMetaIndexOffsetParentMapping;
private HashBiMap<Integer, Class<? extends Entity>> entityIdClassMap;
private HashBiMap<Integer, Item> itemMap = HashBiMap.create();
private HashBiMap<Integer, Motive> motiveIdMap = HashBiMap.create();
private HashBiMap<Integer, MobEffect> mobEffectMap = HashBiMap.create();
private HashBiMap<Integer, Dimension> dimensionMap = HashBiMap.create();
private HashBiMap<Integer, Block> blockMap = HashBiMap.create();
private HashBiMap<Integer, BlockId> blockIdMap = HashBiMap.create();
private HashBiMap<Integer, Enchantment> enchantmentMap = HashBiMap.create();
private HashBiMap<Integer, Particle> particleIdMap = HashBiMap.create();
private HashBiMap<Integer, Statistic> statisticIdMap = HashBiMap.create();
private HashMap<String, HashMap<String, BlockModelInterface>> modelMap = new HashMap<>();
private Integer blockTextureId; // OpenGL texture id for all block texture
@ -160,7 +160,11 @@ public class VersionMapping {
return dimensionMap.get(versionId);
}
@Nullable
public Block getBlockById(int versionId) {
if (versionId == ProtocolDefinition.NULL_BLOCK_ID) {
return null;
}
if (parentMapping != null) {
Block block = parentMapping.getBlockById(versionId);
if (block != null) {
@ -348,16 +352,6 @@ public class VersionMapping {
dimensionMap = Versions.PRE_FLATTENING_MAPPING.dimensionMap;
break;
}
itemMap = HashBiMap.create();
enchantmentMap = HashBiMap.create();
statisticIdMap = HashBiMap.create();
statisticIdentifierMap = HashBiMap.create();
blockIdMap = HashBiMap.create();
motiveIdMap = HashBiMap.create();
motiveIdentifierMap = HashBiMap.create();
particleIdMap = HashBiMap.create();
particleIdentifierMap = HashBiMap.create();
mobEffectMap = HashBiMap.create();
if (data == null) {
break;
@ -433,17 +427,11 @@ public class VersionMapping {
}
if (data == null) {
blockMap = HashBiMap.create();
break;
}
blockMap = Blocks.load(mod, data, !version.isFlattened());
}
case ENTITIES -> {
entityInformationMap = HashBiMap.create();
entityMetaIndexMap = new HashMap<>();
entityMetaIndexOffsetParentMapping = new HashMap<>();
entityIdClassMap = HashBiMap.create();
if (data == null) {
break;
}
@ -462,7 +450,6 @@ public class VersionMapping {
}
if (data == null) {
modelMap = new HashMap<>();
break;
}
Pair<HashMap<String, BlockModelInterface>, Integer> pair = BlockModelLoader.load(mod, data);

View File

@ -27,6 +27,7 @@ import java.text.StringCharacterIterator;
import java.util.ArrayList;
public class BaseComponent extends ChatComponent {
private final static String LEGACY_RESET_SUFFIX = String.valueOf(ProtocolDefinition.TEXT_COMPONENT_SPECIAL_PREFIX_CHAR) + PostChatFormattingCodes.RESET.getChar();
private final ArrayList<ChatComponent> parts = new ArrayList<>();
public BaseComponent() {
@ -157,18 +158,25 @@ public class BaseComponent extends ChatComponent {
return PostChatFormattingCodes.RESET.getANSI() + getANSIColoredMessage();
}
@Override
public String getANSIColoredMessage() {
StringBuilder builder = new StringBuilder();
parts.forEach((chatPart -> builder.append(chatPart.getANSIColoredMessage())));
return builder.toString();
}
@Override
public String getLegacyText() {
StringBuilder builder = new StringBuilder();
parts.forEach((chatPart -> builder.append(chatPart.getLegacyText())));
return builder.toString();
String string = builder.toString();
if (string.endsWith(LEGACY_RESET_SUFFIX)) {
string = string.substring(0, string.length() - LEGACY_RESET_SUFFIX.length());
}
return string;
}
@Override
public String getMessage() {
StringBuilder builder = new StringBuilder();
parts.forEach((chatPart -> builder.append(chatPart.getMessage())));
@ -195,4 +203,8 @@ public class BaseComponent extends ChatComponent {
parts.add(new BaseComponent(message));
return this;
}
public boolean isEmpty() {
return parts.isEmpty();
}
}

View File

@ -157,7 +157,9 @@ public class TextComponent extends ChatComponent {
@Override
public ObservableList<Node> getJavaFXText(ObservableList<Node> nodes) {
Text text = new Text(this.text);
if (color != null) {
if (color == null) {
text.setFill(Color.WHITE);
} else {
text.setFill(Color.web(color.toString()));
}
formatting.forEach((chatFormattingCode -> {

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.gui.main;
import com.jfoenix.controls.*;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.data.locale.LocaleManager;
import de.bixilon.minosoft.data.locale.Strings;
@ -26,11 +27,11 @@ import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.stage.Window;
import java.net.URL;
@ -45,8 +46,7 @@ public class AccountWindow implements Initializable {
public void initialize(URL url, ResourceBundle resourceBundle) {
AccountListCell.listView.setCellFactory((lv) -> AccountListCell.newInstance());
ObservableList<MojangAccount> accounts = FXCollections.observableArrayList();
accounts.addAll(Minosoft.getAccountList().values());
ObservableList<MojangAccount> accounts = FXCollections.observableArrayList(Minosoft.getAccountList().values());
AccountListCell.listView.setItems(accounts);
accountPane.setCenter(AccountListCell.listView);
@ -55,35 +55,39 @@ public class AccountWindow implements Initializable {
@FXML
public void addAccount() {
Dialog<?> dialog = new Dialog<>();
JFXAlert<?> dialog = new JFXAlert<>();
dialog.setTitle(LocaleManager.translate(Strings.LOGIN_DIALOG_TITLE));
dialog.setHeaderText(LocaleManager.translate(Strings.LOGIN_DIALOG_HEADER));
((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().add(GUITools.logo);
GUITools.initializePane(dialog.getDialogPane());
JFXDialogLayout layout = new JFXDialogLayout();
layout.setHeading(new Label(LocaleManager.translate(Strings.LOGIN_DIALOG_HEADER)));
ButtonType loginButtonType = new ButtonType(LocaleManager.translate(Strings.BUTTON_LOGIN), ButtonBar.ButtonData.OK_DONE);
dialog.getDialogPane().getButtonTypes().addAll(loginButtonType, ButtonType.CANCEL);
JFXButton loginButton = new JFXButton(LocaleManager.translate(Strings.BUTTON_LOGIN));
layout.setActions(loginButton);
GridPane grid = new GridPane();
GridPane gridPane = new GridPane();
gridPane.setHgap(15);
gridPane.setVgap(15);
TextField email = new TextField();
email.setPromptText(LocaleManager.translate(Strings.EMAIL));
PasswordField password = new PasswordField();
password.setPromptText(LocaleManager.translate(Strings.PASSWORD));
JFXTextField emailField = new JFXTextField();
emailField.setPromptText(LocaleManager.translate(Strings.EMAIL));
grid.add(new Label(LocaleManager.translate(Strings.EMAIL) + ":"), 0, 0);
grid.add(email, 1, 0);
grid.add(new Label(LocaleManager.translate(Strings.PASSWORD) + ":"), 0, 1);
grid.add(password, 1, 1);
Node loginButton = dialog.getDialogPane().lookupButton(loginButtonType);
JFXPasswordField passwordField = new JFXPasswordField();
passwordField.setPromptText(LocaleManager.translate(Strings.PASSWORD));
email.textProperty().addListener((observable, oldValue, newValue) -> loginButton.setDisable(newValue.trim().isEmpty()));
gridPane.add(new Label(LocaleManager.translate(Strings.EMAIL) + ":"), 0, 0);
gridPane.add(emailField, 1, 0);
gridPane.add(new Label(LocaleManager.translate(Strings.PASSWORD) + ":"), 0, 1);
gridPane.add(passwordField, 1, 1);
emailField.textProperty().addListener((observable, oldValue, newValue) -> loginButton.setDisable(newValue.trim().isEmpty()));
loginButton.setDisable(true);
dialog.getDialogPane().setContent(grid);
layout.setBody(gridPane);
dialog.setContent(layout);
Platform.runLater(email::requestFocus);
Platform.runLater(emailField::requestFocus);
loginButton.addEventFilter(ActionEvent.ACTION, event -> {
MojangAccountAuthenticationAttempt attempt = MojangAuthentication.login(email.getText(), password.getText());
MojangAccountAuthenticationAttempt attempt = MojangAuthentication.login(emailField.getText(), passwordField.getText());
if (attempt.succeeded()) {
// login okay
MojangAccount account = attempt.getAccount();
@ -91,6 +95,7 @@ public class AccountWindow implements Initializable {
account.saveToConfig();
AccountListCell.listView.getItems().add(account);
Log.info(String.format("Added and saved account (playerName=%s, email=%s, uuid=%s)", account.getPlayerName(), account.getMojangUserName(), account.getUUID()));
dialog.close();
return;
}
event.consume();
@ -98,14 +103,25 @@ public class AccountWindow implements Initializable {
error.setStyle("-fx-text-fill: red");
error.setText(attempt.getError());
grid.add(new Label(LocaleManager.translate(Strings.ERROR)), 0, 2);
grid.add(error, 1, 2);
gridPane.add(new Label(LocaleManager.translate(Strings.ERROR)), 0, 2);
gridPane.add(error, 1, 2);
// ToDo resize window
});
Window window = dialog.getDialogPane().getScene().getWindow();
window.setOnCloseRequest(windowEvent -> window.hide());
dialog.getDialogPane().setOnKeyReleased(keyEvent -> {
if (keyEvent.getCode() != KeyCode.ENTER) {
return;
}
if (emailField.getText().trim().isEmpty()) {
return;
}
loginButton.fire();
});
dialog.showAndWait();
}
}

View File

@ -13,29 +13,32 @@
package de.bixilon.minosoft.gui.main;
import com.jfoenix.controls.JFXComboBox;
import de.bixilon.minosoft.data.mappings.versions.Version;
import de.bixilon.minosoft.data.mappings.versions.Versions;
import de.bixilon.minosoft.logging.LogLevels;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ComboBox;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
import java.util.Base64;
public class GUITools {
public final static Image logo = new Image(GUITools.class.getResourceAsStream("/icons/windowIcon.png"));
public final static ObservableList<Version> versions = FXCollections.observableArrayList();
public final static ComboBox<Version> versionList = new ComboBox<>(GUITools.versions);
public final static ObservableList<LogLevels> logLevels = FXCollections.observableList(Arrays.asList(LogLevels.values().clone()));
public final static Image MINOSOFT_LOGO = new Image(GUITools.class.getResourceAsStream("/icons/windowIcon.png"));
public final static ObservableList<Version> VERSIONS = FXCollections.observableArrayList();
public final static JFXComboBox<Version> VERSION_COMBO_BOX = new JFXComboBox<>(GUITools.VERSIONS);
public final static ObservableList<LogLevels> LOG_LEVELS = FXCollections.observableList(Arrays.asList(LogLevels.values().clone()));
static {
GUITools.versions.add(Versions.LOWEST_VERSION_SUPPORTED);
Versions.getVersionIdMap().forEach((key, value) -> GUITools.versions.add(value));
GUITools.VERSIONS.add(Versions.LOWEST_VERSION_SUPPORTED);
Versions.getVersionIdMap().forEach((key, value) -> GUITools.VERSIONS.add(value));
GUITools.versions.sort((a, b) -> {
GUITools.VERSIONS.sort((a, b) -> {
if (a.getVersionId() == -1) {
return -Integer.MAX_VALUE;
}
@ -66,4 +69,17 @@ public class GUITools {
return null;
}
}
public static Scene initializeScene(Scene scene) {
scene.getStylesheets().add("/layout/style.css");
if (scene.getWindow() instanceof Stage stage) {
stage.getIcons().add(GUITools.MINOSOFT_LOGO);
}
return scene;
}
public static Pane initializePane(Pane pane) {
initializeScene(pane.getScene());
return pane;
}
}

View File

@ -44,10 +44,8 @@ public class Launcher {
if (exit) {
return;
}
Stage stage = new Stage();
stage.getIcons().add(GUITools.logo);
GUITools.versionList.setCellFactory(new Callback<>() {
GUITools.VERSION_COMBO_BOX.setCellFactory(new Callback<>() {
@Override
public ListCell<Version> call(ListView<Version> p) {
return new ListCell<>() {
@ -76,11 +74,12 @@ public class Launcher {
System.exit(1);
}
Stage stage = new Stage();
Scene scene = new Scene(root, 600, 800);
stage.setScene(scene);
stage.setTitle(LocaleManager.translate(Strings.MAIN_WINDOW_TITLE));
stage.getIcons().add(GUITools.logo);
GUITools.initializeScene(scene);
stage.setOnCloseRequest(windowEvent -> System.exit(0));
if (exit) {
return;

View File

@ -13,10 +13,16 @@
package de.bixilon.minosoft.gui.main;
import com.jfoenix.controls.JFXAlert;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialogLayout;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.data.locale.LocaleManager;
import de.bixilon.minosoft.data.locale.Strings;
import de.bixilon.minosoft.data.mappings.versions.Versions;
import de.bixilon.minosoft.data.text.BaseComponent;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.protocol.LANServerListener;
import de.bixilon.minosoft.util.DNSUtil;
@ -25,11 +31,12 @@ import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
@ -37,6 +44,7 @@ import javafx.scene.layout.GridPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javax.annotation.Nullable;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
@ -62,22 +70,28 @@ public class MainWindow implements Initializable {
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle(LocaleManager.translate(Strings.MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_TITLE));
stage.getIcons().add(GUITools.logo);
stage.setScene(new Scene(parent));
GUITools.initializeScene(stage.getScene());
Platform.setImplicitExit(false);
stage.setOnCloseRequest(event -> {
if (Minosoft.getSelectedAccount() == null) {
event.consume();
Alert alert = new Alert(Alert.AlertType.WARNING, LocaleManager.translate(Strings.ERROR), ButtonType.CANCEL, ButtonType.OK);
alert.setHeaderText(LocaleManager.translate(Strings.MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_HEADER));
alert.setContentText(LocaleManager.translate(Strings.MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_ERROR));
alert.showAndWait().ifPresent((type) -> {
if (type == ButtonType.OK) {
System.exit(0);
return;
}
alert.close();
});
JFXAlert<?> alert = new JFXAlert<>();
GUITools.initializePane(alert.getDialogPane());
alert.setTitle(LocaleManager.translate(Strings.ERROR));
JFXDialogLayout layout = new JFXDialogLayout();
layout.setHeading(new Label(LocaleManager.translate(Strings.MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_HEADER)));
layout.setBody(new Label(LocaleManager.translate(Strings.MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_ERROR)));
JFXButton cancel = new JFXButton(ButtonType.CANCEL.getText());
cancel.setOnAction((actionEvent -> alert.close()));
JFXButton close = new JFXButton(ButtonType.OK.getText());
close.setOnAction(actionEvent -> System.exit(0));
layout.setActions(cancel, close);
alert.setContent(layout);
alert.showAndWait();
} else {
stage.close();
}
@ -106,6 +120,116 @@ public class MainWindow implements Initializable {
});
}
public static void addOrEditServer(@Nullable final Server server) {
JFXAlert<?> dialog = new JFXAlert<>();
GUITools.initializePane(dialog.getDialogPane());
JFXDialogLayout layout = new JFXDialogLayout();
GridPane gridPane = new GridPane();
gridPane.setVgap(15);
gridPane.setHgap(50);
JFXButton submitButton;
JFXTextField serverNameField = new JFXTextField();
serverNameField.setPromptText(LocaleManager.translate(Strings.SERVER_NAME));
JFXTextField serverAddressField = new JFXTextField();
serverAddressField.setPromptText(LocaleManager.translate(Strings.SERVER_ADDRESS));
RequiredFieldValidator serverAddressValidator = new RequiredFieldValidator();
serverAddressValidator.setMessage(LocaleManager.translate(Strings.SERVER_ADDRESS_INPUT_REQUIRED));
serverAddressField.getValidators().add(serverAddressValidator);
serverAddressField.focusedProperty().addListener((o, oldValue, newValue) -> {
if (!newValue) {
serverAddressField.validate();
}
});
GUITools.VERSION_COMBO_BOX.getSelectionModel().select(Versions.LOWEST_VERSION_SUPPORTED);
if (server == null) {
// add
dialog.setTitle(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_TITLE));
layout.setHeading(new Label(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_HEADER)));
submitButton = new JFXButton(LocaleManager.translate(Strings.BUTTON_ADD));
serverNameField.setText(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_DEFAULT_SERVER_NAME));
} else {
dialog.setTitle(LocaleManager.translate(Strings.EDIT_SERVER_DIALOG_TITLE, server.getName().getMessage()));
layout.setHeading(new Label(LocaleManager.translate(Strings.EDIT_SERVER_DIALOG_HEADER)));
submitButton = new JFXButton(LocaleManager.translate(Strings.BUTTON_SAVE));
serverNameField.setText(server.getName().getLegacyText());
serverAddressField.setText(server.getAddress());
if (server.getDesiredVersionId() != -1) {
GUITools.VERSION_COMBO_BOX.getSelectionModel().select(Versions.getVersionById(server.getDesiredVersionId()));
}
}
submitButton.setButtonType(JFXButton.ButtonType.RAISED);
gridPane.add(new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":"), 0, 0);
gridPane.add(serverNameField, 1, 0);
gridPane.add(new Label(LocaleManager.translate(Strings.SERVER_ADDRESS) + ":"), 0, 1);
gridPane.add(serverAddressField, 1, 1);
gridPane.add(new Label(LocaleManager.translate(Strings.VERSION) + ":"), 0, 2);
gridPane.add(GUITools.VERSION_COMBO_BOX, 1, 2);
layout.setBody(gridPane);
JFXButton closeButton = new JFXButton(ButtonType.CLOSE.getText());
closeButton.setOnAction((actionEvent -> dialog.hide()));
closeButton.setButtonType(JFXButton.ButtonType.RAISED);
layout.setActions(closeButton, submitButton);
serverAddressField.textProperty().addListener((observable, oldValue, newValue) -> submitButton.setDisable(newValue.trim().isEmpty()));
submitButton.setDisable(serverAddressField.getText().isBlank());
dialog.setContent(layout);
Platform.runLater(serverNameField::requestFocus);
submitButton.setOnAction(actionEvent -> {
Server server1 = server;
BaseComponent serverName = new BaseComponent(serverNameField.getText());
String serverAddress = DNSUtil.correctHostName(serverAddressField.getText());
int desiredVersionId = GUITools.VERSION_COMBO_BOX.getSelectionModel().getSelectedItem().getVersionId();
if (server1 == null) {
server1 = new Server(Server.getNextServerId(), serverName, serverAddress, desiredVersionId);
Minosoft.serverList.add(server1);
ServerListCell.listView.getItems().add(server1);
} else {
server1.setName(serverName);
server1.setAddress(serverAddress);
server1.setDesiredVersionId(desiredVersionId);
if (server1.getCell() != null) {
server1.getCell().setName(server1.getName());
//ToDo: version
}
}
server1.saveToConfig();
Log.info(String.format("%s and saved server (serverName=%s, serverAddress=%s, version=%d)", ((server == null) ? "Added" : "Edited"), serverName.getLegacyText(), serverAddress, desiredVersionId));
dialog.hide();
});
dialog.getDialogPane().setOnKeyReleased(keyEvent -> {
if (keyEvent.getCode() != KeyCode.ENTER) {
return;
}
if (serverAddressField.getText().trim().isEmpty()) {
return;
}
submitButton.fire();
});
dialog.showAndWait();
}
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
serversPane.setCenter(ServerListCell.listView);
@ -125,54 +249,7 @@ public class MainWindow implements Initializable {
@FXML
public void addServer() {
Dialog<?> dialog = new Dialog<>();
dialog.setTitle(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_TITLE));
dialog.setHeaderText(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_HEADER));
((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().add(GUITools.logo);
ButtonType addButtonType = new ButtonType(LocaleManager.translate(Strings.BUTTON_ADD), ButtonBar.ButtonData.OK_DONE);
dialog.getDialogPane().getButtonTypes().addAll(addButtonType, ButtonType.CANCEL);
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(20, 300, 10, 10));
TextField serverName = new TextField();
serverName.setPromptText(LocaleManager.translate(Strings.SERVER_NAME));
serverName.setText(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_DEFAULT_SERVER_NAME));
TextField serverAddress = new TextField();
serverAddress.setPromptText(LocaleManager.translate(Strings.SERVER_ADDRESS));
GUITools.versionList.getSelectionModel().select(Versions.LOWEST_VERSION_SUPPORTED);
grid.add(new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":"), 0, 0);
grid.add(serverName, 1, 0);
grid.add(new Label(LocaleManager.translate(Strings.SERVER_ADDRESS) + ":"), 0, 1);
grid.add(serverAddress, 1, 1);
grid.add(new Label(LocaleManager.translate(Strings.VERSION) + ":"), 0, 2);
grid.add(GUITools.versionList, 1, 2);
Node addButton = dialog.getDialogPane().lookupButton(addButtonType);
serverAddress.textProperty().addListener((observable, oldValue, newValue) -> addButton.setDisable(newValue.trim().isEmpty()));
addButton.setDisable(true);
dialog.getDialogPane().setContent(grid);
Platform.runLater(serverName::requestFocus);
dialog.setResultConverter(dialogButton -> {
if (dialogButton == addButtonType) {
Server server = new Server(Server.getNextServerId(), serverName.getText(), DNSUtil.correctHostName(serverAddress.getText()), GUITools.versionList.getSelectionModel().getSelectedItem().getVersionId());
Minosoft.serverList.add(server);
server.saveToConfig();
ServerListCell.listView.getItems().add(server);
Log.info(String.format("Added and saved server (serverName=%s, serverAddress=%s, version=%d)", server.getName(), server.getAddress(), server.getDesiredVersionId()));
}
return null;
});
dialog.showAndWait();
addOrEditServer(null);
}
@FXML
@ -205,10 +282,9 @@ public class MainWindow implements Initializable {
Parent parent = new FXMLLoader(MainWindow.class.getResource("/layout/settings.fxml")).load();
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.getIcons().add(GUITools.logo);
stage.setTitle(LocaleManager.translate(Strings.SETTINGS_TITLE));
stage.getIcons().add(GUITools.logo);
stage.setScene(new Scene(parent));
GUITools.initializeScene(stage.getScene());
stage.addEventHandler(KeyEvent.KEY_PRESSED, (KeyEvent event) -> {
if (event.getCode() == KeyCode.ESCAPE) {
stage.close();

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.main;
import com.google.gson.JsonObject;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.data.text.BaseComponent;
import de.bixilon.minosoft.protocol.network.Connection;
import de.bixilon.minosoft.protocol.protocol.ConnectionReasons;
import de.bixilon.minosoft.protocol.protocol.LANServerListener;
@ -25,34 +26,37 @@ import java.util.ArrayList;
import java.util.Base64;
public class Server {
static int highestServerId;
final int id;
final ArrayList<Connection> connections = new ArrayList<>();
String name;
String address;
int desiredVersion;
byte[] favicon;
Connection lastPing;
private static int highestServerId;
private final int id;
private final ArrayList<Connection> connections = new ArrayList<>();
private BaseComponent name;
private BaseComponent addressName;
private String address;
private int desiredVersion;
private byte[] favicon;
private Connection lastPing;
private boolean readOnly = false;
private ServerListCell cell;
public Server(int id, String name, String address, int desiredVersion, byte[] favicon) {
public Server(int id, BaseComponent name, String address, int desiredVersion, byte[] favicon) {
this(id, name, address, desiredVersion);
this.favicon = favicon;
}
public Server(int id, String name, String address, int desiredVersion) {
public Server(int id, BaseComponent name, String address, int desiredVersion) {
this.id = id;
if (id > highestServerId) {
highestServerId = id;
}
this.name = name;
this.address = address;
this.addressName = new BaseComponent(address);
this.desiredVersion = desiredVersion;
}
public Server(ServerAddress address) {
this.id = getNextServerId();
this.name = String.format("LAN Server #%d", LANServerListener.getServers().size());
this.name = new BaseComponent(String.format("LAN Server #%d", LANServerListener.getServers().size()));
this.address = address.toString();
this.desiredVersion = -1; // Automatic
this.readOnly = true;
@ -63,7 +67,7 @@ public class Server {
}
public static Server deserialize(JsonObject json) {
Server server = new Server(json.get("id").getAsInt(), json.get("name").getAsString(), json.get("address").getAsString(), json.get("version").getAsInt());
Server server = new Server(json.get("id").getAsInt(), new BaseComponent(json.get("name").getAsString()), json.get("address").getAsString(), json.get("version").getAsInt());
if (json.has("favicon")) {
server.setFavicon(Base64.getDecoder().decode(json.get("favicon").getAsString()));
}
@ -113,11 +117,15 @@ public class Server {
return String.format("%s (%s)", getName(), getAddress());
}
public String getName() {
public BaseComponent getName() {
if (name.isEmpty()) {
return addressName;
}
return name;
}
public void setName(String name) {
public void setName(BaseComponent name) {
this.name = name;
}
@ -127,6 +135,7 @@ public class Server {
public void setAddress(String address) {
this.address = address;
this.addressName = new BaseComponent(address);
}
public void ping() {
@ -164,7 +173,7 @@ public class Server {
public JsonObject serialize() {
JsonObject json = new JsonObject();
json.addProperty("id", id);
json.addProperty("name", name);
json.addProperty("name", name.getLegacyText());
json.addProperty("address", address);
json.addProperty("version", desiredVersion);
if (favicon != null) {
@ -184,4 +193,12 @@ public class Server {
public boolean isReadOnly() {
return readOnly;
}
public ServerListCell getCell() {
return cell;
}
public void setCell(ServerListCell cell) {
this.cell = cell;
}
}

View File

@ -13,12 +13,16 @@
package de.bixilon.minosoft.gui.main;
import com.jfoenix.controls.JFXAlert;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialogLayout;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.data.Player;
import de.bixilon.minosoft.data.locale.LocaleManager;
import de.bixilon.minosoft.data.locale.Strings;
import de.bixilon.minosoft.data.mappings.versions.Version;
import de.bixilon.minosoft.data.mappings.versions.Versions;
import de.bixilon.minosoft.data.text.BaseComponent;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.modding.event.EventInvokerCallback;
import de.bixilon.minosoft.modding.event.events.ConnectionStateChangeEvent;
@ -26,11 +30,9 @@ import de.bixilon.minosoft.modding.event.events.ServerListPingArriveEvent;
import de.bixilon.minosoft.protocol.network.Connection;
import de.bixilon.minosoft.protocol.ping.ForgeModInfo;
import de.bixilon.minosoft.protocol.ping.ServerListPing;
import de.bixilon.minosoft.util.DNSUtil;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
@ -38,7 +40,6 @@ import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
@ -54,13 +55,14 @@ import java.util.ResourceBundle;
public class ServerListCell extends ListCell<Server> implements Initializable {
public static final ListView<Server> listView = new ListView<>();
public ImageView icon;
public TextFlow motd;
public Label version;
public Label players;
public Label serverBrand;
public Label serverName;
public AnchorPane root;
public ImageView faviconField;
public TextFlow nameField;
public TextFlow motdField;
public Label versionField;
public Label playersField;
public Label brandField;
public GridPane root;
public MenuItem optionsConnect;
public MenuItem optionsShowInfo;
public MenuItem optionsEdit;
@ -97,10 +99,6 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
optionsDelete.setText(LocaleManager.translate(Strings.SERVER_ACTION_DELETE));
}
public AnchorPane getRoot() {
return root;
}
@Override
protected void updateItem(Server server, boolean empty) {
super.updateItem(server, empty);
@ -117,16 +115,17 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
if (server.equals(this.server)) {
return;
}
server.setCell(this);
resetCell();
this.server = server;
serverName.setText(server.getName());
setName(server.getName());
Image favicon = GUITools.getImage(server.getFavicon());
if (favicon == null) {
favicon = GUITools.logo;
favicon = GUITools.MINOSOFT_LOGO;
}
icon.setImage(favicon);
faviconField.setImage(favicon);
if (server.isConnected()) {
setStyle("-fx-background-color: darkseagreen;");
optionsSessions.setDisable(false);
@ -149,37 +148,37 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
}
if (ping == null) {
// Offline
players.setText("");
version.setText(LocaleManager.translate(Strings.OFFLINE));
version.setStyle("-fx-text-fill: red;");
playersField.setText("");
versionField.setText(LocaleManager.translate(Strings.OFFLINE));
versionField.setStyle("-fx-text-fill: red;");
setErrorMotd(String.format("%s", server.getLastPing().getLastConnectionException()));
optionsConnect.setDisable(true);
canConnect = false;
return;
}
players.setText(LocaleManager.translate(Strings.SERVER_INFO_SLOTS_PLAYERS_ONLINE, ping.getPlayerOnline(), ping.getMaxPlayers()));
playersField.setText(LocaleManager.translate(Strings.SERVER_INFO_SLOTS_PLAYERS_ONLINE, ping.getPlayerOnline(), ping.getMaxPlayers()));
Version serverVersion;
if (server.getDesiredVersionId() == -1) {
serverVersion = Versions.getVersionByProtocolId(ping.getProtocolId());
} else {
serverVersion = Versions.getVersionById(server.getDesiredVersionId());
version.setStyle("-fx-text-fill: green;");
versionField.setStyle("-fx-text-fill: -secondary-light-light-color;");
}
if (serverVersion == null) {
version.setText(ping.getServerBrand());
version.setStyle("-fx-text-fill: red;");
versionField.setText(ping.getServerBrand());
versionField.setStyle("-fx-text-fill: red;");
optionsConnect.setDisable(true);
canConnect = false;
} else {
version.setText(serverVersion.getVersionName());
versionField.setText(serverVersion.getVersionName());
optionsConnect.setDisable(false);
canConnect = true;
}
serverBrand.setText(ping.getServerModInfo().getBrand());
serverBrand.setTooltip(new Tooltip(ping.getServerModInfo().getInfo()));
motd.getChildren().addAll(ping.getMotd().getJavaFXText());
brandField.setText(ping.getServerModInfo().getBrand());
brandField.setTooltip(new Tooltip(ping.getServerModInfo().getInfo()));
motdField.getChildren().setAll(ping.getMotd().getJavaFXText());
if (ping.getFavicon() != null) {
icon.setImage(GUITools.getImage(ping.getFavicon()));
faviconField.setImage(GUITools.getImage(ping.getFavicon()));
if (!Arrays.equals(ping.getFavicon(), server.getFavicon())) {
server.setFavicon(ping.getFavicon());
server.saveToConfig();
@ -191,34 +190,40 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
}
if (server.getLastPing().getLastConnectionException() != null) {
// connection failed because of an error in minosoft, but ping was okay
version.setStyle("-fx-text-fill: red;");
versionField.setStyle("-fx-text-fill: red;");
optionsConnect.setDisable(true);
canConnect = false;
setErrorMotd(String.format("%s: %s", server.getLastPing().getLastConnectionException().getClass().getCanonicalName(), server.getLastPing().getLastConnectionException().getLocalizedMessage()));
setErrorMotd(String.format("%s: %s", server.getLastPing().getLastConnectionException().getClass().getCanonicalName(), server.getLastPing().getLastConnectionException().getMessage()));
}
})));
}
public void setName(BaseComponent name) {
nameField.getChildren().setAll(name.getJavaFXText());
for (Node node : nameField.getChildren()) {
node.setStyle("-fx-font-size: 15pt ;");
}
}
private void resetCell() {
// clear all cells
setStyle(null);
motd.getChildren().clear();
serverBrand.setText("");
serverBrand.setTooltip(null);
motd.setStyle(null);
version.setText(LocaleManager.translate(Strings.CONNECTING));
version.setStyle(null);
players.setText("");
motdField.getChildren().clear();
brandField.setText("");
brandField.setTooltip(null);
motdField.setStyle(null);
versionField.setText(LocaleManager.translate(Strings.CONNECTING));
versionField.setStyle(null);
playersField.setText("");
optionsConnect.setDisable(true);
optionsEdit.setDisable(false);
optionsDelete.setDisable(false);
}
private void setErrorMotd(String message) {
motd.getChildren().clear();
Text text = new Text(message);
text.setFill(Color.RED);
motd.getChildren().add(text);
motdField.getChildren().setAll(text);
}
public void delete() {
@ -227,12 +232,12 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
}
server.getConnections().forEach(Connection::disconnect);
server.delete();
Log.info(String.format("Deleted server (name=\"%s\", address=\"%s\")", server.getName(), server.getAddress()));
Log.info(String.format("Deleted server (name=\"%s\", address=\"%s\")", server.getName().getLegacyText(), server.getAddress()));
listView.getItems().remove(server);
}
public void refresh() {
Log.info(String.format("Refreshing server status (serverName=\"%s\", address=\"%s\")", server.getName(), server.getAddress()));
Log.info(String.format("Refreshing server status (serverName=\"%s\", address=\"%s\")", server.getName().getLegacyText(), server.getAddress()));
if (server.getLastPing() == null) {
// server was not pinged, don't even try, only costs memory and cpu
return;
@ -250,7 +255,7 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
case SECONDARY -> optionsMenu.fire();
case MIDDLE -> {
listView.getSelectionModel().select(server);
edit();
editServer();
}
}
}
@ -273,68 +278,8 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
}
public void edit() {
if (server.isReadOnly()) {
return;
}
Dialog<?> dialog = new Dialog<>();
dialog.setTitle(LocaleManager.translate(Strings.EDIT_SERVER_DIALOG_TITLE, server.getName()));
dialog.setHeaderText(LocaleManager.translate(Strings.EDIT_SERVER_DIALOG_HEADER));
((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().add(GUITools.logo);
ButtonType saveButtonType = new ButtonType(LocaleManager.translate(Strings.BUTTON_SAVE), ButtonBar.ButtonData.OK_DONE);
dialog.getDialogPane().getButtonTypes().addAll(saveButtonType, ButtonType.CANCEL);
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(20, 300, 10, 10));
TextField serverName = new TextField();
serverName.setPromptText(LocaleManager.translate(Strings.SERVER_NAME));
serverName.setText(server.getName());
TextField serverAddress = new TextField();
serverAddress.setPromptText(LocaleManager.translate(Strings.SERVER_ADDRESS));
serverAddress.setText(server.getAddress());
if (server.getDesiredVersionId() == -1) {
GUITools.versionList.getSelectionModel().select(Versions.LOWEST_VERSION_SUPPORTED);
} else {
GUITools.versionList.getSelectionModel().select(Versions.getVersionById(server.getDesiredVersionId()));
}
grid.add(new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":"), 0, 0);
grid.add(serverName, 1, 0);
grid.add(new Label(LocaleManager.translate(Strings.SERVER_ADDRESS) + ":"), 0, 1);
grid.add(serverAddress, 1, 1);
grid.add(new Label(LocaleManager.translate(Strings.VERSION) + ":"), 0, 2);
grid.add(GUITools.versionList, 1, 2);
Node saveButton = dialog.getDialogPane().lookupButton(saveButtonType);
serverAddress.textProperty().addListener((observable, oldValue, newValue) -> saveButton.setDisable(newValue.trim().isEmpty()));
dialog.getDialogPane().setContent(grid);
Platform.runLater(serverName::requestFocus);
dialog.setResultConverter(dialogButton -> {
if (dialogButton == saveButtonType) {
serverName.setText(serverName.getText());
server.setName(serverName.getText());
server.setDesiredVersionId(GUITools.versionList.getSelectionModel().getSelectedItem().getVersionId());
if (server.getDesiredVersionId() != -1) {
version.setText(Versions.getVersionById(server.getDesiredVersionId()).getVersionName());
version.setTextFill(Color.BLACK);
}
server.setAddress(DNSUtil.correctHostName(serverAddress.getText()));
server.saveToConfig();
Log.info(String.format("Edited and saved server (serverName=%s, serverAddress=%s, version=%d)", server.getName(), server.getAddress(), server.getDesiredVersionId()));
}
return null;
});
dialog.showAndWait();
public void editServer() {
MainWindow.addOrEditServer(server);
}
private void handleConnectionCallback(ConnectionStateChangeEvent event) {
@ -363,19 +308,24 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
}
public void showInfo() {
Dialog<?> dialog = new Dialog<>();
dialog.setTitle("View server info: " + server.getName());
((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().add(GUITools.logo);
JFXAlert<?> dialog = new JFXAlert<>();
dialog.setTitle("View server info: " + server.getName().getMessage());
GUITools.initializePane(dialog.getDialogPane());
ButtonType loginButtonType = ButtonType.CLOSE;
dialog.getDialogPane().getButtonTypes().add(loginButtonType);
JFXDialogLayout layout = new JFXDialogLayout();
JFXButton closeButton = new JFXButton(ButtonType.CLOSE.getText());
closeButton.setOnAction((actionEvent -> dialog.hide()));
closeButton.setButtonType(JFXButton.ButtonType.RAISED);
layout.setActions(closeButton);
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(20, 300, 10, 10));
Label serverNameLabel = new Label(server.getName());
TextFlow serverNameLabel = new TextFlow();
serverNameLabel.getChildren().setAll(server.getName().getJavaFXText());
Label serverAddressLabel = new Label(server.getAddress());
Label forcedVersionLabel = new Label();
@ -386,7 +336,9 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
}
int column = -1;
grid.add(new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":"), 0, ++column);
Label a = new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":");
a.setWrapText(false);
grid.add(a, 0, ++column);
grid.add(serverNameLabel, 1, column);
grid.add(new Label(LocaleManager.translate(Strings.SERVER_ADDRESS) + ":"), 0, ++column);
grid.add(serverAddressLabel, 1, column);
@ -415,7 +367,7 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
Label serverBrandLabel = new Label(lastPing.getServerBrand());
Label playersOnlineMaxLabel = new Label(LocaleManager.translate(Strings.SERVER_INFO_SLOTS_PLAYERS_ONLINE, lastPing.getPlayerOnline(), lastPing.getMaxPlayers()));
TextFlow motdLabel = new TextFlow();
motdLabel.getChildren().addAll(lastPing.getMotd().getJavaFXText());
motdLabel.getChildren().setAll(lastPing.getMotd().getJavaFXText());
Label moddedBrandLabel = new Label(lastPing.getServerModInfo().getBrand());
grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_REAL_SERVER_ADDRESS) + ":"), 0, ++column);
@ -440,9 +392,9 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
}
}
}
dialog.getDialogPane().setContent(grid);
// ToDo: size probably
layout.setBody(grid);
dialog.setContent(layout);
dialog.showAndWait();
}
@ -454,8 +406,8 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle(LocaleManager.translate(Strings.SESSIONS_DIALOG_TITLE, server.getName()));
stage.getIcons().add(GUITools.logo);
stage.setScene(new Scene(parent));
GUITools.initializeScene(stage.getScene());
stage.show();
} catch (IOException e) {
e.printStackTrace();

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.gui.main;
import com.jfoenix.controls.JFXComboBox;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.config.ConfigurationPaths;
import de.bixilon.minosoft.data.locale.LocaleManager;
@ -20,7 +21,6 @@ import de.bixilon.minosoft.data.locale.Strings;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.logging.LogLevels;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.layout.GridPane;
@ -30,14 +30,14 @@ import java.util.ResourceBundle;
public class SettingsWindow implements Initializable {
public GridPane tabGeneral;
public ComboBox<LogLevels> generalLogLevel;
public JFXComboBox<LogLevels> generalLogLevel;
public Tab general;
public Tab download;
public Label generalLogLevelLabel;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
generalLogLevel.setItems(GUITools.logLevels);
generalLogLevel.setItems(GUITools.LOG_LEVELS);
generalLogLevel.getSelectionModel().select(Log.getLevel());
generalLogLevel.setOnAction((actionEvent -> {
LogLevels newLevel = generalLogLevel.getValue();

View File

@ -13,25 +13,27 @@
package de.bixilon.minosoft.gui.main;
import com.jfoenix.controls.JFXAlert;
import com.jfoenix.controls.JFXDialogLayout;
import com.jfoenix.controls.JFXProgressBar;
import de.bixilon.minosoft.data.locale.LocaleManager;
import de.bixilon.minosoft.data.locale.Strings;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.util.CountUpAndDownLatch;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.GridPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
public class StartProgressWindow extends Application {
public static CountDownLatch toolkitLatch = new CountDownLatch(2); // 2 if not started, 1 if started, 2 if loaded
public static Dialog<Boolean> progressDialog;
public final static CountDownLatch toolkitLatch = new CountDownLatch(2); // 2 if not started, 1 if started, 2 if loaded
public static JFXAlert<Boolean> progressDialog;
private static JFXProgressBar progressBar;
private static Label progressLabel;
private static boolean exit = false;
public static void show(CountUpAndDownLatch progress) throws InterruptedException {
@ -44,20 +46,30 @@ public class StartProgressWindow extends Application {
latch.countDown();
return;
}
AtomicReference<ProgressBar> progressBar = new AtomicReference<>();
AtomicReference<Label> progressLabel = new AtomicReference<>();
Platform.runLater(() -> {
progressDialog = new Dialog<>();
progressDialog = new JFXAlert<>();
GUITools.initializePane(progressDialog.getDialogPane());
progressDialog.setTitle(LocaleManager.translate(Strings.MINOSOFT_STILL_STARTING_TITLE));
progressDialog.setHeaderText(LocaleManager.translate(Strings.MINOSOFT_STILL_STARTING_HEADER));
GridPane grid = new GridPane();
progressBar.set(new ProgressBar());
progressLabel.set(new Label());
grid.add(progressBar.get(), 0, 0);
grid.add(progressLabel.get(), 1, 0);
progressDialog.getDialogPane().setContent(grid);
JFXDialogLayout layout = new JFXDialogLayout();
layout.setHeading(new Label(LocaleManager.translate(Strings.MINOSOFT_STILL_STARTING_HEADER)));
progressBar = new JFXProgressBar();
progressBar.setPrefHeight(50);
progressLabel = new Label();
GridPane gridPane = new GridPane();
gridPane.setHgap(20);
gridPane.add(progressBar, 0, 0);
gridPane.add(progressLabel, 1, 0);
layout.setBody(gridPane);
progressDialog.setContent(layout);
Stage stage = (Stage) progressDialog.getDialogPane().getScene().getWindow();
stage.getIcons().add(GUITools.logo);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setOnCloseRequest((request) -> System.exit(0));
if (exit) {
@ -75,8 +87,8 @@ public class StartProgressWindow extends Application {
e.printStackTrace();
}
Platform.runLater(() -> {
progressBar.get().setProgress(1.0F - ((float) progress.getCount() / progress.getTotal()));
progressLabel.get().setText(String.format("%d / %d", (progress.getTotal() - progress.getCount()), progress.getTotal()));
progressBar.setProgress(1.0F - ((float) progress.getCount() / progress.getTotal()));
progressLabel.setText(String.format("%d / %d", (progress.getTotal() - progress.getCount()), progress.getTotal()));
});
}
hideDialog();
@ -105,6 +117,7 @@ public class StartProgressWindow extends Application {
@Override
public void start(Stage stage) {
Platform.setImplicitExit(false);
toolkitLatch.countDown();
}
}

View File

@ -41,8 +41,8 @@ public class PacketChunkData implements ClientboundPacket {
if (buffer.getVersionId() < 23) {
this.location = new ChunkLocation(buffer.readInt(), buffer.readInt());
boolean groundUpContinuous = buffer.readBoolean();
short sectionBitMask = buffer.readShort();
short addBitMask = buffer.readShort();
int sectionBitMask = buffer.readUnsignedShort();
int addBitMask = buffer.readUnsignedShort();
// decompress chunk data
InByteBuffer decompressed;
@ -60,15 +60,14 @@ public class PacketChunkData implements ClientboundPacket {
boolean groundUpContinuous = buffer.readBoolean();
int sectionBitMask;
if (buffer.getVersionId() < 60) {
sectionBitMask = buffer.readShort();
sectionBitMask = buffer.readUnsignedShort();
} else {
sectionBitMask = buffer.readInt();
}
int size = buffer.readVarInt();
int lastPos = buffer.getPosition();
chunk = ChunkUtil.readChunkPacket(buffer, sectionBitMask, 0, groundUpContinuous, containsSkyLight);
buffer.setPosition(size + lastPos);
chunk = ChunkUtil.readChunkPacket(buffer, (short) sectionBitMask, (short) 0, groundUpContinuous, containsSkyLight);
return true;
}
this.location = new ChunkLocation(buffer.readInt(), buffer.readInt());
@ -99,7 +98,7 @@ public class PacketChunkData implements ClientboundPacket {
int lastPos = buffer.getPosition();
if (size > 0) {
chunk = ChunkUtil.readChunkPacket(buffer, (short) sectionBitMask, (short) 0, groundUpContinuous, containsSkyLight);
chunk = ChunkUtil.readChunkPacket(buffer, sectionBitMask, 0, groundUpContinuous, containsSkyLight);
// set position of the byte buffer, because of some reasons HyPixel makes some weird stuff and sends way to much 0 bytes. (~ 190k), thanks @pokechu22
buffer.setPosition(size + lastPos);
}

View File

@ -29,22 +29,15 @@ public class PacketEntityEquipment implements ClientboundPacket {
@Override
public boolean read(InByteBuffer buffer) {
if (buffer.getVersionId() < 7) {
entityId = buffer.readInt();
slots.put(InventorySlots.EntityInventorySlots.byId(buffer.readShort(), buffer.getVersionId()), buffer.readSlot());
return true;
}
entityId = buffer.readEntityId();
if (buffer.getVersionId() < 49) {
entityId = buffer.readVarInt();
slots.put(InventorySlots.EntityInventorySlots.byId(buffer.readShort(), buffer.getVersionId()), buffer.readSlot());
return true;
}
if (buffer.getVersionId() < 732) {
entityId = buffer.readVarInt();
slots.put(InventorySlots.EntityInventorySlots.byId(buffer.readVarInt(), buffer.getVersionId()), buffer.readSlot());
return true;
}
entityId = buffer.readVarInt();
boolean slotAvailable = true;
while (slotAvailable) {
int slotId = buffer.readByte();

View File

@ -36,7 +36,7 @@ public class PacketRespawn implements ClientboundPacket {
@Override
public boolean read(InByteBuffer buffer) {
if (buffer.getVersionId() < 718) {
if (buffer.getVersionId() < 108) {
if (buffer.getVersionId() < 47) { // ToDo: this should be 108 but wiki.vg is wrong. In 1.8 it is an int.
dimension = buffer.getConnection().getMapping().getDimensionById(buffer.readByte());
} else {
dimension = buffer.getConnection().getMapping().getDimensionById(buffer.readInt());

View File

@ -123,8 +123,8 @@ public class InByteBuffer {
return readByte() == 1;
}
public short[] readLEShorts(int num) {
short[] ret = new short[num];
public int[] readUnsignedLEShorts(int num) {
int[] ret = new int[num];
for (int i = 0; i < ret.length; i++) {
ret[i] = (short) (readByte() & 0xFF);
ret[i] |= (readByte() & 0xFF) << 8;

View File

@ -335,13 +335,8 @@ public class PacketHandler {
}
public void handle(PacketEntityVelocity pkg) {
Entity entity;
if (pkg.getEntityId() == connection.getPlayer().getEntity().getEntityId()) {
// that's us!
entity = connection.getPlayer().getEntity();
} else {
entity = connection.getPlayer().getWorld().getEntity(pkg.getEntityId());
}
Entity entity = connection.getPlayer().getWorld().getEntity(pkg.getEntityId());
if (entity == null) {
// thanks mojang
return;
@ -496,6 +491,7 @@ public class PacketHandler {
for (int i = 0; i < 4; i++) {
nbt.writeTag(String.format("Text%d", (i + 1)), new StringTag(pkg.getLines()[i].getLegacyText()));
}
// ToDo: handle sign updates
}
public void handle(PacketEntityAnimation pkg) {
@ -594,7 +590,7 @@ public class PacketHandler {
connection.fireEvent(new SingleSlotChangeEvent(connection, pkg));
if (pkg.getWindowId() == -1) {
// invalid window Id
// thanks mojang
// ToDo: what is windowId -1
return;
}
@ -648,9 +644,8 @@ public class PacketHandler {
case CREATE_UPDATE -> connection.getPlayer().getScoreboardManager().getObjective(pkg.getScoreName()).addScore(new ScoreboardScore(pkg.getItemName(), pkg.getScoreName(), pkg.getScoreValue()));
case REMOVE -> {
ScoreboardObjective objective = connection.getPlayer().getScoreboardManager().getObjective(pkg.getScoreName());
if (objective == null) {
Log.warn(String.format("Server tried to remove score witch was not created before (itemName=\"%s\", scoreName=\"%s\")!", pkg.getItemName(), pkg.getScoreName()));
} else {
if (objective != null) {
// thanks mojang
objective.removeScore(pkg.getItemName());
}
}

View File

@ -39,6 +39,8 @@ public final class ProtocolDefinition {
public static final int DEFAULT_BUFFER_SIZE = 4096;
public static final int NULL_BLOCK_ID = 0;
static {
// java does (why ever) not allow to directly assign a null
InetAddress temp;

View File

@ -23,10 +23,10 @@ public final class BitByte {
return ((in & mask) == mask);
}
public static byte getBitCount(short input) {
public static byte getBitCount(int input) {
byte ret = 0;
for (byte i = 0; i < Short.BYTES * 8; i++) { // bytes to bits
if (isBitSetShort(input, i)) {
if (isBitSet(input, i)) {
ret++;
}
}

View File

@ -27,7 +27,7 @@ import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
import java.util.concurrent.ConcurrentHashMap;
public final class ChunkUtil {
public static Chunk readChunkPacket(InByteBuffer buffer, short sectionBitMask, short addBitMask, boolean groundUpContinuous, boolean containsSkyLight) {
public static Chunk readChunkPacket(InByteBuffer buffer, int sectionBitMask, int addBitMask, boolean groundUpContinuous, boolean containsSkyLight) {
if (buffer.getVersionId() < 23) {
if (sectionBitMask == 0x00 && groundUpContinuous) {
// unload chunk
@ -95,15 +95,11 @@ public final class ChunkUtil {
return new Chunk(sectionMap);
}
if (buffer.getVersionId() < 62) { // ToDo: was this really changed in 62?
if (sectionBitMask == 0x00 && groundUpContinuous) {
// unload chunk
return null;
}
byte sections = BitByte.getBitCount(sectionBitMask);
int totalBlocks = RenderConstants.SECTION_HEIGHT * RenderConstants.SECTION_WIDTH * RenderConstants.SECTION_WIDTH * sections;
int halfBytes = totalBlocks / 2; // half bytes
short[] blockData = buffer.readLEShorts(totalBlocks); // blocks >>> 4, data & 0xF
int[] blockData = buffer.readUnsignedLEShorts(totalBlocks); // blocks >>> 4, data & 0xF
byte[] light = buffer.readBytes(halfBytes);
byte[] skyLight = null;
@ -113,6 +109,10 @@ public final class ChunkUtil {
if (groundUpContinuous) {
byte[] biomes = buffer.readBytes(RenderConstants.SECTION_WIDTH * RenderConstants.SECTION_WIDTH);
}
if (sectionBitMask == 0x00 && groundUpContinuous) {
// unload chunk
return null;
}
int arrayPos = 0;
ConcurrentHashMap<Byte, ChunkSection> sectionMap = new ConcurrentHashMap<>();
@ -125,9 +125,9 @@ public final class ChunkUtil {
for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) {
for (int nibbleX = 0; nibbleX < RenderConstants.SECTION_WIDTH; nibbleX++) {
int blockId = blockData[arrayPos] & 0xFFFF;
int blockId = blockData[arrayPos];
Block block = buffer.getConnection().getMapping().getBlockById(blockId);
if (block.equals(Blocks.nullBlock)) {
if (block == null || block.equals(Blocks.nullBlock)) {
arrayPos++;
continue;
}

View File

@ -85,7 +85,7 @@ public class AsyncTaskWorker {
} catch (Exception e) {
e.printStackTrace();
if (task.getImportance() == TaskImportance.REQUIRED) {
Log.fatal(String.format("Task %s (%s) failed: %s", task.getTaskName(), task.getTaskDescription(), e.getLocalizedMessage()));
Log.fatal(String.format("Task %s (%s) failed: %s", task.getTaskName(), task.getTaskDescription(), e.getMessage()));
if (exceptionRunnable != null) {
exceptionRunnable.onFatal(e);
}

View File

@ -4,7 +4,7 @@
"OFFLINE": "Offline",
"CONNECTING": "Verbinde...",
"ADD_SERVER_DIALOG_TITLE": "Server hinzufügen - Minosoft",
"ADD_SERVER_DIALOG_HEADER": "Bitte gib den Namen und die Serveradrese ein um fortzufahren",
"ADD_SERVER_DIALOG_HEADER": "Bitte gib den Namen und die Serveradresse ein um fortzufahren",
"ADD_SERVER_DIALOG_DEFAULT_SERVER_NAME": "Ein Minosoft Server",
"EDIT_SERVER_DIALOG_TITLE": "Server bearbeiten: {0} - Minosoft",
"EDIT_SERVER_DIALOG_HEADER": "Server bearbeiten",
@ -16,7 +16,7 @@
"BUTTON_ADD": "Hinzufügen",
"VERSION_AUTOMATIC": "Automatisch",
"FORCED_VERSION": "Erzwungene Version",
"SERVER_INFO_LAST_CONNECTION_EXCEPTION": "Letzer Verbindungsfehler",
"SERVER_INFO_LAST_CONNECTION_EXCEPTION": "Letzter Verbindungsfehler",
"SERVER_INFO_VERSION_UNKNOWN": "Unbekannt ({0})",
"SERVER_INFO_SLOTS_PLAYERS_ONLINE": "{0} / {1}",
"SERVER_INFO_REAL_SERVER_ADDRESS": "Reale Serveradresse",
@ -24,7 +24,7 @@
"SERVER_INFO_PLAYERS_ONLINE": "Spieler online",
"SERVER_INFO_MESSAGE_OF_THE_DAY": "MotD",
"SERVER_INFO_SERVER_MODDED_BRAND": "Serverart",
"SERVER_INFO_SERVER_MODDED_MOD_LIST": "Modliste",
"SERVER_INFO_SERVER_MODDED_MOD_LIST": "Mod liste",
"SESSIONS_DIALOG_TITLE": "Verbindungen - {0} - Minosoft",
"ACCOUNTS_ACTION_SELECT": "Auswählen",
"ACCOUNTS_ACTION_DELETE": "Löschen",
@ -51,7 +51,7 @@
"SESSIONS_MENU_DISCONNECT": "Trennen",
"SESSIONS_MENU_DISCONNECT_FROM_ALL": "...von allen",
"SETTINGS_TITLE": "Einstellungen - Minosoft",
"SETTINGS_GENERAL": "Allgemeim",
"SETTINGS_GENERAL": "Allgemein",
"SETTINGS_GENERAL_LOG_LEVEL": "Log Level",
"SETTINGS_DOWNLOAD": "Download",
"LOGIN_DIALOG_TITLE": "Anmelden - Minosoft",

View File

@ -10,6 +10,7 @@
"EDIT_SERVER_DIALOG_HEADER": "Edit the server",
"SERVER_NAME": "Server name",
"SERVER_ADDRESS": "Server address",
"SERVER_ADDRESS_INPUT_REQUIRED": "A server address is required",
"VERSION": "Version",
"BUTTON_SAVE": "Save",
"BUTTON_LOGIN": "Login",
@ -63,4 +64,4 @@
"MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_TITLE": "Manage accounts",
"MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_HEADER": "Are you sure?",
"MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_ERROR": "No account selected, Minosoft will exit."
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.TextFlow?>
<!--
~ Minosoft
~ Copyright (C) 2020 Moritz Zwerger
@ -16,25 +11,67 @@
~
~ This software is not affiliated with Mojang AB, the original developer of Minecraft.
-->
<AnchorPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:id="root" maxHeight="-Infinity" maxWidth="500.0" minHeight="-Infinity" minWidth="500.0" onMouseClicked="#clicked" prefWidth="500.0" fx:controller="de.bixilon.minosoft.gui.main.ServerListCell">
<ImageView fx:id="icon" fitHeight="100.0" fitWidth="100.0" layoutX="54.0" layoutY="108.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.topAnchor="5.0" />
<Label fx:id="serverName" layoutX="111.0" layoutY="14.0" maxWidth="200.0" minWidth="10.0" text="#Servername#" underline="true" AnchorPane.leftAnchor="110.0" AnchorPane.topAnchor="5.0">
<font>
<Font size="17.0" />
</font>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.TextFlow?>
<GridPane xmlns:fx="http://javafx.com/fxml/1" fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="580" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="de.bixilon.minosoft.gui.main.ServerListCell">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="ALWAYS" maxWidth="200.0" minWidth="10.0" prefWidth="150.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="ALWAYS"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="ALWAYS"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="ALWAYS"/>
</rowConstraints>
<ImageView fx:id="faviconField" fitHeight="100.0" fitWidth="100.0" pickOnBounds="true" preserveRatio="true" GridPane.columnSpan="3" GridPane.halignment="LEFT" GridPane.hgrow="ALWAYS" GridPane.rowSpan="3" GridPane.valignment="TOP" GridPane.vgrow="ALWAYS">
</ImageView>
<TextFlow fx:id="nameField" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.columnSpan="3">
<GridPane.margin>
<Insets left="15.0"/>
</GridPane.margin>
</TextFlow>
<TextFlow fx:id="motdField" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="1" GridPane.rowSpan="2">
<GridPane.margin>
<Insets left="15.0"/>
</GridPane.margin>
</TextFlow>
<Label fx:id="versionField" text="VERSION" textAlignment="RIGHT" GridPane.columnIndex="4" GridPane.halignment="RIGHT">
<GridPane.margin>
<Insets right="10.0"/>
</GridPane.margin>
</Label>
<Label fx:id="players" layoutX="408.0" layoutY="8.0" AnchorPane.rightAnchor="40.0" AnchorPane.topAnchor="5.0" />
<TextFlow fx:id="motd" layoutX="104.0" layoutY="49.0" maxWidth="320.0" AnchorPane.bottomAnchor="15.0" AnchorPane.leftAnchor="105.0" AnchorPane.rightAnchor="100.0" AnchorPane.topAnchor="40.0" />
<Label fx:id="version" layoutX="350.0" layoutY="8.0" text="#Version#" AnchorPane.rightAnchor="110.0" AnchorPane.topAnchor="5.0" />
<MenuButton fx:id="optionsMenu" layoutX="389.0" layoutY="81.0" mnemonicParsing="false" text="⋮" AnchorPane.bottomAnchor="0.0" AnchorPane.rightAnchor="0.0">
<Label fx:id="playersField" minHeight="-Infinity" minWidth="-Infinity" text="100000 / 100000" GridPane.columnIndex="5" GridPane.halignment="RIGHT">
<GridPane.margin>
<Insets right="15.0"/>
</GridPane.margin>
</Label>
<Label fx:id="brandField" text="BRAND" GridPane.columnIndex="5" GridPane.halignment="RIGHT" GridPane.rowIndex="1">
<GridPane.margin>
<Insets right="15.0"/>
</GridPane.margin>
</Label>
<MenuButton mnemonicParsing="false" text="⋮" GridPane.columnIndex="5" GridPane.halignment="RIGHT" GridPane.rowIndex="2">
<items>
<MenuItem fx:id="optionsConnect" disable="true" mnemonicParsing="false" onAction="#connect" text="-Connect-" />
<MenuItem fx:id="optionsShowInfo" mnemonicParsing="false" onAction="#showInfo" text="-Info-" />
<MenuItem fx:id="optionsEdit" mnemonicParsing="false" onAction="#edit" text="-Edit-" />
<MenuItem fx:id="optionsRefresh" mnemonicParsing="false" onAction="#refresh" text="-Refresh-" />
<MenuItem fx:id="optionsSessions" mnemonicParsing="false" onAction="#manageSessions" disable="true" text="-Sessions-" />
<MenuItem fx:id="optionsDelete" mnemonicParsing="false" style="-fx-text-fill: red" onAction="#delete" text="-Delete-" />
<MenuItem fx:id="optionsConnect" disable="true" mnemonicParsing="false" onAction="#connect" text="-Connect-"/>
<MenuItem fx:id="optionsShowInfo" mnemonicParsing="false" onAction="#showInfo" text="-Info-"/>
<MenuItem fx:id="optionsEdit" mnemonicParsing="false" onAction="#editServer" text="-Edit-"/>
<MenuItem fx:id="optionsRefresh" mnemonicParsing="false" onAction="#refresh" text="-Refresh-"/>
<MenuItem fx:id="optionsSessions" disable="true" mnemonicParsing="false" onAction="#manageSessions" text="-Sessions-"/>
<MenuItem fx:id="optionsDelete" mnemonicParsing="false" onAction="#delete" style="-fx-text-fill: red" text="-Delete-"/>
</items>
<GridPane.margin>
<Insets right="15.0"/>
</GridPane.margin>
</MenuButton>
<Label layoutX="464.0" layoutY="59.0" text="#Brand#" fx:id="serverBrand" AnchorPane.bottomAnchor="30.0" AnchorPane.rightAnchor="5.0" />
</AnchorPane>
<padding>
<Insets bottom="10.0" top="10.0"/>
</padding>
</GridPane>

View File

@ -1,7 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.input.KeyCodeCombination?>
<?import javafx.scene.layout.*?>
<!--
~ Minosoft
~ Copyright (C) 2020 Moritz Zwerger
@ -14,6 +11,9 @@
~
~ This software is not affiliated with Mojang AB, the original developer of Minecraft.
-->
<?import javafx.scene.control.*?>
<?import javafx.scene.input.KeyCodeCombination?>
<?import javafx.scene.layout.*?>
<VBox xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" prefHeight="400.0" prefWidth="640.0" fx:controller="de.bixilon.minosoft.gui.main.MainWindow">
<MenuBar VBox.vgrow="NEVER">
<Menu fx:id="menuFile" mnemonicParsing="false" text="-_File-">
@ -36,9 +36,9 @@
<MenuItem fx:id="menuAccountManage" mnemonicParsing="false" onAction="#manageAccounts" text="-Manage-" />
</Menu>
</MenuBar>
<AnchorPane VBox.vgrow="ALWAYS">
<ScrollPane fitToHeight="true" fitToWidth="true" layoutX="14.0" layoutY="14.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="500.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<BorderPane fx:id="serversPane" />
<AnchorPane VBox.vgrow="ALWAYS" styleClass="anchor-pane">
<ScrollPane fitToHeight="true" fitToWidth="true" layoutX="14.0" layoutY="14.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<BorderPane fx:id="serversPane"/>
</ScrollPane>
</AnchorPane>
</VBox>

View File

@ -1,7 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<!--
~ Minosoft
~ Copyright (C) 2020 Moritz Zwerger
@ -14,23 +11,29 @@
~
~ This software is not affiliated with Mojang AB, the original developer of Minecraft.
-->
<VBox xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" prefHeight="400.0" prefWidth="640.0" fx:controller="de.bixilon.minosoft.gui.main.SettingsWindow">
<TabPane prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE">
<?import com.jfoenix.controls.JFXComboBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.*?>
<VBox xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1" prefHeight="400.0" prefWidth="640.0" fx:controller="de.bixilon.minosoft.gui.main.SettingsWindow" styleClass="vbox">
<TabPane prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" styleClass="tab-pane">
<Tab fx:id="general" text="-General-">
<GridPane fx:id="tabGeneral" hgap="10" minHeight="0.0" minWidth="0.0" prefHeight="429.0" prefWidth="640.0" vgap="10">
<padding>
<Insets bottom="10" left="10" right="300" top="10" />
<Insets bottom="10" left="10" right="300" top="10"/>
</padding>
<columnConstraints>
<ColumnConstraints />
<ColumnConstraints />
<ColumnConstraints/>
<ColumnConstraints/>
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
</rowConstraints>
<Label fx:id="generalLogLevelLabel" text="-Log level-" />
<ComboBox fx:id="generalLogLevel" prefWidth="150.0" GridPane.columnIndex="1" />
<JFXComboBox fx:id="generalLogLevel" prefWidth="150.0" GridPane.columnIndex="1"/>
</GridPane>
</Tab>
<Tab disable="true" fx:id="download" text="Download">

View File

@ -0,0 +1,167 @@
* {
-primary-color: #448aff;
-primary-light-color: #83b9ff;
-primary-dark-color: #005ecb;
-secondary-color: #2c3746;
-secondary-light-color: #566171;
-secondary-dark-color: #03111f;
-primary-text-color: #000000;
-secondary-text-color: #ffffff;
-secondary-light-light-color: #868191;
}
.root {
-fx-background-color: -secondary-color;
-fx-text-fill: -secondary-text-color;
}
.jfx-button {
-jfx-button-type: RAISED;
-fx-background-color: -primary-color;
-fx-text-fill: -secondary-text-color;
}
.jfx-alert-content-container, .jfx-text-field {
-fx-background-color: -secondary-color;
-fx-text-fill: -secondary-text-color;
-fx-prompt-text-fill: -secondary-light-color;
}
.label {
-fx-text-fill: -secondary-text-color;
}
.jfx-combo-box {
-fx-background-color: -secondary-color;
-fx-text-fill: -secondary-text-color;
}
.combo-box .list-cell {
-fx-background: -secondary-color;
-fx-background-color: transparent;
-fx-text-fill: -secondary-text-color;
}
.combo-box-popup .list-view {
-fx-background-color: -secondary-color;
}
.combo-box-popup .list-view .list-cell:filled:selected, .combo-box-popup .list-view .list-cell:filled:selected:hover {
-fx-background: -primary-light-color;
-fx-background-color: -secondary-dark-color;
-fx-text-fill: -secondary-text-color;
}
.combo-box-popup .list-view .list-cell:filled:hover {
-fx-background-color: -secondary-light-color;
-fx-text-fill: -secondary-text-color;
}
.combo-box-base {
-fx-background-color: -secondary-color;
}
.jfx-progress-bar > .track {
-fx-background-color: -secondary-light-color;
}
.jfx-progress-bar > .bar, .jfx-progress-bar:indeterminate > .bar {
-fx-background-color: -primary-color;
}
.jfx-progress-bar > .secondary-bar,
.jfx-progress-bar:indeterminate > .secondary-bar {
-fx-background-color: -secondary-light-color;
}
.list-cell {
-fx-background-color: -secondary-color;
}
.list-cell:selected {
-fx-background-color: -primary-color;
}
.list-cell:filled:hover {
-fx-background-color: -primary-dark-color;
}
.menu-bar {
-fx-background-color: -secondary-color;
}
.menu-item {
-fx-background-color: -secondary-color;
-fx-text-fill: -secondary-text-color;
}
.menu-item:selected {
-fx-background-color: -primary-color;
}
.menu-item:hover {
-fx-background-color: -primary-dark-color;
}
.menu-item:disabled {
-fx-opacity: 80%;
}
.menu-button {
-fx-background-color: -secondary-light-color;
-fx-text-fill: -secondary-text-color;
}
.menu-bar .menu-button {
-fx-background-color: -secondary-color;
}
.menu-bar .menu-button:hover {
-fx-background-color: -secondary-light-color;
}
.menu-bar {
-fx-background-color: -secondary-color;
}
.context-menu {
-fx-background-color: -secondary-color;
}
.tab-pane, .tab, .tab-header-area .tab-header-background {
-fx-background-color: -secondary-color;
-fx-text-fill: -secondary-text-color;
}
.tab:selected {
-fx-background-color: -secondary-light-color;
}
.tab-label {
-fx-text-fill: -secondary-text-color;
}
.vbox {
-fx-background-color: -secondary-color;
-fx-text-fill: -secondary-text-color;
}
.anchor-pane {
-fx-background-color: -secondary-color;
}
.scroll-pane {
-fx-background-color: -secondary-color;
}
.scroll-pane:selected {
-fx-background-color: -secondary-color;
}
.jfx-password-field {
-fx-text-fill: -secondary-text-color;
}
.list-view {
-fx-background-color: -secondary-color;
}