Compare commits

..

61 Commits

Author SHA1 Message Date
8fee6c7f14 Merge pull request #339 from AtlasMediaGroup/merge/development/main
Merge development into main
2023-07-25 13:38:29 -05:00
0559e99fb1 Drop ptero_id column from admin table
Fixes a SQLException thrown when adding admins to an older table schema version.
2023-07-25 18:56:06 +01:00
1251276451 Fix formatting in AdminList 2023-07-25 18:32:59 +01:00
9e584069e6 Ignore interact events from Spectators 2023-07-25 17:43:15 +01:00
11c24cff68 Ignore cancelled interact events 2023-07-25 17:42:32 +01:00
476c87ceb0 Improve Discord bridge sanitization 2023-07-25 17:32:28 +01:00
9bef4581aa Use Bukkit.getScheduler().runTaskAsynchronously to execute the report 2023-07-25 17:08:05 +01:00
794a25ba16 Remove getCommandMap() method in CommandBlocker 2023-07-25 16:40:35 +01:00
b4dd35c4df Stop pinning minor & patch revisions of workflows 2023-07-25 15:13:17 +01:00
ec19b6d398 Make the Discord command parsing more forgiving 2023-07-25 04:13:40 +01:00
b2c636f919 Fix invalid Discord command handling 2023-07-25 03:57:24 +01:00
8876076a9d Fix JDA deprecation issue 2023-07-25 03:47:33 +01:00
80f19f0349 Disable mentions in archival message 2023-07-25 03:47:05 +01:00
011535cf16 Make Discord report filing system asynchronous 2023-07-25 03:45:22 +01:00
eb99dcd3a3 Optimize EssentialsBridge imports 2023-07-25 03:05:19 +01:00
597a464623 Add run/ to .gitignore 2023-07-25 03:05:16 +01:00
08c8393abc Fix ArrayIndexOutOfBounds when a newly added admin leaves the game 2023-07-25 03:05:12 +01:00
ac704614c0 Fix updated plugin versions 2023-07-25 03:05:09 +01:00
04029eb144 Don't try to vanish/unvanish offline players...
(cherry picked from commit a03ecfd6f3248a6b4588db19549d4daf76952742)
2023-07-25 03:05:05 +01:00
00e5403491 Remove SK89Q maven repositories 2023-07-25 03:05:02 +01:00
08115470b0 Fix reactions showing up in Discord bridge & colour codes showing up in bridge 2023-07-25 03:04:56 +01:00
6e140ace7d Fix /ci tab completion throwing exceptions 2023-07-25 00:26:47 +01:00
9ce4dc6f3a Fix CommandSpy colours 2023-07-25 00:21:41 +01:00
f67db2286d Update GitHub actions dependencies 2023-07-25 00:18:26 +01:00
07b3553748 Update Essentials & WorldGuard 2023-07-25 00:16:26 +01:00
bbbccc2b10 Update some dependencies 2023-07-25 00:14:13 +01:00
d471490a94 Merge pull request #338 from AtlasMediaGroup/merge/main/development
Main -> Development
2023-07-24 17:56:29 -05:00
8f6d276bb6 Merge branch 'main' of github.com:AtlasMediaGroup/TotalFreedomMod into merge/main/development 2023-07-24 23:39:09 +01:00
b5178e6761 Merge pull request #336 from AtlasMediaGroup/feat/configurable-item-drops
Add configuration value for player item drops (main)
2023-07-24 17:35:30 -05:00
e11d72b54b Merge branch 'main' into merge/main/development 2023-07-24 23:23:01 +01:00
ee594e7c63 Add configuration value for player item drops 2023-07-23 00:18:23 +01:00
41cf62c8c0 Merge pull request #333 from AtlasMediaGroup/Paldiu-patch-1
Update plugin.yml
2023-07-11 11:49:44 -05:00
268b71f8a3 Update plugin.yml 2023-07-11 11:38:45 -05:00
a84a47980a Merge pull request #331 from AtlasMediaGroup/manual-patch-conflict-1
Update pom.xml
2023-07-11 11:33:47 -05:00
3a502713ea Merge branch 'main' into manual-patch-conflict-1 2023-07-11 09:18:06 -05:00
5dc5e5dcc5 Merge pull request #332 from AtlasMediaGroup/manual-patch-conflict-2
Update plugin.yml
2023-07-11 09:17:54 -05:00
171daf25a4 Update plugin.yml 2023-07-11 09:06:11 -05:00
2fa7b6855b Update pom.xml 2023-07-11 09:05:04 -05:00
7faf719555 Remove UUID from vanished list on removal (#298)
Co-authored-by: Ryan <Wild1145@users.noreply.github.com>
Co-authored-by: Paldiu <pawereus@gmail.com>
2023-07-05 16:10:07 +01:00
3bcf0f5082 Merge pull request #325 from AtlasMediaGroup/dependabot/maven/development/com.sk89q.worldedit-worldedit-bukkit-7.2.15
Bump worldedit-bukkit from 7.2.12 to 7.2.15
2023-07-04 18:49:01 -05:00
c5f24b46d5 Merge pull request #327 from AtlasMediaGroup/ver/1.19.3-main
Update to 1.19.4
2023-07-04 17:37:37 -05:00
3016c57e3e Merge branch 'main' into ver/1.19.3-main 2023-07-04 17:25:10 -05:00
00351f1163 Merge pull request #326 from AtlasMediaGroup/fix/movement-validator
Miscellaneous improvements to the movement validator
2023-07-04 17:24:55 -05:00
40d22fa2e3 Bump worldedit-bukkit from 7.2.12 to 7.2.15
Bumps worldedit-bukkit from 7.2.12 to 7.2.15.

---
updated-dependencies:
- dependency-name: com.sk89q.worldedit:worldedit-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 22:28:55 +00:00
41923b29d7 Merge pull request #301 from AtlasMediaGroup/ver/1.19.3
Update to 1.19.4
2023-07-01 16:28:08 -06:00
0e7a2d9bce Update to 1.19.4 2023-06-20 04:32:45 +01:00
dcebf7bbe7 Use Adventure for kick message 2023-06-17 20:23:54 +01:00
d30e335f57 Disallow custom spawns that are out of bounds 2023-06-17 20:23:24 +01:00
cca95dc3f1 Add dedicated method for checking if a position is out of bounds 2023-06-17 20:23:18 +01:00
42b68011ea Improve distance check 2023-06-17 20:09:22 +01:00
87d7ba19de Remove inventory checks in MovementValidator 2023-06-17 20:06:56 +01:00
16c00e3ed6 Update Scissors API artifact version to 1.19.4 2023-06-11 21:27:27 +01:00
79e7f6904b Merge branch 'development' into ver/1.19.3 2023-04-02 10:21:14 +01:00
1c096b97e3 Merge pull request #314 from AtlasMediaGroup/merge-main-to-dev
Merge main to dev
2023-03-31 21:29:35 -05:00
cc48f93556 Merge branch 'main' into development 2023-03-31 21:15:34 -05:00
dd373fc9aa Merge pull request #307 from AtlasMediaGroup/RELEASE-2022.06.1
Release 2022.06.1
2023-03-31 18:25:42 -05:00
41331e719d Updates version to 2022.06.1 2023-03-08 19:58:14 -07:00
72c83ba84a Merge pull request #306 from AtlasMediaGroup/critical-exploit-fix
Patches critical exploit in the command blocker
2023-03-08 19:53:51 -07:00
3deaaafb88 Patches critical exploit 2023-03-08 19:52:30 -07:00
520bd97176 Merge branch 'development' into ver/1.19.3 2023-03-04 05:14:30 +00:00
654f5900ba Update to 1.19.3 2023-02-20 17:44:57 +00:00
382 changed files with 9407 additions and 9343 deletions

View File

@ -25,7 +25,7 @@ jobs:
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@v4.2.0
uses: codacy/codacy-analysis-cli-action@v4
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations

View File

@ -38,7 +38,7 @@ jobs:
uses: actions/checkout@v3
- name: Setup Java JDK
uses: actions/setup-java@v3.9.0
uses: actions/setup-java@v3
with:
# The Java version to make available on the path. Takes a whole or semver Java version, or 1.x syntax (e.g. 1.8 => Java 8.x). Early access versions can be specified in the form of e.g. 14-ea, 14.0.0-ea, or 14.0.0-ea.28
java-version: 17

View File

@ -13,7 +13,7 @@ jobs:
# Java 16 Builds
- name: Set up JDK 17
uses: actions/setup-java@v3.9.0
uses: actions/setup-java@v3
with:
java-version: 17
distribution: 'adopt'

5
.gitignore vendored
View File

@ -29,7 +29,7 @@ manifest.mf
*.iml
# Maven excludes
target/
/target
# OS generated files
.DS_Store
@ -39,3 +39,6 @@ target/
ehthumbs.db
Thumbs.db
.idea/inspectionProfiles/Project_Default.xml
# Common working directory
run/

View File

@ -1,250 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>me.totalfreedom</groupId>
<artifactId>TotalFreedomMod</artifactId>
<version>2023.03</version>
</parent>
<artifactId>commons</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId>
<version>1.0.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.luckperms</groupId>
<artifactId>api</artifactId>
<version>5.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.inject</artifactId>
<version>0.3.5</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<!-- Filter resources for build.properties -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<!-- Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<outputFileName>TotalFreedomMod.jar</outputFileName>
<compilerVersion>17</compilerVersion>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<!-- Git describe -->
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>4.9.10</version>
<executions>
<execution>
<id>get-the-git-infos</id>
<goals>
<goal>revision</goal>
</goals>
</execution>
<execution>
<id>validate-the-git-infos</id>
<goals>
<goal>validateRevision</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
<prefix>git</prefix>
<dateFormat>yyyy-MM-dd HH:mm:ss</dateFormat>
<verbose>false</verbose>
<format>properties</format>
<failOnNoGitDirectory>false</failOnNoGitDirectory>
<failOnUnableToExtractRepoInfo>false</failOnUnableToExtractRepoInfo>
<includeOnlyProperties>
<includeOnlyProperty>git.commit.id.abbrev</includeOnlyProperty>
</includeOnlyProperties>
<gitDescribe>
<skip>false</skip>
<always>false</always>
<abbrev>7</abbrev>
<dirty>-dirty</dirty>
<match>*</match>
</gitDescribe>
</configuration>
</plugin>
<!-- Antrun -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>default-cli</id>
<phase>initialize</phase>
<configuration>
<target>
<propertyfile file="${project.basedir}/src/main/resources/build.properties"
comment="Build information. Edit this to your liking.">
<entry key="buildAuthor" default="unknown"/>
<entry key="buildNumber" default="0"/>
<entry key="buildCodeName" value="${tfm.build.codename}"/>
<entry key="buildVersion" value="${project.version}"/>
<entry key="buildDate" value="${timestamp}"/>
<!--suppress UnresolvedMavenProperty -->
<entry key="buildHead" value="${git.commit.id.abbrev}"/>
</propertyfile>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Properties -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.1.0</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>${project.basedir}/src/main/resources/build.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
<!-- Buildnumber -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<buildNumberPropertyName>maven.buildnumber</buildNumberPropertyName>
<buildNumberPropertiesFileLocation>${project.basedir}/src/main/resources/build.properties
</buildNumberPropertiesFileLocation>
<format>{0,number,#}</format>
<items>
<item>buildNumber</item>
</items>
</configuration>
</plugin>
<!-- Shade -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<relocations>
<relocation>
<pattern>io.papermc.lib</pattern>
<shadedPattern>me.totalfreedom.totalfreedommod.paperlib
</shadedPattern> <!-- Replace this -->
</relocation>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>me.totalfreedom.totalfreedommod</shadedPattern>
</relocation>
</relocations>
<artifactSet>
<includes>
<include>org.reflections:reflections</include>
<include>io.papermc:paperlib</include>
<include>org.bstats:bstats-bukkit</include>
<include>org.bstats:bstats-base</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,229 +0,0 @@
package me.totalfreedom.totalfreedommod;
import com.google.common.base.Strings;
import io.papermc.paper.event.player.AsyncChatEvent;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.api.event.AdminChatEvent;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.player.FPlayer;
import me.totalfreedom.totalfreedommod.rank.Displayable;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import java.util.Arrays;
public class ChatManager extends FreedomService
{
@Override
public void onStart()
{
}
@Override
public void onStop()
{
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onPlayerChat(AsyncChatEvent event)
{
// Important information for later down the line
String steamrolled = FUtil.steamroll(event.originalMessage());
Player player = event.getPlayer();
FPlayer fPlayer = plugin.pl.getPlayer(player);
// Chat is disabled
if (!ConfigEntry.TOGGLE_CHAT.getBoolean() && !plugin.al.isAdmin(player))
{
event.getPlayer().sendMessage(FUtil.miniMessage("<red>The chat is currently disabled."));
event.setCancelled(true);
return;
}
// Locked up
else if (fPlayer.isLockedUp())
{
event.getPlayer().sendMessage(FUtil.miniMessage("<red>You are locked up and thus can't talk."));
event.setCancelled(true);
return;
}
// Admin chat is enabled
else if (fPlayer.inAdminChat())
{
adminChat(player, steamrolled, true);
event.setCancelled(true);
return;
}
// The event was already cancelled elsewhere or the player was muted
else if (event.isCancelled() || fPlayer.isMuted())
{
return;
}
// Splitter
Component splitter = Component.text("»", NamedTextColor.DARK_GRAY);
// Message
TextComponent.Builder message = Component.text();
// Truncate the message if it's too long
if (steamrolled.length() > 256)
{
steamrolled = steamrolled.substring(0, 256);
}
// Did this because sonarlint was complaining about doing the unboxing in the if statement.
// Something about returning null because it was boxed... I'm not sure.
boolean unboxed = ConfigEntry.FOURCHAN_ENABLED.getBoolean();
// Chat colorization
// -- 4chan mode --
if (steamrolled.startsWith("> ") && unboxed)
{
message.append(Component.text(steamrolled, NamedTextColor.GREEN));
}
// -- Legacy chat colors --
else if (FUtil.containsChatColor(steamrolled))
{
message.append(FUtil.colorizeAsComponent(steamrolled.replace("&k", "")));
}
// -- MiniMessage --
else
{
message.append(FUtil.miniMessage(steamrolled));
}
// This simply filters out shit like &k in a simple but stupid way.
Component filtered = FUtil.miniMessage(FUtil.miniMessage(message.build()));
// Pinging
String steamrolledFiltered = FUtil.steamroll(filtered);
Arrays.stream(steamrolledFiltered.split(" ")).filter(string -> string.startsWith("@")).forEach(possiblePlayer ->
{
Player potential = server.getPlayer(possiblePlayer.replace("@", ""));
// Ping only that particular player
if (potential != null)
{
ping(potential);
}
// Ping everyone (if the person pinging is an admin)
else if (possiblePlayer.equalsIgnoreCase("@everyone") && plugin.al.isAdmin(player))
{
server.getOnlinePlayers().forEach(this::ping);
}
});
event.message(filtered);
event.renderer((source, displayName, msg, viewer) -> FUtil.miniMessage("<tag><nickname> <splitter> <message>",
Placeholder.component("tag", plugin.pl.getPlayer(source).getTag().append(Component.space())),
Placeholder.component("nickname", displayName),
Placeholder.component("splitter", splitter),
Placeholder.component("message", msg)));
}
@EventHandler
public void onAdminChat(AdminChatEvent event)
{
Displayable display = event.getDisplayable();
String flatAbv = FUtil.miniMessage(display.getAbbr());
Component defaultFormat = FUtil.miniMessage("<prefix><dark_gray>[<aqua>ADMIN<dark_gray>] <dark_red><name> <dark_gray>[<rankcolor><rank></rankcolor>]</dark_gray><white>: <gold><message>",
Placeholder.component("prefix", event.getPrefix()),
Placeholder.component("name", event.getName()),
Placeholder.unparsed("rank", flatAbv),
TagResolver.resolver("rankcolor", Tag.styling(getColor(display))),
Placeholder.component("message", event.getMessage()));
plugin.getComponentLogger().info(defaultFormat);
;
server.getOnlinePlayers().stream().filter(player -> plugin.al.isAdmin(player)).forEach(player ->
{
Admin admin = plugin.al.getAdmin(player);
if (!Strings.isNullOrEmpty(admin.getAcFormat()))
{
String format = admin.getAcFormat();
player.sendMessage(FUtil.miniMessage(format,
Placeholder.component("prefix", event.getPrefix()),
Placeholder.component("name", event.getName()),
Placeholder.unparsed("rank", flatAbv),
TagResolver.resolver("rankcolor", Tag.styling(getColor(display))),
Placeholder.component("message", event.getMessage())));
}
else
{
player.sendMessage(defaultFormat);
}
});
}
public TextColor getColor(Displayable display)
{
return display.getColor();
}
public void adminChat(Component name, Displayable displayable, Component message, boolean async)
{
AdminChatEvent event = new AdminChatEvent(name, displayable, message, async);
event.callEvent();
}
public void adminChat(Key key, Component prefix, Component name, Displayable displayable, Component message, boolean async)
{
AdminChatEvent event = new AdminChatEvent(key, prefix, name, displayable, message, async);
event.callEvent();
}
public void adminChat(CommandSender sender, String message)
{
adminChat(sender, message, false);
}
public void adminChat(CommandSender sender, String message, boolean async)
{
Displayable display = plugin.rm.getDisplay(sender);
adminChat(Component.text(sender.getName()), display, Component.text(message), async);
}
public void reportAction(Player reporter, String reportedName, String report)
{
messageAllAdmins("<red>[REPORTS]</red> <gold><reporter> has reported <reported> for <reason>.",
Placeholder.unparsed("reporter", reporter.getName()),
Placeholder.unparsed("reported", reportedName),
Placeholder.unparsed("reason", report));
}
public void messageAllAdmins(String message, TagResolver... placeholders)
{
Component parsed = FUtil.miniMessage(message, placeholders);
plugin.getComponentLogger().info(parsed);
server.getOnlinePlayers().stream().filter(player -> plugin.al.isAdmin(player)).forEach(player ->
player.sendMessage(parsed));
}
public void broadcastSplit(String forAdmins, String forOperators, TagResolver... placeholders)
{
messageAllAdmins(forAdmins, placeholders);
server.getOnlinePlayers().stream().filter(player -> !plugin.al.isAdmin(player)).forEach(player ->
player.sendMessage(FUtil.miniMessage(forOperators, placeholders)));
}
public void ping(Player player)
{
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, SoundCategory.MASTER, 1337F, 0.9F);
}
}

View File

@ -1,181 +0,0 @@
package me.totalfreedom.totalfreedommod;
import com.google.common.collect.Multimap;
import io.papermc.lib.PaperLib;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class MovementValidator extends FreedomService
{
public static final int MAX_XYZ_COORD = 29999998;
public static final int MAX_DISTANCE_TRAVELED = 100;
@Override
public void onStart()
{
}
@Override
public void onStop()
{
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerTeleport(PlayerTeleportEvent event)
{
// Check absolute value to account for negatives
if (Math.abs(Objects.requireNonNull(event.getTo()).getX()) >= MAX_XYZ_COORD || Math.abs(event.getTo().getZ()) >= MAX_XYZ_COORD || Math.abs(event.getTo().getY()) >= MAX_XYZ_COORD)
{
event.setCancelled(true); // illegal position, cancel it
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerMove(PlayerMoveEvent event)
{
final Player player = event.getPlayer();
Location from = event.getFrom();
Location to = event.getTo();
assert to != null;
if (to.getX() >= from.getX() + MAX_DISTANCE_TRAVELED || to.getY() >= from.getY() + MAX_DISTANCE_TRAVELED || to.getZ() >= from.getZ() + MAX_DISTANCE_TRAVELED)
{
event.setCancelled(true);
player.kickPlayer(ChatColor.RED + "You were moving too quickly!");
}
// Check absolute value to account for negatives
if (Math.abs(event.getTo().getX()) >= MAX_XYZ_COORD || Math.abs(event.getTo().getZ()) >= MAX_XYZ_COORD || Math.abs(event.getTo().getY()) >= MAX_XYZ_COORD)
{
event.setCancelled(true);
PaperLib.teleportAsync(player, player.getWorld().getSpawnLocation());
}
if (exploitItem(event.getPlayer().getInventory().getHelmet()))
{
event.getPlayer().getInventory().setHelmet(new ItemStack(Material.AIR));
event.getPlayer().sendMessage(ChatColor.RED + "An item with both negative infinity and positive infinity attributes was cleared from your helmet slot.");
event.setCancelled(true);
}
if (exploitItem(event.getPlayer().getInventory().getBoots()))
{
event.getPlayer().getInventory().setBoots(new ItemStack(Material.AIR));
event.getPlayer().sendMessage(ChatColor.RED + "An item with both negative infinity and positive infinity attributes was cleared from your boots slot.");
event.setCancelled(true);
}
if (exploitItem(event.getPlayer().getInventory().getLeggings()))
{
event.getPlayer().getInventory().setLeggings(new ItemStack(Material.AIR));
event.getPlayer().sendMessage(ChatColor.RED + "An item with both negative infinity and positive infinity attributes was cleared from your leggings slot.");
event.setCancelled(true);
}
if (exploitItem(event.getPlayer().getInventory().getChestplate()))
{
event.getPlayer().getInventory().setChestplate(new ItemStack(Material.AIR));
event.getPlayer().sendMessage(ChatColor.RED + "An item with both negative infinity and positive infinity attributes was cleared from your chestplate slot.");
event.setCancelled(true);
}
if (exploitItem(event.getPlayer().getInventory().getItemInMainHand()))
{
event.getPlayer().getInventory().setItemInMainHand(new ItemStack(Material.AIR));
event.getPlayer().sendMessage(ChatColor.RED + "An item with both negative infinity and positive infinity attributes was cleared from your hand.");
event.setCancelled(true);
}
if (exploitItem(event.getPlayer().getInventory().getItemInOffHand()))
{
event.getPlayer().getInventory().setItemInOffHand(new ItemStack(Material.AIR));
event.getPlayer().sendMessage(ChatColor.RED + "An item with both negative infinity and positive infinity attributes was cleared from your offhand.");
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerLogin(PlayerLoginEvent event)
{
final Player player = event.getPlayer();
// Validate position
if (Math.abs(player.getLocation().getX()) >= MAX_XYZ_COORD || Math.abs(player.getLocation().getZ()) >= MAX_XYZ_COORD || Math.abs(player.getLocation().getY()) >= MAX_XYZ_COORD)
{
PaperLib.teleportAsync(player, player.getWorld().getSpawnLocation()); // Illegal position, teleport to spawn
}
}
@EventHandler
public void onPlayerHoldItem(PlayerItemHeldEvent event)
{
if (exploitItem(event.getPlayer().getInventory().getItemInMainHand()))
{
event.getPlayer().getInventory().setItemInMainHand(new ItemStack(Material.AIR));
event.getPlayer().sendMessage(ChatColor.RED + "An item with both negative infinity and positive infinity attributes was cleared from your hand.");
}
if (exploitItem(event.getPlayer().getInventory().getItemInOffHand()))
{
event.getPlayer().getInventory().setItemInOffHand(new ItemStack(Material.AIR));
event.getPlayer().sendMessage(ChatColor.RED + "An item with both negative infinity and positive infinity attributes was cleared from your offhand.");
}
}
private Boolean exploitItem(ItemStack item)
{
if (item == null)
{
return false;
}
ItemMeta meta = item.getItemMeta();
if (meta != null)
{
Multimap<Attribute, AttributeModifier> attributes = meta.getAttributeModifiers();
if (attributes != null)
{
Map<Attribute, Collection<AttributeModifier>> attrMap = attributes.asMap();
// For every attribute...
for (Attribute attr : attributes.keySet())
{
// Default values
boolean posInf = false;
boolean negInf = false;
// For every AttributeModifier...
for (AttributeModifier modifier : attrMap.get(attr))
{
// Are they ∞ or -∞?
if (modifier.getAmount() == Double.POSITIVE_INFINITY)
{
posInf = true;
}
else if (modifier.getAmount() == Double.NEGATIVE_INFINITY)
{
negInf = true;
}
}
// Are both values set as true?
if (posInf && negInf)
{
return true;
}
}
}
}
return false;
}
}

View File

@ -1,27 +0,0 @@
package me.totalfreedom.totalfreedommod.api;
public class Aggregator
{
private Context<TFD4JCommons> discord;
private Context<ShoppeCommons> shoppe;
public Context<TFD4JCommons> getDiscordContext()
{
return discord;
}
public void setDiscordContext(Context<TFD4JCommons> discord)
{
this.discord = discord;
}
public Context<ShoppeCommons> getShoppeContext()
{
return shoppe;
}
public void setShoppeContext(Context<ShoppeCommons> shoppe)
{
this.shoppe = shoppe;
}
}

View File

@ -1,16 +0,0 @@
package me.totalfreedom.totalfreedommod.api;
public class Context<T>
{
private final T value;
public Context(T value)
{
this.value = value;
}
public T getValue()
{
return value;
}
}

View File

@ -1,7 +0,0 @@
package me.totalfreedom.totalfreedommod.api;
@FunctionalInterface
public interface Interpolator
{
double[] interpolate(double from, double to, int max);
}

View File

@ -1,55 +0,0 @@
package me.totalfreedom.totalfreedommod.api;
import me.totalfreedom.totalfreedommod.player.PlayerData;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
public interface ShoppeCommons
{
int getCoinsPerReactionWin();
void startReactionTimer();
void forceStartReaction();
void startReaction();
void endReaction(String winner);
String getShopPrefix();
String getShopTitle();
Inventory generateShopGUI(PlayerData playerData);
Inventory generateLoginMessageGUI(Player player);
boolean isRealItem(PlayerData data, ShopItem shopItem, PlayerInventory inventory, ItemStack realItem);
boolean isRealItem(PlayerData data, ShopItem shopItem, ItemStack givenItem, ItemStack realItem);
ItemStack getLightningRod();
ItemStack getGrapplingHook();
ItemStack getFireBall();
ItemStack getRideablePearl();
ItemStack getStackingPotato();
ItemStack getClownFish();
boolean canAfford(int price, int coins);
int amountNeeded(int price, int coins);
ItemStack shopGUIItem(ShopItem item, PlayerData data);
ShopItem getShopItem(int slot);
String getReactionString();
}

View File

@ -1,33 +0,0 @@
package me.totalfreedom.totalfreedommod.api;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.player.PlayerData;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.util.Map;
public interface TFD4JCommons
{
void messageAdminChatChannel(String message);
void clearQueue();
void messageChatChannel(String message, boolean system);
boolean syncRoles(Admin admin, String id);
String getCode(PlayerData playerData);
String generateCode(int size);
Map<String, PlayerData> getLinkCodes();
String formatBotTag();
boolean sendReportOffline(Player reporter, OfflinePlayer reported, String reason);
boolean sendReport(Player reporter, Player reported, String reason);
boolean isEnabled();
}

View File

@ -1,74 +0,0 @@
package me.totalfreedom.totalfreedommod.api.event;
import me.totalfreedom.totalfreedommod.rank.Displayable;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public class AdminChatEvent extends Event
{
private static HandlerList handlerList = new HandlerList();
//--
private Key identifier;
private Component prefix = Component.empty();
private Component name;
private Displayable displayable;
private Component message;
public AdminChatEvent(Key identifier, Component prefix, Component name, Displayable rank, Component message, boolean async)
{
super(async);
this.identifier = identifier;
this.prefix = prefix;
this.name = name;
this.displayable = rank;
this.message = message;
}
public AdminChatEvent(Component name, Displayable rank, Component message, boolean async)
{
super(async);
this.identifier = Key.key("tfm", "default");
this.name = name;
this.displayable = rank;
this.message = message;
}
public static HandlerList getHandlerList()
{
return handlerList;
}
@Override
public @NotNull HandlerList getHandlers()
{
return handlerList;
}
public Key getIdentifier()
{
return identifier;
}
public Component getPrefix()
{
return prefix;
}
public Component getName()
{
return name;
}
public Displayable getDisplayable()
{
return displayable;
}
public Component getMessage()
{
return message;
}
}

View File

@ -1,59 +0,0 @@
package me.totalfreedom.totalfreedommod.bridge;
import me.totalfreedom.totalfreedommod.rank.GroupProvider;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.track.TrackManager;
import org.bukkit.Bukkit;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.UnknownDependencyException;
public class LuckPermsBridge
{
private final LuckPerms luckPerms;
public LuckPermsBridge()
{
RegisteredServiceProvider<LuckPerms> provider = Bukkit.getServicesManager()
.getRegistration(LuckPerms.class);
if (provider == null) throw new UnknownDependencyException("LuckPerms must be present!");
this.luckPerms = provider.getProvider();
setupTracks();
}
public LuckPerms getAPI()
{
return luckPerms;
}
public void setupTracks()
{
TrackManager trackManager = getAPI().getTrackManager();
if (!trackManager.isLoaded("fakeOp"))
{
trackManager.createAndLoadTrack("fakeOp").whenComplete((track, exception) ->
{
track.appendGroup(GroupProvider.NON_OP.getGroup().getLuckPermsGroup());
track.appendGroup(GroupProvider.OP.getGroup().getLuckPermsGroup());
});
}
if (!trackManager.isLoaded("admin"))
{
trackManager.createAndLoadTrack("admin").whenComplete((track, exception) ->
{
track.appendGroup(GroupProvider.ADMIN.getGroup().getLuckPermsGroup());
track.appendGroup(GroupProvider.SENIOR_ADMIN.getGroup().getLuckPermsGroup());
});
}
if (!trackManager.isLoaded("builder"))
{
trackManager.createAndLoadTrack("builder").whenComplete((track, exception) ->
track.appendGroup(GroupProvider.MASTER_BUILDER.getGroup().getLuckPermsGroup()));
}
}
}

View File

@ -1,45 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.*;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
@Intercept("banlist")
@CommandPermissions(permission = "banlist", source = SourceType.BOTH)
@CommandParameters(description = "Shows all banned player names. Admins may optionally use 'purge' to clear the list.", usage = "/<command> [purge]")
public class Command_banlist extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length > 0)
{
if (args[0].equalsIgnoreCase("purge"))
{
checkPermission("tfm.banlist.purge");
FUtil.adminAction(sender.getName(), "Purging the ban list", true);
msgNew("<green>Purged <amount> player bans.", Placeholder.unparsed("amount", String.valueOf(plugin.bm.purge())));
return true;
}
return false;
}
msgNew("<total> player bans (<usernames> usernames, <ips> IPs)",
Placeholder.unparsed("total", String.valueOf(plugin.bm.getAllBans().size())),
Placeholder.unparsed("usernames", String.valueOf(plugin.bm.getUsernameBans())),
Placeholder.unparsed("ips", String.valueOf(plugin.bm.getIpBans().size())));
return true;
}
@Override
protected List<String> getTabCompleteOptions(CommandSender sender, Command command, String alias, String[] args)
{
return args.length == 1 && sender.hasPermission("tfm.banlist.purge") ? Collections.singletonList("purge") : Collections.emptyList();
}
}

View File

@ -1,115 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.player.FPlayer;
import me.totalfreedom.totalfreedommod.punishments.Punishment;
import me.totalfreedom.totalfreedommod.punishments.PunishmentType;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
@CommandPermissions(permission = "blockpvp", source = SourceType.BOTH)
@CommandParameters(description = "Toggle PVP mode for everyone or a certain player.", usage = "/<command> [<player> | list | purge | all]", aliases = "pvpblock,pvpmode")
public class Command_blockpvp extends FreedomCommand
{
@Override
public boolean run(final CommandSender sender, final Player playerSender, final Command cmd, final String commandLabel, String[] args, final boolean senderIsConsole)
{
if (args.length == 0)
{
return false;
}
switch (args[0].toLowerCase())
{
// List
case "list" ->
{
List<String> restricted = server.getOnlinePlayers().stream().filter(player ->
plugin.pl.getPlayer(player).isPvpBlocked()).map(Player::getName).toList();
if (restricted.isEmpty())
{
msgNew("Nobody currently has their PVP abilities restricted.");
}
else
{
msgNew("PVP abilities are restricted for these player(s): <players>",
Placeholder.unparsed("players", FUtil.listToString(restricted)));
}
return true;
}
// Purge
case "purge" ->
{
FUtil.adminAction(sender.getName(), "Restoring PVP abilities for all players", true);
List<? extends Player> affected = server.getOnlinePlayers().stream().filter(player -> plugin.pl.getPlayer(player).isPvpBlocked()).toList();
affected.forEach(player ->
{
msgNew(player, "<green>Your PVP abilities have been restored.");
plugin.pl.getPlayer(player).setPvpBlocked(false);
});
msgNew("Restored PVP abilities for <count> players.", Placeholder.unparsed("count", String.valueOf(affected.size())));
}
// All
case "all" ->
{
FUtil.adminAction(sender.getName(), "Restricting PVP capabilities for all non-admins", true);
List<? extends Player> affected = server.getOnlinePlayers().stream().filter(player -> !plugin.al.isAdmin(player)).toList();
affected.forEach(player ->
{
msgNew(player, "<red>Your PVP abilities have been restricted.");
plugin.pl.getPlayer(player).setPvpBlocked(true);
});
msgNew("Restricted PVP abilities for <count> players.", Placeholder.unparsed("count", String.valueOf(affected.size())));
}
// Specific players
default ->
{
final Player p = getPlayer(args[0]);
if (p == null)
{
msg(PLAYER_NOT_FOUND);
return true;
}
final FPlayer pd = plugin.pl.getPlayer(p);
if (pd.isPvpBlocked())
{
FUtil.adminAction(sender.getName(), "Restoring PVP capabilities for " + p.getName(), true);
pd.setPvpBlocked(false);
msgNew("Enabled the ability to PVP for <player>.", Placeholder.unparsed("player", p.getName()));
msgNew(p, "<green>Your PVP abilities have been restored.");
}
else
{
if (plugin.al.isAdmin(p))
{
msgNew("<red><player> is an admin, and cannot have their PVP disabled.", Placeholder.unparsed("player", p.getName()));
return true;
}
FUtil.adminAction(sender.getName(), "Restricting PVP for " + p.getName(), true);
pd.setPvpBlocked(true);
plugin.pul.logPunishment(new Punishment(p.getName(), FUtil.getIp(p), sender.getName(), PunishmentType.BLOCKPVP, null));
msgNew(p, "<red>Your PVP abilities have been restricted.");
msgNew("Restricted PVP abilities for <player>. ", Placeholder.unparsed("player", p.getName()));
}
}
}
return true;
}
}

View File

@ -1,42 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.api.ShopItem;
import me.totalfreedom.totalfreedommod.command.handling.*;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandDependencies({"TF-Shoppe"})
@CommandPermissions(permission = "clownfish", source = SourceType.ONLY_IN_GAME)
@CommandParameters(description = "Obtain a clown fish", usage = "/<command>")
public class Command_clownfish extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (plugin.sh == null)
{
msgNew("<red>Shop is currently disabled.");
return true;
}
if (plugin.pl.getData(playerSender).hasItem(ShopItem.CLOWN_FISH))
{
playerSender.getInventory().addItem(plugin.sh.getClownFish());
msgNew("<green>You have been given a <name>.", Placeholder.unparsed("name", ShopItem.CLOWN_FISH.getName()));
}
else if (plugin.pl.getPlayer(playerSender).isClownfishDisabled())
{
msgNew("<red>An admin has disabled your ability to use the <name>. Guess you were the clown after all.",
Placeholder.unparsed("name", ShopItem.CLOWN_FISH.getName()));
}
else
{
msgNew("<red>You don't own a <name>! Purchase one from the shop.", Placeholder.unparsed("name", ShopItem.CLOWN_FISH.getName()));
}
return true;
}
}

View File

@ -1,39 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.apache.commons.lang.StringUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandPermissions(permission = "consolesay", source = SourceType.ONLY_CONSOLE)
@CommandParameters(description = "Telnet/Console command - Send a chat message with chat formatting over telnet.", usage = "/<command> <message>", aliases = "csay")
public class Command_consolesay extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length == 0)
{
return false;
}
server.broadcast(FUtil.miniMessage("<gray>[CONSOLE] <red><sender> <dark_gray>» <white><message>",
Placeholder.unparsed("sender", sender.getName()),
Placeholder.unparsed("message", StringUtils.join(args, " "))));
if (plugin.dc != null)
{
String message = StringUtils.join(args, " ");
plugin.dc.messageChatChannel("[CONSOLE] " + sender.getName() + " \u00BB " + ChatColor.stripColor(message), true);
}
return true;
}
}

View File

@ -1,38 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import java.util.Collections;
import java.util.Random;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.util.FUtil;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
@CommandPermissions(permission = "cookie", source = SourceType.BOTH)
@CommandParameters(description = "For those who have no friends - gives a cookie to everyone on the server.", usage = "/<command>")
public class Command_cookie extends FreedomCommand
{
private static final Random RANDOM = new Random();
@Override
public boolean run(CommandSender sender, Player sender_p, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
final ItemStack heldItem = new ItemStack(Material.COOKIE);
final ItemMeta heldItemMeta = heldItem.getItemMeta();
assert heldItemMeta != null;
heldItemMeta.displayName(FUtil.miniMessage("<rainbow>Cookie"));
heldItemMeta.lore(Collections.singletonList(FUtil.miniMessage("<rainbow>But, you can have a cookie anyways,\nsince you are sad you are have no friends.")));
heldItem.setItemMeta(heldItemMeta);
server.getOnlinePlayers().forEach(player -> player.getInventory().addItem(heldItem));
server.broadcast(FUtil.miniMessage("<rainbow:" + RANDOM.nextInt() + ">Imagine that you have zero cookies and you split them evenly among zero friends. How many cookies does each person get? See? It doesn't make sense. And Cookie Monster is sad that there are no cookies, and you are sad that you have no friends."));
return true;
}
}

View File

@ -1,68 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.*;
import me.totalfreedom.totalfreedommod.rank.Hierarchy;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.concurrent.atomic.AtomicBoolean;
@Intercept("deop")
@CommandPermissions(permission = "deop", source = SourceType.BOTH)
@CommandParameters(description = "Deop a player", usage = "/<command> <partialname>")
public class Command_deop extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length < 1)
{
return false;
}
boolean silent = false;
if (args.length == 2)
{
silent = args[1].equalsIgnoreCase("-s");
}
Player player = Bukkit.getServer().getPlayer(args[0]);
if (player == null || plugin.al.isVanished(player.getUniqueId()))
{
msg(sender, PLAYER_NOT_FOUND);
return true;
}
AtomicBoolean atomicBoolean = new AtomicBoolean(silent);
Hierarchy.getHierarchy().demoteUser(Hierarchy.getHierarchy().op(), player).whenComplete((result, throwable) ->
{
if (throwable != null)
{
msgNew("<red>Could not demote <player> to non-OP. Check the logs for more details.", player(player));
FLog.severe("Error while demoting " + player.getName() + " to non-OP:");
FLog.severe(throwable);
return;
}
if (result == null || !result.wasSuccessful()) {
msgNew("<red><player> is already non-op.", Placeholder.unparsed("player", player.getName()));
return;
}
msg(player, YOU_ARE_NOT_OP);
if (!atomicBoolean.get())
{
FUtil.adminAction(sender.getName(), "De-opping " + player.getName(), false);
}
});
return true;
}
}

View File

@ -1,46 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.rank.Hierarchy;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandPermissions(permission = "deop.all", source = SourceType.BOTH, blockHostConsole = true)
@CommandParameters(description = "Deop everyone on the server.", usage = "/<command>")
public class Command_deopall extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
FUtil.adminAction(sender.getName(), "De-opping all players on the server", true);
server.getOnlinePlayers().forEach(player ->
Hierarchy.getHierarchy().demoteUser(Hierarchy.getHierarchy().op(), player).whenComplete((result, ex) ->
{
if (ex != null)
{
msgNew("<red>Could not demote <player> to non-OP. Check the logs for more details.", player(player));
FLog.severe("Failed to demote " + player.getName() + " to non-OP:");
FLog.severe(ex);
return;
}
if (result == null || !result.wasSuccessful()) {
msgNew("<red><player> is already non-OP.", Placeholder.unparsed("player", player.getName()));
return;
}
msg(player, YOU_ARE_NOT_OP);
}));
return true;
}
}

View File

@ -1,32 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.player.FPlayer;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandPermissions(permission = "explosivearrows", source = SourceType.ONLY_IN_GAME)
@CommandParameters(description = "Make arrows explode", usage = "/<command>", aliases = "ea")
public class Command_explosivearrows extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
FPlayer player = plugin.pl.getPlayer(playerSender);
player.setExplosiveArrowsEnabled(!player.isExplosiveArrowsEnabled());
msgNew("<statuscolor>You <status> have explosive arrows.",
TagResolver.resolver("statuscolor", Tag.styling(player.isExplosiveArrowsEnabled() ? NamedTextColor.GREEN : NamedTextColor.RED)),
Placeholder.unparsed("status", player.isExplosiveArrowsEnabled() ? "now" : "no longer"));
return true;
}
}

View File

@ -1,35 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.api.ShopItem;
import me.totalfreedom.totalfreedommod.command.handling.*;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandDependencies({"TF-Shoppe"})
@CommandPermissions(permission = "fireball", source = SourceType.ONLY_IN_GAME)
@CommandParameters(description = "Obtain a fire ball", usage = "/<command>")
public class Command_fireball extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (plugin.sh == null)
{
msgNew("<red>Shop is currently disabled.");
return true;
}
if (plugin.pl.getData(playerSender).hasItem(ShopItem.FIRE_BALL))
{
playerSender.getInventory().addItem(plugin.sh.getFireBall());
msgNew("<green>You have been given the <item>.", Placeholder.unparsed("item", ShopItem.FIRE_BALL.getName()));
}
else
{
msgNew("<red>You don't own the <item>! Purchase it from the shop.", Placeholder.unparsed("item", ShopItem.FIRE_BALL.getName()));
}
return true;
}
}

View File

@ -1,70 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.freeze.FreezeData;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandPermissions(permission = "freeze", source = SourceType.BOTH)
@CommandParameters(description = "Freeze/Unfreeze a specified player, or all non-admins on the server.", usage = "/<command> [target | purge]", aliases = "fr")
public class Command_freeze extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length == 0)
{
boolean gFreeze = !plugin.fm.isGlobalFreeze();
plugin.fm.setGlobalFreeze(gFreeze);
if (!gFreeze)
{
FUtil.adminAction(sender.getName(), "Unfreezing all players", false);
msgNew("Players are now free to move.");
}
else
{
FUtil.adminAction(sender.getName(), "Freezing all players", false);
server.getOnlinePlayers().stream().filter(player -> !isAdmin(player)).forEach(player ->
{
FUtil.playerTitle(player, "<red>You have been frozen.", "<yellow>Please be patient and you will be unfrozen shortly.");
msgNew(player, "<red>You have been globally frozen due to an OP breaking the rules, please wait and you will be unfrozen soon.");
});
msgNew("Players are now frozen.");
}
return true;
}
if (args[0].equalsIgnoreCase("purge"))
{
FUtil.adminAction(sender.getName(), "Unfreezing all players", false);
plugin.fm.purge();
server.getOnlinePlayers().stream().filter(player -> !isAdmin(player)).forEach(player -> FUtil.playerTitle(player, "<green>You have been unfrozen.", "<yellow>You may now move again."));
return true;
}
final Player player = getPlayer(args[0]);
if (player == null)
{
msg(PLAYER_NOT_FOUND);
return true;
}
final FreezeData fd = plugin.pl.getPlayer(player).getFreezeData();
fd.setFrozen(!fd.isFrozen());
msgNew("<player> has been <status>.", Placeholder.unparsed("player", player.getName()),
Placeholder.unparsed("status", fd.isFrozen() ? "frozen" : "unfrozen"));
msgNew(player, "You have been <status>.", Placeholder.unparsed("status", fd.isFrozen() ? "frozen" : "unfrozen"));
return true;
}
}

View File

@ -1,60 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.api.ShopItem;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.player.PlayerData;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.apache.commons.lang.StringUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandPermissions(permission = "loginmessage", source = SourceType.ONLY_IN_GAME)
@CommandParameters(description = "Change your login message", usage = "/<command> [message]")
public class Command_loginmessage extends FreedomCommand
{
@Override
public boolean run(final CommandSender sender, final Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (plugin.sh == null && !sender.hasPermission("tfm.loginmessage.custom") || !plugin.pl.getData(playerSender).hasItem(ShopItem.LOGIN_MESSAGES) && !isAdmin(playerSender))
{
msg("You did not purchase the ability to use login messages, or the shop is not present! Purchase the ability from the shop.", ChatColor.RED);
return true;
}
if (args.length == 0)
{
playerSender.openInventory(plugin.sh.generateLoginMessageGUI(playerSender));
return true;
}
checkPermission("tfm.loginmessage.custom");
String message = StringUtils.join(args, " ");
if (!message.contains("<rank>") && !message.contains("<coloredrank>"))
{
msgNew("<red>Your login message must contain your rank. Use either \\\\<rank> or \\\\<coloredrank> to specify where you want the rank.");
return true;
}
int length = FUtil.steamroll(FUtil.miniMessage(message, Placeholder.unparsed("name", ""),
Placeholder.unparsed("rank", ""),
Placeholder.unparsed("coloredrank", ""),
Placeholder.unparsed("art", ""))).length();
if (length > 100)
{
msgNew("<red>Your login message cannot be more than 100 characters (excluding your rank and your name)");
return true;
}
PlayerData data = getData(playerSender);
data.setLoginMessage(message);
plugin.pl.save(data);
msgNew("<green>Your login message is now the following:");
msg(plugin.rm.craftLoginMessage(playerSender, message));
return true;
}
}

View File

@ -1,48 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandPermissions(permission = "nickmm", source = SourceType.ONLY_IN_GAME)
@CommandParameters(description = """
Essentials Interface Command - Colorify your nickname.
For Example: /nickmm <red><name> will color your name red.
You can also use tags like <gradient> and <rainbow>.
For example: /nickmm <gradient:red:green:blue><name>""", usage = "/<command> <nickname>")
public class Command_nickmm extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (!server.getPluginManager().isPluginEnabled("Essentials"))
{
msg("Essentials is not enabled on this server.");
return true;
}
if (args[0].isEmpty()) {
return false;
}
if (args[0].matches(ChatColor.COLOR_CHAR + "[0-9a-fkm-o]"))
{
msgNew("<red>That nickname contains invalid characters.");
return true;
}
Component parsed = FUtil.miniMessage(args[0], Placeholder.unparsed("name", sender.getName()));
plugin.esb.setNickname(sender.getName(), FUtil.miniMessage(parsed));
msgNew("Your nickname is now: " + FUtil.miniMessage(parsed));
return false;
}
}

View File

@ -1,73 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.*;
import me.totalfreedom.totalfreedommod.rank.Hierarchy;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.concurrent.atomic.AtomicBoolean;
@Intercept("op")
@CommandPermissions(permission = "op", source = SourceType.BOTH, cooldown = 5)
@CommandParameters(description = "OP a player", usage = "/<command> <partialname>")
public class Command_op extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length < 1)
{
return false;
}
boolean silent = false;
if (args.length == 2)
{
silent = args[1].equalsIgnoreCase("-s");
}
Player player = Bukkit.getServer().getPlayer(args[0]);
if (player == null || plugin.al.isVanished(player.getUniqueId()))
{
msg(sender, PLAYER_NOT_FOUND);
return true;
}
AtomicBoolean atomicBoolean = new AtomicBoolean(silent);
Hierarchy.getHierarchy().promoteUser(Hierarchy.getHierarchy().op(), player).whenComplete((result, throwable) ->
{
if (throwable != null)
{
msgNew("<red>Failed to promote <player> to OP. Check logs for more details.", player(player));
FLog.severe("Failed to promote " + player.getName() + " to OP:");
FLog.severe(throwable);
return;
}
if (result == null) {
msgNew("<red><player> was not on the track! Added.", player(player));
}
else if (!result.wasSuccessful())
{
msgNew("<red><player> is already OP!", player(player));
return;
}
msg(player, YOU_ARE_OP);
if (!atomicBoolean.get())
{
FUtil.adminAction(sender.getName(), "Opping " + player.getName(), false);
}
});
return true;
}
}

View File

@ -1,46 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.rank.Hierarchy;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandPermissions(permission = "op.all", source = SourceType.BOTH, cooldown = 30)
@CommandParameters(description = "OP everyone on the server.", usage = "/<command>")
public class Command_opall extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
FUtil.adminAction(sender.getName(), "Opping all players on the server", true);
server.getOnlinePlayers().forEach(player ->
Hierarchy.getHierarchy().promoteUser(Hierarchy.getHierarchy().op(), player).whenComplete((result, throwable) ->
{
if (throwable != null)
{
msgNew("<red>Failed to promote <player> to OP. Check the logs for more details.", player(player));
FLog.severe("Failed to promote " + player.getName());
FLog.severe(throwable);
return;
}
if (result == null) {
msgNew("<red><player> was not present on the track! Added.", player(player));
} else if (!result.wasSuccessful()) {
msgNew("<red>Player is already OP!", player(player));
return;
}
msg(player, YOU_ARE_OP);
}));
return true;
}
}

View File

@ -1,41 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.rank.Hierarchy;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandPermissions(permission = "opme", source = SourceType.ONLY_IN_GAME)
@CommandParameters(description = "OPs the command sender.", usage = "/<command>")
public class Command_opme extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
FUtil.adminAction(sender.getName(), "Opping " + sender.getName(), false);
Hierarchy.getHierarchy().promoteUser(Hierarchy.getHierarchy().op(), playerSender)
.whenComplete((result, error) ->
{
if (error != null)
{
FLog.severe("Error while promoting " + playerSender.getName() + " to OP: " + error.getMessage());
return;
}
if (result != null && !result.wasSuccessful()) {
msgNew("<red>You are already op!");
return;
}
msg(YOU_ARE_OP);
});
return true;
}
}

View File

@ -1,61 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.*;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Intercept("report")
@CommandPermissions(permission = "report", source = SourceType.ONLY_IN_GAME, blockHostConsole = true)
@CommandParameters(description = "Report a player for all admins to see.", usage = "/<command> <player> <reason>")
public class Command_report extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length < 2)
{
return false;
}
OfflinePlayer player = Bukkit.getOfflinePlayer(args[0]);
if (sender instanceof Player && (player.equals(playerSender)))
{
msgNew("<red>Please, don't try to report yourself.");
return true;
}
if (plugin.al.isAdmin(player))
{
msgNew("<red>You can't report admins with this command.");
return true;
}
String report = StringUtils.join(ArrayUtils.subarray(args, 1, args.length), " ");
plugin.cm.reportAction(playerSender, player.getName(), report);
boolean logged = false;
if (plugin.dc != null && plugin.dc.isEnabled())
{
Player online = Bukkit.getPlayer(player.getUniqueId());
logged = (online != null)
? plugin.dc.sendReport(playerSender, online, report)
: plugin.dc.sendReportOffline(playerSender, player, report);
}
msgNew("<green>Thank you, your report has been successfully logged.");
if (logged)
{
msgNew("<red>Note: This report has been logged to a Discord channel, as with any report system, spamming reports can lead to you getting banned.");
}
return true;
}
}

View File

@ -1,329 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.player.FPlayer;
import me.totalfreedom.totalfreedommod.rank.DisplayableGroup;
import me.totalfreedom.totalfreedommod.rank.GroupProvider;
import me.totalfreedom.totalfreedommod.rank.Hierarchy;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import me.totalfreedom.totalfreedommod.util.PermissibleCompletion;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.luckperms.api.model.group.Group;
import org.apache.commons.lang.StringUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@CommandPermissions(permission = "saconfig", source = SourceType.BOTH)
@CommandParameters(description = "List, add, remove, or set the rank of admins, clean or reload the admin list, or view admin information.", usage = "/<command> <list | clean | reload | | setrank <username> <rank> | <add | remove | info> <username>>", aliases = "slconfig")
public class Command_saconfig extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length < 1)
{
return false;
}
switch (args[0])
{
case "list" ->
{
msgNew("<gold>Admins: <admins>", Placeholder.unparsed("admins", StringUtils.join(plugin.al.getAdminNames(), ", ")));
return true;
}
case "clean" ->
{
checkConsole();
checkPermission("tfm.saconfig.clean");
FUtil.adminAction(sender.getName(), "Cleaning the admin list", true);
plugin.al.deactivateOldEntries(true);
msgNew("<gold>Admins: <admins>", Placeholder.unparsed("admins", StringUtils.join(plugin.al.getAdminNames(), ", ")));
return true;
}
case "reload" ->
{
checkPermission("tfm.saconfig.reload");
FUtil.adminAction(sender.getName(), "Reloading the admin list", true);
plugin.al.load();
msgNew("Admin list reloaded!");
return true;
}
case "promote" ->
{
checkConsole();
checkPermission("tfm.saconfig.promote");
if (args.length < 2)
{
return false;
}
Player player = getPlayer(args[1]);
if (player == null)
{
msgNew("<red>Player not found.");
return true;
}
Hierarchy.getHierarchy()
.promoteUser(Hierarchy.getHierarchy().admin(), player)
.whenComplete((result, ex) ->
{
if (ex != null)
{
FLog.severe("Failed to promote "
+ player.getName()
+ " to the next rank");
return;
}
if (result == null) {
msgNew("<green>Added <player> to the ADMIN group.", player(player));
}
else if (!result.wasSuccessful() || result.getGroupTo().isEmpty())
{
msgNew("<red>Failed to promote <player> to the next rank.", player(player));
return;
} else {
result.getGroupTo().ifPresentOrElse(group ->
{
Admin admin = plugin.al.getAdmin(player);
if (admin == null)
{
admin = new Admin(player);
plugin.al.addAdmin(admin);
}
Group actual = Hierarchy.getHierarchy().getGroup(group);
DisplayableGroup rank = GroupProvider.fromLuckPermsGroup(actual).getGroup();
if (rank == null)
{
msgNew("<red>Unknown rank: <rank>", Placeholder.unparsed("rank", args[2]));
return;
}
admin.setRank(rank);
admin.addIp(FUtil.getIp(player));
admin.setActive(true);
admin.setLastLogin(new Date());
plugin.al.save(admin);
plugin.al.updateTables();
if (plugin.dc != null && plugin.dc.isEnabled() && ConfigEntry.DISCORD_ROLE_SYNC.getBoolean())
{
plugin.dc.syncRoles(admin, plugin.pl.getData(player).getDiscordID());
}
msgNew("Set <admin>'s rank to <rank>.", Placeholder.unparsed("admin", admin.getName()), Placeholder.component("rank", rank.getName()));
final FPlayer fPlayer = plugin.pl.getPlayer(player);
if (fPlayer.getFreezeData().isFrozen())
{
fPlayer.getFreezeData().setFrozen(false);
msgNew(player, "You have been unfrozen.");
}
msgNew("<gold>Admin <player> has been promoted to <rank>",
player(player),
Placeholder.unparsed("rank", group));
}, () -> msgNew("<red>Failed to promote <player> to the next rank.", player(player)));
}
});
return true;
}
case "info" ->
{
if (args.length < 2)
{
return false;
}
checkPermission("tfm.saconfig.info");
Admin admin = plugin.al.getEntryByName(args[1]);
if (admin == null)
{
final Player player = getPlayer(args[1]);
if (player != null)
{
admin = plugin.al.getAdmin(player);
}
}
if (admin == null)
{
msgNew("Unknown admin: <arg>", arg(args[1]));
return true;
} else
{
msgNew(admin.toString());
}
return true;
}
case "demote" ->
{
checkConsole();
checkPermission("tfm.saconfig.demote");
if (args.length < 2)
{
return false;
}
Player player = getPlayer(args[1]);
if (player == null)
{
msgNew("<red>Player not found.");
return true;
}
Hierarchy.getHierarchy()
.demoteUser(Hierarchy.getHierarchy().admin(), player)
.whenComplete((result, ex) ->
{
if (ex != null)
{
FLog.severe("Failed to demote "
+ player.getName()
+ " to the next rank");
return;
}
if (result == null || !result.wasSuccessful() || result.getGroupTo().isEmpty())
{
msgNew("<red>Failed to demote <player> to the next rank.", player(player));
return;
}
result.getGroupTo().ifPresentOrElse(group ->
{
Admin admin = plugin.al.getAdmin(player);
if (admin == null)
{
admin = new Admin(player);
plugin.al.addAdmin(admin);
}
Group actual = Hierarchy.getHierarchy().getGroup(group);
DisplayableGroup rank = GroupProvider.fromLuckPermsGroup(actual).getGroup();
if (rank == null)
{
msgNew("<red>Unknown rank: <rank>", Placeholder.unparsed("rank", args[2]));
return;
}
admin.setRank(rank);
admin.setLastLogin(new Date());
plugin.al.save(admin);
plugin.al.updateTables();
if (plugin.dc != null && plugin.dc.isEnabled() && ConfigEntry.DISCORD_ROLE_SYNC.getBoolean())
{
plugin.dc.syncRoles(admin, plugin.pl.getData(player).getDiscordID());
}
msgNew("Set <admin>'s rank to <rank>.", Placeholder.unparsed("admin", admin.getName()), Placeholder.component("rank", rank.getName()));
final FPlayer fPlayer = plugin.pl.getPlayer(player);
if (fPlayer.getFreezeData().isFrozen())
{
fPlayer.getFreezeData().setFrozen(false);
msgNew(player, "You have been unfrozen.");
}
msgNew("<gold>Admin <player> has been demoted to <rank>",
Placeholder.unparsed("player", player.getName()),
Placeholder.unparsed("rank", group));
}, () -> msgNew("<red>Failed to demote <player> to the next rank.", Placeholder.unparsed("player", player.getName())));
});
}
case "remove" ->
{
if (args.length < 2)
{
return false;
}
checkConsole();
checkPermission("tfm.saconfig.remove");
Player player = getPlayer(args[1]);
Admin admin = plugin.al.getAdmin(player);
plugin.al.removeAdmin(admin);
Hierarchy.getHierarchy().dropUserFromAll(Hierarchy.getHierarchy().admin(), player);
FUtil.adminAction(sender.getName(), "Removing " + admin.getName() + " from the admin list", true);
admin.setActive(false);
plugin.al.save(admin);
plugin.al.updateTables();
if (plugin.dc != null && plugin.dc.isEnabled() && ConfigEntry.DISCORD_ROLE_SYNC.getBoolean())
{
plugin.dc.syncRoles(admin, plugin.pl.getData(admin.getName())
.getDiscordID());
}
return true;
}
default ->
{
return false;
}
}
return false;
}
@Override
public List<String> getTabCompleteOptions(CommandSender sender, Command command, String alias, String[] args)
{
if (args.length == 1)
{
return argumentCompletions(args[0],
PermissibleCompletion.of("tfm.saconfig.info", "info"),
PermissibleCompletion.of("tfm.saconfig.demote", "demote"),
PermissibleCompletion.of("tfm.saconfig.remove", "remove"),
PermissibleCompletion.of("tfm.saconfig.reload", "reload"),
PermissibleCompletion.of("tfm.saconfig.clean", "clean"),
PermissibleCompletion.of("tfm.saconfig.promote", "promote"));
}
if (args.length == 2 && (args[0].equals("add") || args[0].equals("remove") || args[0].equals("setrank") || args[0].equals("info")))
{
return playerCompletions(args[1]);
}
if (args.length == 3 && args[0].equals("setrank") && sender.hasPermission("tfm.saconfig.setrank"))
{
return Arrays.asList("ADMIN", "SENIOR_ADMIN");
}
return Collections.emptyList();
}
}

View File

@ -1,37 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.*;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.apache.commons.lang.StringUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Intercept("say")
@CommandPermissions(permission = "say", source = SourceType.BOTH)
@CommandParameters(description = "Broadcasts the given message as the server, includes sender name.", usage = "/<command> <message>")
public class Command_say extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length == 0)
{
return false;
}
String message = StringUtils.join(args, " ");
server.broadcast(FUtil.miniMessage("<light_purple>[Server:<player>] <message>",
Placeholder.unparsed("player", sender.getName()),
Placeholder.unparsed("message", message)));
if (plugin.dc != null)
{
plugin.dc.messageChatChannel(String.format("[Server:%s] \u00BB %s", sender.getName(), message), true);
}
return true;
}
}

View File

@ -1,34 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.api.ShopItem;
import me.totalfreedom.totalfreedommod.command.handling.*;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandDependencies({"TF-Shoppe"})
@CommandPermissions(permission = "stackingpotato", source = SourceType.ONLY_IN_GAME)
@CommandParameters(description = "Obtain a stacking potato", usage = "/<command>")
public class Command_stackingpotato extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (plugin.sh == null)
{
msgNew("<red>Shop is currently disabled.");
return true;
}
if (plugin.pl.getData(playerSender).hasItem(ShopItem.STACKING_POTATO))
{
playerSender.getInventory().addItem(plugin.sh.getStackingPotato());
msgNew("<green>You have been given the <item>.", Placeholder.unparsed("item", ShopItem.STACKING_POTATO.getName()));
} else
{
msgNew("<red>You don't own the <item>! Purchase it from the shop.", Placeholder.unparsed("item", ShopItem.STACKING_POTATO.getName()));
}
return true;
}
}

View File

@ -1,51 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Sound;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@CommandPermissions(permission = "stopsound", source = SourceType.ONLY_IN_GAME)
@CommandParameters(description = "Stops all sounds or a specified sound.", usage = "/<command> [sound]")
public class Command_stopsound extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length > 0)
{
Arrays.stream(Sound.values()).filter(snd -> snd != null && snd.name().equalsIgnoreCase(args[0])).findAny().ifPresentOrElse(sound ->
{
playerSender.stopSound(sound);
msgNew("<green>Stopped all <sound> sounds.", Placeholder.unparsed("sound", sound.name()));
}, () -> msgNew("<red><sound> is not a valid sound.", Placeholder.unparsed("sound", args[0])));
return true;
}
playerSender.stopAllSounds();
msgNew("<green>Stopped all sounds.");
return true;
}
@Override
public List<String> getTabCompleteOptions(CommandSender sender, Command command, String alias, String[] args)
{
if (args.length <= 1)
{
return Arrays.stream(Sound.values()).map(Enum::name).toList();
}
return Collections.emptyList();
}
}

View File

@ -1,205 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.player.FPlayer;
import me.totalfreedom.totalfreedommod.player.PlayerData;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandPermissions(permission = "tag", source = SourceType.BOTH)
@CommandParameters(description = "Allows you to set your own prefix.", usage = "/<command> [-ns] <set <tag..> | list | off | clear <player> | clearall>")
public class Command_tag extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
boolean save = true;
if (args.length < 1)
{
return false;
}
if (args[0].equalsIgnoreCase("-ns"))
{
save = false;
args = ArrayUtils.remove(args, 0);
}
if (args.length == 1)
{
switch (args[0].toLowerCase())
{
case "list":
{
msgNew("Tags for all online players:");
server.getOnlinePlayers().stream().filter(player -> !(plugin.al.isVanished(player.getUniqueId()) && !isAdmin(sender)) && plugin.pl.getPlayer(player).getTag() != null).forEach(player -> {
msgNew("<player>: <tag>", Placeholder.unparsed("player", player.getName()),
Placeholder.component("tag", plugin.pl.getPlayer(player).getTag()));
});
return true;
}
case "clearall":
{
if (!sender.hasPermission("tfm.tag.clear.all"))
{
noPerms();
return true;
}
FUtil.adminAction(sender.getName(), "Removing all tags", false);
int count = 0;
for (final Player player : server.getOnlinePlayers())
{
final FPlayer playerdata = plugin.pl.getPlayer(player);
if (playerdata.getTag() != null)
{
count++;
playerdata.setTag(null);
}
}
msgNew("<count> tag(s) removed.", Placeholder.unparsed("count", String.valueOf(count)));
return true;
}
case "off":
{
if (senderIsConsole)
{
msgNew("<red>\"/tag off\" can't be used from the console.");
}
else
{
plugin.pl.getPlayer(playerSender).setTag(null);
if (save)
{
save(playerSender, null);
}
msgNew("Your tag has been removed. <saved>",
Placeholder.unparsed("saved", save ? "(Saved)" : ""));
}
return true;
}
default:
{
return false;
}
}
}
else if (args.length >= 2)
{
switch (args[0].toLowerCase())
{
case "clear":
{
if (!sender.hasPermission("tfm.tag.clear.others"))
{
noPerms();
return true;
}
final Player player = getPlayer(args[1]);
if (player == null)
{
msg(FreedomCommand.PLAYER_NOT_FOUND);
return true;
}
plugin.pl.getPlayer(player).setTag(null);
if (save)
{
save(player, null);
}
msgNew("Removed <player>'s tag. <saved>",
Placeholder.unparsed("player", player.getName()),
Placeholder.unparsed("saved", save ? "(Saved)" : ""));
return true;
}
case "set":
{
if (senderIsConsole)
{
msgNew("<red>\"/tag set\" can't be used from the console.");
return true;
}
final String inputTag = StringUtils.join(args, " ", 1, args.length);
Component tag;
if (FUtil.containsChatColor(inputTag))
{
tag = FUtil.colorizeAsComponent(inputTag.replace("&k", ""));
} else
{
tag = FUtil.miniMessage(inputTag);
}
String steamrolled = FUtil.steamroll(tag);
int tagLimit = (plugin.al.isAdmin(sender) ? 30 : 20);
if (steamrolled.length() > tagLimit)
{
FLog.debug("FUCK YOU " + steamrolled.length());
FLog.debug("FUCK YOU " + steamrolled);
msgNew("<red>That tag is too long (Max is <max> characters).", Placeholder.unparsed("max", String.valueOf(tagLimit)));
return true;
}
else if (!plugin.al.isAdmin(sender) && ConfigEntry.FORBIDDEN_WORDS.getStringList().stream().anyMatch(word -> steamrolled.toLowerCase().contains(word)))
{
msgNew("<red>That tag contains a forbidden word.");
return true;
}
else
{
plugin.pl.getPlayer(playerSender).setTag(tag);
if (save)
{
save(playerSender, tag);
}
msgNew("Tag set to '<tag>' <saved>",
Placeholder.component("tag", tag.hoverEvent(HoverEvent.showText(Component.translatable("chat.copy")))
.clickEvent(ClickEvent.copyToClipboard(FUtil.miniMessage(tag)))),
Placeholder.unparsed("saved", save ? "(Saved)" : ""));
}
return true;
}
default:
{
return false;
}
}
}
return false;
}
public void save(Player player, Component tag)
{
PlayerData playerData = plugin.pl.getData(player);
playerData.setTag(tag);
plugin.pl.save(playerData);
}
}

View File

@ -1,188 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.GameRuleHandler;
import me.totalfreedom.totalfreedommod.LoginProcess;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@CommandPermissions(permission = "toggle", source = SourceType.BOTH)
@CommandParameters(description = "Toggles TotalFreedomMod settings", usage = "/<command> [option] [value] [value]")
public class Command_toggle extends FreedomCommand
{
private final List<String> toggles = Arrays.asList(
"waterplace", "fireplace", "lavaplace", "fluidspread", "lavadmg", "firespread", "frostwalk",
"firework", "prelog", "lockdown", "petprotect", "entitywipe", "nonuke [range] [count]",
"explosives [radius]", "unsafeenchs", "bells", "armorstands", "masterblocks", "books", "grindstones",
"jukeboxes", "spawners", "4chan", "beehives", "respawnanchors", "autotp", "autoclear", "minecarts", "mp44",
"landmines", "tossmob", "gravity", "chat", "disguises");
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length == 0)
{
msgNew("Available toggles: ");
toggles.forEach(toggle -> msgNew("- <toggle>", Placeholder.unparsed("toggle", toggle)));
return false;
}
switch (args[0].toLowerCase())
{
case "waterplace" -> toggle("Water placement is", ConfigEntry.ALLOW_WATER_PLACE);
case "frostwalk" -> toggle("Frost walker enchantment is", ConfigEntry.ALLOW_FROSTWALKER);
case "fireplace" -> toggle("Fire placement is", ConfigEntry.ALLOW_FIRE_PLACE);
case "lavaplace" -> toggle("Lava placement is", ConfigEntry.ALLOW_LAVA_PLACE);
case "fluidspread" -> toggle("Fluid spread is", ConfigEntry.ALLOW_FLUID_SPREAD);
case "lavadmg" -> toggle("Lava damage is", ConfigEntry.ALLOW_LAVA_DAMAGE);
case "firespread" ->
{
toggle("Fire spread is", ConfigEntry.ALLOW_FIRE_SPREAD);
plugin.gr.setGameRule(GameRuleHandler.GameRule.DO_FIRE_TICK, ConfigEntry.ALLOW_FIRE_SPREAD.getBoolean());
}
case "prelog" -> toggle("Command prelogging is", ConfigEntry.ENABLE_PREPROCESS_LOG);
case "lockdown" ->
{
boolean active = !LoginProcess.isLockdownEnabled();
LoginProcess.setLockdownEnabled(active);
FUtil.adminAction(sender.getName(), (active ? "A" : "De-a") + "ctivating server lockdown", true);
}
case "petprotect" -> toggle("Tamed pet protection is", ConfigEntry.ENABLE_PET_PROTECT);
case "entitywipe" -> toggle("Automatic entity wiping is", ConfigEntry.AUTO_ENTITY_WIPE);
case "firework" -> toggle("Firework explosion is", ConfigEntry.ALLOW_FIREWORK_EXPLOSION);
case "nonuke" ->
{
if (args.length >= 2)
{
try
{
ConfigEntry.NUKE_MONITOR_RANGE.setDouble(Math.max(1.0, Math.min(500.0, Double.parseDouble(args[1]))));
} catch (NumberFormatException ex)
{
msgNew("<red>The input provided is not a valid integer.");
return true;
}
}
if (args.length >= 3)
{
try
{
ConfigEntry.NUKE_MONITOR_COUNT_BREAK.setInteger(Math.max(1, Math.min(500, Integer.parseInt(args[2]))));
} catch (NumberFormatException ex)
{
msgNew("<red>The input provided is not a valid integer.");
return true;
}
}
toggle("Nuke monitor is", ConfigEntry.NUKE_MONITOR_ENABLED);
if (ConfigEntry.NUKE_MONITOR_ENABLED.getBoolean())
{
msgNew("Anti-freecam range is set to <range> blocks.", Placeholder.unparsed("range", String.valueOf(ConfigEntry.NUKE_MONITOR_RANGE.getDouble())));
msgNew("Block throttle rate is set to <count> blocks destroyed per 5 seconds.", Placeholder.unparsed("count", String.valueOf(ConfigEntry.NUKE_MONITOR_COUNT_BREAK.getInteger())));
}
}
case "explosives" ->
{
if (args.length == 2)
{
try
{
ConfigEntry.EXPLOSIVE_RADIUS.setDouble(Math.max(1.0, Math.min(30.0, Double.parseDouble(args[1]))));
} catch (NumberFormatException ex)
{
msgNew("<red>The input provided is not a valid integer.");
return true;
}
}
toggle("Explosions are", ConfigEntry.ALLOW_EXPLOSIONS);
if (ConfigEntry.ALLOW_EXPLOSIONS.getBoolean())
{
msgNew("Radius set to <radius>.", Placeholder.unparsed("radius", String.valueOf(ConfigEntry.EXPLOSIVE_RADIUS.getDouble())));
}
}
case "unsafeenchs" -> toggle("Unsafe enchantments are", ConfigEntry.ALLOW_UNSAFE_ENCHANTMENTS);
case "bells" -> toggle("The ringing of bells is", ConfigEntry.ALLOW_BELLS);
case "armorstands" -> toggle("The placement of armor stands is", ConfigEntry.ALLOW_ARMOR_STANDS);
case "masterblocks" -> toggle("Master blocks are", ConfigEntry.ALLOW_MASTERBLOCKS);
case "books" -> toggle("Books are", ConfigEntry.ALLOW_BOOKS);
case "grindstones" -> toggle("Grindstones are", ConfigEntry.ALLOW_GRINDSTONES);
case "jukeboxes" -> toggle("Jukeboxes are", ConfigEntry.ALLOW_JUKEBOXES);
case "spawners" -> toggle("Spawners are", ConfigEntry.ALLOW_SPAWNERS);
case "4chan" -> toggle("4chan mode is", ConfigEntry.FOURCHAN_ENABLED);
case "beehives" -> toggle("Beehives are", ConfigEntry.ALLOW_BEEHIVES);
case "respawnanchors" -> toggle("Respawn anchors are", ConfigEntry.ALLOW_RESPAWN_ANCHORS);
case "autotp" -> toggle("Teleportation on join is", ConfigEntry.AUTO_TP);
case "autoclear" -> toggle("Clearing inventories on join is", ConfigEntry.AUTO_CLEAR);
case "minecarts" -> toggle("Minecarts are", ConfigEntry.ALLOW_MINECARTS);
case "landmines" -> toggle("Landmines are", ConfigEntry.LANDMINES_ENABLED);
case "mp44" -> toggle("MP44 is", ConfigEntry.MP44_ENABLED);
case "tossmob" -> toggle("Tossmob is", ConfigEntry.TOSSMOB_ENABLED);
case "gravity" -> toggle("Block gravity is", ConfigEntry.ALLOW_GRAVITY);
case "chat" -> toggle("Chat is", ConfigEntry.TOGGLE_CHAT);
case "disguises" ->
{
if (!plugin.ldb.isEnabled())
{
msgNew("<red>LibsDisguises is not enabled.");
return true;
}
if (plugin.ldb.isDisguisesEnabled())
{
plugin.ldb.undisguiseAll(true);
}
plugin.ldb.setDisguisesEnabled(!plugin.ldb.isDisguisesEnabled());
msgNew("Disguises are now <status>.", Placeholder.unparsed("status", plugin.ldb.isDisguisesEnabled() ? "enabled." : "disabled."));
}
default ->
{
msgNew("Available toggles: ");
toggles.forEach(toggle -> msgNew("- <toggle>", Placeholder.unparsed("toggle", toggle)));
return false;
}
}
return true;
}
private void toggle(final String name, final ConfigEntry entry)
{
msgNew("<name> now <status>.", Placeholder.unparsed("name", name), Placeholder.unparsed("status",
entry.setBoolean(!entry.getBoolean()) ? "enabled" : "disabled"));
}
@Override
public List<String> getTabCompleteOptions(CommandSender sender, Command command, String alias, String[] args)
{
if (!plugin.al.isAdmin(sender))
{
return Collections.emptyList();
}
if (args.length == 1)
{
return Arrays.asList(
"waterplace", "fireplace", "lavaplace", "fluidspread", "lavadmg", "firespread", "frostwalk",
"firework", "prelog", "lockdown", "petprotect", "entitywipe", "nonuke", "explosives", "unsafeenchs",
"bells", "armorstands", "structureblocks", "jigsaws", "grindstones", "jukeboxes", "spawners", "4chan", "beehives",
"respawnanchors", "autotp", "autoclear", "minecarts", "mp44", "landmines", "tossmob", "gravity", "chat", "disguises");
}
return Collections.emptyList();
}
}

View File

@ -1,38 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.command.handling.*;
import me.totalfreedom.totalfreedommod.player.FPlayer;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandDependencies({"TF-Shoppe"})
@CommandPermissions(permission = "clownfish.toggle", source = SourceType.BOTH)
@CommandParameters(description = "Toggle whether or not a player has the ability to use clownfish", usage = "/<command> <player>", aliases = "togglecf")
public class Command_toggleclownfish extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length == 0)
{
return false;
}
Player player = server.getPlayer(args[0]);
if (player == null)
{
msg(PLAYER_NOT_FOUND);
return true;
}
FPlayer fplayer = plugin.pl.getPlayer(player);
fplayer.setClownfishDisabled(!fplayer.isClownfishDisabled());
msgNew("<player> will <status> have the ability to use the Clownfish.",
Placeholder.unparsed("player", args[0]),
Placeholder.unparsed("status", fplayer.isClownfishDisabled() ? "no longer" : "now"));
return true;
}
}

View File

@ -1,69 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.command.handling.CommandParameters;
import me.totalfreedom.totalfreedommod.command.handling.CommandPermissions;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.handling.SourceType;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.util.FLog;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
/*
* See https://github.com/TotalFreedom/License - This file may not be edited or removed.
*/
@CommandPermissions(source = SourceType.BOTH)
@CommandParameters(description = "Shows information about TotalFreedomMod or reloads it", usage = "/<command> [reload]", aliases = "tfm")
public class Command_totalfreedommod extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length == 1)
{
if (!args[0].equals("reload"))
{
return false;
}
if (!plugin.al.isAdmin(sender))
{
noPerms();
return true;
}
plugin.config.load();
plugin.fsh.stopServices();
plugin.fsh.startServices();
msgNew("<name> v<version> reloaded.",
Placeholder.unparsed("name", TotalFreedomMod.pluginName),
Placeholder.unparsed("version", TotalFreedomMod.pluginVersion));
FLog.info(String.format("%s v%s reloaded.",
TotalFreedomMod.pluginName,
TotalFreedomMod.pluginVersion));
return true;
}
TotalFreedomMod.BuildProperties build = TotalFreedomMod.build;
msgNew("<gold>TotalFreedomMod for 'Total Freedom', the original all-op server.");
msgNew("<gold>Running on <server>.", Placeholder.unparsed("server", ConfigEntry.SERVER_NAME.getString()));
msgNew("<gold>Created by Madgeek1450 and Prozza.");
msgNew("<gold>Version <blue><codename> - <version> Build <number> </blue>(<blue><head></blue>)",
Placeholder.unparsed("codename", build.codename),
Placeholder.unparsed("version", build.version),
Placeholder.unparsed("number", build.number),
Placeholder.unparsed("head", build.head));
msgNew("<gold>Compiled <blue><date></blue> by <blue><author></blue>",
Placeholder.unparsed("date", build.date),
Placeholder.unparsed("author", build.author));
msgNew("<green>Visit <aqua>http://github.com/TotalFreedom/TotalFreedomMod</aqua> for more information.");
return true;
}
}

View File

@ -1,43 +0,0 @@
package me.totalfreedom.totalfreedommod.command;
import me.totalfreedom.totalfreedommod.api.ShopItem;
import me.totalfreedom.totalfreedommod.command.handling.*;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandDependencies({"TF-Shoppe"})
@CommandPermissions(permission = "trail", source = SourceType.ONLY_IN_GAME)
@CommandParameters(description = "Trails rainbow particles behind you as you walk/fly.", usage = "/<command>")
public class Command_trail extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (plugin.sh == null)
{
msgNew("<red>Shop is not enabled.");
return true;
}
if (!plugin.pl.getData(playerSender).hasItem(ShopItem.RAINBOW_TRAIL))
{
msgNew("<red>You didn't purchase the ability to have a <item>! Purchase it from the shop.", Placeholder.unparsed("item", ShopItem.RAINBOW_TRAIL.getName()));
return true;
}
if (plugin.tr.contains(playerSender))
{
plugin.tr.remove(playerSender);
msgNew("Trail disabled.");
} else
{
plugin.tr.add(playerSender);
msgNew("Trail enabled. Run this command again to disable it.");
}
return true;
}
}

View File

@ -1,10 +0,0 @@
package me.totalfreedom.totalfreedommod.command.handling;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandDependencies
{
String[] value();
}

View File

@ -1,145 +0,0 @@
package me.totalfreedom.totalfreedommod.command.handling;
import me.totalfreedom.totalfreedommod.FreedomService;
import me.totalfreedom.totalfreedommod.util.FLog;
import org.bukkit.Bukkit;
import org.reflections.Reflections;
import java.util.*;
import java.util.concurrent.CompletableFuture;
public class CommandLoader extends FreedomService
{
private final List<FreedomCommand> commands;
public CommandLoader()
{
commands = new ArrayList<>();
}
@Override
public void onStart()
{
}
@Override
public void onStop()
{
}
public void add(FreedomCommand command)
{
commands.add(command);
command.register();
}
public FreedomCommand getByName(String name)
{
for (FreedomCommand command : commands)
{
if (name.equals(command.getName()))
{
return command;
}
}
return null;
}
public boolean isAlias(String alias)
{
for (FreedomCommand command : commands)
{
if (Arrays.asList(command.getAliases().split(",")).contains(alias))
{
return true;
}
}
return false;
}
public void loadCommands()
{
Reflections commandDir = new Reflections("me.totalfreedom.totalfreedommod.command");
Interceptor interceptor = new Interceptor(plugin);
Set<Class<? extends FreedomCommand>> commandClasses = commandDir.getSubTypesOf(FreedomCommand.class);
Set<Class<? extends FreedomCommand>> postLoadCommands = new HashSet<>();
for (Class<? extends FreedomCommand> commandClass : commandClasses)
{
if (commandClass.isAnnotationPresent(CommandDependencies.class))
{
postLoadCommands.add(commandClass);
}
if (commandClass.isAnnotationPresent(Intercept.class))
{
Intercept intercept = commandClass.getAnnotation(Intercept.class);
interceptor.intercept(intercept.value());
postLoadCommands.add(commandClass);
}
addClass(commandClass);
}
doPostLoading(interceptor, postLoadCommands);
FLog.info("Loaded " + commands.size() + " commands");
}
private void doPostLoading(Interceptor interceptor, Set<Class<? extends FreedomCommand>> postLoadCommands)
{
Bukkit.getScheduler().runTaskLater(plugin, () ->
CompletableFuture.runAsync(interceptor::setOverrides)
.whenComplete((v, th) ->
{
if (th != null)
{
FLog.severe("Failed to set command overrides");
th.printStackTrace();
return;
}
for (Class<? extends FreedomCommand> commandClass : postLoadCommands)
{
if (checkDependencies(commandClass)) return;
addClass(commandClass);
}
}), 1);
}
private boolean checkDependencies(Class<? extends FreedomCommand> commandClass)
{
if (commandClass.isAnnotationPresent(CommandDependencies.class))
{
for (String dependency : commandClass.getAnnotation(CommandDependencies.class).value())
{
if (Bukkit.getPluginManager().getPlugin(dependency) == null)
{
FLog.warning("Failed to register command: /" + commandClass.getSimpleName().replace("Command_", "") + " (Missing dependency: " + dependency + ")");
return true;
}
}
}
return false;
}
private void addClass(Class<? extends FreedomCommand> commandClass)
{
try
{
add(commandClass.newInstance());
} catch (InstantiationException | IllegalAccessException ex)
{
FLog.warning("Failed to register command: /" + commandClass.getSimpleName().replace("Command_", ""));
}
}
public List<FreedomCommand> getCommands()
{
return commands;
}
}

View File

@ -1,13 +0,0 @@
package me.totalfreedom.totalfreedommod.command.handling;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Intercept
{
String value();
}

View File

@ -1,74 +0,0 @@
package me.totalfreedom.totalfreedommod.command.handling;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.util.FLog;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.PluginIdentifiableCommand;
import java.util.HashMap;
import java.util.Map;
public class Interceptor
{
private final TotalFreedomMod plugin;
private final Map<String, Command> overrides = new HashMap<>();
public Interceptor(TotalFreedomMod plugin)
{
this.plugin = plugin;
}
public void intercept(String command)
{
getPluginCommands().entrySet()
.stream()
.filter(entry -> !((PluginIdentifiableCommand) entry.getValue()) // Check that it isn't a tfm command
.getPlugin()
.getName()
.equalsIgnoreCase(plugin.getName()))
.filter(entry -> entry.getValue() // Check that the command is the one we want to intercept
.getName()
.equalsIgnoreCase(command))
.forEach(entry -> overrides.put(entry.getKey(), entry.getValue())); // Intercept.
getFallbackCommands().entrySet()
.stream()
.filter(entry -> entry.getValue() // Check that the command is the one we want to intercept
.getName()
.equalsIgnoreCase(command))
.forEach(entry -> overrides.put(entry.getKey(), entry.getValue())); // Intercept.
}
public void setOverrides()
{
overrides.forEach((key, value) ->
{
Bukkit.getCommandMap().getKnownCommands().remove(key, value);
FLog.info("Overriding command: " + key);
});
}
private Map<String, Command> getFallbackCommands() {
final Map<String, Command> fallbackCommands = new HashMap<>();
for (final Map.Entry<String, Command> entry : Bukkit.getCommandMap().getKnownCommands().entrySet()) {
if (!(entry.getValue() instanceof PluginIdentifiableCommand)) {
fallbackCommands.put(entry.getKey(), entry.getValue());
}
}
return fallbackCommands;
}
private Map<String, Command> getPluginCommands()
{
final Map<String, Command> pluginCommands = new HashMap<>();
for (final Map.Entry<String, Command> entry : Bukkit.getCommandMap().getKnownCommands().entrySet())
{
if (entry.getValue() instanceof PluginIdentifiableCommand)
{
pluginCommands.put(entry.getKey(), entry.getValue());
}
}
return pluginCommands;
}
}

View File

@ -1,15 +0,0 @@
package me.totalfreedom.totalfreedommod.command.handling;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
public enum SourceType
{
ONLY_IN_GAME, ONLY_CONSOLE, BOTH;
public boolean permissionCheck(CommandSender sender)
{
return (sender instanceof Player && this == ONLY_IN_GAME) || (sender instanceof ConsoleCommandSender && this == ONLY_CONSOLE) || this == BOTH;
}
}

View File

@ -1,70 +0,0 @@
package me.totalfreedom.totalfreedommod.fun;
import me.totalfreedom.totalfreedommod.FreedomService;
import me.totalfreedom.totalfreedommod.api.ShopItem;
import me.totalfreedom.totalfreedommod.util.ParticleDisplay;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerMoveEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.SplittableRandom;
import java.util.UUID;
public class Trailer extends FreedomService
{
private final SplittableRandom random = new SplittableRandom();
private final Map<UUID, ParticleDisplay> trailPlayers = new HashMap<>(); // player UUID and relative particle instance.
@Override
public void onStart()
{
}
@Override
public void onStop()
{
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerMove(PlayerMoveEvent event)
{
if (plugin.sh == null) return; // Shop is disabled
/* Doesn't continue any further if...
* - The trail list is empty
* - The player doesn't have their trail enabled in the first place
* - The player doesn't have the trail item in the shop at all
* - The player doesn't have permission to modify blocks in their current world
*/
if (trailPlayers.isEmpty()
|| !trailPlayers.containsKey(event.getPlayer().getUniqueId())
|| !plugin.pl.getData(event.getPlayer()).hasItem(ShopItem.RAINBOW_TRAIL))
{
return;
}
final Player player = event.getPlayer();
final ParticleDisplay particleDisplay = trailPlayers.get(player.getUniqueId());
particleDisplay.spawnNext(player);
}
public void remove(Player player)
{
trailPlayers.remove(player.getUniqueId());
}
public void add(Player player)
{
if (trailPlayers.containsKey(player.getUniqueId())) return;
trailPlayers.put(player.getUniqueId(), new ParticleDisplay());
}
public boolean contains(Player player)
{
return trailPlayers.containsKey(player.getUniqueId());
}
}

View File

@ -1,31 +0,0 @@
package me.totalfreedom.totalfreedommod.perms;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.model.group.GroupManager;
import java.util.concurrent.CompletableFuture;
public class GroupWrapper
{
private final GroupManager manager;
public GroupWrapper(GroupManager manager)
{
this.manager = manager;
}
public CompletableFuture<Group> getGroup(String name)
{
if (!manager.isLoaded(name) || !manager.getLoadedGroups().contains(manager.getGroup(name)))
{
return manager.createAndLoadGroup(name);
}
return CompletableFuture.supplyAsync(() -> manager.getGroup(name));
}
public void saveGroup(String name)
{
getGroup(name).thenAccept(manager::saveGroup);
}
}

View File

@ -1,39 +0,0 @@
package me.totalfreedom.totalfreedommod.perms;
import net.luckperms.api.track.Track;
import net.luckperms.api.track.TrackManager;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
public class TrackWrapper
{
private final TrackManager manager;
private final Set<Track> trackSet;
public TrackWrapper(TrackManager manager)
{
this.manager = manager;
this.trackSet = new HashSet<>();
trackSet.addAll(manager.getLoadedTracks());
}
public CompletableFuture<Track> getTrack(String name)
{
if (!manager.isLoaded(name) || !trackSet.contains(manager.getTrack(name)))
{
return manager.createAndLoadTrack(name).thenApplyAsync(a -> {
trackSet.add(a);
return a;
});
}
return CompletableFuture.supplyAsync(() -> manager.getTrack(name));
}
public void saveTrack(String name)
{
getTrack(name).thenAccept(manager::saveTrack);
}
}

View File

@ -1,84 +0,0 @@
package me.totalfreedom.totalfreedommod.perms;
import net.luckperms.api.cacheddata.CachedMetaData;
import net.luckperms.api.cacheddata.CachedPermissionData;
import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.model.user.User;
import net.luckperms.api.query.QueryOptions;
public class UserData
{
private User user;
private CachedMetaData metaData;
private CachedPermissionData permissionData;
private ImmutableContextSet contextSet;
private QueryOptions queryOptions;
public UserData(User user, CachedMetaData metaData, CachedPermissionData permissionData, ImmutableContextSet contextSet, QueryOptions queryOptions)
{
this.user = user;
this.metaData = metaData;
this.permissionData = permissionData;
this.contextSet = contextSet;
this.queryOptions = queryOptions;
}
public User getUser()
{
return user;
}
public void setUser(User user)
{
this.user = user;
}
public CachedMetaData getMetaData()
{
return metaData;
}
public void setMetaData(CachedMetaData metaData)
{
this.metaData = metaData;
}
public CachedPermissionData getPermissionData()
{
return permissionData;
}
public void setPermissionData(CachedPermissionData permissionData)
{
this.permissionData = permissionData;
}
public ImmutableContextSet getContextSet()
{
return contextSet;
}
public void setContextSet(ImmutableContextSet contextSet)
{
this.contextSet = contextSet;
}
public QueryOptions getQueryOptions()
{
return queryOptions;
}
public void setQueryOptions(QueryOptions queryOptions)
{
this.queryOptions = queryOptions;
}
public UserData copy()
{
return new UserData(getUser(),
getMetaData(),
getPermissionData(),
getContextSet(),
getQueryOptions());
}
}

View File

@ -1,124 +0,0 @@
package me.totalfreedom.totalfreedommod.perms;
import me.totalfreedom.totalfreedommod.rank.DisplayableGroup;
import me.totalfreedom.totalfreedommod.rank.GroupProvider;
import net.luckperms.api.cacheddata.CachedMetaData;
import net.luckperms.api.cacheddata.CachedPermissionData;
import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.model.user.User;
import net.luckperms.api.model.user.UserManager;
import net.luckperms.api.node.NodeType;
import net.luckperms.api.node.types.InheritanceNode;
import net.luckperms.api.platform.PlayerAdapter;
import net.luckperms.api.query.QueryOptions;
import org.bukkit.entity.Player;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
public class UserWrapper
{
private final UserManager manager;
private final PlayerAdapter<Player> playerAdapter;
private final Set<UserData> userDataSet;
public UserWrapper(UserManager manager, PlayerAdapter<Player> adapter)
{
this.manager = manager;
this.playerAdapter = adapter;
this.userDataSet = new HashSet<>();
}
public CompletableFuture<Void> addUserData(Player player)
{
User user = playerAdapter.getUser(player);
CachedPermissionData permissionData = playerAdapter.getPermissionData(player);
ImmutableContextSet contextSet = playerAdapter.getContext(player);
QueryOptions queryOptions = playerAdapter.getQueryOptions(player);
CachedMetaData metaData = playerAdapter.getMetaData(player);
UserData userData = new UserData(user, metaData, permissionData, contextSet, queryOptions);
return CompletableFuture.runAsync(() -> userDataSet.add(userData));
}
public CompletableFuture<User> getUser(Player player)
{
if (!manager.isLoaded(player.getUniqueId()) || !manager.getLoadedUsers().contains(manager.getUser(player.getUniqueId())))
{
return manager.loadUser(player.getUniqueId());
}
return CompletableFuture.supplyAsync(() -> manager.getUser(player.getUniqueId()));
}
public CompletableFuture<UserData> getUserData(Player player)
{
return getUser(player).thenApply(user ->
{
for (UserData userData : userDataSet)
{
if (userData.getUser().getUniqueId().equals(user.getUniqueId()))
{
return userData;
}
}
return null;
});
}
public CompletableFuture<Void> removeUserData(Player player)
{
return getUserData(player).thenAccept(userDataSet::remove);
}
public CompletableFuture<Void> updateUserData(Player player)
{
return getUserData(player).thenApply(userData ->
{
UserData newData = userData.copy();
CachedPermissionData permissionData = playerAdapter.getPermissionData(player);
ImmutableContextSet contextSet = playerAdapter.getContext(player);
QueryOptions queryOptions = playerAdapter.getQueryOptions(player);
CachedMetaData metaData = playerAdapter.getMetaData(player);
newData.setPermissionData(permissionData);
newData.setContextSet(contextSet);
newData.setQueryOptions(queryOptions);
newData.setMetaData(metaData);
userDataSet.remove(userData);
return newData;
}).thenAccept(userDataSet::add);
}
public void addToGroup(User user, DisplayableGroup group)
{
CompletableFuture.runAsync(() ->
manager.modifyUser(user.getUniqueId(), c ->
{
if (!c.getNodes(NodeType.INHERITANCE)
.contains(GroupProvider.inheritanceNode(group)))
c.data().add(GroupProvider.inheritanceNode(group));
}));
}
public void removeFromGroup(User user, Group group)
{
InheritanceNode groupNode = InheritanceNode.builder(group).build();
CompletableFuture.runAsync(() ->
manager.modifyUser(user.getUniqueId(), userConsumer ->
{
if (userConsumer.getNodes(NodeType.INHERITANCE)
.contains(groupNode))
userConsumer.data().remove(groupNode);
}));
}
public void saveUser(User user)
{
CompletableFuture.runAsync(() -> manager.saveUser(user));
}
}

View File

@ -1,31 +0,0 @@
package me.totalfreedom.totalfreedommod.rank;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
public interface Displayable
{
Component getArticle();
Component getName();
Component getTag();
Component getAbbr();
Component getPlural();
TextColor getColor();
org.bukkit.ChatColor getTeamColor();
Component getColoredName();
Component getColoredTag();
Component getColoredLoginMessage();
boolean hasTeam();
boolean hasDefaultLoginMessage();
}

View File

@ -1,178 +0,0 @@
package me.totalfreedom.totalfreedommod.rank;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.luckperms.api.model.data.DataType;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.node.types.InheritanceNode;
import net.luckperms.api.node.types.PrefixNode;
import net.luckperms.api.node.types.WeightNode;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
public class DisplayableGroup implements Displayable
{
private final Group group;
private final Component name;
private final Component abbr;
private final Component plural;
private final Component article;
private final int weight;
private final Component tag;
private final Component coloredTag;
private final TextColor color;
private final org.bukkit.ChatColor teamColor;
private final boolean hasTeam;
private final boolean hasDefaultLoginMessage;
public DisplayableGroup(String group,
Component plural,
Component tag,
int weight,
TextColor color,
org.bukkit.ChatColor teamColor,
boolean hasTeam,
boolean hasDefaultLoginMessage)
{
Group matched = TotalFreedomMod.getPlugin().lpb.getAPI().getGroupManager().getGroup(group);
if (matched == null)
{
CompletableFuture<Group> cfg = TotalFreedomMod.getPlugin()
.lpb
.getAPI()
.getGroupManager()
.createAndLoadGroup(group);
cfg.thenAcceptAsync(g ->
{
WeightNode weightNode = WeightNode.builder(weight).build();
PrefixNode prefixNode = PrefixNode.builder()
.prefix(FUtil.miniMessage(GroupProvider.OPEN.append(tag.color(color)).append(GroupProvider.CLOSE)))
.priority(1)
.build();
g.getData(DataType.NORMAL).add(prefixNode);
g.getData(DataType.NORMAL).add(weightNode);
}).join(); // Block until the group is created and loaded.
matched = TotalFreedomMod.getPlugin().lpb.getAPI().getGroupManager().getGroup(group);
if (matched == null)
throw new IllegalArgumentException("Group " + group + " does not exist and could not be created.");
}
this.group = matched;
this.name = (matched.getDisplayName() != null) ? FUtil.miniMessage(matched.getDisplayName()) : FUtil.miniMessage(matched.getName());
this.plural = plural;
this.article = StringUtils.startsWithAny(this.name.toString().toLowerCase(Locale.ROOT), new String[]{"a", "e", "i", "o", "u"}) ? Component.text("an") : Component.text("a");
this.abbr = tag;
this.weight = weight;
this.tag = GroupProvider.OPEN.append(tag).append(GroupProvider.CLOSE);
this.color = color;
this.teamColor = teamColor;
this.hasTeam = hasTeam;
this.coloredTag = tag.color(color);
this.hasDefaultLoginMessage = hasDefaultLoginMessage;
}
public boolean isAtLeast(@NotNull DisplayableGroup rank)
{
return rank.getLuckPermsGroup().getWeight().orElse(0)
<= getLuckPermsGroup().getWeight().orElse(0);
}
public int getWeight()
{
return weight;
}
public Group getLuckPermsGroup()
{
return this.group;
}
@Override
public Component getArticle()
{
return this.article;
}
@Override
public Component getName()
{
return name;
}
@Override
public Component getTag()
{
return tag;
}
@Override
public Component getAbbr()
{
return abbr;
}
@Override
public Component getPlural()
{
return plural;
}
@Override
public TextColor getColor()
{
return color;
}
@Override
public org.bukkit.ChatColor getTeamColor()
{
return teamColor;
}
@Override
public Component getColoredName()
{
return name.color(color);
}
@Override
public Component getColoredTag()
{
return coloredTag;
}
@Override
public Component getColoredLoginMessage()
{
return article.append(Component.text(" ")).append(name.color(color));
}
@Override
public boolean hasTeam()
{
return hasTeam;
}
@Override
public boolean hasDefaultLoginMessage()
{
return hasDefaultLoginMessage;
}
}

View File

@ -1,75 +0,0 @@
package me.totalfreedom.totalfreedommod.rank;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.model.user.User;
import net.luckperms.api.node.matcher.NodeMatcher;
import net.luckperms.api.node.types.InheritanceNode;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import java.util.Set;
@FunctionalInterface
public interface GroupProvider<T extends DisplayableGroup>
{
Component OPEN = Component.text("[", NamedTextColor.DARK_GRAY);
Component CLOSE = Component.text("]", NamedTextColor.DARK_GRAY);
GroupProvider<DisplayableGroup> NON_OP = () -> new DisplayableGroup("default", Component.text("Non-Ops"), Component.empty(), 0, NamedTextColor.WHITE, null, false, false);
GroupProvider<DisplayableGroup> OP = () -> new DisplayableGroup("op", Component.text("Operators"), Component.text("Op"), 1, NamedTextColor.GREEN, null, false, false);
GroupProvider<DisplayableGroup> MASTER_BUILDER = () -> new DisplayableGroup("builder", Component.text("Master Builders"), Component.text("MB"), 2, NamedTextColor.DARK_AQUA, ChatColor.DARK_AQUA, true, true);
GroupProvider<DisplayableGroup> ADMIN = () -> new DisplayableGroup("admin", Component.text("Administrators"), Component.text("Admin"), 3, NamedTextColor.DARK_GREEN, ChatColor.DARK_GREEN, true, true);
GroupProvider<DisplayableGroup> SENIOR_ADMIN = () -> new DisplayableGroup("senior", Component.text("Senior Administrators"), Component.text("SrA"), 4, NamedTextColor.GOLD, ChatColor.GOLD, true, true);
static InheritanceNode inheritanceNode(DisplayableGroup group)
{
return InheritanceNode.builder(group.getLuckPermsGroup()).build();
}
static NodeMatcher<InheritanceNode> nodeMatcher(DisplayableGroup group)
{
return NodeMatcher.key(inheritanceNode(group));
}
static User getUser(Player player)
{
return TotalFreedomMod.getPlugin()
.lpb.getAPI()
.getPlayerAdapter(Player.class)
.getUser(player);
}
static GroupProvider<DisplayableGroup> fromString(String arg)
{
return switch (arg.toLowerCase())
{
case "op" -> OP;
case "builder" -> MASTER_BUILDER;
case "admin" -> ADMIN;
case "senior" -> SENIOR_ADMIN;
default -> NON_OP;
};
}
static GroupProvider<DisplayableGroup> fromLuckPermsGroup(Group group)
{
return switch (group.getName().toLowerCase())
{
case "op" -> OP;
case "builder" -> MASTER_BUILDER;
case "admin" -> ADMIN;
case "senior" -> SENIOR_ADMIN;
default -> NON_OP;
};
}
static Set<GroupProvider<DisplayableGroup>> providerSet()
{
return Set.of(NON_OP, OP, MASTER_BUILDER, ADMIN, SENIOR_ADMIN);
}
T getGroup();
}

View File

@ -1,245 +0,0 @@
package me.totalfreedom.totalfreedommod.rank;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.perms.GroupWrapper;
import me.totalfreedom.totalfreedommod.perms.TrackWrapper;
import me.totalfreedom.totalfreedommod.perms.UserWrapper;
import me.totalfreedom.totalfreedommod.util.FLog;
import net.luckperms.api.event.EventBus;
import net.luckperms.api.event.EventSubscription;
import net.luckperms.api.event.node.NodeAddEvent;
import net.luckperms.api.event.node.NodeRemoveEvent;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.model.user.User;
import net.luckperms.api.node.NodeType;
import net.luckperms.api.node.types.InheritanceNode;
import net.luckperms.api.platform.PlayerAdapter;
import net.luckperms.api.track.DemotionResult;
import net.luckperms.api.track.PromotionResult;
import net.luckperms.api.track.Track;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class Hierarchy
{
private static final Hierarchy hierarchy = new Hierarchy(); // static singleton for global state.
private final GroupWrapper groupWrapper;
private final TrackWrapper trackWrapper;
private final UserWrapper userWrapper;
private final PlayerAdapter<Player> playerAdapter;
private Hierarchy()
{
this.playerAdapter = TotalFreedomMod.getPlugin().lpb.getAPI().getPlayerAdapter(Player.class);
this.groupWrapper = new GroupWrapper(TotalFreedomMod.getPlugin().lpb.getAPI().getGroupManager());
this.trackWrapper = new TrackWrapper(TotalFreedomMod.getPlugin().lpb.getAPI().getTrackManager());
this.userWrapper = new UserWrapper(TotalFreedomMod.getPlugin().lpb.getAPI().getUserManager(),
getPlayerAdapter());
new LuckPermsUserDataListener().register();
}
public static Hierarchy getHierarchy()
{
return hierarchy;
}
public PlayerAdapter<Player> getPlayerAdapter()
{
return playerAdapter;
}
public boolean isUserOnAdminTrack(Player player)
{
return userWrapper.getUser(player)
.thenApply(user -> user.getNodes(NodeType.INHERITANCE)
.contains(GroupProvider.inheritanceNode(GroupProvider.ADMIN.getGroup())))
.join();
}
public Track op()
{
return trackWrapper.getTrack("OP").join();
}
public Track builder()
{
return trackWrapper.getTrack("BUILDER").join();
}
public Track admin()
{
return trackWrapper.getTrack("ADMIN").join();
}
public void addInheritance(DisplayableGroup previous, DisplayableGroup current)
{
CompletableFuture.runAsync(() ->
{
current.getLuckPermsGroup().data().add(InheritanceNode.builder(previous.getLuckPermsGroup()).build());
groupWrapper.saveGroup(current.getLuckPermsGroup().getName());
}).whenComplete((a, b) ->
{
if (b != null)
{
FLog.severe(b);
}
});
}
public Group getGroup(String name)
{
return groupWrapper.getGroup(name).join();
}
public void addGroupToTrack(Track track, DisplayableGroup group)
{
trackWrapper.getTrack(track.getName()).thenAccept(t ->
{
t.appendGroup(group.getLuckPermsGroup());
trackWrapper.saveTrack(t.getName());
}).whenComplete((a, b) ->
{
if (b != null)
{
FLog.severe(b);
}
});
}
public void addUserData(Player player)
{
userWrapper.addUserData(player).whenComplete((a, b) ->
{
if (b != null)
{
FLog.severe(b);
}
});
}
public void updateUserData(Player player)
{
userWrapper.updateUserData(player).whenComplete((a, b) ->
{
if (b != null)
{
FLog.severe(b);
}
});
}
public void dropUserData(Player player)
{
userWrapper.removeUserData(player).whenComplete((a, b) ->
{
if (b != null)
{
FLog.severe(b);
}
});
}
public CompletableFuture<PromotionResult> promoteUser(Track track, Player player)
{
return userWrapper.getUserData(player)
.thenApply(data -> track.promote(data.getUser(), data.getContextSet()));
}
public CompletableFuture<DemotionResult> demoteUser(Track track, Player player)
{
return userWrapper.getUserData(player)
.thenApply(data -> track.demote(data.getUser(), data.getContextSet()));
}
public void addUserToGroup(DisplayableGroup group, Player player)
{
userWrapper.getUserData(player).thenAccept(user ->
userWrapper.addToGroup(user.getUser(), group))
.whenComplete((a, b) ->
{
if (b != null)
{
FLog.severe(b);
}
});
}
public void dropUserFromAll(Track track, Player player)
{
userWrapper.getUserData(player).thenAccept(data ->
{
for (String group : track.getGroups())
{
groupWrapper.getGroup(group).whenComplete((g, b) ->
{
if (b != null)
{
FLog.severe(b);
return;
}
if (data.getUser().getNodes(NodeType.INHERITANCE)
.contains(InheritanceNode.builder(g).build()))
userWrapper.removeFromGroup(data.getUser(), g);
});
}
}).whenComplete((a, b) ->
{
if (b != null)
{
FLog.severe(b);
}
});
}
private class LuckPermsUserDataListener
{
private final Map<NamespacedKey, EventSubscription<?>> subscriptions = new HashMap<>();
public void register()
{
EventBus eventBus = TotalFreedomMod.getPlugin().lpb.getAPI().getEventBus();
subscriptions.put(new NamespacedKey(TotalFreedomMod.getPlugin(), "node_add"), eventBus.subscribe(TotalFreedomMod.getPlugin(), NodeAddEvent.class, this::onNodeAdd));
subscriptions.put(new NamespacedKey(TotalFreedomMod.getPlugin(), "node_remove"), eventBus.subscribe(TotalFreedomMod.getPlugin(), NodeRemoveEvent.class, this::onNodeRemove));
}
public void unregister()
{
subscriptions.forEach((key, subscription) -> subscription.close());
subscriptions.clear();
}
private void onNodeAdd(NodeAddEvent event)
{
if (event.isUser())
{
User user = (User) event.getTarget();
Player player = Bukkit.getPlayer(user.getUniqueId());
if (player != null)
{
TotalFreedomMod.getPlugin().rm.updateDisplay(player);
updateUserData(player);
}
}
}
private void onNodeRemove(NodeRemoveEvent event)
{
if (event.isUser())
{
User user = (User) event.getTarget();
Player player = Bukkit.getPlayer(user.getUniqueId());
if (player != null)
{
TotalFreedomMod.getPlugin().rm.updateDisplay(player);
updateUserData(player);
}
}
}
}
}

View File

@ -1,154 +0,0 @@
package me.totalfreedom.totalfreedommod.rank;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
public enum Title implements Displayable
{
MASTER_BUILDER(Component.text("a"),
Component.text("Master Builder"),
Component.text("Master Builders"),
NamedTextColor.DARK_AQUA,
org.bukkit.ChatColor.DARK_AQUA,
Component.text("MB"),
true,
true),
EXECUTIVE(Component.text("an"),
Component.text("Executive"),
Component.text("Executives"),
NamedTextColor.RED,
org.bukkit.ChatColor.RED,
Component.text("Exec"),
true,
true),
ASST_EXEC(Component.text("an"),
Component.text("Assistant Executive"),
Component.text("Assistant Executives"),
NamedTextColor.RED,
org.bukkit.ChatColor.RED,
Component.text("Asst Exec"),
true,
true),
DEVELOPER(Component.text("a"),
Component.text("Developer"),
Component.text("Developers"),
NamedTextColor.DARK_PURPLE,
org.bukkit.ChatColor.DARK_PURPLE,
Component.text("Dev"),
true,
true),
OWNER(Component.text("an"),
Component.text("Owner"),
Component.text("Owners"),
NamedTextColor.DARK_RED,
org.bukkit.ChatColor.DARK_RED,
Component.text("Owner"),
true,
true);
private final Component article;
private final Component name;
private final Component abbr;
private final Component plural;
private final Component tag;
private final Component coloredTag;
private final TextColor color;
private final org.bukkit.ChatColor teamColor;
private final boolean hasTeam;
private final boolean hasDefaultLoginMessage;
Title(Component article, Component name, Component plural, TextColor color, org.bukkit.ChatColor teamColor, Component tag, Boolean hasTeam, Boolean hasDefaultLoginMessage)
{
this.article = article;
this.name = name;
this.plural = plural;
this.coloredTag = tag.color(color);
this.abbr = tag;
this.tag = GroupProvider.OPEN.append(tag).append(GroupProvider.CLOSE);
this.color = color;
this.teamColor = teamColor;
this.hasTeam = hasTeam;
this.hasDefaultLoginMessage = hasDefaultLoginMessage;
}
@Override
public Component getColoredName()
{
return name.color(color);
}
@Override
public boolean hasTeam()
{
return hasTeam;
}
@Override
public boolean hasDefaultLoginMessage()
{
return hasDefaultLoginMessage;
}
@Override
public Component getColoredLoginMessage()
{
return article.append(Component.text(" ").append(name.color(color)));
}
@Override
public Component getArticle()
{
return article;
}
@Override
public Component getName()
{
return name;
}
@Override
public Component getAbbr()
{
return abbr;
}
@Override
public Component getPlural()
{
return plural;
}
@Override
public Component getTag()
{
return tag;
}
@Override
public Component getColoredTag()
{
return coloredTag;
}
@Override
public TextColor getColor()
{
return color;
}
@Override
public org.bukkit.ChatColor getTeamColor()
{
return teamColor;
}
}

View File

@ -1,93 +0,0 @@
package me.totalfreedom.totalfreedommod.sql;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ResultSetProvider
{
List<Map<String, Object>> allRowsResultSet = new ArrayList<>();
Map<String, Object> singularResultMap = new HashMap<>();
private ResultSetProvider(Map<String, Object> singularResultMap)
{
this.singularResultMap = singularResultMap;
}
private ResultSetProvider(ResultSet resultSet, boolean allRows) throws SQLException
{
if (allRows)
{
while (resultSet.next())
{
allRowsResultSet.add(mapResultSet(resultSet));
}
} else
{
if (resultSet.next())
{
this.singularResultMap = mapResultSet(resultSet);
}
}
}
public static ResultSetProvider provideAllRows(ResultSet resultSet) throws SQLException
{
return new ResultSetProvider(resultSet, true);
}
public static ResultSetProvider provideSpecificRow(ResultSet resultSet) throws SQLException
{
return new ResultSetProvider(resultSet, false);
}
public static ResultSetProvider fromRow(Map<String, Object> row)
{
return new ResultSetProvider(row);
}
public List<Map<String, Object>> getAllRowsResultSet()
{
return allRowsResultSet;
}
private Map<String, Object> mapResultSet(ResultSet rs) throws SQLException
{
Map<String, Object> result = new HashMap<>();
while (rs.next())
{
int columns = rs.getMetaData().getColumnCount();
for (int i = 1; i <= columns; i++)
{
String columnName = rs.getMetaData().getColumnName(i);
Object columnValue = rs.getObject(i);
result.put(columnName, columnValue);
}
}
return result;
}
public String getString(String key)
{
return (String) singularResultMap.get(key);
}
public int getInt(String key)
{
return (int) singularResultMap.get(key);
}
public boolean getBoolean(String key)
{
return (boolean) singularResultMap.get(key);
}
public long getLong(String key)
{
return (long) singularResultMap.get(key);
}
}

View File

@ -1,592 +0,0 @@
package me.totalfreedom.totalfreedommod.sql;
import me.totalfreedom.totalfreedommod.FreedomService;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.banning.Ban;
import me.totalfreedom.totalfreedommod.player.PlayerData;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import java.sql.*;
import java.text.MessageFormat;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
public class SQLite extends FreedomService
{
public static final String TABLE_CHECK_FAILURE = "Failed to check tables on database: ";
private final String FILE_NAME = "database.db";
private Connection connection;
@Override
public void onStart()
{
connect();
checkTables().whenComplete((result, throwable) ->
{
if (throwable != null)
{
FLog.severe(TABLE_CHECK_FAILURE + throwable.getMessage());
}
});
}
@Override
public void onStop()
{
disconnect();
}
public void connect()
{
try
{
connection = DriverManager.getConnection("jdbc:sqlite:" + plugin.getDataFolder() + "/" + FILE_NAME);
FLog.info("Successfully connected to the database.");
} catch (SQLException e)
{
FLog.severe("Failed to connect to the database: " + e.getMessage());
}
}
public void disconnect()
{
try
{
if (connection != null)
{
connection.close();
}
} catch (SQLException e)
{
FLog.severe("Failed to disconnect from the database: " + e.getMessage());
}
}
public CompletableFuture<Void> checkTables()
{
return CompletableFuture.supplyAsync(() ->
{
try
{
return connection.getMetaData();
} catch (SQLException e)
{
throw new CompletionException(TABLE_CHECK_FAILURE, e);
}
}).thenAcceptAsync(meta ->
{
futureBansTable(meta);
futureAdminsTable(meta);
futurePlayersTable(meta);
});
}
private void futurePlayersTable(DatabaseMetaData meta)
{
tableNotExists(meta, "players").whenComplete((result, throwable) ->
{
if (throwable != null)
{
FLog.severe(throwable.getMessage());
return;
}
if (result)
{
createPlayersTable().whenComplete((result2, throwable2) ->
{
if (throwable2 != null)
{
FLog.severe(throwable2.getMessage());
}
});
}
});
}
private void futureAdminsTable(DatabaseMetaData meta)
{
tableNotExists(meta, "admins").whenComplete((result, throwable) ->
{
if (throwable != null)
{
FLog.severe(throwable.getMessage());
return;
}
if (result)
{
createAdminsTable().whenComplete((result2, throwable2) ->
{
if (throwable2 != null)
{
FLog.severe(throwable2.getMessage());
}
});
}
});
}
private void futureBansTable(DatabaseMetaData meta)
{
tableNotExists(meta, "bans").whenComplete((result, throwable) ->
{
if (throwable != null)
{
FLog.severe(throwable.getMessage());
return;
}
if (Boolean.TRUE.equals(result)) // using primitive for some reason... ask SonarLint.
{
createBanTable().whenComplete((result2, throwable2) ->
{
if (throwable2 != null)
{
FLog.severe(throwable2.getMessage());
}
});
}
});
}
private CompletableFuture<Void> createPlayersTable()
{
return CompletableFuture.supplyAsync(() ->
{
try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE `players` (`uuid` VARCHAR NOT NULL, `ips` VARCHAR NOT NULL, `notes` VARCHAR, `tag` VARCHAR, `discord_id` VARCHAR, `master_builder` BOOLEAN NOT NULL, `ride_mode` VARCHAR NOT NULL, `coins` INT, `items` VARCHAR, `total_votes` INT NOT NULL, `display_discord` BOOLEAN NOT NULL, `login_message` VARCHAR, `inspect` BOOLEAN NOT NULL);"))
{
statement.executeUpdate();
} catch (SQLException e)
{
throw new CompletionException("Failed to create the players table.", e);
}
return null;
});
}
private CompletableFuture<Void> createAdminsTable()
{
return CompletableFuture.supplyAsync(() ->
{
try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE `admins` (`uuid` VARCHAR NOT NULL, `ips` VARCHAR NOT NULL, `rank` VARCHAR NOT NULL, `active` BOOLEAN NOT NULL, `last_login` LONG NOT NULL, `command_spy` BOOLEAN NOT NULL, `potion_spy` BOOLEAN NOT NULL, `ac_format` VARCHAR);"))
{
statement.executeUpdate();
} catch (SQLException e)
{
throw new CompletionException("Failed to create the admins table.", e);
}
return null;
});
}
private CompletableFuture<Void> createBanTable()
{
return CompletableFuture.supplyAsync(() ->
{
try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE `bans` (`name` VARCHAR, `uuid` VARCHAR, `ips` VARCHAR, `by` VARCHAR NOT NULL, `at` LONG NOT NULL, `expires` LONG, `reason` VARCHAR);"))
{
statement.executeUpdate();
} catch (SQLException e)
{
throw new CompletionException("Failed to create the bans table.", e);
}
return null;
});
}
public CompletableFuture<Void> truncate(String table)
{
return CompletableFuture.supplyAsync(() ->
{
try (PreparedStatement statement = connection.prepareStatement("DELETE FROM ?"))
{
statement.setString(1, table);
statement.executeUpdate();
} catch (SQLException e)
{
FLog.severe("Failed to truncate " + table + ": " + e.getMessage());
}
return null;
});
}
public CompletableFuture<ResultSetProvider> getBanList()
{
return CompletableFuture.supplyAsync(() ->
{
ResultSetProvider provider;
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM bans"))
{
try (ResultSet result = statement.executeQuery())
{
provider = ResultSetProvider.provideAllRows(result);
}
} catch (SQLException e)
{
throw new CompletionException("Failed to get ban list.", e);
}
return provider;
});
}
public CompletableFuture<ResultSetProvider> getAdminList()
{
return CompletableFuture.supplyAsync(() ->
{
ResultSetProvider provider;
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM bans"))
{
try (ResultSet result = statement.executeQuery())
{
provider = ResultSetProvider.provideAllRows(result);
}
} catch (SQLException ex)
{
throw new CompletionException("Failed to get admin list.", ex);
}
return provider;
});
}
public CompletableFuture<Void> setAdminValue(Admin admin, String key, Object value)
{
return CompletableFuture.supplyAsync(() ->
{
try
{
Object[] data = {key, admin.getUuid()};
PreparedStatement statement = connection.prepareStatement(MessageFormat.format("UPDATE admins SET {0}=? WHERE uuid=''{1}''", data));
setUnknownType(statement, 1, value).whenComplete((result, throwable) ->
{
if (throwable != null)
{
FLog.severe(throwable.getMessage());
}
try
{
result.executeUpdate();
} catch (SQLException ex)
{
throw new CompletionException("Failed to update admin value.", ex);
}
});
} catch (SQLException e)
{
throw new CompletionException("Failed to update admin value.", e);
}
return null;
});
}
public CompletableFuture<Void> setPlayerValue(PlayerData player, String key, Object value)
{
return CompletableFuture.supplyAsync(() ->
{
try
{
Object[] data = {key, player.getUuid()};
PreparedStatement statement = connection.prepareStatement(MessageFormat.format("UPDATE players SET {0}=? WHERE uuid=''{1}''", data));
setUnknownType(statement, 1, value).whenComplete((result, throwable) ->
{
if (throwable != null)
{
FLog.severe(throwable.getMessage());
}
try
{
result.executeUpdate();
} catch (SQLException ex)
{
throw new CompletionException("Failed to update player value.", ex);
}
});
} catch (SQLException e)
{
throw new CompletionException("Failed to update player value.", e);
}
return null;
});
}
public CompletableFuture<PreparedStatement> setUnknownType(PreparedStatement statement, int index, Object value)
{
return CompletableFuture.supplyAsync(() ->
{
try
{
if (value == null)
{
statement.setString(index, null);
} else if (value.getClass().equals(String.class))
{
String v = (String) value;
statement.setString(index, v);
} else if (value.getClass().equals(Integer.class))
{
int v = (int) value;
statement.setInt(index, v);
} else if (value.getClass().equals(Boolean.class))
{
boolean v = (boolean) value;
statement.setBoolean(index, v);
} else if (value.getClass().equals(Long.class))
{
long v = (long) value;
statement.setLong(index, v);
}
return statement;
} catch (SQLException ex)
{
throw new CompletionException("Failed to set unknown type.", ex);
}
});
}
public Object getValue(ResultSetProvider provider, String key, Object value)
{
Object result = null;
if (value instanceof String)
{
result = provider.getString(key);
} else if (value instanceof Integer)
{
result = provider.getInt(key);
} else if (value instanceof Boolean)
{
result = provider.getBoolean(key);
} else if (value instanceof Long)
{
result = provider.getLong(key);
}
return result;
}
public CompletableFuture<Void> addAdmin(Admin admin)
{
return CompletableFuture.supplyAsync(() ->
{
try (PreparedStatement statement = connection.prepareStatement("INSERT INTO admins VALUES (?, ?, ?, ?, ?, ?, ?, ?)"))
{
statement.setString(1, admin.getUuid().toString());
statement.setString(2, FUtil.listToString(admin.getIps()));
statement.setString(3, admin.getRank().toString());
statement.setBoolean(4, admin.isActive());
statement.setLong(5, admin.getLastLogin().getTime());
statement.setBoolean(6, admin.getCommandSpy());
statement.setBoolean(7, admin.getPotionSpy());
statement.setString(8, admin.getAcFormat());
statement.executeUpdate();
} catch (SQLException e)
{
throw new CompletionException("Failed to add admin.", e);
}
return null;
});
}
public CompletableFuture<Void> addPlayer(PlayerData player)
{
return CompletableFuture.supplyAsync(() ->
{
try (PreparedStatement statement = connection.prepareStatement("INSERT INTO players VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"))
{
statement.setString(1, player.getUuid().toString());
statement.setString(2, FUtil.listToString(player.getIps()));
statement.setString(3, FUtil.listToString(player.getNotes()));
statement.setString(4, FUtil.miniMessage(player.getTag()));
statement.setString(5, player.getDiscordID());
statement.setBoolean(6, player.isMasterBuilder());
statement.setString(7, player.getRideMode().name());
statement.setInt(8, player.getCoins());
statement.setString(9, FUtil.listToString(player.getItems()));
statement.setInt(10, player.getTotalVotes());
statement.setBoolean(11, player.doesDisplayDiscord());
statement.setString(12, player.getLoginMessage());
statement.setBoolean(13, player.hasInspection());
statement.executeUpdate();
} catch (SQLException e)
{
throw new CompletionException("Failed to add player.", e);
}
return null;
});
}
public CompletableFuture<ResultSetProvider> getAdminByUuid(UUID uuid)
{
return CompletableFuture.supplyAsync(() ->
{
ResultSetProvider provider;
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM admins WHERE uuid=?"))
{
statement.setString(1, uuid.toString());
try (ResultSet set = statement.executeQuery())
{
provider = ResultSetProvider.provideSpecificRow(set);
}
} catch (SQLException ex)
{
throw new CompletionException(ex);
}
return provider;
});
}
public CompletableFuture<ResultSetProvider> getPlayerByUuid(UUID uuid)
{
return CompletableFuture.supplyAsync(() ->
{
ResultSetProvider provider;
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM players WHERE uuid=?"))
{
statement.setString(1, uuid.toString());
try (ResultSet set = statement.executeQuery())
{
provider = ResultSetProvider.provideSpecificRow(set);
}
} catch (SQLException ex)
{
throw new CompletionException(ex);
}
return provider;
});
}
public CompletableFuture<ResultSetProvider> getMasterBuilders()
{
return CompletableFuture.supplyAsync(() ->
{
ResultSetProvider provider;
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM players WHERE master_builder=true"))
{
try (ResultSet result = statement.executeQuery())
{
provider = ResultSetProvider.provideAllRows(result);
}
} catch (SQLException ex)
{
throw new CompletionException(ex);
}
return provider;
});
}
public CompletableFuture<ResultSetProvider> getPlayerByIp(String ip)
{
return CompletableFuture.supplyAsync(() ->
{
ResultSetProvider provider;
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM players WHERE ips LIKE %?%"))
{
statement.setString(1, ip);
try (ResultSet set = statement.executeQuery())
{
provider = ResultSetProvider.provideSpecificRow(set);
}
} catch (SQLException e)
{
throw new CompletionException(e);
}
return provider;
});
}
public CompletableFuture<Void> removeAdmin(Admin admin)
{
return CompletableFuture.supplyAsync(() ->
{
try (PreparedStatement statement = connection.prepareStatement("DELETE FROM admins where name=?"))
{
statement.setString(1, admin.getName());
statement.executeUpdate();
} catch (SQLException e)
{
throw new CompletionException("Failed to remove admin.", e);
}
return null;
});
}
public CompletableFuture<Void> addBan(Ban ban)
{
return CompletableFuture.supplyAsync(() ->
{
try (PreparedStatement statement = connection.prepareStatement("INSERT INTO bans VALUES (?, ?, ?, ?, ?, ?, ?)"))
{
statement.setString(1, ban.getUsername());
String uuid = null;
if (ban.hasUUID())
{
uuid = ban.getUuid().toString();
}
statement.setString(2, uuid);
statement.setString(3, FUtil.listToString(ban.getIps()));
statement.setString(4, ban.getBy());
statement.setLong(5, ban.getAt().getTime());
statement.setLong(6, ban.getExpiryUnix());
statement.setString(7, ban.getReason());
statement.executeUpdate();
} catch (SQLException e)
{
throw new CompletionException("Failed to add ban.", e);
}
return null;
});
}
public CompletableFuture<Void> removeBan(Ban ban)
{
return CompletableFuture.supplyAsync(() ->
{
try
{
try (PreparedStatement statement = connection.prepareStatement("DELETE FROM bans WHERE name=?"))
{
statement.setString(1, ban.getUsername());
statement.executeUpdate();
}
for (String ip : ban.getIps())
{
try (PreparedStatement statement = connection.prepareStatement("DELETE FROM bans WHERE ips LIKE %?%"))
{
statement.setString(1, ip);
statement.executeUpdate();
}
}
} catch (SQLException e)
{
throw new CompletionException("Failed to remove ban.", e);
}
return null;
});
}
// We've changed this to read tableNotExists because it's more accurate in context.
public CompletableFuture<Boolean> tableNotExists(DatabaseMetaData meta, String name)
{
return CompletableFuture.supplyAsync(() ->
{
try
{
return !meta.getTables(null, null, name, null).next();
} catch (SQLException ex)
{
throw new CompletionException(TABLE_CHECK_FAILURE, ex);
}
});
}
}

View File

@ -1,33 +0,0 @@
package me.totalfreedom.totalfreedommod.util;
import java.util.regex.Pattern;
public class FConverter
{
private static final Pattern godFuckingDamnit = Pattern.compile(".*(?i)(&((#[a-f0-9]{3,6})|([0-9a-fklmnor]))|%[a-z]+%).*");
public static boolean needsConversion(String messageOrFormat)
{
return godFuckingDamnit.matcher(messageOrFormat).find();
}
public static String convertAdminChatFormat(String format)
{
return FUtil.MINI_MESSAGE.serialize(FUtil.LEGACY_AMPERSAND.deserialize(
format.replaceAll("%name%", "<name>")
.replaceAll("%rank%", "<rank>")
.replaceAll("%rankcolor%", "<rankcolor>")
.replaceAll("%msg%", "<message>")))
.replaceAll("\\\\<", "<"); // GOD FUCKING DAMMIT
}
public static String convertLoginMessage(String message)
{
return FUtil.MINI_MESSAGE.serialize(FUtil.LEGACY_AMPERSAND.deserialize(
message.replaceAll("%name%", "<name>")
.replaceAll("%rank%", "<rank>")
.replaceAll("%coloredrank%", "<coloredrank>")
.replaceAll("%art%", "<art>")))
.replaceAll("\\\\<", "<"); // GOD FUCKING DAMMIT
}
}

View File

@ -1,30 +0,0 @@
package me.totalfreedom.totalfreedommod.util;
import org.bukkit.Material;
import org.bukkit.block.Biome;
import org.bukkit.entity.EntityType;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
public class Groups
{
public static final Set<Material> WOOL_COLORS = Arrays.stream(Material.values()).filter((m) -> m.name().endsWith("_WOOL")).collect(Collectors.toSet());
public static final Set<Material> SHULKER_BOXES = Arrays.stream(Material.values()).filter((m) -> m.name().endsWith("SHULKER_BOX")).collect(Collectors.toSet());
public static final Set<EntityType> MOB_TYPES = Arrays.stream(EntityType.values()).filter(EntityType::isAlive).filter(EntityType::isSpawnable).collect(Collectors.toSet());
public static final Set<Material> SPAWN_EGGS = Arrays.stream(Material.values()).filter((mat) -> mat.name().endsWith("_SPAWN_EGG")).collect(Collectors.toSet());
public static final Set<Material> BANNERS = Arrays.stream(Material.values()).filter((m) -> m.name().endsWith("_BANNER")).collect(Collectors.toSet());
public static final Set<Biome> EXPLOSIVE_BED_BIOMES = new HashSet<>(Arrays.asList(
Biome.NETHER_WASTES,
Biome.CRIMSON_FOREST,
Biome.SOUL_SAND_VALLEY,
Biome.WARPED_FOREST,
Biome.BASALT_DELTAS,
Biome.END_BARRENS,
Biome.END_HIGHLANDS,
Biome.END_MIDLANDS,
Biome.THE_END,
Biome.SMALL_END_ISLANDS));
}

View File

@ -1,110 +0,0 @@
package me.totalfreedom.totalfreedommod.util;
import me.totalfreedom.totalfreedommod.api.Interpolator;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import org.bukkit.Color;
import java.util.LinkedHashSet;
public class Interpolation
{
public LinkedHashSet<Color> rainbow(int length)
{
LinkedHashSet<Color> base = new LinkedHashSet<>();
LinkedHashSet<Color> redToOrange = hsvGradient(length, Color.RED, Color.ORANGE, this::linear);
LinkedHashSet<Color> orangeToYellow = hsvGradient(length, Color.ORANGE, Color.YELLOW, this::linear);
LinkedHashSet<Color> yellowToGreen = hsvGradient(length, Color.YELLOW, Color.GREEN, this::linear);
LinkedHashSet<Color> greenToBlue = hsvGradient(length, Color.GREEN, Color.BLUE, this::linear);
LinkedHashSet<Color> blueToPurple = hsvGradient(length, Color.BLUE, Color.PURPLE, this::linear);
LinkedHashSet<Color> purpleToRed = hsvGradient(length, Color.PURPLE, Color.RED, this::linear);
base.addAll(redToOrange);
base.addAll(orangeToYellow);
base.addAll(yellowToGreen);
base.addAll(greenToBlue);
base.addAll(blueToPurple);
base.addAll(purpleToRed);
return base;
}
private double[] linear(double from, double to, int max)
{
final double[] res = new double[max];
for (int i = 0; i < max; i++)
{
res[i] = from + i * ((to - from) / (max - 1));
}
return res;
}
private LinkedHashSet<Color> hsvGradient(int length, Color from, Color to, Interpolator interpolator)
{
// returns a float-array where hsv[0] = hue, hsv[1] = saturation, hsv[2] = value/brightness
final float[] hsvFrom = java.awt.Color.RGBtoHSB(from.getRed(), from.getGreen(), from.getBlue(), null);
final float[] hsvTo = java.awt.Color.RGBtoHSB(to.getRed(), to.getGreen(), to.getBlue(), null);
final double[] h = interpolator.interpolate(hsvFrom[0], hsvTo[0], length);
final double[] s = interpolator.interpolate(hsvFrom[1], hsvTo[1], length);
final double[] v = interpolator.interpolate(hsvFrom[2], hsvTo[2], length);
final LinkedHashSet<Color> gradient = new LinkedHashSet<>();
for (int i = 0; i < length; i++)
{
final int rgb = java.awt.Color.HSBtoRGB((float) h[i], (float) s[i], (float) v[i]);
final Color color = Color.fromRGB(rgb);
gradient.add(color);
}
return gradient;
}
public LinkedHashSet<Color> rgbGradient(int length, Color from, Color to, Interpolator interpolator)
{
final double[] r = interpolator.interpolate(from.getRed(), to.getRed(), length);
final double[] g = interpolator.interpolate(from.getGreen(), to.getGreen(), length);
final double[] b = interpolator.interpolate(from.getBlue(), to.getBlue(), length);
final LinkedHashSet<Color> gradient = new LinkedHashSet<>();
for (int i = 0; i < length; i++)
{
final Color color = Color.fromRGB((int) r[i], (int) g[i], (int) b[i]);
gradient.add(color);
}
return gradient;
}
public LinkedHashSet<TextColor> componentRGBGradient(int length, TextColor from, TextColor to, Interpolator interpolator)
{
final double[] r = interpolator.interpolate(from.red(), to.red(), length);
final double[] g = interpolator.interpolate(from.green(), to.green(), length);
final double[] b = interpolator.interpolate(from.blue(), to.blue(), length);
final LinkedHashSet<TextColor> gradient = new LinkedHashSet<>();
for (int i = 0; i < length; i++)
{
final TextColor color = TextColor.color((int) r[i], (int) g[i], (int) b[i]);
gradient.add(color);
}
return gradient;
}
public LinkedHashSet<TextColor> rainbowComponent(int length)
{
LinkedHashSet<TextColor> base = new LinkedHashSet<>();
LinkedHashSet<TextColor> redToOrange = componentRGBGradient(length, NamedTextColor.RED, NamedTextColor.GOLD, this::linear);
LinkedHashSet<TextColor> orangeToYellow = componentRGBGradient(length, NamedTextColor.GOLD, NamedTextColor.YELLOW, this::linear);
LinkedHashSet<TextColor> yellowToGreen = componentRGBGradient(length, NamedTextColor.YELLOW, NamedTextColor.GREEN, this::linear);
LinkedHashSet<TextColor> greenToBlue = componentRGBGradient(length, NamedTextColor.GREEN, NamedTextColor.BLUE, this::linear);
LinkedHashSet<TextColor> blueToPurple = componentRGBGradient(length, NamedTextColor.BLUE, NamedTextColor.LIGHT_PURPLE, this::linear);
LinkedHashSet<TextColor> purpleToRed = componentRGBGradient(length, TextColor.color(75, 0, 130), TextColor.color(255, 0, 0), this::linear);
base.addAll(redToOrange);
base.addAll(orangeToYellow);
base.addAll(yellowToGreen);
base.addAll(greenToBlue);
base.addAll(blueToPurple);
base.addAll(purpleToRed);
return base;
}
}

View File

@ -1,57 +0,0 @@
package me.totalfreedom.totalfreedommod.util;
import com.destroystokyo.paper.ParticleBuilder;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
public class ParticleDisplay
{
private final Interpolation interpolation;
private Iterator<Color> colorIterator;
public ParticleDisplay()
{
this.interpolation = new Interpolation();
this.colorIterator = interpolation.rainbow(43).iterator();
}
public void spawnNext(Player player)
{
Location location = getBehind(player);
Color color = getIterator().next();
Particle.DustOptions options = new Particle.DustOptions(color, 3);
ParticleBuilder builder = new ParticleBuilder(Particle.REDSTONE);
builder.data(options)
.receivers(30, 15, true)
.offset(0.5, 0.5, 0.5)
.location(location)
.spawn();
}
private Location getBehind(Player player)
{
@NotNull Vector inverse = player.getLocation()
.clone()
.getDirection()
.normalize()
.multiply(-1);
return player.getLocation().add(inverse);
}
private Iterator<Color> getIterator()
{
if (!this.colorIterator.hasNext())
{
this.colorIterator = interpolation.rainbow(43).iterator();
}
return this.colorIterator;
}
}

View File

@ -1,28 +0,0 @@
package me.totalfreedom.totalfreedommod.util;
public class PermissibleCompletion
{
private final String permission;
private final String completion;
protected PermissibleCompletion(String permission, String completion)
{
this.completion = completion;
this.permission = permission;
}
public String getPermission()
{
return permission;
}
public String getCompletion()
{
return completion;
}
public static PermissibleCompletion of(String permission, String completion)
{
return new PermissibleCompletion(permission, completion);
}
}

View File

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>me.totalfreedom</groupId>
<artifactId>TotalFreedomMod</artifactId>
<version>2023.03</version>
</parent>
<artifactId>discord</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.discord4j</groupId>
<artifactId>discord4j-core</artifactId>
<version>3.2.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.totalfreedom</groupId>
<artifactId>commons</artifactId>
<version>2023.03</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.5.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,95 +0,0 @@
package me.totalfreedom.discord;
import discord4j.core.DiscordClientBuilder;
import discord4j.core.GatewayDiscordClient;
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
import discord4j.core.object.entity.Guild;
import me.totalfreedom.discord.command.HelpCommand;
import me.totalfreedom.discord.command.ListCommand;
import me.totalfreedom.discord.command.TPSCommand;
import me.totalfreedom.discord.handling.CommandHandler;
import me.totalfreedom.discord.react.ReactiveBukkitScheduler;
import me.totalfreedom.discord.util.SnowflakeEntry;
import me.totalfreedom.discord.util.TFM_Bridge;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.player.PlayerData;
import me.totalfreedom.totalfreedommod.util.FLog;
import org.bukkit.Bukkit;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.Map;
public class Bot
{
private final GatewayDiscordClient client;
private final TFM_Bridge tfm;
private final HashMap<String, PlayerData> LINK_CODES = new HashMap<>();
public Bot()
{
//Creates the gateway client and connects to the gateway
this.client = DiscordClientBuilder.create(ConfigEntry.DISCORD_TOKEN.getString())
.build()
.login()
.block();
this.tfm = new TFM_Bridge(this);
}
public void initialize() {
if (client == null) throw new IllegalStateException();
}
public String formatBotTag() {
return client.getSelf()
.blockOptional()
.orElseThrow()
.getUsername() + "#" + client.getSelf()
.blockOptional()
.orElseThrow()
.getDiscriminator();
}
public TFM_Bridge getTFM()
{
return tfm;
}
public Mono<Guild> getGuildById()
{
return client.getGuildById(SnowflakeEntry.SERVER_ID.getSnowflake());
}
public GatewayDiscordClient getClient()
{
return client;
}
public Map<String, PlayerData> getLinkCodes()
{
return LINK_CODES;
}
public boolean shouldISendReport()
{
if (ConfigEntry.DISCORD_REPORT_CHANNEL_ID.getString().isEmpty())
{
return false;
}
if (ConfigEntry.DISCORD_SERVER_ID.getString().isEmpty())
{
FLog.severe("No Discord server ID was specified in the config, but there is a report channel ID.");
return false;
}
Guild server = client.getGuildById(SnowflakeEntry.SERVER_ID.getSnowflake()).block();
if (server == null)
{
FLog.severe("The Discord server ID specified is invalid, or the bot is not on the server.");
return false;
}
return true;
}
}

View File

@ -1,124 +0,0 @@
package me.totalfreedom.discord;
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
import me.totalfreedom.discord.command.HelpCommand;
import me.totalfreedom.discord.command.ListCommand;
import me.totalfreedom.discord.command.TPSCommand;
import me.totalfreedom.discord.handling.CommandHandler;
import me.totalfreedom.discord.listener.*;
import me.totalfreedom.discord.react.ReactiveBukkitScheduler;
import me.totalfreedom.totalfreedommod.api.Context;
import me.totalfreedom.totalfreedommod.api.TFD4JCommons;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.slf4j.Logger;
/**
* @author Paldiu
* @author videogamesm12
* @since 2023-03-16
*/
public class TFD4J extends JavaPlugin
{
private final Logger slf4j = this.getSLF4JLogger();
private Bot bot;
private MinecraftListener mc;
private AdminChatListener ac;
private PrivateMessageListener pm;
private ReactionListener rl;
private TFD4JCommons tfd4jcommons;
private BukkitNative bn;
private CommandHandler ch;
private ReactiveBukkitScheduler rbs;
@Override
public void onEnable()
{
slf4j().info("Hello from TFD4J! Initializing our API implementation...");
this.tfd4jcommons = new TFD4JCommonsImpl(this);
slf4j().info("API successfully initialized! Initializing our bot...");
this.bot = new Bot();
bot.initialize();
slf4j().info("Bot successfully initialized! Abstracting the BukkitScheduler...");
this.rbs = new ReactiveBukkitScheduler(this);
String string = String.format("Scheduler successfully wrapped into %s! Registering the Bukkit Native listener...", ReactiveBukkitScheduler.class.getName()); // Fixes SonarLint's "Invoke methods only conditionally."
slf4j().info(string);
this.bn = new BukkitNative(this);
Bukkit.getPluginManager().registerEvents(this.bn, this);
slf4j().info("Bukkit Native listener successfully registered! Registering the Discord4J Listeners...");
this.mc = new MinecraftListener(this);
this.ac = new AdminChatListener(this);
this.pm = new PrivateMessageListener(this);
this.rl = new ReactionListener(this);
pm.privateMessageReceived();
rl.onReactionAdd();
mc.minecraftChatBound();
ac.adminChatBound();
slf4j().info("Discord4J listeners successfully registered! Registering the Command Handler...");
this.ch = new CommandHandler(bot.getClient().getRestClient());
slf4j().info("Command Handler successfully registered! Registering commands...");
this.ch.registerCommand(new HelpCommand());
this.ch.registerCommand(new ListCommand());
this.ch.registerCommand(new TPSCommand());
this.getBot().getClient().on(ChatInputInteractionEvent.class, ch::handle)
.subscribeOn(getReactiveBukkitScheduler())
.subscribe();
slf4j().info("Commands successfully registered! Providing context to TFM...");
Context<TFD4JCommons> context = new Context<>(tfd4jcommons);
bot.getTFM().getCommons().ag.setDiscordContext(context);
bot.getTFM().getCommons().registerDiscord();
slf4j().info("Context provided! TFD4J is now ready to go!");
}
@Override
public void onDisable()
{
slf4j().info("Disconnecting the Discord bot...");
bot.getClient()
.onDisconnect()
.doOnError(th -> slf4j().error("Error disconnecting the bot!", th))
.doOnSuccess(v -> slf4j().info("Bot disconnected!"))
.subscribe();
slf4j().info("Goodbye from TFD4J!");
}
public Logger slf4j()
{
return slf4j;
}
public Bot getBot()
{
return bot;
}
public TFD4JCommons getImpl()
{
return tfd4jcommons;
}
public MinecraftListener getMinecraftListener()
{
return mc;
}
public AdminChatListener getAdminChatListener()
{
return ac;
}
public ReactiveBukkitScheduler getReactiveBukkitScheduler()
{
return rbs;
}
}

View File

@ -1,368 +0,0 @@
package me.totalfreedom.discord;
import com.google.common.collect.ImmutableList;
import discord4j.common.util.Snowflake;
import discord4j.core.object.entity.Guild;
import discord4j.core.object.entity.Member;
import discord4j.core.object.entity.Message;
import discord4j.core.object.entity.Role;
import discord4j.core.object.entity.channel.TextChannel;
import discord4j.core.object.reaction.ReactionEmoji;
import discord4j.core.spec.EmbedCreateSpec;
import discord4j.core.spec.MessageCreateSpec;
import me.totalfreedom.discord.util.SnowflakeEntry;
import me.totalfreedom.discord.util.Utilities;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.api.TFD4JCommons;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.player.PlayerData;
import me.totalfreedom.totalfreedommod.rank.GroupProvider;
import me.totalfreedom.totalfreedommod.util.FLog;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.WordUtils;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Map;
import java.util.Objects;
public class TFD4JCommonsImpl implements TFD4JCommons
{
private final TFD4J tfd4J;
private final ImmutableList<String> DISCORD_SUBDOMAINS;
private Flux<Message> sentMessages;
public TFD4JCommonsImpl(TFD4J tfd4J)
{
this.tfd4J = tfd4J;
this.sentMessages = Flux.fromIterable(new ArrayList<>());
this.DISCORD_SUBDOMAINS = ImmutableList.of("discordapp.com", "discord.com", "discord.gg");
}
@Override
public void messageAdminChatChannel(String message)
{
String chat_channel_id = ConfigEntry.DISCORD_ADMINCHAT_CHANNEL_ID.getString();
String sanitizedMessage = sanitizeChatMessage(message);
if (sanitizedMessage.isBlank()) return;
if (!chat_channel_id.isEmpty())
{
MessageCreateSpec spec = MessageCreateSpec.builder()
.content(sanitizedMessage)
.build();
Mono<Message> sentMessage = tfd4J
.getBot()
.getClient()
.getChannelById(SnowflakeEntry.ADMIN_CHAT_CHANNEL_ID.getSnowflake())
.ofType(TextChannel.class)
.flatMap(c -> c.createMessage(spec));
sentMessage.subscribe();
}
}
public Flux<Message> getMessagesSent()
{
return sentMessages;
}
private void insert(Mono<Message> messageMono)
{
sentMessages.concatWith(messageMono);
}
@Override
public void clearQueue()
{
sentMessages = Flux.fromIterable(new ArrayList<>());
}
@Override
public void messageChatChannel(String message, boolean system)
{
String chat_channel_id = ConfigEntry.DISCORD_CHAT_CHANNEL_ID.getString();
String sanitizedMessage = (system) ? message : sanitizeChatMessage(message);
if (sanitizedMessage.isBlank()) return;
if (!chat_channel_id.isEmpty())
{
MessageCreateSpec spec = MessageCreateSpec.builder()
.content(sanitizedMessage)
.build();
Mono<Message> sentMessage = tfd4J
.getBot()
.getClient()
.getChannelById(SnowflakeEntry.CHAT_CHANNEL_ID.getSnowflake())
.ofType(TextChannel.class)
.flatMap(c -> c.createMessage(spec));
sentMessage.subscribe();
}
}
private String sanitizeChatMessage(String message)
{
String newMessage = message;
if (message.contains("@"))
{
// \u200B is Zero Width Space, invisible on Discord
newMessage = message.replace("@", "@\u200B");
}
if (message.toLowerCase().contains("discord.gg")) // discord.gg/invite works as an invite
{
return "";
}
for (String subdomain : DISCORD_SUBDOMAINS)
{
if (message.toLowerCase().contains(subdomain + "/invite"))
{
return "";
}
}
if (message.contains("§"))
{
newMessage = message.replace("§", "");
}
return Utilities.deformat(newMessage);
}
@Override
public boolean syncRoles(Admin admin, String discordID)
{
if (discordID == null)
{
return false;
}
Guild server = tfd4J.getBot().getGuildById()
.blockOptional()
.orElseThrow();
Member member = server.getMemberById(Snowflake.of(discordID))
.blockOptional()
.orElseThrow();
Role adminRole = server.getRoleById(SnowflakeEntry.ADMIN_ROLE_ID.getSnowflake())
.blockOptional()
.orElseThrow();
Role senioradminRole = server.getRoleById(SnowflakeEntry.SENIOR_ADMIN_ROLE_ID.getSnowflake())
.blockOptional()
.orElseThrow();
if (!admin.isActive())
{
syncRolesActivityCheck(member, adminRole, senioradminRole);
return true;
}
if (admin.getRank().equals(GroupProvider.ADMIN.getGroup()))
{
syncRolesAdminAssignment(member, adminRole, senioradminRole);
return true;
} else if (admin.getRank().equals(GroupProvider.SENIOR_ADMIN.getGroup()))
{
syncRolesSeniorAssignment(member, adminRole, senioradminRole);
return true;
}
return false;
}
private void syncRolesAdminAssignment(Member member, Role adminRole, Role senioradminRole)
{
member.getRoles().doFirst(() ->
{
if (!member.getRoles().collectList().blockOptional().orElseThrow().contains(adminRole))
{
member.addRole(adminRole.getId()).block();
}
}).doOnEach(r ->
{
Role role = r.get();
if (role == null) return;
if (role.equals(senioradminRole))
{
member.removeRole(role.getId()).block();
}
}).subscribe();
}
private void syncRolesActivityCheck(Member member, Role adminRole, Role senioradminRole)
{
member.getRoles().doOnEach(r ->
{
Role role = r.get();
if (role == null) return;
if (role.equals(adminRole) || role.equals(senioradminRole))
{
member.removeRole(role.getId()).block();
}
}).subscribe();
}
private void syncRolesSeniorAssignment(Member member, Role adminRole, Role senioradminRole)
{
member.getRoles().doFirst(() ->
{
if (!member.getRoles().collectList().blockOptional().orElseThrow().contains(senioradminRole))
{
member.addRole(senioradminRole.getId()).block();
}
}).doOnEach(r ->
{
Role role = r.get();
if (role == null) return;
if (role.equals(adminRole))
{
member.removeRole(role.getId()).block();
}
}).subscribe();
}
@Override
public String getCode(PlayerData playerData)
{
for (String code : this.getLinkCodes().keySet())
{
if (this.getLinkCodes().get(code).equals(playerData))
{
return code;
}
}
return "";
}
@Override
public String generateCode(int size)
{
return RandomStringUtils.randomNumeric(size);
}
@Override
public Map<String, PlayerData> getLinkCodes()
{
return tfd4J.getBot().getLinkCodes();
}
@Override
public String formatBotTag()
{
return tfd4J.getBot().formatBotTag();
}
@Override
public boolean sendReportOffline(Player reporter, OfflinePlayer reported, String reason)
{
if (!tfd4J.getBot().shouldISendReport())
{
return false;
}
final Guild server = tfd4J.getBot().getGuildById().block();
if (server == null) return false;
final TextChannel channel = server.getChannelById(SnowflakeEntry.REPORT_CHANNEL_ID.getSnowflake())
.ofType(TextChannel.class)
.blockOptional()
.orElseThrow();
final EmbedCreateSpec.Builder builder = EmbedCreateSpec.builder()
.title("Report for " + reported.getName() + " (offline)")
.description(reason)
.footer("Reported by " + reporter.getName(), "https://minotar.net/helm/" + reporter.getName() + ".png")
.timestamp(Instant.from(ZonedDateTime.now()));
if (tfd4J.getBot().getTFM().getCommons().esb.isEnabled())
{
com.earth2me.essentials.User user = tfd4J.getBot().getTFM().getCommons().esb.getEssentialsUser(reported.getName());
String location = "World: " + Objects.requireNonNull(user.getLastLocation().getWorld()).getName() + ", X: " + user.getLastLocation().getBlockX() + ", Y: " + user.getLastLocation().getBlockY() + ", Z: " + user.getLastLocation().getBlockZ();
builder.addField("Location", location, true);
builder.addField("God Mode", WordUtils.capitalizeFully(String.valueOf(user.isGodModeEnabled())), true);
if (user.getNickname() != null)
{
builder.addField("Nickname", user.getNickname(), true);
}
}
EmbedCreateSpec embed = builder.build();
Message message = channel.createMessage(embed).block();
if (message != null && !ConfigEntry.DISCORD_REPORT_ARCHIVE_CHANNEL_ID.getString().isEmpty())
{
message.addReaction(ReactionEmoji.unicode("\uD83D\uDCCB")).subscribe();
}
return true;
}
@Override
public boolean sendReport(Player reporter, Player reported, String reason)
{
if (!tfd4J.getBot().shouldISendReport())
{
return false;
}
final Guild server = tfd4J.getBot()
.getClient()
.getGuildById(SnowflakeEntry.SERVER_ID.getSnowflake())
.block();
if (server == null)
{
FLog.severe("The guild ID specified in the config is invalid.");
return false;
}
final TextChannel channel = server.getChannelById(SnowflakeEntry.REPORT_CHANNEL_ID.getSnowflake())
.ofType(TextChannel.class)
.blockOptional()
.orElseThrow();
String location = "World: " + Objects.requireNonNull(reported.getLocation().getWorld()).getName() + ", X: " + reported.getLocation().getBlockX() + ", Y: " + reported.getLocation().getBlockY() + ", Z: " + reported.getLocation().getBlockZ();
final EmbedCreateSpec spec = EmbedCreateSpec.builder()
.title("Report for " + reported.getName())
.description(reason)
.footer("Reported by " + reporter.getName(), "https://minotar.net/helm/" + reporter.getName() + ".png")
.timestamp(Instant.from(ZonedDateTime.now()))
.addField("Location", location, true)
.addField("Game Mode", WordUtils.capitalizeFully(reported.getGameMode().name()), true)
.build();
Message message = channel.createMessage(spec).block();
if (!ConfigEntry.DISCORD_REPORT_ARCHIVE_CHANNEL_ID.getString().isEmpty() && message != null)
{
ReactionEmoji emoji = ReactionEmoji.unicode("\uD83D\uDCCB");
message.addReaction(emoji);
}
return true;
}
@Override
public boolean isEnabled()
{
return tfd4J.isEnabled();
}
}

View File

@ -1,36 +0,0 @@
package me.totalfreedom.discord.command;
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
import discord4j.core.spec.EmbedCreateSpec;
import discord4j.rest.util.Color;
import me.totalfreedom.discord.handling.SlashCommand;
import reactor.core.publisher.Mono;
import java.time.Instant;
public class HelpCommand implements SlashCommand
{
@Override
public String getName()
{
return "help";
}
@Override
public Mono<Void> handle(ChatInputInteractionEvent event)
{
EmbedCreateSpec spec = EmbedCreateSpec.builder()
.color(Color.GREEN)
.title("Help Command")
.addField("Commands", "This is a list of all commands", false)
.addField("\u200B", "\u200B", false)
.addField("help", "Displays the help command. (This command.)", true)
.addField("list", "Displays a list of all online players.", true)
.addField("tps", "Displays the server's TPS.", true)
.timestamp(Instant.now())
.build();
return event.reply()
.withEmbeds(spec);
}
}

View File

@ -1,57 +0,0 @@
package me.totalfreedom.discord.command;
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
import discord4j.core.spec.EmbedCreateSpec;
import discord4j.rest.util.Color;
import me.totalfreedom.discord.handling.SlashCommand;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity;
import reactor.core.publisher.Mono;
import java.util.Iterator;
import java.util.List;
public class ListCommand implements SlashCommand
{
@Override
public String getName()
{
return "list";
}
@Override
public Mono<Void> handle(ChatInputInteractionEvent event)
{
List<String> playerNames = Bukkit.getOnlinePlayers()
.stream()
.map(HumanEntity::getName)
.toList();
StringBuilder sb = new StringBuilder();
Iterator<String> iterator = playerNames.iterator();
while (iterator.hasNext()) {
sb.append(iterator.next());
if (iterator.hasNext()) {
sb.append(", \n");
}
}
String empty = "\u200B";
EmbedCreateSpec spec = EmbedCreateSpec.builder()
.title("Player List - " + ConfigEntry.SERVER_NAME.getString())
.color(Color.BISMARK)
.addField("Online Players", String.join(", ", playerNames), false)
.addField(empty, "Currently Online: " + playerNames.size(), false)
.addField(empty, empty, false)
.addField("Players: ", sb.toString(), true)
.build();
return event.reply()
.withEmbeds(spec)
.withEphemeral(true)
.withContent(sb.toString());
}
}

View File

@ -1,39 +0,0 @@
package me.totalfreedom.discord.command;
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
import discord4j.core.spec.EmbedCreateSpec;
import discord4j.rest.util.Color;
import me.totalfreedom.discord.handling.SlashCommand;
import me.totalfreedom.totalfreedommod.util.FUtil;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
public class TPSCommand implements SlashCommand
{
@Override
public String getName()
{
return "tps";
}
@Override
public Mono<Void> handle(@NotNull ChatInputInteractionEvent event)
{
String tps = String.valueOf(FUtil.getMeanAverageDouble(Bukkit.getServer().getTPS()));
EmbedCreateSpec spec = EmbedCreateSpec.builder()
.title("Current Server Tick Information")
.addField("TPS", tps, false)
.addField("Uptime", FUtil.getUptime(), false)
.addField("Maximum Memory", Math.ceil(FUtil.getMaxMem()) + " MB", false)
.addField("Allocated Memory", Math.ceil(FUtil.getTotalMem()) + " MB", false)
.addField("Free Memory", Math.ceil(FUtil.getFreeMem()) + " MB", false)
.color(Color.BISMARK)
.build();
return event.reply()
.withEmbeds(spec)
.withEphemeral(true);
}
}

View File

@ -1,113 +0,0 @@
package me.totalfreedom.discord.handling;
import discord4j.common.JacksonResources;
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
import discord4j.discordjson.json.ApplicationCommandRequest;
import discord4j.rest.RestClient;
import discord4j.rest.service.ApplicationService;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class CommandHandler
{
private final List<SlashCommand> commands = new ArrayList<>();
private final RestClient restClient;
public CommandHandler(RestClient restClient)
{
this.restClient = restClient;
}
public void registerCommands(List<String> fileNames) throws IOException
{
//Create an ObjectMapper that supports Discord4J classes
final JacksonResources d4jMapper = JacksonResources.create();
// Convenience variables for the sake of easier to read code below
final ApplicationService applicationService = restClient.getApplicationService();
final long applicationId = Objects.requireNonNull(restClient.getApplicationId().block());
//Get our commands json from resources as command data
List<ApplicationCommandRequest> commands = new ArrayList<>();
for (String json : getCommandsJson(fileNames))
{
ApplicationCommandRequest request = d4jMapper.getObjectMapper()
.readValue(json, ApplicationCommandRequest.class);
commands.add(request); //Add to our array list
}
/* Bulk overwrite commands. This is now idempotent, so it is safe to use this even when only 1 command
is changed/added/removed
*/
applicationService.bulkOverwriteGlobalApplicationCommand(applicationId, commands)
.doOnNext(cmd -> Bukkit.getLogger().info("Successfully registered Global Command "
+ cmd.name()))
.doOnError(e -> Bukkit.getLogger().severe("Failed to register global commands.\n"
+ e.getMessage()))
.subscribe();
}
private @NotNull List<String> getCommandsJson(List<String> fileNames) throws IOException
{
// Confirm that the commands folder exists
String commandsFolderName = "commands/";
URL url = this.getClass().getClassLoader().getResource(commandsFolderName);
Objects.requireNonNull(url, commandsFolderName + " could not be found");
//Get all the files inside this folder and return the contents of the files as a list of strings
List<String> list = new ArrayList<>();
for (String file : fileNames)
{
String resourceFileAsString = getResourceFileAsString(commandsFolderName + file);
list.add(Objects.requireNonNull(resourceFileAsString, "Command file not found: " + file));
}
return list;
}
private @Nullable String getResourceFileAsString(String fileName) throws IOException
{
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
try (InputStream resourceAsStream = classLoader.getResourceAsStream(fileName))
{
if (resourceAsStream == null) return null;
try (InputStreamReader inputStreamReader = new InputStreamReader(resourceAsStream);
BufferedReader reader = new BufferedReader(inputStreamReader))
{
return reader.lines().collect(Collectors.joining(System.lineSeparator()));
}
}
}
public void registerCommand(SlashCommand command)
{
commands.add(command);
}
public Mono<Void> handle(ChatInputInteractionEvent event)
{
// Convert our array list to a flux that we can iterate through
return Flux.fromIterable(commands)
//Filter out all commands that don't match the name of the command this event is for
.filter(command -> command.getName().equals(event.getCommandName()))
// Get the first (and only) item in the flux that matches our filter
.next()
//have our command class handle all the logic related to its specific command.
.flatMap(command -> command.handle(event));
}
}

View File

@ -1,10 +0,0 @@
package me.totalfreedom.discord.handling;
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
import reactor.core.publisher.Mono;
public interface SlashCommand {
String getName();
Mono<Void> handle(ChatInputInteractionEvent event);
}

View File

@ -1,125 +0,0 @@
package me.totalfreedom.discord.listener;
import com.google.common.base.Strings;
import discord4j.core.event.domain.message.MessageCreateEvent;
import discord4j.core.object.entity.Attachment;
import discord4j.core.object.entity.Guild;
import discord4j.core.object.entity.Member;
import discord4j.core.object.entity.Message;
import me.totalfreedom.discord.Bot;
import me.totalfreedom.discord.TFD4J;
import me.totalfreedom.discord.util.SnowflakeEntry;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.api.event.AdminChatEvent;
import me.totalfreedom.totalfreedommod.rank.Displayable;
import me.totalfreedom.totalfreedommod.rank.GroupProvider;
import me.totalfreedom.totalfreedommod.rank.Title;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
public class AdminChatListener
{
private static final Key identifier = Key.key("tfd4j", "discord_admin_chat");
//--
private final Bot bot;
private final TFD4J tfd4j;
public AdminChatListener(TFD4J tfd4j)
{
this.tfd4j = tfd4j;
this.bot = tfd4j.getBot();
}
public void adminChatBound()
{
tfd4j.getBot()
.getClient()
.getEventDispatcher()
.on(MessageCreateEvent.class)
.filter(m -> m.getMessage()
.getChannelId()
.equals(SnowflakeEntry.ADMIN_CHAT_CHANNEL_ID.getSnowflake()))
.filter(m -> !m.getMessage()
.getAuthor()
.orElseThrow()
.getId()
.equals(tfd4j.getBot().getClient().getSelfId()))
.doOnError(FLog::severe)
.subscribe(this::createMessageSpec);
}
public void createMessageSpec(MessageCreateEvent m)
{
Member member = m.getMember().orElseThrow(IllegalAccessError::new);
Component name = Component.text(member.getDisplayName());
Message msg = m.getMessage();
TextComponent attachments = Component.empty();
for (Attachment attachment : msg.getAttachments())
{
attachments = attachments.append(
Component.text("[Media] ", NamedTextColor.YELLOW)
.clickEvent(ClickEvent.openUrl(attachment.getUrl()))
.hoverEvent(HoverEvent.showText(Component.text(attachment.getUrl()))));
}
TextComponent message = Component.text(msg.getContent()).append(msg.getAttachments().isEmpty() ?
Component.empty() : Component.space().append(attachments));
TotalFreedomMod.getPlugin().cm.adminChat(identifier, FUtil.miniMessage("<dark_gray>[<dark_aqua>Discord</dark_aqua>] </dark_gray>"), name, getDisplay(member), message, true);
}
public Displayable getDisplay(Member member)
{
Guild server = tfd4j.getBot().getGuildById().block();
// Server Owner
if (server == null) throw new IllegalStateException();
return member.getRoles()
.filter(role -> SnowflakeEntry.acceptableRoleIDs().contains(role.getId()))
.map(role ->
{
if (role.getId().equals(SnowflakeEntry.OWNER_ROLE_ID.getSnowflake()))
{
return Title.OWNER;
} else if (role.getId().equals(SnowflakeEntry.DEVELOPER_ROLE_ID.getSnowflake()))
{
return Title.DEVELOPER;
} else if (role.getId().equals(SnowflakeEntry.EXECUTIVE_ROLE_ID.getSnowflake()))
{
return Title.EXECUTIVE;
} else if (role.getId().equals(SnowflakeEntry.ASSISTANT_EXECUTIVE_ROLE_ID.getSnowflake()))
{
return Title.ASST_EXEC;
} else if (role.getId().equals(SnowflakeEntry.SENIOR_ADMIN_ROLE_ID.getSnowflake()))
{
return GroupProvider.SENIOR_ADMIN.getGroup();
} else if (role.getId().equals(SnowflakeEntry.ADMIN_ROLE_ID.getSnowflake()))
{
return GroupProvider.ADMIN.getGroup();
} else if (role.getId().equals(SnowflakeEntry.MASTERBUILDER_ROLE_ID.getSnowflake()))
{
return GroupProvider.MASTER_BUILDER.getGroup();
} else
{
return GroupProvider.OP.getGroup(); // This should never be reached.
}
}).blockFirst();
}
public static Key getIdentifier()
{
return identifier;
}
}

View File

@ -1,105 +0,0 @@
package me.totalfreedom.discord.listener;
import io.papermc.paper.event.player.AsyncChatEvent;
import me.totalfreedom.discord.Bot;
import me.totalfreedom.discord.TFD4J;
import me.totalfreedom.discord.util.Utilities;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.api.event.AdminChatEvent;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.GameRule;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
public class BukkitNative implements Listener
{
//--
private final TotalFreedomMod commons;
private final Bot bot;
private final TFD4J tfd4j;
public BukkitNative(TFD4J tfd4j)
{
this.tfd4j = tfd4j;
this.bot = tfd4j.getBot();
this.commons = bot.getTFM().getCommons();
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerJoin(PlayerJoinEvent event)
{
if (!commons.al.isVanished(event.getPlayer().getUniqueId()))
{
tfd4j.getImpl().messageChatChannel("**"
+ Utilities.deformat(event.getPlayer().getName())
+ " joined the server" + "**", true);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerLeave(PlayerQuitEvent event)
{
if (!commons.al.isVanished(event.getPlayer().getUniqueId()))
{
tfd4j.getImpl().messageChatChannel("**"
+ Utilities.deformat(event.getPlayer().getName())
+ " left the server" + "**", true);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerDeath(PlayerDeathEvent event)
{
//Avoiding NPE Unboxing Warnings
Boolean b = event.getEntity().getWorld().getGameRuleValue(GameRule.SHOW_DEATH_MESSAGES);
if (b == null || !b)
{
return;
}
Component deathMessage = event.deathMessage();
if (deathMessage != null)
{
tfd4j.getImpl().messageChatChannel("**"
+ Utilities.deformat(PlainTextComponentSerializer.plainText().serialize(deathMessage))
+ "**", true);
}
}
@EventHandler(ignoreCancelled = true)
public void onAsyncPlayerChat(AsyncChatEvent event)
{
Player player = event.getPlayer();
String message = FUtil.steamroll(event.message());
if (!ConfigEntry.ADMIN_ONLY_MODE.getBoolean() && !tfd4j.getServer().hasWhitelist()
&& !commons.pl.getPlayer(player).isMuted() && !commons.pl.getPlayer(player).inAdminChat() && bot != null)
{
tfd4j.getImpl().messageChatChannel(player.getName()
+ " \u00BB "
+ message, true);
}
}
@EventHandler
public void onAdminChat(AdminChatEvent event)
{
if (!event.getIdentifier().equals(AdminChatListener.getIdentifier()))
{
tfd4j.getImpl().messageAdminChatChannel(FUtil.steamroll(event.getName()) + " » " + FUtil.steamroll(event.getMessage()));
}
}
}

View File

@ -1,98 +0,0 @@
package me.totalfreedom.discord.listener;
import discord4j.core.event.domain.message.MessageCreateEvent;
import discord4j.core.object.entity.Attachment;
import discord4j.core.object.entity.Member;
import discord4j.core.object.entity.Message;
import discord4j.core.object.entity.channel.TextChannel;
import me.totalfreedom.discord.Bot;
import me.totalfreedom.discord.TFD4J;
import me.totalfreedom.discord.util.SnowflakeEntry;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Bukkit;
public class MinecraftListener
{
private final TotalFreedomMod commons;
private final Bot bot;
private final TFD4J tfd4j;
public MinecraftListener(TFD4J tfd4j)
{
this.tfd4j = tfd4j;
this.bot = tfd4j.getBot();
this.commons = bot.getTFM().getCommons();
}
public void minecraftChatBound()
{
tfd4j.getBot().getClient()
.getEventDispatcher()
.on(MessageCreateEvent.class)
.filter(m -> m.getMessage()
.getChannelId()
.equals(SnowflakeEntry.CHAT_CHANNEL_ID.getSnowflake()))
.filter(m -> m.getMember().orElse(null) != null)
.filter(m -> !m.getMessage()
.getAuthor()
.orElseThrow(IllegalAccessError::new)
.getId()
.equals(tfd4j.getBot().getClient().getSelfId()))
.doOnError(FLog::severe)
.subscribe(this::doMessageBodyDetails);
}
private void doMessageBodyDetails(MessageCreateEvent m)
{
Member member = m.getMember().orElseThrow();
Message msg = m.getMessage();
String tag = bot.getTFM().getDisplay(member);
TextComponent.Builder builder = Component.text();
TextComponent prefix = Component.text("[", NamedTextColor.DARK_GRAY)
.append(Component.text("Discord", NamedTextColor.DARK_AQUA)
.hoverEvent(HoverEvent.showText(Component.text("Click to join our Discord server!")))
.clickEvent(ClickEvent.openUrl(ConfigEntry.DISCORD_INVITE_LINK.getString())))
.append(Component.text("] ", NamedTextColor.DARK_GRAY));
TextComponent user = Component.empty();
// Tag (if they have one)
if (tag != null && !tag.isEmpty())
{
user = LegacyComponentSerializer.legacyAmpersand().deserialize(tag).append(Component.space());
}
user = user.append(Component.text(FUtil.stripColors(member.getDisplayName()).trim(), NamedTextColor.RED));
TextComponent message = Component.text(": ", NamedTextColor.DARK_GRAY)
.append(Component.text(FUtil.stripColors(msg.getContent()), NamedTextColor.WHITE));
// Attachments
if (!msg.getAttachments().isEmpty())
{
if (!msg.getContent().isEmpty())
{
message = message.append(Component.space());
}
for (Attachment attachment : msg.getAttachments())
{
message = message.append(Component.text("[Media] ", NamedTextColor.YELLOW)
.hoverEvent(HoverEvent.showText(Component.text(attachment.getUrl())))
.clickEvent(ClickEvent.openUrl(attachment.getUrl())));
}
}
Bukkit.broadcast(builder.append(prefix, user, message).build());
}
}

View File

@ -1,56 +0,0 @@
package me.totalfreedom.discord.listener;
import discord4j.core.event.domain.message.MessageCreateEvent;
import me.totalfreedom.discord.TFD4J;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.player.PlayerData;
public class PrivateMessageListener
{
private final TFD4J tfd4j;
public PrivateMessageListener(TFD4J tfd4j)
{
this.tfd4j = tfd4j;
}
public void privateMessageReceived()
{
tfd4j.getBot()
.getClient()
.getEventDispatcher()
.on(MessageCreateEvent.class)
.filter(event -> event.getMessage().getAuthor().orElse(null) != null)
.filter(event -> !event.getMessage().getAuthor().orElseThrow().getId().equals(tfd4j.getBot().getClient().getSelfId()))
.filter(event -> event.getMessage().getContent().strip().matches("\\d{5}"))
.subscribe(event ->
{
String code = event.getMessage().getContent().strip();
String name;
if (tfd4j.getBot().getLinkCodes().get(code) != null)
{
PlayerData player = tfd4j.getBot().getLinkCodes().get(code);
name = player.getName();
player.setDiscordID(event.getMessage().getAuthor().orElseThrow().getId().asString());
Admin admin = TotalFreedomMod.getPlugin().al.getEntryByUuid(player.getUuid());
if (admin != null)
{
tfd4j.getImpl().syncRoles(admin, player.getDiscordID());
}
TotalFreedomMod.getPlugin().pl.save(player);
tfd4j.getBot().getLinkCodes().remove(code);
} else
{
return;
}
event.getMessage()
.getChannel()
.blockOptional()
.orElseThrow(UnsupportedOperationException::new)
.createMessage("Link successful. Now this Discord account is linked with your Minecraft account **" + name + "**.").block();
});
}
}

View File

@ -1,76 +0,0 @@
package me.totalfreedom.discord.listener;
import discord4j.core.event.domain.message.ReactionAddEvent;
import discord4j.core.object.Embed;
import discord4j.core.object.entity.Member;
import discord4j.core.object.entity.Message;
import discord4j.core.object.entity.channel.TextChannel;
import discord4j.discordjson.json.MessageCreateRequest;
import me.totalfreedom.discord.TFD4J;
import me.totalfreedom.discord.util.SnowflakeEntry;
import me.totalfreedom.totalfreedommod.util.FLog;
public class ReactionListener
{
private final TFD4J tfd4j;
public ReactionListener(TFD4J tfd4J)
{
this.tfd4j = tfd4J;
}
public void onReactionAdd()
{
tfd4j.getBot()
.getClient()
.getEventDispatcher()
.on(ReactionAddEvent.class)
.filter(r -> r.getGuild().block() != null)
.filter(r -> r.getMember().orElse(null) != null)
.filter(r -> !r.getMember()
.orElseThrow()
.getId()
.equals(tfd4j.getBot().getClient().getSelfId()))
.filter(r -> !r.getChannelId()
.equals(SnowflakeEntry.REPORT_CHANNEL_ID.getSnowflake()))
.filter(r -> r.getEmoji()
.asUnicodeEmoji()
.orElseThrow(UnsupportedOperationException::new)
.getRaw()
.equals("\uD83D\uDCCB"))
.doOnError(FLog::severe)
.subscribe(this::reactionWork);
}
private void reactionWork(ReactionAddEvent event)
{
final TextChannel archiveChannel = tfd4j.getBot()
.getClient()
.getChannelById(SnowflakeEntry.ARCHIVE_REPORT_CHANNEL_ID.getSnowflake())
.ofType(TextChannel.class)
.blockOptional()
.orElseThrow();
final Message message = event.getMessage().blockOptional().orElseThrow();
final Member completer = event.getMember().orElseThrow();
if (!message.getAuthor().orElseThrow().getId().equals(tfd4j.getBot().getClient().getSelfId()))
{
return;
}
// We don't need other embeds... yet?
final Embed embed = message.getEmbeds().get(0);
final MessageCreateRequest request = MessageCreateRequest.builder()
.content("Report completed by " + completer.getUsername()
+ " (" + completer.getDiscriminator()
+ ")")
.addEmbed(embed.getData())
.build();
archiveChannel.getRestChannel().createMessage(request);
message.delete().block();
}
}

View File

@ -1,35 +0,0 @@
package me.totalfreedom.discord.react;
import org.bukkit.scheduler.BukkitTask;
import reactor.core.Disposable;
/**
* This class is a wrapper for a BukkitTask that implements the Disposable interface.
* This is so we can schedule non-blocking tasks asynchronously on the Bukkit Scheduler.
* <p>
* From <a href="https://github.com/SimplexDevelopment/SimplexSS">SimplexSS</a>
*
* @param task The task to wrap.
*/
public record DisposableBukkitTask(BukkitTask task) implements Disposable
{
/**
* Disposes of the task upstream on the Bukkit scheduler.
*/
@Override
public void dispose()
{
task.cancel();
}
/**
* Checks if the task is cancelled.
*
* @return true if the task is cancelled, false otherwise.
*/
@Override
public boolean isDisposed()
{
return task.isCancelled();
}
}

View File

@ -1,96 +0,0 @@
package me.totalfreedom.discord.react;
import java.util.concurrent.TimeUnit;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import reactor.core.Disposable;
import reactor.core.scheduler.Scheduler;
/**
* An abstraction layer over the {@link BukkitScheduler} to allow for the use as a {@link Scheduler}.
* This will allow us to perform non-blocking operations on the main server thread.
*
* @author SimplexDevelopment
*/
public final class ReactiveBukkitScheduler
implements Scheduler, Scheduler.Worker {
/**
* The plugin instance.
*/
private final JavaPlugin plugin;
/**
* The bukkit scheduler.
*/
private final BukkitScheduler scheduler;
public ReactiveBukkitScheduler(JavaPlugin plugin) {
this.plugin = plugin;
this.scheduler = plugin.getServer().getScheduler();
}
/**
* Delegates to the {@link BukkitScheduler}.
*
* @param task The task to delegate.
* @return A disposable that can be used to cancel the task.
*/
@Override
public @NotNull Disposable schedule(@NotNull Runnable task) {
return new DisposableBukkitTask(scheduler.runTask(plugin, task));
}
/**
* Delegates to the {@link BukkitScheduler} with a delay.
*
* @param task The task to delegate
* @param delay The amount of time to wait before running the task
* @param unit Unused parameter in this implementation.
* Regardless of what value you use, this parameter will never be called.
* @return A disposable that can be used to cancel the task.
*/
@Override
public @NotNull Disposable schedule(@NotNull Runnable task, long delay, @Deprecated @Nullable TimeUnit unit) {
return new DisposableBukkitTask(scheduler.runTaskLater(plugin, task, delay));
}
/**
* Delegates to the {@link BukkitScheduler} with a delay and a period.
* The initial delay may be 0L, but the period must be greater than 0L.
*
* @param task The task to delegate.
* @param initialDelay The amount of time to wait before running the task.
* @param period The amount of time to wait between each execution of the task.
* @param unit Unused parameter in this implementation.
* Regardless of what value you use, this parameter will never be called.
* @return A disposable that can be used to cancel the task.
*/
@Override
public @NotNull Disposable schedulePeriodically(@NotNull Runnable task, long initialDelay, long period, @Deprecated @Nullable TimeUnit unit) {
if (period <= 0L) {
throw new IllegalArgumentException("Period must be greater than 0L");
}
return new DisposableBukkitTask(scheduler.runTaskTimer(plugin, task, initialDelay, period));
}
/**
* A new {@link Worker}.
*
* @return This class instance, as it implements {@link Worker}.
*/
@Override
public @NotNull Scheduler.Worker createWorker() {
return this;
}
/**
* This method does nothing and is unused.
*/
@Override
@Deprecated
public void dispose() {
// This method does nothing and is only here because it's being overridden from a parent.
}
}

View File

@ -1,51 +0,0 @@
package me.totalfreedom.discord.util;
import discord4j.common.util.Snowflake;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import java.util.HashSet;
import java.util.Set;
public enum SnowflakeEntry
{
ADMIN_CHAT_CHANNEL_ID(ConfigEntry.DISCORD_ADMINCHAT_CHANNEL_ID),
CHAT_CHANNEL_ID(ConfigEntry.DISCORD_CHAT_CHANNEL_ID),
REPORT_CHANNEL_ID(ConfigEntry.DISCORD_REPORT_CHANNEL_ID),
ARCHIVE_REPORT_CHANNEL_ID(ConfigEntry.DISCORD_REPORT_ARCHIVE_CHANNEL_ID),
//--
SERVER_ID(ConfigEntry.DISCORD_SERVER_ID),
//--
OWNER_ROLE_ID(ConfigEntry.DISCORD_SERVER_OWNER_ROLE_ID),
DEVELOPER_ROLE_ID(ConfigEntry.DISCORD_DEVELOPER_ROLE_ID),
EXECUTIVE_ROLE_ID(ConfigEntry.DISCORD_EXECUTIVE_ROLE_ID),
ASSISTANT_EXECUTIVE_ROLE_ID(ConfigEntry.DISCORD_ASSISTANT_EXECUTIVE_ROLE_ID),
SENIOR_ADMIN_ROLE_ID(ConfigEntry.DISCORD_SENIOR_ADMIN_ROLE_ID),
ADMIN_ROLE_ID(ConfigEntry.DISCORD_NEW_ADMIN_ROLE_ID),
MASTERBUILDER_ROLE_ID(ConfigEntry.DISCORD_MASTER_BUILDER_ROLE_ID);
private ConfigEntry entry;
SnowflakeEntry(ConfigEntry entry)
{
this.entry = entry;
}
public Snowflake getSnowflake()
{
return Snowflake.of(entry.getString());
}
public static Set<Snowflake> acceptableRoleIDs()
{
Set<Snowflake> acceptableRoleIDs = new HashSet<>();
acceptableRoleIDs.add(SnowflakeEntry.OWNER_ROLE_ID.getSnowflake());
acceptableRoleIDs.add(SnowflakeEntry.DEVELOPER_ROLE_ID.getSnowflake());
acceptableRoleIDs.add(SnowflakeEntry.EXECUTIVE_ROLE_ID.getSnowflake());
acceptableRoleIDs.add(SnowflakeEntry.ASSISTANT_EXECUTIVE_ROLE_ID.getSnowflake());
acceptableRoleIDs.add(SnowflakeEntry.SENIOR_ADMIN_ROLE_ID.getSnowflake());
acceptableRoleIDs.add(SnowflakeEntry.ADMIN_ROLE_ID.getSnowflake());
acceptableRoleIDs.add(SnowflakeEntry.MASTERBUILDER_ROLE_ID.getSnowflake());
return acceptableRoleIDs;
}
}

View File

@ -1,64 +0,0 @@
package me.totalfreedom.discord.util;
import discord4j.core.object.entity.Guild;
import discord4j.core.object.entity.Member;
import me.totalfreedom.discord.Bot;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.rank.GroupProvider;
import me.totalfreedom.totalfreedommod.rank.Title;
import me.totalfreedom.totalfreedommod.util.FUtil;
import org.bukkit.Bukkit;
public class TFM_Bridge
{
private final Bot bot;
private final TotalFreedomMod commons;
public TFM_Bridge(Bot bot)
{
this.bot = bot;
this.commons = (TotalFreedomMod) Bukkit.getPluginManager().getPlugin("TotalFreedomMod");
if (commons == null) throw new IllegalStateException();
}
public String getDisplay(Member member)
{
Guild server = bot.getGuildById().block();
// Server Owner
assert server != null;
return member.getRoles().map(role ->
{
if (role.getId().equals(SnowflakeEntry.OWNER_ROLE_ID.getSnowflake()))
{
return FUtil.miniMessage(Title.OWNER.getColoredTag());
} else if (role.getId().equals(SnowflakeEntry.DEVELOPER_ROLE_ID.getSnowflake()))
{
return FUtil.miniMessage(Title.DEVELOPER.getColoredTag());
} else if (role.getId().equals(SnowflakeEntry.EXECUTIVE_ROLE_ID.getSnowflake()))
{
return FUtil.miniMessage(Title.EXECUTIVE.getColoredTag());
} else if (role.getId().equals(SnowflakeEntry.ASSISTANT_EXECUTIVE_ROLE_ID.getSnowflake()))
{
return FUtil.miniMessage(Title.ASST_EXEC.getColoredTag());
} else if (role.getId().equals(SnowflakeEntry.SENIOR_ADMIN_ROLE_ID.getSnowflake()))
{
return FUtil.miniMessage(GroupProvider.SENIOR_ADMIN.getGroup().getColoredTag());
} else if (role.getId().equals(SnowflakeEntry.ADMIN_ROLE_ID.getSnowflake()))
{
return FUtil.miniMessage(GroupProvider.ADMIN.getGroup().getColoredTag());
} else if (role.getId().equals(SnowflakeEntry.MASTERBUILDER_ROLE_ID.getSnowflake()))
{
return FUtil.miniMessage(GroupProvider.MASTER_BUILDER.getGroup().getColoredTag());
} else
{
return "";
}
}).blockFirst();
}
public TotalFreedomMod getCommons()
{
return commons;
}
}

View File

@ -1,14 +0,0 @@
package me.totalfreedom.discord.util;
public class Utilities
{
private Utilities() {
throw new AssertionError();
}
// Leaving this here so I don't need to do more work than necessary.
public static String deformat(String input)
{
return input.replaceAll("([_\\\\`*>|])", "\\\\$1");
}
}

View File

@ -1,4 +0,0 @@
{
"name": "help",
"description": "Bot help command."
}

View File

@ -1,4 +0,0 @@
{
"name": "list",
"description": "List all currently online players"
}

View File

@ -1,4 +0,0 @@
{
"name": "tps",
"description": "Gets the current TPS for the server."
}

View File

@ -1,8 +0,0 @@
name: TFD4J
main: me.totalfreedom.discord.TFD4J
version: 2023.03
api-version: 1.19
depend: [TotalFreedomMod]
libraries:
- com.discord4j:discord4j-core:3.2.0
- io.projectreactor:reactor-core:3.4.9

261
pom.xml
View File

@ -5,18 +5,12 @@
<groupId>me.totalfreedom</groupId>
<artifactId>TotalFreedomMod</artifactId>
<version>2023.03</version>
<packaging>pom</packaging>
<modules>
<module>commons</module>
<module>shop</module>
<module>discord</module>
</modules>
<version>2022.06.1</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<tfm.build.codename>Caladrius</tfm.build.codename>
<tfm.build.codename>Phoenix</tfm.build.codename>
<jar.finalName>${project.name}</jar.finalName>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>MM/dd/yyyy HH:mm</maven.build.timestamp.format>
@ -101,10 +95,31 @@
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.13.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.totalfreedom.scissors</groupId>
<artifactId>Scissors-API</artifactId>
<version>1.19.3-R0.1-SNAPSHOT</version>
<version>1.19.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
@ -125,24 +140,38 @@
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.2.12</version>
<version>7.2.15</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>4.4.1_353</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.coreprotect</groupId>
<artifactId>coreprotect</artifactId>
<version>21.2</version>
<version>21.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sk89q.worldguard</groupId>
<artifactId>worldguard-bukkit</artifactId>
<version>7.0.7</version>
<version>7.0.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId>
<version>1.0.8</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.vexsoftware</groupId>
<artifactId>votifier</artifactId>
@ -153,37 +182,50 @@
<dependency>
<groupId>net.essentialsx</groupId>
<artifactId>EssentialsX</artifactId>
<version>2.19.6</version>
<version>2.20.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.29.1-GA</version>
<scope>provided</scope>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>23.0.0</version>
<scope>provided</scope>
<version>24.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.2</version>
<version>3.3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.0</version>
<version>5.10.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.inject</artifactId>
<version>0.3.5</version>
</dependency>
</dependencies>
<pluginRepositories>
@ -193,6 +235,185 @@
</pluginRepository>
</pluginRepositories>
<build>
<!-- Filter resources for build.properties -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<!-- Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<outputFileName>TotalFreedomMod.jar</outputFileName>
<compilerVersion>17</compilerVersion>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<!-- Git describe -->
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>4.9.10</version>
<executions>
<execution>
<id>get-the-git-infos</id>
<goals>
<goal>revision</goal>
</goals>
</execution>
<execution>
<id>validate-the-git-infos</id>
<goals>
<goal>validateRevision</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
<prefix>git</prefix>
<dateFormat>yyyy-MM-dd HH:mm:ss</dateFormat>
<verbose>false</verbose>
<format>properties</format>
<failOnNoGitDirectory>false</failOnNoGitDirectory>
<failOnUnableToExtractRepoInfo>false</failOnUnableToExtractRepoInfo>
<includeOnlyProperties>
<includeOnlyProperty>git.commit.id.abbrev</includeOnlyProperty>
</includeOnlyProperties>
<gitDescribe>
<skip>false</skip>
<always>false</always>
<abbrev>7</abbrev>
<dirty>-dirty</dirty>
<match>*</match>
</gitDescribe>
</configuration>
</plugin>
<!-- Antrun -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>default-cli</id>
<phase>initialize</phase>
<configuration>
<target>
<propertyfile file="${project.basedir}/src/main/resources/build.properties"
comment="Build information. Edit this to your liking.">
<entry key="buildAuthor" default="unknown"/>
<entry key="buildNumber" default="0"/>
<entry key="buildCodeName" value="${tfm.build.codename}"/>
<entry key="buildVersion" value="${project.version}"/>
<entry key="buildDate" value="${timestamp}"/>
<!--suppress UnresolvedMavenProperty -->
<entry key="buildHead" value="${git.commit.id.abbrev}"/>
</propertyfile>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Properties -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.1.0</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>${project.basedir}/src/main/resources/build.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
<!-- Buildnumber -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<buildNumberPropertyName>maven.buildnumber</buildNumberPropertyName>
<buildNumberPropertiesFileLocation>${project.basedir}/src/main/resources/build.properties
</buildNumberPropertiesFileLocation>
<format>{0,number,#}</format>
<items>
<item>buildNumber</item>
</items>
</configuration>
</plugin>
<!-- Shade -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<relocations>
<relocation>
<pattern>io.papermc.lib</pattern>
<shadedPattern>me.totalfreedom.totalfreedommod.paperlib
</shadedPattern> <!-- Replace this -->
</relocation>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>me.totalfreedom.totalfreedommod</shadedPattern>
</relocation>
</relocations>
<artifactSet>
<includes>
<include>org.reflections:reflections</include>
<include>io.papermc:paperlib</include>
<include>org.bstats:bstats-bukkit</include>
<include>org.bstats:bstats-base</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<!-- Checkstyle -->
<plugins>

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>me.totalfreedom</groupId>
<artifactId>TotalFreedomMod</artifactId>
<version>2023.03</version>
</parent>
<artifactId>shop</artifactId>
<dependencies>
<dependency>
<groupId>me.totalfreedom</groupId>
<artifactId>commons</artifactId>
<version>2023.03</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@ -1,53 +0,0 @@
package me.totalfreedom.shop;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.api.Context;
import me.totalfreedom.totalfreedommod.api.ShoppeCommons;
import org.bukkit.plugin.java.JavaPlugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TFShoppe extends JavaPlugin
{
private final Logger slf4j = LoggerFactory.getLogger("TF-Shoppe");
private Shop shop;
private Votifier votifier;
public Logger slf4j()
{
return slf4j;
}
@Override
public void onEnable()
{
slf4j().info("Hello from the TF-Shoppe! Attempting to resolve TotalFreedomMod...");
TotalFreedomMod plugin = (TotalFreedomMod) getServer().getPluginManager().getPlugin("TotalFreedomMod");
if (plugin == null)
{
slf4j().error("TotalFreedomMod not found! Disabling...");
getServer().getPluginManager().disablePlugin(this);
return;
}
slf4j().info("TotalFreedomMod found! Registering the shop...");
shop = new Shop();
slf4j().info("Shop registered! Registering the Votifier listener...");
votifier = new Votifier();
slf4j().info("Votifier listener registered! Providing context to TFM...");
Context<ShoppeCommons> context = new Context<>(shop);
plugin.ag.setShoppeContext(context);
plugin.registerShoppe();
slf4j().info("Context provided! TF-Shoppe is now ready to go!");
}
@Override
public void onDisable()
{
slf4j().info("Goodbye from the TF-Shoppe!");
}
}

View File

@ -1,6 +0,0 @@
name: TF-Shoppe
main: me.totalfreedom.shop.TFShoppe
version: ${project.version}
authors: [AtlasMediaGroup, TotalFreedom]
api-version: 1.19
depend: [TotalFreedomMod]

View File

@ -87,8 +87,10 @@ public class AntiSpam extends FreedomService
@EventHandler(priority = EventPriority.LOW)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event)
{
String command = event.getMessage();
final Player player = event.getPlayer();
final FPlayer fPlayer = plugin.pl.getPlayer(player);
fPlayer.setLastCommand(command);
if (fPlayer.allCommandsBlocked())
{

View File

@ -2,6 +2,7 @@ package me.totalfreedom.totalfreedommod;
import me.totalfreedom.totalfreedommod.banning.IndefiniteBanList;
import me.totalfreedom.totalfreedommod.config.YamlConfig;
import me.totalfreedom.totalfreedommod.permissions.PermissionConfig;
import me.totalfreedom.totalfreedommod.punishments.PunishmentList;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
@ -31,6 +32,7 @@ public class BackupManager extends FreedomService
{
createBackups(TotalFreedomMod.CONFIG_FILENAME, true);
createBackups(IndefiniteBanList.CONFIG_FILENAME);
createBackups(PermissionConfig.PERMISSIONS_FILENAME, true);
createBackups(PunishmentList.CONFIG_FILENAME);
createBackups("database.db");
}

View File

@ -0,0 +1,189 @@
package me.totalfreedom.totalfreedommod;
import com.google.common.base.Strings;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.player.FPlayer;
import me.totalfreedom.totalfreedommod.rank.Displayable;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FSync;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import static me.totalfreedom.totalfreedommod.util.FUtil.playerMsg;
public class ChatManager extends FreedomService
{
@Override
public void onStart()
{
}
@Override
public void onStop()
{
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onPlayerChatFormat(AsyncPlayerChatEvent event)
{
try
{
handleChatEvent(event);
}
catch (Exception ex)
{
FLog.severe(ex);
}
}
private void handleChatEvent(AsyncPlayerChatEvent event)
{
final Player player = event.getPlayer();
String originalMessage = event.getMessage();
if (plugin.mu.onPlayerChat(player) || plugin.sh.handlePlayerChat(player, originalMessage))
{
event.setCancelled(true);
return;
}
String message = originalMessage.trim();
// Format colors and strip &k
message = FUtil.colorize(message);
message = message.replaceAll(ChatColor.MAGIC.toString(), "&k");
if (!ConfigEntry.TOGGLE_CHAT.getBoolean() && !plugin.al.isAdmin(player))
{
event.setCancelled(true);
playerMsg(player, "Chat is currently disabled.", org.bukkit.ChatColor.RED);
return;
}
// Truncate messages that are too long - 256 characters is vanilla client max
if (message.length() > 256)
{
message = message.substring(0, 256);
FSync.playerMsg(player, "Message was shortened because it was too long to send.");
}
final FPlayer fPlayer = plugin.pl.getPlayerSync(player);
if (fPlayer.isLockedUp())
{
FSync.playerMsg(player, "You're locked up and cannot talk.");
event.setCancelled(true);
return;
}
// Check for adminchat
if (fPlayer.inAdminChat())
{
FSync.adminChatMessage(player, message);
event.setCancelled(true);
return;
}
plugin.dc.onPlayerChat(player, ChatColor.stripColor(message));
// Check for 4chan trigger
if (ConfigEntry.FOURCHAN_ENABLED.getBoolean())
{
boolean green = ChatColor.stripColor(message).toLowerCase().startsWith(">");
boolean orange = ChatColor.stripColor(message).toLowerCase().endsWith("<");
if (green)
{
message = ChatColor.GREEN + message;
}
else if (orange)
{
message = ChatColor.GOLD + message;
}
}
// Finally, set message
event.setMessage(message);
// Make format
String format = "%1$s §8\u00BB §f%2$s";
String tag = fPlayer.getTag();
if (tag != null && !tag.isEmpty())
{
format = tag.replace("%", "%%") + " " + format;
}
// Check for mentions
String stripped = ChatColor.stripColor(message).toLowerCase();
/* There is an issue would have allowed muted players to ping players. The issue is caused by the order in which
* these event handlers are registered when the plugin starts up. Muter is registered after the ChatManager,
* which results in latter being called first (before the former can cancel it). EventPriority does not seem to
* make a difference. As a short-term solution I've added this mute check alongside the usual isCancelled check
* so that the issue is mitigated, but a long-term solution should be to change the order in which things like
* ChatManager and Muter are registered. */
if (!event.isCancelled() && !plugin.pl.getPlayer(player).isMuted())
{
server.getOnlinePlayers().forEach(pl ->
{
if (stripped.contains("@" + pl.getName()) || (plugin.al.isAdmin(player) && stripped.contains("@everyone")))
{
pl.playSound(pl.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, SoundCategory.MASTER, 1337F, 0.9F);
}
});
}
// Set format
event.setFormat(format);
}
public ChatColor getColor(Displayable display)
{
return display.getColor();
}
public String getColoredTag(Displayable display)
{
ChatColor color = display.getColor();
return color + display.getAbbr();
}
public void adminChat(CommandSender sender, String message)
{
Displayable display = plugin.rm.getDisplay(sender);
FLog.info("[ADMIN] " + sender.getName() + " " + display.getTag() + ": " + message, true);
plugin.dc.messageAdminChatChannel(sender.getName() + " \u00BB " + message);
server.getOnlinePlayers().stream().filter(player -> plugin.al.isAdmin(player)).forEach(player ->
{
Admin admin = plugin.al.getAdmin(player);
if (!Strings.isNullOrEmpty(admin.getAcFormat()))
{
String format = admin.getAcFormat();
ChatColor color = getColor(display);
String msg = format.replace("%name%", sender.getName()).replace("%rank%", display.getAbbr()).replace("%rankcolor%", color.toString()).replace("%msg%", message);
player.sendMessage(FUtil.colorize(msg));
}
else
{
player.sendMessage("[" + ChatColor.AQUA + "ADMIN" + ChatColor.WHITE + "] " + ChatColor.DARK_RED + sender.getName() + ChatColor.DARK_GRAY + " [" + getColoredTag(display) + ChatColor.DARK_GRAY + "]" + ChatColor.WHITE + ": " + ChatColor.GOLD + FUtil.colorize(message));
}
});
}
public void reportAction(Player reporter, String reportedName, String report)
{
for (Player player : server.getOnlinePlayers())
{
if (plugin.al.isAdmin(player))
{
playerMsg(player, ChatColor.RED + "[REPORTS] " + ChatColor.GOLD + reporter.getName() + " has reported " + reportedName + " for " + report);
}
}
FLog.info("[REPORTS] " + reporter.getName() + " has reported " + reportedName + " for " + report);
}
}

View File

@ -23,7 +23,7 @@ public class CommandSpy extends FreedomService
{
server.getOnlinePlayers().stream().filter(player -> plugin.al.isAdmin(player)
&& plugin.al.getAdmin(player).getCommandSpy() && player != event.getPlayer()).forEach(player ->
player.sendMessage(Component.text(event.getPlayer().getName()).append(Component.text(": "))
.append(Component.text(event.getMessage())).color(NamedTextColor.GRAY)));
player.sendMessage(Component.text(event.getPlayer().getName(), NamedTextColor.GRAY).append(Component.text(": ", NamedTextColor.GRAY))
.append(Component.text(event.getMessage(), NamedTextColor.GRAY))));
}
}

View File

@ -11,7 +11,7 @@ public abstract class FreedomService implements Listener
protected final Server server;
protected final Logger logger;
protected FreedomService()
public FreedomService()
{
plugin = TotalFreedomMod.getPlugin();
server = plugin.getServer();

View File

@ -17,7 +17,7 @@ import java.util.Random;
import java.util.function.Consumer;
import me.totalfreedom.totalfreedommod.admin.Admin;
import me.totalfreedom.totalfreedommod.banning.Ban;
import me.totalfreedom.totalfreedommod.command.handling.FreedomCommand;
import me.totalfreedom.totalfreedommod.command.FreedomCommand;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.fun.Jumppads;
import me.totalfreedom.totalfreedommod.player.FPlayer;
@ -614,7 +614,7 @@ public class FrontDoor extends FreedomService
{
for (Player player : Bukkit.getOnlinePlayers())
{
plugin.pl.getPlayer(player).setTag(FUtil.miniMessage("[" + ChatColor.BLUE + "Total" + ChatColor.GOLD + "Freedom" + ChatColor.WHITE + "]"));
plugin.pl.getPlayer(player).setTag("[" + ChatColor.BLUE + "Total" + ChatColor.GOLD + "Freedom" + ChatColor.WHITE + "]");
}
break;
}

Some files were not shown because too many files have changed in this diff Show More