package tc.oc.commons.bukkit.trophies; import java.util.List; import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; import com.google.common.util.concurrent.ListenableFuture; import org.bukkit.entity.Player; import org.bukkit.event.EventBus; import tc.oc.api.bukkit.users.BukkitUserStore; import tc.oc.api.docs.Trophy; import tc.oc.api.docs.User; import tc.oc.api.docs.UserId; import tc.oc.api.docs.virtual.UserDoc; import tc.oc.minecraft.scheduler.SyncExecutor; import tc.oc.api.trophies.TrophyStore; import tc.oc.api.users.UserService; import tc.oc.commons.core.stream.Collectors; import tc.oc.commons.core.util.Streams; import static com.google.common.util.concurrent.Futures.immediateFuture; import static tc.oc.commons.core.concurrent.FutureUtils.mapAsync; import static tc.oc.commons.core.concurrent.FutureUtils.mapSync; /** * Handles listing, granting, and revoking of {@link Trophy}s from {@link User}s. */ @Singleton public class TrophyCase { private final SyncExecutor syncExecutor; private final TrophyStore trophyStore; private final BukkitUserStore userStore; private final UserService userService; private final EventBus eventBus; @Inject TrophyCase(SyncExecutor syncExecutor, TrophyStore trophyStore, BukkitUserStore userStore, UserService userService, EventBus eventBus) { this.syncExecutor = syncExecutor; this.trophyStore = trophyStore; this.userStore = userStore; this.userService = userService; this.eventBus = eventBus; } public ListenableFuture<Set<Trophy>> getTrophies(UserId userId) { return mapSync(userService.find(userId), user -> user.trophy_ids() .stream() .map(trophyStore::byId) .collect(Collectors.toImmutableSet())); } public boolean hasTrophy(User user, Trophy trophy) { return user.trophy_ids().contains(trophy._id()); } public boolean hasTrophy(Player player, Trophy trophy) { return hasTrophy(userStore.getUser(player), trophy); } public ListenableFuture<Boolean> hasTrophy(UserId userId, Trophy trophy) { return mapSync(userService.find(userId), user -> hasTrophy(user, trophy)); } public ListenableFuture<Boolean> giveTrophy(UserId userId, Trophy trophy) { return grantOrRevoke(userId, trophy, true); } public ListenableFuture<Boolean> revokeTrophy(UserId userId, Trophy trophy) { return grantOrRevoke(userId, trophy, false); } public ListenableFuture<Boolean> grantOrRevoke(UserId userId, Trophy trophy, boolean grant) { return mapAsync(userService.find(userId), user -> { if(grant == user.trophy_ids().contains(trophy._id())) { return immediateFuture(false); } final List<String> trophyIds = (grant ? Streams.append(user.trophy_ids().stream(), trophy._id()) : Streams.remove(user.trophy_ids().stream(), trophy._id())) .collect(Collectors.toImmutableList()); final ListenableFuture<User> future = userService.update(user, (UserDoc.Trophies) () -> trophyIds); future.addListener(() -> eventBus.callEvent(new TrophyEvent(user, trophy, grant)), syncExecutor); return mapSync(future, u -> true); }); } }