From e6bfbaef250c8498039af3ad7f2c17f7a02c4cf8 Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Mon, 9 Aug 2021 00:53:39 -0500 Subject: [PATCH] Added Discord integration Overhauled the DOM for chat so that the actual definitions are in html and css, and javascript is reduced to only functionality (where possible). Added a button that switches between Discord and Legacy chat. Added an API for retrieving player info (to set the username properly in Discord) (cherry picked from commit e3b790fa2b6f25267abd06d76083e9a691522d89) --- .../handler/PlayerInfoRequestHandler.java | 51 +++++ .../async/handler/RootUriRequestHandler.java | 5 + .../src/main/web/css/gemp-001/hall.css | 72 ++++++- .../gemp-lotr-async/src/main/web/hall.html | 33 ++- .../src/main/web/includes/changeLog.html | 8 + .../src/main/web/js/gemp-022/chat.js | 204 +++++++++++++----- .../src/main/web/js/gemp-022/communication.js | 14 ++ .../com/gempukku/lotro/hall/HallServer.java | 2 +- 8 files changed, 325 insertions(+), 64 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/PlayerInfoRequestHandler.java diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/PlayerInfoRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/PlayerInfoRequestHandler.java new file mode 100644 index 000000000..f124f49b6 --- /dev/null +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/PlayerInfoRequestHandler.java @@ -0,0 +1,51 @@ +package com.gempukku.lotro.async.handler; + +import com.gempukku.lotro.async.HttpProcessingException; +import com.gempukku.lotro.async.ResponseWriter; +import com.gempukku.lotro.db.PlayerStatistic; +import com.gempukku.lotro.db.vo.GameHistoryEntry; +import com.gempukku.lotro.game.GameHistoryService; +import com.gempukku.lotro.game.Player; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.QueryStringDecoder; +import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.lang.reflect.Type; +import java.text.DecimalFormat; +import java.util.List; +import java.util.Map; + +import com.google.gson.Gson; + +public class PlayerInfoRequestHandler extends LotroServerRequestHandler implements UriRequestHandler { + private Gson JsonConvert = new Gson(); + + public PlayerInfoRequestHandler(Map context) { + super(context); + + } + + @Override + public void handleRequest(String uri, HttpRequest request, Map context, ResponseWriter responseWriter, String remoteIp) throws Exception { + if (uri.equals("") && request.method() == HttpMethod.GET) { + QueryStringDecoder queryDecoder = new QueryStringDecoder(request.getUri()); + String participantId = getQueryParameterSafely(queryDecoder, "participantId"); + Player resourceOwner = getResourceOwnerSafely(request, participantId); + + String playerName = resourceOwner.getName(); + responseWriter.writeJsonResponse(JsonConvert.toJson(playerName)); + + } else { + throw new HttpProcessingException(404); + } + } + + + + +} diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/RootUriRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/RootUriRequestHandler.java index 12f63933f..f6379246a 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/RootUriRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/RootUriRequestHandler.java @@ -34,6 +34,7 @@ public class RootUriRequestHandler implements UriRequestHandler { private TournamentRequestHandler _tournamentRequestHandler; private SoloDraftRequestHandler _soloDraftRequestHandler; private PlaytestRequestHandler _playtestRequestHandler; + private PlayerInfoRequestHandler _playerInfoRequestHandler; private Pattern originPattern; @@ -60,6 +61,7 @@ public class RootUriRequestHandler implements UriRequestHandler { _tournamentRequestHandler = new TournamentRequestHandler(context); _soloDraftRequestHandler = new SoloDraftRequestHandler(context); _playtestRequestHandler = new PlaytestRequestHandler(context); + _playerInfoRequestHandler = new PlayerInfoRequestHandler(context); } @Override @@ -116,6 +118,9 @@ public class RootUriRequestHandler implements UriRequestHandler { } else if (uri.startsWith(_serverContextPath + "playtesting")) { _playtestRequestHandler.handleRequest(uri.substring(_serverContextPath.length() + 11), request, context, responseWriter, remoteIp); + } else if (uri.startsWith(_serverContextPath + "player")) { + _playerInfoRequestHandler.handleRequest(uri.substring(_serverContextPath.length() + 6), request, context, responseWriter, remoteIp); + } else { throw new HttpProcessingException(404); } diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/css/gemp-001/hall.css b/gemp-lotr/gemp-lotr-async/src/main/web/css/gemp-001/hall.css index 34e92712f..63f3ff8bd 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/css/gemp-001/hall.css +++ b/gemp-lotr/gemp-lotr-async/src/main/web/css/gemp-001/hall.css @@ -172,4 +172,74 @@ table.tables td, table.tables th { tr.played { background-color: #990000; -} \ No newline at end of file +} + +#chat { + display: grid; + grid-template-columns: auto 150px; + position:relative; + width:100%; + height:100%; + grid-gap: 3px; + overflow: hidden; +} + +#chatarea { + position:relative; + width: 100%; + height: 100%; + overflow: hidden; +} + +#chatMessages { + height: 100%; + max-height: 100%; + overflow-y: scroll; + display: flex; + flex-direction: column; +} + +#userListColumn { + display: flex; + flex-direction: column; +} + +#userList { + flex-grow: 1; + overflow: auto; +} + +#toggleChatButt { + flex: none; + height: 25px; +} + +#legacyChat { + + display: grid; + width: 100%; + height: 100%; + max-height: 100%; + grid-template-columns: auto; + grid-template-rows: auto 25px; +} + +#legacyChatInput { + display: flex; +} + +#chatTalk { + flex-grow: 1; +} + +#discordChat { + position: absolute; + top: 0; + width: 100%; + height: 100%; +} +#widgetbot { + position: relative; + width: 100%; + height: 100%; +} diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/hall.html b/gemp-lotr/gemp-lotr-async/src/main/web/hall.html index b91c8eb72..1445c52b9 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/hall.html +++ b/gemp-lotr/gemp-lotr-async/src/main/web/hall.html @@ -63,7 +63,7 @@ $("#latestNews").append( "If you find any problems with specific card or rules in general, please report it on TLHH forum - Report a bug, please include game replay link."); - chat = new ChatBoxUI("Game Hall", $("#chat"), "/gemp-lotr-server", true, null, false, true, null); + chat = new ChatBoxUI("Game Hall", $("#chat"), "/gemp-lotr-server", true, null, false, true, null, true); chat.setBounds(2, 2, 780 - 4, 200 - 4); chat.showTimestamps = true; @@ -188,8 +188,35 @@
-
+
+
+
+
+
+ + + + +
+
+ + +
+ + +
+
+
+
+ +
+ + + + + +
diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/includes/changeLog.html b/gemp-lotr/gemp-lotr-async/src/main/web/includes/changeLog.html index 7df692ed1..0d48794a5 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/includes/changeLog.html +++ b/gemp-lotr/gemp-lotr-async/src/main/web/includes/changeLog.html @@ -1,5 +1,13 @@
 Most recent update
+09 Aug. 2021
+- Added Discord integration.  Click the "Switch to Discord" button in the lower right for integration with the Discord server of the Player's Council.
+- (If it says "Discord is currently unavailable", try switching channels in the left navigation bar or refreshing the page.)
+- (If you see any bugs or have any issues, please report it to @ketura on the PC Discord.)
+- If you don't like it or it's being too buggy, feel free to switch back to the old chat by clicking the "Switch to Legacy" button in the lower right.
+- Check out the #gemp-announcements channel for a list of things you can do, or check out the Markdown tutorial here for examples of how to use some of the new functionality.
+
+22 Aug. 2019
 - Added "The Clouds Burst" Expansion for The Hobbit Draft game
 - "Final Cry" should now work if The Balrog is discarded or killed in a skirmish
 - "Anything goes" format now allows for sites from Fellowship or King blocks in addition to Towers block
diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/chat.js b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/chat.js
index a1df00b1e..a99f08d96 100644
--- a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/chat.js
+++ b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/chat.js
@@ -1,7 +1,8 @@
 var ChatBoxUI = Class.extend({
     name:null,
+    userName:null,
     div:null,
-    communication:null,
+    comm:null,
 
     chatMessagesDiv:null,
     chatTalkDiv:null,
@@ -23,29 +24,46 @@ var ChatBoxUI = Class.extend({
     stopUpdates: false,
     
     dialogListener: null,
+    
+    enableDiscord: false,
+    discordDiv:null,
+    discordWidget:null,
+    chatEmbed:null,
+    displayDiscord:true,
+    
+    toggleChatButton:null,
 
-    init:function (name, div, url, showList, playerListener, showHideSystemButton, showLockButton, displayChatListener) {
+    init:function (name, div, url, showList, playerListener, showHideSystemButton, showLockButton, displayChatListener, allowDiscord=false) {
         var that = this;
+             
         this.hiddenClasses = new Array();
         this.playerListener = playerListener;
-        this.dialogListener = displayChatListener,
+        this.dialogListener = displayChatListener;
         this.name = name;
         this.div = div;
-        this.communication = new GempLotrCommunication(url, function (xhr, ajaxOptions, thrownError) {
-            that.appendMessage("Unkown chat problem occured (error=" + xhr.status + ")", "warningMessage");
+        this.comm = new GempLotrCommunication(url, function (xhr, ajaxOptions, thrownError) {
+            that.appendMessage("Unknown chat problem occured (error=" + xhr.status + ")", "warningMessage");
         });
+        this.enableDiscord = allowDiscord;
 
-        this.chatMessagesDiv = $("
"); - this.div.append(this.chatMessagesDiv); + this.chatMessagesDiv = $("#chatMessages"); if (this.name != null) { - this.chatTalkDiv = $(""); + + this.discordDiv = $("#discordChat"); + this.comm.getPlayerInfo(function(json) + { + that.userName = json; + }, this.chatErrorMap()); + this.chatTalkDiv = $("#chatTalk"); + + this.hideSystemButton = $("#showSystemButton"); if (showHideSystemButton) { - this.hideSystemButton = $("").button( - {icons:{ - primary:"ui-icon-zoomin" - }, text:false}); + hideSystemButton.button({icons:{ + primary:"ui-icon-zoomin" + }, text:false}); + this.hideSystemButton.click( function () { if (that.isShowingMessageClass("systemMessage")) { @@ -58,35 +76,36 @@ var ChatBoxUI = Class.extend({ }); this.hideMessageClass("systemMessage"); } + else + { + this.hideSystemButton.hide(); + this.hideSystemButton = null; + } + this.lockButton = $("#lockChatButton"); if (showLockButton) { - this.lockButton = $("").button( - {icons:{ - primary:"ui-icon-locked" - }, text:false}); + this.lockButton.button({icons:{ + primary:"ui-icon-locked" + }, text:false}); + this.lockButton.click( - function () { - if (that.lockChat) { - $('#lockChatButton').button("option", "icons", {primary:'ui-icon-locked'}); - that.lockChat = false; - } else { - $('#lockChatButton').button("option", "icons", {primary:'ui-icon-unlocked'}); - that.lockChat = true; - } - }); + function () { + if (that.lockChat) { + $('#lockChatButton').button("option", "icons", {primary:'ui-icon-locked'}); + that.lockChat = false; + } else { + $('#lockChatButton').button("option", "icons", {primary:'ui-icon-unlocked'}); + that.lockChat = true; + } + }); + } + else + { + this.lockButton.hide(); + this.lockButton = null; } - if (showList) { - this.chatListDiv = $("
"); - this.div.append(this.chatListDiv); - } - if (this.hideSystemButton != null) - this.div.append(this.hideSystemButton); - if (this.lockButton != null) - this.div.append(this.lockButton); - this.div.append(this.chatTalkDiv); - - this.communication.startChat(this.name, + this.comm.startChat(this.name, function (xml) { that.processMessages(xml, true); }, this.chatErrorMap()); @@ -100,11 +119,26 @@ var ChatBoxUI = Class.extend({ $(this).val(""); } }); + + + if (showList) { + this.chatListDiv = $("#userList"); + this.toggleChatButton = $("#toggleChatButt"); + + this.toggleChatButton.button(); + this.toggleChatButton.click( function() { + that.toggleChat(); + }); + } + + this.setDiscordVisible(false); + } else { this.talkBoxHeight = 0; } }, + hideMessageClass:function (msgClass) { this.hiddenClasses.push(msgClass); $("div.message." + msgClass, this.chatMessagesDiv).hide(); @@ -128,29 +162,74 @@ var ChatBoxUI = Class.extend({ }, setBounds:function (x, y, width, height) { - var talkBoxPadding = 3; - var userListWidth = 150; - if (this.chatListDiv == null) - userListWidth = 0; - - if (this.chatListDiv != null) - this.chatListDiv.css({ position:"absolute", left:x + width - userListWidth + "px", top:y + "px", width:userListWidth, height:height - this.talkBoxHeight - 3 * talkBoxPadding, overflow:"auto" }); - this.chatMessagesDiv.css({ position:"absolute", left:x + "px", top:y + "px", width:width - userListWidth, height:height - this.talkBoxHeight - 3 * talkBoxPadding, overflow:"auto" }); - if (this.chatTalkDiv != null) { - var leftTextBoxPadding = 0; - - if (this.hideSystemButton != null) { - this.hideSystemButton.css({position:"absolute", left:x + width - talkBoxPadding - this.talkBoxHeight + "px", top:y - 2 * talkBoxPadding + (height - this.talkBoxHeight) + "px", width:this.talkBoxHeight, height:this.talkBoxHeight}); - leftTextBoxPadding += this.talkBoxHeight + talkBoxPadding; + this.handleChatVisibility(); + }, + + handleChatVisibility:function() { + + if(this.enableDiscord) + { + if(this.displayDiscord) + { + this.toggleChatButton.text("Switch to Legacy"); + + if(this.chatEmbed == null) + { + this.discordDiv.show(); + this.chatEmbed = $(""); + var script = $(""); + this.discordDiv.append(script); + this.discordDiv.append(this.chatEmbed); + } } - if (this.lockButton != null) { - this.lockButton.css({position:"absolute", left:x + width - talkBoxPadding - this.talkBoxHeight - leftTextBoxPadding + "px", top:y - 2 * talkBoxPadding + (height - this.talkBoxHeight) + "px", width:this.talkBoxHeight, height:this.talkBoxHeight}); - leftTextBoxPadding += this.talkBoxHeight + talkBoxPadding; - } - - this.chatTalkDiv.css({ position:"absolute", left:x + talkBoxPadding + "px", top:y - 2 * talkBoxPadding + (height - this.talkBoxHeight) + "px", width:width - 3 * talkBoxPadding - leftTextBoxPadding, height:this.talkBoxHeight }); + else + { + this.toggleChatButton.text("Switch to Discord"); + } } + + if(this.enableDiscord && this.displayDiscord) + { + + this.discordDiv.show(); + + if(this.chatMessagesDiv != null) + this.chatMessagesDiv.hide(); + if(this.chatTalkDiv != null) + this.chatTalkDiv.hide(); + if(this.hideSystemButton != null) + this.hideSystemButton.hide(); + if(this.lockButton != null) + this.lockButton.hide(); + } + else + { + + this.discordDiv.hide(); + + if(this.chatMessagesDiv != null) + this.chatMessagesDiv.show(); + if(this.chatTalkDiv != null) + this.chatTalkDiv.show(); + if(this.hideSystemButton != null) + this.hideSystemButton.show(); + if(this.lockButton != null) + this.lockButton.show(); + } + + }, + + toggleChat:function() { + this.setDiscordVisible(!this.displayDiscord); + }, + + setDiscordVisible:function(visible) + { + this.displayDiscord = visible; + + this.handleChatVisibility(); + }, checkForEnd:function (message, msgClass) { @@ -249,20 +328,25 @@ var ChatBoxUI = Class.extend({ updateChatMessages:function () { var that = this; - this.communication.updateChat(this.name, function (xml) { + this.comm.updateChat(this.name, function (xml) { that.processMessages(xml, true); }, this.chatErrorMap()); }, sendMessage:function (message) { var that = this; - this.communication.sendChatMessage(this.name, message, this.chatErrorMap()); + this.comm.sendChatMessage(this.name, message, this.chatErrorMap()); + + //this.chatEmbed.emit("sendMessage", message); }, chatMalfunction: function() { this.stopUpdates = true; this.chatTalkDiv.prop('disabled', true); this.chatTalkDiv.css({"background-color": "#ff9999"}); + + this.discordDiv.prop('disabled', true); + this.discordDiv.css({"background-color": "#ff9999"}); }, chatErrorMap:function() { @@ -289,5 +373,7 @@ var ChatBoxUI = Class.extend({ that.appendMessage("You have been inactive for too long and were removed from the chat room. Refresh the page if you wish to re-enter.", "warningMessage"); } }; - } + }, + + }); diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/communication.js b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/communication.js index 955126eb9..808e2a721 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/communication.js +++ b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/communication.js @@ -657,6 +657,20 @@ var GempLotrCommunication = Class.extend({ }); }, + getPlayerInfo:function (callback, errorMap) { + $.ajax({ + type:"GET", + url:this.url + "/player", + cache:false, + data:{ + participantId:getUrlParam("participantId") + }, + success:this.deliveryCheck(callback), + error:this.errorCheck(errorMap), + dataType:"json" + }); + }, + getStatus:function (callback, errorMap) { $.ajax({ type:"GET", diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java index 056bc9fe9..7e6d12d53 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java @@ -91,7 +91,7 @@ public class HallServer extends AbstractServer { tableHolder = new TableHolder(leagueService, ignoreDAO); _hallChat = _chatServer.createChatRoom("Game Hall", true, 15, true, - "You're now in the Game Hall, use /help to get a list of available commands"); + "You're now in the Game Hall, use /help to get a list of available commands.
Don't forget to check out the new Discord chat integration! Click the 'Switch to Discord' button in the lower right ---->"); _hallChat.addChatCommandCallback("ban", new ChatCommandCallback() { @Override