diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/pom.xml b/pom.xml
index e69de29..7573f27 100644
--- a/pom.xml
+++ b/pom.xml
@@ -0,0 +1,97 @@
+
+ 4.0.0
+
+ com.minster586
+ tiktok-stream-plugin
+ 1.0.0
+ jar
+
+ TikTokStreamPlugin
+ Integrates TikTok Live events with Minecraft 1.19
+
+
+ 17
+ ${java.version}
+ ${java.version}
+
+
+
+
+
+ org.spigotmc
+ spigot-api
+ 1.19-R0.1-SNAPSHOT
+ provided
+
+
+
+
+ org.java-websocket
+ Java-WebSocket
+ 1.5.3
+
+
+
+
+ com.google.code.gson
+ gson
+ 2.10.1
+
+
+
+
+ org.yaml
+ snakeyaml
+ 2.2
+
+
+
+
+
+
+ spigot-repo
+ https://hub.spigotmc.org/nexus/content/repositories/snapshots/
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ ${java.version}
+ ${java.version}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.5.0
+
+
+ package
+ shade
+
+
+
+ org.java_websocket
+ com.minster586.shaded.websocket
+
+
+ true
+ false
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/minster586/events/TikTokEventDispatcher.java b/src/main/java/com/minster586/events/TikTokEventDispatcher.java
new file mode 100644
index 0000000..d293c79
--- /dev/null
+++ b/src/main/java/com/minster586/events/TikTokEventDispatcher.java
@@ -0,0 +1,102 @@
+package com.minster586.tiktokstream.events;
+
+import com.minster586.tiktokstream.TikTokStreamPlugin;
+import com.minster586.tiktokstream.config.ConfigManager;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import net.md_5.bungee.api.chat.TextComponent;
+import net.md_5.bungee.api.ChatMessageType;
+import com.minster586.ui.NotificationManager;
+
+import java.util.List;
+
+public class TikTokEventDispatcher {
+
+ private final ConfigManager config;
+
+ public TikTokEventDispatcher() {
+ this.config = TikTokStreamPlugin.getInstance().getConfigManager();
+ }
+
+ public void handleGift(String username, String giftName, int amount) {
+ if (!config.isGiftEnabled()) return;
+
+ List locations = config.getGiftLocations();
+ String prefix = config.getPrefix();
+
+ String chatMessage = config.getGiftChatMessage()
+ .replace("%prefix%", prefix)
+ .replace("%username%", username)
+ .replace("%giftName%", giftName)
+ .replace("%amount%", String.valueOf(amount));
+
+ String actionBarMessage = config.getGiftActionBarMessage()
+ .replace("%prefix%", prefix)
+ .replace("%username%", username)
+ .replace("%giftName%", giftName)
+ .replace("%amount%", String.valueOf(amount));
+
+ if (locations.contains("chat")) {
+ Bukkit.broadcastMessage(chatMessage);
+ }
+
+ if (locations.contains("action-bar")) {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(actionBarMessage));
+ }
+ }
+
+ // Toast notifications removed. Use NotificationManager for chat/action-bar only.
+ }
+
+ public void handleJoin(String username) {
+ if (!config.isJoinEnabled()) return;
+
+ String location = config.getJoinLocation();
+ String message = config.getJoinActionBarMessage().replace("%username%", username);
+
+ switch (location) {
+ case "chat" -> Bukkit.broadcastMessage(config.getJoinChatMessage().replace("%username%", username));
+ case "action-bar" -> Bukkit.getOnlinePlayers().forEach(p -> p.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)));
+ // Toast notifications removed
+ }
+ }
+
+ public void handleChat(String username, String messageText) {
+ if (!config.isChatEnabled()) return;
+
+ String location = config.getChatLocation();
+ String formatted = config.getChatMessage()
+ .replace("%prefix%", config.getPrefix())
+ .replace("%username%", username)
+ .replace("%message%", messageText);
+
+ switch (location) {
+ case "chat" -> Bukkit.broadcastMessage(formatted);
+ case "action-bar" -> Bukkit.getOnlinePlayers().forEach(p -> p.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(
+ config.getChatActionBarMessage()
+ .replace("%username%", username)
+ .replace("%message%", messageText)
+ )));
+ // Toast notifications removed
+ }
+ }
+
+ public void handleFollow(String username) {
+ if (!config.isFollowEnabled()) return;
+
+ List locations = config.getFollowLocations();
+
+ if (locations.contains("chat")) {
+ Bukkit.broadcastMessage(config.getFollowChatMessage().replace("%username%", username));
+ }
+
+ if (locations.contains("action-bar")) {
+ Bukkit.getOnlinePlayers().forEach(p -> p.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(
+ config.getFollowActionBarMessage().replace("%username%", username)
+ )));
+ }
+
+ // Toast notifications removed. Use NotificationManager for chat/action-bar only.
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/minster586/tiktokstream/TikTokLiveCommand.java b/src/main/java/com/minster586/tiktokstream/TikTokLiveCommand.java
new file mode 100644
index 0000000..35835bd
--- /dev/null
+++ b/src/main/java/com/minster586/tiktokstream/TikTokLiveCommand.java
@@ -0,0 +1,44 @@
+package com.minster586.tiktokstream;
+
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class TikTokLiveCommand implements CommandExecutor, TabCompleter {
+ private final TikTokStreamPlugin plugin;
+ private static final String PERMISSION = "tiktok.live";
+
+ public TikTokLiveCommand(TikTokStreamPlugin plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!sender.hasPermission(PERMISSION)) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to use this command.");
+ return true;
+ }
+ if (args.length != 1 || !(args[0].equalsIgnoreCase("enable") || args[0].equalsIgnoreCase("disable"))) {
+ sender.sendMessage(ChatColor.YELLOW + "Usage: /tiktok live ");
+ return true;
+ }
+ boolean enable = args[0].equalsIgnoreCase("enable");
+ plugin.setTiktokLiveEnabled(enable);
+ sender.sendMessage(ChatColor.GREEN + "TikTok live notifications " + (enable ? "enabled" : "disabled") + ".");
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ if (args.length == 1) {
+ return Arrays.asList("enable", "disable");
+ }
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/com/minster586/tiktokstream/TikTokStreamPlugin.java b/src/main/java/com/minster586/tiktokstream/TikTokStreamPlugin.java
index 9189af9..d06f19a 100644
--- a/src/main/java/com/minster586/tiktokstream/TikTokStreamPlugin.java
+++ b/src/main/java/com/minster586/tiktokstream/TikTokStreamPlugin.java
@@ -2,15 +2,18 @@ package com.minster586.tiktokstream;
import com.minster586.tiktokstream.config.ConfigManager;
import com.minster586.tiktokstream.websocket.StreamerBotWebSocketClient;
+import com.minster586.tiktokstream.util.GiftMappingManager;
import org.bukkit.plugin.java.JavaPlugin;
import java.net.URI;
-public class TikTokStreamPlugin extends JavaPlugin {
+public class TikTokStreamPlugin extends JavaPlugin {
private static TikTokStreamPlugin instance;
private ConfigManager configManager;
private StreamerBotWebSocketClient webSocketClient;
+ private GiftMappingManager giftMappingManager;
+ private boolean tiktokLiveEnabled = true;
@Override
public void onEnable() {
@@ -20,12 +23,31 @@ public class TikTokStreamPlugin extends JavaPlugin {
configManager = new ConfigManager(this);
configManager.load();
+ // Initialize GiftMappingManager
+ String giftMappingUrl = getConfig().getString("config.giftMappingUrl");
+ if (giftMappingUrl != null && !giftMappingUrl.isEmpty()) {
+ giftMappingManager = new GiftMappingManager(this, giftMappingUrl);
+ } else {
+ getLogger().warning("No giftMappingUrl found in config! Gift names will not be available.");
+ }
+
String websocketUrl = configManager.getWebSocketUrl();
webSocketClient = new StreamerBotWebSocketClient(URI.create(websocketUrl));
webSocketClient.connect();
+ // Register /tiktok live command
+ getCommand("tiktok").setExecutor(new TikTokLiveCommand(this));
+ getCommand("tiktok").setTabCompleter(new TikTokLiveCommand(this));
+
getLogger().info("TikTokStreamPlugin enabled and connected to Streamer.bot.");
}
+ public boolean isTiktokLiveEnabled() {
+ return tiktokLiveEnabled;
+ }
+
+ public void setTiktokLiveEnabled(boolean enabled) {
+ this.tiktokLiveEnabled = enabled;
+ }
@Override
public void onDisable() {
@@ -42,4 +64,8 @@ public class TikTokStreamPlugin extends JavaPlugin {
public ConfigManager getConfigManager() {
return configManager;
}
+
+ public GiftMappingManager getGiftMappingManager() {
+ return giftMappingManager;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/minster586/tiktokstream/config/ConfigManager.java b/src/main/java/com/minster586/tiktokstream/config/ConfigManager.java
new file mode 100644
index 0000000..c18b27d
--- /dev/null
+++ b/src/main/java/com/minster586/tiktokstream/config/ConfigManager.java
@@ -0,0 +1,150 @@
+package com.minster586.tiktokstream.config;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.plugin.java.JavaPlugin;
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.*;
+
+public class ConfigManager {
+
+ private final JavaPlugin plugin;
+ private FileConfiguration config;
+
+ public ConfigManager(JavaPlugin plugin) {
+ this.plugin = plugin;
+ }
+
+ public void load() {
+ File configFile = new File(plugin.getDataFolder(), "config.yml");
+
+ if (!configFile.exists()) {
+ plugin.saveResource("config.yml", false);
+ }
+
+ config = YamlConfiguration.loadConfiguration(configFile);
+
+ // Load defaults from resources/config.yml
+ InputStream defaultStream = plugin.getResource("config.yml");
+ if (defaultStream != null) {
+ YamlConfiguration defaultConfig = YamlConfiguration.loadConfiguration(new InputStreamReader(defaultStream));
+ config.setDefaults(defaultConfig);
+ }
+ }
+
+ // 🔧 Accessors (no hardcoded defaults — rely on config.yml)
+ public String getPrefix() {
+ return config.getString("config.prefix");
+ }
+
+ public String getTikTokUsername() {
+ return config.getString("config.tiktok_username");
+ }
+
+ public String getGiftMappingUrl() {
+ return config.getString("config.giftMappingUrl");
+ }
+
+
+ public String getWebSocketUrl() {
+ return config.getString("config.websocket.url");
+ }
+
+
+ public int getWebSocketRefreshDelay() {
+ return config.getInt("config.websocket.refresh-delay");
+ }
+
+ public boolean isJoinEnabled() {
+ return config.getBoolean("config.settings.join.joined-enabled");
+ }
+
+ public String getJoinLocation() {
+ return config.getString("config.settings.join.loctions");
+ }
+
+ public String getJoinChatMessage() {
+ return config.getString("config.settings.join.chat-message");
+ }
+
+ public String getJoinActionBarMessage() {
+ return config.getString("config.settings.join.action-bar-message");
+ }
+
+ public boolean isGiftEnabled() {
+ return config.getBoolean("config.settings.gift.gifts-enabled");
+ }
+
+ public List getGiftLocations() {
+ return parseLocationList("config.settings.gift.loctions");
+ }
+
+ public String getGiftChatMessage() {
+ return config.getString("config.settings.gift.chat-message");
+ }
+
+ public String getGiftActionBarMessage() {
+ return config.getString("config.settings.gift.action-bar-message");
+ }
+
+ public boolean isChatEnabled() {
+ return config.getBoolean("config.settings.chat.chat-enabled");
+ }
+
+ public String getChatLocation() {
+ return config.getString("config.settings.chat.loctions");
+ }
+
+ public String getChatMessage() {
+ return config.getString("config.settings.chat.chat-message");
+ }
+
+ public String getChatActionBarMessage() {
+ return config.getString("config.settings.chat.action-bar-message");
+ }
+
+
+ public boolean isFollowEnabled() {
+ return config.getBoolean("config.settings.follows.follow-enabled");
+ }
+
+ public List getFollowLocations() {
+ return parseLocationList("config.settings.follows.loctions");
+ }
+
+ public String getFollowChatMessage() {
+ return config.getString("config.settings.follows.chat-message");
+ }
+
+ public String getFollowActionBarMessage() {
+ return config.getString("config.settings.follows.action-bar-message");
+ }
+
+
+
+ // 🔧 Helpers
+ private List parseLocationList(String path) {
+ String raw = config.getString(path);
+ if (raw == null) return Collections.emptyList();
+ return Arrays.stream(raw.split(","))
+ .map(String::trim)
+ .filter(s -> !s.isEmpty())
+ .toList();
+ }
+
+ private Integer getNullableInt(String path) {
+ if (!config.contains(path) || config.get(path) == null) return null;
+ return config.getInt(path);
+ }
+ // Generic config accessors for plugin internals
+ public int getIntOrDefault(String path, int def) {
+ if (!config.contains(path) || config.get(path) == null) return def;
+ return config.getInt(path);
+ }
+
+ public String getStringOrDefault(String path, String def) {
+ if (!config.contains(path) || config.get(path) == null) return def;
+ return config.getString(path);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/minster586/tiktokstream/util/GiftMappingManager.java b/src/main/java/com/minster586/tiktokstream/util/GiftMappingManager.java
new file mode 100644
index 0000000..c46dd40
--- /dev/null
+++ b/src/main/java/com/minster586/tiktokstream/util/GiftMappingManager.java
@@ -0,0 +1,94 @@
+package com.minster586.tiktokstream.util;
+
+import org.bukkit.plugin.java.JavaPlugin;
+
+import java.io.*;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import org.yaml.snakeyaml.Yaml;
+
+public class GiftMappingManager {
+ private final JavaPlugin plugin;
+ private final File mappingFile;
+ private Map giftMap = new HashMap<>();
+
+ public GiftMappingManager(JavaPlugin plugin, String mappingUrl) {
+ this.plugin = plugin;
+ this.mappingFile = new File(plugin.getDataFolder(), "gift-mapping.yaml");
+ checkAndUpdateMapping(mappingUrl);
+ loadMapping();
+ }
+
+ private void checkAndUpdateMapping(String urlStr) {
+ try {
+ // Download remote file to temp
+ File tempFile = File.createTempFile("gift-mapping", ".yaml");
+ try (InputStream in = new URL(urlStr).openStream();
+ FileOutputStream out = new FileOutputStream(tempFile)) {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = in.read(buffer)) != -1) {
+ out.write(buffer, 0, bytesRead);
+ }
+ }
+ // Compare contents
+ boolean shouldReplace = !mappingFile.exists() || !filesEqual(mappingFile, tempFile);
+ if (shouldReplace) {
+ try (InputStream in = new FileInputStream(tempFile);
+ OutputStream out = new FileOutputStream(mappingFile)) {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = in.read(buffer)) != -1) {
+ out.write(buffer, 0, bytesRead);
+ }
+ }
+ plugin.getLogger().info("Gift mapping updated from remote.");
+ } else {
+ plugin.getLogger().info("Gift mapping is up to date.");
+ }
+ tempFile.delete();
+ } catch (IOException e) {
+ plugin.getLogger().warning("Failed to check/update gift mapping: " + e.getMessage());
+ }
+ }
+
+ private boolean filesEqual(File f1, File f2) throws IOException {
+ if (f1.length() != f2.length()) return false;
+ try (InputStream in1 = new FileInputStream(f1); InputStream in2 = new FileInputStream(f2)) {
+ int b1, b2;
+ do {
+ b1 = in1.read();
+ b2 = in2.read();
+ if (b1 != b2) return false;
+ } while (b1 != -1);
+ }
+ return true;
+ }
+
+ // downloadMapping is now handled by checkAndUpdateMapping
+
+ public void loadMapping() {
+ if (!mappingFile.exists()) return;
+ try (InputStream input = new FileInputStream(mappingFile)) {
+ Yaml yaml = new Yaml();
+ Map data = yaml.load(input);
+ giftMap.clear();
+ if (data != null) {
+ for (Map.Entry entry : data.entrySet()) {
+ try {
+ int id = Integer.parseInt(entry.getKey());
+ giftMap.put(id, String.valueOf(entry.getValue()));
+ } catch (NumberFormatException ignored) {}
+ }
+ }
+ } catch (IOException e) {
+ plugin.getLogger().warning("Failed to load gift mapping: " + e.getMessage());
+ }
+ }
+
+ public String getGiftName(int id) {
+ return giftMap.getOrDefault(id, "Unknown Gift");
+ }
+}
diff --git a/src/main/java/com/minster586/tiktokstream/websocket/StreamerBotWebSocketClient.java b/src/main/java/com/minster586/tiktokstream/websocket/StreamerBotWebSocketClient.java
new file mode 100644
index 0000000..c731b50
--- /dev/null
+++ b/src/main/java/com/minster586/tiktokstream/websocket/StreamerBotWebSocketClient.java
@@ -0,0 +1,65 @@
+package com.minster586.tiktokstream.websocket;
+
+
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.handshake.ServerHandshake;
+import java.net.URI;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import com.minster586.tiktokstream.TikTokStreamPlugin;
+import com.minster586.tiktokstream.config.ConfigManager;
+
+public class StreamerBotWebSocketClient extends WebSocketClient {
+ private int retryCount = 0;
+ private final ConfigManager configManager;
+ private final int maxRetries;
+ private final String notifyPermission;
+ private final String notifyMessage;
+
+ public StreamerBotWebSocketClient(URI serverUri) {
+ super(serverUri);
+ this.configManager = TikTokStreamPlugin.getInstance().getConfigManager();
+ this.maxRetries = configManager != null ? configManager.getIntOrDefault("config.websocket.retry-count", 3) : 3;
+ this.notifyPermission = configManager != null ? configManager.getStringOrDefault("config.websocket.notify-permission", "tiktok.live") : "tiktok.live";
+ this.notifyMessage = configManager != null ? configManager.getStringOrDefault("config.websocket.notify-message", "§c[StreamerBot] Could not connect after %retries% attempts. Check your config or Streamer.bot status.") : "§c[StreamerBot] Could not connect after %retries% attempts. Check your config or Streamer.bot status.";
+ }
+
+ @Override
+ public void onOpen(ServerHandshake handshakedata) {
+ retryCount = 0; // Reset on successful connection
+ }
+
+ @Override
+ public void onMessage(String message) {
+ // Handle incoming messages from Streamer.bot here
+ }
+
+ @Override
+ public void onClose(int code, String reason, boolean remote) {
+ if (retryCount < maxRetries) {
+ retryCount++;
+ try {
+ Thread.sleep(2000L * retryCount); // Exponential backoff
+ } catch (InterruptedException ignored) {}
+ this.reconnect();
+ } else {
+ String msg = notifyMessage.replace("%retries%", String.valueOf(maxRetries));
+ notifyOps(msg);
+ }
+ }
+
+ @Override
+ public void onError(Exception ex) {
+ // Optionally log errors
+ }
+
+ private void notifyOps(String message) {
+ Bukkit.getScheduler().runTask(Bukkit.getPluginManager().getPlugin("TikTokStreamPlugin"), () -> {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ if (player.isOp() || player.hasPermission(notifyPermission)) {
+ player.sendMessage(message);
+ }
+ }
+ });
+ }
+}
diff --git a/src/main/java/com/minster586/ui/NotificationManager.java b/src/main/java/com/minster586/ui/NotificationManager.java
new file mode 100644
index 0000000..85bccba
--- /dev/null
+++ b/src/main/java/com/minster586/ui/NotificationManager.java
@@ -0,0 +1,54 @@
+package com.minster586.ui;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import net.md_5.bungee.api.chat.TextComponent;
+import net.md_5.bungee.api.ChatMessageType;
+
+import java.util.Map;
+
+public class NotificationManager {
+ private static final JavaPlugin plugin = JavaPlugin.getProvidingPlugin(NotificationManager.class);
+
+ public static void sendNotification(Player player, ConfigurationSection section, Map placeholders) {
+ if (section == null) return;
+
+ String locationsRaw = section.getString("locations", "").toLowerCase();
+ String[] locations = locationsRaw.split(",");
+
+ for (String loc : locations) {
+ switch (loc.trim()) {
+ case "chat":
+ sendChat(player, section.getString("chat-message", ""), placeholders);
+ break;
+ case "action-bar":
+ sendActionBar(player, section.getString("action-bar-message", ""), placeholders);
+ break;
+ default:
+ Bukkit.getLogger().warning("Unknown notification location: " + loc);
+ }
+ }
+ }
+
+ private static void sendChat(Player player, String message, Map placeholders) {
+ if (message == null || message.isEmpty()) return;
+ player.sendMessage(ChatColor.translateAlternateColorCodes('&', replacePlaceholders(message, placeholders)));
+ }
+
+ private static void sendActionBar(Player player, String message, Map placeholders) {
+ if (message == null || message.isEmpty()) return;
+ player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(replacePlaceholders(message, placeholders)));
+ }
+
+ private static String replacePlaceholders(String input, Map placeholders) {
+ if (input == null) return "";
+ for (Map.Entry entry : placeholders.entrySet()) {
+ input = input.replace("%" + entry.getKey() + "%", entry.getValue());
+ }
+ return input;
+ }
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
new file mode 100644
index 0000000..ce6cfb4
--- /dev/null
+++ b/src/main/resources/config.yml
@@ -0,0 +1,33 @@
+config:
+ prefix: [TikTok]
+ tiktok_username: Change-me #this is the username of your tiktok account with out the "@" symbol
+ giftMappingUrl: "https://yourdomain.com/gift-mapping.yaml" #you can change if need but might want to make sure it follows same scheam
+
+ websocket:
+ url: "ws://localhost:8080" # change IP if need
+ refresh-delay: 6 # this is in seconds
+ retry-count: 3 # Number of times to retry connecting to Streamer.bot
+ notify-permission: "tiktok.live" # Permission required to receive connection failure notifications
+ notify-message: "§c[StreamerBot] Could not connect after %retries% attempts. Check your config or Streamer.bot status."
+
+ settings:
+ join:
+ joined-enabled: true
+ loctions: action-bar #this can be chat, action-bar
+ chat-message: ""
+ action-bar-message: "%username% joined the stream!"
+ gift:
+ gifts-enabled: true
+ loctions: chat #this can be chat, action-bar
+ chat-message: "%prefix% - %username% sent a %giftName%!"
+ action-bar-message: ""
+ chat:
+ chat-enabled: true
+ loctions: chat #this can be chat, action-bar
+ chat-message: "%prefix% - [%username%] > %message%"
+ action-bar-message: ""
+ follows:
+ follow-enabled: true
+ loctions: chat #this can be chat, action-bar
+ chat-message: "%prefix% - [%username%] Followed"
+ action-bar-message: ""
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..2c80df9
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,16 @@
+name: TikTokStreamPlugin
+main: com.minster586.tiktokstream.TikTokStreamPlugin
+version: 1.0.0
+author: minster586
+description: Integrates TikTok Live events with Minecraft 1.19
+api-version: 1.19
+
+commands:
+ tiktok:
+ description: TikTok live control command
+ usage: /tiktok live
+ permission: tiktok.live
+permissions:
+ tiktok.live:
+ description: Allows control of TikTok live notifications
+ default: op