feat: Implemented moving items between players
This commit is contained in:
parent
5dc191c842
commit
d8969df0d3
@ -6,7 +6,7 @@ Jednoduchá multiplayer hra napsaná v Javě.
|
|||||||
|
|
||||||
Backend je napsaný v Javě pomocí Spring. Jedná se o jednoduchý HTTP server.
|
Backend je napsaný v Javě pomocí Spring. Jedná se o jednoduchý HTTP server.
|
||||||
|
|
||||||
**Ano jsem debil, využít relační databázi nebyl rozhodě dobrý nápad. Došlo mi to uprostřed programování a už se mi nechtělo vracet zpět.**
|
**Ano jsem debil, využít relační databázi nebyl rozhodně dobrý nápad. Došlo mi to uprostřed programování a už se mi nechtělo vracet zpět.**
|
||||||
|
|
||||||
### Enviromental variables
|
### Enviromental variables
|
||||||
|
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
package cz.jzitnik.chronos.controllers;
|
package cz.jzitnik.chronos.controllers;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import cz.jzitnik.chronos.entities.Item;
|
import cz.jzitnik.chronos.entities.Item;
|
||||||
import cz.jzitnik.chronos.entities.Message;
|
import cz.jzitnik.chronos.entities.Message;
|
||||||
import cz.jzitnik.chronos.entities.MessageType;
|
import cz.jzitnik.chronos.entities.MessageType;
|
||||||
import cz.jzitnik.chronos.entities.Player;
|
import cz.jzitnik.chronos.entities.Player;
|
||||||
|
import cz.jzitnik.chronos.payload.errors.FullInventoryError;
|
||||||
import cz.jzitnik.chronos.payload.errors.ItemNotUsableException;
|
import cz.jzitnik.chronos.payload.errors.ItemNotUsableException;
|
||||||
import cz.jzitnik.chronos.payload.errors.NotFoundError;
|
import cz.jzitnik.chronos.payload.errors.NotFoundError;
|
||||||
import cz.jzitnik.chronos.payload.requests.PlayerNameRequest;
|
import cz.jzitnik.chronos.payload.requests.PlayerNameRequest;
|
||||||
import cz.jzitnik.chronos.payload.responses.InventoryFullResponse;
|
import cz.jzitnik.chronos.payload.responses.InventoryFullResponse;
|
||||||
|
import cz.jzitnik.chronos.payload.responses.ItemMoveMessageResponse;
|
||||||
import cz.jzitnik.chronos.payload.responses.UnifiedResponse;
|
import cz.jzitnik.chronos.payload.responses.UnifiedResponse;
|
||||||
import cz.jzitnik.chronos.repository.GameRepository;
|
import cz.jzitnik.chronos.repository.GameRepository;
|
||||||
import cz.jzitnik.chronos.repository.ItemRepository;
|
import cz.jzitnik.chronos.repository.ItemRepository;
|
||||||
@ -19,6 +23,8 @@ import org.springframework.http.HttpStatus;
|
|||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@CrossOrigin(origins = "*", maxAge = 3600)
|
@CrossOrigin(origins = "*", maxAge = 3600)
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/game/players")
|
@RequestMapping("/game/players")
|
||||||
@ -116,4 +122,58 @@ public class PlayerController {
|
|||||||
|
|
||||||
return ResponseEntity.ok(UnifiedResponse.success(item));
|
return ResponseEntity.ok(UnifiedResponse.success(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
@CheckUser
|
||||||
|
public ResponseEntity<UnifiedResponse<List<Player>, Error>> getAllPlayers(@RequestParam String playerKey) {
|
||||||
|
var player = playerRepository.findByPlayerKey(playerKey).get();
|
||||||
|
var game = player.getGame();
|
||||||
|
|
||||||
|
var players = game.getPlayers();
|
||||||
|
|
||||||
|
return ResponseEntity.ok(UnifiedResponse.success(players));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/send_item")
|
||||||
|
@CheckUser
|
||||||
|
public ResponseEntity<UnifiedResponse<Object, Error>> sendItem(@RequestParam String playerKey, @RequestParam Long itemId, @RequestParam Long playerId) {
|
||||||
|
var player = playerRepository.findByPlayerKey(playerKey).get();
|
||||||
|
|
||||||
|
var player2Optional = playerRepository.findById(playerId);
|
||||||
|
if (player2Optional.isEmpty()) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(UnifiedResponse.failure(new NotFoundError("Player with id " + playerId + " was not found!")));
|
||||||
|
}
|
||||||
|
var player2 = player2Optional.get();
|
||||||
|
|
||||||
|
var itemOptional = itemRepository.findById(itemId);
|
||||||
|
if (itemOptional.isEmpty()) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(UnifiedResponse.failure(new NotFoundError("Item with id " + itemId + " was not found!")));
|
||||||
|
}
|
||||||
|
var item = itemOptional.get();
|
||||||
|
|
||||||
|
if (item.getOwner() == null || !item.getOwner().getId().equals(player.getId())) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(UnifiedResponse.failure(new Error("You don't own this item!")));
|
||||||
|
}
|
||||||
|
if (player.getInventorySize() - player.getInventory().size() == 0) {
|
||||||
|
// Inventory is full
|
||||||
|
return ResponseEntity.status(HttpStatus.CONFLICT).body(UnifiedResponse.failure(new FullInventoryError("Player has full inventory!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
item.setOwner(player2);
|
||||||
|
itemRepository.save(item);
|
||||||
|
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
try {
|
||||||
|
var json = objectMapper.writeValueAsString(new ItemMoveMessageResponse(item.getItemType(), player2.getName()));
|
||||||
|
|
||||||
|
var message = new Message(player, json, MessageType.ITEM_MOVED);
|
||||||
|
|
||||||
|
player.getMessages().add(message);
|
||||||
|
playerRepository.save(player);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(UnifiedResponse.success(null));
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,6 @@ public enum MessageType {
|
|||||||
LOST_ITEM,
|
LOST_ITEM,
|
||||||
ITEM_USED,
|
ITEM_USED,
|
||||||
KEY_FRAGMENT_HANDED_OVER,
|
KEY_FRAGMENT_HANDED_OVER,
|
||||||
|
ITEM_MOVED,
|
||||||
JOINED,
|
JOINED,
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package cz.jzitnik.chronos.payload.errors;
|
||||||
|
|
||||||
|
public class FullInventoryError extends Error {
|
||||||
|
public FullInventoryError(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package cz.jzitnik.chronos.payload.responses;
|
||||||
|
|
||||||
|
import cz.jzitnik.chronos.entities.ItemType;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public class ItemMoveMessageResponse {
|
||||||
|
private ItemType itemType;
|
||||||
|
private String playerToName;
|
||||||
|
}
|
@ -138,4 +138,16 @@ public interface ApiService {
|
|||||||
Call<UnifiedResponse<GameWonResponse, Error>> gameWon(
|
Call<UnifiedResponse<GameWonResponse, Error>> gameWon(
|
||||||
@Query("playerKey") String playerKey
|
@Query("playerKey") String playerKey
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@GET("game/players")
|
||||||
|
Call<UnifiedResponse<List<Player>, Error>> getAllPlayers(
|
||||||
|
@Query("playerKey") String playerKey
|
||||||
|
);
|
||||||
|
|
||||||
|
@POST("game/players/send_item")
|
||||||
|
Call<UnifiedResponse<Object, Error>> sendItem(
|
||||||
|
@Query("playerKey") String playerKey,
|
||||||
|
@Query("itemId") Long itemId,
|
||||||
|
@Query("playerId") Long playerId
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package cz.jzitnik.api.responses;
|
||||||
|
|
||||||
|
import cz.jzitnik.api.types.ItemType;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class ItemMoveMessageResponse {
|
||||||
|
private ItemType itemType;
|
||||||
|
private String playerToName;
|
||||||
|
}
|
@ -3,6 +3,7 @@ package cz.jzitnik.api.types;
|
|||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import cz.jzitnik.api.ApiService;
|
import cz.jzitnik.api.ApiService;
|
||||||
|
import cz.jzitnik.api.responses.ItemMoveMessageResponse;
|
||||||
import cz.jzitnik.utils.Cli;
|
import cz.jzitnik.utils.Cli;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
@ -85,6 +86,17 @@ public class Message {
|
|||||||
yield "Hráč " + Cli.Colors.BLUE + author.getName() + Cli.Colors.RESET + " využil item unknown.";
|
yield "Hráč " + Cli.Colors.BLUE + author.getName() + Cli.Colors.RESET + " využil item unknown.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case ITEM_MOVED -> {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
try {
|
||||||
|
var data = objectMapper.readValue(content, ItemMoveMessageResponse.class);
|
||||||
|
|
||||||
|
yield "Hráč " + Cli.Colors.BLUE + author.getName() + Cli.Colors.RESET + " dal " + Cli.Colors.BLUE + data.getItemType() + Cli.Colors.RESET + " hráči " + Cli.Colors.BLUE + data.getPlayerToName() + Cli.Colors.RESET + ".";
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
yield "Hráč " + Cli.Colors.BLUE + author.getName() + Cli.Colors.RESET + " dal neznámý item neznámému hráči.";
|
||||||
|
}
|
||||||
|
}
|
||||||
case KEY_FRAGMENT_HANDED_OVER -> "Hráč " + Cli.Colors.BLUE + author.getName() + Cli.Colors.RESET + " odevzdal " + Cli.Colors.BLUE + "Fragment klíče" + Cli.Colors.RESET + ".";
|
case KEY_FRAGMENT_HANDED_OVER -> "Hráč " + Cli.Colors.BLUE + author.getName() + Cli.Colors.RESET + " odevzdal " + Cli.Colors.BLUE + "Fragment klíče" + Cli.Colors.RESET + ".";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,6 @@ public enum MessageType {
|
|||||||
LOST_ITEM,
|
LOST_ITEM,
|
||||||
ITEM_USED,
|
ITEM_USED,
|
||||||
KEY_FRAGMENT_HANDED_OVER,
|
KEY_FRAGMENT_HANDED_OVER,
|
||||||
|
ITEM_MOVED,
|
||||||
JOINED,
|
JOINED,
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import lombok.Setter;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ public class CommandPalette {
|
|||||||
USER_PROFILE,
|
USER_PROFILE,
|
||||||
CHAT_OPEN,
|
CHAT_OPEN,
|
||||||
CHAT_SEND,
|
CHAT_SEND,
|
||||||
|
PLAYER_LIST_OPEN,
|
||||||
CHECK_WINNABLE,
|
CHECK_WINNABLE,
|
||||||
EXIT,
|
EXIT,
|
||||||
}
|
}
|
||||||
@ -68,7 +70,7 @@ public class CommandPalette {
|
|||||||
|
|
||||||
var configPath = ConfigPathProvider.getPath();
|
var configPath = ConfigPathProvider.getPath();
|
||||||
|
|
||||||
File file = new File(configPath);
|
File file = new File(Path.of(configPath, "config.json").toString());
|
||||||
file.delete();
|
file.delete();
|
||||||
|
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
@ -81,6 +83,7 @@ public class CommandPalette {
|
|||||||
allCommands.add(new Command("Otevřít profil uživatele", CommandType.USER_PROFILE));
|
allCommands.add(new Command("Otevřít profil uživatele", CommandType.USER_PROFILE));
|
||||||
allCommands.add(new Command("Otevřít chat", CommandType.CHAT_OPEN));
|
allCommands.add(new Command("Otevřít chat", CommandType.CHAT_OPEN));
|
||||||
allCommands.add(new Command("Odeslat zprávu do chatu", CommandType.CHAT_SEND));
|
allCommands.add(new Command("Odeslat zprávu do chatu", CommandType.CHAT_SEND));
|
||||||
|
allCommands.add(new Command("Zobrazit list všech hráčů", CommandType.PLAYER_LIST_OPEN));
|
||||||
allCommands.add(new Command("Zkontrolovat vyhratelnost hry", CommandType.CHECK_WINNABLE));
|
allCommands.add(new Command("Zkontrolovat vyhratelnost hry", CommandType.CHECK_WINNABLE));
|
||||||
allCommands.add(new Command("Odejít ze hry", CommandType.EXIT));
|
allCommands.add(new Command("Odejít ze hry", CommandType.EXIT));
|
||||||
|
|
||||||
@ -148,6 +151,12 @@ public class CommandPalette {
|
|||||||
Cli.info("Hra je dost možná nevyhratelná!");
|
Cli.info("Hra je dost možná nevyhratelná!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
yield displayIndex();
|
||||||
|
}
|
||||||
|
case PLAYER_LIST_OPEN -> {
|
||||||
|
var playerList = new PlayerList(apiService, playerKey);
|
||||||
|
playerList.display();
|
||||||
|
|
||||||
yield displayIndex();
|
yield displayIndex();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -21,6 +21,11 @@ public class Inventory {
|
|||||||
System.out.println();
|
System.out.println();
|
||||||
Cli.info("Váš inventář:");
|
Cli.info("Váš inventář:");
|
||||||
|
|
||||||
|
if (player.getInventory().isEmpty()) {
|
||||||
|
System.out.println("Inventář je prázdný!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a map to group items by ItemType and count occurrences
|
// Create a map to group items by ItemType and count occurrences
|
||||||
Map<ItemType, Integer> itemCounts = new HashMap<>();
|
Map<ItemType, Integer> itemCounts = new HashMap<>();
|
||||||
List<Item> usableItemList = new ArrayList<>();
|
List<Item> usableItemList = new ArrayList<>();
|
||||||
|
74
frontend/src/main/java/cz/jzitnik/game/PlayerList.java
Normal file
74
frontend/src/main/java/cz/jzitnik/game/PlayerList.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package cz.jzitnik.game;
|
||||||
|
|
||||||
|
import cz.jzitnik.api.ApiService;
|
||||||
|
import cz.jzitnik.api.types.Item;
|
||||||
|
import cz.jzitnik.api.types.Player;
|
||||||
|
import cz.jzitnik.utils.Cli;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class PlayerList {
|
||||||
|
private ApiService apiService;
|
||||||
|
private String playerKey;
|
||||||
|
|
||||||
|
|
||||||
|
public void display() throws IOException {
|
||||||
|
var response = apiService.getAllPlayers(playerKey).execute();
|
||||||
|
var players = response.body().getData().get();
|
||||||
|
|
||||||
|
Cli.printHeader("List všech hráčů");
|
||||||
|
|
||||||
|
for (Player player1 : players) {
|
||||||
|
System.out.println("Jméno: " + Cli.Colors.BLUE + player1.getName() + Cli.Colors.RESET + ", V místnosti: " + Cli.Colors.BLUE + player1.getCurrentRoom() + Cli.Colors.RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (players.size() == 1) {
|
||||||
|
// There is only one player so can't send item to another player
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("\n");
|
||||||
|
var options = new String[] { "Předat item hráči", "Zavřít list hráčů"};
|
||||||
|
|
||||||
|
var selectedIndex = Cli.selectOptionIndex(Arrays.asList(options));
|
||||||
|
|
||||||
|
if (selectedIndex == 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select item from inventory
|
||||||
|
var res = apiService.getMe(playerKey).execute();
|
||||||
|
var me = res.body().getData().get();
|
||||||
|
var inventory = me.getInventory();
|
||||||
|
|
||||||
|
if (inventory.isEmpty()) {
|
||||||
|
Cli.error("Nemáte žádné itemy v inventáři");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var playerList = players.stream().filter(player -> !player.getId().equals(me.getId())).toList();
|
||||||
|
var playerOptions = playerList.stream().map(Player::getName).toList();
|
||||||
|
|
||||||
|
System.out.println("\n\nVyberte hráče kterému chcete dát item");
|
||||||
|
var selectedPlayerIndex = Cli.selectOptionIndex(playerOptions);
|
||||||
|
var selectedPlayer = playerList.get(selectedPlayerIndex);
|
||||||
|
|
||||||
|
System.out.println("\n\nVyberte item který chcete dát hráči");
|
||||||
|
var items = inventory.stream().map(Item::toString).toList();
|
||||||
|
var selectedItemIndex = Cli.selectOptionIndex(items);
|
||||||
|
var selectedItem = inventory.get(selectedItemIndex);
|
||||||
|
|
||||||
|
var finalResponse = apiService.sendItem(playerKey, selectedItem.getId(), selectedPlayer.getId()).execute();
|
||||||
|
|
||||||
|
if (finalResponse.code() == HttpStatus.SC_CONFLICT) {
|
||||||
|
Cli.error("Hráč " + Cli.Colors.BLUE + selectedPlayer.getName() + Cli.Colors.RESET + " má plný inventář!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cli.success("Item byl úspěšně předán hráči " + Cli.Colors.BLUE + selectedPlayer.getName() + Cli.Colors.RESET + ".");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user