Skip to content

Commit 5dc6a2b

Browse files
committed
Change the UserManager to use CompletableFutures to avoid on-thread IO
* EventContextKeys that were users are now UUIDs.
1 parent 5c78552 commit 5dc6a2b

File tree

6 files changed

+92
-68
lines changed

6 files changed

+92
-68
lines changed

src/main/java/org/spongepowered/api/command/parameter/Parameter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,8 +655,8 @@ static Parameter.Value.Builder<URL> url() {
655655
*
656656
* @return A {@link Parameter.Value.Builder}
657657
*/
658-
static Parameter.Value.Builder<User> user() {
659-
return Parameter.builder(User.class, ResourceKeyedValueParameters.USER);
658+
static Parameter.Value.Builder<UUID> user() {
659+
return Parameter.builder(UUID.class, ResourceKeyedValueParameters.USER);
660660
}
661661

662662
/**

src/main/java/org/spongepowered/api/command/parameter/managed/ValueParameter.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ default Optional<? extends T> parseValue(
111111
* you wish to do so, implement {@link ValueParameter} instead.
112112
*
113113
* {@inheritDoc}
114-
* @return
115114
*/
116115
@Override
117116
default List<CommandCompletion> complete(final CommandContext context, final String currentInput) {

src/main/java/org/spongepowered/api/command/parameter/managed/standard/ResourceKeyedValueParameters.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.spongepowered.api.registry.RegistryScope;
4444
import org.spongepowered.api.registry.RegistryScopes;
4545
import org.spongepowered.api.registry.RegistryTypes;
46+
import org.spongepowered.api.user.UserManager;
4647
import org.spongepowered.api.util.Color;
4748
import org.spongepowered.api.world.Locatable;
4849
import org.spongepowered.api.world.server.ServerLocation;
@@ -402,14 +403,27 @@ public final class ResourceKeyedValueParameters {
402403
public static final DefaultedRegistryReference<ResourceKeyedValueParameter<URL>> URL = ResourceKeyedValueParameters.key(ResourceKey.sponge("url"));
403404

404405
/**
405-
* Expect an argument to represent a player who has been online at some
406-
* point, as a {@link User}.
406+
* Expect an argument to represent the UUID of a player who has been online
407+
* at some point - that is, a {@link UUID} where either:
408+
*
409+
* <ul>
410+
* <li>The player is online; or</li>
411+
* <li>The user with the returned {@link UUID} has user data available
412+
* in the {@link UserManager} (that is, for this UUID,
413+
* {@link UserManager#exists(java.util.UUID)} will return {@code true}).
414+
* </li>
415+
* </ul>
416+
*
417+
* <p>As {@link User} objects are potentially slow to load, they are not
418+
* created or returned here. In general, you will want to run
419+
* {@link UserManager#load(java.util.UUID)} on the returned UUID to actually
420+
* obtain the user.</p>
407421
*
408422
* <p>This parameter accepts selectors (to obtain players).</p>
409423
*
410-
* <p>Returns a {@link User}.</p>
424+
* <p>Returns a {@link UUID}.</p>
411425
*/
412-
public static final DefaultedRegistryReference<ResourceKeyedValueParameter<User>> USER = ResourceKeyedValueParameters.key(ResourceKey.sponge("user"));
426+
public static final DefaultedRegistryReference<ResourceKeyedValueParameter<UUID>> USER = ResourceKeyedValueParameters.key(ResourceKey.sponge("user"));
413427

414428
/**
415429
* Expect an argument to represent a {@link UUID}

src/main/java/org/spongepowered/api/entity/living/player/User.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
import org.spongepowered.api.item.inventory.ArmorEquipable;
3434
import org.spongepowered.api.item.inventory.Carrier;
3535
import org.spongepowered.api.item.inventory.Inventory;
36+
import org.spongepowered.api.item.inventory.entity.PlayerInventory;
3637
import org.spongepowered.api.item.inventory.entity.UserInventory;
38+
import org.spongepowered.api.item.inventory.type.CarriedInventory;
3739
import org.spongepowered.api.profile.GameProfile;
3840
import org.spongepowered.api.service.permission.Subject;
3941
import org.spongepowered.api.util.annotation.DoNotStore;
@@ -129,12 +131,18 @@ public interface User extends DataHolder.Mutable, ArmorEquipable, Tamer, Subject
129131
*/
130132
Vector3d rotation();
131133

134+
/**
135+
* {@inheritDoc}
136+
*
137+
* Note that this may be either a {@link PlayerInventory} or
138+
* {@link UserInventory}, depending on whether the user is online or not.
139+
*/
132140
@Override
133-
UserInventory inventory();
141+
CarriedInventory<? extends Carrier> inventory();
134142

135143
/**
136-
* Gets the {@link Inventory} available for this Player's shared {@link EnderChest}
137-
* contents.
144+
* Gets the {@link Inventory} available for this Player's shared
145+
* {@link EnderChest} contents.
138146
*
139147
* @return The ender chest inventory
140148
*/

src/main/java/org/spongepowered/api/event/EventContextKeys.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
import org.spongepowered.math.vector.Vector3d;
5656
import org.spongepowered.plugin.PluginContainer;
5757

58+
import java.util.UUID;
59+
5860
/**
5961
* Standard keys for use within {@link EventContext}s.
6062
*/
@@ -111,7 +113,7 @@ public final class EventContextKeys {
111113
/**
112114
* Represents the creator of an {@link Entity} or a {@link BlockState} at a {@link Location}
113115
*/
114-
public static final EventContextKey<User> CREATOR = EventContextKeys.key(ResourceKey.sponge("creator"), User.class);
116+
public static final EventContextKey<UUID> CREATOR = EventContextKeys.key(ResourceKey.sponge("creator"), UUID.class);
115117

116118
/**
117119
* Represents the {@link DamageType} to an entity.
@@ -199,9 +201,9 @@ public final class EventContextKeys {
199201
public static final EventContextKey<BlockSnapshot> NEIGHBOR_NOTIFY_SOURCE = EventContextKeys.key(ResourceKey.sponge("neighbor_notify_source"), BlockSnapshot.class);
200202

201203
/**
202-
* Represents the {@link User} that notified a block.
204+
* Represents the {@link UUID} of a {@link User} that notified a block.
203205
*/
204-
public static final EventContextKey<User> NOTIFIER = EventContextKeys.key(ResourceKey.sponge("notifier"), User.class);
206+
public static final EventContextKey<UUID> NOTIFIER = EventContextKeys.key(ResourceKey.sponge("notifier"), UUID.class);
205207

206208
/**
207209
* Used when a {@link BlockTypes#PISTON_HEAD} extends.

src/main/java/org/spongepowered/api/user/UserManager.java

Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@
2929
import org.spongepowered.api.profile.GameProfile;
3030
import org.spongepowered.api.profile.GameProfileManager;
3131

32-
import java.util.Collection;
3332
import java.util.Optional;
3433
import java.util.UUID;
34+
import java.util.concurrent.CompletableFuture;
3535
import java.util.stream.Stream;
3636

3737
/**
3838
* Stores the persistent {@link User} data of a {@link Player}.
39+
*
40+
* <p>Any {@link User}s retrieved from this manager should not be stored, as
41+
* they may become invalid at any time.</p>
3942
*/
4043
public interface UserManager {
4144

@@ -45,7 +48,7 @@ public interface UserManager {
4548
* @param uniqueId The UUID of the user
4649
* @return {@link User} or Optional.empty() if not found
4750
*/
48-
Optional<User> find(UUID uniqueId);
51+
CompletableFuture<Optional<User>> load(UUID uniqueId);
4952

5053
/**
5154
* Gets the data of a {@link User} by their last known user name
@@ -57,58 +60,76 @@ public interface UserManager {
5760
* @param lastKnownName The user name
5861
* @return {@link User} or Optional.empty() if not found
5962
*/
60-
Optional<User> find(String lastKnownName);
63+
CompletableFuture<Optional<User>> load(String lastKnownName);
6164

6265
/**
6366
* Gets the data of a {@link User} by their {@link GameProfile}.
6467
*
6568
* @param profile The profile
6669
* @return {@link User} or Optional.empty() if not found
6770
*/
68-
Optional<User> find(GameProfile profile);
71+
CompletableFuture<Optional<User>> load(GameProfile profile);
6972

7073
/**
71-
* Gets or creates a persistent {@link User} associated with the given
72-
* {@link GameProfile}.
73-
*
74-
* <p>To obtain a {@link GameProfile}, use the {@link GameProfileManager}.
75-
* </p>
74+
* Gets or creates a persistent {@link User} with the given UUID.
7675
*
77-
* @param profile The profile
76+
* @param uuid The {@link UUID} of the player to load or create.
7877
* @return The user object
7978
*/
80-
User findOrCreate(GameProfile profile);
79+
CompletableFuture<User> loadOrCreate(UUID uuid);
8180

8281
/**
83-
* Gets the collection of all {@link GameProfile}s with stored {@link User}
84-
* data.
82+
* Deletes the data associated with a {@link User}, if the player is
83+
* offline.
8584
*
86-
* <p>This method may be resource intensive, particularly for servers that
87-
* have a large number of {@link User}s. If you require a subset of this
88-
* {@link Collection}, use {@link #streamOfMatches(String)} or
89-
* {@link #streamAll()} and use {@link Stream} operations for your queries
90-
* instead.</p>
85+
* @param uuid The uuid of the user to delete
86+
* @return true if the deletion was successful
87+
*/
88+
CompletableFuture<Boolean> delete(UUID uuid);
89+
90+
/**
91+
* If the implementation supports caching user objects, this will hint
92+
* to the implementation that the user with the given UUID should no
93+
* longer be cached. Any {@link User} objects held that this point
94+
* will become invalid (though developers should not be storing
95+
* users).
9196
*
92-
* <p>This {@link Stream} may contain profiles that only hold a result for
93-
* {@link GameProfile#uniqueId()}, that is, do not return a user's name.
94-
* Such profiles should thus be treated as incomplete and are no more than
95-
* an indicator that a {@link User} associated with the given {@link UUID}
96-
* exists.</p>
97+
* <p>Be aware, any changes that have been made to the user may not
98+
* be saved.</p>
9799
*
98-
* <p>Similarly, for {@link GameProfile}s that are filled and thus contain
99-
* name data, the profile information is based on the latest information
100-
* the server holds and no attempt is made to update this information.</p>
100+
* <p>Users that are online will not be affected by this call.</p>
101101
*
102-
* <p>If you require up to date {@link GameProfile}s, use the appropriate
103-
* methods on the {@link GameProfileManager} and/or its associated
104-
* {@link GameProfileManager}.</p>
102+
* @param uuid The UUID of the user to save.
103+
* @return {@code true} if the user was removed from a cache.
104+
*/
105+
boolean removeFromCache(UUID uuid);
106+
107+
/**
108+
* If the implementation supports caching user objects, this will hint
109+
* to the implementation that the user with the given UUID should be saved
110+
* to the disk immediately.
105111
*
106-
* <p>Use {@link #find(GameProfile)} to load the {@link User} data associated
107-
* with the associated {@link GameProfile}.</p>
112+
* <p>If an exception is encountered during save, the completed future
113+
* will be exceptional and the boolean will be {@code null}. It is therefore
114+
* recommended that you check for any exceptions this future holds.</p>
108115
*
109-
* @return A {@link Stream} of {@link GameProfile}s
116+
* @param uuid The user to attempt to save.
117+
* @return A completed future that returns {@code true} if the implementation
118+
* saved the user.
119+
*/
120+
CompletableFuture<Boolean> forceSave(UUID uuid);
121+
122+
/**
123+
* Returns whether data to create a {@link User} exists for a given
124+
* player with a specified {@link UUID}.
125+
*
126+
* <p>If this is {@code false}, then {@link #load(UUID)} will return
127+
* an {@linkplain Optional#empty() empty optional}.</p>
128+
*
129+
* @param playerUuid The {@link UUID} of the player to check.
130+
* @return If the player has existing user data that can be loaded.
110131
*/
111-
Collection<GameProfile> all();
132+
boolean exists(UUID playerUuid);
112133

113134
/**
114135
* Gets a {@link Stream} that returns a {@link GameProfile} for each stored
@@ -128,33 +149,13 @@ public interface UserManager {
128149
* methods on the {@link GameProfileManager} and/or its associated
129150
* {@link GameProfileManager}.</p>
130151
*
131-
* <p>Use {@link #find(GameProfile)} to load the {@link User} data associated
152+
* <p>Use {@link #load(GameProfile)} to load the {@link User} data associated
132153
* with the associated {@link GameProfile}.</p>
133154
*
134155
* @return A {@link Stream} of {@link GameProfile}s
135156
*/
136157
Stream<GameProfile> streamAll();
137158

138-
/**
139-
* Deletes the data associated with a {@link User}.
140-
*
141-
* <p>This may not work if the user is logged in.</p>
142-
*
143-
* @param profile The profile of the user to delete
144-
* @return true if the deletion was successful
145-
*/
146-
boolean delete(GameProfile profile);
147-
148-
/**
149-
* Deletes the data associated with a {@link User}.
150-
*
151-
* <p>This may not work if the user is logged in.</p>
152-
*
153-
* @param user The user to delete
154-
* @return true if the deletion was successful
155-
*/
156-
boolean delete(User user);
157-
158159
/**
159160
* Gets a {@link Stream} that returns a {@link GameProfile} for each stored
160161
* {@link User} whose last known user names start with the given string
@@ -168,7 +169,7 @@ public interface UserManager {
168169
* methods on the {@link GameProfileManager} and/or its associated
169170
* {@link GameProfileManager}.</p>
170171
*
171-
* <p>Use {@link #find(GameProfile)} to load associated {@link User} data.
172+
* <p>Use {@link #load(GameProfile)} to load associated {@link User} data.
172173
* </p>
173174
*
174175
* @param lastKnownName The name to check for

0 commit comments

Comments
 (0)