Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit a25cf5e

Browse files
committed
Adds support for Simple Discord Link Bot
This is very fast and straight forward support for Simple Discord Link Bot mod. Currently, it uses the config options from messageDestinations.chat format, so by default it will be plain text output, unless embed is enabled. This version also uses JOIN_LEAVE message type for displaying VaultHunters mod related chat messages. Fixes #1
1 parent d2de2c3 commit a25cf5e

File tree

9 files changed

+377
-1
lines changed

9 files changed

+377
-1
lines changed

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ dependencies {
115115
implementation fg.deobf("curse.maven:vault-hunters-official-mod-458203:${project.vhVersion}")
116116
implementation fg.deobf("curse.maven:dcintegration-324952:${project.dcintegration}")
117117
implementation fg.deobf("curse.maven:mc2discord-325235:${project.mc2discord}")
118+
implementation fg.deobf("curse.maven:simple-discord-link-bot-forge-fabric-spigot-541320:${project.sdlink}")
118119
}
119120

120121

@@ -123,6 +124,7 @@ mixin {
123124
add sourceSets.main, 'mixins.vhdiscord.refmap.json'
124125
config 'mixins.vhdiscord.dcintegration.json'
125126
config 'mixins.vhdiscord.mc2discord.json'
127+
config 'mixins.vhdiscord.sdlink.json'
126128
}
127129

128130
//Manifest attributes
@@ -159,6 +161,7 @@ curseforge {
159161
relations {
160162
optionalDependency("dcintegration")
161163
optionalDependency("mc2discord")
164+
optionalDependency("sdlink")
162165
requiredDependency("vault-hunters-official-mod")
163166
}
164167
}

gradle.properties

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ vhVersion=4570130
1111
mc2discord=4119890
1212
# Discord for forge Version (https://www.curseforge.com/minecraft/mc-mods/dcintegration/files)
1313
dcintegration=4452457
14+
# Simple Discord Link Bot Version (https://www.curseforge.com/minecraft/mc-mods/simple-discord-link-bot-forge-fabric-spigot/files/)
15+
sdlink=4559687
1416
# Project Version
15-
version=1.1.3
17+
version=1.2.0

src/main/java/lv/id/bonne/vhdiscord/config/VHDiscordMixinConnector.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ public class VHDiscordMixinConnector implements IMixinConnector
2121
public void connect() {
2222
Mixins.addConfiguration("mixins.vhdiscord.dcintegration.json");
2323
Mixins.addConfiguration("mixins.vhdiscord.mc2discord.json");
24+
Mixins.addConfiguration("mixins.vhdiscord.sdlink.json");
2425
}
2526
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// Created by BONNe
3+
// Copyright - 2023
4+
//
5+
6+
7+
package lv.id.bonne.vhdiscord.sdlink;
8+
9+
import lv.id.bonne.vhdiscord.config.MixinConfigPlugin;
10+
import net.minecraftforge.fml.loading.LoadingModList;
11+
12+
13+
/**
14+
* Configuration for Simple Discord Link Bot mod.
15+
* {@linkplain <a href="https://www.curseforge.com/minecraft/mc-mods/simple-discord-link-bot-forge-fabric-spigot/">SDLink</a>}
16+
*/
17+
public class SDLinkModConfiguration extends MixinConfigPlugin
18+
{
19+
@Override
20+
public boolean shouldApplyMixin(String targetClassName, String mixinClassName)
21+
{
22+
return LoadingModList.get().getModFileById("sdlink") != null;
23+
}
24+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
//
2+
// Created by BONNe
3+
// Copyright - 2023
4+
//
5+
6+
7+
package lv.id.bonne.vhdiscord.sdlink.mixin;
8+
9+
10+
import com.google.gson.JsonArray;
11+
import com.google.gson.JsonElement;
12+
import com.google.gson.JsonObject;
13+
import com.google.gson.JsonParser;
14+
import com.mojang.brigadier.StringReader;
15+
import com.mojang.brigadier.exceptions.CommandSyntaxException;
16+
import org.spongepowered.asm.mixin.Mixin;
17+
import org.spongepowered.asm.mixin.Overwrite;
18+
19+
import lv.id.bonne.vhdiscord.parser.VaultItemsHandler;
20+
import me.hypherionmc.sdlink.ForgeEventHandler;
21+
import me.hypherionmc.sdlink.server.ServerEvents;
22+
import net.minecraft.commands.arguments.NbtTagArgument;
23+
import net.minecraft.nbt.CompoundTag;
24+
import net.minecraft.network.chat.Component;
25+
import net.minecraft.network.chat.MutableComponent;
26+
import net.minecraft.network.chat.TextComponent;
27+
import net.minecraft.resources.ResourceLocation;
28+
import net.minecraft.server.level.ServerPlayer;
29+
import net.minecraft.world.item.Item;
30+
import net.minecraft.world.item.ItemStack;
31+
import net.minecraftforge.event.ServerChatEvent;
32+
import net.minecraftforge.eventbus.api.SubscribeEvent;
33+
import net.minecraftforge.registries.ForgeRegistries;
34+
import net.minecraftforge.registries.IForgeRegistry;
35+
36+
37+
/**
38+
* This class takes over ForgeMessageUtils class public static method genItemStackEmbedIfAvailable and
39+
* rewrite it, so it could handle VaultHunters items.
40+
*/
41+
@Mixin(ForgeEventHandler.class)
42+
public class MixinForgeEventsHandler
43+
{
44+
/**
45+
* The Forge Item registry.
46+
*/
47+
private static final IForgeRegistry<Item> ITEM_REGISTRY = ForgeRegistries.ITEMS;
48+
49+
50+
/**
51+
* @author BONNe
52+
* @reason Implements custom VH Item parsing.
53+
*/
54+
@SubscribeEvent
55+
@Overwrite(remap = false)
56+
public void serverChatEvent(ServerChatEvent event)
57+
{
58+
boolean messageParsed;
59+
60+
final Component msg = event.getComponent();
61+
final JsonObject json = JsonParser.parseString(Component.Serializer.toJson(msg)).getAsJsonObject();
62+
63+
if (json.has("with") && json.get("with").isJsonArray())
64+
{
65+
messageParsed = MixinForgeEventsHandler.searchAndParseArray(event.getPlayer(), json.getAsJsonArray("with"));
66+
}
67+
else if (json.has("extra") && json.get("extra").isJsonArray())
68+
{
69+
messageParsed = MixinForgeEventsHandler.searchAndParseArray(event.getPlayer(), json.getAsJsonArray("extra"));
70+
}
71+
else
72+
{
73+
messageParsed = false;
74+
}
75+
76+
if (!messageParsed)
77+
{
78+
ServerEvents.getInstance().onServerChatEvent(msg,
79+
event.getPlayer().getName(),
80+
event.getPlayer().getUUID().toString());
81+
}
82+
}
83+
84+
85+
/**
86+
* This method search for "show_item" hoverEvent and crafts MessageEmbed for VaultHunters items
87+
* from it.
88+
* @param player Player who sends the chat message.
89+
* @param array of json objects.
90+
* @return MessageEmbed text for item, or null.
91+
*/
92+
private static boolean searchAndParseArray(ServerPlayer player, JsonArray array)
93+
{
94+
for (JsonElement object : array)
95+
{
96+
if (object instanceof JsonObject singleElement)
97+
{
98+
if (singleElement.has("hoverEvent"))
99+
{
100+
final JsonObject hoverEvent = singleElement.getAsJsonObject("hoverEvent");
101+
102+
if (hoverEvent.has("action") &&
103+
hoverEvent.get("action").getAsString().equals("show_item") &&
104+
hoverEvent.has("contents"))
105+
{
106+
if (hoverEvent.getAsJsonObject("contents").has("tag"))
107+
{
108+
return MixinForgeEventsHandler.parseAndSendMessage(player,
109+
hoverEvent.getAsJsonObject("contents").getAsJsonObject());
110+
}
111+
}
112+
}
113+
}
114+
}
115+
116+
return false;
117+
}
118+
119+
120+
/**
121+
* This method parses given item json data and sends chat message if parsing was successful.
122+
* @param itemJson item json data.
123+
* @param player Player who sends the chat message.
124+
* @return {@code true} if parsing was successful, {@code false} otherwise.
125+
*/
126+
private static boolean parseAndSendMessage(ServerPlayer player, JsonObject itemJson)
127+
{
128+
try
129+
{
130+
ItemStack itemStack = new ItemStack(ITEM_REGISTRY.getValue(
131+
new ResourceLocation(itemJson.get("id").getAsString())));
132+
133+
if (itemJson.has("tag"))
134+
{
135+
CompoundTag tag = (CompoundTag) NbtTagArgument.nbtTag().parse(
136+
new StringReader(itemJson.get("tag").getAsString()));
137+
itemStack.setTag(tag);
138+
}
139+
140+
CompoundTag itemTag = itemStack.getOrCreateTag();
141+
142+
// Here we hook into Vault Hunters items.
143+
144+
if (itemJson.get("id").getAsString().startsWith("the_vault"))
145+
{
146+
String description = VaultItemsHandler.generateVaultHuntersItemTooltips(itemJson,
147+
itemStack,
148+
itemTag);
149+
150+
if (description != null && !description.isBlank())
151+
{
152+
MixinForgeEventsHandler.craftVaultHuntersItemMessage(player, itemStack, description);
153+
return true;
154+
}
155+
}
156+
}
157+
catch (CommandSyntaxException ignored)
158+
{
159+
}
160+
161+
return false;
162+
}
163+
164+
165+
/**
166+
* This message sends given item description in the chat.
167+
* @param player Player who sends chat message.
168+
* @param itemStack ItemStack item.
169+
* @param description the description of message.
170+
*/
171+
private static void craftVaultHuntersItemMessage(ServerPlayer player,
172+
ItemStack itemStack,
173+
final String description)
174+
{
175+
if (ServerEvents.getInstance() == null ||
176+
!ServerEvents.getInstance().getBotEngine().isBotReady() ||
177+
description == null ||
178+
description.isBlank())
179+
{
180+
return;
181+
}
182+
183+
MutableComponent chatComponent = new TextComponent("\n" + description);
184+
ServerEvents.getInstance().onServerChatEvent(chatComponent, player.getName(), player.getUUID().toString());
185+
}
186+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// Created by BONNe
3+
// Copyright - 2023
4+
//
5+
6+
7+
package lv.id.bonne.vhdiscord.sdlink.mixin;
8+
9+
10+
import org.spongepowered.asm.mixin.Mixin;
11+
import org.spongepowered.asm.mixin.injection.At;
12+
import org.spongepowered.asm.mixin.injection.Inject;
13+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
14+
15+
16+
import iskallia.vault.util.MiscUtils;
17+
import me.hypherionmc.sdlink.server.ServerEvents;
18+
import me.hypherionmc.sdlinklib.config.ConfigController;
19+
import me.hypherionmc.sdlinklib.discord.DiscordMessage;
20+
import me.hypherionmc.sdlinklib.discord.messages.MessageAuthor;
21+
import me.hypherionmc.sdlinklib.discord.messages.MessageType;
22+
import net.minecraft.network.chat.Component;
23+
24+
25+
/**
26+
* This catches message from MiscUtils.broadcast method and resends it to the discord server.
27+
*/
28+
@Mixin(MiscUtils.class)
29+
public class MixinMiscUtils
30+
{
31+
/**
32+
* This method sends the VaultHunters MiscUtils.broadcast message to the discord server.
33+
* That method is called when player unlocks some new gear type, or discovers modifier.
34+
* @param message Message that was sent to players
35+
* @param ci Callback info
36+
*/
37+
@Inject(method = "broadcast(Lnet/minecraft/network/chat/Component;)V", at = @At("RETURN"), remap = false)
38+
private static void broadcastMessageToDiscord(Component message, CallbackInfo ci)
39+
{
40+
if (ServerEvents.getInstance().getBotEngine() == null)
41+
{
42+
// Bot engine is not setup. Do nothing.
43+
return;
44+
}
45+
46+
if (!ConfigController.modConfig.generalConfig.enabled)
47+
{
48+
// Config is disabled. Do nothing.
49+
return;
50+
}
51+
52+
DiscordMessage discordMessage = new DiscordMessage.Builder(ServerEvents.getInstance().getBotEngine(), MessageType.JOIN_LEAVE).
53+
withMessage(message.getString()).
54+
withAuthor(MessageAuthor.SERVER).
55+
build();
56+
discordMessage.sendMessage();
57+
}
58+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//
2+
// Created by BONNe
3+
// Copyright - 2023
4+
//
5+
6+
7+
package lv.id.bonne.vhdiscord.sdlink.mixin;
8+
9+
10+
import org.spongepowered.asm.mixin.Mixin;
11+
import org.spongepowered.asm.mixin.injection.At;
12+
import org.spongepowered.asm.mixin.injection.Inject;
13+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
14+
import java.util.UUID;
15+
16+
17+
import me.hypherionmc.sdlink.server.ServerEvents;
18+
import me.hypherionmc.sdlinklib.config.ConfigController;
19+
import me.hypherionmc.sdlinklib.discord.DiscordMessage;
20+
import me.hypherionmc.sdlinklib.discord.messages.MessageAuthor;
21+
import me.hypherionmc.sdlinklib.discord.messages.MessageType;
22+
import net.minecraft.network.chat.ChatType;
23+
import net.minecraft.network.chat.Component;
24+
import net.minecraft.server.level.ServerPlayer;
25+
import net.minecraft.server.players.PlayerList;
26+
import net.minecraftforge.server.ServerLifecycleHooks;
27+
28+
29+
/**
30+
* Adds missing messages when players enters/exits vault
31+
*/
32+
@Mixin(PlayerList.class)
33+
public class MixinPlayerVaultInteraction
34+
{
35+
@Inject(method = "broadcastMessage(Lnet/minecraft/network/chat/Component;Lnet/minecraft/network/chat/ChatType;Ljava/util/UUID;)V", at = @At("HEAD"))
36+
private void broadcastMessageToDiscord(Component p_11265_, ChatType p_11266_, UUID p_11267_, CallbackInfo ci)
37+
{
38+
if (ServerEvents.getInstance().getBotEngine() == null)
39+
{
40+
// Bot engine is not setup. Do nothing.
41+
return;
42+
}
43+
44+
if (!ConfigController.modConfig.generalConfig.enabled)
45+
{
46+
// Config is disabled. Do nothing.
47+
return;
48+
}
49+
50+
if (p_11266_ != ChatType.CHAT)
51+
{
52+
// VaultHunters posts messages with ChatType.CHAT
53+
return;
54+
}
55+
56+
String text = p_11265_.getString();
57+
58+
final ServerPlayer p = ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayer(p_11267_);
59+
60+
if (p == null || !text.startsWith(p.getName().getString()))
61+
{
62+
// If player is not known or message does not start with player name, do nothing.
63+
return;
64+
}
65+
66+
// These are currently known messages when player enters/exits vault.
67+
68+
if (text.endsWith("opened a Vault!") ||
69+
text.endsWith("opened the Final Vault!") ||
70+
(text.contains(" entered a ") && text.endsWith("Vault!")) ||
71+
(text.contains(" entered an ") && text.endsWith("Vault!")) ||
72+
(text.contains(" defeated ") && text.endsWith("!")) ||
73+
text.endsWith(" was defeated.") ||
74+
text.endsWith(" survived.") ||
75+
text.endsWith(" completed the Vault!"))
76+
{
77+
DiscordMessage discordMessage = new DiscordMessage.Builder(ServerEvents.getInstance().getBotEngine(), MessageType.JOIN_LEAVE).
78+
withMessage(text.replaceFirst(p.getName().getString(), "**" + p.getName().getString() + "**")).
79+
withAuthor(MessageAuthor.SERVER).
80+
build();
81+
discordMessage.sendMessage();
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)