Skip to content

Commit

Permalink
Merge branch 'dev/2.0.0' of https://github.com/ArcanePlugins/Treasury
Browse files Browse the repository at this point in the history
…into new/permissions-api
  • Loading branch information
MrIvanPlays committed Feb 2, 2023
2 parents eb81eae + 4b6ae33 commit dac47d7
Show file tree
Hide file tree
Showing 34 changed files with 2,768 additions and 440 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### Local Development Files ###
local/

### Eclipse ###
.metadata
bin/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
/**
* Represents a namespaced key, used for unique identification of any so-called "non-player"
* object the Treasury APIs have.
* <br>
* A namespaced key is created from 2 parts: a namespace, and a key. In this implementation,
* they're both represented via the {@link String} object. Namespacing keys allows for having the
* same key "name" with a different namespace e.g. "treasury:test" and "economy:test", hence
* their proven advantage over just a single {@code String} for identification.
*
* @author MrIvanPlays
* @since 2.0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
package me.lokka30.treasury.api.common.event;

/**
* An interface, which can be implemented by events which should be cancellable.
* Represents an interface, which can be implemented by events, which should be cancellable.
* <br>
* Upon cancellation, events may postpone the execution of code, or events may require it for
* updating data in the event.
*
* @author MrIvanPlays
* @since v1.1.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
import org.jetbrains.annotations.NotNull;

/**
* Represents a subscriber of an event. This should be used only if you want to block event
* execution.
* Represents a subscriber of an event. An event subscriber is an object that listens for incoming
* event calls.
* <br>
* Best practice is to use this for complex event subscribers, e.g. when event call block is needed,
* and use the {@link SimpleEventSubscriber} for so-called "simple" event subscribers.
*
* <p>Examples:
* <pre>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,69 +15,46 @@
import org.jetbrains.annotations.NotNull;

/**
* A utility class to help with {@link CompletableFuture} stuff
* A utility class to help with {@link CompletableFuture completable futures}.
*
* @author MrIvanPlays, A248
* @since 1.2.1
*/
public class FutureHelper {

/**
* Does exactly what {@link #mapJoinFilter(Function, Function, Collection)} does except that
* it doesn't map data types.
* Joins and filters futures. All the futures are mapped to return a collective future of the
* same data type whilst simultaneously filtering them via the specified {@code filter}
* {@link Function}.
*
* @param filter filter
* @param futures futures
* @param <T> type parameter
* @return future with collection
* @return joined and filtered future
*/
@NotNull
public static <T> CompletableFuture<Collection<T>> joinAndFilter(
@NotNull Function<T, CompletableFuture<TriState>> filter,
@NotNull Collection<CompletableFuture<T>> futures
) {
return mapJoinFilter(filter, Function.identity(), futures);
}

/**
* Maps, joins, and filters futures.
* Maps all the futures holding data type A to return a collection of data type B
* via the specified {@code mapper} {@link Function} and filters them via the specified
* filter function.
*
* @param filter filter
* @param mapper mapper
* @param futures futures of data type A
* @param <A> type parameter A
* @param <B> type parameter B
* @return future with collection of data type B
*/
@NotNull
public static <A, B> CompletableFuture<Collection<B>> mapJoinFilter(
@NotNull Function<A, CompletableFuture<TriState>> filter,
@NotNull Function<A, B> mapper,
@NotNull Collection<CompletableFuture<A>> futures
) {
Objects.requireNonNull(filter, "filter");
Objects.requireNonNull(mapper, "mapper");
Objects.requireNonNull(futures, "futures");

List<CompletableFuture<Map.Entry<A, TriState>>> filteredFutures =
List<CompletableFuture<Map.Entry<T, TriState>>> filteredFutures =
new ArrayList<>(futures.size());
for (CompletableFuture<A> future : futures) {
filteredFutures.add(future.thenCompose((a) -> filter
.apply(a)
.thenApply((allowed) -> new AbstractMap.SimpleImmutableEntry<>(a, allowed))));
for (CompletableFuture<T> future : futures) {
filteredFutures.add(future.thenCompose((a) -> filter.apply(a).thenApply(allowed -> new AbstractMap.SimpleImmutableEntry<>(a, allowed))));
}
return CompletableFuture.allOf(
filteredFutures.toArray(new CompletableFuture[0])
).thenApply((ignore) -> {
List<B> results = new ArrayList<>(filteredFutures.size());
for (CompletableFuture<Map.Entry<A, TriState>> filteredFuture : filteredFutures) {
List<T> results = new ArrayList<>(filteredFutures.size());
for (CompletableFuture<Map.Entry<T, TriState>> filteredFuture : filteredFutures) {
// By now, all futures are complete -- join() will not block
Map.Entry<A, TriState> entry = filteredFuture.join();
Map.Entry<T, TriState> entry = filteredFuture.join();
if (entry.getValue() == TriState.TRUE) {
results.add(mapper.apply(entry.getKey()));
results.add(entry.getKey());
}
}
return results;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
import org.jetbrains.annotations.NotNull;

/**
* Implementors providing and managing economy data create a class
* which implements this interface to be registered in
* the specific platform they're implementing it for.
* Implementors providing and managing economy data create a class which implements this
* interface to be registered in Treasury's {@link me.lokka30.treasury.api.common.service
* Services API}.
*
* @author lokka30, Jikoo, MrIvanPlays, NoahvdAa, creatorfromhell
* @since v1.0.0
Expand All @@ -50,6 +50,10 @@ public interface EconomyProvider {

/**
* Request whether the specified {@link AccountData} has an associated {@link Account}.
* <br>
* This is here for edge case situations, where calling the {@link #accountAccessor()} does
* not make sense. Per standard, calling the {@link #accountAccessor()} will give an account,
* whether just created or pulled from a database.
*
* @param accountData data about the account type and specific account identifiers
* @return future with {@link Response} which if successful returns the resulting {@link TriState}
Expand Down Expand Up @@ -83,7 +87,7 @@ public interface EconomyProvider {
* @since v1.0.0
*/
@NotNull
default CompletableFuture<Collection<NamespacedKey>> retrieveAllAccountsPlayerIsMemberOf(@NotNull UUID playerId) {
default CompletableFuture<Collection<Response<NonPlayerAccount>>> retrieveAllAccountsPlayerIsMemberOf(@NotNull UUID playerId) {
Objects.requireNonNull(playerId, "playerId");

return retrieveNonPlayerAccountIds().thenCompose(result -> {
Expand All @@ -100,7 +104,7 @@ default CompletableFuture<Collection<NamespacedKey>> retrieveAllAccountsPlayerIs
.withIdentifier(identifier)
.get());
}
return FutureHelper.mapJoinFilter(res -> {
return FutureHelper.joinAndFilter(res -> {
if (!res.isSuccessful()) {
return CompletableFuture.completedFuture(TriState.FALSE);
} else {
Expand All @@ -111,7 +115,7 @@ default CompletableFuture<Collection<NamespacedKey>> retrieveAllAccountsPlayerIs
return CompletableFuture.completedFuture(res1.getResult());
});
}
}, res -> res.getResult().getIdentifier(), accountFutures);
}, accountFutures);
});
}

Expand All @@ -125,7 +129,7 @@ default CompletableFuture<Collection<NamespacedKey>> retrieveAllAccountsPlayerIs
* @since v1.0.0
*/
@NotNull
default CompletableFuture<Collection<NamespacedKey>> retrieveAllAccountsPlayerHasPermission(
default CompletableFuture<Collection<Response<NonPlayerAccount>>> retrieveAllAccountsPlayerHasPermission(
@NotNull UUID playerId, @NotNull AccountPermission @NotNull ... permissions
) {
Objects.requireNonNull(playerId, "playerId");
Expand All @@ -145,7 +149,7 @@ default CompletableFuture<Collection<NamespacedKey>> retrieveAllAccountsPlayerHa
.withIdentifier(identifier)
.get());
}
return FutureHelper.mapJoinFilter(res -> {
return FutureHelper.joinAndFilter(res -> {
if (!res.isSuccessful()) {
return CompletableFuture.completedFuture(TriState.FALSE);
} else {
Expand All @@ -159,7 +163,7 @@ default CompletableFuture<Collection<NamespacedKey>> retrieveAllAccountsPlayerHa
return CompletableFuture.completedFuture(res1.getResult());
});
}
}, res -> res.getResult().getIdentifier(), accountFutures);
}, accountFutures);
});
}

Expand Down Expand Up @@ -218,7 +222,7 @@ default String getPrimaryCurrencyId() {
*
* @param currency The currency to un-register with the {@link EconomyProvider}.
* @return future with {@link Response} which if successful returns a {@link TriState}
* whether the registration was successful. IF the currency was successfully registered,
* whether the registration was successful. If the currency was successfully registered,
* this shall be {@link TriState#TRUE}, otherwise {@link TriState#FALSE} and if that
* currency is not registered already, {@link TriState#UNSPECIFIED}.
* @since v2.0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,10 @@
public interface Account {

/**
* Returns the name of this {@link Account}, if specified. Empty optional otherwise.
* Returns the name of this {@link Account}, if specified. Otherwise, an empty
* {@link Optional} is returned.
*
* <p>A economy provider may choose not to provide a name.
*
* @return an optional fulfilled with a name or an empty optional
* @return an optional, fulfilled with either a name or an empty optional.
* @since v1.0.0
*/
@NotNull
Expand Down Expand Up @@ -287,7 +286,7 @@ default CompletableFuture<Response<BigDecimal>> resetBalance(
.newBuilder()
.withCurrency(currency)
.withInitiator(initiator)
.withTransactionAmount(BigDecimal.ZERO)
.withTransactionAmount(currency.getStartingBalance(this))
.withReason(reason)
.withImportance(importance)
.withTransactionType(EconomyTransactionType.SET)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ private AccountData(
}

/**
* Returns whether this account data holds a {@link PlayerAccount player account} or {link NonPlayerAccount non-player account} data.
* Returns whether this account data holds a {@link PlayerAccount player account} or
* {@link NonPlayerAccount non-player account} data.
*
* @return whether held data references a player account
* @since 2.0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
import me.lokka30.treasury.api.economy.transaction.EconomyTransactionInitiator;

/**
* Enum that holds the permissions of an {@link Account} that is shared among multiple players.
* Represents an enum, describing all the permissions a {@link PlayerAccount player account} may
* have on a {@link NonPlayerAccount non player account}.
*
* @author MrNemo64
* @see Account
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
import org.jetbrains.annotations.NotNull;

/**
* This is used to differentiate between a {@link PlayerAccount player account} and an
* {@link Account account} that is not associated with a player.
* Represents a non-player account. A non-player account is an account that is not owned by a
* player. Such account might be, for example, a bank account.
*
* @author lokka30, MrNemo64, MrIvanPlays
* @see Account
* @see NonPlayerAccount
* @since v1.0.0
*/
public interface NonPlayerAccount extends Account {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

package me.lokka30.treasury.api.economy.account;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
Expand All @@ -15,23 +14,19 @@
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import me.lokka30.treasury.api.common.misc.TriState;
import me.lokka30.treasury.api.common.response.FailureReason;
import me.lokka30.treasury.api.common.response.Response;
import me.lokka30.treasury.api.economy.currency.Currency;
import me.lokka30.treasury.api.economy.response.EconomyFailureReason;
import me.lokka30.treasury.api.economy.transaction.EconomyTransaction;
import me.lokka30.treasury.api.economy.transaction.EconomyTransactionImportance;
import me.lokka30.treasury.api.economy.transaction.EconomyTransactionInitiator;
import me.lokka30.treasury.api.economy.transaction.EconomyTransactionType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* A PlayerAccount is an Account owned by a Player.
* Economy providers are likely to create player accounts
* for players when they join the server, although
* this is optional, which should be taken into consideration
* when trying to access a player account which may not exist
* yet for a player.
* A {@code PlayerAccount} is an {@link Account account} owned by a Player. Economy providers are
* likely to create player accounts for players when they join the server, although this is
* optional.
* <br>
* A Player, on all the platforms Treasury plugin aims to support, is described as a minecraft
* client, mainly identifiable by a {@link #getUniqueId() unique-id}.
*
* @author lokka30, Geolykt, creatorfromhell
* @see Account
Expand All @@ -47,6 +42,12 @@ public interface PlayerAccount extends Account {
.stream(AccountPermission.values())
.collect(Collectors.toConcurrentMap(p -> p, $ -> TriState.TRUE)));

/**
* A {@link FailureReason}, describing that for {@code PlayerAccounts}, modifying the
* permissions are not supported.
*/
FailureReason PLAYER_ACCOUNT_PERMISSION_MODIFICATION_NOT_SUPPORTED = () -> "Cannot modify the permissions of a player account!";

/**
* {@inheritDoc}
*/
Expand All @@ -57,14 +58,24 @@ default CompletableFuture<Response<TriState>> setName(@Nullable String name) {
}

/**
* Get the {@link UUID} of the {@code Account}.
* Get the {@link UUID unique identifier} of this {@code PlayerAccount}.
*
* @return uuid of the Account.
* @return account identifier
* @see UUID
* @since v1.0.0
*/
@NotNull UUID getUniqueId();

/**
* Get this {@code PlayerAccount} as a {@link EconomyTransactionInitiator transaction
* initiator}.
* <p>
* The return value of this method shall be cached upon a {@code PlayerAccount} creation.
*
* @return this player account, represented by an economy transaction initiator
*/
@NotNull EconomyTransactionInitiator<UUID> getAsTransactionInitiator();

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -141,42 +152,7 @@ default CompletableFuture<Response<TriState>> setPermission(
) {
Objects.requireNonNull(player, "player");

return CompletableFuture.completedFuture(Response.failure(EconomyFailureReason.PLAYER_ACCOUNT_PERMISSION_MODIFICATION_NOT_SUPPORTED));
}

/**
* Resets the player's balance. Unlike resetting balances of non-player
* and non player accounts, resetting a player account's balance will set the
* player's balance to the 'starting balance' of the currency (other
* accounts set it to zero instead). This is why the overridden method exists.
*
* @param initiator the one who initiated this transaction
* @param currency of the balance being reset
* @return see {@link Account#resetBalance(EconomyTransactionInitiator, Currency, EconomyTransactionImportance, String)}
* @see Account#resetBalance(EconomyTransactionInitiator, Currency, EconomyTransactionImportance, String)
* @since v1.0.0
*/
@Override
@NotNull
default CompletableFuture<Response<BigDecimal>> resetBalance(
@NotNull EconomyTransactionInitiator<?> initiator,
@NotNull Currency currency,
@NotNull EconomyTransactionImportance importance,
@Nullable String reason
) {
Objects.requireNonNull(initiator, "initiator");
Objects.requireNonNull(currency, "currency");
Objects.requireNonNull(importance, "importance");

return doTransaction(EconomyTransaction
.newBuilder()
.withCurrency(currency)
.withInitiator(initiator)
.withTransactionAmount(currency.getStartingBalance(getUniqueId()))
.withReason(reason)
.withImportance(importance)
.withTransactionType(EconomyTransactionType.SET)
.build());
return CompletableFuture.completedFuture(Response.failure(PLAYER_ACCOUNT_PERMISSION_MODIFICATION_NOT_SUPPORTED));
}

}
Loading

0 comments on commit dac47d7

Please sign in to comment.