/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - Illarion e.V.
*
* Illarion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Illarion 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.
*/
package illarion.client.gui.controller;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.NiftyEventSubscriber;
import de.lessvoid.nifty.controls.*;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.input.NiftyInputEvent;
import de.lessvoid.nifty.input.NiftyStandardInputEvent;
import de.lessvoid.nifty.screen.KeyInputHandler;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;
import illarion.client.Game;
import illarion.client.IllaClient;
import illarion.client.Login;
import illarion.client.Servers;
import illarion.client.resources.SongFactory;
import illarion.client.util.AudioPlayer;
import illarion.client.util.Lang;
import org.illarion.engine.Engine;
import org.illarion.engine.sound.Music;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* This is the screen controller that takes care of displaying the login screen.
*
* @author Martin Karing <nitram@illarion.org>
*/
public final class LoginScreenController implements ScreenController, KeyInputHandler {
/**
* This is the logging instance for this class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(LoginScreenController.class);
/**
* The engine that is used in this game instance.
*/
@Nonnull
private final Engine engine;
/**
* The game that is the parent of this class.
*/
@Nonnull
private final Game game;
/**
* The last error code that was received from the server. This will be {@code 0} in case there was no error or
* any larger value in case there is a error.
*/
private int lastErrorCode;
/**
* The text field that contains the login name.
*/
@Nonnull
private TextField nameTxt;
/**
* The instance of the Nifty-GUI that was bound to this controller.
*/
private Nifty nifty;
/**
* The text field that contains the password.
*/
@Nonnull
private TextField passwordTxt;
/**
* The generated popup that is shown in case a error occurred during the login.
*/
private Element popupError;
/**
* This variable is set true in case the popup is visible.
*/
private boolean popupIsVisible;
/**
* The generated popup that is shown while the client is busy fetching the characters from the server.
*/
private Element popupReceiveChars;
/**
* This value is set {@code true} in case a new response was received from the server that needs to be processed
* upon the next update loop.
*/
private boolean receivedLoginResponse;
/**
* The checkbox that is ticked in case the password is supposed to be saved.
*/
@Nullable
private CheckBox savePassword;
/**
* The screen this controller is a part of.
*/
private Screen screen;
/**
* The drop down box is used to select a server.
*/
@Nullable
private DropDown<String> server;
public LoginScreenController(@Nonnull Game game, @Nonnull Engine engine) {
this.game = game;
this.engine = engine;
}
@Override
public void bind(@Nonnull Nifty nifty, @Nonnull Screen screen) {
this.nifty = nifty;
this.screen = screen;
nameTxt = screen.findNiftyControl("nameTxt", TextField.class);
passwordTxt = screen.findNiftyControl("passwordTxt", TextField.class);
savePassword = screen.findNiftyControl("savePassword", CheckBox.class);
nameTxt.getElement().addInputHandler(this);
passwordTxt.getElement().addInputHandler(this);
Login login = Login.getInstance();
login.restoreServer();
restoreLoginData();
if (IllaClient.DEFAULT_SERVER == Servers.Illarionserver) {
@Nullable Element serverPanel = screen.findElementById("serverPanel");
if (serverPanel != null) {
serverPanel.hide();
} else {
LOGGER.error("Failed to find server panel on the screen.");
}
} else {
//noinspection unchecked
server = screen.findNiftyControl("server", DropDown.class);
if (server != null) {
server.addItem("${login-bundle.server.develop}");
server.addItem("${login-bundle.server.test}");
server.addItem("${login-bundle.server.game}");
server.addItem("${login-bundle.server.custom}");
server.selectItemByIndex(IllaClient.getCfg().getInteger("server"));
} else {
LOGGER.error("Failed to find server drop down on the login screen.");
}
}
popupError = nifty.createPopup("loginError");
popupReceiveChars = nifty.createPopup("receivingCharacters");
nifty.subscribeAnnotations(this);
}
private void restoreLoginData() {
Login login = Login.getInstance();
login.restoreLoginData();
nameTxt.setText(login.getLoginName());
passwordTxt.setText(login.getPassword());
savePassword.setChecked(login.getStorePassword());
}
@Override
public void onStartScreen() {
AudioPlayer audioPlayer = AudioPlayer.getInstance();
audioPlayer.initAudioPlayer(engine.getSounds());
Music illarionTheme = SongFactory.getInstance().getSong(2, engine.getAssets().getSoundsManager());
audioPlayer.setLastMusic(illarionTheme);
if (IllaClient.getCfg().getBoolean("musicOn")) {
if (illarionTheme != null) {
if (!audioPlayer.isCurrentMusic(illarionTheme)) {
// may be null in case OpenAL is not working
audioPlayer.playMusic(illarionTheme);
}
}
}
if (nameTxt.getDisplayedText().isEmpty()) {
nameTxt.setFocus();
} else {
passwordTxt.setFocus();
}
}
@Override
public void onEndScreen() {
}
@Override
public boolean keyEvent(@Nonnull NiftyInputEvent inputEvent) {
if (inputEvent == NiftyStandardInputEvent.SubmitText) {
if (popupIsVisible) {
closeError();
} else {
login();
}
return true;
}
return false;
}
/**
* This function is called in case the close button in the error popup is clicked.
*
* @param topic the topic of the event
* @param event the data of the event
*/
@NiftyEventSubscriber(id = "errorButtonClose")
public void onCloseErrorButtonClicked(String topic, ButtonClickedEvent event) {
closeError();
}
/**
* This function closes the error popup that is displayed in case the login to the server failed.
*/
private void closeError() {
popupIsVisible = false;
nifty.closePopup(popupError.getId(), () -> nameTxt.getElement().setFocus());
}
/**
* This function is called in case the credits button is clicked.
*
* @param topic the topic of the event
* @param event the data of the event
*/
@NiftyEventSubscriber(id = "creditsBtn")
public void onCreditsButtonClicked(String topic, ButtonClickedEvent event) {
nifty.gotoScreen("creditsStart");
}
/**
* This function is called in case the exit button is clicked.
*
* @param topic the topic of the event
* @param event the data of the event
*/
@NiftyEventSubscriber(id = "exitBtn")
public void onExitButtonClicked(String topic, ButtonClickedEvent event) {
IllaClient.ensureExit();
}
/**
* This function is called in case the login button is clicked.
*
* @param topic the topic of the event
* @param event the data of the event
*/
@NiftyEventSubscriber(id = "loginBtn")
public void onLoginButtonClicked(String topic, ButtonClickedEvent event) {
login();
}
/**
* This function triggers the login process. It will request the character list of the player from the server.
*/
private void login() {
nifty.showPopup(screen, popupReceiveChars.getId(), null);
Login login = Login.getInstance();
login.setLoginData(nameTxt.getRealText(), passwordTxt.getRealText());
if (server != null) {
login.applyServerByKey(server.getSelectedIndex());
} else {
login.setServer(Servers.Illarionserver);
}
login.storeData(savePassword.isChecked());
if (login.isCharacterListRequired()) {
login.requestCharacterList(errorCode -> {
lastErrorCode = errorCode;
receivedLoginResponse = true;
nifty.closePopup(popupReceiveChars.getId());
});
} else {
engine.getSounds().stopMusic(15);
game.enterState(Game.STATE_LOADING);
}
}
/**
* This function is called in case the option button is clicked.
*
* @param topic the topic of the event
* @param event the data of the event
*/
@NiftyEventSubscriber(id = "optionBtn")
public void onOptionsButtonClicked(String topic, ButtonClickedEvent event) {
options();
}
/**
* This function switches the screen to the option screen.
*/
private void options() {
nifty.gotoScreen("options");
}
@NiftyEventSubscriber(id = "server")
public void onServerChanged(@Nonnull String topic, @Nonnull DropDownSelectionChangedEvent<String> data) {
Login.getInstance().applyServerByKey(server.getSelectedIndex());
restoreLoginData();
}
@NiftyEventSubscriber(id = "server")
public void onServerChangedEvent(String topic, @Nonnull DropDownSelectionChangedEvent<String> event) {
if (event.getSelectionItemIndex() == 4) {
nameTxt.setText(IllaClient.getCfg().getString("testserverLogin"));
passwordTxt.setText(IllaClient.getCfg().getString("testserverPass"));
} else {
Login login = Login.getInstance();
nameTxt.setText(login.getLoginName());
passwordTxt.setText(login.getPassword());
}
}
/**
* This function has to be called at every update loop of Nifty. It will ensure that all updates are processed
* synchronized to the Nifty-GUI update loop.
*/
public void update() {
if (!receivedLoginResponse || (nifty.getCurrentScreen() != screen)) {
return;
}
receivedLoginResponse = false;
if (lastErrorCode > 0) {
Label errorText = popupError.findNiftyControl("#errorText", Label.class);
errorText.setText(getErrorText(lastErrorCode));
nifty.showPopup(screen, popupError.getId(), popupError.findElementById("#closeButton"));
popupIsVisible = true;
} else {
@Nullable Screen charSelectScreen = nifty.getScreen("charSelect");
if (charSelectScreen == null) {
throw new IllegalStateException("The character select screen was not found! This is bad.");
}
@Nonnull ScreenController charScreenController = charSelectScreen.getScreenController();
if (charScreenController instanceof CharScreenController) {
((CharScreenController) charScreenController).fillMyListBox();
}
nifty.gotoScreen(charSelectScreen.getScreenId());
}
}
/**
* Get the text that describes a error code.
*
* @param error the error code
* @return the localized text that describes the error for the player
*/
public static String getErrorText(int error) {
return Lang.getMsg("login.error." + Integer.toString(error));
}
}