Refactored UsersTable#registerUser to a transaction:

- Removed ProxyRegisterProcessor
- Optimized name updating to occur on login instead of chat events
  - This removes the need to store player names in the DataCache.
This commit is contained in:
Rsl1122 2019-02-01 11:52:17 +02:00
parent 8a15e03096
commit feaf7849d2
20 changed files with 147 additions and 155 deletions

View File

@ -67,8 +67,7 @@ public class ChatListener implements Listener {
private void actOnChatEvent(AsyncPlayerChatEvent event) {
Player p = event.getPlayer();
UUID uuid = p.getUniqueId();
String name = p.getName();
String displayName = p.getDisplayName();
processing.submit(processorFactory.nameProcessor(uuid, name, displayName));
processing.submit(processorFactory.nameProcessor(uuid, displayName));
}
}

View File

@ -162,7 +162,7 @@ public class PlayerOnlineListener implements Listener {
processing.submitCritical(() -> sessionCache.cacheSession(uuid, new Session(uuid, serverInfo.getServerUUID(), time, world, gm)));
runnableFactory.create("Player Register: " + uuid,
processors.player().registerProcessor(uuid, player::getFirstPlayed, playerName,
processors.player().nameProcessor(uuid, playerName, displayName),
processors.player().nameProcessor(uuid, displayName),
processors.info().playerPageUpdateProcessor(uuid)
)
).runTaskAsynchronously();

View File

@ -17,7 +17,9 @@
package com.djrapitops.plan.system.listeners.bungee;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.transactions.events.GeoInfoStoreTransaction;
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
import com.djrapitops.plan.system.cache.GeolocationCache;
import com.djrapitops.plan.system.cache.SessionCache;
import com.djrapitops.plan.system.database.DBSystem;
@ -89,14 +91,16 @@ public class PlayerOnlineListener implements Listener {
sessionCache.cacheSession(uuid, new Session(uuid, serverInfo.getServerUUID(), time, null, null));
Database database = dbSystem.getDatabase();
boolean gatheringGeolocations = config.isTrue(DataGatheringSettings.GEOLOCATIONS);
if (gatheringGeolocations) {
dbSystem.getDatabase().executeTransaction(
database.executeTransaction(
new GeoInfoStoreTransaction(uuid, address, time, geolocationCache::getCountry)
);
}
processing.submit(processors.player().proxyRegisterProcessor(uuid, name, time));
database.executeTransaction(new PlayerRegisterTransaction(uuid, () -> time, name));
processing.submit(processors.info().playerPageUpdateProcessor(uuid));
ResponseCache.clearResponse(PageId.SERVER.of(serverInfo.getServerUUID()));
} catch (Exception e) {

View File

@ -139,6 +139,13 @@ public class DataStoreQueries {
};
}
/**
* Store player's Geo Information in the database.
*
* @param playerUUID UUID of the player.
* @param geoInfo GeoInfo of the player.
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
*/
public static Executable storeGeoInfo(UUID playerUUID, GeoInfo geoInfo) {
return connection -> {
if (!updateGeoInfo(playerUUID, geoInfo).execute(connection)) {
@ -172,4 +179,43 @@ public class DataStoreQueries {
}
};
}
/**
* Store a BaseUser for the player in the database.
*
* @param playerUUID UUID of the player.
* @param registered Time the player registered on the server for the first time.
* @param playerName Name of the player.
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
*/
public static Executable registerBaseUser(UUID playerUUID, long registered, String playerName) {
return new ExecStatement(UsersTable.INSERT_STATEMENT) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, playerUUID.toString());
statement.setString(2, playerName);
statement.setLong(3, registered);
statement.setInt(4, 0); // times kicked
}
};
}
/**
* Update player's name in the database in case they have changed it.
*
* @param playerUUID UUID of the player.
* @param playerName Name of the player.
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
*/
public static Executable updatePlayerName(UUID playerUUID, String playerName) {
String sql = "UPDATE " + UsersTable.TABLE_NAME + " SET " + UsersTable.USER_NAME + "=?" +
" WHERE " + UsersTable.USER_UUID + "=?";
return new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, playerName);
statement.setString(2, playerUUID.toString());
}
};
}
}

View File

@ -0,0 +1,55 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.db.access.transactions.events;
import com.djrapitops.plan.db.access.queries.DataStoreQueries;
import com.djrapitops.plan.db.access.queries.PlayerFetchQueries;
import com.djrapitops.plan.db.access.transactions.Transaction;
import java.util.UUID;
import java.util.function.LongSupplier;
/**
* Transaction for registering player's BaseUser to the database.
*
* @author Rsl1122
*/
public class PlayerRegisterTransaction extends Transaction {
private final UUID playerUUID;
private final LongSupplier registered;
private final String playerName;
public PlayerRegisterTransaction(UUID playerUUID, LongSupplier registered, String playerName) {
this.playerUUID = playerUUID;
this.registered = registered;
this.playerName = playerName;
}
@Override
protected boolean shouldBeExecuted() {
return playerUUID != null && playerName != null;
}
@Override
protected void performOperations() {
if (!query(PlayerFetchQueries.isPlayerRegistered(playerUUID))) {
execute(DataStoreQueries.registerBaseUser(playerUUID, registered.getAsLong(), playerName));
}
execute(DataStoreQueries.updatePlayerName(playerUUID, playerName));
}
}

View File

@ -25,7 +25,6 @@ import com.djrapitops.plan.db.access.ExecStatement;
import com.djrapitops.plan.db.access.QueryAllStatement;
import com.djrapitops.plan.db.access.QueryStatement;
import com.djrapitops.plan.db.sql.parsing.*;
import com.djrapitops.plugin.utilities.Verify;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -135,27 +134,6 @@ public class UsersTable extends Table {
});
}
/**
* Register a new user (UUID) to the database.
*
* @param uuid UUID of the player.
* @param registered Register date.
* @param name Name of the player.
* @throws IllegalArgumentException If uuid or name are null.
*/
public void registerUser(UUID uuid, long registered, String name) {
Verify.nullCheck(uuid, name);
execute(new ExecStatement(insertStatement) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
statement.setLong(2, registered);
statement.setString(3, name);
}
});
}
public void updateName(UUID uuid, String name) {
String sql = Update.values(tableName, USER_NAME)
.where(USER_UUID + "=?")

View File

@ -77,14 +77,9 @@ public class DataCache extends SessionCache implements SubSystem {
* Used to update PlayerName and DisplayName caches.
*
* @param uuid UUID of the player.
* @param playerName Name of the player.
* @param displayName DisplayName of the player.
*/
public void updateNames(UUID uuid, String playerName, String displayName) {
if (playerName != null) {
playerNames.put(uuid, playerName);
uuids.put(playerName, uuid);
}
public void updateDisplayName(UUID uuid, String displayName) {
if (displayName != null) {
displayNames.put(uuid, displayName);
}
@ -92,7 +87,7 @@ public class DataCache extends SessionCache implements SubSystem {
/**
* Used to get the player name in the cache.
*
* <p>
* It is recommended to use
* {@link com.djrapitops.plan.data.store.keys.AnalysisKeys#PLAYER_NAMES} and
* {@link com.djrapitops.plan.data.store.keys.PlayerKeys#NAME} when possible

View File

@ -70,9 +70,6 @@ public interface SaveOperations {
@Deprecated
void opStatus(UUID uuid, boolean op);
@Deprecated
void registerNewUser(UUID uuid, long registered, String name);
@Deprecated
void playerWasKicked(UUID uuid);

View File

@ -137,11 +137,6 @@ public class SQLSaveOps extends SQLOps implements SaveOperations {
userInfoTable.updateOpStatus(uuid, op);
}
@Override
public void registerNewUser(UUID uuid, long registered, String name) {
usersTable.registerUser(uuid, registered, name);
}
@Override
public void playerWasKicked(UUID uuid) {
usersTable.kicked(uuid);

View File

@ -19,7 +19,6 @@ package com.djrapitops.plan.system.processing.processors.player;
import com.djrapitops.plan.data.store.objects.Nickname;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.system.cache.DataCache;
import com.djrapitops.plan.system.database.databases.operation.SaveOperations;
import com.djrapitops.plan.system.processing.CriticalRunnable;
import java.util.UUID;
@ -32,19 +31,17 @@ import java.util.UUID;
public class NameProcessor implements CriticalRunnable {
private final UUID uuid;
private final String playerName;
private final Nickname nickname;
private final Database database;
private final DataCache dataCache;
NameProcessor(
UUID uuid, String playerName, Nickname nickname,
UUID uuid, Nickname nickname,
Database database,
DataCache dataCache
) {
this.uuid = uuid;
this.playerName = playerName;
this.nickname = nickname;
this.database = database;
this.dataCache = dataCache;
@ -52,18 +49,15 @@ public class NameProcessor implements CriticalRunnable {
@Override
public void run() {
String cachedName = dataCache.getName(uuid);
String cachedDisplayName = dataCache.getDisplayName(uuid);
boolean sameAsCached = nickname.getName().equals(cachedDisplayName);
if (playerName.equals(cachedName) && sameAsCached) {
if (sameAsCached) {
return;
}
dataCache.updateNames(uuid, playerName, nickname.getName());
dataCache.updateDisplayName(uuid, nickname.getName());
SaveOperations save = database.save();
save.playerName(uuid, playerName);
save.playerDisplayName(uuid, nickname);
database.save().playerDisplayName(uuid, nickname);
}
}

View File

@ -65,10 +65,6 @@ public class PlayerProcessors {
return new BanAndOpProcessor(uuid, banned, op, dbSystem.get().getDatabase());
}
public ProxyRegisterProcessor proxyRegisterProcessor(UUID uuid, String name, long registered, Runnable... afterProcess) {
return new ProxyRegisterProcessor(uuid, name, registered, processing.get(), dbSystem.get().getDatabase(), afterProcess);
}
public EndSessionProcessor endSessionProcessor(UUID uuid, long time) {
return new EndSessionProcessor(uuid, time, dataCache.get());
}
@ -77,9 +73,9 @@ public class PlayerProcessors {
return new KickProcessor(uuid, dbSystem.get().getDatabase());
}
public NameProcessor nameProcessor(UUID uuid, String playerName, String displayName) {
public NameProcessor nameProcessor(UUID uuid, String displayName) {
Nickname nickname = new Nickname(displayName, System.currentTimeMillis(), serverInfo.get().getServerUUID());
return new NameProcessor(uuid, playerName, nickname, dbSystem.get().getDatabase(), dataCache.get());
return new NameProcessor(uuid, nickname, dbSystem.get().getDatabase(), dataCache.get());
}
public PingInsertProcessor pingInsertProcessor(UUID uuid, List<DateObj<Integer>> pingList) {

View File

@ -1,68 +0,0 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.system.processing.processors.player;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.PlayerFetchQueries;
import com.djrapitops.plan.system.processing.CriticalRunnable;
import com.djrapitops.plan.system.processing.Processing;
import java.util.UUID;
/**
* Processor that registers a new User for all servers to use as UUID - ID reference.
*
* @author Rsl1122
*/
public class ProxyRegisterProcessor implements CriticalRunnable {
private final UUID uuid;
private final String name;
private final long registered;
private final Runnable[] afterProcess;
private final Processing processing;
private final Database database;
ProxyRegisterProcessor(
UUID uuid, String name, long registered,
Processing processing,
Database database,
Runnable... afterProcess
) {
this.uuid = uuid;
this.name = name;
this.registered = registered;
this.processing = processing;
this.database = database;
this.afterProcess = afterProcess;
}
@Override
public void run() {
try {
if (database.query(PlayerFetchQueries.isPlayerRegistered(uuid))) {
return;
}
database.save().registerNewUser(uuid, registered, name);
} finally {
for (Runnable process : afterProcess) {
processing.submit(process);
}
}
}
}

View File

@ -17,7 +17,7 @@
package com.djrapitops.plan.system.processing.processors.player;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.PlayerFetchQueries;
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
import com.djrapitops.plan.system.database.databases.operation.CheckOperations;
import com.djrapitops.plan.system.database.databases.operation.SaveOperations;
import com.djrapitops.plan.system.processing.Processing;
@ -62,9 +62,7 @@ public class RegisterProcessor extends AbsRunnable {
CheckOperations check = database.check();
SaveOperations save = database.save();
try {
if (!database.query(PlayerFetchQueries.isPlayerRegistered(uuid))) {
save.registerNewUser(uuid, registered.getAsLong(), name);
}
database.executeTransaction(new PlayerRegisterTransaction(uuid, registered, name));
if (!check.isPlayerRegisteredOnThisServer(uuid)) {
save.registerNewUserOnThisServer(uuid, registered.getAsLong());
}

View File

@ -35,6 +35,7 @@ import com.djrapitops.plan.db.access.queries.containers.ContainerFetchQueries;
import com.djrapitops.plan.db.access.transactions.*;
import com.djrapitops.plan.db.access.transactions.events.CommandStoreTransaction;
import com.djrapitops.plan.db.access.transactions.events.GeoInfoStoreTransaction;
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction;
import com.djrapitops.plan.db.patches.Patch;
import com.djrapitops.plan.db.sql.tables.*;
@ -225,12 +226,12 @@ public abstract class CommonDBTest {
}
private void saveUserOne() {
db.getUsersTable().registerUser(playerUUID, 123456789L, "Test");
db.executeTransaction(new PlayerRegisterTransaction(playerUUID, () -> 123456789L, "Test"));
db.getUsersTable().kicked(playerUUID);
}
private void saveUserTwo() {
db.getUsersTable().registerUser(player2UUID, 123456789L, "Test");
db.executeTransaction(new PlayerRegisterTransaction(player2UUID, () -> 123456789L, "Test"));
}
@Test
@ -487,7 +488,7 @@ public abstract class CommonDBTest {
SessionsTable sessionsTable = db.getSessionsTable();
NicknamesTable nicknamesTable = db.getNicknamesTable();
usersTable.registerUser(playerUUID, 223456789L, "Test_name");
db.executeTransaction(new PlayerRegisterTransaction(playerUUID, () -> 223456789L, "Test_name"));
userInfoTable.registerUserInfo(playerUUID, 223456789L);
saveTwoWorlds();
@ -780,7 +781,7 @@ public abstract class CommonDBTest {
public void testRegister() {
assertFalse(db.query(PlayerFetchQueries.isPlayerRegistered(playerUUID)));
assertFalse(db.check().isPlayerRegisteredOnThisServer(playerUUID));
db.save().registerNewUser(playerUUID, 1000L, "name");
db.executeTransaction(new PlayerRegisterTransaction(playerUUID, () -> 1000L, "name"));
db.save().registerNewUserOnThisServer(playerUUID, 500L);
assertTrue(db.query(PlayerFetchQueries.isPlayerRegistered(playerUUID)));
assertTrue(db.check().isPlayerRegisteredOnThisServer(playerUUID));
@ -932,10 +933,9 @@ public abstract class CommonDBTest {
String exp1 = "TestName";
String exp2 = "TestName2";
UsersTable usersTable = db.getUsersTable();
UUID uuid1 = UUID.randomUUID();
usersTable.registerUser(uuid1, 0L, exp1);
usersTable.registerUser(UUID.randomUUID(), 0L, exp2);
db.executeTransaction(new PlayerRegisterTransaction(uuid1, () -> 0L, exp1));
db.executeTransaction(new PlayerRegisterTransaction(UUID.randomUUID(), () -> 0L, exp2));
String search = "testname";
@ -951,8 +951,9 @@ public abstract class CommonDBTest {
public void testGetMatchingNickNames() {
UUID uuid = UUID.randomUUID();
String userName = RandomData.randomString(10);
db.getUsersTable().registerUser(uuid, 0L, userName);
db.getUsersTable().registerUser(playerUUID, 1L, "Not random");
db.executeTransaction(new PlayerRegisterTransaction(uuid, () -> 0L, userName));
db.executeTransaction(new PlayerRegisterTransaction(playerUUID, () -> 1L, "Not random"));
String nickname = "2" + RandomData.randomString(10);
db.getNicknamesTable().saveUserName(uuid, new Nickname(nickname, System.currentTimeMillis(), serverUUID));

View File

@ -18,7 +18,7 @@ package com.djrapitops.plan.db;
import com.djrapitops.plan.data.container.GeoInfo;
import com.djrapitops.plan.db.access.queries.ServerAggregateQueries;
import com.djrapitops.plan.db.sql.tables.UsersTable;
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.DatabaseSettings;
import org.junit.BeforeClass;
@ -70,10 +70,9 @@ public class MySQLTest extends CommonDBTest {
UUID secondUuid = UUID.randomUUID();
UUID thirdUuid = UUID.randomUUID();
UsersTable usersTable = db.getUsersTable();
usersTable.registerUser(firstUuid, 0, "");
usersTable.registerUser(secondUuid, 0, "");
usersTable.registerUser(thirdUuid, 0, "");
db.executeTransaction(new PlayerRegisterTransaction(firstUuid, () -> 0L, ""));
db.executeTransaction(new PlayerRegisterTransaction(secondUuid, () -> 0L, ""));
db.executeTransaction(new PlayerRegisterTransaction(thirdUuid, () -> 0L, ""));
saveGeoInfo(firstUuid, new GeoInfo("-", "Norway", 0, "3"));
saveGeoInfo(firstUuid, new GeoInfo("-", "Finland", 5, "3"));

View File

@ -21,8 +21,8 @@ import com.djrapitops.plan.data.container.GeoInfo;
import com.djrapitops.plan.db.access.queries.LargeFetchQueries;
import com.djrapitops.plan.db.access.queries.OptionalFetchQueries;
import com.djrapitops.plan.db.access.queries.ServerAggregateQueries;
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
import com.djrapitops.plan.db.sql.tables.ServerTable;
import com.djrapitops.plan.db.sql.tables.UsersTable;
import com.djrapitops.plan.system.info.server.Server;
import org.junit.BeforeClass;
import org.junit.Test;
@ -97,10 +97,9 @@ public class SQLiteTest extends CommonDBTest {
UUID secondUuid = UUID.randomUUID();
UUID thirdUuid = UUID.randomUUID();
UsersTable usersTable = db.getUsersTable();
usersTable.registerUser(firstUuid, 0, "");
usersTable.registerUser(secondUuid, 0, "");
usersTable.registerUser(thirdUuid, 0, "");
db.executeTransaction(new PlayerRegisterTransaction(firstUuid, () -> 0L, ""));
db.executeTransaction(new PlayerRegisterTransaction(secondUuid, () -> 0L, ""));
db.executeTransaction(new PlayerRegisterTransaction(thirdUuid, () -> 0L, ""));
saveGeoInfo(firstUuid, new GeoInfo("-", "Norway", 0, "3"));
saveGeoInfo(firstUuid, new GeoInfo("-", "Finland", 5, "3"));

View File

@ -20,6 +20,7 @@ import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.DataStoreQueries;
import com.djrapitops.plan.db.access.transactions.Transaction;
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction;
import com.djrapitops.plan.system.PlanSystem;
import com.djrapitops.plan.system.database.DBSystem;
@ -81,7 +82,7 @@ public class JSErrorRegressionTest {
DBSystem dbSystem = bukkitSystem.getDatabaseSystem();
Database database = dbSystem.getDatabase();
UUID uuid = TestConstants.PLAYER_ONE_UUID;
database.save().registerNewUser(uuid, 1000L, "TestPlayer");
database.executeTransaction(new PlayerRegisterTransaction(uuid, () -> 1000L, "name"));
Session session = new Session(uuid, TestConstants.SERVER_UUID, 1000L, "world", "SURVIVAL");
session.endSession(11000L);
database.executeTransaction(new WorldNameStoreTransaction(TestConstants.SERVER_UUID, "world"));

View File

@ -66,9 +66,8 @@ public class SpongeChatListener {
private void actOnChatEvent(@First Player player) {
UUID uuid = player.getUniqueId();
String name = player.getName();
String displayName = player.getDisplayNameData().displayName().get().toPlain();
processing.submit(processorFactory.nameProcessor(uuid, name, displayName));
processing.submit(processorFactory.nameProcessor(uuid, displayName));
}
}

View File

@ -167,7 +167,7 @@ public class SpongePlayerListener {
processing.submitCritical(() -> sessionCache.cacheSession(uuid, new Session(uuid, serverInfo.getServerUUID(), time, world, gm)));
runnableFactory.create("Player Register: " + uuid,
processors.player().registerProcessor(uuid, () -> time, playerName,
processors.player().nameProcessor(uuid, playerName, displayName),
processors.player().nameProcessor(uuid, displayName),
processors.info().playerPageUpdateProcessor(uuid)
)
).runTaskAsynchronously();

View File

@ -17,7 +17,9 @@
package com.djrapitops.plan.system.listeners.velocity;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.transactions.events.GeoInfoStoreTransaction;
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
import com.djrapitops.plan.system.cache.GeolocationCache;
import com.djrapitops.plan.system.cache.SessionCache;
import com.djrapitops.plan.system.database.DBSystem;
@ -92,14 +94,16 @@ public class PlayerOnlineListener {
sessionCache.cacheSession(uuid, new Session(uuid, serverInfo.getServerUUID(), time, null, null));
Database database = dbSystem.getDatabase();
boolean gatheringGeolocations = config.isTrue(DataGatheringSettings.GEOLOCATIONS);
if (gatheringGeolocations) {
dbSystem.getDatabase().executeTransaction(
database.executeTransaction(
new GeoInfoStoreTransaction(uuid, address, time, geolocationCache::getCountry)
);
}
processing.submit(processors.player().proxyRegisterProcessor(uuid, name, time));
database.executeTransaction(new PlayerRegisterTransaction(uuid, () -> time, name));
processing.submit(processors.info().playerPageUpdateProcessor(uuid));
ResponseCache.clearResponse(PageId.SERVER.of(serverInfo.getServerUUID()));
} catch (Exception e) {