Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b4a97ab
chore: add issue types to new issues (#6094)
Chew Mar 19, 2025
2719a18
Release 2.21.0
JRoy Mar 13, 2025
46ba679
Prepare for 2.21.1 dev builds
JRoy Mar 13, 2025
40540eb
Expose `IUser#getLastActivityTime` to API (#6101)
maxcom1 Mar 24, 2025
cb6187b
Add option to customize nickname regex filter (#5200)
Lunna5 Mar 24, 2025
50b696b
Adds social spy message type for in EssentialsDiscord (#5620)
mrbubbles06 Mar 24, 2025
dabe687
Add SignTransactionEvent for buy and sell signs (#6071)
sumsar1812 Mar 24, 2025
0cb387f
Fix NPE when unlinking offline players (#6111)
JRoy Mar 29, 2025
f09541c
Update to Minecraft 1.21.5 (#6109)
JRoy Mar 29, 2025
c7ff994
Fire GlobalChatEvent even when local chat is disabled (#6113)
mdcfe Mar 30, 2025
f3a1b2b
Fix hex colors not working in chat (#6114)
JRoy Mar 31, 2025
06c886c
Fix /baltop on 1.15.2 and below (#6115)
JRoy Mar 31, 2025
2bb4438
Fix further trade sign validation mismatches (#6116)
JRoy Mar 31, 2025
8455212
Fix /spawnmob on < 1.21.5 (#6121)
JRoy Apr 5, 2025
be3e641
New Crowdin updates (#6089)
Flask-Bot Apr 19, 2025
3f5b122
Use legacy text for TranslatableException#getMessage (#6134)
kennytv Apr 27, 2025
fe43017
Fix "heer" typo in messages_en.properties (#6135)
luftwafflezz Apr 29, 2025
a58db23
Update English source strings with fixes from Crowdin (#6140)
mdcfe May 18, 2025
d137031
Improve config comments & ordering (#6108)
JasonHorkles May 18, 2025
3b0c229
New Crowdin updates (#6131)
Flask-Bot May 18, 2025
3fe1495
Fix unexpected behavior with essentials.home.bed & essentials.sethome…
Hunh0w May 25, 2025
aebe851
Fix double messages when deleting a non-existent home (#6150)
JRoy May 25, 2025
3a5c7c4
Revert changes to /home and /sethome that break bed interactions (#6151)
mdcfe May 25, 2025
3d28d82
Release 2.21.1
JRoy Apr 13, 2025
e836747
Prepare for 2.21.2 dev builds (#6128)
JRoy May 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/report-a-bug.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Report bug
description: Report a bug in EssentialsX.
labels: 'bug: unconfirmed'
type: Bug
body:
- type: markdown
attributes:
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/request-a-feature.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Request a feature
description: Suggest a feature you want to see in EssentialsX!
labels: 'type: enhancement'
type: Feature
body:
- type: markdown
attributes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,8 @@ public interface ISettings extends IConf {

boolean showZeroBaltop();

String getNickRegex();

BigDecimal getMultiplier(final User user);

int getMaxItemLore();
Expand Down
11 changes: 11 additions & 0 deletions Essentials/src/main/java/com/earth2me/essentials/IUser.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,17 @@ default boolean hasOutstandingTeleportRequest() {

String getFormattedJailTime();

/**
* Returns last activity time.
* <p>
* It is used internally to determine if user's afk status should be set to
* true because of ACTIVITY {@link AfkStatusChangeEvent.Cause}, or the player
* should be kicked for being afk too long.
*
* @return Last activity time (Epoch Milliseconds)
*/
long getLastActivityTime();

@Deprecated
List<String> getMails();

Expand Down
58 changes: 56 additions & 2 deletions Essentials/src/main/java/com/earth2me/essentials/MobCompat.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Camel;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.Cow;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Fox;
Expand All @@ -18,22 +20,39 @@
import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Panda;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Pig;
import org.bukkit.entity.Player;
import org.bukkit.entity.Salmon;
import org.bukkit.entity.TropicalFish;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Wolf;
import org.bukkit.inventory.ItemStack;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;

import static com.earth2me.essentials.utils.EnumUtil.getEntityType;

public final class MobCompat {

// Constants for mob interfaces added in later versions
@SuppressWarnings("rawtypes")
public static final Class RAIDER = ReflUtil.getClassCached("org.bukkit.entity.Raider");
public static final Class<?> RAIDER = ReflUtil.getClassCached("org.bukkit.entity.Raider");

// Stupid hacks to avoid Commodore rewrites.
private static final Class<?> COW = ReflUtil.getClassCached("org.bukkit.entity.Cow");
private static final Class<?> COW_VARIANT = ReflUtil.getClassCached("org.bukkit.entity.Cow$Variant");
private static final MethodHandle COW_VARIANT_HANDLE;

static {
MethodHandle handle = null;
try {
handle = MethodHandles.lookup().findVirtual(COW, "setVariant", MethodType.methodType(void.class, COW_VARIANT));
} catch (final Throwable ignored) {
}
COW_VARIANT_HANDLE = handle;
}

// Constants for mobs added in later versions
public static final EntityType LLAMA = getEntityType("LLAMA");
Expand Down Expand Up @@ -250,6 +269,41 @@ public static void setSalmonSize(Entity spawned, String s) {
}
}

public static void setCowVariant(final Entity spawned, final String variant) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_21_5_R01) || COW_VARIANT_HANDLE == null) {
return;
}

if (spawned instanceof Cow) {
try {
COW_VARIANT_HANDLE.invoke(spawned, RegistryUtil.valueOf(COW_VARIANT, variant));
} catch (Throwable ignored) {
}
}
}

public static void setChickenVariant(final Entity spawned, final String variant) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_21_5_R01)) {
return;
}

if (spawned instanceof Chicken) {
//noinspection DataFlowIssue
((Chicken) spawned).setVariant(RegistryUtil.valueOf(Chicken.Variant.class, variant));
}
}

public static void setPigVariant(final Entity spawned, final String variant) {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_21_5_R01)) {
return;
}

if (spawned instanceof Pig) {
//noinspection DataFlowIssue
((Pig) spawned).setVariant(RegistryUtil.valueOf(Pig.Variant.class, variant));
}
}

public enum CatType {
// These are (loosely) Mojang names for the cats
SIAMESE("SIAMESE", "SIAMESE_CAT"),
Expand Down
19 changes: 19 additions & 0 deletions Essentials/src/main/java/com/earth2me/essentials/MobData.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.bukkit.entity.Ageable;
import org.bukkit.entity.Boat;
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
Expand Down Expand Up @@ -221,6 +222,15 @@ public enum MobData {
SMALL_SALMON("small", MobCompat.SALMON, "salmon:SMALL", true),
MEDIUM_SALMON("medium", MobCompat.SALMON, "salmon:MEDIUM", true),
LARGE_SALMON("large", MobCompat.SALMON, "salmon:LARGE", true),
TEMPERATE_COW("temperate", EntityType.COW.getEntityClass(), "cow:TEMPERATE", true),
WARM_COW("warm", EntityType.COW.getEntityClass(), "cow:WARM", true),
COLD_COW("cold", EntityType.COW.getEntityClass(), "cow:COLD", true),
TEMPERATE_CHICKEN("temperate", Chicken.class, "chicken:TEMPERATE", true),
WARM_CHICKEN("warm", Chicken.class, "chicken:WARM", true),
COLD_CHICKEN("cold", Chicken.class, "chicken:COLD", true),
TEMPERATE_PIG("temperate", Pig.class, "pig:TEMPERATE", true),
WARM_PIG("warm", Pig.class, "pig:WARM", true),
COLD_PIG("cold", Pig.class, "pig:COLD", true),
;

final private String nickname;
Expand Down Expand Up @@ -442,6 +452,15 @@ public void setData(final Entity spawned, final Player target, final String rawD
case "salmon":
MobCompat.setSalmonSize(spawned, split[1]);
break;
case "cow":
MobCompat.setCowVariant(spawned, split[1]);
break;
case "chicken":
MobCompat.setChickenVariant(spawned, split[1]);
break;
case "pig":
MobCompat.setPigVariant(spawned, split[1]);
break;
}
} else {
Essentials.getWrappedLogger().warning("Unknown mob data type: " + this.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2120,6 +2120,11 @@ public boolean showZeroBaltop() {
return config.getBoolean("show-zero-baltop", true);
}

@Override
public String getNickRegex() {
return config.getString("allowed-nicks-regex", "^[a-zA-Z_0-9§]+$");
}

@Override
public BigDecimal getMultiplier(final User user) {
BigDecimal multiplier = defaultMultiplier;
Expand Down
5 changes: 5 additions & 0 deletions Essentials/src/main/java/com/earth2me/essentials/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,11 @@ public boolean checkMuteTimeout(final long currentTime) {
return false;
}

@Override
public long getLastActivityTime() {
return this.lastActivity;
}

@Deprecated
public void updateActivity(final boolean broadcast) {
updateActivity(broadcast, AfkStatusChangeEvent.Cause.UNKNOWN);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists;
import net.essentialsx.api.v2.services.BalanceTop;
import org.bukkit.Bukkit;
Expand Down Expand Up @@ -121,9 +122,14 @@ public void run() {
final User user = ess.getUser(entry.getKey());

final Statistic PLAY_ONE_TICK = EnumUtil.getStatistic("PLAY_ONE_MINUTE", "PLAY_ONE_TICK");
final boolean offlineStatisticSupported = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_2_R01);
final long playtime;
if (user.getBase() == null || !user.getBase().isOnline()) {
playtime = Bukkit.getServer().getOfflinePlayer(entry.getKey()).getStatistic(PLAY_ONE_TICK);
if (offlineStatisticSupported) {
playtime = Bukkit.getServer().getOfflinePlayer(entry.getKey()).getStatistic(PLAY_ONE_TICK);
} else {
playtime = -1;
}
} else {
playtime = user.getBase().getStatistic(PLAY_ONE_TICK);
}
Expand All @@ -133,7 +139,8 @@ public void run() {
// Checking if player meets the requirements of minimum balance and minimum playtime to be listed in baltop list
if ((ess.getSettings().showZeroBaltop() || balance.compareTo(BigDecimal.ZERO) > 0)
&& balance.compareTo(ess.getSettings().getBaltopMinBalance()) >= 0 &&
playTimeSecs >= ess.getSettings().getBaltopMinPlaytime()) {
// Skip playtime check for offline players on versions below 1.15.2
(playtime == -1 || playTimeSecs >= ess.getSettings().getBaltopMinPlaytime())) {
newCache.getLines().add(AdventureUtil.miniToLegacy(tlLiteral("balanceTopLine", pos, entry.getValue().getDisplayName(), AdventureUtil.parsed(NumberUtil.displayCurrency(balance, ess)))));
}
pos++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ private void deleteHome(CommandSource sender, User user, String home) {

try {
user.delHome(home);
sender.sendTl("deleteHome", home);
} catch (Exception e) {
sender.sendTl("invalidHome", home);
}
sender.sendTl("deleteHome", home);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ protected void updatePlayer(final Server server, final CommandSource sender, fin

private String formatNickname(final User user, final String nick) throws Exception {
final String newNick = user == null ? FormatUtil.replaceFormat(nick) : FormatUtil.formatString(user, "essentials.nick", nick);
if (!newNick.matches("^[a-zA-Z_0-9" + ChatColor.COLOR_CHAR + "]+$") && user != null && !user.isAuthorized("essentials.nick.allowunsafe")) {
if (!newNick.matches(ess.getSettings().getNickRegex()) && user != null && !user.isAuthorized("essentials.nick.allowunsafe")) {
throw new TranslatableException("nickNamesAlpha");
} else if (getNickLength(newNick) > ess.getSettings().getMaxNickLength()) {
throw new TranslatableException("nickTooLong");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.earth2me.essentials.ChargeException;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import net.ess3.api.events.SignTransactionEvent;
import net.ess3.api.IEssentials;
import net.ess3.api.MaxMoneyException;
import org.bukkit.inventory.ItemStack;
Expand Down Expand Up @@ -45,6 +46,12 @@ protected boolean onSignInteract(final ISign sign, final User player, final Stri
}

charge.isAffordableFor(player);
final SignTransactionEvent signTransactionEvent = new SignTransactionEvent(sign, this, player, items.getItemStack(), SignTransactionEvent.TransactionType.BUY, charge.getMoney());

ess.getServer().getPluginManager().callEvent(signTransactionEvent);
if (signTransactionEvent.isCancelled()) {
return true;
}
if (!items.pay(player)) {
throw new ChargeException("inventoryFull");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.Trade.OverflowType;
import com.earth2me.essentials.User;
import net.ess3.api.events.SignTransactionEvent;
import net.ess3.api.IEssentials;
import net.ess3.api.MaxMoneyException;
import org.bukkit.inventory.ItemStack;
Expand Down Expand Up @@ -47,6 +48,13 @@ protected boolean onSignInteract(final ISign sign, final User player, final Stri
}

charge.isAffordableFor(player);

final SignTransactionEvent signTransactionEvent = new SignTransactionEvent(sign, this, player, charge.getItemStack(), SignTransactionEvent.TransactionType.SELL, money.getMoney());
ess.getServer().getPluginManager().callEvent(signTransactionEvent);
if (signTransactionEvent.isCancelled()) {
return false;
}

money.pay(player, OverflowType.DROP);
charge.charge(player);
Trade.log("Sign", "Sell", "Interact", username, charge, username, money, sign.getBlock().getLocation(), player.getMoney(), ess);
Expand Down
Loading