Merge 45d0ff46ae
into b7d7f1188f
This commit is contained in:
commit
990aa8c7f4
|
@ -5,7 +5,7 @@
|
||||||
<groupId>tc.oc</groupId>
|
<groupId>tc.oc</groupId>
|
||||||
<artifactId>api-parent</artifactId>
|
<artifactId>api-parent</artifactId>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
<version>1.11-SNAPSHOT</version>
|
<version>1.12.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>api</artifactId>
|
<artifactId>api</artifactId>
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package tc.oc.api;
|
package tc.oc.api;
|
||||||
|
|
||||||
|
import tc.oc.api.chat.ChatModelManifest;
|
||||||
import tc.oc.api.document.DocumentsManifest;
|
import tc.oc.api.document.DocumentsManifest;
|
||||||
import tc.oc.api.engagement.EngagementModelManifest;
|
import tc.oc.api.engagement.EngagementModelManifest;
|
||||||
|
import tc.oc.api.friendships.FriendshipModelManifest;
|
||||||
import tc.oc.api.games.GameModelManifest;
|
import tc.oc.api.games.GameModelManifest;
|
||||||
import tc.oc.api.http.HttpManifest;
|
import tc.oc.api.http.HttpManifest;
|
||||||
import tc.oc.api.maps.MapModelManifest;
|
import tc.oc.api.maps.MapModelManifest;
|
||||||
|
@ -44,5 +46,7 @@ public final class ApiManifest extends HybridManifest {
|
||||||
install(new WhisperModelManifest());
|
install(new WhisperModelManifest());
|
||||||
install(new TrophyModelManifest());
|
install(new TrophyModelManifest());
|
||||||
install(new TournamentModelManifest());
|
install(new TournamentModelManifest());
|
||||||
|
install(new FriendshipModelManifest());
|
||||||
|
install(new ChatModelManifest());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package tc.oc.api.chat;
|
||||||
|
|
||||||
|
import tc.oc.api.docs.Chat;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
|
import tc.oc.api.model.ModelBinders;
|
||||||
|
import tc.oc.commons.core.inject.HybridManifest;
|
||||||
|
|
||||||
|
public class ChatModelManifest extends HybridManifest implements ModelBinders {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bindModel(Chat.class, ChatDoc.Partial.class, model -> {
|
||||||
|
model.bindDefaultService().to(model.nullService());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package tc.oc.api.docs;
|
||||||
|
|
||||||
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
public interface Chat extends ChatDoc.Complete {}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package tc.oc.api.docs;
|
||||||
|
|
||||||
|
import tc.oc.api.docs.virtual.FriendshipDoc;
|
||||||
|
|
||||||
|
public interface Friendship extends FriendshipDoc.Complete {}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package tc.oc.api.docs.virtual;
|
||||||
|
|
||||||
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
import tc.oc.api.docs.PlayerId;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public interface ChatDoc {
|
||||||
|
interface Partial extends PartialModel {}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface Base extends Model, Partial {
|
||||||
|
@Nonnull String message();
|
||||||
|
@Nonnull String server_id();
|
||||||
|
@Nullable String match_id();
|
||||||
|
@Nonnull Type type();
|
||||||
|
@Nonnull Instant sent_at();
|
||||||
|
@Nullable Broadcast broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface Broadcast extends Partial {
|
||||||
|
@Nonnull Destination destination();
|
||||||
|
@Nullable String id();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface Creation extends Base {
|
||||||
|
@Nullable String sender_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface Complete extends Base {
|
||||||
|
@Nullable PlayerId sender();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
TEAM(true), SERVER(true), ADMIN(false), BROADCAST(false);
|
||||||
|
|
||||||
|
public boolean batchUpdate;
|
||||||
|
|
||||||
|
Type(boolean batchUpdate) {
|
||||||
|
this.batchUpdate = batchUpdate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Destination {
|
||||||
|
SERVER, FAMILY, GAME, NETWORK, GLOBAL
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package tc.oc.api.docs.virtual;
|
||||||
|
|
||||||
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
import tc.oc.api.docs.PlayerId;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public interface FriendshipDoc {
|
||||||
|
|
||||||
|
interface Partial extends PartialModel {}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface Complete extends Model, Partial {
|
||||||
|
Instant sent_date();
|
||||||
|
@Nullable Instant decision_date();
|
||||||
|
PlayerId friender();
|
||||||
|
PlayerId friended();
|
||||||
|
boolean undecided();
|
||||||
|
boolean accepted();
|
||||||
|
boolean rejected();
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ public interface MapDoc extends Model {
|
||||||
enum Genre { OBJECTIVES, DEATHMATCH, OTHER }
|
enum Genre { OBJECTIVES, DEATHMATCH, OTHER }
|
||||||
Genre genre();
|
Genre genre();
|
||||||
|
|
||||||
enum Gamemode { tdm, ctw, ctf, dtc, dtm, ad, koth, blitz, rage, scorebox, arcade, gs, ffa, mixed, skywars, survival }
|
enum Gamemode { tdm, ctw, ctf, dtc, dtm, ad, koth, blitz, rage, scorebox, arcade, gs, ffa, mixed, skywars, survival, payload }
|
||||||
Set<Gamemode> gamemode();
|
Set<Gamemode> gamemode();
|
||||||
|
|
||||||
List<Team> teams();
|
List<Team> teams();
|
||||||
|
|
|
@ -30,11 +30,7 @@ public interface MatchDoc extends Model {
|
||||||
Collection<String> winning_team_ids();
|
Collection<String> winning_team_ids();
|
||||||
Collection<String> winning_user_ids();
|
Collection<String> winning_user_ids();
|
||||||
|
|
||||||
enum Mutation {
|
Set<String> mutations();
|
||||||
BLITZ, UHC, EXPLOSIVES, NO_FALL, MOBS, STRENGTH, DOUBLE_JUMP, INVISIBILITY, LIGHTNING, RAGE, ELYTRA;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<Mutation> mutations();
|
|
||||||
|
|
||||||
@Serialize
|
@Serialize
|
||||||
interface Team extends MapDoc.Team, CompetitorDoc {
|
interface Team extends MapDoc.Team, CompetitorDoc {
|
||||||
|
|
|
@ -22,6 +22,7 @@ public interface PunishmentDoc {
|
||||||
boolean silent();
|
boolean silent();
|
||||||
boolean automatic();
|
boolean automatic();
|
||||||
boolean active();
|
boolean active();
|
||||||
|
boolean off_record();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serialize
|
@Serialize
|
||||||
|
@ -29,7 +30,6 @@ public interface PunishmentDoc {
|
||||||
@Nullable String punisher_id();
|
@Nullable String punisher_id();
|
||||||
@Nullable String punished_id();
|
@Nullable String punished_id();
|
||||||
@Nullable Type type();
|
@Nullable Type type();
|
||||||
boolean off_record();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serialize
|
@Serialize
|
||||||
|
|
|
@ -50,10 +50,15 @@ public interface ServerDoc {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serialize
|
@Serialize
|
||||||
interface CurrentPort extends Partial {
|
interface Port extends Partial {
|
||||||
Integer current_port();
|
Integer current_port();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface Ip extends Partial {
|
||||||
|
String ip();
|
||||||
|
}
|
||||||
|
|
||||||
@Serialize
|
@Serialize
|
||||||
interface Online extends Partial {
|
interface Online extends Partial {
|
||||||
boolean online();
|
boolean online();
|
||||||
|
@ -95,7 +100,7 @@ public interface ServerDoc {
|
||||||
* Startup info sent to the API
|
* Startup info sent to the API
|
||||||
*/
|
*/
|
||||||
@Serialize
|
@Serialize
|
||||||
interface Startup extends Online, CurrentPort {
|
interface Startup extends Online, Port {
|
||||||
@Nullable DeployInfo deploy_info();
|
@Nullable DeployInfo deploy_info();
|
||||||
Map<String, String> plugin_versions();
|
Map<String, String> plugin_versions();
|
||||||
Set<Integer> protocol_versions();
|
Set<Integer> protocol_versions();
|
||||||
|
@ -105,7 +110,8 @@ public interface ServerDoc {
|
||||||
* Startup info received from the API
|
* Startup info received from the API
|
||||||
*/
|
*/
|
||||||
@Serialize
|
@Serialize
|
||||||
interface Configuration extends Partial {
|
interface Configuration extends Rotations {
|
||||||
|
String domain();
|
||||||
String settings_profile();
|
String settings_profile();
|
||||||
Map<UUID, String> operators();
|
Map<UUID, String> operators();
|
||||||
@Nullable Team team();
|
@Nullable Team team();
|
||||||
|
@ -116,10 +122,10 @@ public interface ServerDoc {
|
||||||
Visibility startup_visibility();
|
Visibility startup_visibility();
|
||||||
boolean whitelist_enabled();
|
boolean whitelist_enabled();
|
||||||
boolean waiting_room();
|
boolean waiting_room();
|
||||||
|
|
||||||
@Nullable String resource_pack_url();
|
@Nullable String resource_pack_url();
|
||||||
@Nullable String resource_pack_sha1();
|
@Nullable String resource_pack_sha1();
|
||||||
boolean resource_pack_fast_update();
|
boolean resource_pack_fast_update();
|
||||||
|
@Nullable String cross_server_profile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serialize
|
@Serialize
|
||||||
|
@ -138,7 +144,18 @@ public interface ServerDoc {
|
||||||
|
|
||||||
@Serialize
|
@Serialize
|
||||||
interface Mutation extends Partial {
|
interface Mutation extends Partial {
|
||||||
Set<MatchDoc.Mutation> queued_mutations();
|
Set<String> queued_mutations();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface Rotations extends Partial {
|
||||||
|
List<Rotation> rotations();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface Rotation extends Document {
|
||||||
|
String name();
|
||||||
|
String next_map_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,6 +14,7 @@ public interface SessionDoc {
|
||||||
interface Complete extends Model, Partial {
|
interface Complete extends Model, Partial {
|
||||||
String family_id();
|
String family_id();
|
||||||
String server_id();
|
String server_id();
|
||||||
|
@Nullable String version();
|
||||||
PlayerId user();
|
PlayerId user();
|
||||||
@Nullable String nickname();
|
@Nullable String nickname();
|
||||||
@Nullable String nickname_lower();
|
@Nullable String nickname_lower();
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package tc.oc.api.docs.virtual;
|
package tc.oc.api.docs.virtual;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -44,6 +43,11 @@ public interface UserDoc {
|
||||||
List<String> trophy_ids();
|
List<String> trophy_ids();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface Channel extends Partial {
|
||||||
|
@Nonnull ChatDoc.Type chat_channel();
|
||||||
|
}
|
||||||
|
|
||||||
interface License {
|
interface License {
|
||||||
|
|
||||||
@Serialize
|
@Serialize
|
||||||
|
@ -80,10 +84,14 @@ public interface UserDoc {
|
||||||
* Stuff we get from the API on login, and keep around for plugins to use
|
* Stuff we get from the API on login, and keep around for plugins to use
|
||||||
*/
|
*/
|
||||||
@Serialize
|
@Serialize
|
||||||
interface Login extends Identity, Locale, Trophies, License.Complete {
|
interface Login extends Identity, Locale, Trophies, DefaultServer, FriendTokens, DeathScreen, License.Complete, Channel {
|
||||||
int raindrops();
|
int raindrops();
|
||||||
|
int maptokens();
|
||||||
|
int mutationtokens();
|
||||||
String mc_last_sign_in_ip();
|
String mc_last_sign_in_ip();
|
||||||
@Nullable Date trial_expires_at();
|
@Nullable Date trial_expires_at();
|
||||||
|
@Nullable Instant nickname_updated_at();
|
||||||
|
Map<String, Map<String, Map<String, Object>>> stats_value();
|
||||||
Map<String, Map<String, Boolean>> mc_permissions_by_realm();
|
Map<String, Map<String, Boolean>> mc_permissions_by_realm();
|
||||||
Map<String, Map<String, String>> mc_settings_by_profile();
|
Map<String, Map<String, String>> mc_settings_by_profile();
|
||||||
Map<String, String> classes();
|
Map<String, String> classes();
|
||||||
|
@ -110,4 +118,20 @@ public interface UserDoc {
|
||||||
interface ResourcePackResponse extends Partial {
|
interface ResourcePackResponse extends Partial {
|
||||||
UserDoc.ResourcePackStatus resource_pack_status();
|
UserDoc.ResourcePackStatus resource_pack_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface DefaultServer extends Partial {
|
||||||
|
@Nullable String default_server_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface DeathScreen extends Partial {
|
||||||
|
String death_screen();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
interface FriendTokens extends Partial {
|
||||||
|
int friend_tokens_limit();
|
||||||
|
int friend_tokens_concurrent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package tc.oc.api.friendships;
|
||||||
|
|
||||||
|
import com.google.inject.multibindings.OptionalBinder;
|
||||||
|
import tc.oc.api.docs.Friendship;
|
||||||
|
import tc.oc.api.docs.virtual.FriendshipDoc;
|
||||||
|
import tc.oc.api.model.ModelBinders;
|
||||||
|
import tc.oc.commons.core.inject.HybridManifest;
|
||||||
|
|
||||||
|
public class FriendshipModelManifest extends HybridManifest implements ModelBinders {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bindModel(Friendship.class, FriendshipDoc.Partial.class, model -> {
|
||||||
|
model.bindService().to(FriendshipService.class);
|
||||||
|
});
|
||||||
|
|
||||||
|
OptionalBinder.newOptionalBinder(publicBinder(), FriendshipService.class)
|
||||||
|
.setDefault().to(NullFriendshipService.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package tc.oc.api.friendships;
|
||||||
|
|
||||||
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
import tc.oc.api.docs.virtual.Document;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
public interface FriendshipRequest extends Document {
|
||||||
|
String friender_id();
|
||||||
|
@Nullable String friended_id();
|
||||||
|
|
||||||
|
static FriendshipRequest create(String friender_id, @Nullable String friended_id) {
|
||||||
|
return new FriendshipRequest() {
|
||||||
|
public String friender_id() { return friender_id; }
|
||||||
|
public String friended_id() { return friended_id; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package tc.oc.api.friendships;
|
||||||
|
|
||||||
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
import tc.oc.api.docs.Friendship;
|
||||||
|
import tc.oc.api.docs.virtual.Document;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
public interface FriendshipResponse extends Document {
|
||||||
|
boolean success();
|
||||||
|
@Nullable String error();
|
||||||
|
@Nullable List<Friendship> friendships();
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package tc.oc.api.friendships;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import tc.oc.api.docs.Friendship;
|
||||||
|
import tc.oc.api.docs.virtual.FriendshipDoc;
|
||||||
|
import tc.oc.api.model.ModelService;
|
||||||
|
|
||||||
|
public interface FriendshipService extends ModelService<Friendship, FriendshipDoc.Partial> {
|
||||||
|
|
||||||
|
ListenableFuture<FriendshipResponse> create(FriendshipRequest request);
|
||||||
|
|
||||||
|
ListenableFuture<FriendshipResponse> destroy(FriendshipRequest request);
|
||||||
|
|
||||||
|
ListenableFuture<FriendshipResponse> list(FriendshipRequest request);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package tc.oc.api.friendships;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import tc.oc.api.docs.Friendship;
|
||||||
|
import tc.oc.api.docs.virtual.FriendshipDoc;
|
||||||
|
import tc.oc.api.exceptions.NotFound;
|
||||||
|
import tc.oc.api.model.NullModelService;
|
||||||
|
|
||||||
|
public class NullFriendshipService extends NullModelService<Friendship, FriendshipDoc.Partial> implements FriendshipService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<FriendshipResponse> create(FriendshipRequest request) {
|
||||||
|
return Futures.immediateFailedFuture(new NotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<FriendshipResponse> destroy(FriendshipRequest request) {
|
||||||
|
return Futures.immediateFailedFuture(new NotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<FriendshipResponse> list(FriendshipRequest request) {
|
||||||
|
return Futures.immediateFailedFuture(new NotFound());
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,8 @@ import tc.oc.api.message.types.PlayGameRequest;
|
||||||
import tc.oc.api.message.types.PlayerTeleportRequest;
|
import tc.oc.api.message.types.PlayerTeleportRequest;
|
||||||
import tc.oc.api.message.types.Reply;
|
import tc.oc.api.message.types.Reply;
|
||||||
import tc.oc.api.message.types.UpdateMultiResponse;
|
import tc.oc.api.message.types.UpdateMultiResponse;
|
||||||
|
import tc.oc.api.message.types.UseServerRequest;
|
||||||
|
import tc.oc.api.message.types.UseServerResponse;
|
||||||
import tc.oc.api.servers.ServerSearchRequest;
|
import tc.oc.api.servers.ServerSearchRequest;
|
||||||
import tc.oc.api.sessions.BadNickname;
|
import tc.oc.api.sessions.BadNickname;
|
||||||
import tc.oc.api.sessions.SessionChange;
|
import tc.oc.api.sessions.SessionChange;
|
||||||
|
@ -47,5 +49,8 @@ public class MessagesManifest extends HybridManifest {
|
||||||
messages.register(PlayGameRequest.class);
|
messages.register(PlayGameRequest.class);
|
||||||
messages.register(CycleRequest.class);
|
messages.register(CycleRequest.class);
|
||||||
messages.register(CycleResponse.class);
|
messages.register(CycleResponse.class);
|
||||||
|
|
||||||
|
messages.register(UseServerRequest.class);
|
||||||
|
messages.register(UseServerResponse.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package tc.oc.api.message.types;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
import tc.oc.api.message.Message;
|
||||||
|
import tc.oc.api.queue.MessageDefaults;
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
@MessageDefaults.RoutingKey("use_server")
|
||||||
|
@MessageDefaults.ExpirationMillis(10000)
|
||||||
|
public interface UseServerRequest extends Message {
|
||||||
|
@Nonnull String user_id();
|
||||||
|
@Nonnull String server_name();
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package tc.oc.api.message.types;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
public interface UseServerResponse extends Reply {
|
||||||
|
String server_name();
|
||||||
|
boolean now();
|
||||||
|
|
||||||
|
UseServerResponse EMPTY = new UseServerResponse() {
|
||||||
|
@Override public String server_name() {
|
||||||
|
return "default";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean success() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable @Override public String error() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean now() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package tc.oc.api.reports;
|
package tc.oc.api.reports;
|
||||||
|
|
||||||
import java.util.Collection;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import tc.oc.api.annotations.Serialize;
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
@ -15,39 +15,33 @@ import static com.google.common.base.Preconditions.checkState;
|
||||||
public class ReportSearchRequest extends FindRequest<Report> {
|
public class ReportSearchRequest extends FindRequest<Report> {
|
||||||
|
|
||||||
@Serialize private final @Nullable String server_id;
|
@Serialize private final @Nullable String server_id;
|
||||||
@Serialize private final @Nullable Collection<String> family_ids;
|
|
||||||
@Serialize private final @Nullable String user_id;
|
@Serialize private final @Nullable String user_id;
|
||||||
|
@Serialize private final boolean cross_server;
|
||||||
|
|
||||||
private final int page, perPage;
|
private final int page, perPage;
|
||||||
|
|
||||||
private ReportSearchRequest(String server_id, Collection<String> family_ids, String user_id, int page, int perPage) {
|
private ReportSearchRequest(String server_id, String user_id, boolean cross_server, int page, int perPage) {
|
||||||
checkArgument(page > 0);
|
checkArgument(page > 0);
|
||||||
checkArgument(perPage > 0);
|
checkArgument(perPage > 0);
|
||||||
|
|
||||||
this.server_id = server_id;
|
this.server_id = server_id;
|
||||||
this.family_ids = family_ids;
|
|
||||||
this.user_id = user_id;
|
this.user_id = user_id;
|
||||||
|
this.cross_server = cross_server;
|
||||||
this.page = page;
|
this.page = page;
|
||||||
this.perPage = perPage;
|
this.perPage = perPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReportSearchRequest create(int page, int perPage) {
|
public static ReportSearchRequest create(int page, int perPage) {
|
||||||
return new ReportSearchRequest(null, null, null, page, perPage);
|
return new ReportSearchRequest(null, null, false, page, perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReportSearchRequest forServer(ServerDoc.Identity server) {
|
public ReportSearchRequest forServer(ServerDoc.Identity server, boolean cross_server) {
|
||||||
checkState(server_id == null);
|
return new ReportSearchRequest(server._id(), null, cross_server, page, perPage);
|
||||||
return new ReportSearchRequest(server._id(), null, null, page, perPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReportSearchRequest forFamilies(Collection<String> familyIds) {
|
|
||||||
checkState(family_ids == null);
|
|
||||||
return new ReportSearchRequest(null, familyIds, null, page, perPage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReportSearchRequest forPlayer(PlayerId playerId) {
|
public ReportSearchRequest forPlayer(PlayerId playerId) {
|
||||||
checkState(user_id == null);
|
checkState(user_id == null);
|
||||||
return new ReportSearchRequest(server_id, family_ids, playerId._id(), page, perPage);
|
return new ReportSearchRequest(server_id, playerId._id(), true, page, perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,7 +33,5 @@ public class TypeAdaptersManifest extends Manifest {
|
||||||
|
|
||||||
gson.bindAdapter(new TypeLiteral<Set<MapDoc.Gamemode>>(){})
|
gson.bindAdapter(new TypeLiteral<Set<MapDoc.Gamemode>>(){})
|
||||||
.to(new TypeLiteral<LenientEnumSetTypeAdapter<MapDoc.Gamemode>>(){});
|
.to(new TypeLiteral<LenientEnumSetTypeAdapter<MapDoc.Gamemode>>(){});
|
||||||
gson.bindAdapter(new TypeLiteral<Set<MatchDoc.Mutation>>(){})
|
|
||||||
.to(new TypeLiteral<LenientEnumSetTypeAdapter<MatchDoc.Mutation>>(){});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import tc.oc.api.docs.Server;
|
import tc.oc.api.docs.Server;
|
||||||
import tc.oc.api.docs.virtual.ServerDoc;
|
import tc.oc.api.docs.virtual.ServerDoc;
|
||||||
|
import tc.oc.api.message.types.UseServerRequest;
|
||||||
|
import tc.oc.api.message.types.UseServerResponse;
|
||||||
import tc.oc.api.model.NullModelService;
|
import tc.oc.api.model.NullModelService;
|
||||||
|
|
||||||
public class NullServerService extends NullModelService<Server, ServerDoc.Partial> implements ServerService {
|
public class NullServerService extends NullModelService<Server, ServerDoc.Partial> implements ServerService {
|
||||||
|
@ -12,4 +14,8 @@ public class NullServerService extends NullModelService<Server, ServerDoc.Partia
|
||||||
public ListenableFuture<?> doBungeeMetric(BungeeMetricRequest request) {
|
public ListenableFuture<?> doBungeeMetric(BungeeMetricRequest request) {
|
||||||
return Futures.immediateFuture(null);
|
return Futures.immediateFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public ListenableFuture<UseServerResponse> requestServer(UseServerRequest request) {
|
||||||
|
return Futures.immediateFuture(UseServerResponse.EMPTY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,13 @@ package tc.oc.api.servers;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import tc.oc.api.docs.Server;
|
import tc.oc.api.docs.Server;
|
||||||
import tc.oc.api.docs.virtual.ServerDoc;
|
import tc.oc.api.docs.virtual.ServerDoc;
|
||||||
|
import tc.oc.api.message.types.UseServerRequest;
|
||||||
|
import tc.oc.api.message.types.UseServerResponse;
|
||||||
import tc.oc.api.model.ModelService;
|
import tc.oc.api.model.ModelService;
|
||||||
|
|
||||||
public interface ServerService extends ModelService<Server, ServerDoc.Partial> {
|
public interface ServerService extends ModelService<Server, ServerDoc.Partial> {
|
||||||
|
|
||||||
ListenableFuture<?> doBungeeMetric(BungeeMetricRequest request);
|
ListenableFuture<?> doBungeeMetric(BungeeMetricRequest request);
|
||||||
|
|
||||||
|
ListenableFuture<UseServerResponse> requestServer(UseServerRequest request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,11 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||||
@Singleton
|
@Singleton
|
||||||
public class ServerStore extends ModelStore<Server> {
|
public class ServerStore extends ModelStore<Server> {
|
||||||
|
|
||||||
|
private final SetMultimap<String, Server> byName = HashMultimap.create();
|
||||||
private final Map<String, Server> byBungeeName = new HashMap<>();
|
private final Map<String, Server> byBungeeName = new HashMap<>();
|
||||||
private final SetMultimap<ServerDoc.Role, Server> byRole = HashMultimap.create();
|
private final SetMultimap<ServerDoc.Role, Server> byRole = HashMultimap.create();
|
||||||
|
private final SetMultimap<ServerDoc.Network, Server> byNetwork = HashMultimap.create();
|
||||||
|
private final SetMultimap<String, Server> byFamily = HashMultimap.create();
|
||||||
private final SetMultimap<String, Server> byArenaId = HashMultimap.create();
|
private final SetMultimap<String, Server> byArenaId = HashMultimap.create();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -32,6 +35,18 @@ public class ServerStore extends ModelStore<Server> {
|
||||||
return new ServerSearchRequest();
|
return new ServerSearchRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ImmutableSet<Server> byName(String name) {
|
||||||
|
return ImmutableSet.copyOf(byName.get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableSet<Server> byNetwork(ServerDoc.Network network) {
|
||||||
|
return ImmutableSet.copyOf(byNetwork.get(network));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableSet<Server> byFamily(String family) {
|
||||||
|
return ImmutableSet.copyOf(byFamily.get(family));
|
||||||
|
}
|
||||||
|
|
||||||
public @Nullable Server tryBungeeName(String name) {
|
public @Nullable Server tryBungeeName(String name) {
|
||||||
checkArgument(!"default".equals(name), "Cannot lookup lobbies by bungee_name");
|
checkArgument(!"default".equals(name), "Cannot lookup lobbies by bungee_name");
|
||||||
return byBungeeName.get(name);
|
return byBungeeName.get(name);
|
||||||
|
@ -59,10 +74,20 @@ public class ServerStore extends ModelStore<Server> {
|
||||||
return playerCount;
|
return playerCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canCommunicate(String serverIdA, String serverIdB) {
|
||||||
|
if(serverIdA.equals(serverIdB)) return true;
|
||||||
|
String profileA = byId(serverIdA).cross_server_profile();
|
||||||
|
String profileB = byId(serverIdB).cross_server_profile();
|
||||||
|
return profileA != null && profileB != null && profileA.equalsIgnoreCase(profileB);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void unindex(Server doc) {
|
protected void unindex(Server doc) {
|
||||||
super.unindex(doc);
|
super.unindex(doc);
|
||||||
|
byName.remove(doc.name(), doc);
|
||||||
byRole.remove(doc.role(), doc);
|
byRole.remove(doc.role(), doc);
|
||||||
|
if(doc.network() != null) byNetwork.remove(doc.network(), doc);
|
||||||
|
if(doc.family() != null) byFamily.remove(doc.family(), doc);
|
||||||
if(doc.arena_id() != null) byArenaId.remove(doc.arena_id(), doc);
|
if(doc.arena_id() != null) byArenaId.remove(doc.arena_id(), doc);
|
||||||
if(doc.bungee_name() != null) byBungeeName.remove(doc.bungee_name());
|
if(doc.bungee_name() != null) byBungeeName.remove(doc.bungee_name());
|
||||||
}
|
}
|
||||||
|
@ -70,7 +95,10 @@ public class ServerStore extends ModelStore<Server> {
|
||||||
@Override
|
@Override
|
||||||
protected void reindex(Server doc) {
|
protected void reindex(Server doc) {
|
||||||
super.reindex(doc);
|
super.reindex(doc);
|
||||||
|
byName.put(doc.name(), doc);
|
||||||
byRole.put(doc.role(), doc);
|
byRole.put(doc.role(), doc);
|
||||||
|
if(doc.network() != null) byNetwork.put(doc.network(), doc);
|
||||||
|
if(doc.family() != null) byFamily.put(doc.family(), doc);
|
||||||
if(doc.arena_id() != null) byArenaId.put(doc.arena_id(), doc);
|
if(doc.arena_id() != null) byArenaId.put(doc.arena_id(), doc);
|
||||||
if(doc.bungee_name() != null) byBungeeName.put(doc.bungee_name(), doc);
|
if(doc.bungee_name() != null) byBungeeName.put(doc.bungee_name(), doc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,6 @@ import tc.oc.api.message.types.Reply;
|
||||||
|
|
||||||
@Serialize
|
@Serialize
|
||||||
public interface BadNickname extends Reply {
|
public interface BadNickname extends Reply {
|
||||||
enum Problem { TAKEN, INVALID }
|
enum Problem { TAKEN, INVALID, THROTTLE }
|
||||||
Problem problem();
|
Problem problem();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,5 +15,7 @@ public interface SessionStartRequest extends Document {
|
||||||
|
|
||||||
InetAddress ip();
|
InetAddress ip();
|
||||||
|
|
||||||
|
String version();
|
||||||
|
|
||||||
@Nullable String previous_session_id();
|
@Nullable String previous_session_id();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package tc.oc.api.users;
|
||||||
|
|
||||||
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
import tc.oc.api.docs.virtual.Document;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
public interface ChangeGroupRequest extends Document {
|
||||||
|
String group();
|
||||||
|
String type();
|
||||||
|
@Nullable Instant end();
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package tc.oc.api.users;
|
||||||
|
|
||||||
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
import tc.oc.api.docs.virtual.Document;
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
public interface CreditTokensRequest extends Document {
|
||||||
|
String type();
|
||||||
|
int amount();
|
||||||
|
|
||||||
|
static CreditTokensRequest raindrops(int amount) {
|
||||||
|
return new CreditTokensRequest() {
|
||||||
|
public String type() { return "raindrops"; }
|
||||||
|
public int amount() { return amount; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static CreditTokensRequest maps(int amount) {
|
||||||
|
return new CreditTokensRequest() {
|
||||||
|
public String type() { return "maptokens"; }
|
||||||
|
public int amount() { return amount; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static CreditTokensRequest mutations(int amount) {
|
||||||
|
return new CreditTokensRequest() {
|
||||||
|
public String type() { return "mutationtokens"; }
|
||||||
|
public int amount() { return amount; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package tc.oc.api.users;
|
||||||
|
|
||||||
|
import tc.oc.api.annotations.Serialize;
|
||||||
|
import tc.oc.api.docs.virtual.Document;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
@Serialize
|
||||||
|
public interface FriendJoinRequest extends Document {
|
||||||
|
int amount();
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import tc.oc.api.annotations.Serialize;
|
||||||
import tc.oc.api.docs.virtual.Document;
|
import tc.oc.api.docs.virtual.Document;
|
||||||
|
|
||||||
@Serialize
|
@Serialize
|
||||||
public interface CreditRaindropsRequest extends Document {
|
public interface FriendJoinResponse extends Document {
|
||||||
int raindrops();
|
boolean authorized();
|
||||||
|
String message();
|
||||||
}
|
}
|
|
@ -31,10 +31,20 @@ public class NullUserService extends NullModelService<User, UserDoc.Partial> imp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<UserUpdateResponse> creditRaindrops(UserId userId, CreditRaindropsRequest request) {
|
public ListenableFuture<UserUpdateResponse> creditTokens(UserId userId, CreditTokensRequest request) {
|
||||||
return Futures.immediateFuture(UserUpdateResponse.FAILURE);
|
return Futures.immediateFuture(UserUpdateResponse.FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<User> changeGroup(UserId userId, ChangeGroupRequest request) {
|
||||||
|
return Futures.immediateFailedFuture(new NotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<FriendJoinResponse> joinFriend(UserId userId, FriendJoinRequest request) {
|
||||||
|
return Futures.immediateFailedFuture(new NotFound());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<User> purchaseGizmo(UserId userId, PurchaseGizmoRequest request) {
|
public ListenableFuture<User> purchaseGizmo(UserId userId, PurchaseGizmoRequest request) {
|
||||||
return Futures.immediateFailedFuture(new NotFound());
|
return Futures.immediateFailedFuture(new NotFound());
|
||||||
|
|
|
@ -19,11 +19,11 @@ public interface UserService extends ModelService<User, UserDoc.Partial> {
|
||||||
|
|
||||||
ListenableFuture<?> logout(LogoutRequest request);
|
ListenableFuture<?> logout(LogoutRequest request);
|
||||||
|
|
||||||
default ListenableFuture<UserUpdateResponse> creditRaindrops(UserId userId, int raindrops) {
|
ListenableFuture<UserUpdateResponse> creditTokens(UserId userId, CreditTokensRequest request);
|
||||||
return creditRaindrops(userId, () -> raindrops);
|
|
||||||
}
|
|
||||||
|
|
||||||
ListenableFuture<UserUpdateResponse> creditRaindrops(UserId userId, CreditRaindropsRequest request);
|
ListenableFuture<User> changeGroup(UserId userId, ChangeGroupRequest request);
|
||||||
|
|
||||||
|
ListenableFuture<FriendJoinResponse> joinFriend(UserId userId, FriendJoinRequest request);
|
||||||
|
|
||||||
ListenableFuture<User> purchaseGizmo(UserId userId, PurchaseGizmoRequest request);
|
ListenableFuture<User> purchaseGizmo(UserId userId, PurchaseGizmoRequest request);
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
package tc.oc.api.util;
|
package tc.oc.api.util;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import tc.oc.minecraft.api.command.CommandSender;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public final class Permissions {
|
public interface Permissions {
|
||||||
|
|
||||||
private Permissions() {}
|
String CONSOLE = "ocn.console";
|
||||||
|
String LOGIN = "ocn.login";
|
||||||
public static final String CONSOLE = "ocn.console";
|
String STAFF = "projectares.staff";
|
||||||
public static final String LOGIN = "ocn.login";
|
String OBSERVER = "ocn.observer";
|
||||||
public static final String STAFF = "projectares.staff";
|
String PARTICIPANT = "ocn.participant";
|
||||||
public static final String OBSERVER = "ocn.observer";
|
String MAPMAKER = "ocn.mapmaker";
|
||||||
public static final String PARTICIPANT = "ocn.participant";
|
String DEVELOPER = "ocn.developer";
|
||||||
public static final String MAPMAKER = "ocn.mapmaker";
|
String MAPDEV = "pgm.mapdev";
|
||||||
public static final String DEVELOPER = "ocn.developer";
|
String MAPERRORS = "pgm.maperrors";
|
||||||
public static final String MAPDEV = "pgm.mapdev";
|
|
||||||
public static final String MAPERRORS = "pgm.maperrors";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge the given by-realm permissions into a single set of permissions using the given (ordered) realms
|
* Merge the given by-realm permissions into a single set of permissions using the given (ordered) realms
|
||||||
|
@ -24,7 +27,7 @@ public final class Permissions {
|
||||||
* @param permsByRealm Permissions, grouped by realm
|
* @param permsByRealm Permissions, grouped by realm
|
||||||
* @return Effective permissions
|
* @return Effective permissions
|
||||||
*/
|
*/
|
||||||
public static Map<String, Boolean> mergePermissions(Collection<String> realms, Map<String, Map<String, Boolean>> permsByRealm) {
|
static Map<String, Boolean> mergePermissions(Collection<String> realms, Map<String, Map<String, Boolean>> permsByRealm) {
|
||||||
Map<String, Boolean> effectivePerms = new HashMap<>();
|
Map<String, Boolean> effectivePerms = new HashMap<>();
|
||||||
for(String realm : realms) {
|
for(String realm : realms) {
|
||||||
Map<String, Boolean> perms = permsByRealm.get(realm);
|
Map<String, Boolean> perms = permsByRealm.get(realm);
|
||||||
|
@ -34,4 +37,42 @@ public final class Permissions {
|
||||||
}
|
}
|
||||||
return effectivePerms;
|
return effectivePerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of enums a {@link CommandSender} has permission to use.
|
||||||
|
*
|
||||||
|
* This is useful for enums that correspond to an action. Instead of granting permission
|
||||||
|
* to a user for each node, they have access to any enum below the highest ordinal node.
|
||||||
|
* <code>
|
||||||
|
* enum Trig {
|
||||||
|
* SOH, CAH, TOA
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
* So if a sender has explicit permission to ocn.foo.cah, the sender has implicit
|
||||||
|
* permission to use Trig.SOH and Trig.CAH.
|
||||||
|
*
|
||||||
|
* @param sender The command sender.
|
||||||
|
* @param enumClass The class of the enum to get the values from.
|
||||||
|
* @return List of {@link E}s that the {@param sender} is allowed to use, ascending order based on {@link E#ordinal()}.
|
||||||
|
*/
|
||||||
|
static <E extends Enum> List<E> enumPermissions(CommandSender sender, String base, Class<E> enumClass) {
|
||||||
|
final List<E> enums = Lists.newArrayList(enumClass.getEnumConstants());
|
||||||
|
final Function<E, String> normalizer = value -> base + "." + value.name().toLowerCase().replaceAll("_", "-");
|
||||||
|
final int max = enums.stream()
|
||||||
|
.filter(value -> sender.hasPermission(normalizer.apply(value)))
|
||||||
|
.map(E::ordinal)
|
||||||
|
.max(Integer::compare)
|
||||||
|
.orElse(-1);
|
||||||
|
return enums.subList(0, max + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether a {@link CommandSender} has permission to use a selected {@link E}.
|
||||||
|
*
|
||||||
|
* @see #enumPermissions(CommandSender, String, Class)
|
||||||
|
* @return Whether the {@param sender} has permission.
|
||||||
|
*/
|
||||||
|
static <E extends Enum> boolean hasPermissionForEnum(CommandSender sender, String base, E selected) {
|
||||||
|
return enumPermissions(sender, base, (Class<E>) selected.getClass()).contains(selected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<groupId>tc.oc</groupId>
|
<groupId>tc.oc</groupId>
|
||||||
<artifactId>api-parent</artifactId>
|
<artifactId>api-parent</artifactId>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
<version>1.11-SNAPSHOT</version>
|
<version>1.12.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>api-bukkit</artifactId>
|
<artifactId>api-bukkit</artifactId>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<groupId>tc.oc</groupId>
|
<groupId>tc.oc</groupId>
|
||||||
<artifactId>api-parent</artifactId>
|
<artifactId>api-parent</artifactId>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
<version>1.11-SNAPSHOT</version>
|
<version>1.12.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>api-bungee</artifactId>
|
<artifactId>api-bungee</artifactId>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<groupId>tc.oc</groupId>
|
<groupId>tc.oc</groupId>
|
||||||
<artifactId>api-parent</artifactId>
|
<artifactId>api-parent</artifactId>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
<version>1.11-SNAPSHOT</version>
|
<version>1.12.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>api-minecraft</artifactId>
|
<artifactId>api-minecraft</artifactId>
|
||||||
|
|
|
@ -2,6 +2,8 @@ package tc.oc.api.minecraft;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
@ -150,6 +152,14 @@ public class MinecraftServiceImpl implements MinecraftService, MessageListener,
|
||||||
handleLocalReconfigure(serverService.update(apiConfiguration.serverId(), startupDocument).get());
|
handleLocalReconfigure(serverService.update(apiConfiguration.serverId(), startupDocument).get());
|
||||||
|
|
||||||
logger.info("Connected to API as server." + getLocalServer()._id());
|
logger.info("Connected to API as server." + getLocalServer()._id());
|
||||||
|
|
||||||
|
if(apiConfiguration.publishIp()) {
|
||||||
|
String oldIp = server.ip(), newIp = startupDocument.ip();
|
||||||
|
if(!Objects.equals(oldIp, newIp)) {
|
||||||
|
updateLocalServer((ServerDoc.Ip) () -> newIp).get();
|
||||||
|
logger.info("Changed ip from " + oldIp + " to " + newIp);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
this.processIntoIOException(e);
|
this.processIntoIOException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,4 +12,6 @@ public interface MinecraftApiConfiguration extends ApiConfiguration {
|
||||||
String box();
|
String box();
|
||||||
|
|
||||||
ServerDoc.Role role();
|
ServerDoc.Role role();
|
||||||
|
|
||||||
|
boolean publishIp();
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,11 @@ public class MinecraftApiConfigurationImpl implements MinecraftApiConfiguration
|
||||||
return ServerDoc.Role.valueOf(config.getString("server.role").toUpperCase());
|
return ServerDoc.Role.valueOf(config.getString("server.role").toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean publishIp() {
|
||||||
|
return config.getBoolean("server.publishIp", false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String primaryQueueName() {
|
public String primaryQueueName() {
|
||||||
return "server." + serverId();
|
return "server." + serverId();
|
||||||
|
|
|
@ -23,7 +23,7 @@ import tc.oc.commons.core.commands.NestedCommands;
|
||||||
import tc.oc.commons.core.formatting.StringUtils;
|
import tc.oc.commons.core.formatting.StringUtils;
|
||||||
import tc.oc.minecraft.api.command.CommandSender;
|
import tc.oc.minecraft.api.command.CommandSender;
|
||||||
|
|
||||||
class ModelCommands implements NestedCommands {
|
public class ModelCommands implements NestedCommands {
|
||||||
|
|
||||||
public static class Parent implements Commands {
|
public static class Parent implements Commands {
|
||||||
@Command(
|
@Command(
|
||||||
|
|
|
@ -154,6 +154,11 @@ public class LocalServerDocument extends StartupServerDocument implements Server
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String domain() {
|
||||||
|
return "play.stratus.network";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String settings_profile() {
|
public String settings_profile() {
|
||||||
return "public";
|
return "public";
|
||||||
|
@ -218,6 +223,11 @@ public class LocalServerDocument extends StartupServerDocument implements Server
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String cross_server_profile() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<UUID, String> fake_usernames() {
|
public Map<UUID, String> fake_usernames() {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
|
@ -279,7 +289,12 @@ public class LocalServerDocument extends StartupServerDocument implements Server
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<MatchDoc.Mutation> queued_mutations() {
|
public Set<String> queued_mutations() {
|
||||||
return mutations != null ? mutations.queued_mutations() : Collections.emptySet();
|
return mutations != null ? mutations.queued_mutations() : Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ServerDoc.Rotation> rotations() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,7 @@ import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import tc.oc.api.docs.Server;
|
import tc.oc.api.docs.Server;
|
||||||
import tc.oc.api.docs.virtual.ServerDoc;
|
import tc.oc.api.docs.virtual.ServerDoc;
|
||||||
import tc.oc.api.message.types.FindMultiRequest;
|
import tc.oc.api.message.types.*;
|
||||||
import tc.oc.api.message.types.FindMultiResponse;
|
|
||||||
import tc.oc.api.message.types.FindRequest;
|
|
||||||
import tc.oc.api.message.types.PartialModelUpdate;
|
|
||||||
import tc.oc.api.message.types.UpdateMultiRequest;
|
|
||||||
import tc.oc.api.message.types.UpdateMultiResponse;
|
|
||||||
import tc.oc.api.model.NullModelService;
|
import tc.oc.api.model.NullModelService;
|
||||||
import tc.oc.api.servers.BungeeMetricRequest;
|
import tc.oc.api.servers.BungeeMetricRequest;
|
||||||
import tc.oc.api.servers.ServerService;
|
import tc.oc.api.servers.ServerService;
|
||||||
|
@ -54,4 +49,8 @@ public class LocalServerService extends NullModelService<Server, ServerDoc.Parti
|
||||||
request.documents().forEach(this::update);
|
request.documents().forEach(this::update);
|
||||||
return super.updateMulti(request);
|
return super.updateMulti(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public ListenableFuture<UseServerResponse> requestServer(UseServerRequest request) {
|
||||||
|
return Futures.immediateFuture(UseServerResponse.EMPTY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
package tc.oc.api.minecraft.servers;
|
package tc.oc.api.minecraft.servers;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URL;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -15,6 +20,7 @@ import com.google.common.io.Files;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import tc.oc.api.docs.virtual.DeployInfo;
|
import tc.oc.api.docs.virtual.DeployInfo;
|
||||||
import tc.oc.api.docs.virtual.ServerDoc;
|
import tc.oc.api.docs.virtual.ServerDoc;
|
||||||
|
import tc.oc.api.minecraft.config.MinecraftApiConfiguration;
|
||||||
import tc.oc.commons.core.logging.Loggers;
|
import tc.oc.commons.core.logging.Loggers;
|
||||||
import tc.oc.commons.core.util.Lazy;
|
import tc.oc.commons.core.util.Lazy;
|
||||||
import tc.oc.minecraft.api.plugin.PluginFinder;
|
import tc.oc.minecraft.api.plugin.PluginFinder;
|
||||||
|
@ -26,6 +32,7 @@ public class StartupServerDocument implements ServerDoc.Startup {
|
||||||
@Inject private Gson gson;
|
@Inject private Gson gson;
|
||||||
@Inject private LocalServer minecraftServer;
|
@Inject private LocalServer minecraftServer;
|
||||||
@Inject private PluginFinder pluginFinder;
|
@Inject private PluginFinder pluginFinder;
|
||||||
|
@Inject private MinecraftApiConfiguration configuration;
|
||||||
|
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
@Inject void init(Loggers loggers) {
|
@Inject void init(Loggers loggers) {
|
||||||
|
@ -51,6 +58,16 @@ public class StartupServerDocument implements ServerDoc.Startup {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private final Lazy<String> ip = Lazy.from(() -> {
|
||||||
|
try {
|
||||||
|
URL url = new URL("http://checkip.amazonaws.com");
|
||||||
|
return new BufferedReader(new InputStreamReader(url.openStream())).readLine();
|
||||||
|
} catch(IOException e) {
|
||||||
|
logger.log(Level.SEVERE, "Unable to find external ip", e);
|
||||||
|
return minecraftServer.getAddress().getHostName();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@Override public boolean online() {
|
@Override public boolean online() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -70,4 +87,8 @@ public class StartupServerDocument implements ServerDoc.Startup {
|
||||||
@Override public Set<Integer> protocol_versions() {
|
@Override public Set<Integer> protocol_versions() {
|
||||||
return minecraftServer.getProtocolVersions();
|
return minecraftServer.getProtocolVersions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String ip() {
|
||||||
|
return ip.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import tc.oc.api.docs.Session;
|
||||||
import tc.oc.api.docs.UserId;
|
import tc.oc.api.docs.UserId;
|
||||||
import tc.oc.api.minecraft.users.UserStore;
|
import tc.oc.api.minecraft.users.UserStore;
|
||||||
import tc.oc.minecraft.api.entity.Player;
|
import tc.oc.minecraft.api.entity.Player;
|
||||||
|
import tc.oc.minecraft.protocol.MinecraftVersion;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class LocalSessionFactory {
|
public class LocalSessionFactory {
|
||||||
|
@ -41,6 +42,13 @@ public class LocalSessionFactory {
|
||||||
return localServer._id();
|
return localServer._id();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String version() {
|
||||||
|
return userStore.byUserId(userId)
|
||||||
|
.map(player -> MinecraftVersion.describeProtocol(player.getProtocolVersion()))
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PlayerId user() {
|
public PlayerId user() {
|
||||||
return playerId;
|
return playerId;
|
||||||
|
|
|
@ -7,12 +7,14 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import tc.oc.api.docs.PlayerId;
|
import tc.oc.api.docs.PlayerId;
|
||||||
import tc.oc.api.docs.SimplePlayerId;
|
import tc.oc.api.docs.SimplePlayerId;
|
||||||
import tc.oc.api.docs.User;
|
import tc.oc.api.docs.User;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
import tc.oc.api.docs.virtual.UserDoc;
|
import tc.oc.api.docs.virtual.UserDoc;
|
||||||
import tc.oc.api.minecraft.servers.DefaultPermissions;
|
import tc.oc.api.minecraft.servers.DefaultPermissions;
|
||||||
|
|
||||||
|
@ -40,6 +42,11 @@ public class LocalUserDocument extends SimplePlayerId implements User {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Instant nickname_updated_at() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable String mc_locale() {
|
public @Nullable String mc_locale() {
|
||||||
return null;
|
return null;
|
||||||
|
@ -80,6 +87,16 @@ public class LocalUserDocument extends SimplePlayerId implements User {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int maptokens() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int mutationtokens() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String mc_last_sign_in_ip() {
|
public String mc_last_sign_in_ip() {
|
||||||
return ip;
|
return ip;
|
||||||
|
@ -90,6 +107,11 @@ public class LocalUserDocument extends SimplePlayerId implements User {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Map<String, Map<String, Object>>> stats_value() {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Map<String, Boolean>> mc_permissions_by_realm() {
|
public Map<String, Map<String, Boolean>> mc_permissions_by_realm() {
|
||||||
return ImmutableMap.of(
|
return ImmutableMap.of(
|
||||||
|
@ -121,4 +143,29 @@ public class LocalUserDocument extends SimplePlayerId implements User {
|
||||||
public int enemy_kills() {
|
public int enemy_kills() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String default_server_id() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int friend_tokens_limit() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int friend_tokens_concurrent() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String death_screen() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChatDoc.Type chat_channel() {
|
||||||
|
return ChatDoc.Type.TEAM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,17 +18,7 @@ import tc.oc.api.docs.virtual.UserDoc;
|
||||||
import tc.oc.api.exceptions.NotFound;
|
import tc.oc.api.exceptions.NotFound;
|
||||||
import tc.oc.api.minecraft.sessions.LocalSessionFactory;
|
import tc.oc.api.minecraft.sessions.LocalSessionFactory;
|
||||||
import tc.oc.api.model.NullModelService;
|
import tc.oc.api.model.NullModelService;
|
||||||
import tc.oc.api.users.ChangeClassRequest;
|
import tc.oc.api.users.*;
|
||||||
import tc.oc.api.users.ChangeSettingRequest;
|
|
||||||
import tc.oc.api.users.CreditRaindropsRequest;
|
|
||||||
import tc.oc.api.users.LoginRequest;
|
|
||||||
import tc.oc.api.users.LoginResponse;
|
|
||||||
import tc.oc.api.users.LogoutRequest;
|
|
||||||
import tc.oc.api.users.PurchaseGizmoRequest;
|
|
||||||
import tc.oc.api.users.UserSearchRequest;
|
|
||||||
import tc.oc.api.users.UserSearchResponse;
|
|
||||||
import tc.oc.api.users.UserService;
|
|
||||||
import tc.oc.api.users.UserUpdateResponse;
|
|
||||||
import tc.oc.commons.core.concurrent.FutureUtils;
|
import tc.oc.commons.core.concurrent.FutureUtils;
|
||||||
import tc.oc.minecraft.api.user.UserFinder;
|
import tc.oc.minecraft.api.user.UserFinder;
|
||||||
|
|
||||||
|
@ -118,8 +108,7 @@ class LocalUserService extends NullModelService<User, UserDoc.Partial> implement
|
||||||
return Futures.immediateFuture(null);
|
return Futures.immediateFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private ListenableFuture<UserUpdateResponse> update(UserId userId) {
|
||||||
public ListenableFuture<UserUpdateResponse> creditRaindrops(UserId userId, CreditRaindropsRequest request) {
|
|
||||||
return FutureUtils.mapSync(find(userId), user -> new UserUpdateResponse() {
|
return FutureUtils.mapSync(find(userId), user -> new UserUpdateResponse() {
|
||||||
@Override
|
@Override
|
||||||
public boolean success() {
|
public boolean success() {
|
||||||
|
@ -133,6 +122,31 @@ class LocalUserService extends NullModelService<User, UserDoc.Partial> implement
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<UserUpdateResponse> creditTokens(UserId userId, CreditTokensRequest request) {
|
||||||
|
return update(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<User> changeGroup(UserId userId, ChangeGroupRequest request) {
|
||||||
|
return find(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<FriendJoinResponse> joinFriend(UserId userId, FriendJoinRequest request) {
|
||||||
|
return Futures.immediateFuture(new FriendJoinResponse() {
|
||||||
|
@Override
|
||||||
|
public boolean authorized() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String message() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<User> purchaseGizmo(UserId userId, PurchaseGizmoRequest request) {
|
public ListenableFuture<User> purchaseGizmo(UserId userId, PurchaseGizmoRequest request) {
|
||||||
return find(userId);
|
return find(userId);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<groupId>tc.oc</groupId>
|
<groupId>tc.oc</groupId>
|
||||||
<artifactId>api-parent</artifactId>
|
<artifactId>api-parent</artifactId>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
<version>1.11-SNAPSHOT</version>
|
<version>1.12.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>api-ocn</artifactId>
|
<artifactId>api-ocn</artifactId>
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package tc.oc.api.ocn;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import tc.oc.api.docs.Friendship;
|
||||||
|
import tc.oc.api.docs.virtual.FriendshipDoc;
|
||||||
|
import tc.oc.api.friendships.FriendshipRequest;
|
||||||
|
import tc.oc.api.friendships.FriendshipResponse;
|
||||||
|
import tc.oc.api.friendships.FriendshipService;
|
||||||
|
import tc.oc.api.http.HttpOption;
|
||||||
|
import tc.oc.api.model.HttpModelService;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class OCNFriendshipService extends HttpModelService<Friendship, FriendshipDoc.Partial> implements FriendshipService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<FriendshipResponse> create(FriendshipRequest request) {
|
||||||
|
return this.client().post(collectionUri("create"), request, FriendshipResponse.class, HttpOption.INFINITE_RETRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<FriendshipResponse> destroy(FriendshipRequest request) {
|
||||||
|
return this.client().post(collectionUri("destroy"), request, FriendshipResponse.class, HttpOption.INFINITE_RETRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<FriendshipResponse> list(FriendshipRequest request) {
|
||||||
|
return this.client().post(collectionUri("list"), request, FriendshipResponse.class, HttpOption.INFINITE_RETRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package tc.oc.api.ocn;
|
package tc.oc.api.ocn;
|
||||||
|
|
||||||
import tc.oc.api.docs.Arena;
|
import tc.oc.api.docs.Arena;
|
||||||
|
import tc.oc.api.docs.Chat;
|
||||||
import tc.oc.api.docs.Death;
|
import tc.oc.api.docs.Death;
|
||||||
import tc.oc.api.docs.Game;
|
import tc.oc.api.docs.Game;
|
||||||
import tc.oc.api.docs.Objective;
|
import tc.oc.api.docs.Objective;
|
||||||
|
@ -8,11 +9,13 @@ import tc.oc.api.docs.Participation;
|
||||||
import tc.oc.api.docs.Punishment;
|
import tc.oc.api.docs.Punishment;
|
||||||
import tc.oc.api.docs.Report;
|
import tc.oc.api.docs.Report;
|
||||||
import tc.oc.api.docs.Trophy;
|
import tc.oc.api.docs.Trophy;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
import tc.oc.api.docs.virtual.DeathDoc;
|
import tc.oc.api.docs.virtual.DeathDoc;
|
||||||
import tc.oc.api.docs.virtual.MatchDoc;
|
import tc.oc.api.docs.virtual.MatchDoc;
|
||||||
import tc.oc.api.docs.virtual.PunishmentDoc;
|
import tc.oc.api.docs.virtual.PunishmentDoc;
|
||||||
import tc.oc.api.docs.virtual.ReportDoc;
|
import tc.oc.api.docs.virtual.ReportDoc;
|
||||||
import tc.oc.api.engagement.EngagementService;
|
import tc.oc.api.engagement.EngagementService;
|
||||||
|
import tc.oc.api.friendships.FriendshipService;
|
||||||
import tc.oc.api.games.TicketService;
|
import tc.oc.api.games.TicketService;
|
||||||
import tc.oc.api.maps.MapService;
|
import tc.oc.api.maps.MapService;
|
||||||
import tc.oc.api.model.ModelBinders;
|
import tc.oc.api.model.ModelBinders;
|
||||||
|
@ -46,6 +49,9 @@ public class OCNModelsManifest extends HybridManifest implements ModelBinders {
|
||||||
bindModel(Punishment.class, PunishmentDoc.Partial.class, model -> {
|
bindModel(Punishment.class, PunishmentDoc.Partial.class, model -> {
|
||||||
model.bindService().to(model.httpService());
|
model.bindService().to(model.httpService());
|
||||||
});
|
});
|
||||||
|
bindModel(Chat.class, ChatDoc.Partial.class, model -> {
|
||||||
|
model.bindService().to(model.httpService());
|
||||||
|
});
|
||||||
bindModel(MatchDoc.class, model -> {
|
bindModel(MatchDoc.class, model -> {
|
||||||
model.bindService().to(model.httpService());
|
model.bindService().to(model.httpService());
|
||||||
});
|
});
|
||||||
|
@ -58,7 +64,6 @@ public class OCNModelsManifest extends HybridManifest implements ModelBinders {
|
||||||
bindModel(Objective.class, model -> {
|
bindModel(Objective.class, model -> {
|
||||||
model.bindService().to(model.httpService());
|
model.bindService().to(model.httpService());
|
||||||
});
|
});
|
||||||
|
|
||||||
publicBinder().install(new Manifest() {
|
publicBinder().install(new Manifest() {
|
||||||
@Override protected void configure() {
|
@Override protected void configure() {
|
||||||
// Specialized AMQP services
|
// Specialized AMQP services
|
||||||
|
@ -72,6 +77,7 @@ public class OCNModelsManifest extends HybridManifest implements ModelBinders {
|
||||||
forOptional(TournamentService.class).setBinding().to(OCNTournamentService.class);
|
forOptional(TournamentService.class).setBinding().to(OCNTournamentService.class);
|
||||||
forOptional(UserService.class).setBinding().to(OCNUserService.class);
|
forOptional(UserService.class).setBinding().to(OCNUserService.class);
|
||||||
forOptional(WhisperService.class).setBinding().to(OCNWhisperService.class);
|
forOptional(WhisperService.class).setBinding().to(OCNWhisperService.class);
|
||||||
|
forOptional(FriendshipService.class).setBinding().to(OCNFriendshipService.class);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,12 @@ import tc.oc.api.docs.virtual.ServerDoc;
|
||||||
import tc.oc.api.http.HttpOption;
|
import tc.oc.api.http.HttpOption;
|
||||||
import tc.oc.api.message.types.FindMultiResponse;
|
import tc.oc.api.message.types.FindMultiResponse;
|
||||||
import tc.oc.api.message.types.FindRequest;
|
import tc.oc.api.message.types.FindRequest;
|
||||||
|
import tc.oc.api.message.types.UseServerRequest;
|
||||||
|
import tc.oc.api.message.types.UseServerResponse;
|
||||||
import tc.oc.api.model.HttpModelService;
|
import tc.oc.api.model.HttpModelService;
|
||||||
import tc.oc.api.queue.QueueQueryService;
|
import tc.oc.api.queue.QueueQueryService;
|
||||||
|
import tc.oc.api.queue.Transaction;
|
||||||
|
import tc.oc.api.queue.Transaction.Factory;
|
||||||
import tc.oc.api.servers.BungeeMetricRequest;
|
import tc.oc.api.servers.BungeeMetricRequest;
|
||||||
import tc.oc.api.servers.ServerService;
|
import tc.oc.api.servers.ServerService;
|
||||||
|
|
||||||
|
@ -19,9 +23,11 @@ import tc.oc.api.servers.ServerService;
|
||||||
class OCNServerService extends HttpModelService<Server, ServerDoc.Partial> implements ServerService {
|
class OCNServerService extends HttpModelService<Server, ServerDoc.Partial> implements ServerService {
|
||||||
|
|
||||||
private final QueueQueryService<Server> queryService;
|
private final QueueQueryService<Server> queryService;
|
||||||
|
private final Transaction.Factory transactionFactory;
|
||||||
|
|
||||||
@Inject OCNServerService(QueueQueryService<Server> queryService) {
|
@Inject public OCNServerService(QueueQueryService<Server> queryService, Factory transactionFactory) {
|
||||||
this.queryService = queryService;
|
this.queryService = queryService;
|
||||||
|
this.transactionFactory = transactionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,6 +35,10 @@ class OCNServerService extends HttpModelService<Server, ServerDoc.Partial> imple
|
||||||
return this.client().post("/servers/metric", request, HttpOption.INFINITE_RETRY);
|
return this.client().post("/servers/metric", request, HttpOption.INFINITE_RETRY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public ListenableFuture<UseServerResponse> requestServer(UseServerRequest request) {
|
||||||
|
return transactionFactory.request(request, UseServerResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<FindMultiResponse<Server>> all() {
|
public ListenableFuture<FindMultiResponse<Server>> all() {
|
||||||
return queryService.all();
|
return queryService.all();
|
||||||
|
|
|
@ -15,17 +15,7 @@ import tc.oc.api.message.types.PlayerTeleportRequest;
|
||||||
import tc.oc.api.minecraft.users.UserStore;
|
import tc.oc.api.minecraft.users.UserStore;
|
||||||
import tc.oc.api.model.HttpModelService;
|
import tc.oc.api.model.HttpModelService;
|
||||||
import tc.oc.api.queue.Exchange;
|
import tc.oc.api.queue.Exchange;
|
||||||
import tc.oc.api.users.ChangeClassRequest;
|
import tc.oc.api.users.*;
|
||||||
import tc.oc.api.users.ChangeSettingRequest;
|
|
||||||
import tc.oc.api.users.CreditRaindropsRequest;
|
|
||||||
import tc.oc.api.users.LoginRequest;
|
|
||||||
import tc.oc.api.users.LoginResponse;
|
|
||||||
import tc.oc.api.users.LogoutRequest;
|
|
||||||
import tc.oc.api.users.PurchaseGizmoRequest;
|
|
||||||
import tc.oc.api.users.UserSearchRequest;
|
|
||||||
import tc.oc.api.users.UserSearchResponse;
|
|
||||||
import tc.oc.api.users.UserService;
|
|
||||||
import tc.oc.api.users.UserUpdateResponse;
|
|
||||||
import tc.oc.commons.core.concurrent.FutureUtils;
|
import tc.oc.commons.core.concurrent.FutureUtils;
|
||||||
import tc.oc.minecraft.api.entity.Player;
|
import tc.oc.minecraft.api.entity.Player;
|
||||||
|
|
||||||
|
@ -82,13 +72,23 @@ class OCNUserService extends HttpModelService<User, UserDoc.Partial> implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<UserUpdateResponse> creditRaindrops(UserId userId, CreditRaindropsRequest request) {
|
public ListenableFuture<User> purchaseGizmo(UserId userId, PurchaseGizmoRequest request) {
|
||||||
return handleUserUpdate(client().post(memberUri(userId, "credit_raindrops"), request, UserUpdateResponse.class, HttpOption.INFINITE_RETRY));
|
return handleUpdate(client().post(memberUri(userId, "purchase_gizmo"), request, User.class, HttpOption.INFINITE_RETRY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<User> purchaseGizmo(UserId userId, PurchaseGizmoRequest request) {
|
public ListenableFuture<UserUpdateResponse> creditTokens(UserId userId, CreditTokensRequest request) {
|
||||||
return handleUpdate(client().post(memberUri(userId, "purchase_gizmo"), request, User.class, HttpOption.INFINITE_RETRY));
|
return handleUserUpdate(client().post(memberUri(userId, "credit_tokens"), request, UserUpdateResponse.class, HttpOption.INFINITE_RETRY));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<User> changeGroup(UserId userId, ChangeGroupRequest request) {
|
||||||
|
return handleUpdate(client().post(memberUri(userId, "change_group"), request, User.class, HttpOption.INFINITE_RETRY));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<FriendJoinResponse> joinFriend(UserId userId, FriendJoinRequest request) {
|
||||||
|
return client().post(memberUri(userId, "join_friend"), request, FriendJoinResponse.class, HttpOption.INFINITE_RETRY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<groupId>tc.oc</groupId>
|
<groupId>tc.oc</groupId>
|
||||||
<artifactId>ProjectAres</artifactId>
|
<artifactId>ProjectAres</artifactId>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
<version>1.11-SNAPSHOT</version>
|
<version>1.12.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>api-parent</artifactId>
|
<artifactId>api-parent</artifactId>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<artifactId>commons</artifactId>
|
<artifactId>commons</artifactId>
|
||||||
<groupId>tc.oc</groupId>
|
<groupId>tc.oc</groupId>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
<version>1.11-SNAPSHOT</version>
|
<version>1.12.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>commons-bukkit</artifactId>
|
<artifactId>commons-bukkit</artifactId>
|
||||||
|
@ -41,18 +41,6 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.rmsy.Channels</groupId>
|
|
||||||
<artifactId>Channels</artifactId>
|
|
||||||
<version>1.9-SNAPSHOT</version>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>bukkit</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>me.anxuiz</groupId>
|
<groupId>me.anxuiz</groupId>
|
||||||
<artifactId>bukkit-settings</artifactId>
|
<artifactId>bukkit-settings</artifactId>
|
||||||
|
|
|
@ -2,7 +2,6 @@ package tc.oc.bukkit.analytics;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import tc.oc.analytics.Gauge;
|
import tc.oc.analytics.Gauge;
|
||||||
import tc.oc.analytics.MetricFactory;
|
import tc.oc.analytics.MetricFactory;
|
||||||
import tc.oc.api.bukkit.users.OnlinePlayers;
|
import tc.oc.api.bukkit.users.OnlinePlayers;
|
||||||
|
|
|
@ -3,7 +3,6 @@ package tc.oc.bukkit.analytics;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import tc.oc.analytics.Count;
|
import tc.oc.analytics.Count;
|
||||||
import tc.oc.analytics.Gauge;
|
import tc.oc.analytics.Gauge;
|
||||||
import tc.oc.analytics.MetricFactory;
|
import tc.oc.analytics.MetricFactory;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package tc.oc.commons.bukkit;
|
package tc.oc.commons.bukkit;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
|
@ -12,7 +11,8 @@ import tc.oc.bukkit.analytics.BukkitPlayerReporter;
|
||||||
import tc.oc.bukkit.analytics.LatencyReporter;
|
import tc.oc.bukkit.analytics.LatencyReporter;
|
||||||
import tc.oc.bukkit.analytics.TickReporter;
|
import tc.oc.bukkit.analytics.TickReporter;
|
||||||
import tc.oc.commons.bukkit.broadcast.BroadcastManifest;
|
import tc.oc.commons.bukkit.broadcast.BroadcastManifest;
|
||||||
import tc.oc.commons.bukkit.channels.AdminChatManifest;
|
import tc.oc.commons.bukkit.channels.ChannelManifest;
|
||||||
|
import tc.oc.commons.bukkit.chat.ChatManifest;
|
||||||
import tc.oc.commons.bukkit.chat.ComponentRenderContext;
|
import tc.oc.commons.bukkit.chat.ComponentRenderContext;
|
||||||
import tc.oc.commons.bukkit.chat.ComponentRendererRegistry;
|
import tc.oc.commons.bukkit.chat.ComponentRendererRegistry;
|
||||||
import tc.oc.commons.bukkit.chat.ComponentRenderers;
|
import tc.oc.commons.bukkit.chat.ComponentRenderers;
|
||||||
|
@ -24,6 +24,8 @@ import tc.oc.commons.bukkit.chat.TextComponentRenderer;
|
||||||
import tc.oc.commons.bukkit.chat.TranslatableComponentRenderer;
|
import tc.oc.commons.bukkit.chat.TranslatableComponentRenderer;
|
||||||
import tc.oc.commons.bukkit.chat.UserTextComponent;
|
import tc.oc.commons.bukkit.chat.UserTextComponent;
|
||||||
import tc.oc.commons.bukkit.chat.UserTextComponentRenderer;
|
import tc.oc.commons.bukkit.chat.UserTextComponentRenderer;
|
||||||
|
import tc.oc.commons.bukkit.commands.GroupCommands;
|
||||||
|
import tc.oc.commons.bukkit.commands.MiscCommands;
|
||||||
import tc.oc.commons.bukkit.commands.PermissionCommands;
|
import tc.oc.commons.bukkit.commands.PermissionCommands;
|
||||||
import tc.oc.commons.bukkit.commands.ServerCommands;
|
import tc.oc.commons.bukkit.commands.ServerCommands;
|
||||||
import tc.oc.commons.bukkit.commands.ServerVisibilityCommands;
|
import tc.oc.commons.bukkit.commands.ServerVisibilityCommands;
|
||||||
|
@ -33,6 +35,7 @@ import tc.oc.commons.bukkit.commands.UserCommands;
|
||||||
import tc.oc.commons.bukkit.commands.UserFinder;
|
import tc.oc.commons.bukkit.commands.UserFinder;
|
||||||
import tc.oc.commons.bukkit.debug.LeakListener;
|
import tc.oc.commons.bukkit.debug.LeakListener;
|
||||||
import tc.oc.commons.bukkit.event.targeted.TargetedEventManifest;
|
import tc.oc.commons.bukkit.event.targeted.TargetedEventManifest;
|
||||||
|
import tc.oc.commons.bukkit.flairs.FlairConfiguration;
|
||||||
import tc.oc.commons.bukkit.format.ServerFormatter;
|
import tc.oc.commons.bukkit.format.ServerFormatter;
|
||||||
import tc.oc.commons.bukkit.freeze.PlayerFreezer;
|
import tc.oc.commons.bukkit.freeze.PlayerFreezer;
|
||||||
import tc.oc.commons.bukkit.inject.BukkitPluginManifest;
|
import tc.oc.commons.bukkit.inject.BukkitPluginManifest;
|
||||||
|
@ -60,17 +63,19 @@ import tc.oc.commons.bukkit.nick.PlayerOrder;
|
||||||
import tc.oc.commons.bukkit.nick.PlayerOrderCache;
|
import tc.oc.commons.bukkit.nick.PlayerOrderCache;
|
||||||
import tc.oc.commons.bukkit.punishment.PunishmentManifest;
|
import tc.oc.commons.bukkit.punishment.PunishmentManifest;
|
||||||
import tc.oc.commons.bukkit.raindrops.RaindropManifest;
|
import tc.oc.commons.bukkit.raindrops.RaindropManifest;
|
||||||
import tc.oc.commons.bukkit.report.ReportAnnouncer;
|
import tc.oc.commons.bukkit.report.ReportManifest;
|
||||||
import tc.oc.commons.bukkit.report.ReportCommands;
|
|
||||||
import tc.oc.commons.bukkit.respack.ResourcePackCommands;
|
import tc.oc.commons.bukkit.respack.ResourcePackCommands;
|
||||||
import tc.oc.commons.bukkit.respack.ResourcePackListener;
|
import tc.oc.commons.bukkit.respack.ResourcePackListener;
|
||||||
import tc.oc.commons.bukkit.respack.ResourcePackManager;
|
import tc.oc.commons.bukkit.respack.ResourcePackManager;
|
||||||
import tc.oc.commons.bukkit.restart.RestartCommands;
|
import tc.oc.commons.bukkit.restart.RestartCommands;
|
||||||
import tc.oc.commons.bukkit.sessions.SessionListener;
|
import tc.oc.commons.bukkit.sessions.SessionListener;
|
||||||
import tc.oc.commons.bukkit.settings.SettingManifest;
|
import tc.oc.commons.bukkit.settings.SettingManifest;
|
||||||
|
import tc.oc.commons.bukkit.stats.StatsManifest;
|
||||||
import tc.oc.commons.bukkit.suspend.SuspendListener;
|
import tc.oc.commons.bukkit.suspend.SuspendListener;
|
||||||
import tc.oc.commons.bukkit.tablist.PlayerTabEntry;
|
import tc.oc.commons.bukkit.tablist.PlayerTabEntry;
|
||||||
import tc.oc.commons.bukkit.tablist.TabRender;
|
import tc.oc.commons.bukkit.tablist.TabRender;
|
||||||
|
import tc.oc.commons.bukkit.teleport.Navigator;
|
||||||
|
import tc.oc.commons.bukkit.teleport.NavigatorInterface;
|
||||||
import tc.oc.commons.bukkit.teleport.NavigatorManifest;
|
import tc.oc.commons.bukkit.teleport.NavigatorManifest;
|
||||||
import tc.oc.commons.bukkit.teleport.PlayerServerChanger;
|
import tc.oc.commons.bukkit.teleport.PlayerServerChanger;
|
||||||
import tc.oc.commons.bukkit.teleport.TeleportCommands;
|
import tc.oc.commons.bukkit.teleport.TeleportCommands;
|
||||||
|
@ -80,6 +85,7 @@ import tc.oc.commons.bukkit.ticket.TicketBooth;
|
||||||
import tc.oc.commons.bukkit.ticket.TicketCommands;
|
import tc.oc.commons.bukkit.ticket.TicketCommands;
|
||||||
import tc.oc.commons.bukkit.ticket.TicketDisplay;
|
import tc.oc.commons.bukkit.ticket.TicketDisplay;
|
||||||
import tc.oc.commons.bukkit.ticket.TicketListener;
|
import tc.oc.commons.bukkit.ticket.TicketListener;
|
||||||
|
import tc.oc.commons.bukkit.tokens.TokenManifest;
|
||||||
import tc.oc.commons.bukkit.trophies.TrophyCase;
|
import tc.oc.commons.bukkit.trophies.TrophyCase;
|
||||||
import tc.oc.commons.bukkit.trophies.TrophyCommands;
|
import tc.oc.commons.bukkit.trophies.TrophyCommands;
|
||||||
import tc.oc.commons.bukkit.users.JoinMessageManifest;
|
import tc.oc.commons.bukkit.users.JoinMessageManifest;
|
||||||
|
@ -105,11 +111,15 @@ public final class CommonsBukkitManifest extends HybridManifest {
|
||||||
install(new SettingManifest());
|
install(new SettingManifest());
|
||||||
install(new WhisperManifest());
|
install(new WhisperManifest());
|
||||||
install(new JoinMessageManifest());
|
install(new JoinMessageManifest());
|
||||||
install(new AdminChatManifest());
|
install(new ChatManifest());
|
||||||
|
install(new ChannelManifest());
|
||||||
install(new BroadcastManifest());
|
install(new BroadcastManifest());
|
||||||
install(new LocalizationManifest());
|
install(new LocalizationManifest());
|
||||||
install(new NavigatorManifest());
|
install(new NavigatorManifest());
|
||||||
install(new RaindropManifest());
|
install(new RaindropManifest());
|
||||||
|
install(new ReportManifest());
|
||||||
|
install(new TokenManifest());
|
||||||
|
install(new StatsManifest());
|
||||||
install(new PunishmentManifest());
|
install(new PunishmentManifest());
|
||||||
|
|
||||||
// These are already bound as facets, so they only need to be exposed
|
// These are already bound as facets, so they only need to be exposed
|
||||||
|
@ -119,6 +129,7 @@ public final class CommonsBukkitManifest extends HybridManifest {
|
||||||
expose(TicketDisplay.class);
|
expose(TicketDisplay.class);
|
||||||
expose(TicketListener.class);
|
expose(TicketListener.class);
|
||||||
|
|
||||||
|
bindAndExpose(FlairConfiguration.class);
|
||||||
bindAndExpose(PlayerAppearanceChanger.class);
|
bindAndExpose(PlayerAppearanceChanger.class);
|
||||||
bindAndExpose(UserFinder.class);
|
bindAndExpose(UserFinder.class);
|
||||||
bindAndExpose(Teleporter.class);
|
bindAndExpose(Teleporter.class);
|
||||||
|
@ -155,6 +166,9 @@ public final class CommonsBukkitManifest extends HybridManifest {
|
||||||
facets.register(LeakListener.class);
|
facets.register(LeakListener.class);
|
||||||
facets.register(LocaleListener.class);
|
facets.register(LocaleListener.class);
|
||||||
facets.register(LoginListener.class);
|
facets.register(LoginListener.class);
|
||||||
|
facets.register(MiscCommands.class);
|
||||||
|
facets.register(Navigator.class);
|
||||||
|
facets.register(NavigatorInterface.class);
|
||||||
facets.register(NicknameCommands.class);
|
facets.register(NicknameCommands.class);
|
||||||
facets.register(PermissionCommands.class);
|
facets.register(PermissionCommands.class);
|
||||||
facets.register(PermissionCommands.Parent.class);
|
facets.register(PermissionCommands.Parent.class);
|
||||||
|
@ -163,8 +177,6 @@ public final class CommonsBukkitManifest extends HybridManifest {
|
||||||
facets.register(PlayerFreezer.class);
|
facets.register(PlayerFreezer.class);
|
||||||
facets.register(PlayerOrderCache.class);
|
facets.register(PlayerOrderCache.class);
|
||||||
facets.register(PlayerServerChanger.class);
|
facets.register(PlayerServerChanger.class);
|
||||||
facets.register(ReportAnnouncer.class);
|
|
||||||
facets.register(ReportCommands.class);
|
|
||||||
facets.register(ResourcePackCommands.class);
|
facets.register(ResourcePackCommands.class);
|
||||||
facets.register(ResourcePackCommands.Parent.class);
|
facets.register(ResourcePackCommands.Parent.class);
|
||||||
facets.register(ResourcePackListener.class);
|
facets.register(ResourcePackListener.class);
|
||||||
|
@ -189,6 +201,7 @@ public final class CommonsBukkitManifest extends HybridManifest {
|
||||||
facets.register(WindowManager.class);
|
facets.register(WindowManager.class);
|
||||||
facets.register(AppealAlertListener.class);
|
facets.register(AppealAlertListener.class);
|
||||||
facets.register(SuspendListener.class);
|
facets.register(SuspendListener.class);
|
||||||
|
facets.register(GroupCommands.Parent.class);
|
||||||
|
|
||||||
// DataDog
|
// DataDog
|
||||||
facets.register(TickReporter.class);
|
facets.register(TickReporter.class);
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package tc.oc.commons.bukkit.broadcast;
|
package tc.oc.commons.bukkit.broadcast;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import java.util.Map;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package tc.oc.commons.bukkit.broadcast;
|
package tc.oc.commons.bukkit.broadcast;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
|
import java.util.List;
|
||||||
import tc.oc.commons.bukkit.broadcast.model.BroadcastPrefix;
|
import tc.oc.commons.bukkit.broadcast.model.BroadcastPrefix;
|
||||||
import tc.oc.commons.bukkit.broadcast.model.BroadcastSchedule;
|
import tc.oc.commons.bukkit.broadcast.model.BroadcastSchedule;
|
||||||
import tc.oc.commons.bukkit.settings.SettingBinder;
|
import tc.oc.commons.bukkit.settings.SettingBinder;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package tc.oc.commons.bukkit.broadcast;
|
package tc.oc.commons.bukkit.broadcast;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import org.w3c.dom.Attr;
|
||||||
import java.time.Duration;
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import tc.oc.commons.bukkit.broadcast.model.BroadcastPrefix;
|
import tc.oc.commons.bukkit.broadcast.model.BroadcastPrefix;
|
||||||
|
@ -44,8 +44,13 @@ public class BroadcastParser implements DocumentParser<List<BroadcastSchedule>>
|
||||||
}
|
}
|
||||||
|
|
||||||
public BroadcastSchedule parseSchedule(Element el) throws ParseException {
|
public BroadcastSchedule parseSchedule(Element el) throws ParseException {
|
||||||
|
Duration delay = Duration.ZERO;
|
||||||
|
Attr delayAttr = el.getAttributeNode("delay");
|
||||||
|
if (delayAttr != null) {
|
||||||
|
delay = durationParser.parse(delayAttr);
|
||||||
|
}
|
||||||
return new BroadcastSchedule(
|
return new BroadcastSchedule(
|
||||||
durationParser.parse(XML.requireAttr(el, "interval")),
|
delay, durationParser.parse(XML.requireAttr(el, "interval")),
|
||||||
serverFilterParser.parse(el), XML.childrenNamed(el, "messages").map(this::parseMessages)
|
serverFilterParser.parse(el), XML.childrenNamed(el, "messages").map(this::parseMessages)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package tc.oc.commons.bukkit.broadcast;
|
package tc.oc.commons.bukkit.broadcast;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -10,9 +12,6 @@ import java.util.stream.Stream;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
import tc.oc.api.bukkit.users.OnlinePlayers;
|
import tc.oc.api.bukkit.users.OnlinePlayers;
|
||||||
|
@ -123,7 +122,7 @@ public class BroadcastScheduler implements PluginFacet {
|
||||||
set -> messageMapFactory.create(configPath.resolve(SOURCES_PATH).resolve(set.path()),
|
set -> messageMapFactory.create(configPath.resolve(SOURCES_PATH).resolve(set.path()),
|
||||||
TRANSLATIONS_PATH.resolve(set.path())))
|
TRANSLATIONS_PATH.resolve(set.path())))
|
||||||
);
|
);
|
||||||
this.task = scheduler.createRepeatingTask(schedule.interval(), this::dispatch);
|
this.task = scheduler.createRepeatingTask(schedule.delay(), schedule.interval(), this::dispatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispatch() {
|
void dispatch() {
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
package tc.oc.commons.bukkit.broadcast;
|
||||||
|
|
||||||
|
import static tc.oc.api.util.Permissions.hasPermissionForEnum;
|
||||||
|
import static tc.oc.commons.bukkit.commands.CommandUtils.newCommandException;
|
||||||
|
import static tc.oc.commons.bukkit.commands.CommandUtils.tryEnum;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.sk89q.minecraft.util.commands.Command;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandException;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
|
||||||
|
import com.sk89q.minecraft.util.commands.SuggestionContext;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import tc.oc.api.bukkit.users.BukkitUserStore;
|
||||||
|
import tc.oc.api.docs.Chat;
|
||||||
|
import tc.oc.api.docs.Game;
|
||||||
|
import tc.oc.api.docs.Server;
|
||||||
|
import tc.oc.api.docs.User;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
|
import tc.oc.api.games.GameStore;
|
||||||
|
import tc.oc.api.servers.ServerStore;
|
||||||
|
import tc.oc.commons.bukkit.chat.Audiences;
|
||||||
|
import tc.oc.commons.bukkit.chat.BukkitSound;
|
||||||
|
import tc.oc.commons.bukkit.chat.ChatCreator;
|
||||||
|
import tc.oc.commons.bukkit.chat.PlayerComponent;
|
||||||
|
import tc.oc.commons.bukkit.chat.WarningComponent;
|
||||||
|
import tc.oc.commons.bukkit.commands.CommandUtils;
|
||||||
|
import tc.oc.commons.bukkit.nick.IdentityProvider;
|
||||||
|
import tc.oc.commons.core.chat.Audience;
|
||||||
|
import tc.oc.commons.core.chat.Component;
|
||||||
|
import tc.oc.commons.core.commands.Commands;
|
||||||
|
import tc.oc.commons.core.formatting.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows {@link User}s to broadcast {@link Chat} messages across multiple servers.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class BroadcastSender implements Commands {
|
||||||
|
|
||||||
|
private final static String PERMISSION = "ocn.broadcast";
|
||||||
|
|
||||||
|
private final Server server;
|
||||||
|
private final ServerStore serverStore;
|
||||||
|
private final GameStore gameStore;
|
||||||
|
private final ChatCreator chatCreator;
|
||||||
|
private final Audiences audiences;
|
||||||
|
private final BukkitUserStore userStore;
|
||||||
|
private final IdentityProvider identityProvider;
|
||||||
|
|
||||||
|
@Inject BroadcastSender(Server server, ServerStore serverStore, GameStore gameStore, ChatCreator chatCreator, Audiences audiences, BukkitUserStore userStore, IdentityProvider identityProvider) {
|
||||||
|
this.server = server;
|
||||||
|
this.serverStore = serverStore;
|
||||||
|
this.gameStore = gameStore;
|
||||||
|
this.chatCreator = chatCreator;
|
||||||
|
this.audiences = audiences;
|
||||||
|
this.userStore = userStore;
|
||||||
|
this.identityProvider = identityProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> destinations(@Nullable ChatDoc.Destination type) {
|
||||||
|
Stream<String> options = Stream.empty();
|
||||||
|
if(type != null) {
|
||||||
|
switch(type) {
|
||||||
|
case SERVER:
|
||||||
|
options = serverStore.all().map(Server::name);
|
||||||
|
break;
|
||||||
|
case FAMILY:
|
||||||
|
options = serverStore.all().map(Server::family);
|
||||||
|
break;
|
||||||
|
case GAME:
|
||||||
|
options = gameStore.all().map(Game::name);
|
||||||
|
break;
|
||||||
|
case NETWORK:
|
||||||
|
options = serverStore.all().map(Server::network).map(Enum::name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return options.map(String::toLowerCase).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "broadcast", "b" },
|
||||||
|
desc = "Broadcast a message to players across the network.",
|
||||||
|
usage = "<destination type> <destination name> [message...]",
|
||||||
|
min = 1
|
||||||
|
)
|
||||||
|
public List<String> broadcast(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
SuggestionContext suggest = args.getSuggestionContext();
|
||||||
|
ChatDoc.Destination type = tryEnum(args.getString(0, ""), ChatDoc.Destination.class);
|
||||||
|
Set<String> destinations = destinations(type);
|
||||||
|
String message = "";
|
||||||
|
String destination = "";
|
||||||
|
|
||||||
|
if(suggest != null) {
|
||||||
|
switch(suggest.getIndex()) {
|
||||||
|
case 0:
|
||||||
|
return CommandUtils.completeEnum(args.getString(0), ChatDoc.Destination.class);
|
||||||
|
case 1:
|
||||||
|
if(type != null && type != ChatDoc.Destination.GLOBAL) {
|
||||||
|
return StringUtils.complete(args.getString(1), destinations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == null) {
|
||||||
|
type = ChatDoc.Destination.SERVER;
|
||||||
|
destination = server._id();
|
||||||
|
message = args.getJoinedStrings(0);
|
||||||
|
} else if(args.argsLength() >= 2) {
|
||||||
|
if(type == ChatDoc.Destination.GLOBAL) {
|
||||||
|
destination = null;
|
||||||
|
message = args.getJoinedStrings(1);
|
||||||
|
} else if(args.argsLength() >= 3) {
|
||||||
|
destination = args.getString(1);
|
||||||
|
message = args.getJoinedStrings(2);
|
||||||
|
if(!destinations.contains(destination)) {
|
||||||
|
throw newCommandException(sender, new WarningComponent("command.error.invalidOption", destination, destinations));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CommandUtils.notEnoughArguments(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hasPermissionForEnum(sender, PERMISSION, type)) {
|
||||||
|
chatCreator.broadcast(
|
||||||
|
sender instanceof Player ? userStore.tryUser((Player) sender) : null,
|
||||||
|
message,
|
||||||
|
type,
|
||||||
|
destination
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new CommandPermissionsException();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show(Chat chat) {
|
||||||
|
final Audience audience = audiences.all();
|
||||||
|
audience.playSound(new BukkitSound(Sound.ENTITY_ENDERDRAGON_HURT, 1, 1));
|
||||||
|
audience.sendMessage(
|
||||||
|
new Component(
|
||||||
|
Lists.newArrayList(
|
||||||
|
new Component("["),
|
||||||
|
new TranslatableComponent("broadcast.prefix"),
|
||||||
|
new Component("] "),
|
||||||
|
new Component(chat.message())
|
||||||
|
), ChatColor.RED
|
||||||
|
).hoverEvent(
|
||||||
|
HoverEvent.Action.SHOW_TEXT,
|
||||||
|
new TranslatableComponent(
|
||||||
|
"tip.sentBy",
|
||||||
|
new PlayerComponent(identityProvider.currentOrConsoleIdentity(chat.sender()))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package tc.oc.commons.bukkit.broadcast;
|
package tc.oc.commons.bukkit.broadcast;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import me.anxuiz.settings.Setting;
|
import me.anxuiz.settings.Setting;
|
||||||
import me.anxuiz.settings.SettingBuilder;
|
import me.anxuiz.settings.SettingBuilder;
|
||||||
import me.anxuiz.settings.types.BooleanType;
|
import me.anxuiz.settings.types.BooleanType;
|
||||||
|
@ -57,7 +56,6 @@ public class BroadcastSettings {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NEWS:
|
case NEWS:
|
||||||
case ALERT:
|
|
||||||
setting = NEWS;
|
setting = NEWS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -70,6 +68,7 @@ public class BroadcastSettings {
|
||||||
setting = RANDOM;
|
setting = RANDOM;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ALERT:
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package tc.oc.commons.bukkit.broadcast.model;
|
package tc.oc.commons.bukkit.broadcast.model;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import tc.oc.commons.core.inspect.Inspectable;
|
import tc.oc.commons.core.inspect.Inspectable;
|
||||||
import tc.oc.commons.core.stream.Collectors;
|
import tc.oc.commons.core.stream.Collectors;
|
||||||
import tc.oc.minecraft.server.ServerFilter;
|
import tc.oc.minecraft.server.ServerFilter;
|
||||||
|
@ -14,11 +13,13 @@ import tc.oc.minecraft.server.ServerFilter;
|
||||||
*/
|
*/
|
||||||
public class BroadcastSchedule extends Inspectable.Impl {
|
public class BroadcastSchedule extends Inspectable.Impl {
|
||||||
|
|
||||||
|
@Inspect private final Duration delay;
|
||||||
@Inspect private final Duration interval;
|
@Inspect private final Duration interval;
|
||||||
@Inspect private final ImmutableList<BroadcastSet> messages;
|
@Inspect private final ImmutableList<BroadcastSet> messages;
|
||||||
@Inspect private final ServerFilter serverFilter;
|
@Inspect private final ServerFilter serverFilter;
|
||||||
|
|
||||||
public BroadcastSchedule(Duration interval, ServerFilter serverFilter, Stream<BroadcastSet> messages) {
|
public BroadcastSchedule(Duration delay, Duration interval, ServerFilter serverFilter, Stream<BroadcastSet> messages) {
|
||||||
|
this.delay = delay;
|
||||||
this.interval = interval;
|
this.interval = interval;
|
||||||
this.serverFilter = serverFilter;
|
this.serverFilter = serverFilter;
|
||||||
this.messages = messages.collect(Collectors.toImmutableList());
|
this.messages = messages.collect(Collectors.toImmutableList());
|
||||||
|
@ -31,6 +32,13 @@ public class BroadcastSchedule extends Inspectable.Impl {
|
||||||
return interval;
|
return interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time before first broadcast
|
||||||
|
*/
|
||||||
|
public Duration delay() {
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Relative path of the localized message list.
|
* Relative path of the localized message list.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package tc.oc.commons.bukkit.broadcast.model;
|
package tc.oc.commons.bukkit.broadcast.model;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import tc.oc.commons.core.inspect.Inspectable;
|
import tc.oc.commons.core.inspect.Inspectable;
|
||||||
|
|
||||||
public class BroadcastSet extends Inspectable.Impl {
|
public class BroadcastSet extends Inspectable.Impl {
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
package tc.oc.commons.bukkit.channels;
|
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import com.github.rmsy.channels.Channel;
|
|
||||||
import com.github.rmsy.channels.ChannelsPlugin;
|
|
||||||
import com.github.rmsy.channels.PlayerManager;
|
|
||||||
import com.github.rmsy.channels.event.ChannelMessageEvent;
|
|
||||||
import com.github.rmsy.channels.impl.SimpleChannel;
|
|
||||||
import com.sk89q.minecraft.util.commands.Command;
|
|
||||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
|
||||||
import com.sk89q.minecraft.util.commands.CommandException;
|
|
||||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
|
||||||
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
|
|
||||||
import com.sk89q.minecraft.util.commands.CommandUsageException;
|
|
||||||
import com.sk89q.minecraft.util.commands.Console;
|
|
||||||
import me.anxuiz.settings.Setting;
|
|
||||||
import me.anxuiz.settings.SettingBuilder;
|
|
||||||
import me.anxuiz.settings.types.BooleanType;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.permissions.Permission;
|
|
||||||
import org.bukkit.permissions.PermissionDefault;
|
|
||||||
import tc.oc.api.bukkit.users.OnlinePlayers;
|
|
||||||
import tc.oc.commons.bukkit.settings.SettingManagerProvider;
|
|
||||||
import tc.oc.commons.core.commands.Commands;
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
public class AdminChannel extends SimpleChannel implements Commands {
|
|
||||||
|
|
||||||
static final Setting SETTING = new SettingBuilder()
|
|
||||||
.name("AdminChat").alias("ac")
|
|
||||||
.summary("Show confidential staff info")
|
|
||||||
.type(new BooleanType())
|
|
||||||
.defaultValue(true).get();
|
|
||||||
|
|
||||||
public static final String PERM_NODE = "chat.admin";
|
|
||||||
public static final String PERM_SEND = PERM_NODE + ".send";
|
|
||||||
public static final String PERM_RECEIVE = PERM_NODE + ".receive";
|
|
||||||
|
|
||||||
public static final String PREFIX = ChatColor.WHITE + "[" + ChatColor.GOLD + "A" + ChatColor.WHITE + "]";
|
|
||||||
public static final String BROADCAST_FORMAT = PREFIX + " {2}";
|
|
||||||
public static final String FORMAT = PREFIX + " {1}" + ChatColor.WHITE + ": {2}";
|
|
||||||
|
|
||||||
private final ConsoleCommandSender console;
|
|
||||||
private final OnlinePlayers players;
|
|
||||||
private final SettingManagerProvider settings;
|
|
||||||
|
|
||||||
@Inject AdminChannel(ConsoleCommandSender console, OnlinePlayers players, SettingManagerProvider settings) {
|
|
||||||
super(FORMAT, BROADCAST_FORMAT, new Permission(PERM_RECEIVE, PermissionDefault.OP));
|
|
||||||
this.players = players;
|
|
||||||
this.settings = settings;
|
|
||||||
this.console = console;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Command(aliases = "a",
|
|
||||||
desc = "Sends a message to the staff channel (or sets the staff channel to your default channel).",
|
|
||||||
max = -1,
|
|
||||||
min = 0,
|
|
||||||
anyFlags = true,
|
|
||||||
usage = "[message...]")
|
|
||||||
@Console
|
|
||||||
@CommandPermissions({PERM_SEND, PERM_RECEIVE})
|
|
||||||
public void onAdminChatCommand(final CommandContext arguments, final CommandSender sender) throws CommandException {
|
|
||||||
if(arguments.argsLength() == 0) {
|
|
||||||
if (sender.hasPermission(PERM_RECEIVE)) {
|
|
||||||
if (sender instanceof Player) {
|
|
||||||
Player player = (Player) sender;
|
|
||||||
PlayerManager playerManager = ChannelsPlugin.get().getPlayerManager();
|
|
||||||
Channel oldChannel = playerManager.getMembershipChannel(player);
|
|
||||||
playerManager.setMembershipChannel(player, this);
|
|
||||||
if (!oldChannel.equals(this)) {
|
|
||||||
sender.sendMessage(org.bukkit.ChatColor.YELLOW + "Changed default channel to administrator chat");
|
|
||||||
} else {
|
|
||||||
throw new CommandException("Administrator chat is already your default channel");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new CommandUsageException("You must provide a message.", "/a <message...>");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new CommandPermissionsException();
|
|
||||||
}
|
|
||||||
} else if (sender.hasPermission(PERM_SEND)) {
|
|
||||||
Player sendingPlayer = null;
|
|
||||||
if (sender instanceof Player) {
|
|
||||||
sendingPlayer = (Player) sender;
|
|
||||||
}
|
|
||||||
this.sendMessage(arguments.getJoinedStrings(0), sendingPlayer);
|
|
||||||
if (!sender.hasPermission(PERM_RECEIVE)) {
|
|
||||||
sender.sendMessage(org.bukkit.ChatColor.YELLOW + "Message sent");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new CommandPermissionsException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessageToViewer(Player sender, CommandSender viewer, String sanitizedMessage, ChannelMessageEvent event) {
|
|
||||||
if(viewer != null && !isEnabled(viewer)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.sendMessageToViewer(sender, viewer, sanitizedMessage, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnabled(Player viewer) {
|
|
||||||
return (boolean) settings.getManager(viewer)
|
|
||||||
.getValue(SETTING);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnabled(CommandSender viewer) {
|
|
||||||
return !(viewer instanceof Player) || isEnabled((Player) viewer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVisible(CommandSender viewer) {
|
|
||||||
return viewer.hasPermission(getListeningPermission()) &&
|
|
||||||
isEnabled(viewer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stream<CommandSender> viewers() {
|
|
||||||
return Stream.<CommandSender>concat(Stream.of(console),
|
|
||||||
players.all().stream())
|
|
||||||
.filter(this::isVisible);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package tc.oc.commons.bukkit.channels;
|
|
||||||
|
|
||||||
import tc.oc.commons.bukkit.settings.SettingBinder;
|
|
||||||
import tc.oc.commons.core.inject.HybridManifest;
|
|
||||||
import tc.oc.commons.core.plugin.PluginFacetBinder;
|
|
||||||
|
|
||||||
public class AdminChatManifest extends HybridManifest {
|
|
||||||
@Override
|
|
||||||
protected void configure() {
|
|
||||||
new SettingBinder(publicBinder())
|
|
||||||
.addBinding().toInstance(AdminChannel.SETTING);
|
|
||||||
|
|
||||||
new PluginFacetBinder(binder())
|
|
||||||
.register(AdminChannel.class);
|
|
||||||
|
|
||||||
expose(AdminChannel.class);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package tc.oc.commons.bukkit.channels;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import tc.oc.api.docs.Chat;
|
||||||
|
import tc.oc.api.docs.PlayerId;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
|
import tc.oc.commons.core.chat.Audience;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link Audience} that sends {@link Chat} messages to the API.
|
||||||
|
*/
|
||||||
|
public interface Channel extends Audience {
|
||||||
|
|
||||||
|
ChatDoc.Type type();
|
||||||
|
|
||||||
|
void chat(CommandSender sender, String message);
|
||||||
|
|
||||||
|
void chat(@Nullable PlayerId playerId, String message);
|
||||||
|
|
||||||
|
void show(Chat message);
|
||||||
|
|
||||||
|
boolean sendable(CommandSender sender);
|
||||||
|
|
||||||
|
boolean viewable(CommandSender sender);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package tc.oc.commons.bukkit.channels;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import tc.oc.api.docs.PlayerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a command sender chats in a local {@link Channel}.
|
||||||
|
* If cancelled, the message will not be seen by users or reported to the API.
|
||||||
|
*/
|
||||||
|
public class ChannelChatEvent extends Event implements Cancellable {
|
||||||
|
private final static HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
private final Channel channel;
|
||||||
|
private final PlayerId sender;
|
||||||
|
private final String message;
|
||||||
|
private boolean cancelled;
|
||||||
|
|
||||||
|
public ChannelChatEvent(Channel channel, PlayerId sender, String message) {
|
||||||
|
this.channel = channel;
|
||||||
|
this.sender = sender;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Channel channel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable
|
||||||
|
PlayerId sender() {
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String message() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancelled) {
|
||||||
|
this.cancelled = cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
package tc.oc.commons.bukkit.channels;
|
||||||
|
|
||||||
|
import com.sk89q.minecraft.util.commands.Command;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandException;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
|
import tc.oc.commons.bukkit.chat.Audiences;
|
||||||
|
import tc.oc.commons.bukkit.commands.CommandUtils;
|
||||||
|
import tc.oc.commons.bukkit.util.SyncPlayerExecutorFactory;
|
||||||
|
import tc.oc.commons.core.commands.Commands;
|
||||||
|
import tc.oc.commons.core.commands.TranslatableCommandException;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class ChannelCommands implements Commands, Listener {
|
||||||
|
|
||||||
|
private final SyncPlayerExecutorFactory syncPlayerExecutorFactory;
|
||||||
|
private final ChannelRouter channelRouter;
|
||||||
|
private final Audiences audiences;
|
||||||
|
|
||||||
|
@Inject ChannelCommands(SyncPlayerExecutorFactory syncPlayerExecutorFactory, ChannelRouter channelRouter, Audiences audiences) {
|
||||||
|
this.syncPlayerExecutorFactory = syncPlayerExecutorFactory;
|
||||||
|
this.channelRouter = channelRouter;
|
||||||
|
this.audiences = audiences;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = "a",
|
||||||
|
desc = "Send a message to the staff channel.",
|
||||||
|
usage = "[message...]"
|
||||||
|
)
|
||||||
|
public void admin(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
onChatCommand(ChatDoc.Type.ADMIN, args, sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "g", "shout" },
|
||||||
|
desc = "Send a message to everyone on the local server.",
|
||||||
|
usage = "[message...]"
|
||||||
|
)
|
||||||
|
public void server(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
onChatCommand(ChatDoc.Type.SERVER, args, sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = "t",
|
||||||
|
desc = "Send a message to your teammates.",
|
||||||
|
usage = "[message...]"
|
||||||
|
)
|
||||||
|
public void chat(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
onChatCommand(ChatDoc.Type.TEAM, args, sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onChatCommand(ChatDoc.Type type, CommandContext args, CommandSender sender) throws CommandException {
|
||||||
|
final String typeName = type.name().toLowerCase();
|
||||||
|
final Channel channel = channelRouter.getChannel(sender, type)
|
||||||
|
.orElseThrow(() -> new TranslatableCommandException("channels.unavailable", typeName));
|
||||||
|
if(channel.sendable(sender)) {
|
||||||
|
if(args.argsLength() == 0) {
|
||||||
|
final Player player = CommandUtils.senderToPlayer(sender);
|
||||||
|
if(channel.equals(channelRouter.getDefaultChannel(player))) {
|
||||||
|
throw new TranslatableCommandException("channels.default.alreadySet", typeName);
|
||||||
|
} else {
|
||||||
|
channelRouter.setDefaultChannel(player, channel.type());
|
||||||
|
audiences.get(player).sendMessage(new TranslatableComponent("channels.default.set", typeName));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
channel.chat(sender, args.getJoinedStrings(0));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new CommandPermissionsException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
|
public void onChat(AsyncPlayerChatEvent event) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
syncPlayerExecutorFactory.queued(event.getPlayer()).execute(player -> {
|
||||||
|
Channel channel = channelRouter.getDefaultChannel(player);
|
||||||
|
String message = event.getMessage().trim();
|
||||||
|
|
||||||
|
if(message.startsWith("!")) {
|
||||||
|
channel = channelRouter.getChannel(ChatDoc.Type.SERVER).get();
|
||||||
|
message = message.substring(1).trim();
|
||||||
|
} else if(message.startsWith("@a ")) {
|
||||||
|
channel = channelRouter.getChannel(ChatDoc.Type.SERVER).get();
|
||||||
|
message = message.substring(3).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!channel.sendable(player)) {
|
||||||
|
// If player cannot chat in their preferred channel,
|
||||||
|
// assume they can send to the default channel.
|
||||||
|
channel = channelRouter.getDefaultChannel();
|
||||||
|
}
|
||||||
|
if(!message.isEmpty()) {
|
||||||
|
channel.chat(player, message);
|
||||||
|
} else {
|
||||||
|
audiences.get(player).sendWarning(new TranslatableComponent("channels.message.empty"), false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package tc.oc.commons.bukkit.channels;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import org.bukkit.configuration.Configuration;
|
||||||
|
|
||||||
|
public class ChannelConfiguration {
|
||||||
|
|
||||||
|
private final Configuration config;
|
||||||
|
|
||||||
|
@Inject ChannelConfiguration(Configuration config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean admin_enabled() {
|
||||||
|
return config.getBoolean("channels.admin.enabled", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean admin_cross_server() {
|
||||||
|
return config.getBoolean("channels.admin.cross-server", false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package tc.oc.commons.bukkit.channels;
|
||||||
|
|
||||||
|
import tc.oc.commons.bukkit.channels.admin.AdminChannel;
|
||||||
|
import tc.oc.commons.bukkit.channels.server.ServerChannel;
|
||||||
|
import tc.oc.commons.bukkit.settings.SettingBinder;
|
||||||
|
import tc.oc.commons.core.inject.HybridManifest;
|
||||||
|
import tc.oc.commons.core.plugin.PluginFacetBinder;
|
||||||
|
|
||||||
|
public class ChannelManifest extends HybridManifest {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
|
||||||
|
bindAndExpose(ChannelRouter.class);
|
||||||
|
expose(ChannelCommands.class);
|
||||||
|
expose(AdminChannel.class);
|
||||||
|
expose(ServerChannel.class);
|
||||||
|
|
||||||
|
final PluginFacetBinder facets = new PluginFacetBinder(binder());
|
||||||
|
facets.register(ChannelCommands.class);
|
||||||
|
facets.register(AdminChannel.class);
|
||||||
|
facets.register(ServerChannel.class);
|
||||||
|
|
||||||
|
final SettingBinder settings = new SettingBinder(publicBinder());
|
||||||
|
settings.addBinding().toInstance(AdminChannel.SETTING);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package tc.oc.commons.bukkit.channels;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import tc.oc.api.bukkit.users.BukkitUserStore;
|
||||||
|
import tc.oc.api.docs.Chat;
|
||||||
|
import tc.oc.api.docs.User;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
|
import tc.oc.api.docs.virtual.UserDoc;
|
||||||
|
import tc.oc.api.users.UserService;
|
||||||
|
import tc.oc.commons.bukkit.channels.admin.AdminChannel;
|
||||||
|
import tc.oc.commons.bukkit.channels.server.ServerChannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link Channel} based on the {@link ChatDoc.Type}.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class ChannelRouter {
|
||||||
|
|
||||||
|
private final BukkitUserStore userStore;
|
||||||
|
private final UserService userService;
|
||||||
|
private final ServerChannel serverChannel;
|
||||||
|
private final AdminChannel adminChannel;
|
||||||
|
private Function<Player, Channel> teamChannelFunction;
|
||||||
|
|
||||||
|
@Inject ChannelRouter(BukkitUserStore userStore, UserService userService, ServerChannel serverChannel, AdminChannel adminChannel) {
|
||||||
|
this.userStore = userStore;
|
||||||
|
this.userService = userService;
|
||||||
|
this.serverChannel = serverChannel;
|
||||||
|
this.adminChannel = adminChannel;
|
||||||
|
setTeamChannelFunction(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Channel> getChannel(ChatDoc.Type type) {
|
||||||
|
return getChannel(null, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Channel> getChannel(Chat chat) {
|
||||||
|
return getChannel(userStore.find(chat.sender()), chat.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Channel> getChannel(@Nullable CommandSender sender, ChatDoc.Type type) {
|
||||||
|
Channel channel = null;
|
||||||
|
if(type == ChatDoc.Type.SERVER) {
|
||||||
|
channel = serverChannel;
|
||||||
|
} else if(type == ChatDoc.Type.ADMIN) {
|
||||||
|
channel = adminChannel;
|
||||||
|
} else if(sender != null && sender instanceof Player && type == ChatDoc.Type.TEAM) {
|
||||||
|
channel = teamChannelFunction.apply((Player) sender);
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Channel getDefaultChannel() {
|
||||||
|
return serverChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Channel getDefaultChannel(Player player) {
|
||||||
|
return getChannel(player, userStore.getUser(player).chat_channel()).orElse(getDefaultChannel());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListenableFuture<User> setDefaultChannel(Player player, ChatDoc.Type type) {
|
||||||
|
return userService.update(userStore.playerId(player), new UserDoc.Channel() {
|
||||||
|
@Override
|
||||||
|
public ChatDoc.Type chat_channel() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTeamChannelFunction(@Nullable Function<Player, Channel> function) {
|
||||||
|
teamChannelFunction = function != null ? function : sender -> serverChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package tc.oc.commons.bukkit.channels;
|
||||||
|
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.permissions.Permission;
|
||||||
|
import tc.oc.commons.core.chat.Audience;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link Audience} with membership access based off of a {@link Permission} node.
|
||||||
|
*/
|
||||||
|
public interface PermissibleChannel extends Channel {
|
||||||
|
|
||||||
|
Permission permission();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean sendable(CommandSender sender) {
|
||||||
|
return sender.hasPermission(permission());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean viewable(CommandSender sender) {
|
||||||
|
return sender.hasPermission(permission());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
package tc.oc.commons.bukkit.channels;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventBus;
|
||||||
|
import tc.oc.api.bukkit.users.BukkitUserStore;
|
||||||
|
import tc.oc.api.docs.Chat;
|
||||||
|
import tc.oc.api.docs.PlayerId;
|
||||||
|
import tc.oc.commons.bukkit.chat.Audiences;
|
||||||
|
import tc.oc.commons.bukkit.chat.ChatCreator;
|
||||||
|
import tc.oc.commons.bukkit.chat.NameStyle;
|
||||||
|
import tc.oc.commons.bukkit.chat.PlayerComponent;
|
||||||
|
import tc.oc.commons.bukkit.nick.IdentityProvider;
|
||||||
|
import tc.oc.commons.core.chat.Audience;
|
||||||
|
import tc.oc.commons.core.chat.Component;
|
||||||
|
import tc.oc.commons.core.chat.MultiAudience;
|
||||||
|
import tc.oc.commons.core.plugin.PluginFacet;
|
||||||
|
|
||||||
|
public abstract class SimpleChannel implements MultiAudience, Channel, PluginFacet {
|
||||||
|
|
||||||
|
@Inject protected Audiences audiences;
|
||||||
|
@Inject protected EventBus eventBus;
|
||||||
|
@Inject protected BukkitUserStore userStore;
|
||||||
|
@Inject protected ChatCreator chatCreator;
|
||||||
|
@Inject protected IdentityProvider identityProvider;
|
||||||
|
|
||||||
|
public abstract BaseComponent prefix();
|
||||||
|
|
||||||
|
public abstract BaseComponent format(Chat chat, PlayerComponent sender, String message);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(BaseComponent message) {
|
||||||
|
MultiAudience.super.sendMessage(new Component(prefix()).extra(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<? extends Audience> audiences() {
|
||||||
|
return Stream.of(audiences.filter(this::viewable));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void chat(@Nullable PlayerId playerId, String message) {
|
||||||
|
final ChannelChatEvent event = new ChannelChatEvent(this, playerId, message);
|
||||||
|
eventBus.callEvent(event);
|
||||||
|
if(!event.isCancelled()) {
|
||||||
|
chatCreator.chat(playerId, event.message(), type(), this::show);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String message) {
|
||||||
|
sendMessage(new TextComponent(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void show(Chat chat) {
|
||||||
|
sendMessage(format(
|
||||||
|
chat,
|
||||||
|
new PlayerComponent(
|
||||||
|
identityProvider.currentOrConsoleIdentity(chat.sender()),
|
||||||
|
NameStyle.VERBOSE_SIMPLE
|
||||||
|
), chat.message()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void chat(CommandSender sender, String message) {
|
||||||
|
chat(sender instanceof Player ? userStore.tryUser((Player) sender) : null, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
package tc.oc.commons.bukkit.channels.admin;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import me.anxuiz.settings.Setting;
|
||||||
|
import me.anxuiz.settings.SettingBuilder;
|
||||||
|
import me.anxuiz.settings.types.BooleanType;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.permissions.Permission;
|
||||||
|
import org.bukkit.permissions.PermissionDefault;
|
||||||
|
import tc.oc.api.docs.Chat;
|
||||||
|
import tc.oc.api.docs.Server;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
|
import tc.oc.api.servers.ServerStore;
|
||||||
|
import tc.oc.commons.bukkit.channels.PermissibleChannel;
|
||||||
|
import tc.oc.commons.bukkit.channels.SimpleChannel;
|
||||||
|
import tc.oc.commons.bukkit.chat.PlayerComponent;
|
||||||
|
import tc.oc.commons.bukkit.format.ServerFormatter;
|
||||||
|
import tc.oc.commons.bukkit.permissions.PermissionRegistry;
|
||||||
|
import tc.oc.commons.bukkit.settings.SettingManagerProvider;
|
||||||
|
import tc.oc.commons.core.chat.Component;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class AdminChannel extends SimpleChannel implements PermissibleChannel {
|
||||||
|
|
||||||
|
public final static Permission PERMISSION = new Permission("chat.admin", PermissionDefault.OP);
|
||||||
|
public final static Setting SETTING = new SettingBuilder()
|
||||||
|
.name("AdminChat")
|
||||||
|
.alias("ac")
|
||||||
|
.summary("Show confidential staff chat")
|
||||||
|
.type(new BooleanType())
|
||||||
|
.defaultValue(true)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
private final SettingManagerProvider settings;
|
||||||
|
private final PermissionRegistry permissions;
|
||||||
|
private final Server localServer;
|
||||||
|
private final ServerStore serverStore;
|
||||||
|
|
||||||
|
@Inject AdminChannel(PermissionRegistry permissions, SettingManagerProvider settings, Server localServer, ServerStore serverStore) {
|
||||||
|
this.settings = settings;
|
||||||
|
this.permissions = permissions;
|
||||||
|
this.localServer = localServer;
|
||||||
|
this.serverStore = serverStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enable() {
|
||||||
|
permissions.register(PERMISSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Permission permission() {
|
||||||
|
return PERMISSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean viewable(CommandSender sender) {
|
||||||
|
return !(sender instanceof Player) ||
|
||||||
|
(PermissibleChannel.super.viewable(sender) &&
|
||||||
|
settings.getManager((Player) sender).getValue(SETTING, Boolean.class, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseComponent prefix() {
|
||||||
|
return new Component().extra("[").extra(new Component("A", ChatColor.GOLD)).extra("] ");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseComponent format(Chat chat, PlayerComponent player, String message) {
|
||||||
|
Component component = new Component();
|
||||||
|
if(!localServer._id().equals(chat.server_id())) {
|
||||||
|
final Server server = serverStore.byId(chat.server_id());
|
||||||
|
component.extra(ServerFormatter.light.nameWithDatacenter(server)).extra(" ");
|
||||||
|
}
|
||||||
|
return component.extra(player).extra(": ").extra(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChatDoc.Type type() {
|
||||||
|
return ChatDoc.Type.ADMIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package tc.oc.commons.bukkit.channels.server;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import tc.oc.api.docs.Chat;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
|
import tc.oc.commons.bukkit.channels.SimpleChannel;
|
||||||
|
import tc.oc.commons.bukkit.chat.PlayerComponent;
|
||||||
|
import tc.oc.commons.core.chat.Component;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class ServerChannel extends SimpleChannel {
|
||||||
|
|
||||||
|
@Inject ServerChannel() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseComponent prefix() {
|
||||||
|
return new Component();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseComponent format(Chat chat, PlayerComponent sender, String message) {
|
||||||
|
return new Component().extra("<").extra(sender).extra(">: ").extra(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChatDoc.Type type() {
|
||||||
|
return ChatDoc.Type.SERVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean sendable(CommandSender sender) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean viewable(CommandSender sender) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,11 +1,10 @@
|
||||||
package tc.oc.commons.bukkit.chat;
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import com.google.common.collect.HashBasedTable;
|
import com.google.common.collect.HashBasedTable;
|
||||||
import com.google.common.collect.Table;
|
import com.google.common.collect.Table;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import tc.oc.commons.bukkit.nick.Identity;
|
import tc.oc.commons.bukkit.nick.Identity;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import tc.oc.api.docs.Chat;
|
||||||
|
import tc.oc.api.docs.Server;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
|
import tc.oc.api.docs.virtual.ServerDoc;
|
||||||
|
import tc.oc.api.message.MessageListener;
|
||||||
|
import tc.oc.api.message.MessageQueue;
|
||||||
|
import tc.oc.api.message.types.ModelUpdate;
|
||||||
|
import tc.oc.api.servers.ServerStore;
|
||||||
|
import tc.oc.commons.bukkit.broadcast.BroadcastSender;
|
||||||
|
import tc.oc.commons.bukkit.channels.Channel;
|
||||||
|
import tc.oc.commons.bukkit.channels.ChannelConfiguration;
|
||||||
|
import tc.oc.commons.bukkit.channels.ChannelRouter;
|
||||||
|
import tc.oc.commons.core.plugin.PluginFacet;
|
||||||
|
import tc.oc.minecraft.scheduler.MainThreadExecutor;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class ChatAnnouncer implements PluginFacet, MessageListener {
|
||||||
|
|
||||||
|
private final ChannelConfiguration configuration;
|
||||||
|
private final Server server;
|
||||||
|
private final ServerStore serverStore;
|
||||||
|
private final MessageQueue queue;
|
||||||
|
private final MainThreadExecutor executor;
|
||||||
|
private final ChannelRouter channelRouter;
|
||||||
|
private final BroadcastSender broadcaster;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ChatAnnouncer(ChannelConfiguration configuration, Server server, ServerStore serverStore,
|
||||||
|
MessageQueue queue, MainThreadExecutor executor, ChannelRouter channelRouter,
|
||||||
|
BroadcastSender broadcaster) {
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.server = server;
|
||||||
|
this.serverStore = serverStore;
|
||||||
|
this.queue = queue;
|
||||||
|
this.executor = executor;
|
||||||
|
this.channelRouter = channelRouter;
|
||||||
|
this.broadcaster = broadcaster;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enable() {
|
||||||
|
queue.bind(ModelUpdate.class);
|
||||||
|
queue.subscribe(this, executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disable() {
|
||||||
|
queue.unsubscribe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MessageListener.HandleMessage
|
||||||
|
public void onChat(ModelUpdate<Chat> message) {
|
||||||
|
final Chat chat = message.document();
|
||||||
|
if(shouldAnnounce(chat)) {
|
||||||
|
final ChatDoc.Type type = chat.type();
|
||||||
|
final Optional<Channel> channel = channelRouter.getChannel(chat);
|
||||||
|
if(channel.isPresent()) {
|
||||||
|
channel.get().show(chat);
|
||||||
|
} else if(type == ChatDoc.Type.BROADCAST) {
|
||||||
|
broadcaster.show(chat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldAnnounce(Chat chat) {
|
||||||
|
final boolean remote = serverStore.canCommunicate(server._id(), chat.server_id());
|
||||||
|
switch(chat.type()) {
|
||||||
|
case SERVER:
|
||||||
|
case TEAM:
|
||||||
|
return false;
|
||||||
|
case ADMIN:
|
||||||
|
if (!configuration.admin_cross_server() && !chat.server_id().equalsIgnoreCase(server._id())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return configuration.admin_enabled() && remote;
|
||||||
|
case BROADCAST:
|
||||||
|
return shouldAnnounce(chat.broadcast());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldAnnounce(ChatDoc.Broadcast broadcast) {
|
||||||
|
final String destination = broadcast.id();
|
||||||
|
switch(broadcast.destination()) {
|
||||||
|
case SERVER:
|
||||||
|
return server._id().equalsIgnoreCase(destination);
|
||||||
|
case FAMILY:
|
||||||
|
final String family = server.family();
|
||||||
|
return family == null || family.equalsIgnoreCase(destination);
|
||||||
|
case GAME:
|
||||||
|
final String game = server.game_id();
|
||||||
|
return game == null || game.equalsIgnoreCase(destination);
|
||||||
|
case NETWORK:
|
||||||
|
final ServerDoc.Network network = server.network();
|
||||||
|
return network == null || network.name().equalsIgnoreCase(destination);
|
||||||
|
case GLOBAL:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
|
import static java.util.Optional.ofNullable;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import tc.oc.api.docs.Chat;
|
||||||
|
import tc.oc.api.docs.PlayerId;
|
||||||
|
import tc.oc.api.docs.Server;
|
||||||
|
import tc.oc.api.docs.virtual.ChatDoc;
|
||||||
|
import tc.oc.api.docs.virtual.MatchDoc;
|
||||||
|
import tc.oc.api.model.BatchUpdater;
|
||||||
|
import tc.oc.api.model.BatchUpdaterFactory;
|
||||||
|
import tc.oc.api.model.IdFactory;
|
||||||
|
import tc.oc.api.model.ModelService;
|
||||||
|
import tc.oc.commons.core.plugin.PluginFacet;
|
||||||
|
import tc.oc.minecraft.api.event.Listener;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class ChatCreator implements PluginFacet, Listener {
|
||||||
|
|
||||||
|
private final IdFactory idFactory;
|
||||||
|
private final ModelService<Chat, ChatDoc.Partial> chatService;
|
||||||
|
private final BatchUpdater<ChatDoc.Partial> chatBatchUpdater;
|
||||||
|
private final Server server;
|
||||||
|
|
||||||
|
@Inject ChatCreator(IdFactory idFactory, ModelService<Chat, ChatDoc.Partial> chatService, BatchUpdaterFactory<ChatDoc.Partial> chatBatchUpdaterFactory, Server server) {
|
||||||
|
this.idFactory = idFactory;
|
||||||
|
this.chatService = chatService;
|
||||||
|
this.chatBatchUpdater = chatBatchUpdaterFactory.createBatchUpdater(Duration.ofMinutes(1));
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListenableFuture<Chat> chat(@Nullable PlayerId sender, String message, ChatDoc.Type type, Consumer<Chat> callback) {
|
||||||
|
return send(sender, message, type, null, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListenableFuture<Chat> broadcast(@Nullable PlayerId sender, String message, ChatDoc.Destination destination, String destination_id) {
|
||||||
|
return send(sender, message, ChatDoc.Type.BROADCAST,
|
||||||
|
new ChatDoc.Broadcast() {
|
||||||
|
public ChatDoc.Destination destination() { return destination; }
|
||||||
|
public String id() { return destination_id; }
|
||||||
|
}, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ListenableFuture<Chat> send(@Nullable PlayerId sender, String message, ChatDoc.Type type, @Nullable ChatDoc.Broadcast broadcast, @Nullable Consumer<Chat> callback) {
|
||||||
|
final Instant time = Instant.now();
|
||||||
|
final String id = idFactory.newId();
|
||||||
|
ChatDoc.Creation chat = new ChatDoc.Creation() {
|
||||||
|
public String _id() { return id; }
|
||||||
|
public String sender_id() { return sender != null ? sender._id() : null; }
|
||||||
|
public String message() { return message; }
|
||||||
|
public String server_id() { return server._id(); }
|
||||||
|
public String match_id() { return ofNullable(server.current_match()).map(MatchDoc::_id).orElse(null); }
|
||||||
|
public ChatDoc.Type type() { return type; }
|
||||||
|
public Instant sent_at() { return time; }
|
||||||
|
public ChatDoc.Broadcast broadcast() { return broadcast; }
|
||||||
|
};
|
||||||
|
// Some chats are only consumed by the local server,
|
||||||
|
// so those messages can have delayed reporting to the API.
|
||||||
|
if(type.batchUpdate) {
|
||||||
|
if(callback != null) callback.accept(mock(sender, chat));
|
||||||
|
chatBatchUpdater.update(chat);
|
||||||
|
return Futures.immediateFuture(null);
|
||||||
|
} else {
|
||||||
|
return chatService.update(chat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Chat mock(@Nullable PlayerId sender, ChatDoc.Creation chat) {
|
||||||
|
return new Chat() {
|
||||||
|
public PlayerId sender() { return sender; }
|
||||||
|
public String _id() { return chat._id(); }
|
||||||
|
public String message() { return chat.message(); }
|
||||||
|
public String server_id() { return chat.server_id(); }
|
||||||
|
public String match_id() { return chat.match_id(); }
|
||||||
|
public ChatDoc.Type type() { return chat.type(); }
|
||||||
|
public Instant sent_at() { return chat.sent_at(); }
|
||||||
|
public ChatDoc.Broadcast broadcast() { return chat.broadcast(); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
|
import tc.oc.commons.bukkit.broadcast.BroadcastSender;
|
||||||
|
import tc.oc.commons.core.inject.HybridManifest;
|
||||||
|
import tc.oc.commons.core.plugin.PluginFacetBinder;
|
||||||
|
|
||||||
|
public class ChatManifest extends HybridManifest {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
|
||||||
|
expose(ChatCreator.class);
|
||||||
|
expose(ChatAnnouncer.class);
|
||||||
|
expose(BroadcastSender.class);
|
||||||
|
|
||||||
|
final PluginFacetBinder facets = new PluginFacetBinder(binder());
|
||||||
|
facets.register(ChatCreator.class);
|
||||||
|
facets.register(ChatAnnouncer.class);
|
||||||
|
facets.register(BroadcastSender.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package tc.oc.commons.bukkit.chat;
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import tc.oc.commons.bukkit.flairs.FlairRenderer;
|
||||||
import tc.oc.commons.bukkit.nick.Identity;
|
import tc.oc.commons.bukkit.nick.Identity;
|
||||||
import tc.oc.commons.bukkit.nick.UsernameRenderer;
|
import tc.oc.commons.bukkit.nick.UsernameRenderer;
|
||||||
import tc.oc.commons.core.chat.Component;
|
import tc.oc.commons.core.chat.Component;
|
||||||
|
|
|
@ -3,7 +3,6 @@ package tc.oc.commons.bukkit.chat;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
|
|
@ -2,7 +2,6 @@ package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
|
@ -13,12 +12,17 @@ import tc.oc.commons.core.util.ExceptionUtils;
|
||||||
public class Links {
|
public class Links {
|
||||||
private Links() {}
|
private Links() {}
|
||||||
|
|
||||||
public static final String HOST = "localhost"; // TODO: configurable
|
public static final String HOST = "stratus.network";
|
||||||
|
public static final String SHOP_HOST = "stratusnetwork.buycraft.net";
|
||||||
|
|
||||||
public static URI homeUri(String path) throws URISyntaxException {
|
public static URI homeUri(String path) throws URISyntaxException {
|
||||||
return new URI("http", HOST, path, null);
|
return new URI("http", HOST, path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static URI shopUri() throws URISyntaxException {
|
||||||
|
return new URI("http", SHOP_HOST, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
public static URI homeUriSafe(String path) {
|
public static URI homeUriSafe(String path) {
|
||||||
return ExceptionUtils.propagate(() -> homeUri(path));
|
return ExceptionUtils.propagate(() -> homeUri(path));
|
||||||
}
|
}
|
||||||
|
@ -39,8 +43,12 @@ public class Links {
|
||||||
return homeLinkSafe("/");
|
return homeLinkSafe("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BaseComponent shopLink(boolean compact) throws URISyntaxException {
|
||||||
|
return new LinkComponent(shopUri(), compact);
|
||||||
|
}
|
||||||
|
|
||||||
public static BaseComponent shopLink() {
|
public static BaseComponent shopLink() {
|
||||||
return homeLinkSafe("/shop");
|
return ExceptionUtils.propagate(() -> shopLink(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BaseComponent appealLink() {
|
public static BaseComponent appealLink() {
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package tc.oc.commons.bukkit.chat;
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.google.common.collect.ForwardingSet;
|
import com.google.common.collect.ForwardingSet;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The formatting properties for each different context in which names are displayed.
|
* The formatting properties for each different context in which names are displayed.
|
||||||
|
@ -50,6 +49,13 @@ public class NameStyle extends ForwardingSet<NameFlag> {
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
public static final NameStyle VERBOSE_SIMPLE = new NameStyle(
|
||||||
|
Sets.difference(
|
||||||
|
VERBOSE,
|
||||||
|
Sets.newHashSet(NameFlag.SELF, NameFlag.FRIEND)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
// Fancy minus mapmaker flair (for display in map credits)
|
// Fancy minus mapmaker flair (for display in map credits)
|
||||||
public static final NameStyle MAPMAKER = new NameStyle(
|
public static final NameStyle MAPMAKER = new NameStyle(
|
||||||
Sets.difference(
|
Sets.difference(
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package tc.oc.commons.bukkit.chat;
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import tc.oc.commons.bukkit.nick.Identity;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import tc.oc.commons.bukkit.nick.Identity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These are the parameters that determine how a player's name is
|
* These are the parameters that determine how a player's name is
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package tc.oc.commons.bukkit.chat;
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Iterators;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.Iterators;
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
|
@ -16,9 +18,6 @@ import tc.oc.commons.core.chat.Component;
|
||||||
import tc.oc.commons.core.util.IndexedFunction;
|
import tc.oc.commons.core.util.IndexedFunction;
|
||||||
import tc.oc.commons.core.util.Numbers;
|
import tc.oc.commons.core.util.Numbers;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
public class Paginator<T> {
|
public class Paginator<T> {
|
||||||
public static final int DEFAULT_PER_PAGE = 14;
|
public static final int DEFAULT_PER_PAGE = 14;
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@ public class Paginator<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void display(CommandSender sender, Collection<? extends T> results, int page) {
|
public void display(CommandSender sender, Collection<? extends T> results, int page) {
|
||||||
display(BukkitAudiences.getAudience(sender), results, page);
|
display(Audiences.Deprecated.get(sender), results, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void display(Audience audience, Collection<? extends T> results, int page) {
|
public void display(Audience audience, Collection<? extends T> results, int page) {
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
package tc.oc.commons.bukkit.chat;
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import tc.oc.commons.bukkit.nick.Identity;
|
import tc.oc.commons.bukkit.nick.Identity;
|
||||||
import tc.oc.commons.core.chat.ImmutableComponent;
|
import tc.oc.commons.core.chat.ImmutableComponent;
|
||||||
import tc.oc.commons.core.util.Utils;
|
import tc.oc.commons.core.util.Utils;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component that renders as a player's name.
|
* A component that renders as a player's name.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,7 +2,6 @@ package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package tc.oc.commons.bukkit.chat;
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import java.util.List;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import tc.oc.commons.bukkit.localization.MessageTemplate;
|
import tc.oc.commons.bukkit.localization.MessageTemplate;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package tc.oc.commons.bukkit.chat;
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
package tc.oc.commons.bukkit.chat;
|
package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
|
||||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import tc.oc.commons.bukkit.localization.Translator;
|
|
||||||
import tc.oc.commons.core.chat.Component;
|
|
||||||
import tc.oc.commons.core.chat.Components;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import tc.oc.commons.bukkit.localization.Translator;
|
||||||
|
import tc.oc.commons.core.chat.Component;
|
||||||
|
import tc.oc.commons.core.chat.Components;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class TranslatableComponentRenderer extends BaseComponentRenderer<TranslatableComponent> {
|
public class TranslatableComponentRenderer extends BaseComponentRenderer<TranslatableComponent> {
|
||||||
|
|
|
@ -3,7 +3,6 @@ package tc.oc.commons.bukkit.chat;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
|
|
@ -2,7 +2,6 @@ package tc.oc.commons.bukkit.chat;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import tc.oc.commons.bukkit.nick.Identity;
|
import tc.oc.commons.bukkit.nick.Identity;
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
package tc.oc.commons.bukkit.commands;
|
package tc.oc.commons.bukkit.commands;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.format.DateTimeParseException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||||
import com.sk89q.minecraft.util.commands.CommandException;
|
import com.sk89q.minecraft.util.commands.CommandException;
|
||||||
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
|
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
|
@ -20,9 +25,11 @@ import org.bukkit.permissions.Permission;
|
||||||
import tc.oc.api.docs.PlayerId;
|
import tc.oc.api.docs.PlayerId;
|
||||||
import tc.oc.api.docs.Server;
|
import tc.oc.api.docs.Server;
|
||||||
import tc.oc.commons.bukkit.chat.ComponentRenderers;
|
import tc.oc.commons.bukkit.chat.ComponentRenderers;
|
||||||
|
import tc.oc.commons.bukkit.chat.ListComponent;
|
||||||
import tc.oc.commons.bukkit.localization.Translations;
|
import tc.oc.commons.bukkit.localization.Translations;
|
||||||
import tc.oc.commons.core.chat.Component;
|
import tc.oc.commons.core.chat.Component;
|
||||||
import tc.oc.commons.core.commands.TranslatableCommandException;
|
import tc.oc.commons.core.commands.TranslatableCommandException;
|
||||||
|
import tc.oc.commons.core.formatting.StringUtils;
|
||||||
import tc.oc.commons.core.util.TimeUtils;
|
import tc.oc.commons.core.util.TimeUtils;
|
||||||
|
|
||||||
public abstract class CommandUtils {
|
public abstract class CommandUtils {
|
||||||
|
@ -124,14 +131,14 @@ public abstract class CommandUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Duration getDuration(CommandContext args, int index, Duration def) throws CommandException {
|
public static Duration getDuration(CommandContext args, int index, Duration def) throws CommandException {
|
||||||
return args.argsLength() > index ? getDuration(args.getString(index), null) : def;
|
return getDuration(args.getString(index, null), def);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable Duration getDuration(@Nullable String text) throws CommandException {
|
public static @Nullable Duration getDuration(String text) throws CommandException {
|
||||||
return getDuration(text, null);
|
return getDuration(text, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Duration getDuration(@Nullable String text, Duration def) throws CommandException {
|
public static Duration getDuration(String text, Duration def) throws CommandException {
|
||||||
if(text == null) {
|
if(text == null) {
|
||||||
return def;
|
return def;
|
||||||
} else {
|
} else {
|
||||||
|
@ -143,6 +150,26 @@ public abstract class CommandUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static @Nullable <E extends Enum<E>> E getEnum(CommandContext args, CommandSender sender, int index, Class<E> type) throws CommandException {
|
||||||
|
return getEnum(args, sender, index, type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E extends Enum<E>> E getEnum(CommandContext args, CommandSender sender, int index, Class<E> type, E def) throws CommandException {
|
||||||
|
return getEnum(args.getString(index, null), sender, type, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E extends Enum<E>> E getEnum(String text, CommandSender sender, Class<E> type, E def) throws CommandException {
|
||||||
|
if(text == null) {
|
||||||
|
return def;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return Enum.valueOf(type, text.toUpperCase().replace(' ', '_'));
|
||||||
|
} catch(IllegalArgumentException e) {
|
||||||
|
throw newCommandException(sender, new TranslatableComponent("command.error.invalidEnum", text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static String getDisplayName(CommandSender target) {
|
public static String getDisplayName(CommandSender target) {
|
||||||
return getDisplayName(target, null);
|
return getDisplayName(target, null);
|
||||||
}
|
}
|
||||||
|
@ -198,4 +225,35 @@ public abstract class CommandUtils {
|
||||||
public static void notEnoughArguments(CommandSender sender) throws CommandException {
|
public static void notEnoughArguments(CommandSender sender) throws CommandException {
|
||||||
throw new CommandException(Translations.get().t("command.error.notEnoughArguments", sender));
|
throw new CommandException(Translations.get().t("command.error.notEnoughArguments", sender));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <E extends Enum> Map<String, E> enumChoices(Class<E> enumClass) {
|
||||||
|
return Stream.of(enumClass.getEnumConstants())
|
||||||
|
.collect(Collectors.toMap(e -> e.name().toLowerCase().replaceAll("_", "-"), Function.identity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E extends Enum> List<String> enumChoicesList(Class<E> enumClass) {
|
||||||
|
return new ArrayList<>(enumChoices(enumClass).keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable <E extends Enum> E tryEnum(String text, Class<E> enumClass) {
|
||||||
|
return StringUtils.bestFuzzyMatch(text, enumChoices(enumClass), 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E extends Enum> E tryEnum(String text, Class<E> enumClass, E def) {
|
||||||
|
final E option = tryEnum(text, enumClass);
|
||||||
|
return option == null ? def : option;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E extends Enum> E getEnum(String text, Class<E> enumClass) throws CommandException {
|
||||||
|
final E option = tryEnum(text, enumClass);
|
||||||
|
if(option != null) {
|
||||||
|
return option;
|
||||||
|
} else {
|
||||||
|
throw new TranslatableCommandException("command.error.invalidOption", text, new ListComponent(enumChoicesList(enumClass), TextComponent::new));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E extends Enum> List<String> completeEnum(String prefix, Class<E> enumClass) {
|
||||||
|
return StringUtils.complete(prefix, enumChoicesList(enumClass));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
package tc.oc.commons.bukkit.commands;
|
||||||
|
|
||||||
|
import com.sk89q.minecraft.util.commands.Command;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandException;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
|
||||||
|
import com.sk89q.minecraft.util.commands.NestedCommand;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
|
import tc.oc.api.bukkit.users.BukkitUserStore;
|
||||||
|
import tc.oc.api.docs.User;
|
||||||
|
import tc.oc.api.users.ChangeGroupRequest;
|
||||||
|
import tc.oc.api.users.UserService;
|
||||||
|
import tc.oc.commons.bukkit.chat.Audiences;
|
||||||
|
import tc.oc.commons.core.commands.Commands;
|
||||||
|
import tc.oc.commons.core.commands.NestedCommands;
|
||||||
|
import tc.oc.commons.core.concurrent.Flexecutor;
|
||||||
|
import tc.oc.commons.core.util.ThrowingBiConsumer;
|
||||||
|
import tc.oc.minecraft.scheduler.Sync;
|
||||||
|
|
||||||
|
public class GroupCommands implements NestedCommands {
|
||||||
|
|
||||||
|
public static class Parent implements Commands {
|
||||||
|
@Command(
|
||||||
|
aliases = { "group" },
|
||||||
|
desc = "Commands to edit group membership",
|
||||||
|
min = 1,
|
||||||
|
max = -1
|
||||||
|
)
|
||||||
|
@NestedCommand(value = {GroupCommands.class})
|
||||||
|
public void commands() throws CommandPermissionsException {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Flexecutor flexecutor;
|
||||||
|
private final BukkitUserStore userStore;
|
||||||
|
private final UserService userService;
|
||||||
|
private final UserFinder userFinder;
|
||||||
|
private final Audiences audiences;
|
||||||
|
|
||||||
|
@Inject GroupCommands(@Sync Flexecutor flexecutor, BukkitUserStore userStore, UserService userService, UserFinder userFinder, Audiences audiences) {
|
||||||
|
this.flexecutor = flexecutor;
|
||||||
|
this.userStore = userStore;
|
||||||
|
this.userService = userService;
|
||||||
|
this.userFinder = userFinder;
|
||||||
|
this.audiences = audiences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void edit(final CommandContext args, final CommandSender sender, boolean add, boolean expire, ThrowingBiConsumer<User, String, Exception> consumer) throws CommandException {
|
||||||
|
if(!(sender instanceof ConsoleCommandSender)) throw new CommandPermissionsException();
|
||||||
|
flexecutor.callback(
|
||||||
|
userFinder.findUser(sender, args, 0),
|
||||||
|
response -> {
|
||||||
|
String group = args.getString(1);
|
||||||
|
flexecutor.callback(
|
||||||
|
userService.changeGroup(response.user, new ChangeGroupRequest() {
|
||||||
|
public String group() {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
public String type() {
|
||||||
|
return add ? "join" : (expire ? "expire" : "leave");
|
||||||
|
}
|
||||||
|
public Instant end() {
|
||||||
|
try {
|
||||||
|
Duration duration = CommandUtils.getDuration(args, 2, null);
|
||||||
|
return add && duration != null ? Instant.now().plus(duration) : null;
|
||||||
|
} catch(CommandException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
user -> consumer.acceptThrows(user, group)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "join" },
|
||||||
|
desc = "Add a player to a group",
|
||||||
|
usage = "<player> <group> [duration]",
|
||||||
|
min = 2,
|
||||||
|
max = 3
|
||||||
|
)
|
||||||
|
public void join(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
edit(args, sender, true, false, (User user, String group) -> {
|
||||||
|
sender.sendMessage("Added " + user.username() + " to the " + group + " group");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "leave" },
|
||||||
|
desc = "Remove a player to a group",
|
||||||
|
usage = "<player> <group>",
|
||||||
|
min = 2,
|
||||||
|
max = 2
|
||||||
|
)
|
||||||
|
public void leave(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
edit(args, sender, false, false, (User user, String group) -> {
|
||||||
|
sender.sendMessage("Removed " + user.username() + " from the " + group + " group");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "expire" },
|
||||||
|
desc = "Expire a player's membership to a group",
|
||||||
|
usage = "<player> <group>",
|
||||||
|
min = 2,
|
||||||
|
max = 2
|
||||||
|
)
|
||||||
|
public void expire(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
edit(args, sender, false, true, (User user, String group) -> {
|
||||||
|
sender.sendMessage("Expired " + user.username() + "'s membership from the " + group + " group");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,359 @@
|
||||||
|
package tc.oc.commons.bukkit.commands;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.sk89q.minecraft.util.commands.Command;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandException;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.FireworkEffect;
|
||||||
|
import org.bukkit.FireworkEffect.Type;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
|
import org.bukkit.entity.Firework;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.meta.FireworkMeta;
|
||||||
|
import tc.oc.api.bukkit.users.BukkitUserStore;
|
||||||
|
import tc.oc.api.docs.virtual.UserDoc;
|
||||||
|
import tc.oc.api.users.UserService;
|
||||||
|
import tc.oc.commons.bukkit.chat.Audiences;
|
||||||
|
import tc.oc.commons.bukkit.chat.HeaderComponent;
|
||||||
|
import tc.oc.commons.bukkit.chat.PlayerComponent;
|
||||||
|
import tc.oc.commons.bukkit.nick.IdentityProvider;
|
||||||
|
import tc.oc.commons.core.chat.Audience;
|
||||||
|
import tc.oc.commons.core.chat.Component;
|
||||||
|
import tc.oc.commons.core.commands.Commands;
|
||||||
|
import tc.oc.commons.core.concurrent.Flexecutor;
|
||||||
|
import tc.oc.commons.core.stream.Collectors;
|
||||||
|
import tc.oc.commons.core.util.Streams;
|
||||||
|
import tc.oc.minecraft.protocol.MinecraftVersion;
|
||||||
|
import tc.oc.minecraft.scheduler.Sync;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commands for miscellaneous purposes.
|
||||||
|
*/
|
||||||
|
public class MiscCommands implements Commands {
|
||||||
|
|
||||||
|
private static final Random RANDOM = new Random();
|
||||||
|
|
||||||
|
private final Flexecutor flexecutor;
|
||||||
|
private final UserService userService;
|
||||||
|
private final BukkitUserStore userStore;
|
||||||
|
private final UserFinder userFinder;
|
||||||
|
private final IdentityProvider identityProvider;
|
||||||
|
private final Audiences audiences;
|
||||||
|
|
||||||
|
@Inject MiscCommands(@Sync Flexecutor flexecutor, UserService userService, BukkitUserStore userStore, UserFinder userFinder, IdentityProvider identityProvider, Audiences audiences) {
|
||||||
|
this.flexecutor = flexecutor;
|
||||||
|
this.userService = userService;
|
||||||
|
this.userStore = userStore;
|
||||||
|
this.userFinder = userFinder;
|
||||||
|
this.identityProvider = identityProvider;
|
||||||
|
this.audiences = audiences;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "playerversion", "pv" },
|
||||||
|
desc = "Shows statics on what version players online are using",
|
||||||
|
flags = "ad",
|
||||||
|
min = 0,
|
||||||
|
max = 1
|
||||||
|
)
|
||||||
|
@CommandPermissions("ocn.version")
|
||||||
|
public void listPlayerVersions(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
Audience audience = audiences.get(sender);
|
||||||
|
if (args.hasFlag('a')) {
|
||||||
|
Map<String, Integer> playerCountVersionMap = new HashMap<>();
|
||||||
|
userStore.stream().forEach(player -> {
|
||||||
|
String version = MinecraftVersion.describeProtocol(player.getProtocolVersion(), !args.hasFlag('d'));
|
||||||
|
playerCountVersionMap.put(version, playerCountVersionMap.getOrDefault(version, 0) + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
audience.sendMessage(new HeaderComponent(new Component(ChatColor.AQUA).translate("list.player.versions.title")));
|
||||||
|
for (Map.Entry<String, Integer> entry : playerCountVersionMap.entrySet()) {
|
||||||
|
audience.sendMessage(new TranslatableComponent("list.player.versions.message." + (entry.getValue() == 1 ? "singular" : "plural"),
|
||||||
|
ChatColor.AQUA + entry.getValue().toString(),
|
||||||
|
ChatColor.AQUA + entry.getKey(),
|
||||||
|
String.format("%.1f", 100 * entry.getValue() / (double) userStore.count()) + "%"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Player player = CommandUtils.getPlayerOrSelf(args, sender, 0);
|
||||||
|
audience.sendMessage(new TranslatableComponent("list.player.version.singular.message", new PlayerComponent(identityProvider.createIdentity(player)), ChatColor.AQUA + MinecraftVersion.describeProtocol(player.getProtocolVersion(), false)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "playerlocale", "locale" },
|
||||||
|
desc = "Shows statics on what locale players online are in",
|
||||||
|
flags = "a",
|
||||||
|
min = 0,
|
||||||
|
max = 1
|
||||||
|
)
|
||||||
|
@CommandPermissions("ocn.locale")
|
||||||
|
public void listPlayerLocales(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
Audience audience = audiences.get(sender);
|
||||||
|
if (args.hasFlag('a')) {
|
||||||
|
Map<String, Long> playerLocaleMap = userStore.stream().collect(java.util.stream.Collectors.groupingBy(Player::getLocale, java.util.stream.Collectors.counting()));
|
||||||
|
|
||||||
|
audience.sendMessage(new HeaderComponent(new Component(ChatColor.AQUA).translate("list.player.locales.title")));
|
||||||
|
for (Map.Entry<String, Long> entry : playerLocaleMap.entrySet()) {
|
||||||
|
audience.sendMessage(new TranslatableComponent("list.player.locales.message." + (entry.getValue() == 1 ? "singular" : "plural"),
|
||||||
|
ChatColor.AQUA + entry.getValue().toString(),
|
||||||
|
ChatColor.AQUA + entry.getKey(),
|
||||||
|
String.format("%.1f", 100 * entry.getValue() / (double) userStore.count()) + "%"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Player player = CommandUtils.getPlayerOrSelf(args, sender, 0);
|
||||||
|
audience.sendMessage(new TranslatableComponent("list.player.locale.singular.message", new PlayerComponent(identityProvider.createIdentity(player)), ChatColor.AQUA + player.getLocale()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "coinflip" },
|
||||||
|
desc = "Flip a Coin",
|
||||||
|
flags = "b",
|
||||||
|
min = 0,
|
||||||
|
max = 0
|
||||||
|
)
|
||||||
|
@CommandPermissions("coinflip")
|
||||||
|
public void coinFlip(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
if (args.hasFlag('b')) {
|
||||||
|
Bukkit.broadcastMessage(ChatColor.AQUA + (Math.random() < 0.5 ? "Heads" : "Tails"));
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(ChatColor.AQUA + (Math.random() < 0.5 ? "Heads" : "Tails"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "togglegravity" },
|
||||||
|
usage = "<player>",
|
||||||
|
desc = "Toggle a player's gravity.",
|
||||||
|
min = 0,
|
||||||
|
max = 1
|
||||||
|
)
|
||||||
|
@CommandPermissions("togglegravity")
|
||||||
|
public void noGravity(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
Player player = CommandUtils.getPlayerOrSelf(args, sender, 0);
|
||||||
|
player.setGravity(!player.hasGravity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "join-friend-tokens" },
|
||||||
|
usage = "<player> <concurrent> <limit>",
|
||||||
|
desc = "Change the join friend tokens limit for a premium player",
|
||||||
|
min = 3
|
||||||
|
)
|
||||||
|
public void joinFriend(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
if(!(sender instanceof ConsoleCommandSender)) throw new CommandPermissionsException();
|
||||||
|
int concurrent = args.getInteger(1, 1);
|
||||||
|
int limit = args.getInteger(2, 3);
|
||||||
|
flexecutor.callback(
|
||||||
|
userFinder.findLocalPlayer(sender, args, 0),
|
||||||
|
response -> {
|
||||||
|
userService.update(response.user, new UserDoc.FriendTokens() {
|
||||||
|
@Override
|
||||||
|
public int friend_tokens_limit() {
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int friend_tokens_concurrent() {
|
||||||
|
return concurrent;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "change-death-screen" },
|
||||||
|
usage = "<player> <+1/-1>",
|
||||||
|
desc = "Allow a player to change their death screen",
|
||||||
|
min = 2
|
||||||
|
)
|
||||||
|
public void deathScreen(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
if(!(sender instanceof ConsoleCommandSender)) throw new CommandPermissionsException();
|
||||||
|
boolean enable = args.getInteger(1, +1) > 0;
|
||||||
|
flexecutor.callback(
|
||||||
|
userFinder.findLocalPlayer(sender, args, 0),
|
||||||
|
response -> {
|
||||||
|
if((response.user.death_screen() == null) != enable) {
|
||||||
|
userService.update(response.user, (UserDoc.DeathScreen) () -> enable ? "default" : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "vice" },
|
||||||
|
desc = "WELCOME BACK VICE!"
|
||||||
|
)
|
||||||
|
public void vice(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
Player player = CommandUtils.senderToPlayer(sender);
|
||||||
|
UUID vice = UUID.fromString("bf331953-4f92-43ee-8abc-7544b8234936");
|
||||||
|
if (!(player.isOp() || player.getUniqueId().equals(vice))) throw new CommandPermissionsException();
|
||||||
|
Set<Location> fireworkLocs = Sets.newHashSet();
|
||||||
|
Location center = player.getLocation();
|
||||||
|
if (!player.getUniqueId().equals(vice) && sender.getServer().getPlayer(vice) != null)
|
||||||
|
center = sender.getServer().getPlayer(vice).getLocation();
|
||||||
|
center = center.clone();
|
||||||
|
fireworkLocs.add(center);
|
||||||
|
int radius = 5;
|
||||||
|
for (int i = 0 - radius; i <= radius; i = i + (radius / 2)) {
|
||||||
|
if (i == 0) continue;
|
||||||
|
fireworkLocs.add(center.clone().add(i, 0, 0));
|
||||||
|
fireworkLocs.add(center.clone().add(0, 0, i));
|
||||||
|
fireworkLocs.add(center.clone().add(i, 0, i));
|
||||||
|
}
|
||||||
|
for (Location location : fireworkLocs) {
|
||||||
|
FireworkMeta meta = (FireworkMeta) Bukkit.getItemFactory().getItemMeta(Material.FIREWORK);
|
||||||
|
meta.setPower(RANDOM.nextInt(15));
|
||||||
|
meta.addEffect(randomRGBEffect());
|
||||||
|
|
||||||
|
Firework firework = (Firework) location.getWorld().spawnEntity(location, EntityType.FIREWORK);
|
||||||
|
firework.setFireworkMeta(meta);
|
||||||
|
}
|
||||||
|
sender.getServer().broadcast(new TextComponent(
|
||||||
|
ChatColor.RED + "WELCOME " +
|
||||||
|
ChatColor.YELLOW + "BACK " +
|
||||||
|
ChatColor.GREEN + "VICE" +
|
||||||
|
ChatColor.BLUE + "!!")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FireworkEffect randomRGBEffect() {
|
||||||
|
return FireworkEffect.builder()
|
||||||
|
.flicker(RANDOM.nextBoolean())
|
||||||
|
.trail(true)
|
||||||
|
.with(Type.values()[RANDOM.nextInt(4)])
|
||||||
|
.withColor(Color.fromRGB(RANDOM.nextInt(255), RANDOM.nextInt(255), RANDOM.nextInt(255)))
|
||||||
|
.withColor(Color.fromRGB(RANDOM.nextInt(255), RANDOM.nextInt(255), RANDOM.nextInt(255)))
|
||||||
|
.withColor(Color.fromRGB(RANDOM.nextInt(255), RANDOM.nextInt(255), RANDOM.nextInt(255)))
|
||||||
|
.withFade(Color.fromRGB(RANDOM.nextInt(255), RANDOM.nextInt(255), RANDOM.nextInt(255)))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "sudo" },
|
||||||
|
usage = "<player> [command... (rand|mode|near|color|*)=value]",
|
||||||
|
desc = "Run a command as console or another player",
|
||||||
|
flags = "cd",
|
||||||
|
anyFlags = true,
|
||||||
|
min = 1,
|
||||||
|
max = -1
|
||||||
|
)
|
||||||
|
@CommandPermissions("sudo")
|
||||||
|
public void sudo(final CommandContext args, final CommandSender sender) throws CommandException {
|
||||||
|
Server server = sender.getServer();
|
||||||
|
int index = 1;
|
||||||
|
CommandSender other = userStore.find(args.getString(0, ""));
|
||||||
|
if(other == null) {
|
||||||
|
other = args.hasFlag('c') ? server.getConsoleSender() : sender;
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
if(!sender.equals(other) && !sender.hasPermission("sudo.others")) {
|
||||||
|
throw new CommandPermissionsException();
|
||||||
|
}
|
||||||
|
String command = args.getJoinedStrings(index);
|
||||||
|
List<String> commands = getPermutations(sender, command);
|
||||||
|
String explanation;
|
||||||
|
if(commands.size() == 1) {
|
||||||
|
explanation = "/" + commands.get(0);
|
||||||
|
} else {
|
||||||
|
explanation = commands.size() + ChatColor.WHITE.toString() + " commands";
|
||||||
|
}
|
||||||
|
sender.sendMessage("Executing " + ChatColor.AQUA + explanation + ChatColor.WHITE + " as " + identityProvider.currentIdentity(other).getName(sender));
|
||||||
|
for(String cmd : commands) {
|
||||||
|
if(commands.size() > 1 && args.hasFlag('d')) {
|
||||||
|
sender.sendMessage(" > " + cmd);
|
||||||
|
}
|
||||||
|
server.dispatchCommand(other, cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPermutations(CommandSender sender, String command) throws CommandException {
|
||||||
|
List<String> permutations = new ArrayList<>();
|
||||||
|
getPermutations(sender, command, permutations);
|
||||||
|
return permutations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getPermutations(CommandSender sender, String command, List<String> commands) throws CommandException {
|
||||||
|
Matcher matcher = Pattern.compile("\\*|[A-Za-z]{1,}=[A-Za-z0-9_-]{1,}").matcher(command);
|
||||||
|
if(matcher.find()) {
|
||||||
|
String keyValue = matcher.group();
|
||||||
|
for(String name : getPlayers(sender, keyValue).map(player -> player.getName(sender)).collect(Collectors.toImmutableList())) {
|
||||||
|
getPermutations(sender, matcher.replaceFirst(name), commands);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
commands.add(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<Player> getPlayers(CommandSender sender, String keyValue) throws CommandException {
|
||||||
|
Stream<Player> players = userStore.stream();
|
||||||
|
int seperator = keyValue.indexOf("=");
|
||||||
|
String key = seperator != -1 ? keyValue.substring(0, seperator) : keyValue;
|
||||||
|
String value = seperator != -1 ? keyValue.substring(seperator + 1, keyValue.length()) : "";
|
||||||
|
int parsed;
|
||||||
|
try {
|
||||||
|
parsed = Integer.parseInt(value);
|
||||||
|
} catch(NumberFormatException nfe) {
|
||||||
|
parsed = -1;
|
||||||
|
}
|
||||||
|
int valueInt = parsed;
|
||||||
|
switch(key) {
|
||||||
|
case "rand":
|
||||||
|
return players.collect(Collectors.toRandomSubList(valueInt)).stream();
|
||||||
|
case "mode":
|
||||||
|
return players.filter(p -> p.getGameMode().getValue() == valueInt);
|
||||||
|
case "near":
|
||||||
|
Location location = CommandUtils.senderToPlayer(sender).getLocation();
|
||||||
|
return players.filter(p -> p.getLocation().distance(location) <= valueInt);
|
||||||
|
case "color":
|
||||||
|
ChatColor color = CommandUtils.getEnum(value, sender, ChatColor.class, ChatColor.WHITE);
|
||||||
|
return players.filter(p -> getFuzzyColor(p).equals(color));
|
||||||
|
case "perm":
|
||||||
|
return players.filter(p -> p.hasPermission(value));
|
||||||
|
case "*":
|
||||||
|
return Streams.shuffle(players);
|
||||||
|
default:
|
||||||
|
throw new CommandException("Unrecognized player filter '" + key + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChatColor getFuzzyColor(CommandSender sender) {
|
||||||
|
if(sender instanceof Player) {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
Matcher matcher = ChatColor.STRIP_COLOR_PATTERN.matcher(player.getDisplayName(sender));
|
||||||
|
String color = null;
|
||||||
|
while(matcher.find()) {
|
||||||
|
color = matcher.group();
|
||||||
|
}
|
||||||
|
if(color != null) {
|
||||||
|
return ChatColor.getByChar(color.charAt(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ChatColor.WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,6 +5,11 @@ import com.sk89q.minecraft.util.commands.CommandContext;
|
||||||
import com.sk89q.minecraft.util.commands.CommandException;
|
import com.sk89q.minecraft.util.commands.CommandException;
|
||||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||||
import com.sk89q.minecraft.util.commands.NestedCommand;
|
import com.sk89q.minecraft.util.commands.NestedCommand;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.permissions.Permission;
|
import org.bukkit.permissions.Permission;
|
||||||
|
@ -14,12 +19,6 @@ import tc.oc.api.util.Permissions;
|
||||||
import tc.oc.commons.core.commands.Commands;
|
import tc.oc.commons.core.commands.Commands;
|
||||||
import tc.oc.commons.core.commands.NestedCommands;
|
import tc.oc.commons.core.commands.NestedCommands;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class PermissionCommands implements NestedCommands {
|
public class PermissionCommands implements NestedCommands {
|
||||||
public static class Parent implements Commands {
|
public static class Parent implements Commands {
|
||||||
@Command(
|
@Command(
|
||||||
|
|
|
@ -4,11 +4,10 @@ import com.google.common.base.Preconditions;
|
||||||
import com.sk89q.minecraft.util.commands.CommandException;
|
import com.sk89q.minecraft.util.commands.CommandException;
|
||||||
import com.sk89q.minecraft.util.commands.WrappedCommandSender;
|
import com.sk89q.minecraft.util.commands.WrappedCommandSender;
|
||||||
import com.sk89q.minecraft.util.pagination.PaginatedResult;
|
import com.sk89q.minecraft.util.pagination.PaginatedResult;
|
||||||
|
import java.util.List;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import tc.oc.commons.core.chat.ChatUtils;
|
import tc.oc.commons.core.chat.ChatUtils;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class PrettyPaginatedResult<T> extends PaginatedResult<T> {
|
public abstract class PrettyPaginatedResult<T> extends PaginatedResult<T> {
|
||||||
protected final String header;
|
protected final String header;
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue