Last active
November 2, 2024 00:54
Empire Command SystemFramework licensed MIT - WORK TO MAKE THIS A LIBRARY: https://github.com/aikar/commands
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface CommandAlias { | |
String value(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface CommandCompletion { | |
String value(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface CommandPermission { | |
String value(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface Default { | |
String value() default ""; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface Flags { | |
String value(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface Optional { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
/** | |
* Don't join remaining arguments | |
*/ | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface Single {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface Split { | |
String value() default ","; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface Subcommand { | |
String value(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface Syntax { | |
String value(); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface Values { | |
String value(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands; | |
import com.empireminecraft.config.EmpireServer; | |
import com.empireminecraft.config.PlayerSettingKey; | |
import com.empireminecraft.data.EmpireUser; | |
import com.empireminecraft.features.friends.Friend; | |
import com.empireminecraft.features.items.CustomItems; | |
import com.empireminecraft.features.survival.mobs.CustomMob; | |
import com.empireminecraft.systems.db.DbRow; | |
import com.empireminecraft.systems.db.EmpireDb; | |
import com.empireminecraft.systems.residence.TagManager; | |
import com.empireminecraft.systems.residence.protection.Residence; | |
import com.empireminecraft.systems.residence.protection.ResidenceFlag; | |
import com.empireminecraft.systems.residence.protection.ResidenceFlags; | |
import com.empireminecraft.systems.residence.protection.ResidenceStore; | |
import com.empireminecraft.util.NumUtil; | |
import com.empireminecraft.util.Patterns; | |
import com.empireminecraft.util.UserUtil; | |
import com.empireminecraft.util.Util; | |
import com.google.common.collect.ImmutableList; | |
import com.google.common.collect.Lists; | |
import org.bukkit.command.CommandSender; | |
import org.bukkit.entity.EntityType; | |
import org.bukkit.entity.Player; | |
import java.sql.SQLException; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.List; | |
import java.util.stream.Collectors; | |
import java.util.stream.IntStream; | |
import java.util.stream.Stream; | |
public final class CommandCompletions { | |
private CommandCompletions() {} | |
private static final List<String> EMPTY = ImmutableList.of(); | |
public static List<String> of(CommandSender sender, String completion, String input) { | |
if (completion == null) { | |
return ImmutableList.of(); | |
} | |
String[] complete = Patterns.COLON.split(completion, 2); | |
switch (complete[0]) { | |
case "@promos": | |
try { | |
final List<DbRow> rows = EmpireDb.getResults("SELECT name, enabled FROM promos"); | |
final List<String> promos = new ArrayList<>(); | |
rows.stream() | |
.filter(row -> ( | |
complete.length == 2 && "all".equals(complete[1])) | |
|| ((Integer) 1).equals(row.get("enabled"))) | |
.forEach(row -> promos.add(row.get("name"))); | |
return promos; | |
} catch (SQLException e) { | |
Util.sendMsg(sender, "&cError getting promotions"); | |
Util.printException("Exception in getting promos", e); | |
} | |
break; | |
case "@friends": { | |
if ((sender instanceof Player)) { | |
final Player player = (Player) sender; | |
final EmpireUser user = player.getUser(); | |
return user.getFriendsList() | |
.getFriends() | |
.valueCollection() | |
.stream() | |
.map(Friend::getFriendName) | |
.collect(Collectors.toList()); | |
} | |
break; | |
} | |
case "@bannedplayers": | |
if (!(sender instanceof Player) || UserUtil.isModerator((Player) sender)) { | |
try { | |
return EmpireDb.getFirstColumnResults( | |
"SELECT u.name FROM user_ban b JOIN user u ON b.user_id = u.user_id WHERE " + | |
"u.name LIKE ?", input + "%"); | |
} catch (SQLException e) { | |
e.printStackTrace(); | |
} | |
return ImmutableList.of(); | |
} | |
break; | |
case "@flags": | |
final Collection<ResidenceFlag> allFlags = ResidenceFlags.getFlags(); | |
List<String> flags = Lists.newArrayListWithExpectedSize(allFlags.size() * 2); | |
allFlags.forEach(flag -> { | |
if (flag.subFlags.isEmpty()) { | |
if (flag.parent == null) { // ignore subflags since they are in allFlags map | |
flags.add(flag.name); | |
} | |
} else { | |
flags.addAll(flag.subFlags.stream() | |
.map(sflag -> flag.name + ":" + sflag.name) | |
.collect(Collectors.toList())); | |
} | |
}); | |
return flags; | |
case "@biomes": | |
return Residence.getAllowedBiomes(false); | |
case "@flagstates": | |
return ImmutableList.of("true","t","false","f","remove","r"); | |
case "@residences": | |
List<String> list = Lists.newArrayList(); | |
list.addAll(ResidenceStore.nameMap.keySet()); | |
if (!input.isEmpty()) { | |
String first = input.substring(0, 1); | |
if (NumUtil.isNumber(first)) { | |
list.addAll(ResidenceStore.addrMap.keySet().stream().map(String::valueOf).collect(Collectors.toList())); | |
} else if ("+".equals(first)) { | |
list.addAll(TagManager.tagMap.keySet().stream().map((tag) -> "+" + tag).collect(Collectors.toList())); | |
} | |
} | |
return list; | |
case "@range": | |
if (complete.length == 1) { | |
return ImmutableList.of(); | |
} | |
final String[] ranges = Patterns.DASH.split(complete[1]); | |
int start; | |
int end; | |
if (ranges.length != 2) { | |
start = 0; | |
end = Util.parseInt(ranges[0], 0); | |
} else { | |
start = Util.parseInt(ranges[0], 0); | |
end = Util.parseInt(ranges[1], 0); | |
} | |
return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); | |
case "@timeunits": | |
return ImmutableList.of("hours", "days", "weeks", "months", "minutes"); | |
case "@allplayers": | |
return EmpireUser.lookupNames(input, | |
complete.length > 1 ? Util.parseInt(complete[1]) : null); | |
case "@rareitems": | |
return Lists.newArrayList(CustomItems.customItems.keySet()); | |
case "@mobs": | |
final Stream<String> normal = Stream.of(EntityType.values()) | |
.map(entityType -> Util.simplifyString(entityType.getName())); | |
final Stream<String> custom = CustomMob.allTypes.values().stream() | |
.map(customMob -> Util.simplifyString(customMob.customType)); | |
return Stream.concat(normal, custom).collect(Collectors.toList()); | |
case "@psetting": | |
return Stream.of(PlayerSettingKey.values()).map((key) -> key.key).collect(Collectors.toList()); | |
case "@staffplayers": | |
return Util.nullDefault(EmpireUser.lookupStaff(input), EMPTY); | |
case "@servers": | |
return Util.enumNames(EmpireServer.values()); | |
default: | |
return Lists.newArrayList(Patterns.PIPE.split(completion)); | |
} | |
return EMPTY; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands; | |
import com.empireminecraft.commands.features.*; | |
import com.empireminecraft.commands.misc.*; | |
import com.empireminecraft.commands.staff.*; | |
import org.bukkit.Bukkit; | |
public final class Commands { | |
private Commands() {} | |
public static void initialize() { | |
new ForumPassCommand(); | |
new ChatCommand(); | |
new VoteCommand(); | |
new WasteCommand(); | |
new FrontierCommand(); | |
new WasteNetherCommand(); | |
new FrontierNetherCommand(); | |
new PlayerSettingCommand(); | |
new AssistantCommand(); | |
new MapCommand(); | |
new CurrencyCommand(); | |
new ReportCommand(); | |
new ResidenceCommand(); | |
new VaultCommand(); | |
new FriendsCommand(); | |
// Staff Commands | |
new GoToCommand(); | |
new ModCommands(); | |
new EMCBotCommands(); | |
new SrStaffCommands(); | |
new ModeCommand(); | |
new GriefLogCommand(); | |
// Misc | |
new OtherPluginsCommands(); | |
new PlayerInfoCommand(); | |
new PlayerNoteCommand(); | |
new StaffCommand(); | |
new MiscCommands(); | |
new ServerCommand(); | |
new HelpCommand(); | |
new CompassCommand(); | |
// RCON / CommandQueue | |
new BackendCommands(); | |
Bukkit.getServer().getCommandMap().register("empire", new EnchantCommand()); | |
EnchantCommand.buildEnchantments(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.misc; | |
import com.empireminecraft.commands.EmpireCommand; | |
import com.empireminecraft.commands.annotation.CommandAlias; | |
import com.empireminecraft.commands.annotation.Default; | |
import com.empireminecraft.commands.annotation.Subcommand; | |
import com.empireminecraft.config.EmpireServer; | |
import com.empireminecraft.data.Worlds; | |
import com.empireminecraft.systems.Formatting; | |
import com.empireminecraft.systems.db.DbRow; | |
import com.empireminecraft.systems.db.EmpireDb; | |
import com.empireminecraft.systems.outposts.Frontier; | |
import com.empireminecraft.systems.outposts.Wastelands; | |
import com.empireminecraft.systems.residence.protection.Residence; | |
import com.empireminecraft.systems.residence.protection.ResidenceStore; | |
import com.empireminecraft.util.*; | |
import org.bukkit.Location; | |
import org.bukkit.World; | |
import org.bukkit.entity.Player; | |
import java.sql.SQLException; | |
import java.util.List; | |
import static com.empireminecraft.systems.Formatting.*; | |
import static com.empireminecraft.util.Util.printException; | |
@CommandAlias("comp|location|loc") | |
public class CompassCommand extends EmpireCommand { | |
public CompassCommand() { | |
super("compass"); | |
} | |
@Subcommand("set") | |
public static void setCompass(Player player, Integer x, Integer z) { | |
final World world = player.getWorld(); | |
if (!Worlds.isWilderness(world)) { | |
Util.sendMsg(player, COL_ERR + "Compass targets may only be set in the overworld."); | |
} | |
player.setCompassTarget(new Location(player.getWorld(), x, 64, z)); | |
Util.sendMsg(player, COL_PRI + "Set compass target to " + COL_SEC + x + "," + z); | |
} | |
@Subcommand("bed") | |
public static void bedCompass(Player player) { | |
World world = player.getWorld(); | |
Location bedLoc = player.getBedSpawnLocation(); | |
if (bedLoc == null) { | |
Util.sendMsg(player, COL_ERR + "You do not have a valid bed spawn set"); | |
return; | |
} | |
if (world != bedLoc.getWorld()) { | |
Util.sendMsg(player, COL_ERR + "Wrong World. Bed is in world &f" + bedLoc.getWorld().getName()); | |
return; | |
} | |
if (!Worlds.isWilderness(world)) { | |
Util.sendMsg(player, COL_ERR + "Compass targets may only be set in the overworld."); | |
} | |
player.setCompassTarget(bedLoc); | |
Util.sendMsg(player, COL_PRI + "&aSet compass target to " + COL_SEC + Util.formatLocation(bedLoc)); | |
} | |
@Subcommand("spawn|outpost") | |
public static void spawnCompass(Player player) { | |
Location loc = setSpawnCompass(player); | |
if (loc != null) { | |
Util.sendMsg(player, COL_PRI + "&aSet compass target to " + COL_SEC + Util.formatLocation(loc)); | |
} | |
} | |
public static Location setSpawnCompass(Player player) { | |
final World world = player.getWorld(); | |
if (!Worlds.isWilderness(world)) { | |
Util.sendMsg(player, COL_ERR + "Compass targets may only be set in the overworld."); | |
return null; | |
} | |
Location loc = world.getSpawnLocation(); | |
if (Worlds.isWastelands(world)) { | |
loc = Wastelands.getCurrentRegion(player.getLocation()).getSpawnLocation(world); | |
} else if (Worlds.isFrontier(world) && Worlds.isPrimaryWorld(world)) { | |
loc = Frontier.getNearestOutpost(player.getLocation()).center; | |
} else if (world == Worlds.TOWN) { | |
List<Residence> resList = ResidenceStore.getByOwner(player.getUserId()); | |
if (!resList.isEmpty()) { | |
loc = resList.get(0).getTPLoc(); | |
} | |
} | |
player.setCompassTarget(loc); | |
return loc; | |
} | |
@Subcommand("distance|dis") | |
public static void onDistance(Player player) { | |
double distance = Util.distance2d(player.getLocation(), player.getCompassTarget()); | |
Util.sendMsg(player, COL_PRI + "Distance to compass target is " + COL_SEC + Util.round(distance, 2)); | |
} | |
@Subcommand("death") | |
public static void deathCompass(final Player player) { | |
final Long userId = player.getUserId(); | |
final Integer serverId = EmpireServer.getServerId(); | |
BukkitUtil.runTaskAsync( () -> { | |
try { | |
DbRow row = EmpireDb.getFirstRow("SELECT * FROM log_death WHERE user_id=? AND server_id=? ORDER BY time DESC LIMIT 1", userId, serverId); | |
if (row == null) { | |
Util.sendMsg(player, "&cYou have not died on this server... yet!"); | |
return; | |
} | |
String[] msg = Patterns.SPACE_DASH_SPACE.split(row.get("death_message")); | |
Location deathLoc = Util.stringToLocation(msg[0]); | |
World world = player.getWorld(); | |
if (world != deathLoc.getWorld()) { | |
Util.sendMsg(player, COL_ERR + "Wrong World. Last death is in world &f" + deathLoc.getWorld().getName()); | |
return; | |
} | |
if (!Worlds.isWilderness(world)) { | |
Util.sendMsg(player, COL_ERR + "Compass targets may only be set in the overworld."); | |
} | |
player.setCompassTarget(deathLoc); | |
Util.sendMsg(player, COL_PRI + "&aSet compass target to " + COL_SEC + Util.formatLocation(deathLoc)); | |
} catch (SQLException e) { | |
printException("Exception in deathCompass: " + player.getName(), e); | |
Util.sendMsg(player, "&cUnknown error."); | |
} | |
}); | |
} | |
@CommandAlias("direction|dir") | |
public static void onDirection(Player player) { | |
String direction; | |
float yaw = player.getLocation().getYaw(); | |
if (yaw < 0) { yaw += 360; } | |
if (NumUtil.isBetween(yaw, 0, 22.5)) { direction = "South"; } | |
else if (NumUtil.isBetween(yaw, 22.5, 67.5)) { direction = "South West"; } | |
else if (NumUtil.isBetween(yaw, 67.5, 117.5)) { direction = "West"; } | |
else if (NumUtil.isBetween(yaw, 117.5, 157.5)) { direction = "North West"; } | |
else if (NumUtil.isBetween(yaw, 157.5, 202.5)) { direction = "North"; } | |
else if (NumUtil.isBetween(yaw, 202.5, 247.5)) { direction = "North East"; } | |
else if (NumUtil.isBetween(yaw, 247.5, 292.5)) { direction = "East"; } | |
else if (NumUtil.isBetween(yaw, 292.5, 337.5)) { direction = "South East"; } | |
else if (NumUtil.isBetween(yaw, 337.5, 360)) {direction = "South";} | |
else { direction = "Unknown"; } | |
Util.sendMsg(player, COL_PRI + "You are facing: " + COL_SEC + direction); | |
} | |
@Default | |
@Subcommand("default") | |
public static void onLocation(Player player, @Default("false") Boolean showDebug) { | |
Util.sendMsg(player, Formatting.heading("Your Location")); | |
Location loc = player.getLocation(); | |
ChatAPI.newMessage() | |
.msgColor(COL_PRI + "You are on " + COL_SEC + EmpireServer.getServer().name()) | |
.msgColor(COL_PRI + " @ " + COL_SEC + Util.formatLocation(loc)) | |
.msgColor(COL_TERT + " [LIVEMAP]") | |
.tooltip("Click to go to Live Map") | |
.link(MapCommand.getMapLink(loc)) | |
.send(player); | |
onDirection(player); | |
if (Worlds.isWastelands(player.getWorld())) { | |
Util.sendMsg(player, COL_PRI + "You are in the &cWastelands " + COL_SEC + Wastelands.getCurrentRegion(loc).name + COL_PRI + " region."); | |
} | |
if (loc.getWorld() == Worlds.FRONTIER_WILD) { | |
Util.sendMsg(player, COL_PRI + "You are in the &9Frontier " + COL_SEC + Frontier.getNearestOutpost(loc).name + COL_PRI + " region."); | |
} | |
Util.sendMsg(player, COL_PRI + "Compass target: " + COL_SEC + Util.formatLocation(player.getCompassTarget())); | |
onDistance(player); | |
if (showDebug) { | |
Util.sendMsg(player, COL_PRI + "Chunk: " + COL_TERT + | |
(loc.getBlockX() >> 4) + "," + | |
(loc.getBlockZ() >> 4)); | |
Util.sendMsg(player, COL_PRI + "Region File: " + COL_TERT + | |
(loc.getBlockX() >> 9) + "," + | |
(loc.getBlockZ() >> 9)); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.contexts; | |
import com.empireminecraft.commands.InvalidCommandArgument; | |
import com.empireminecraft.data.EmpireUser; | |
import lombok.Data; | |
import org.bukkit.entity.Player; | |
@Data public class AnyPlayer { | |
final EmpireUser user; | |
public Player getPlayer() { | |
return user.player; | |
} | |
public static ContextResolver<AnyPlayer> getResolver() { | |
return (c) -> { | |
String who = c.popFirstArg(); | |
EmpireUser user = EmpireUser.getUserLoosely(who); | |
if (user == null) { | |
throw new InvalidCommandArgument("Could not find a player with the username " + who); | |
} | |
return new AnyPlayer(user); | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.contexts; | |
import com.empireminecraft.commands.InvalidCommandArgument; | |
import com.empireminecraft.commands.annotation.Single; | |
import com.empireminecraft.commands.annotation.Split; | |
import com.empireminecraft.commands.annotation.Values; | |
import com.empireminecraft.config.language.MiscLang; | |
import com.empireminecraft.data.EmpireUser; | |
import com.empireminecraft.data.Worlds; | |
import com.empireminecraft.features.EmpireMobArena; | |
import com.empireminecraft.features.friends.Friend; | |
import com.empireminecraft.systems.residence.protection.Residence; | |
import com.empireminecraft.systems.residence.protection.ResidenceFlagGroup; | |
import com.empireminecraft.systems.residence.selection.SelectionManager; | |
import com.empireminecraft.util.Patterns; | |
import com.empireminecraft.util.UserUtil; | |
import com.empireminecraft.util.Util; | |
import com.google.common.collect.Maps; | |
import com.sk89q.worldedit.bukkit.selections.CuboidSelection; | |
import org.bukkit.Bukkit; | |
import org.bukkit.World; | |
import org.bukkit.command.CommandSender; | |
import org.bukkit.configuration.InvalidConfigurationException; | |
import org.bukkit.entity.Entity; | |
import org.bukkit.entity.Player; | |
import org.spigotmc.SneakyThrow; | |
import java.util.List; | |
import java.util.Map; | |
public final class CommandContexts { | |
static final Map<Class<?>, ContextResolver<?>> contextMap = Maps.newHashMap(); | |
private CommandContexts() {} | |
public static void initialize() { | |
registerSenderAwareContext(Residence.class, Residence.getResolver()); | |
registerContext(Integer.class, (c) -> { | |
try { | |
return Integer.parseInt(c.popFirstArg()); | |
} catch (NumberFormatException e) { | |
throw new InvalidCommandArgument("Must be a number"); | |
} | |
}); | |
registerContext(Long.class, (c) -> { | |
try { | |
return Long.parseLong(c.popFirstArg()); | |
} catch (NumberFormatException e) { | |
throw new InvalidCommandArgument("Must be a number"); | |
} | |
}); | |
registerContext(Float.class, (c) -> { | |
try { | |
return Float.parseFloat(c.popFirstArg()); | |
} catch (NumberFormatException e) { | |
throw new InvalidCommandArgument("Must be a number"); | |
} | |
}); | |
registerContext(Double.class, (c) -> { | |
try { | |
return Double.parseDouble(c.popFirstArg()); | |
} catch (NumberFormatException e) { | |
throw new InvalidCommandArgument("Must be a number"); | |
} | |
}); | |
registerContext(Boolean.class, (c) -> { | |
switch (c.popFirstArg()) { | |
case "t": | |
case "true": | |
case "on": | |
case "y": | |
case "yes": | |
case "1": | |
return true; | |
} | |
return false; | |
}); | |
registerContext(String.class, (c) -> { | |
final Values values = c.getParam().getAnnotation(Values.class); | |
if (values != null) { | |
return c.popFirstArg(); | |
} | |
if (c.isLastArg() && c.getParam().getAnnotation(Single.class) == null) { | |
return Util.join(c.getArgs()); | |
} | |
return c.popFirstArg(); | |
}); | |
registerContext(String[].class, (c) -> { | |
String val; | |
if (c.isLastArg() && c.getParam().getAnnotation(Single.class) == null) { | |
val = Util.join(c.getArgs()); | |
} else { | |
val = c.popFirstArg(); | |
} | |
Split split = c.getParam().getAnnotation(Split.class); | |
if (split != null) { | |
if (val.isEmpty()) { | |
throw new InvalidCommandArgument(); | |
} | |
return Patterns.getPattern(split.value()).split(val); | |
} else if (!c.isLastArg()) { | |
SneakyThrow.sneaky(new InvalidConfigurationException("Weird Command signature... String[] should be last or @Split")); | |
} | |
String[] result = c.getArgs().toArray(new String[c.getArgs().size()]); | |
c.getArgs().clear(); | |
return result; | |
}); | |
registerContext(EmpireUser.class, (c) -> { | |
String who = c.popFirstArg(); | |
if (!UserUtil.isValidName(who)) { | |
throw new InvalidCommandArgument("Invalid Minecraft Name Format. 3-16 characters"); | |
} | |
EmpireUser user = c.hasFlag("loose") ? EmpireUser.getUserLoosely(who) : EmpireUser.getUser(who); | |
if (user == null) { | |
throw new InvalidCommandArgument("Could not find user " + who); | |
} | |
return user; | |
}); | |
registerContext(EmpireUser[].class, (c) -> { | |
String who; | |
if (c.isLastArg() && c.getParam().getAnnotation(Single.class) == null) { | |
who = Util.join(c.getArgs()); | |
} else { | |
who = c.popFirstArg(); | |
} | |
final Integer days = c.getFlagValue("days", 30); | |
final List<EmpireUser> users = EmpireUser.getUsers((Player) c.getSender(), who, days); | |
if (users.isEmpty()) { | |
throw new InvalidCommandArgument("Could not find any of the specified users"); | |
} | |
return users.toArray(new EmpireUser[users.size()]); | |
}); | |
registerContext(OnlinePlayer.class, (c) -> { | |
final String playercheck = c.popFirstArg(); | |
Player player = UserUtil.findPlayerSmart(c.getSender(), playercheck); | |
if (player == null) { | |
Util.sendMsg(c.getSender(), "&cCould not find a player by the name " + playercheck); | |
throw new InvalidCommandArgument(false); | |
} | |
return new OnlinePlayer(player); | |
}); | |
registerSenderAwareContext(World.class, (c) -> { | |
String firstArg = c.getFirstArg(); | |
World world = firstArg != null ? Bukkit.getWorld(Worlds.getWorldByAlias(firstArg)) : null; | |
if (world != null) { | |
c.popFirstArg(); | |
} | |
if (world == null && c.getSender() instanceof Player) { | |
world = ((Entity) c.getSender()).getWorld(); | |
} | |
if (world == null) { | |
throw new InvalidCommandArgument("Invalid World"); | |
} | |
return world; | |
}); | |
registerContext(AnyPlayer.class, AnyPlayer.getResolver()); | |
registerSenderAwareContext(CommandSender.class, CommandExecutionContext::getSender); | |
registerSenderAwareContext(Player.class, (c) -> c.getSender() instanceof Player ? (Player) c.getSender() : null); | |
registerSenderAwareContext(EmpireMobArena.class, c -> { | |
Residence residence = Residence.getResidence((Entity) c.getSender()); | |
if (residence == null || !"mobarena".equals(residence.getTopParent().getName())) { | |
Util.sendMsg(c.getSender(), MiscLang.NOT_IN_MBA); | |
throw new InvalidCommandArgument(false); | |
} | |
// TODO: Remove static ref and be a res feature | |
return EmpireMobArena.instance; | |
}); | |
registerContext(ResidenceFlagGroup.class, ResidenceFlagGroup.getContextResolver()); | |
registerContext(Friend.class, (c) -> { | |
if (!(c.getSender() instanceof Player)) { | |
throw new InvalidCommandArgument("Only players can run this."); | |
} | |
Player player = (Player) c.getSender(); | |
EmpireUser user = player.getUser(); | |
final String firstArg = c.popFirstArg(); | |
if (firstArg == null) { | |
throw new InvalidCommandArgument("Please specify a friends name."); | |
} | |
EmpireUser lookup = EmpireUser.getUserLoosely(firstArg, 90); | |
if (lookup == null) { | |
throw new InvalidCommandArgument("Could not find a player by that name who has played recently.", false); | |
} | |
Friend friend = user.getFriendsList().getFriend(lookup); | |
if (friend == null) { | |
throw new InvalidCommandArgument("That player is not your friend.", false); | |
} | |
return friend; | |
}); | |
registerSenderAwareContext(CuboidSelection.class, (c) -> { | |
if (!(c.getSender() instanceof Player)) { | |
throw new InvalidCommandArgument("Only players can run this."); | |
} | |
CuboidSelection selection = SelectionManager.getSelection((Player) c.getSender()); | |
if (selection == null) { | |
throw new InvalidCommandArgument("You must first make a Cuboid Selection."); | |
} | |
return selection; | |
}); | |
} | |
public static <T> void registerSenderAwareContext(Class<T> context, SenderAwareContextResolver<T> supplier) { | |
contextMap.put(context, supplier); | |
} | |
public static <T> void registerContext(Class<T> context, ContextResolver<T> supplier) { | |
contextMap.put(context, supplier); | |
} | |
public static ContextResolver<?> getResolver(Class<?> type) { | |
Class<?> rootType = type; | |
do { | |
if (type == Object.class) { | |
break; | |
} | |
final ContextResolver<?> resolver = contextMap.get(type); | |
if (resolver != null) { | |
return resolver; | |
} | |
} while ((type = type.getSuperclass()) != null); | |
Util.printException(new InvalidConfigurationException("No context resolver defined for " + rootType.getName())); | |
return null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.contexts; | |
import com.empireminecraft.commands.RegisteredCommand; | |
import com.empireminecraft.commands.annotation.Default; | |
import com.empireminecraft.commands.annotation.Flags; | |
import com.empireminecraft.commands.annotation.Optional; | |
import com.empireminecraft.util.Patterns; | |
import com.empireminecraft.util.Util; | |
import com.google.common.collect.ImmutableMap; | |
import com.google.common.collect.Maps; | |
import lombok.Data; | |
import org.bukkit.command.CommandSender; | |
import java.lang.reflect.Parameter; | |
import java.util.List; | |
import java.util.Map; | |
@Data public class CommandExecutionContext { | |
private final RegisteredCommand cmd; | |
private final Parameter param; | |
private final CommandSender sender; | |
private final List<String> args; | |
private final int index; | |
private final List<Object> passedArgs; | |
private final Map<String, String> flags; | |
public CommandExecutionContext(RegisteredCommand cmd, Parameter param, CommandSender sender, List<String> args, | |
int index, List<Object> passedArgs) { | |
this.cmd = cmd; | |
this.param = param; | |
this.sender = sender; | |
this.args = args; | |
this.index = index; | |
this.passedArgs = passedArgs; | |
Flags flags = param.getAnnotation(Flags.class); | |
if (flags != null) { | |
this.flags = Maps.newHashMap(); | |
for (String s : Patterns.COMMA.split(flags.value())) { | |
String[] v = Patterns.EQUALS.split(s, 2); | |
this.flags.put(v[0], v.length > 1 ? v[1] : null); | |
} | |
} else { | |
this.flags = ImmutableMap.of(); | |
} | |
} | |
public String popFirstArg() { | |
return !args.isEmpty() ? args.remove(0) : null; | |
} | |
public String getFirstArg() { | |
return !args.isEmpty() ? args.get(0) : null; | |
} | |
public boolean isLastArg() { | |
return cmd.parameters.length -1 == index; | |
} | |
public int getNumParams() { | |
return cmd.parameters.length; | |
} | |
public boolean canOverridePlayerContext() { | |
int numRequired = getNumParams(); | |
for (int i = 0; i < cmd.resolvers.length; i++) { | |
Parameter parameter = cmd.parameters[i]; | |
ContextResolver<?> resolver = cmd.resolvers[i]; | |
if (parameter.getAnnotation(Optional.class) != null || parameter.getAnnotation(Default.class) != null) { | |
numRequired--; | |
} else if (resolver instanceof SenderAwareContextResolver) { | |
numRequired--; | |
} | |
} | |
return numRequired >= args.size(); | |
} | |
public <T> T getOtherArgContext(Class<?> clazz) { | |
for (Object passedArg : passedArgs) { | |
if (clazz.isInstance(passedArg)) { | |
return (T) passedArg; | |
} | |
} | |
return null; | |
} | |
public boolean isOptional() { | |
return param.getAnnotation(Optional.class) != null; | |
} | |
public boolean hasFlag(String flag) { | |
return flags.containsKey(flag); | |
} | |
public String getFlagValue(String flag, String def) { | |
return flags.containsKey(flag) ? flags.get(flag) : def; | |
} | |
public Integer getFlagValue(String flag, Integer def) { | |
return Util.parseInt(this.flags.get(flag), def); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.contexts; | |
import com.empireminecraft.commands.InvalidCommandArgument; | |
@FunctionalInterface | |
public interface ContextResolver <C> { | |
C getContext(CommandExecutionContext c) throws InvalidCommandArgument; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.contexts; | |
import com.empireminecraft.data.EmpireUser; | |
import lombok.Data; | |
import org.bukkit.entity.Player; | |
@Data public class OnlinePlayer { | |
public final Player player; | |
public EmpireUser getUser() { | |
return EmpireUser.getUser(player); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands.contexts; | |
public interface SenderAwareContextResolver<C> extends ContextResolver <C> {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands; | |
import com.empireminecraft.commands.annotation.CommandAlias; | |
import com.empireminecraft.commands.annotation.CommandPermission; | |
import com.empireminecraft.commands.annotation.Default; | |
import com.empireminecraft.commands.annotation.Subcommand; | |
import com.empireminecraft.config.language.MiscLang; | |
import com.empireminecraft.util.Patterns; | |
import com.empireminecraft.util.Util; | |
import com.google.common.collect.*; | |
import lombok.AllArgsConstructor; | |
import lombok.Data; | |
import org.apache.commons.lang.StringUtils; | |
import org.bukkit.Bukkit; | |
import org.bukkit.command.Command; | |
import org.bukkit.command.CommandSender; | |
import org.bukkit.configuration.InvalidConfigurationException; | |
import org.bukkit.util.StringUtil; | |
import org.spigotmc.SneakyThrow; | |
import co.aikar.timings.Timing; | |
import java.lang.reflect.Method; | |
import java.util.*; | |
import java.util.stream.Collectors; | |
public abstract class EmpireCommand extends Command { | |
private final SetMultimap<String, RegisteredCommand> subCommands = HashMultimap.create(); | |
protected String execLabel; | |
protected String execSubcommand; | |
protected String[] origArgs; | |
public EmpireCommand() { | |
this(null); | |
} | |
public EmpireCommand(String cmd) { | |
super(cmd); | |
final Class<? extends EmpireCommand> self = this.getClass(); | |
CommandAlias rootCmdAlias = self.getAnnotation(CommandAlias.class); | |
if (cmd == null) { | |
if (rootCmdAlias == null) { | |
cmd = "__" + self.getSimpleName(); | |
} else { | |
cmd = Patterns.PIPE.split(rootCmdAlias.value())[0]; | |
} | |
cmd = cmd.toLowerCase(); | |
setName(cmd); | |
setLabel(cmd); | |
} | |
this.description = cmd + " commands"; | |
this.usageMessage = "/" + cmd; | |
final CommandPermission perm = self.getAnnotation(CommandPermission.class); | |
if (perm != null) { | |
this.setPermission(perm.value()); | |
} | |
boolean foundDefault = false; | |
for (Method method : self.getDeclaredMethods()) { | |
method.setAccessible(true); | |
String sublist = null; | |
final Subcommand sub = method.getAnnotation(Subcommand.class); | |
final Default def = method.getAnnotation(Default.class); | |
final CommandAlias commandAliases = method.getAnnotation(CommandAlias.class); | |
if (def != null) { | |
if (!foundDefault) { | |
registerSubcommand(method, "__default"); | |
foundDefault = true; | |
} else { | |
SneakyThrow.sneaky(new InvalidConfigurationException("Multiple @Default commands")); | |
} | |
} | |
if (sub != null) { | |
sublist = sub.value(); | |
} else if (commandAliases != null) { | |
sublist = commandAliases.value(); | |
} | |
if (sublist != null) { | |
registerSubcommand(method, sublist); | |
} | |
} | |
try { | |
Method unknown = self.getMethod("onUnknown", CommandSender.class, String.class, String[].class); | |
unknown.setAccessible(true); | |
registerSubcommand(unknown, "__unknown"); | |
} catch (NoSuchMethodException ignored) {} | |
if (rootCmdAlias != null) { | |
List<String> cmdList = new ArrayList<>(); | |
Collections.addAll(cmdList, Patterns.PIPE.split(rootCmdAlias.value().toLowerCase())); | |
cmdList.remove(cmd); | |
for (String cmdAlias : cmdList) { | |
register(cmdAlias, new ForwardingCommand(this)); | |
} | |
} | |
register(getName(), this); | |
} | |
private boolean register(String name, Command cmd) { | |
return Bukkit.getServer().getCommandMap().register(name.toLowerCase(), "empire", cmd); | |
} | |
private void registerSubcommand(Method method, String subCommand) { | |
subCommand = subCommand.toLowerCase(); | |
final String[] subCommandParts = Patterns.SPACE.split(subCommand); | |
// Must run getSubcommandPossibility BEFORE we rewrite it just after this. | |
List<String> cmdList = getSubCommandPossibilityList(subCommandParts); | |
// Strip pipes off for auto complete addition | |
for (int i = 0; i < subCommandParts.length; i++) { | |
subCommandParts[i] = Patterns.PIPE.split(subCommandParts[i])[0]; | |
} | |
String prefSubCommand = StringUtils.join(subCommandParts, " "); | |
final CommandAlias cmdAlias = method.getAnnotation(CommandAlias.class); | |
final String[] aliasNames = cmdAlias != null ? Patterns.PIPE.split(cmdAlias.value().toLowerCase()) : null; | |
String cmdName = aliasNames != null ? aliasNames[0] : getLabel() + " "; | |
RegisteredCommand cmd = new RegisteredCommand(this, cmdName, method, prefSubCommand); | |
for (String subcmd : cmdList) { | |
subCommands.put(subcmd, cmd); | |
} | |
if (aliasNames != null) { | |
for (String name : aliasNames) { | |
register(name, new ForwardingCommand(this, subCommandParts)); | |
} | |
} | |
} | |
/** | |
* Takes a string like "foo|bar baz|qux" and generates a list of | |
* - foo baz | |
* - foo qux | |
* - bar baz | |
* - bar qux | |
* | |
* For every possible sub command combination | |
* | |
* @param subCommandParts | |
* @return List of all sub command possibilities | |
*/ | |
private static List<String> getSubCommandPossibilityList(String[] subCommandParts) { | |
int i = 0; | |
ArrayList<String> current = null; | |
while (true) { | |
ArrayList<String> newList = new ArrayList<>(); | |
if (i < subCommandParts.length) { | |
for (String s1 : Patterns.PIPE.split(subCommandParts[i])) { | |
if (current != null) { | |
newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList())); | |
} else { | |
newList.add(s1); | |
} | |
} | |
} | |
if (i + 1 < subCommandParts.length) { | |
current = newList; | |
i = i + 1; | |
continue; | |
} | |
return newList; | |
} | |
} | |
@Override | |
public final boolean execute(CommandSender sender, String commandLabel, String[] args) { | |
if (!testPermission(sender)) { | |
return true; | |
} | |
commandLabel = commandLabel.toLowerCase(); | |
if (preCommand(sender, commandLabel, args)) { | |
return true; | |
} | |
execSubcommand = null; | |
execLabel = commandLabel; | |
origArgs = args; | |
if (args.length == 0) { | |
onDefault(sender, commandLabel); | |
return true; | |
} | |
CommandSearch cmd = findSubCommand(args); | |
if (cmd != null) { | |
execSubcommand = cmd.getCheckSub(); | |
final String[] execargs = Arrays.copyOfRange(args, cmd.argIndex, args.length); | |
executeCommand(sender, execargs, cmd.cmd); | |
return true; | |
} | |
if (!onUnknown(sender, commandLabel, args)) { | |
help(sender, args); | |
} | |
return true; | |
} | |
private CommandSearch findSubCommand(String[] args) { | |
return findSubCommand(args, false); | |
} | |
private CommandSearch findSubCommand(String[] args, boolean completion) { | |
for (int i = args.length; i >= 0; i--) { | |
String checkSub = StringUtils.join(args, " ", 0, i).toLowerCase(); | |
Set<RegisteredCommand> cmds = subCommands.get(checkSub); | |
final int extraArgs = args.length - i; | |
if (!cmds.isEmpty()) { | |
RegisteredCommand cmd = null; | |
if (cmds.size() == 1) { | |
cmd = Iterables.getOnlyElement(cmds); | |
} else { | |
Optional<RegisteredCommand> optCmd = cmds.stream().filter(c -> { | |
int nonSender = c.nonSenderAwareResolvers; | |
int partialSender = c.optionalResolvers; | |
return extraArgs <= nonSender + partialSender && (completion || extraArgs >= nonSender); | |
}).sorted((c1, c2) -> { | |
int a = c1.nonSenderAwareResolvers + c1.optionalResolvers; | |
int b = c2.nonSenderAwareResolvers + c2.optionalResolvers; | |
if (a == b) { | |
return 0; | |
} | |
return a < b ? 1 : -1; | |
}).findFirst(); | |
if (optCmd.isPresent()) { | |
cmd = optCmd.get(); | |
} | |
} | |
if (cmd != null) { | |
return new CommandSearch(cmd, i, checkSub); | |
} | |
} | |
} | |
return null; | |
} | |
private static void executeCommand(CommandSender sender, String[] args, RegisteredCommand cmd) { | |
if (cmd.hasPermission(sender)) { | |
List<String> sargs = Lists.newArrayList(args); | |
try (Timing subTiming = Util.startTiming("Command: " + cmd.command)) { | |
cmd.invoke(sender, sargs); | |
} | |
} else { | |
Util.sendMsg(sender, MiscLang.COMMAND_PERM_ERROR); | |
} | |
} | |
public boolean canExecute(CommandSender sender, RegisteredCommand cmd) { | |
return true; | |
} | |
@Override | |
public List<String> tabComplete(CommandSender sender, String commandLabel, String[] args) | |
throws IllegalArgumentException { | |
commandLabel = commandLabel.toLowerCase(); | |
final CommandSearch search = findSubCommand(args, true); | |
if (search != null) { | |
args = Arrays.copyOfRange(args, search.argIndex, args.length); | |
return completeCommand(sender, search.cmd, args, commandLabel); | |
} | |
String argString = StringUtils.join(args, " ").toLowerCase(); | |
final List<String> cmds = new ArrayList<>(); | |
for (Map.Entry<String, RegisteredCommand> entry : subCommands.entries()) { | |
final String key = entry.getKey(); | |
if (key.startsWith(argString) && !"__unknown".equals(key)) { | |
final RegisteredCommand value = entry.getValue(); | |
if (!value.hasPermission(sender)) { | |
continue; | |
} | |
String prefCommand = value.prefSubCommand; | |
final String[] psplit = Patterns.SPACE.split(prefCommand); | |
cmds.add(psplit[args.length - 1]); | |
} | |
} | |
final Set<RegisteredCommand> unknownCmds = subCommands.get("__unknown"); | |
if (cmds.isEmpty() && !unknownCmds.isEmpty()) { | |
RegisteredCommand unknownCommand = null; | |
if (unknownCmds.size() == 1) { | |
unknownCommand = Iterables.getOnlyElement(unknownCmds); | |
} | |
if (unknownCommand != null) { | |
return completeCommand(sender, unknownCommand, args, commandLabel); | |
} | |
} | |
return filterTabComplete(args[args.length-1], cmds); | |
} | |
private List<String> completeCommand(CommandSender sender, RegisteredCommand cmd, String[] args, String commandLabel) { | |
if (args.length > cmd.nonSenderAwareResolvers + cmd.optionalResolvers) { | |
return ImmutableList.of(); | |
} | |
if (args.length == 0 || cmd.complete == null) { | |
return args.length < 2 ? super.tabComplete(sender, commandLabel, args) : ImmutableList.of(); | |
} | |
String[] completions = Patterns.SPACE.split(cmd.complete.value()); | |
final int argIndex = args.length - 1; | |
String input = args[argIndex]; | |
final String completion = argIndex < completions.length ? completions[argIndex] : null; | |
if ("@players".equals(completion)) { | |
return super.tabComplete(sender, commandLabel, args); | |
} | |
List<String> cmds = CommandCompletions.of(sender, completion, input); | |
if (cmds.isEmpty()) { | |
cmds = ImmutableList.of(input); | |
} | |
return filterTabComplete(args[(argIndex)], cmds); | |
} | |
private static List<String> filterTabComplete(String arg, List<String> cmds) { | |
return cmds.stream() | |
.distinct() | |
.filter(cmd -> cmd != null && (arg.isEmpty() || StringUtil.startsWithIgnoreCase(cmd, arg))) | |
.collect(Collectors.toList()); | |
} | |
public void help(CommandSender sender, String[] args) { | |
Util.sendMsg(sender, "&cUnknown Command, please type &f/help"); | |
} | |
public void onDefault(CommandSender sender, String commandLabel) { | |
executeDefault(sender); | |
} | |
public boolean onUnknown(CommandSender sender, String commandLabel, String[] args) { | |
help(sender, args); | |
return true; | |
} | |
public boolean executeDefault(CommandSender sender, String... args) { | |
final Set<RegisteredCommand> defs = subCommands.get("__default"); | |
RegisteredCommand def = null; | |
if (!defs.isEmpty()) { | |
if (defs.size() == 1) { | |
def = Iterables.getOnlyElement(defs); | |
} | |
if (def != null) { | |
executeCommand(sender, args, def); | |
return true; | |
} | |
} | |
return false; | |
} | |
public boolean preCommand(CommandSender sender, String commandLabel, String[] args) { | |
return false; | |
} | |
public void doHelp(CommandSender sender, String... args) { | |
help(sender, args); | |
} | |
public void showSyntax(CommandSender sender, RegisteredCommand cmd) { | |
Util.sendMsg(sender, "&cUsage: /" + cmd.command + " " + cmd.syntax); | |
} | |
@Data @AllArgsConstructor | |
public static class CommandSearch { RegisteredCommand cmd; int argIndex; String checkSub; } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands; | |
import org.apache.commons.lang.ArrayUtils; | |
import org.bukkit.command.Command; | |
import org.bukkit.command.CommandSender; | |
import java.util.List; | |
public class ForwardingCommand extends Command { | |
private final Command command; | |
private final String[] baseArgs; | |
private static final String[] NO_ARGS = new String[0]; | |
public ForwardingCommand(Command command) { | |
this(command, NO_ARGS); | |
} | |
public ForwardingCommand(Command command, String[] baseArgs) { | |
super(command.getName()); | |
this.command = command; | |
this.baseArgs = baseArgs; | |
} | |
@Override | |
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { | |
return command.tabComplete(sender, alias, (String[]) ArrayUtils.addAll(baseArgs, args)); | |
} | |
@Override | |
public boolean execute(CommandSender sender, String commandLabel, String[] args) { | |
return command.execute(sender, commandLabel, (String[]) ArrayUtils.addAll(baseArgs, args)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands; | |
public class InvalidCommandArgument extends Exception { | |
public boolean showSyntax = true; | |
public InvalidCommandArgument() { | |
this(null); | |
} | |
public InvalidCommandArgument(boolean showSyntax) { | |
this(null, showSyntax); | |
} | |
public InvalidCommandArgument(String message) { | |
this(message, true); | |
} | |
public InvalidCommandArgument(String message, boolean showSyntax) { | |
super(message, null, false, false); | |
this.showSyntax = showSyntax; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.commands; | |
import com.empireminecraft.commands.annotation.*; | |
import com.empireminecraft.commands.contexts.CommandContexts; | |
import com.empireminecraft.commands.contexts.CommandExecutionContext; | |
import com.empireminecraft.commands.contexts.ContextResolver; | |
import com.empireminecraft.commands.contexts.SenderAwareContextResolver; | |
import com.empireminecraft.systems.residence.protection.Residence; | |
import com.empireminecraft.util.Patterns; | |
import com.empireminecraft.util.Util; | |
import com.google.common.collect.Lists; | |
import com.google.common.collect.Sets; | |
import org.bukkit.World; | |
import org.bukkit.command.CommandSender; | |
import org.bukkit.configuration.InvalidConfigurationException; | |
import org.bukkit.entity.Player; | |
import org.spigotmc.SneakyThrow; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Parameter; | |
import java.util.List; | |
import java.util.Set; | |
import java.util.stream.Collectors; | |
public class RegisteredCommand { | |
public final EmpireCommand scope; | |
public final String command; | |
public final Method method; | |
public final String prefSubCommand; | |
public final Parameter[] parameters; | |
public final ContextResolver<?>[] resolvers; | |
public final String syntax; | |
public final CommandPermission perm; | |
public final CommandCompletion complete; | |
public final int nonSenderAwareResolvers; | |
public final int optionalResolvers; | |
RegisteredCommand(EmpireCommand scope, String command, Method method, String prefSubCommand) { | |
this.scope = scope; | |
if ("__unknown".equals(prefSubCommand)) { | |
prefSubCommand = ""; | |
} | |
this.command = command + (method.getAnnotation(CommandAlias.class) == null && !prefSubCommand.isEmpty() ? prefSubCommand : ""); | |
this.method = method; | |
this.prefSubCommand = prefSubCommand; | |
this.perm = method.getAnnotation(CommandPermission.class); | |
this.complete = method.getAnnotation(CommandCompletion.class); | |
this.parameters = method.getParameters(); | |
this.resolvers = new ContextResolver[this.parameters.length]; | |
final Syntax syntaxStr = method.getAnnotation(Syntax.class); | |
int nonSenderAwareResolvers = 0; | |
int optionalResolvers = 0; | |
StringBuilder syntaxB = new StringBuilder(64); | |
for (int i = 0; i < parameters.length; i++) { | |
final Parameter parameter = parameters[i]; | |
final Class<?> type = parameter.getType(); | |
final ContextResolver<?> resolver = CommandContexts.getResolver(type); | |
if (resolver != null) { | |
resolvers[i] = resolver; | |
if (type == World.class || type == Residence.class || parameter.getAnnotation(Optional.class) != null | |
|| parameter.getAnnotation(Default.class) != null) { | |
optionalResolvers++; | |
} else if (!(resolver instanceof SenderAwareContextResolver)) { | |
nonSenderAwareResolvers++; | |
} | |
if (!CommandSender.class.isAssignableFrom(parameter.getType())) { | |
if (parameter.getAnnotation(Default.class) != null || | |
parameter.getAnnotation(Optional.class) != null || | |
resolver instanceof SenderAwareContextResolver) { | |
syntaxB.append('[').append(parameter.getName()).append("] "); | |
} else { | |
syntaxB.append('<').append(parameter.getName()).append("> "); | |
} | |
} | |
} else { | |
SneakyThrow.sneaky(new InvalidConfigurationException( | |
"Parameter " + type.getSimpleName() + " of " + this.command + " has no resolver" | |
)); | |
} | |
} | |
if (syntaxStr != null) { | |
this.syntax = syntaxStr.value(); | |
} else { | |
this.syntax = syntaxB.toString(); | |
} | |
this.nonSenderAwareResolvers = nonSenderAwareResolvers; | |
this.optionalResolvers = optionalResolvers; | |
} | |
public void invoke(CommandSender sender, List<String> args) { | |
if (!scope.canExecute(sender, this)) { | |
return; | |
} | |
try { | |
List<Object> passedArgs = Lists.newArrayList(); | |
for (int i = 0; i < parameters.length; i++) { | |
boolean isLast = i == parameters.length - 1; | |
final Parameter parameter = parameters[i]; | |
final Class<?> type = parameter.getType(); | |
final ContextResolver<?> resolver = resolvers[i]; | |
if (resolver != null) { | |
CommandExecutionContext context = new CommandExecutionContext(this, parameter, sender, args, i, passedArgs); | |
if (args.isEmpty() && !(isLast && type == String[].class)) { | |
Default def = parameter.getAnnotation(Default.class); | |
Optional opt = parameter.getAnnotation(Optional.class); | |
if (isLast && def != null) { | |
args.add(def.value()); | |
} else if (isLast && opt != null) { | |
passedArgs.add(null); | |
continue; | |
} else if (!(resolver instanceof SenderAwareContextResolver)) { | |
scope.showSyntax(sender, this); | |
return; | |
} | |
} else { | |
final Values values = parameter.getAnnotation(Values.class); | |
if (values != null) { | |
String arg = args.get(0); | |
final String[] split = Patterns.PIPE.split(values.value()); | |
Set<String> possible = Sets.newHashSet(); | |
for (String s : split) { | |
List<String> check = CommandCompletions.of(sender, s, arg); | |
if (!check.isEmpty()) { | |
possible.addAll(check.stream().map(String::toLowerCase).collect(Collectors.toList())); | |
} else { | |
possible.add(s.toLowerCase()); | |
} | |
} | |
if (!possible.contains(arg.toLowerCase())) { | |
throw new InvalidCommandArgument("Must be one of: " + Util.join(possible, ", ")); | |
} | |
} | |
} | |
passedArgs.add(resolver.getContext(context)); | |
} else { | |
Util.sendMsg(sender, "&cUnexpected Error. Staff have been notified of the bug."); | |
return; | |
} | |
} | |
method.invoke(scope, passedArgs.toArray()); | |
} catch (Exception e) { | |
if (e instanceof InvocationTargetException && e.getCause() instanceof InvalidCommandArgument) { | |
e = (Exception) e.getCause(); | |
} | |
if (e instanceof InvalidCommandArgument) { | |
if (e.getMessage() != null && !e.getMessage().isEmpty()) { | |
Util.sendMsg(sender, "&cInvalid Argument: " + e.getMessage()); | |
} | |
if (((InvalidCommandArgument) e).showSyntax) { | |
scope.showSyntax(sender, this); | |
} | |
} else { | |
Util.sendMsg(sender, "&cI'm sorry, but there was an error performing this command."); | |
Util.printException("Exception in command: " + command + " " + Util.join(args), e.getCause()); | |
} | |
} | |
} | |
public boolean hasPermission(CommandSender check) { | |
return perm == null || !(check instanceof Player) || check.hasPermission(perm.value()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment