Skip to content

Commit 5edbc5e

Browse files
committed
Merge branch '2.x' into rework/providers
# Conflicts: # Essentials/src/main/java/com/earth2me/essentials/IEssentials.java
2 parents 0f045fb + dc7fb91 commit 5edbc5e

37 files changed

+966
-675
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
/Essentials/kits.yml
1616
/Essentials/userdata/testplayer1.yml
1717
/Essentials/usermap.csv
18+
/Essentials/usermap.bin
19+
/Essentials/uuids.bin
1820

1921
# Build files
2022
.gradle/

.idea/checkstyle-idea.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Essentials/src/main/java/com/earth2me/essentials/BalanceTopImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public BalanceTopImpl(IEssentials ess) {
2828
private void calculateBalanceTopMap() {
2929
final List<Entry> entries = new LinkedList<>();
3030
BigDecimal newTotal = BigDecimal.ZERO;
31-
for (UUID u : ess.getUserMap().getAllUniqueUsers()) {
32-
final User user = ess.getUserMap().getUser(u);
31+
for (UUID u : ess.getUsers().getAllUserUUIDs()) {
32+
final User user = ess.getUsers().loadUncachedUser(u);
3333
if (user != null) {
3434
if (!ess.getSettings().isNpcsInBalanceRanking() && user.isNPC()) {
3535
// Don't list NPCs in output

Essentials/src/main/java/com/earth2me/essentials/Essentials.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.earth2me.essentials.textreader.KeywordReplacer;
4040
import com.earth2me.essentials.textreader.SimpleTextInput;
4141
import com.earth2me.essentials.updatecheck.UpdateChecker;
42+
import com.earth2me.essentials.userstorage.ModernUserMap;
4243
import com.earth2me.essentials.utils.FormatUtil;
4344
import com.earth2me.essentials.utils.VersionUtil;
4445
import io.papermc.lib.PaperLib;
@@ -143,7 +144,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
143144
private transient CustomItemResolver customItemResolver;
144145
private transient PermissionsHandler permissionsHandler;
145146
private transient AlternativeCommandsHandler alternativeCommandsHandler;
146-
private transient UserMap userMap;
147+
@Deprecated
148+
private transient UserMap legacyUserMap;
149+
private transient ModernUserMap userMap;
147150
private transient BalanceTopImpl balanceTop;
148151
private transient ExecuteTimer execTimer;
149152
private transient MailService mail;
@@ -194,7 +197,7 @@ public void setupForTesting(final Server server) throws IOException, InvalidDesc
194197
LOGGER.log(Level.INFO, dataFolder.toString());
195198
settings = new Settings(this);
196199
mail = new MailServiceImpl(this);
197-
userMap = new UserMap(this);
200+
userMap = new ModernUserMap(this);
198201
balanceTop = new BalanceTopImpl(this);
199202
permissionsHandler = new PermissionsHandler(this, false);
200203
Economy.setEss(this);
@@ -273,11 +276,14 @@ public void onEnable() {
273276
confList.add(settings);
274277
execTimer.mark("Settings");
275278

279+
upgrade.preModules();
280+
execTimer.mark("Upgrade2");
281+
276282
mail = new MailServiceImpl(this);
277283
execTimer.mark("Init(Mail)");
278284

279-
userMap = new UserMap(this);
280-
confList.add(userMap);
285+
userMap = new ModernUserMap(this);
286+
legacyUserMap = new UserMap(userMap);
281287
execTimer.mark("Init(Usermap)");
282288

283289
balanceTop = new BalanceTopImpl(this);
@@ -289,7 +295,7 @@ public void onEnable() {
289295
execTimer.mark("Kits");
290296

291297
upgrade.afterSettings();
292-
execTimer.mark("Upgrade2");
298+
execTimer.mark("Upgrade3");
293299

294300
warps = new Warps(this.getDataFolder());
295301
confList.add(warps);
@@ -536,7 +542,7 @@ public void onDisable() {
536542

537543
Economy.setEss(null);
538544
Trade.closeLog();
539-
getUserMap().getUUIDMap().shutdown();
545+
getUsers().shutdown();
540546

541547
HandlerList.unregisterAll(this);
542548
}
@@ -1015,7 +1021,12 @@ public User getUser(final Player base) {
10151021
if (getSettings().isDebug()) {
10161022
LOGGER.log(Level.INFO, "Constructing new userfile from base player " + base.getName());
10171023
}
1018-
user = new User(base, this);
1024+
user = userMap.loadUncachedUser(base);
1025+
1026+
// The above method will end up creating a new user, but it will not be added to the cache.
1027+
// Since we already call UserMap#getUser() above, we are already okay with adding the user to the cache,
1028+
// so we need to manually add the user to the cache in order to avoid a memory leak and maintain behavior.
1029+
userMap.addCachedUser(user);
10191030
} else {
10201031
user.update(base);
10211032
}
@@ -1151,7 +1162,13 @@ public IItemDb getItemDb() {
11511162
}
11521163

11531164
@Override
1165+
@Deprecated
11541166
public UserMap getUserMap() {
1167+
return legacyUserMap;
1168+
}
1169+
1170+
@Override
1171+
public ModernUserMap getUsers() {
11551172
return userMap;
11561173
}
11571174

Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ public void delayedJoin(final Player player, final String message) {
310310

311311
ess.getBackup().onPlayerJoin();
312312
final User dUser = ess.getUser(player);
313+
dUser.update(player);
313314

314315
dUser.startTransaction();
315316
if (dUser.isNPC()) {
@@ -369,7 +370,7 @@ public void run() {
369370
} else if (ess.getSettings().isCustomJoinMessage()) {
370371
final String msg = (newUsername ? ess.getSettings().getCustomNewUsernameMessage() : ess.getSettings().getCustomJoinMessage())
371372
.replace("{PLAYER}", player.getDisplayName()).replace("{USERNAME}", player.getName())
372-
.replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUserMap().getUniqueUsers()))
373+
.replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUsers().getUserCount()))
373374
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()))
374375
.replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()))
375376
.replace("{PREFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(player)))
@@ -529,6 +530,7 @@ public void onPlayerLoginBanned(final PlayerLoginEvent event) {
529530
public void onPlayerLogin(final PlayerLoginEvent event) {
530531
if (event.getResult() == Result.KICK_FULL) {
531532
final User kfuser = ess.getUser(event.getPlayer());
533+
kfuser.update(event.getPlayer());
532534
if (kfuser.isAuthorized("essentials.joinfullserver")) {
533535
event.allow();
534536
return;

Essentials/src/main/java/com/earth2me/essentials/EssentialsUpgrade.java

Lines changed: 67 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
import com.earth2me.essentials.config.EssentialsConfiguration;
55
import com.earth2me.essentials.config.EssentialsUserConfiguration;
66
import com.earth2me.essentials.craftbukkit.BanLookup;
7+
import com.earth2me.essentials.userstorage.ModernUUIDCache;
78
import com.earth2me.essentials.utils.StringUtil;
89
import com.google.common.base.Charsets;
9-
import com.google.common.collect.Maps;
1010
import com.google.common.io.Files;
1111
import com.google.gson.reflect.TypeToken;
1212
import net.ess3.api.IEssentials;
@@ -31,10 +31,10 @@
3131
import java.math.BigInteger;
3232
import java.security.DigestInputStream;
3333
import java.security.MessageDigest;
34-
import java.text.DecimalFormat;
3534
import java.util.ArrayList;
3635
import java.util.Collections;
3736
import java.util.Date;
37+
import java.util.HashMap;
3838
import java.util.HashSet;
3939
import java.util.List;
4040
import java.util.Locale;
@@ -47,13 +47,12 @@
4747
import java.util.concurrent.TimeUnit;
4848
import java.util.concurrent.atomic.AtomicInteger;
4949
import java.util.logging.Level;
50-
import java.util.regex.Matcher;
5150
import java.util.regex.Pattern;
5251

5352
import static com.earth2me.essentials.I18n.tl;
5453

5554
public class EssentialsUpgrade {
56-
private static final FileFilter YML_FILTER = pathname -> pathname.isFile() && pathname.getName().endsWith(".yml");
55+
public static final FileFilter YML_FILTER = pathname -> pathname.isFile() && pathname.getName().endsWith(".yml");
5756
private static final String PATTERN_CONFIG_UUID_REGEX = "(?mi)^uuid:\\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\s*$";
5857
private static final Pattern PATTERN_CONFIG_UUID = Pattern.compile(PATTERN_CONFIG_UUID_REGEX);
5958
private static final String PATTERN_CONFIG_NAME_REGEX = "(?mi)^lastAccountName:\\s*[\"\']?(\\w+)[\"\']?\\s*$";
@@ -93,7 +92,6 @@ public static void uuidFileConvert(final IEssentials ess, final Boolean ignoreUF
9392
final int showProgress = countFiles % 250;
9493

9594
if (showProgress == 0) {
96-
ess.getUserMap().getUUIDMap().forceWriteUUIDMap();
9795
ess.getLogger().info("Converted " + countFiles + "/" + userdir.list().length);
9896
}
9997

@@ -103,7 +101,8 @@ public static void uuidFileConvert(final IEssentials ess, final Boolean ignoreUF
103101
final EssentialsUserConfiguration config;
104102
UUID uuid = null;
105103
try {
106-
uuid = UUID.fromString(name);
104+
//noinspection ResultOfMethodCallIgnored
105+
UUID.fromString(name);
107106
} catch (final IllegalArgumentException ex) {
108107
final File file = new File(userdir, string);
109108
final EssentialsConfiguration conf = new EssentialsConfiguration(file);
@@ -115,38 +114,40 @@ public static void uuidFileConvert(final IEssentials ess, final Boolean ignoreUF
115114

116115
final String uuidString = conf.getString(uuidConf, null);
117116

117+
//noinspection ConstantConditions
118118
for (int i = 0; i < 4; i++) {
119119
try {
120120
uuid = UUID.fromString(uuidString);
121121
countEssCache++;
122122
break;
123123
} catch (final Exception ex2) {
124124
if (conf.getBoolean("npc", false)) {
125-
uuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8));
125+
uuid = UUID.nameUUIDFromBytes(("NPC:" + (ess.getSettings().isSafeUsermap() ? StringUtil.safeString(name) : name)).getBytes(Charsets.UTF_8));
126126
break;
127127
}
128128

129129
final org.bukkit.OfflinePlayer player = ess.getServer().getOfflinePlayer(name);
130130
uuid = player.getUniqueId();
131131
}
132132

133+
//noinspection ConstantConditions
133134
if (uuid != null) {
134135
countBukkit++;
135136
break;
136137
}
137138
}
138139

140+
//noinspection ConstantConditions
139141
if (uuid != null) {
140142
conf.blockingSave();
141143
config = new EssentialsUserConfiguration(name, uuid, new File(userdir, uuid + ".yml"));
142144
config.convertLegacyFile();
143-
ess.getUserMap().trackUUID(uuid, name, false);
145+
ess.getUsers().loadUncachedUser(uuid);
144146
continue;
145147
}
146148
countFails++;
147149
}
148150
}
149-
ess.getUserMap().getUUIDMap().forceWriteUUIDMap();
150151

151152
ess.getLogger().info("Converted " + countFiles + "/" + countFiles + ". Conversion complete.");
152153
ess.getLogger().info("Converted via cache: " + countEssCache + " :: Converted via lookup: " + countBukkit + " :: Failed to convert: " + countFails);
@@ -913,74 +914,76 @@ private void updateBan(final String playerName, final String banReason, final Lo
913914
Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, banTimeout == 0 ? null : new Date(banTimeout), Console.NAME);
914915
}
915916

916-
private void repairUserMap() {
917-
if (doneFile.getBoolean("userMapRepaired", false)) {
917+
public void generateUidCache() {
918+
if (doneFile.getBoolean("newUidCacheBuilt", false)) {
918919
return;
919920
}
920-
ess.getLogger().info("Starting usermap repair");
921921

922+
final File usermapFile = new File(ess.getDataFolder(), "usermap.bin");
923+
final File uidsFile = new File(ess.getDataFolder(), "uuids.bin");
922924
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
923-
if (!userdataFolder.isDirectory()) {
925+
926+
if (!userdataFolder.isDirectory() || usermapFile.exists() || uidsFile.exists()) {
924927
ess.getLogger().warning("Missing userdata folder, aborting");
928+
doneFile.setProperty("newUidCacheBuilt", true);
929+
doneFile.save();
925930
return;
926931
}
927-
final File[] files = userdataFolder.listFiles(YML_FILTER);
928932

929-
final DecimalFormat format = new DecimalFormat("#0.00");
930-
final Map<String, UUID> names = Maps.newHashMap();
933+
try {
934+
if (!usermapFile.createNewFile() || !uidsFile.createNewFile()) {
935+
ess.getLogger().warning("Couldn't create usermap.bin or uuids.bin, aborting");
936+
return;
937+
}
931938

932-
for (int index = 0; index < files.length; index++) {
933-
final File file = files[index];
934-
try {
935-
UUID uuid = null;
936-
final String filename = file.getName();
937-
final String configData = new String(java.nio.file.Files.readAllBytes(file.toPath()), Charsets.UTF_8);
939+
final Map<UUID, Long> uuids = new HashMap<>();
940+
final Map<String, UUID> nameToUuidMap = new HashMap<>();
938941

939-
if (filename.length() > 36) {
942+
final File[] files = userdataFolder.listFiles(YML_FILTER);
943+
if (files != null) {
944+
for (final File file : files) {
940945
try {
941-
// ".yml" ending has 4 chars...
942-
uuid = UUID.fromString(filename.substring(0, filename.length() - 4));
943-
} catch (final IllegalArgumentException ignored) {
944-
}
945-
}
946-
947-
final Matcher uuidMatcher = PATTERN_CONFIG_UUID.matcher(configData);
948-
if (uuidMatcher.find()) {
949-
try {
950-
uuid = UUID.fromString(uuidMatcher.group(1));
951-
} catch (final IllegalArgumentException ignored) {
952-
}
953-
}
954-
955-
if (uuid == null) {
956-
// Don't import
957-
continue;
958-
}
959-
960-
final Matcher nameMatcher = PATTERN_CONFIG_NAME.matcher(configData);
961-
if (nameMatcher.find()) {
962-
final String username = nameMatcher.group(1);
963-
if (username != null && username.length() > 0) {
964-
names.put(StringUtil.safeString(username), uuid);
946+
final String fileName = file.getName();
947+
final UUID uuid = UUID.fromString(fileName.substring(0, fileName.length() - 4));
948+
final EssentialsConfiguration config = new EssentialsConfiguration(file);
949+
config.load();
950+
String name = config.getString("last-account-name", null);
951+
name = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(name) : name;
952+
final long time = config.getLong("timestamps.logout", 0L);
953+
954+
if (name != null) {
955+
if (nameToUuidMap.containsKey(name)) {
956+
final UUID oldUuid = nameToUuidMap.get(name);
957+
if (oldUuid.version() < uuid.version() || (oldUuid.version() == uuid.version() && uuids.get(oldUuid) < time)) {
958+
ess.getLogger().warning("New UUID found for " + name + ": " + uuid + " (old: " + oldUuid + "). Replacing.");
959+
uuids.remove(oldUuid);
960+
} else {
961+
ess.getLogger().warning("Found UUID for " + name + ": " + uuid + " (old: " + oldUuid + "). Skipping.");
962+
continue;
963+
}
964+
}
965+
966+
uuids.put(uuid, config.getLong("timestamps.logout", 0L));
967+
nameToUuidMap.put(name, uuid);
968+
}
969+
} catch (IllegalArgumentException | IndexOutOfBoundsException ignored) {
965970
}
966971
}
972+
}
967973

968-
if (index % 1000 == 0) {
969-
ess.getLogger().info("Reading: " + format.format((100d * (double) index) / files.length)
970-
+ "%");
971-
}
972-
} catch (final IOException e) {
973-
ess.getLogger().log(Level.SEVERE, "Error while reading file: ", e);
974-
return;
974+
if (!nameToUuidMap.isEmpty()) {
975+
ModernUUIDCache.writeNameUuidMap(usermapFile, nameToUuidMap);
975976
}
976-
}
977977

978-
ess.getUserMap().getNames().putAll(names);
979-
ess.getUserMap().reloadConfig();
978+
if (!uuids.isEmpty()) {
979+
ModernUUIDCache.writeUuidCache(uidsFile, uuids.keySet());
980+
}
980981

981-
doneFile.setProperty("userMapRepaired", true);
982-
doneFile.save();
983-
ess.getLogger().info("Completed usermap repair.");
982+
doneFile.setProperty("newUidCacheBuilt", true);
983+
doneFile.save();
984+
} catch (final IOException e) {
985+
ess.getLogger().log(Level.SEVERE, "Error while generating initial uuids/names cache", e);
986+
}
984987
}
985988

986989
public void beforeSettings() {
@@ -991,6 +994,10 @@ public void beforeSettings() {
991994
moveMotdRulesToFile("rules");
992995
}
993996

997+
public void preModules() {
998+
generateUidCache();
999+
}
1000+
9941001
public void afterSettings() {
9951002
sanitizeAllUserFilenames();
9961003
updateUsersPowerToolsFormat();
@@ -1001,7 +1008,6 @@ public void afterSettings() {
10011008
uuidFileChange();
10021009
banFormatChange();
10031010
warnMetrics();
1004-
repairUserMap();
10051011
convertIgnoreList();
10061012
convertStupidCamelCaseUserdataKeys();
10071013
convertMailList();

0 commit comments

Comments
 (0)