Merge branch '2.x' into feature/socialspy

This commit is contained in:
Josh Roy 2024-02-26 15:25:52 -05:00 committed by GitHub
commit 4109d17741
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
48 changed files with 384 additions and 150 deletions

View File

@ -16,26 +16,32 @@ jobs:
steps:
- name: Checkout Git repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
uses: gradle/gradle-build-action@v3
- name: Build with Gradle
run: |
chmod +x gradlew
./gradlew build --stacktrace
- name: Publish JUnit report
uses: mikepenz/action-junit-report@v4
if: success() || failure() # Run even if the previous step fails
with:
report_paths: '**/build/test-results/test*/TEST-*.xml'
- name: Archive plugin jars on GitHub
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: EssentialsX plugin jars
path: jars/
@ -61,7 +67,7 @@ jobs:
cp -r EssentialsXMPP/build/docs/javadoc/ javadocs/EssentialsXMPP/
- name: Archive Javadocs
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: javadocs
path: javadocs/
@ -74,12 +80,12 @@ jobs:
steps:
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
- name: Download Javadocs
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: javadocs
path: javadocs/

View File

@ -18,26 +18,32 @@ jobs:
steps:
- name: Checkout Git repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
uses: gradle/gradle-build-action@v3
- name: Build with Gradle
run: |
chmod +x gradlew
./gradlew build --stacktrace
- name: Publish JUnit report
uses: mikepenz/action-junit-report@v4
if: success() || failure() # Run even if the previous step fails
with:
report_paths: '**/build/test-results/test*/TEST-*.xml'
- name: Archive plugin jars on GitHub
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: EssentialsX plugin jars
path: jars/

View File

@ -59,7 +59,9 @@ import net.ess3.nms.refl.providers.ReflServerStateProvider;
import net.ess3.nms.refl.providers.ReflSpawnEggProvider;
import net.ess3.nms.refl.providers.ReflSpawnerBlockProvider;
import net.ess3.nms.refl.providers.ReflSyncCommandsProvider;
import net.ess3.provider.BiomeKeyProvider;
import net.ess3.provider.ContainerProvider;
import net.ess3.provider.DamageEventProvider;
import net.ess3.provider.FormattedCommandAliasProvider;
import net.ess3.provider.ItemUnbreakableProvider;
import net.ess3.provider.KnownCommandsProvider;
@ -83,15 +85,18 @@ import net.ess3.provider.providers.BukkitMaterialTagProvider;
import net.ess3.provider.providers.BukkitSpawnerBlockProvider;
import net.ess3.provider.providers.FixedHeightWorldInfoProvider;
import net.ess3.provider.providers.FlatSpawnEggProvider;
import net.ess3.provider.providers.LegacyDamageEventProvider;
import net.ess3.provider.providers.LegacyItemUnbreakableProvider;
import net.ess3.provider.providers.LegacyPlayerLocaleProvider;
import net.ess3.provider.providers.LegacyPotionMetaProvider;
import net.ess3.provider.providers.LegacySpawnEggProvider;
import net.ess3.provider.providers.ModernDamageEventProvider;
import net.ess3.provider.providers.ModernDataWorldInfoProvider;
import net.ess3.provider.providers.ModernItemUnbreakableProvider;
import net.ess3.provider.providers.ModernPersistentDataProvider;
import net.ess3.provider.providers.ModernPlayerLocaleProvider;
import net.ess3.provider.providers.ModernSignDataProvider;
import net.ess3.provider.providers.PaperBiomeKeyProvider;
import net.ess3.provider.providers.PaperContainerProvider;
import net.ess3.provider.providers.PaperKnownCommandsProvider;
import net.ess3.provider.providers.PaperMaterialTagProvider;
@ -193,6 +198,8 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private transient WorldInfoProvider worldInfoProvider;
private transient PlayerLocaleProvider playerLocaleProvider;
private transient SignDataProvider signDataProvider;
private transient DamageEventProvider damageEventProvider;
private transient BiomeKeyProvider biomeKeyProvider;
private transient Kits kits;
private transient RandomTeleport randomTeleport;
private transient UpdateChecker updateChecker;
@ -475,6 +482,16 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
playerLocaleProvider = new LegacyPlayerLocaleProvider();
}
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_20_4_R01)) {
damageEventProvider = new ModernDamageEventProvider();
} else {
damageEventProvider = new LegacyDamageEventProvider();
}
if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_19_4_R01)) {
biomeKeyProvider = new PaperBiomeKeyProvider();
}
execTimer.mark("Init(Providers)");
reload();
@ -625,6 +642,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
public void reload() {
Trade.closeLog();
if (bukkitAudience != null) {
bukkitAudience.close();
bukkitAudience = null;
}
for (final IConf iConf : confList) {
iConf.reloadConfig();
execTimer.mark("Reload(" + iConf.getClass().getSimpleName() + ")");
@ -642,6 +664,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
final PluginManager pm = getServer().getPluginManager();
registerListeners(pm);
AdventureUtil.setEss(this);
bukkitAudience = BukkitAudiences.create(this);
}
@ -863,7 +886,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
sender.sendMessage(command.getUsage().replace("<command>", commandLabel));
}
if (!ex.getMessage().isEmpty()) {
sender.sendMessage(ex.getMessage());
sender.sendComponent(AdventureUtil.miniMessage().deserialize(ex.getMessage()));
}
if (ex.getCause() != null && settings.isDebug()) {
ex.getCause().printStackTrace();
@ -1405,6 +1428,16 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return playerLocaleProvider;
}
@Override
public DamageEventProvider getDamageEventProvider() {
return damageEventProvider;
}
@Override
public BiomeKeyProvider getBiomeKeyProvider() {
return biomeKeyProvider;
}
@Override
public SignDataProvider getSignDataProvider() {
return signDataProvider;

View File

@ -640,12 +640,13 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
|| (!pluginCommand.getName().equals("msg") && !pluginCommand.getName().equals("r"))) { // /msg and /r are handled in SimpleMessageRecipient
final User user = ess.getUser(player);
if (!user.isAuthorized("essentials.chat.spy.exempt")) {
final String playerName = ess.getSettings().isSocialSpyDisplayNames() ? player.getDisplayName() : player.getName();
for (final User spyer : ess.getOnlineUsers()) {
if (spyer.isSocialSpyEnabled() && !player.equals(spyer.getBase())) {
final Component base = (user.isMuted() && ess.getSettings().getSocialSpyListenMutedPlayers())
? spyer.tlComponent("socialSpyMutedPrefix")
: spyer.tlComponent("socialSpyPrefix");
spyer.sendComponent(base.append(AdventureUtil.legacyToAdventure(player.getDisplayName())).append(Component.text(": " + event.getMessage())));
spyer.sendComponent(base.append(AdventureUtil.legacyToAdventure(playerName)).append(Component.text(": " + event.getMessage())));
}
}
}

View File

@ -182,8 +182,10 @@ public class I18n implements net.ess3.api.II18n {
}
final Object[] processedArgs = mutateArgs(objects, arg -> {
final String str = arg instanceof AdventureUtil.ParsedPlaceholder ? arg.toString() : AdventureUtil.miniMessage().escapeTags(arg.toString());
return AdventureUtil.legacyToMini(str);
if (arg instanceof AdventureUtil.ParsedPlaceholder) {
return arg.toString();
}
return AdventureUtil.legacyToMini(AdventureUtil.miniMessage().escapeTags(arg.toString()));
});
return messageFormat.format(processedArgs).replace(' ', ' '); // replace nbsp with a space

View File

@ -9,7 +9,9 @@ import com.earth2me.essentials.perm.PermissionsHandler;
import com.earth2me.essentials.updatecheck.UpdateChecker;
import com.earth2me.essentials.userstorage.IUserMap;
import net.ess3.nms.refl.providers.ReflOnlineModeProvider;
import net.ess3.provider.BiomeKeyProvider;
import net.ess3.provider.ContainerProvider;
import net.ess3.provider.DamageEventProvider;
import net.ess3.provider.FormattedCommandAliasProvider;
import net.ess3.provider.ItemUnbreakableProvider;
import net.ess3.provider.KnownCommandsProvider;
@ -183,5 +185,9 @@ public interface IEssentials extends Plugin {
PlayerLocaleProvider getPlayerLocaleProvider();
DamageEventProvider getDamageEventProvider();
BiomeKeyProvider getBiomeKeyProvider();
PluginCommand getPluginCommand(String cmd);
}

View File

@ -73,6 +73,8 @@ public interface ISettings extends IConf {
boolean isSocialSpyMessages();
boolean isSocialSpyDisplayNames();
Set<String> getMuteCommands();
@Deprecated

View File

@ -1,6 +1,7 @@
package com.earth2me.essentials;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
@ -31,4 +32,11 @@ public class PlayerExtension {
public Location getLocation() {
return base.getLocation();
}
public OfflinePlayer getOffline() {
if (base instanceof OfflinePlayerStub) {
return ((OfflinePlayerStub) base).base;
}
return base;
}
}

View File

@ -6,13 +6,12 @@ import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.VersionUtil;
import io.papermc.lib.PaperLib;
import net.ess3.api.InvalidWorldException;
import net.ess3.provider.BiomeKeyProvider;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Biome;
import java.io.File;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
@ -76,14 +75,10 @@ public class RandomTeleport implements IConf {
config.save();
}
public Set<Biome> getExcludedBiomes() {
final List<String> biomeNames = config.getList("excluded-biomes", String.class);
final Set<Biome> excludedBiomes = new HashSet<>();
for (final String biomeName : biomeNames) {
try {
excludedBiomes.add(Biome.valueOf(biomeName.toUpperCase()));
} catch (final IllegalArgumentException ignored) {
}
public Set<String> getExcludedBiomes() {
final Set<String> excludedBiomes = new HashSet<>();
for (final String key : config.getList("excluded-biomes", String.class)) {
excludedBiomes.add(key.toLowerCase());
}
return excludedBiomes;
}
@ -204,7 +199,31 @@ public class RandomTeleport implements IConf {
}
private boolean isValidRandomLocation(final Location location) {
return location.getBlockY() > ess.getWorldInfoProvider().getMinHeight(location.getWorld()) && !this.getExcludedBiomes().contains(location.getBlock().getBiome());
return location.getBlockY() > ess.getWorldInfoProvider().getMinHeight(location.getWorld()) && !isExcludedBiome(location);
}
// Exclude biome if enum or namespaced key matches
private boolean isExcludedBiome(final Location location) {
final Set<String> excluded = getExcludedBiomes();
final String enumKey = location.getBlock().getBiome().name().toLowerCase();
// Try with good old bukkit enum
if (excluded.contains(enumKey)) {
return true;
}
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_14_4_R01)) {
// No way to get the biome key on versions below this
return false;
}
final String biomeKey;
final BiomeKeyProvider biomeKeyProvider = ess.getBiomeKeyProvider();
if (biomeKeyProvider != null) {
// Works with custom biome keys
biomeKey = biomeKeyProvider.getBiomeKey(location.getBlock()).toString();
} else {
// Custom biome keys resolve as "minecraft:custom" which is unfortunate
biomeKey = location.getBlock().getBiome().getKey().toString();
}
return excluded.contains(biomeKey);
}
public File getFile() {

View File

@ -53,6 +53,8 @@ import static com.earth2me.essentials.I18n.tlLiteral;
public class Settings implements net.ess3.api.ISettings {
private static final BigDecimal DEFAULT_MAX_MONEY = new BigDecimal("10000000000000");
private static final BigDecimal DEFAULT_MIN_MONEY = new BigDecimal("-10000000000000");
private static final Tag DEFAULT_PRIMARY_COLOR = Tag.styling(NamedTextColor.GOLD);
private static final Tag DEFAULT_SECONDARY_COLOR = Tag.styling(NamedTextColor.RED);
private final transient EssentialsConfiguration config;
private final transient IEssentials ess;
private final transient AtomicInteger reloadCount = new AtomicInteger(0);
@ -141,8 +143,8 @@ public class Settings implements net.ess3.api.ISettings {
private double maxProjectileSpeed;
private boolean removeEffectsOnHeal;
private Map<String, String> worldAliases;
private Tag primaryColor = Tag.styling(NamedTextColor.GOLD);
private Tag secondaryColor = Tag.styling(NamedTextColor.RED);
private Tag primaryColor = DEFAULT_PRIMARY_COLOR;
private Tag secondaryColor = DEFAULT_SECONDARY_COLOR;
public Settings(final IEssentials ess) {
this.ess = ess;
@ -454,6 +456,11 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("socialspy-messages", true);
}
@Override
public boolean isSocialSpyDisplayNames() {
return config.getBoolean("socialspy-uses-displaynames", true);
}
private Set<String> _getMuteCommands() {
final Set<String> muteCommands = new HashSet<>();
if (config.isList("mute-commands")) {
@ -1970,7 +1977,8 @@ public class Settings implements net.ess3.api.ISettings {
private Tag _getPrimaryColor() {
final String color = config.getString("message-colors.primary", "#ffaa00");
return Tag.styling(_getTagColor(color, NamedTextColor.GOLD));
final TextColor textColor = _getTagColor(color);
return textColor != null ? Tag.styling(textColor) : DEFAULT_PRIMARY_COLOR;
}
@Override
@ -1980,24 +1988,23 @@ public class Settings implements net.ess3.api.ISettings {
private Tag _getSecondaryColor() {
final String color = config.getString("message-colors.secondary", "#ff5555");
return Tag.styling(_getTagColor(color, NamedTextColor.RED));
final TextColor textColor = _getTagColor(color);
return textColor != null ? Tag.styling(textColor) : DEFAULT_SECONDARY_COLOR;
}
private TextColor _getTagColor(final String color, final TextColor def) {
private TextColor _getTagColor(final String color) {
try {
if (color.startsWith("#") && color.length() == 7 && NumberUtil.isNumeric(color.substring(1))) {
if (color.startsWith("#") && color.length() == 7 && NumberUtil.isHexadecimal(color.substring(1))) {
return TextColor.color(Color.fromRGB(Integer.decode(color)).asRGB());
}
if (color.length() == 1) {
final NamedTextColor named = AdventureUtil.fromChar(color.charAt(0));
return named != null ? named : def;
return AdventureUtil.fromChar(color.charAt(0));
}
final NamedTextColor named = NamedTextColor.NAMES.value(color.toLowerCase(Locale.ENGLISH));
return named != null ? named : def;
return NamedTextColor.NAMES.value(color.toLowerCase(Locale.ENGLISH));
} catch (IllegalArgumentException ignored) {
}
return def;
return null;
}
}

View File

@ -16,6 +16,7 @@ import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists;
import net.ess3.api.IEssentials;
import net.ess3.api.MaxMoneyException;
import net.ess3.api.TranslatableException;
import net.ess3.api.events.AfkStatusChangeEvent;
import net.ess3.api.events.JailStatusChangeEvent;
import net.ess3.api.events.MuteStatusChangeEvent;
@ -225,7 +226,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
cooldownTime.add(Calendar.SECOND, (int) cooldown);
cooldownTime.add(Calendar.MILLISECOND, (int) ((cooldown * 1000.0) % 1000.0));
if (cooldownTime.after(now) && !isAuthorized("essentials.heal.cooldown.bypass")) {
throw new Exception(playerTl("timeBeforeHeal", DateUtil.formatDateDiff(cooldownTime.getTimeInMillis())));
throw new TranslatableException("timeBeforeHeal", DateUtil.formatDateDiff(cooldownTime.getTimeInMillis()));
}
}
setLastHealTimestamp(now.getTimeInMillis());

View File

@ -19,13 +19,13 @@ public class Commandbroadcastworld extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length == 0) {
if (args.length < 2) {
throw new NotEnoughArgumentsException();
}
World world = user.getWorld();
String message = getFinalArg(args, 0);
if (args.length > 1 && ess.getSettings().isAllowWorldInBroadcastworld()) {
if (ess.getSettings().isAllowWorldInBroadcastworld()) {
final World argWorld = ess.getWorld(args[0]);
if (argWorld != null) {
world = argWorld;
@ -39,7 +39,7 @@ public class Commandbroadcastworld extends EssentialsCommand {
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (args.length < 2) {
throw new NotEnoughArgumentsException("world");
throw new NotEnoughArgumentsException();
}
final World world = ess.getWorld(args[0]);
@ -53,7 +53,7 @@ public class Commandbroadcastworld extends EssentialsCommand {
if (message.isEmpty()) {
throw new NotEnoughArgumentsException();
}
ess.broadcastTl(null, u -> u.getBase().getWorld().equals(world), true, "broadcast", message, AdventureUtil.parsed(AdventureUtil.legacyToMini(name)));
ess.broadcastTl(null, u -> !u.getBase().getWorld().equals(world), true, "broadcast", message, AdventureUtil.parsed(AdventureUtil.legacyToMini(name)));
}
@Override

View File

@ -29,8 +29,7 @@ public class Commandkill extends EssentialsLoopCommand {
if (sender.isPlayer() && user.isAuthorized("essentials.kill.exempt") && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.kill.force")) {
throw new PlayerExemptException("killExempt", matchPlayer.getDisplayName());
}
final EntityDamageEvent ede = new EntityDamageEvent(matchPlayer, sender.isPlayer() && sender.getPlayer().getName().equals(matchPlayer.getName()) ? EntityDamageEvent.DamageCause.SUICIDE : EntityDamageEvent.DamageCause.CUSTOM, Float.MAX_VALUE);
server.getPluginManager().callEvent(ede);
final EntityDamageEvent ede = ess.getDamageEventProvider().callDamageEvent(matchPlayer, sender.isPlayer() && sender.getPlayer().getName().equals(matchPlayer.getName()) ? EntityDamageEvent.DamageCause.SUICIDE : EntityDamageEvent.DamageCause.CUSTOM, Float.MAX_VALUE);
if (ede.isCancelled() && sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.kill.force")) {
return;
}

View File

@ -17,8 +17,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.earth2me.essentials.I18n.tlLiteral;
public class Commandme extends EssentialsCommand {
public Commandme() {
super("me");
@ -109,7 +107,7 @@ public class Commandme extends EssentialsCommand {
String message = getFinalArg(args, 0);
message = FormatUtil.replaceFormat(message);
ess.getServer().broadcastMessage(tlLiteral("action", "@", message));
ess.broadcastTl("action", "@", message);
}
@Override

View File

@ -14,13 +14,12 @@ public class Commandsuicide extends EssentialsCommand {
@Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final EntityDamageEvent ede = new EntityDamageEvent(user.getBase(), EntityDamageEvent.DamageCause.SUICIDE, Float.MAX_VALUE);
server.getPluginManager().callEvent(ede);
final EntityDamageEvent ede = ess.getDamageEventProvider().callDamageEvent(user.getBase(), EntityDamageEvent.DamageCause.SUICIDE, Float.MAX_VALUE);
ede.getEntity().setLastDamageCause(ede);
user.getBase().setHealth(0);
user.sendTl("suicideMessage");
user.setDisplayNick();
ess.broadcastTl(user, "suicideSuccess", user.getDisplayName());
ess.broadcastTl(user, "suicideSuccess", new Object[]{user.getDisplayName()});
}
@Override

View File

@ -1,6 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.DescParseTickFormat;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
@ -95,12 +96,12 @@ public class Commandtime extends EssentialsCommand {
private void getWorldsTime(final CommandSource sender, final Collection<World> worlds) {
if (worlds.size() == 1) {
final Iterator<World> iter = worlds.iterator();
sender.sendMessage(DescParseTickFormat.format(iter.next().getTime()));
sender.sendComponent(AdventureUtil.miniMessage().deserialize(DescParseTickFormat.format(iter.next().getTime())));
return;
}
for (final World world : worlds) {
sender.sendTl("timeWorldCurrent", world.getName(), DescParseTickFormat.format(world.getTime()));
sender.sendTl("timeWorldCurrent", world.getName(), AdventureUtil.parsed(DescParseTickFormat.format(world.getTime())));
}
}

View File

@ -83,7 +83,7 @@ public class Commandtogglejail extends EssentialsCommand {
if (args.length > 2) {
player.setJailTimeout(timeDiff);
// 50 MSPT (milliseconds per tick)
player.setOnlineJailedTime(ess.getSettings().isJailOnlineTime() ? ((player.getBase().getStatistic(PLAY_ONE_TICK)) + (timeDiff / 50)) : 0);
player.setOnlineJailedTime(ess.getSettings().isJailOnlineTime() ? ((player.getOffline().getStatistic(PLAY_ONE_TICK)) + (timeDiff / 50)) : 0);
}
final String tlKey;
@ -121,7 +121,7 @@ public class Commandtogglejail extends EssentialsCommand {
final long displayTimeDiff = DateUtil.parseDateDiff(unparsedTime, true);
final long timeDiff = DateUtil.parseDateDiff(unparsedTime, true, ess.getSettings().isJailOnlineTime());
player.setJailTimeout(timeDiff);
player.setOnlineJailedTime(ess.getSettings().isJailOnlineTime() ? ((player.getBase().getStatistic(PLAY_ONE_TICK)) + (timeDiff / 50)) : 0);
player.setOnlineJailedTime(ess.getSettings().isJailOnlineTime() ? ((player.getOffline().getStatistic(PLAY_ONE_TICK)) + (timeDiff / 50)) : 0);
sender.sendTl("jailSentenceExtended", DateUtil.formatDateDiff(displayTimeDiff));
final String tlKey = "jailNotifySentenceExtended";

View File

@ -2,6 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.AdventureUtil;
import net.ess3.api.TranslatableException;
import org.bukkit.Material;
import org.bukkit.Server;
@ -29,7 +30,7 @@ public class Commandunlimited extends EssentialsCommand {
}
if (args[0].equalsIgnoreCase("list")) {
user.sendMessage(getList(user, target));
user.sendComponent(AdventureUtil.miniMessage().deserialize(getList(user, target)));
} else if (args[0].equalsIgnoreCase("clear")) {
for (final Material m : new HashSet<>(target.getUnlimited())) {
if (m == null) {
@ -56,7 +57,7 @@ public class Commandunlimited extends EssentialsCommand {
}
joiner.add(material.toString().toLowerCase(Locale.ENGLISH).replace("_", ""));
}
output.append(joiner.toString());
output.append(joiner);
return output.toString();
}

View File

@ -10,6 +10,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.ess3.api.IEssentials;
import net.ess3.api.TranslatableException;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@ -180,7 +181,7 @@ public abstract class EssentialsCommand implements IEssentialsCommand {
}
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
throw new Exception(tlLiteral("onlyPlayers", commandLabel));
throw new TranslatableException("onlyPlayers", commandLabel);
}
@Override

View File

@ -121,15 +121,17 @@ public class SimpleMessageRecipient implements IMessageRecipient {
// Dont spy on chats involving socialspy exempt players
&& !senderUser.isAuthorized("essentials.chat.spy.exempt")
&& recipientUser != null && !recipientUser.isAuthorized("essentials.chat.spy.exempt")) {
final String senderName = ess.getSettings().isSocialSpyDisplayNames() ? getDisplayName() : getName();
final String recipientName = ess.getSettings().isSocialSpyDisplayNames() ? recipient.getDisplayName() : recipient.getName();
for (final User onlineUser : ess.getOnlineUsers()) {
if (onlineUser.isSocialSpyEnabled()
// Don't send socialspy messages to message sender/receiver to prevent spam
&& !onlineUser.equals(senderUser)
&& !onlineUser.equals(recipient)) {
if (senderUser.isMuted() && ess.getSettings().getSocialSpyListenMutedPlayers()) {
onlineUser.sendComponent(AdventureUtil.miniMessage().deserialize(tlSender("socialSpyMutedPrefix") + tlLiteral("socialSpyMsgFormat", getDisplayName(), recipient.getDisplayName(), message)));
onlineUser.sendComponent(AdventureUtil.miniMessage().deserialize(tlSender("socialSpyMutedPrefix") + tlLiteral("socialSpyMsgFormat", senderName, recipientName, message)));
} else {
onlineUser.sendComponent(AdventureUtil.miniMessage().deserialize(tlLiteral("socialSpyPrefix") + tlLiteral("socialSpyMsgFormat", getDisplayName(), recipient.getDisplayName(), message)));
onlineUser.sendComponent(AdventureUtil.miniMessage().deserialize(tlLiteral("socialSpyPrefix") + tlLiteral("socialSpyMsgFormat", senderName, recipientName, message)));
}
}
}

View File

@ -4,40 +4,55 @@ import net.ess3.api.IEssentials;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.flattener.ComponentFlattener;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.kyori.adventure.text.serializer.legacy.CharacterAndFormat;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.ChatColor;
import net.kyori.adventure.text.serializer.legacy.Reset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public final class AdventureUtil {
private static final LegacyComponentSerializer LEGACY_SERIALIZER;
private static final MiniMessage MINI_MESSAGE_INSTANCE;
private static IEssentials ess;
private static final Pattern NAMED_PATTERN = Pattern.compile(ChatColor.COLOR_CHAR + "[0-9a-fk-orA-FK-OR]");
private static final Pattern HEX_PATTERN = Pattern.compile(ChatColor.COLOR_CHAR + "x((?:" + ChatColor.COLOR_CHAR + "[0-9a-fA-F]){6})");
private static final MiniMessage MINI_MESSAGE_NO_TAGS;
private static final String LOOKUP = "0123456789abcdefklmnor";
private static final String[] MINI_TAGS = new String[] {"black", "dark_blue", "dark_green", "dark_aqua", "dark_red", "dark_purple", "gold", "gray", "dark_gray", "blue", "green", "aqua", "red", "light_purple", "yellow", "white", "obf", "b", "st", "u", "i", "reset"};
private static final NamedTextColor[] COLORS = new NamedTextColor[] {NamedTextColor.BLACK, NamedTextColor.DARK_BLUE, NamedTextColor.DARK_GREEN, NamedTextColor.DARK_AQUA, NamedTextColor.DARK_RED, NamedTextColor.DARK_PURPLE, NamedTextColor.GOLD, NamedTextColor.GRAY, NamedTextColor.DARK_GRAY, NamedTextColor.BLUE, NamedTextColor.GREEN, NamedTextColor.AQUA, NamedTextColor.RED, NamedTextColor.LIGHT_PURPLE, NamedTextColor.YELLOW, NamedTextColor.WHITE};
private static final NamedTextColor[] COLORS = new NamedTextColor[]{NamedTextColor.BLACK, NamedTextColor.DARK_BLUE, NamedTextColor.DARK_GREEN, NamedTextColor.DARK_AQUA, NamedTextColor.DARK_RED, NamedTextColor.DARK_PURPLE, NamedTextColor.GOLD, NamedTextColor.GRAY, NamedTextColor.DARK_GRAY, NamedTextColor.BLUE, NamedTextColor.GREEN, NamedTextColor.AQUA, NamedTextColor.RED, NamedTextColor.LIGHT_PURPLE, NamedTextColor.YELLOW, NamedTextColor.WHITE};
private static IEssentials ess;
private static MiniMessage miniMessageInstance;
static {
final LegacyComponentSerializer.Builder builder = LegacyComponentSerializer.builder().flattener(ComponentFlattener.basic()).useUnusualXRepeatedCharacterHexFormat();
final List<CharacterAndFormat> formats = new ArrayList<>();
formats.addAll(CharacterAndFormat.defaults());
formats.addAll(Arrays.asList(
CharacterAndFormat.characterAndFormat('A', NamedTextColor.GREEN),
CharacterAndFormat.characterAndFormat('B', NamedTextColor.AQUA),
CharacterAndFormat.characterAndFormat('C', NamedTextColor.RED),
CharacterAndFormat.characterAndFormat('D', NamedTextColor.LIGHT_PURPLE),
CharacterAndFormat.characterAndFormat('E', NamedTextColor.YELLOW),
CharacterAndFormat.characterAndFormat('F', NamedTextColor.WHITE),
CharacterAndFormat.characterAndFormat('K', TextDecoration.OBFUSCATED),
CharacterAndFormat.characterAndFormat('L', TextDecoration.BOLD),
CharacterAndFormat.characterAndFormat('M', TextDecoration.STRIKETHROUGH),
CharacterAndFormat.characterAndFormat('N', TextDecoration.UNDERLINED),
CharacterAndFormat.characterAndFormat('O', TextDecoration.ITALIC),
CharacterAndFormat.characterAndFormat('R', Reset.INSTANCE)
));
final LegacyComponentSerializer.Builder builder = LegacyComponentSerializer.builder()
.flattener(ComponentFlattener.basic())
.formats(formats)
.useUnusualXRepeatedCharacterHexFormat();
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_16_1_R01)) {
builder.hexColors();
}
LEGACY_SERIALIZER = builder.build();
MINI_MESSAGE_INSTANCE = MiniMessage.builder()
.tags(TagResolver.builder()
.resolvers(TagResolver.standard())
.resolver(TagResolver.resolver("primary", supplyTag(true)))
.resolver(TagResolver.resolver("secondary", supplyTag(false)))
.build())
.build();
MINI_MESSAGE_NO_TAGS = MiniMessage.miniMessage();
miniMessageInstance = createMiniMessageInstance();
}
private AdventureUtil() {
@ -45,10 +60,21 @@ public final class AdventureUtil {
public static void setEss(final IEssentials ess) {
AdventureUtil.ess = ess;
miniMessageInstance = createMiniMessageInstance();
}
private static MiniMessage createMiniMessageInstance() {
return MiniMessage.builder()
.tags(TagResolver.builder()
.resolvers(TagResolver.standard())
.resolver(TagResolver.resolver("primary", supplyTag(true)))
.resolver(TagResolver.resolver("secondary", supplyTag(false)))
.build())
.build();
}
public static MiniMessage miniMessage() {
return MINI_MESSAGE_INSTANCE;
return miniMessageInstance;
}
/**
@ -81,37 +107,16 @@ public final class AdventureUtil {
/**
* Converts a section sign legacy string to a MiniMessage string.
*
* @param useCustomTags true if gold and red colors should use primary and secondary tags instead.
*/
public static String legacyToMini(String text, boolean useCustomTags) {
StringBuffer buffer = new StringBuffer();
Matcher matcher = HEX_PATTERN.matcher(text);
while (matcher.find()) {
final String code = matcher.group(1).replace(String.valueOf(ChatColor.COLOR_CHAR), "");
matcher.appendReplacement(buffer, "<#" + code + ">");
final Component deserializedText = LEGACY_SERIALIZER.deserialize(text);
if (useCustomTags) {
return miniMessageInstance.serialize(deserializedText);
} else {
return MINI_MESSAGE_NO_TAGS.serialize(deserializedText);
}
matcher.appendTail(buffer);
matcher = NAMED_PATTERN.matcher(buffer.toString());
buffer = new StringBuffer();
while (matcher.find()) {
final int format = LOOKUP.indexOf(Character.toLowerCase(matcher.group().charAt(1)));
if (format != -1) {
String tagName = MINI_TAGS[format];
if (useCustomTags) {
if (tagName.equals("gold")) {
tagName = "primary";
} else if (tagName.equals("red")) {
tagName = "secondary";
}
}
matcher.appendReplacement(buffer, "<" + tagName + ">");
}
}
matcher.appendTail(buffer);
return buffer.toString();
}
/**
@ -125,6 +130,13 @@ public final class AdventureUtil {
return COLORS[index];
}
/**
* Convenience method for submodules to escape MiniMessage tags.
*/
public static String escapeTags(final String input) {
return miniMessage().escapeTags(input);
}
/**
* Parameters for a translation message are not parsed for MiniMessage by default to avoid injection. If you want
* a parameter to be parsed for MiniMessage you must wrap it in a ParsedPlaceholder by using this method.

View File

@ -40,6 +40,13 @@ public final class FormatUtil {
return ChatColor.stripColor(input);
}
public static String stripMiniFormat(final String input) {
if (input == null) {
return null;
}
return AdventureUtil.miniMessage().stripTags(input);
}
//This method is used to simply strip the & convention colour codes
public static String stripEssentialsFormat(final String input) {
if (input == null) {

View File

@ -129,6 +129,15 @@ public final class NumberUtil {
return true;
}
public static boolean isHexadecimal(final String sNum) {
try {
Integer.parseInt(sNum, 16);
return true;
} catch (final NumberFormatException e) {
return false;
}
}
/**
* Backport from Guava.
*/

View File

@ -213,6 +213,10 @@ socialspy-listen-muted-players: true
# If false, social spy will only monitor commands from the list above.
socialspy-messages: true
# Whether social spy should use formatted display names which may include color.
# If false, social spy will use only the actual player names.
socialspy-uses-displaynames: true
# The following settings listen for when a player changes worlds.
# If you use another plugin to control speed and flight, you should change these to false.

View File

@ -227,8 +227,10 @@ public abstract class AbstractChatHandler {
server.getPluginManager().callEvent(spyEvent);
if (!spyEvent.isCancelled()) {
final String legacyString = AdventureUtil.miniToLegacy(String.format(spyEvent.getFormat(), AdventureUtil.legacyToMini(user.getDisplayName()), AdventureUtil.escapeTags(spyEvent.getMessage())));
for (final Player onlinePlayer : spyEvent.getRecipients()) {
onlinePlayer.sendMessage(String.format(spyEvent.getFormat(), user.getDisplayName(), spyEvent.getMessage()));
onlinePlayer.sendMessage(legacyString);
}
}
}

View File

@ -10,6 +10,13 @@ public interface InteractionEvent {
*/
void reply(String message);
/**
* Appends the given string to the initial response message and creates one if it doesn't exist.
* @param tlKey The tlKey of the message to append.
* @param args The args for the message to append.
*/
void replyTl(String tlKey, Object... args);
/**
* Gets the member which caused this event.
* @return the member which caused the event.

View File

@ -61,7 +61,7 @@ public class InteractionControllerImpl extends ListenerAdapter implements Intera
final InteractionEvent interactionEvent = new InteractionEventImpl(event);
final List<String> commandSnowflakes = jda.getSettings().getCommandSnowflakes(command.getName());
if (commandSnowflakes != null && !DiscordUtil.hasRoles(event.getMember(), commandSnowflakes)) {
interactionEvent.reply(tlLiteral("noAccessCommand"));
interactionEvent.replyTl("noAccessCommand");
return;
}
jda.getPlugin().getEss().scheduleSyncDelayedTask(() -> command.onCommand(interactionEvent));

View File

@ -1,5 +1,6 @@
package net.essentialsx.discord.interactions;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.FormatUtil;
import com.google.common.base.Joiner;
import net.dv8tion.jda.api.entities.Message;
@ -18,6 +19,8 @@ import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.earth2me.essentials.I18n.tlLiteral;
/**
* A class which provides information about what triggered an interaction event.
*/
@ -45,6 +48,11 @@ public class InteractionEventImpl implements InteractionEvent {
.queue(null, error -> logger.log(Level.SEVERE, "Error while editing command interaction response", error));
}
@Override
public void replyTl(String tlKey, Object... args) {
reply(AdventureUtil.miniToLegacy(tlLiteral(tlKey, args)));
}
@Override
public InteractionMember getMember() {
return member;

View File

@ -21,7 +21,7 @@ public class ExecuteCommand extends InteractionCommandImpl {
@Override
public void onCommand(final InteractionEvent event) {
final String command = event.getStringArgument("command");
event.reply(tlLiteral("discordCommandExecuteReply", command));
event.replyTl("discordCommandExecuteReply", command);
Bukkit.getScheduler().runTask(jda.getPlugin(), () -> {
try {
Bukkit.dispatchCommand(new DiscordCommandSender(jda, Bukkit.getConsoleSender(), message -> event.reply(MessageUtil.sanitizeDiscordMarkdown(message))).getSender(), command);

View File

@ -3,6 +3,7 @@ package net.essentialsx.discord.interactions.commands;
import com.earth2me.essentials.IEssentials;
import com.earth2me.essentials.PlayerList;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import net.essentialsx.api.v2.services.discord.InteractionCommandArgument;
import net.essentialsx.api.v2.services.discord.InteractionCommandArgumentType;
import net.essentialsx.api.v2.services.discord.InteractionEvent;
@ -45,8 +46,8 @@ public class ListCommand extends InteractionCommandImpl {
final StringBuilder stringBuilder = new StringBuilder();
for (final String str : output) {
stringBuilder.append(str).append("\n");
stringBuilder.append(FormatUtil.stripMiniFormat(str)).append("\n");
}
event.reply(MessageUtil.sanitizeDiscordMarkdown(stringBuilder.substring(0, stringBuilder.length() - 2)));
event.reply(MessageUtil.sanitizeDiscordMarkdown(stringBuilder.substring(0, stringBuilder.length() - 1)));
}
}

View File

@ -2,6 +2,7 @@ package net.essentialsx.discord.interactions.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.commands.PlayerNotFoundException;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.FormatUtil;
import net.essentialsx.api.v2.services.discord.InteractionCommandArgument;
import net.essentialsx.api.v2.services.discord.InteractionCommandArgumentType;
@ -30,28 +31,28 @@ public class MessageCommand extends InteractionCommandImpl {
try {
user = jda.getPlugin().getEss().matchUser(Bukkit.getServer(), null, event.getStringArgument("username"), getHidden, false);
} catch (PlayerNotFoundException e) {
event.reply(tlLiteral("errorWithMessage", e.getMessage()));
event.replyTl("errorWithMessage", e.getMessage());
return;
}
if (!getHidden && user.isIgnoreMsg()) {
event.reply(tlLiteral("msgIgnore", MessageUtil.sanitizeDiscordMarkdown(user.getDisplayName())));
event.replyTl("msgIgnore", MessageUtil.sanitizeDiscordMarkdown(user.getDisplayName()));
return;
}
if (user.isAfk()) {
if (user.getAfkMessage() != null) {
event.reply(tlLiteral("userAFKWithMessage", MessageUtil.sanitizeDiscordMarkdown(user.getDisplayName()), MessageUtil.sanitizeDiscordMarkdown(user.getAfkMessage())));
event.replyTl("userAFKWithMessage", MessageUtil.sanitizeDiscordMarkdown(user.getDisplayName()), MessageUtil.sanitizeDiscordMarkdown(user.getAfkMessage()));
} else {
event.reply(tlLiteral("userAFK", MessageUtil.sanitizeDiscordMarkdown(user.getDisplayName())));
event.replyTl("userAFK", MessageUtil.sanitizeDiscordMarkdown(user.getDisplayName()));
}
}
final String message = event.getMember().hasRoles(jda.getSettings().getPermittedFormattingRoles()) ?
FormatUtil.replaceFormat(event.getStringArgument("message")) : FormatUtil.stripFormat(event.getStringArgument("message"));
event.reply(tlLiteral("msgFormat", tlLiteral("meSender"), MessageUtil.sanitizeDiscordMarkdown(user.getDisplayName()), MessageUtil.sanitizeDiscordMarkdown(message)));
event.replyTl("msgFormat", tlLiteral("meSender"), MessageUtil.sanitizeDiscordMarkdown(user.getDisplayName()), MessageUtil.sanitizeDiscordMarkdown(message));
user.sendMessage(tlLiteral("msgFormat", event.getMember().getTag(), user.playerTl("meRecipient"), message));
user.sendTl("msgFormat", event.getMember().getTag(), AdventureUtil.parsed(user.playerTl("meRecipient")), message);
// We use an atomic reference here so that java will garbage collect the recipient
final AtomicReference<DiscordMessageRecipient> ref = new AtomicReference<>(new DiscordMessageRecipient(event.getMember()));
jda.getPlugin().getEss().runTaskLaterAsynchronously(() -> ref.set(null), 6000); // Expires after 5 minutes

View File

@ -53,14 +53,14 @@ public class AccountInteractionCommand implements InteractionCommand {
final InteractionMember effectiveUser = userArg == null ? event.getMember() : userArg;
final IUser user = accounts.getUser(effectiveUser.getId());
if (user == null) {
event.reply(tlLiteral(event.getMember().getId().equals(effectiveUser.getId()) ? "discordCommandAccountResponseNotLinked" : "discordCommandAccountResponseNotLinkedOther", effectiveUser.getAsMention()));
event.replyTl(event.getMember().getId().equals(effectiveUser.getId()) ? "discordCommandAccountResponseNotLinked" : "discordCommandAccountResponseNotLinkedOther", effectiveUser.getAsMention());
return;
}
if (event.getMember().getId().equals(effectiveUser.getId())) {
event.reply(tlLiteral("discordCommandAccountResponseLinked", user.getName()));
event.replyTl("discordCommandAccountResponseLinked", user.getName());
return;
}
event.reply(tlLiteral("discordCommandAccountResponseLinkedOther", effectiveUser.getAsMention(), user.getName()));
event.replyTl("discordCommandAccountResponseLinkedOther", effectiveUser.getAsMention(), user.getName());
}
}

View File

@ -25,18 +25,18 @@ public class LinkInteractionCommand implements InteractionCommand {
@Override
public void onCommand(InteractionEvent event) {
if (accounts.isLinked(event.getMember().getId())) {
event.reply(tlLiteral("discordCommandLinkHasAccount"));
event.replyTl("discordCommandLinkHasAccount");
return;
}
final UUID uuid = accounts.getPendingUUID(event.getStringArgument("code"));
if (uuid == null) {
event.reply(tlLiteral("discordCommandLinkInvalidCode"));
event.replyTl("discordCommandLinkInvalidCode");
return;
}
accounts.registerAccount(uuid, event.getMember(), DiscordLinkStatusChangeEvent.Cause.SYNC_PLAYER);
event.reply(tlLiteral("discordCommandLinkLinked"));
event.replyTl("discordCommandLinkLinked");
}
@Override

View File

@ -20,10 +20,10 @@ public class UnlinkInteractionCommand implements InteractionCommand {
@Override
public void onCommand(InteractionEvent event) {
if (!accounts.removeAccount(event.getMember(), DiscordLinkStatusChangeEvent.Cause.UNSYNC_PLAYER)) {
event.reply(tlLiteral("discordCommandUnlinkInvalidCode"));
event.replyTl("discordCommandUnlinkInvalidCode");
return;
}
event.reply(tlLiteral("discordCommandUnlinkUnlinked"));
event.replyTl("discordCommandUnlinkUnlinked");
}
@Override

View File

@ -60,7 +60,7 @@ public class LinkBukkitListener implements Listener {
} catch (IllegalArgumentException e) {
code = e.getMessage();
}
event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, tlLiteral("discordLinkLoginKick", "/link " + code, ess.getApi().getInviteUrl()));
event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, AdventureUtil.miniToLegacy(tlLiteral("discordLinkLoginKick", "/link " + code, ess.getApi().getInviteUrl())));
}
}

View File

@ -9,5 +9,5 @@ repositories {
dependencies {
implementation("net.kyori", "indra-common", "3.1.3")
implementation("com.github.johnrengelman", "shadow", "8.1.1")
implementation("xyz.jpenilla", "run-task", "2.1.0")
implementation("xyz.jpenilla", "run-task", "2.2.3")
}

View File

@ -11,8 +11,8 @@ val baseExtension = extensions.create<EssentialsBaseExtension>("essentials", pro
val checkstyleVersion = "8.36.2"
val spigotVersion = "1.20.4-R0.1-SNAPSHOT"
val junit5Version = "5.7.0"
val mockitoVersion = "3.2.0"
val junit5Version = "5.10.2"
val mockitoVersion = "3.12.4"
dependencies {
testImplementation("org.junit.jupiter", "junit-jupiter", junit5Version)
@ -26,6 +26,12 @@ dependencies {
}
}
tasks.test {
testLogging {
events("PASSED", "SKIPPED", "FAILED")
}
}
afterEvaluate {
if (baseExtension.injectBukkitApi.get()) {
dependencies {
@ -117,6 +123,8 @@ indra {
javaVersions {
target(8)
minimumToolchain(17)
// Don't enforce running tests on Java 8; we only care about the release for compiling, not running tests
strictVersions(false)
}
}

Binary file not shown.

View File

@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

22
gradlew vendored
View File

@ -83,7 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -130,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
@ -141,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@ -198,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \

20
gradlew.bat vendored
View File

@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

View File

@ -64,8 +64,8 @@ import java.util.Set;
import java.util.UUID;
public class OfflinePlayerStub implements Player {
protected final transient org.bukkit.OfflinePlayer base;
private final transient Server server;
private final transient org.bukkit.OfflinePlayer base;
private transient Location location = new Location(null, 0, 0, 0, 0, 0);
private transient World world;
private boolean allowFlight = false;

View File

@ -0,0 +1,19 @@
package net.ess3.provider.providers;
import net.ess3.provider.DamageEventProvider;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent;
public class LegacyDamageEventProvider implements DamageEventProvider {
@Override
public EntityDamageEvent callDamageEvent(Player player, EntityDamageEvent.DamageCause cause, double damage) {
final EntityDamageEvent ede = new EntityDamageEvent(player, cause, damage);
player.getServer().getPluginManager().callEvent(ede);
return ede;
}
@Override
public String getDescription() {
return "Legacy Damage Event Provider";
}
}

View File

@ -0,0 +1,8 @@
package net.ess3.provider;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
public interface BiomeKeyProvider extends Provider {
NamespacedKey getBiomeKey(Block block);
}

View File

@ -0,0 +1,8 @@
package net.ess3.provider;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent;
public interface DamageEventProvider extends Provider {
EntityDamageEvent callDamageEvent(Player player, EntityDamageEvent.DamageCause cause, double damage);
}

View File

@ -0,0 +1,24 @@
package net.ess3.provider.providers;
import net.ess3.provider.DamageEventProvider;
import org.bukkit.damage.DamageSource;
import org.bukkit.damage.DamageType;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent;
@SuppressWarnings("UnstableApiUsage")
public class ModernDamageEventProvider implements DamageEventProvider {
private final DamageSource MAGIC_SOURCE = DamageSource.builder(DamageType.MAGIC).build();
@Override
public EntityDamageEvent callDamageEvent(Player player, EntityDamageEvent.DamageCause cause, double damage) {
final EntityDamageEvent ede = new EntityDamageEvent(player, cause, MAGIC_SOURCE, damage);
player.getServer().getPluginManager().callEvent(ede);
return ede;
}
@Override
public String getDescription() {
return "1.20.4+ Damage Event Provider";
}
}

View File

@ -11,8 +11,8 @@ dependencies {
implementation(project(':providers:BaseProviders')) {
exclude(module: 'spigot-api')
}
compileOnly 'io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT'
compileOnly 'io.papermc.paper:paper-mojangapi:1.18.2-R0.1-SNAPSHOT'
compileOnly 'io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT'
compileOnly 'io.papermc.paper:paper-mojangapi:1.20.4-R0.1-SNAPSHOT'
}
essentials {

View File

@ -0,0 +1,19 @@
package net.ess3.provider.providers;
import net.ess3.provider.BiomeKeyProvider;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
@SuppressWarnings("deprecation")
public class PaperBiomeKeyProvider implements BiomeKeyProvider {
@Override
public NamespacedKey getBiomeKey(final Block block) {
return Bukkit.getUnsafe().getBiomeKey(block.getWorld(), block.getX(), block.getY(), block.getZ());
}
@Override
public String getDescription() {
return "Paper Biome Key Provider";
}
}