293 lines
10 KiB
Java

package cz.jzitnik.game;
import cz.jzitnik.api.ApiService;
import cz.jzitnik.api.requests.PlayerNameRequest;
import cz.jzitnik.api.types.*;
import cz.jzitnik.api.types.Character;
import cz.jzitnik.game.interactions.Interactions;
import cz.jzitnik.utils.Cli;
import cz.jzitnik.utils.ConfigPathProvider;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.io.Console;
import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import com.fasterxml.jackson.databind.ObjectMapper;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;
@NoArgsConstructor
@Getter
public class Chronos {
private static final String IPV4_PATTERN =
"^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
private static boolean isValidIPv4(String ip) {
return ip.matches(IPV4_PATTERN);
}
private LocalData localData = new LocalData();
private ApiService apiService;
public boolean hasConfig() {
var config_path = ConfigPathProvider.getPath();
File file = new File(Path.of(config_path, "config.json").toString());
return file.exists();
}
public boolean hasUser() {
return localData.getUserSecret() != null;
}
public void loadData() throws IOException {
var config_path = ConfigPathProvider.getPath();
File file = new File(Path.of(config_path, "config.json").toString());
String content = Files.readString(file.toPath());
ObjectMapper objectMapper = new ObjectMapper();
try {
this.localData = objectMapper.readValue(content, LocalData.class);
} catch (Exception e) {
e.printStackTrace();
}
setupApi(localData.getServer());
}
private void setupApi(String baseUrl) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(JacksonConverterFactory.create(new ObjectMapper()))
.build();
this.apiService = retrofit.create(ApiService.class);
}
public void setup() throws IOException {
System.out.println("\n");
Cli.type("Nyní se budeme muset připojit na Chronos server. Zadejte prosím IP adresu serveru na kterém běží chronos server.\nNapř: 127.0.0.1");
Console console = System.console();
String ipaddr = null;
do {
ipaddr = console.readLine(ipaddr == null ? "Zadejte ip adresu serveru: " : "Zadejte platnou ip adresu serveru: ");
} while (!isValidIPv4(ipaddr));
Cli.info("Pokouším se připojit k serveru");
String baseUrl = "http://" + ipaddr + ":8080/";
setupApi(baseUrl);
try {
var response = apiService.status().execute().body();
if (response.getData().isEmpty() || !response.getData().get().equals("working")) {
Cli.error("Tento server pravděpodobně není Chronos server.");
setup();
return;
}
} catch (ConnectException e) {
Cli.error("Nastala chyba při připojování k serveru, zkuste to znovu");
setup();
return;
}
Cli.success("Server byl úspěšně nastaven");
this.localData.setServer(baseUrl);
this.localData.saveData();
}
public void createNewGame() throws IOException {
Cli.printHeader("Vytvoření hry");
Cli.info("Vytvářím novou hru");
var body = apiService.newGame().execute().body();
if (!Objects.requireNonNull(body).getSuccess()) {
System.err.println("Nastala chyba při vytváření hry!");
System.exit(1);
}
var data = body.getData().get();
localData.setGameKey(data.getGameKey());
Cli.success("Byla úspěšně vytvořena hra");
}
public void addUser() throws IOException {
Cli.printHeader("Vytvoření hráče");
Console console = System.console();
var name = console.readLine("Zadejte vaše jméno: ");
var newPlayerBody = apiService.newPlayer(localData.getGameKey(), new PlayerNameRequest(name)).execute().body();
if (!Objects.requireNonNull(newPlayerBody).getSuccess()) {
System.err.println("Nastala chyba při vytváření hráče!");
System.exit(1);
}
localData.setUserSecret(newPlayerBody.getData().get());
}
public void adminPanel() throws IOException {
Cli.printHeader("Čekání na připojení hráčů");
System.out.println();
Cli.center("Kód pro připojení:");
System.out.print(Cli.Colors.GREEN);
Cli.center(localData.getGameKey());
System.out.print(Cli.Colors.RESET);
Cli.center("(pomocí tohoto kódu se hráči můžou napojit)");
System.out.println("\nPo startu hry už se nemůžou napojit noví hráči!");
System.out.println("Stiskněte " + Cli.Colors.CYAN + "Enter" + Cli.Colors.RESET + " pro start hry...");
System.console().readLine();
localData.saveData();
apiService.startGame(localData.getUserSecret(), localData.getGameKey()).execute();
}
public void connectToExisting() throws IOException {
Console console = System.console();
Cli.printHeader("Připojení do hry");
System.out.println();
String code = console.readLine("Zadejte kod pro připojení: ");
var testGameKeyResponse = apiService.testGameKey(code).execute().body().getData().get();
switch (testGameKeyResponse) {
case INVALID_KEY -> {
Cli.error("Nebyla nalezena hra s tímto kódem!");
connectToExisting();
}
case GAME_STARTED -> {
Cli.error("Tato hra již začala!");
connectToExisting();
}
case MAXIUM_PLAYERS -> {
Cli.error("V této hře je již maximální počet hráčů!");
connectToExisting();
}
case WORKING -> localData.setGameKey(code);
}
}
public void waitForStart() throws IOException {
boolean started = false;
while (!started) {
var res = apiService.testGameKey(localData.getGameKey()).execute();
var data = res.body().getData().get();
started = data == TestGameKeyResponse.GAME_STARTED;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public void visit() throws IOException {
var res = apiService.getCurrentRoom(localData.getUserSecret()).execute();
var room = res.body().getData().get();
visit(room);
}
public void visit(Long roomId, boolean changeRoom) throws IOException {
if (changeRoom) {
apiService.moveToRoom(localData.getUserSecret(), roomId).execute();
}
visit();
}
public void visit(Room room) throws IOException {
System.out.println("\n");
if (room.getName().equals("Outside")) {
Cli.info("Nyní jste na náměstí.");
} else {
Cli.info("Nyní se nacházíte v " + Cli.Colors.BLUE + room.getName() + Cli.Colors.RESET + ".");
}
var items = room.getItems();
if (!items.isEmpty()) {
Cli.info("V místnosti se nachází: " + String.join(", ", items.stream().map(Item::toString).toList()));
var options = new String[] {"Vzít si itemy", "Nebrat si itemy"};
var selected = Cli.selectOptionIndex(Arrays.asList(options));
if (selected == 0) {
var response = apiService.takeItemsFromRoom(localData.getUserSecret()).execute();
var itemsGot = response.body().getData().get();
Cli.gotItems(itemsGot);
if (itemsGot.size() < items.size()) {
Cli.info("Některé itemy jste nemohl vzít, protože váš inventář je plný.");
}
}
}
System.out.println();
var characters = room.getCharacters();
if (characters.isEmpty()) {
Cli.type("V místnosti se nenachází jediná duše...");
} else {
talk(characters);
}
var responseRooms = apiService.getAllRooms(localData.getUserSecret()).execute();
var rooms = responseRooms.body().getData().get().stream().filter(rm -> !rm.getId().equals(room.getId())).toList();
System.out.println();
Cli.info("Nyni si vyberte do jaké místnosti chcete jít.");
int selectedIndex = Cli.selectOptionIndex(rooms.stream().map(Room::toString).toList());
visit(rooms.get(selectedIndex).getId(), true);
}
public void talk(List<Character> characters) throws IOException {
List<String> commands = new ArrayList<>(characters.stream().map(chachar -> "Promluvit si s " + chachar.getName()).toList());
commands.add("Přejít do jiné místnosti");
CommandPalette commandPalette = new CommandPalette(commands, apiService, localData.getUserSecret());
int selectedIndex = commandPalette.displayIndex();
if (selectedIndex == commands.size() - 1) {
// Přejít do jiné místnosti
return;
}
// Dangerous I would say but whatever
Character character = characters.get(selectedIndex);
System.out.println();
Cli.type(character, character.getDialog());
if (!character.getInventory().isEmpty()) {
var res = apiService.takeItems(getLocalData().getUserSecret(), character.getId()).execute();
var body = res.body().getData().get();
if (body == TakeItemsResponse.ALREADY_TAKEN) {
Cli.type(Cli.Colors.YELLOW + character.getName() + ": " + Cli.Colors.RESET + "Už jsem ti mé itemy dal. Už pro tebe nic nemám.");
} else {
Cli.gotItems(character.getInventory());
}
}
// Interact with the character if it is interactable
if (character.getInteraction() != null) {
Interactions.runInteraction(character, apiService, localData.getUserSecret());
}
// Refetch the characters
var res = apiService.getCurrentRoom(localData.getUserSecret()).execute();
var room = res.body().getData().get();
talk(room.getCharacters());
}
}