From 7d802053c1f5dabeb5dcf8a74d31c882301dc27f Mon Sep 17 00:00:00 2001 From: Christoph Prenner Date: Thu, 5 Mar 2026 13:49:06 +0100 Subject: [PATCH 1/3] -added DeckserverRemote Method to get all Library cards - added function to display library cards as list with tooltip and quick actions in the notes - added quickactions to notes - added new quick-command-modal show lib --- .../net/deckserver/dwr/DeckserverRemote.java | 15 +++++ src/main/webapp/WEB-INF/jsps/game/notes.jsp | 26 +++++++- .../WEB-INF/jsps/game/quick-command-modal.jsp | 4 ++ src/main/webapp/js/ds.js | 60 ++++++++++++++++++- 4 files changed, 101 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/deckserver/dwr/DeckserverRemote.java b/src/main/java/net/deckserver/dwr/DeckserverRemote.java index a783d1c0..441b21ba 100644 --- a/src/main/java/net/deckserver/dwr/DeckserverRemote.java +++ b/src/main/java/net/deckserver/dwr/DeckserverRemote.java @@ -6,11 +6,15 @@ import net.deckserver.dwr.creators.UpdateFactory; import net.deckserver.dwr.model.GameModel; import net.deckserver.dwr.model.GameView; +import net.deckserver.dwr.model.JolGame; import net.deckserver.dwr.model.PlayerModel; import net.deckserver.game.enums.GameFormat; +import net.deckserver.game.enums.RegionType; import net.deckserver.services.*; +import net.deckserver.storage.json.deck.CardCount; import net.deckserver.storage.json.deck.Deck; import net.deckserver.storage.json.deck.ExtendedDeck; +import net.deckserver.storage.json.game.CardData; import net.deckserver.storage.json.game.ChatData; import net.deckserver.storage.json.system.DeckInfo; import net.deckserver.storage.json.system.GameHistory; @@ -18,14 +22,17 @@ import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; import org.apache.commons.csv.QuoteMode; +import org.apache.commons.lang3.tuple.Pair; import org.directwebremoting.WebContextFactory; import javax.servlet.http.HttpServletRequest; +import java.awt.print.Book; import java.io.IOException; import java.io.StringWriter; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.stream.Collectors; public class DeckserverRemote { @@ -196,6 +203,14 @@ public Deck getGameDeck(String gameName) { return null; } + public List getLib(String gameName) { + JolGame game = GameService.getGameByName(gameName); + String playerName = getPlayer(request); + return game.data().getPlayerRegion(playerName, RegionType.LIBRARY).getCards().stream() + .map(card -> new CardCount(Integer.valueOf(card.getCardId()), card.getName(), 0, null)) + .collect(Collectors.toList()); + } + public Set getGamePlayers(String gameName) { String playerName = getPlayer(request); if (gameName != null && !Strings.isNullOrEmpty(playerName)) { diff --git a/src/main/webapp/WEB-INF/jsps/game/notes.jsp b/src/main/webapp/WEB-INF/jsps/game/notes.jsp index 0941763d..8bfe0693 100644 --- a/src/main/webapp/WEB-INF/jsps/game/notes.jsp +++ b/src/main/webapp/WEB-INF/jsps/game/notes.jsp @@ -9,8 +9,28 @@ - - +
+
+ + + + + +
+
+ +
+
+
    +
    +
    + + +
    \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsps/game/quick-command-modal.jsp b/src/main/webapp/WEB-INF/jsps/game/quick-command-modal.jsp index 76863934..8aed48cb 100644 --- a/src/main/webapp/WEB-INF/jsps/game/quick-command-modal.jsp +++ b/src/main/webapp/WEB-INF/jsps/game/quick-command-modal.jsp @@ -33,7 +33,11 @@ + +
    Crypt
    + + -
    +
    From 0baf66d91df906f405ba13ae885cf48ff8f4133c Mon Sep 17 00:00:00 2001 From: Christoph Prenner Date: Fri, 6 Mar 2026 11:10:03 +0100 Subject: [PATCH 3/3] - added new DTO for CardSimple - added removeShownCards method to DeckserverRemote - added callbackShowLib to render shown cards by a player - adapted notes --- .../net/deckserver/dwr/DeckserverRemote.java | 10 +- .../net/deckserver/dwr/bean/GameBean.java | 5 +- .../net/deckserver/dwr/model/GameView.java | 5 +- .../net/deckserver/dwr/model/JolGame.java | 13 ++- .../storage/json/game/CardSimple.java | 21 ++++ .../storage/json/game/PlayerData.java | 2 + src/main/webapp/WEB-INF/jsps/game/notes.jsp | 17 ++-- .../WEB-INF/jsps/game/quick-command-modal.jsp | 2 +- src/main/webapp/js/ds.js | 97 +++++++++++-------- 9 files changed, 111 insertions(+), 61 deletions(-) create mode 100644 src/main/java/net/deckserver/storage/json/game/CardSimple.java diff --git a/src/main/java/net/deckserver/dwr/DeckserverRemote.java b/src/main/java/net/deckserver/dwr/DeckserverRemote.java index 441b21ba..3059c8cb 100644 --- a/src/main/java/net/deckserver/dwr/DeckserverRemote.java +++ b/src/main/java/net/deckserver/dwr/DeckserverRemote.java @@ -14,7 +14,7 @@ import net.deckserver.storage.json.deck.CardCount; import net.deckserver.storage.json.deck.Deck; import net.deckserver.storage.json.deck.ExtendedDeck; -import net.deckserver.storage.json.game.CardData; +import net.deckserver.storage.json.game.CardSimple; import net.deckserver.storage.json.game.ChatData; import net.deckserver.storage.json.system.DeckInfo; import net.deckserver.storage.json.system.GameHistory; @@ -22,11 +22,9 @@ import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; import org.apache.commons.csv.QuoteMode; -import org.apache.commons.lang3.tuple.Pair; import org.directwebremoting.WebContextFactory; import javax.servlet.http.HttpServletRequest; -import java.awt.print.Book; import java.io.IOException; import java.io.StringWriter; import java.time.OffsetDateTime; @@ -410,6 +408,12 @@ public Map setMessage(String message) { return UpdateFactory.getUpdate(); } + public List removeShownCards(String name) { + String playerName = getPlayer(request); + GameService.getGameByName(name).setShownCards(playerName, null); + return null; + } + public String exportPastGamesAsCsv() throws IOException { CSVFormat format = CSVFormat.DEFAULT.builder() .setHeader("Game", "Started", "Ended", "Player", "Deck", "GW", "VP") diff --git a/src/main/java/net/deckserver/dwr/bean/GameBean.java b/src/main/java/net/deckserver/dwr/bean/GameBean.java index 4a75a7f6..716936c4 100644 --- a/src/main/java/net/deckserver/dwr/bean/GameBean.java +++ b/src/main/java/net/deckserver/dwr/bean/GameBean.java @@ -1,6 +1,7 @@ package net.deckserver.dwr.bean; import lombok.Getter; +import net.deckserver.storage.json.game.CardSimple; import java.util.List; @@ -13,6 +14,7 @@ public class GameBean { private final String hand; private final String globalNotes; private final String privateNotes; + private final List shownCards; private final String label; private final String phase; private final List turn; @@ -29,7 +31,7 @@ public class GameBean { private final int logLength; private final String currentPlayer; - public GameBean(boolean isPlayer, boolean isAdmin, boolean isJudge, int refresh, String hand, String globalNotes, String privateNotes, + public GameBean(boolean isPlayer, boolean isAdmin, boolean isJudge, int refresh, String hand, String globalNotes, String privateNotes, List shownCards, String label, String phase, boolean resetChat, boolean turnChanged, List turn, List turns, String state, List phases, List ping, List pinged, String stamp, String name, int logLength, String currentPlayer) { this.ping = ping; @@ -41,6 +43,7 @@ public GameBean(boolean isPlayer, boolean isAdmin, boolean isJudge, int refresh, this.hand = hand; this.globalNotes = globalNotes; this.privateNotes = privateNotes; + this.shownCards = shownCards; this.label = label; this.phase = phase; this.resetChat = resetChat; diff --git a/src/main/java/net/deckserver/dwr/model/GameView.java b/src/main/java/net/deckserver/dwr/model/GameView.java index fa3d9ce1..f8146d66 100644 --- a/src/main/java/net/deckserver/dwr/model/GameView.java +++ b/src/main/java/net/deckserver/dwr/model/GameView.java @@ -7,6 +7,7 @@ import net.deckserver.services.ChatService; import net.deckserver.services.GameService; import net.deckserver.services.PlayerService; +import net.deckserver.storage.json.game.CardSimple; import net.deckserver.storage.json.game.ChatData; import org.directwebremoting.WebContextFactory; import org.slf4j.Logger; @@ -90,6 +91,7 @@ public GameBean create() { String hand = null; String globalNotes = null; String privateNotes = null; + List shownCards = null; String label; List turn = new ArrayList<>(); List turns = new ArrayList<>(); @@ -118,6 +120,7 @@ public GameBean create() { if (privateNotesChanged) { privateNotes = game.getPrivateNotes(playerName); + shownCards = game.getShownCards(playerName); } label = game.getTurnLabel() + " - " + game.getPhase(); @@ -160,7 +163,7 @@ public GameBean create() { clearAccess(); String stamp = OffsetDateTime.now().format(ISO_OFFSET_DATE_TIME); int logLength = ChatService.getTurn(id, game.getTurnLabel()).size(); - return new GameBean(isPlayer, isAdmin, isJudge, refresh, hand, globalNotes, privateNotes, label, phase.getDescription(), + return new GameBean(isPlayer, isAdmin, isJudge, refresh, hand, globalNotes, privateNotes, shownCards,label, phase.getDescription(), chatReset, tc, turn, turns, state, phases, ping, pinged, stamp, gameName, logLength, currentPlayer); } diff --git a/src/main/java/net/deckserver/dwr/model/JolGame.java b/src/main/java/net/deckserver/dwr/model/JolGame.java index 0adbad8d..bb77136e 100644 --- a/src/main/java/net/deckserver/dwr/model/JolGame.java +++ b/src/main/java/net/deckserver/dwr/model/JolGame.java @@ -14,10 +14,7 @@ import net.deckserver.services.ParserService; import net.deckserver.storage.json.cards.CardSummary; import net.deckserver.storage.json.deck.Deck; -import net.deckserver.storage.json.game.CardData; -import net.deckserver.storage.json.game.GameData; -import net.deckserver.storage.json.game.PlayerData; -import net.deckserver.storage.json.game.RegionData; +import net.deckserver.storage.json.game.*; import java.text.DecimalFormat; import java.util.*; @@ -379,6 +376,13 @@ public void setPrivateNotes(String player, String text) { data.getPlayer(player).setNotes(text); } + public List getShownCards(String player) { + return Optional.ofNullable(data.getPlayer(player)).get().getShownCards(); + } + public void setShownCards(String player, List shownCards) { + data.getPlayer(player).setShownCards(shownCards); + } + public void setLabel(String player, String cardId, String text, boolean quiet) { CardData card = data.getCard(cardId); String cardName = getCardName(card); @@ -626,6 +630,7 @@ public void show(String player, RegionType targetRegion, int amount, Listnew CardSimple(card.getCardId(), card.getName(), card.getOwnerName(), targetRegion.description())).collect(Collectors.toList())); } String msg; boolean self = recipients.size() == 1 && recipients.contains(player); diff --git a/src/main/java/net/deckserver/storage/json/game/CardSimple.java b/src/main/java/net/deckserver/storage/json/game/CardSimple.java new file mode 100644 index 00000000..f8786881 --- /dev/null +++ b/src/main/java/net/deckserver/storage/json/game/CardSimple.java @@ -0,0 +1,21 @@ +package net.deckserver.storage.json.game; + +import lombok.Data; + +@Data +public class CardSimple { + String id; + String name; + String owner; + String region; + + public CardSimple() { + } + + public CardSimple(String cardId, String name, String ownerName, String region) { + this.id = cardId; + this.name = name; + this.owner = ownerName; + this.region = region; + } +} diff --git a/src/main/java/net/deckserver/storage/json/game/PlayerData.java b/src/main/java/net/deckserver/storage/json/game/PlayerData.java index 91789459..3967e81b 100644 --- a/src/main/java/net/deckserver/storage/json/game/PlayerData.java +++ b/src/main/java/net/deckserver/storage/json/game/PlayerData.java @@ -7,6 +7,7 @@ import net.deckserver.game.enums.RegionType; import java.util.HashMap; +import java.util.List; import java.util.Map; @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name") @@ -31,6 +32,7 @@ public class PlayerData { private boolean ousted = false; private String notes; private String choice; + private List shownCards; public PlayerData(String name) { this.name = name; diff --git a/src/main/webapp/WEB-INF/jsps/game/notes.jsp b/src/main/webapp/WEB-INF/jsps/game/notes.jsp index e403cdad..8355aa0d 100644 --- a/src/main/webapp/WEB-INF/jsps/game/notes.jsp +++ b/src/main/webapp/WEB-INF/jsps/game/notes.jsp @@ -8,12 +8,12 @@
    - +
    -
    +
      + placeholder="Private Notes" style="height: 150px;">
      \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsps/game/quick-command-modal.jsp b/src/main/webapp/WEB-INF/jsps/game/quick-command-modal.jsp index 8aed48cb..d3136858 100644 --- a/src/main/webapp/WEB-INF/jsps/game/quick-command-modal.jsp +++ b/src/main/webapp/WEB-INF/jsps/game/quick-command-modal.jsp @@ -33,7 +33,7 @@ -
      diff --git a/src/main/webapp/js/ds.js b/src/main/webapp/js/ds.js index c63bc619..f4156833 100644 --- a/src/main/webapp/js/ds.js +++ b/src/main/webapp/js/ds.js @@ -1131,11 +1131,7 @@ function doSubmit(event) { commandInput.val(""); chatInput.val(""); pingSelect.val(""); - if(command.toLowerCase() == "show lib" || command.toLowerCase() == "show lib "+player){ - showLib(); - } else { - DS.submitForm(game, phase, command, chat, ping, {callback: processData, errorHandler: errorhandler}); - } + DS.submitForm(game, phase, command, chat, ping, {callback: processData, errorHandler: errorhandler}); return false; } @@ -1151,45 +1147,56 @@ function sendCommand(command, message = '') { return false; } -function showLib() { - DS.getLib(game, {callback: callbackShowLib, errorHandler: errorhandler}); - sendCommand("show lib"); -} - function callbackShowLib(data) { let deckModal = $("#deckBodyList"); - $('#quickCommandModal').modal('hide'); + let deckBody = $("#deckBody"); + let cardOwner = $("#cardOwner"); + //empty owner/region of previous shown cards deckModal.empty(); - $("#deckBody").removeClass("d-none"); - - $.each(data, function (index, card) { - const div = $("
      ").addClass("mx-1 me-auto w-100 align-items-center"); - const divLink = $("
      ").addClass("d-flex justify-content-between align-items-center w-100"); - const divButton = $("
      "); - const cardRow = $("
    1. ").addClass("flex-grow-1 list-group-item d-flex justify-content-between align-items-center p-1 shadow"); - const cardLink = $("").text(card.name).attr("data-card-id", card.id).addClass("card-name"); - const sendHand = $("").attr("title", "Draw").addClass("link-dark").on("click", function () { - let target = cardRow.index()+1; - sendCommand('move lib '+ target +' hand'); - cardRow.remove(); - }).append($("").addClass("bi bi-card-list text-decoration-none")); - const play = $("").attr("title", "Play").addClass("link-dark").on("click", function () { - let target = cardRow.index()+1; - sendCommand('move lib '+ target +' ready'); - cardRow.remove(); - }).append($("").addClass("bi bi-play")); - const discard = $("").attr("title", "Discard").addClass("link-dark").on("click", function () { - let target = cardRow.index()+1; - sendCommand('move lib '+ target +' ash'); - cardRow.remove(); - }).append($("").addClass("bi bi-trash")); - divButton.append(sendHand, play, discard); - divLink.append(cardLink, divButton); - div.append(divLink); - cardRow.append(div); - deckModal.append(cardRow); - }) - addCardTooltips("#deckBodyList"); + cardOwner.empty() + //display none all elements in case shown cards have been cleared + deckBody.addClass("d-none"); + cardOwner.addClass("d-none"); + //description who owns and where cards are from + if (data != null && data[0].owner==player) { + cardOwner.text(data[0].owner+" looks at "+data.length+" cards of their "+data[0].region+"."); + } else if(data != null) { + cardOwner.text(data[0].owner+" shows "+data.length+" cards of their "+data[0].region+"."); + } + //only display and render shown Cards if some are to show + if(data!=null) { + toggleDisplay(".shownCards") + $.each(data, function (index, card) { + const div = $("
      ").addClass("mx-1 me-auto w-100 align-items-center"); + const divLink = $("
      ").addClass("d-flex justify-content-between align-items-center w-100"); + const divButton = $("
      "); + const cardRow = $("
    2. ").addClass("flex-grow-1 list-group-item d-flex justify-content-between align-items-center p-1 shadow"); + const cardLink = $("").text(card.name).attr("data-card-id", card.id).addClass("card-name"); + if(card.owner==player) { + const sendHand = $("").attr("title", "Draw").addClass("link-dark").on("click", function () { + let target = cardRow.index()+1; + sendCommand('move '+card.region+' '+ target +' hand'); + cardRow.remove(); + }).append($("").addClass("bi bi-card-list text-decoration-none")); + const play = $("").attr("title", "Play").addClass("link-dark").on("click", function () { + let target = cardRow.index()+1; + sendCommand('move '+card.region+' '+ target +' ready'); + cardRow.remove(); + }).append($("").addClass("bi bi-play")); + const discard = $("").attr("title", "Discard").addClass("link-dark").on("click", function () { + let target = cardRow.index()+1; + sendCommand('move '+card.region+' '+ target +' ash'); + cardRow.remove(); + }).append($("").addClass("bi bi-trash")); + divButton.append(sendHand, play, discard); + } + divLink.append(cardLink, divButton); + div.append(divLink); + cardRow.append(div); + deckModal.append(cardRow); + }) + addCardTooltips("#deckBodyList"); + } } function closeShowLib() { @@ -1323,6 +1330,7 @@ function loadGame(data) { //like another player has shown you some cards. if (data.privateNotes) { privateNotes.val(data.privateNotes); + callbackShowLib(data.shownCards); } if (data.turns.length > 0) { @@ -1560,12 +1568,15 @@ function toggleMode() { wrapper.removeAttr("data-bs-theme"); } } -function toggleDisplay(id) { - $("#"+id).toggleClass("d-none"); +function toggleDisplay(identifier) { + $(identifier).toggleClass("d-none"); } function addDnone(id) { $("#"+id).addClass("d-none"); } function removeDnone(id) { $("#"+id).removeClass("d-none"); +} +function removeShownCards() { + DS.removeShownCards(game, {callback: callbackShowLib, errorHandler: errorhandler}); } \ No newline at end of file