From f3a52b11136b6d8c22268455032602d55eadaa7b Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 28 Oct 2019 18:30:05 -0400 Subject: [PATCH] Add layout chat command --- .../runelite/http/api/chat/ChatClient.java | 47 ++++++++ .../runelite/http/api/chat/LayoutRoom.java | 50 +++++++++ .../http/service/chat/ChatController.java | 21 ++++ .../http/service/chat/ChatService.java | 31 ++++++ .../client/plugins/raids/RaidsPlugin.java | 104 ++++++++++++++++++ 5 files changed, 253 insertions(+) create mode 100644 http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java diff --git a/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java b/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java index 79c4a889ed..3c1565effd 100644 --- a/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java +++ b/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java @@ -309,4 +309,51 @@ public class ChatClient throw new IOException(ex); } } + + public boolean submitLayout(String username, LayoutRoom[] rooms) throws IOException + { + HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + .addPathSegment("chat") + .addPathSegment("layout") + .addQueryParameter("name", username) + .build(); + + Request request = new Request.Builder() + .post(RequestBody.create(RuneLiteAPI.JSON, RuneLiteAPI.GSON.toJson(rooms))) + .url(url) + .build(); + + try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) + { + return response.isSuccessful(); + } + } + + public LayoutRoom[] getLayout(String username) throws IOException + { + HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + .addPathSegment("chat") + .addPathSegment("layout") + .addQueryParameter("name", username) + .build(); + + Request request = new Request.Builder() + .url(url) + .build(); + + try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) + { + if (!response.isSuccessful()) + { + throw new IOException("Unable to look up layout!"); + } + + InputStream in = response.body().byteStream(); + return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), LayoutRoom[].class); + } + catch (JsonParseException ex) + { + throw new IOException(ex); + } + } } diff --git a/http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java b/http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java new file mode 100644 index 0000000000..3498f83eed --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.http.api.chat; + +public enum LayoutRoom +{ + START, + END, + SCAVENGERS, + FARMING, + EMPTY, + + TEKTON, + MUTTADILES, + GUARDIANS, + VESPULA, + SHAMANS, + VASA, + VANGUARDS, + MYSTICS, + UNKNOWN_COMBAT, + + CRABS, + ICE_DEMON, + TIGHTROPE, + THIEVING, + UNKNOWN_PUZZLE; +} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java index 7b5132e47a..15381845b5 100644 --- a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java +++ b/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java @@ -30,11 +30,13 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.runelite.http.api.chat.Duels; +import net.runelite.http.api.chat.LayoutRoom; import net.runelite.http.api.chat.Task; import net.runelite.http.service.util.exception.NotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -208,4 +210,23 @@ public class ChatController } return duels; } + + @PostMapping("/layout") + public void submitLayout(@RequestParam String name, @RequestBody LayoutRoom[] rooms) + { + chatService.setLayout(name, rooms); + } + + @GetMapping("/layout") + public LayoutRoom[] getLayout(@RequestParam String name) + { + LayoutRoom[] layout = chatService.getLayout(name); + + if (layout == null) + { + throw new NotFoundException(); + } + + return layout; + } } diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java index 0b0762d3ea..be497b40bd 100644 --- a/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java +++ b/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java @@ -24,9 +24,13 @@ */ package net.runelite.http.service.chat; +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; import com.google.common.collect.ImmutableMap; import java.time.Duration; +import java.util.List; import java.util.Map; +import net.runelite.http.api.chat.LayoutRoom; import net.runelite.http.api.chat.Task; import net.runelite.http.api.chat.Duels; import net.runelite.http.service.util.redis.RedisPool; @@ -198,4 +202,31 @@ public class ChatService jedis.expire(key, (int) EXPIRE.getSeconds()); } } + + public LayoutRoom[] getLayout(String name) + { + String layout; + try (Jedis jedis = jedisPool.getResource()) + { + layout = jedis.get("layout." + name); + } + + if (layout == null) + { + return null; + } + + List roomList = Splitter.on(' ').splitToList(layout); + return roomList.stream() + .map(LayoutRoom::valueOf) + .toArray(LayoutRoom[]::new); + } + + public void setLayout(String name, LayoutRoom[] rooms) + { + try (Jedis jedis = jedisPool.getResource()) + { + jedis.setex("layout." + name, (int) EXPIRE.getSeconds(), Joiner.on(' ').join(rooms)); + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java index 50f3649a09..4501b5570a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java @@ -24,12 +24,15 @@ */ package net.runelite.client.plugins.raids; +import com.google.common.base.Joiner; import com.google.inject.Binder; import com.google.inject.Provides; +import java.io.IOException; import java.text.DecimalFormat; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; +import java.util.concurrent.ScheduledExecutorService; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -41,6 +44,7 @@ import net.runelite.api.Client; import net.runelite.api.GameState; import net.runelite.api.InstanceTemplates; import net.runelite.api.MenuAction; +import net.runelite.api.MessageNode; import net.runelite.api.NullObjectID; import static net.runelite.api.Perspective.SCENE_SIZE; import net.runelite.api.Point; @@ -53,11 +57,13 @@ import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.VarbitChanged; import net.runelite.client.callback.ClientThread; import net.runelite.client.chat.ChatColorType; +import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageBuilder; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.chat.QueuedMessage; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ChatInput; import net.runelite.client.events.OverlayMenuClicked; import net.runelite.client.game.SpriteManager; import net.runelite.client.plugins.Plugin; @@ -67,9 +73,12 @@ import net.runelite.client.plugins.raids.solver.LayoutSolver; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.util.Text; +import static net.runelite.client.util.Text.sanitize; import net.runelite.client.ws.PartyMember; import net.runelite.client.ws.PartyService; import net.runelite.client.ws.WSClient; +import net.runelite.http.api.chat.ChatClient; +import net.runelite.http.api.chat.LayoutRoom; import net.runelite.http.api.ws.messages.party.PartyChatMessage; @PluginDescriptor( @@ -87,6 +96,7 @@ public class RaidsPlugin extends Plugin private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("###.##"); private static final DecimalFormat POINTS_FORMAT = new DecimalFormat("#,###"); private static final Pattern ROTATION_REGEX = Pattern.compile("\\[(.*?)]"); + private static final String LAYOUT_COMMAND = "!layout"; @Inject private ChatMessageManager chatMessageManager; @@ -121,6 +131,15 @@ public class RaidsPlugin extends Plugin @Inject private WSClient ws; + @Inject + private ChatCommandManager chatCommandManager; + + @Inject + private ChatClient chatClient; + + @Inject + private ScheduledExecutorService scheduledExecutorService; + @Getter private final ArrayList roomWhitelist = new ArrayList<>(); @@ -159,11 +178,13 @@ public class RaidsPlugin extends Plugin overlayManager.add(overlay); updateLists(); clientThread.invokeLater(() -> checkRaidPresence(true)); + chatCommandManager.registerCommandAsync(LAYOUT_COMMAND, this::lookupRaid, this::submitRaid); } @Override protected void shutDown() throws Exception { + chatCommandManager.unregisterCommand(LAYOUT_COMMAND); overlayManager.remove(overlay); infoBoxManager.removeInfoBox(timer); inRaidChambers = false; @@ -583,4 +604,87 @@ public class RaidsPlugin extends Plugin return RaidRoom.EMPTY; } } + + private void lookupRaid(ChatMessage chatMessage, String s) + { + ChatMessageType type = chatMessage.getType(); + + final String player; + if (type.equals(ChatMessageType.PRIVATECHATOUT)) + { + player = client.getLocalPlayer().getName(); + } + else + { + player = sanitize(chatMessage.getName()); + } + + LayoutRoom[] layout; + try + { + layout = chatClient.getLayout(player); + } + catch (IOException ex) + { + log.debug("unable to lookup layout", ex); + return; + } + + if (layout == null || layout.length == 0) + { + return; + } + + String layoutMessage = Joiner.on(", ").join(Arrays.stream(layout) + .map(l -> RaidRoom.valueOf(l.name())) + .filter(room -> room.getType() == RoomType.COMBAT || room.getType() == RoomType.PUZZLE) + .map(RaidRoom::getName) + .toArray()); + + String response = new ChatMessageBuilder() + .append(ChatColorType.HIGHLIGHT) + .append("Layout: ") + .append(ChatColorType.NORMAL) + .append(layoutMessage) + .build(); + + log.debug("Setting response {}", response); + final MessageNode messageNode = chatMessage.getMessageNode(); + messageNode.setRuneLiteFormatMessage(response); + chatMessageManager.update(messageNode); + client.refreshChat(); + } + + private boolean submitRaid(ChatInput chatInput, String s) + { + if (raid == null) + { + return false; + } + + final String playerName = client.getLocalPlayer().getName(); + RaidRoom[] rooms = raid.getRooms(); + + LayoutRoom[] layoutRooms = Arrays.stream(rooms) + .map(room -> LayoutRoom.valueOf(room.name())) + .toArray(LayoutRoom[]::new); + + scheduledExecutorService.execute(() -> + { + try + { + chatClient.submitLayout(playerName, layoutRooms); + } + catch (Exception ex) + { + log.warn("unable to submit layout", ex); + } + finally + { + chatInput.resume(); + } + }); + + return true; + } }