001/*
002 *     Copyright 2021 Siroshun09
003 *
004 *     Licensed under the Apache License, Version 2.0 (the "License");
005 *     you may not use this file except in compliance with the License.
006 *     You may obtain a copy of the License at
007 *
008 *         http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *     Unless required by applicable law or agreed to in writing, software
011 *     distributed under the License is distributed on an "AS IS" BASIS,
012 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *     See the License for the specific language governing permissions and
014 *     limitations under the License.
015 */
016
017package com.github.siroshun09.mccommand.bungee;
018
019
020import com.github.siroshun09.mccommand.bungee.sender.BungeeSender;
021import com.github.siroshun09.mccommand.common.Command;
022import com.github.siroshun09.mccommand.common.context.CommandContext;
023import com.github.siroshun09.mccommand.common.context.SimpleCommandContext;
024import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
025import net.md_5.bungee.api.CommandSender;
026import net.md_5.bungee.api.ProxyServer;
027import net.md_5.bungee.api.plugin.Plugin;
028import net.md_5.bungee.api.plugin.TabExecutor;
029import org.jetbrains.annotations.NotNull;
030
031import java.util.concurrent.Executor;
032import java.util.concurrent.Executors;
033
034/**
035 * The class for registering commands to BungeeCord.
036 */
037public final class BungeeCommandFactory {
038
039    private BungeeCommandFactory() {
040        throw new UnsupportedOperationException();
041    }
042
043    /**
044     * Registers the command.
045     *
046     * @param plugin  the BungeeCord plugin
047     * @param command the command to register
048     */
049    public static void register(@NotNull Plugin plugin, @NotNull Command command) {
050        ProxyServer.getInstance()
051                .getPluginManager()
052                .registerCommand(
053                        plugin,
054                        new BungeeCommandImpl(plugin, command)
055                );
056    }
057
058    /**
059     * Registers the command.
060     * <p>
061     * If you register a command with this method, it will be executed asynchronously.
062     * <p>
063     * Note:
064     * <p>
065     * The tab completion will execute on main thread.
066     *
067     * @param plugin  the BungeeCord plugin
068     * @param command the command to register
069     */
070    public static void registerAsync(@NotNull Plugin plugin, @NotNull Command command) {
071        registerAsync(plugin, command, Executors.newSingleThreadExecutor());
072    }
073
074    /**
075     * Registers the command.
076     * <p>
077     * If you register a command with this method, it will be executed asynchronously.
078     * <p>
079     * Note:
080     * <p>
081     * The tab completion will execute on main thread.
082     *
083     * @param plugin   the BungeeCord plugin
084     * @param command  the command to register
085     * @param executor the executor to run command
086     */
087    public static void registerAsync(@NotNull Plugin plugin, @NotNull Command command, @NotNull Executor executor) {
088        ProxyServer.getInstance()
089                .getPluginManager()
090                .registerCommand(
091                        plugin,
092                        new AsyncBungeeCommandImpl(plugin, command, executor)
093                );
094    }
095
096    private static class BungeeCommandImpl extends net.md_5.bungee.api.plugin.Command implements TabExecutor {
097
098        private final BungeeAudiences audiences;
099        private final Command command;
100
101        private BungeeCommandImpl(@NotNull Plugin plugin, @NotNull Command command) {
102            super(command.getName(), null, command.getAliases().toArray(new String[0]));
103            this.audiences = BungeeAudiences.create(plugin);
104            this.command = command;
105        }
106
107        @Override
108        public void execute(CommandSender sender, String[] args) {
109            command.onExecution(
110                    createContext(sender, args)
111            );
112        }
113
114        @Override
115        public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
116            return command.onTabCompletion(
117                    createContext(sender, args)
118            );
119        }
120
121        private CommandContext createContext(CommandSender sender, String[] args) {
122            return SimpleCommandContext.newBuilder()
123                    .setCommand(command)
124                    .setSender(new BungeeSender(audiences, sender))
125                    .setArguments(args)
126                    .setLabel(command.getName())
127                    .build();
128        }
129    }
130
131    private static class AsyncBungeeCommandImpl extends net.md_5.bungee.api.plugin.Command implements TabExecutor {
132
133        private final BungeeAudiences audiences;
134        private final Command command;
135        private final Executor executor;
136
137        private AsyncBungeeCommandImpl(@NotNull Plugin plugin, @NotNull Command command, @NotNull Executor executor) {
138            super(command.getName(), null, command.getAliases().toArray(new String[0]));
139            this.audiences = BungeeAudiences.create(plugin);
140            this.command = command;
141            this.executor = executor;
142        }
143
144        @Override
145        public void execute(CommandSender sender, String[] args) {
146            executor.execute(() ->
147                    command.onExecution(
148                            createContext(sender, args)
149                    )
150            );
151        }
152
153        @Override
154        public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
155            return command.onTabCompletion(
156                    createContext(sender, args)
157            );
158        }
159
160        private CommandContext createContext(CommandSender sender, String[] args) {
161            return SimpleCommandContext.newBuilder()
162                    .setCommand(command)
163                    .setSender(new BungeeSender(audiences, sender))
164                    .setArguments(args)
165                    .setLabel(command.getName())
166                    .build();
167        }
168    }
169}