From 6786eb1be828c6b29161640f2821d018afb7c46b Mon Sep 17 00:00:00 2001 From: jzitnik-dev Date: Fri, 20 Dec 2024 19:00:14 +0100 Subject: [PATCH] feat: One step ahead for interactions implementation --- .../chronos/controllers/RoomController.java | 11 +++ .../chronos/controllers/StatusController.java | 2 - .../jzitnik/chronos/entities/Character.java | 4 ++ .../jzitnik/chronos/entities/Interaction.java | 27 ++++++++ .../main/java/cz/jzitnik/api/ApiService.java | 7 ++ .../java/cz/jzitnik/api/types/Character.java | 2 + .../cz/jzitnik/api/types/InteractionData.java | 16 +++++ .../main/java/cz/jzitnik/game/Chronos.java | 68 ++++++++++++++++--- .../game/interactions/Interactions.java | 13 ++++ .../src/main/java/cz/jzitnik/utils/Cli.java | 63 +++++++++++++++++ 10 files changed, 202 insertions(+), 11 deletions(-) create mode 100644 backend/src/main/java/cz/jzitnik/chronos/entities/Interaction.java create mode 100644 frontend/src/main/java/cz/jzitnik/api/types/InteractionData.java create mode 100644 frontend/src/main/java/cz/jzitnik/game/interactions/Interactions.java diff --git a/backend/src/main/java/cz/jzitnik/chronos/controllers/RoomController.java b/backend/src/main/java/cz/jzitnik/chronos/controllers/RoomController.java index cf374b6..ced8013 100644 --- a/backend/src/main/java/cz/jzitnik/chronos/controllers/RoomController.java +++ b/backend/src/main/java/cz/jzitnik/chronos/controllers/RoomController.java @@ -10,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.List; @CrossOrigin(origins = "*", maxAge = 3600) @RestController @@ -24,6 +25,16 @@ public class RoomController { @Autowired private GameService gameService; + @GetMapping + @CheckUser + public ResponseEntity, Error>> getAllRooms(@RequestParam("playerKey") String playerKey) { + var player = playerRepository.findByPlayerKey(playerKey).get(); + + return ResponseEntity.ok( + UnifiedResponse.success(player.getGame().getRooms()) + ); + } + @GetMapping("/current_room") @CheckUser public ResponseEntity> getCurrentRoom(@RequestParam("playerKey") String playerKey) { diff --git a/backend/src/main/java/cz/jzitnik/chronos/controllers/StatusController.java b/backend/src/main/java/cz/jzitnik/chronos/controllers/StatusController.java index 6650a99..8aa5e56 100644 --- a/backend/src/main/java/cz/jzitnik/chronos/controllers/StatusController.java +++ b/backend/src/main/java/cz/jzitnik/chronos/controllers/StatusController.java @@ -10,8 +10,6 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/status") public class StatusController { - - // Don't decode this base64, just go to /status endpoint, you'll be surprised @GetMapping public UnifiedResponse getStatus() { return UnifiedResponse.success("working"); diff --git a/backend/src/main/java/cz/jzitnik/chronos/entities/Character.java b/backend/src/main/java/cz/jzitnik/chronos/entities/Character.java index f5721b1..d0d729f 100644 --- a/backend/src/main/java/cz/jzitnik/chronos/entities/Character.java +++ b/backend/src/main/java/cz/jzitnik/chronos/entities/Character.java @@ -42,6 +42,10 @@ public class Character { @JsonIgnore private List playersWhoSaw = new ArrayList<>(); + @OneToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "interaction_data_id", referencedColumnName = "id") + private cz.jzitnik.chronos.entities.Interaction interactionData; + private String dialog; public Character(String name, Room room, String dialog) { diff --git a/backend/src/main/java/cz/jzitnik/chronos/entities/Interaction.java b/backend/src/main/java/cz/jzitnik/chronos/entities/Interaction.java new file mode 100644 index 0000000..f0bbf4f --- /dev/null +++ b/backend/src/main/java/cz/jzitnik/chronos/entities/Interaction.java @@ -0,0 +1,27 @@ +package cz.jzitnik.chronos.entities; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@Setter +@NoArgsConstructor +public class Interaction { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "start_text") + private String startText; + + @Column(name = "interacted_with_text") + private String interactedWithText; + + @OneToOne(mappedBy = "interactionData") + @JsonIgnore + private Character character; +} diff --git a/frontend/src/main/java/cz/jzitnik/api/ApiService.java b/frontend/src/main/java/cz/jzitnik/api/ApiService.java index 44cde47..63d1718 100644 --- a/frontend/src/main/java/cz/jzitnik/api/ApiService.java +++ b/frontend/src/main/java/cz/jzitnik/api/ApiService.java @@ -12,6 +12,8 @@ import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.Query; +import java.util.List; + public interface ApiService { @GET("status") Call> status(); @@ -36,6 +38,11 @@ public interface ApiService { @Query("gameKey") String gameKey ); + @GET("game/rooms") + Call, Error>> getAllRooms( + @Query("playerKey") String playerKey + ); + @GET("game/rooms/current_room") Call> getCurrentRoom( @Query("playerKey") String playerKey diff --git a/frontend/src/main/java/cz/jzitnik/api/types/Character.java b/frontend/src/main/java/cz/jzitnik/api/types/Character.java index 09ab031..f0a5ab6 100644 --- a/frontend/src/main/java/cz/jzitnik/api/types/Character.java +++ b/frontend/src/main/java/cz/jzitnik/api/types/Character.java @@ -21,4 +21,6 @@ public class Character { private boolean interactedWith; private String dialog; + + private InteractionData interactionData; } diff --git a/frontend/src/main/java/cz/jzitnik/api/types/InteractionData.java b/frontend/src/main/java/cz/jzitnik/api/types/InteractionData.java new file mode 100644 index 0000000..0a49a4d --- /dev/null +++ b/frontend/src/main/java/cz/jzitnik/api/types/InteractionData.java @@ -0,0 +1,16 @@ +package cz.jzitnik.api.types; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class InteractionData { + private Long id; + + private String startText; + + private String interactedWithText; +} diff --git a/frontend/src/main/java/cz/jzitnik/game/Chronos.java b/frontend/src/main/java/cz/jzitnik/game/Chronos.java index 93e89ba..8a01649 100644 --- a/frontend/src/main/java/cz/jzitnik/game/Chronos.java +++ b/frontend/src/main/java/cz/jzitnik/game/Chronos.java @@ -6,6 +6,7 @@ import cz.jzitnik.api.types.Character; import cz.jzitnik.api.types.Room; import cz.jzitnik.api.types.TakeItemsResponse; import cz.jzitnik.api.types.TestGameKeyResponse; +import cz.jzitnik.game.interactions.Interactions; import cz.jzitnik.utils.Cli; import cz.jzitnik.utils.ConfigPathProvider; import lombok.Getter; @@ -17,13 +18,13 @@ import java.io.IOException; import java.net.ConnectException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import com.fasterxml.jackson.databind.ObjectMapper; import retrofit2.Retrofit; import retrofit2.converter.jackson.JacksonConverterFactory; -import retrofit2.http.GET; @NoArgsConstructor @Getter @@ -202,17 +203,22 @@ public class Chronos { public void visit() throws IOException { var res = apiService.getCurrentRoom(localData.getUserSecret()).execute(); var room = res.body().getData().get(); - visit(room, false); + visit(room); } - public void visit(Room room) throws IOException { - visit(room, true); - } - public void visit(Room room, boolean changeRoom) throws IOException { + public void visit(Long roomId, boolean changeRoom) throws IOException { if (changeRoom) { - apiService.moveToRoom(localData.getUserSecret(), room.getId()); + apiService.moveToRoom(localData.getUserSecret(), roomId).execute(); } - Cli.info("Nyní se nacházíte v místnosti " + room.getName()); + visit(); + } + public void visit(Room room) throws IOException { + System.out.println("\n"); + if (room.getName().equals("Outside")) { + Cli.info("Nyní jste venku"); + } else { + Cli.info("Nyní se nacházíte v místnosti " + room.getName()); + } if (room.getCharacters().isEmpty()) { Cli.type("V místnosti je prázno... Ani jedna duše."); @@ -220,8 +226,52 @@ public class Chronos { for (Character character : room.getCharacters()) { talkWith(character); } + + if (!room.getCharacters().isEmpty()) { + interactWithAny(room.getCharacters()); + } + + 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::getName).toList()); + + visit(rooms.get(selectedIndex).getId(), true); } + private void interactWithAny(List characters) throws IOException { + if (characters.stream().anyMatch(character -> character.getInteraction() != null)) { + List interactablePostavy = characters.stream().filter( + character -> character.getInteraction() != null && + !character.isInteractedWith() + ).toList(); + + if (interactablePostavy.isEmpty()) { + return; + } + + List options = new ArrayList<>(interactablePostavy.stream().map(Character::getName).toList()); + options.add("Neinteragovat s nikým"); + + Cli.info("Můžete interagovat s následujícími postavami:"); + int selectedIndex = Cli.selectOptionIndex(options); + + if (selectedIndex == options.size() - 1) { + return; + } + + var character = characters.get(selectedIndex); + + Interactions.runInteraction(character); + + var currentRoom = apiService.getCurrentRoom(localData.getUserSecret()).execute().body().getData(); + + interactWithAny(currentRoom.get().getCharacters().stream().filter(chachar -> !chachar.isInteractedWith()).toList()); + } + } public void talkWith(Character character) throws IOException { Cli.type("V místnosti je " + character.getName()); diff --git a/frontend/src/main/java/cz/jzitnik/game/interactions/Interactions.java b/frontend/src/main/java/cz/jzitnik/game/interactions/Interactions.java new file mode 100644 index 0000000..72de356 --- /dev/null +++ b/frontend/src/main/java/cz/jzitnik/game/interactions/Interactions.java @@ -0,0 +1,13 @@ +package cz.jzitnik.game.interactions; + +import cz.jzitnik.api.types.Character; + +public class Interactions { + public static void runInteraction(Character character) { + switch (character.getInteraction()) { + case Farmer -> { + System.out.println("Inplement interaction with farmer"); + } + } + } +} diff --git a/frontend/src/main/java/cz/jzitnik/utils/Cli.java b/frontend/src/main/java/cz/jzitnik/utils/Cli.java index 854ca9d..0988219 100644 --- a/frontend/src/main/java/cz/jzitnik/utils/Cli.java +++ b/frontend/src/main/java/cz/jzitnik/utils/Cli.java @@ -1,5 +1,6 @@ package cz.jzitnik.utils; +import java.util.List; import java.util.Scanner; public class Cli { @@ -169,4 +170,66 @@ public class Cli { } } } + + /** + * Displays a menu with the provided options and returns the selected option. + * + * @param options Array of options to display to the user. + * @return The selected option as a String. + */ + public static int selectOptionIndex(String[] options) { + Scanner scanner = new Scanner(System.in); + int choice; + + System.out.println("Vyberte možnost:"); + for (int i = 0; i < options.length; i++) { + System.out.println((i + 1) + ". " + options[i]); + } + + while (true) { + System.out.print("Vložte číslo možnosti: "); + if (scanner.hasNextInt()) { + choice = scanner.nextInt(); + if (choice >= 1 && choice <= options.length) { + return choice - 1; + } else { + System.out.println("Neplatní možnost, vyberte číslo mezi 1 a " + options.length); + } + } else { + System.out.println("Neplatný vstup, vložte číslo."); + scanner.next(); + } + } + } + + /** + * Displays a menu with the provided options and returns the selected option. + * + * @param options Array of options to display to the user. + * @return The selected option as a String. + */ + public static int selectOptionIndex(List options) { + Scanner scanner = new Scanner(System.in); + int choice; + + System.out.println("Vyberte možnost:"); + for (int i = 0; i < options.size(); i++) { + System.out.println((i + 1) + ". " + options.get(i)); + } + + while (true) { + System.out.print("Vložte číslo možnosti: "); + if (scanner.hasNextInt()) { + choice = scanner.nextInt(); + if (choice >= 1 && choice <= options.size()) { + return choice - 1; + } else { + System.out.println("Neplatní možnost, vyberte číslo mezi 1 a " + options.size()); + } + } else { + System.out.println("Neplatný vstup, vložte číslo."); + scanner.next(); + } + } + } }