001/*
002 * Colonel -- a brigadier expansion library
003 * Copyright (C) zml and Colonel contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package ca.stellardrift.colonel.api;
018
019import ca.stellardrift.colonel.impl.ServerArgumentTypes;
020import com.google.auto.value.AutoValue;
021import com.mojang.brigadier.arguments.ArgumentType;
022import com.mojang.brigadier.suggestion.SuggestionProvider;
023import net.minecraft.command.argument.ArgumentTypes;
024import net.minecraft.command.argument.serialize.ArgumentSerializer;
025import net.minecraft.command.suggestion.SuggestionProviders;
026import net.minecraft.util.Identifier;
027import org.checkerframework.checker.nullness.qual.Nullable;
028
029import java.util.function.Function;
030
031/**
032 * An argument type that only needs to be known on the server
033 *
034 * @param <T> argument type
035 */
036@AutoValue
037public abstract class ServerArgumentType<T extends ArgumentType<?>> {
038
039    public static <T extends ArgumentType<?>> Builder<T> builder(final Identifier id) {
040        return new AutoValue_ServerArgumentType.Builder<T>()
041                .id(id)
042                .fallbackSuggestions(SuggestionProviders.ASK_SERVER);
043    }
044
045    /**
046     * The unique identifier for this argument type.
047     *
048     * @return identifier
049     */
050    public abstract Identifier id();
051
052    /**
053     * The argument type class to register
054     *
055     * @return argument type
056     */
057    public abstract Class<? super T> type();
058
059    /**
060     * The type's argument serializer. This will only be used on clients who have this argument attached.
061     *
062     * @see net.minecraft.command.argument.serialize.ConstantArgumentSerializer for a simple implementation
063     * @return serializer
064     */
065    public abstract ArgumentSerializer<T> serializer();
066
067    /**
068     * A function to transform an argument of your type into one understandable by the Vanilla client.
069     *
070     * <p>This is currently unvalidated -- but generally, anything in {@link ArgumentTypes} should be acceptable</p>
071     *
072     * @return argument transformer
073     */
074    public abstract Function<T, ArgumentType<?>> fallbackProvider();
075
076    /**
077     * Add an override for suggestions.
078     *
079     * @return fallback suggestion provider
080     */
081    public abstract @Nullable SuggestionProvider<?> fallbackSuggestions();
082
083    /**
084     * A builder for {@link ServerArgumentType}s
085     *
086     * <p>All values except for {@link #fallbackSuggestions()} are required.</p>
087     *
088     * @param <T> type of argument type
089     */
090    @AutoValue.Builder
091    public static abstract class Builder<T extends ArgumentType<?>> {
092
093        /**
094         * Argument identifier, for registration and via protocol.
095         *
096         * @param id The ID
097         * @return this
098         */
099        abstract Builder<T> id(Identifier id);
100
101        /**
102         * Set the native argument type.
103         *
104         * <p>A superclass is accepted within the type parameter to allow for parameterized argument types.
105         * This does not allow for extensions types.</p>
106         *
107         * @param type Native argument type
108         * @return this
109         */
110        public abstract Builder<T> type(final Class<? super T> type);
111
112        /**
113         * Set the serializer for the native argument type
114         *
115         * @param serial serializer
116         * @return this
117         */
118        public abstract Builder<T> serializer(final ArgumentSerializer<T> serial);
119
120        /**
121         * Set the provider to be sent to clients without this argument type.
122         *
123         * <p>The returned argument type may be provided as </p>
124         *
125         * @param provider function taking own argument type and creating a
126         * @return this
127         */
128        public abstract Builder<T> fallbackProvider(final Function<T, ArgumentType<?>> provider);
129
130        /**
131         * Set the suggestion provider that will be set to clients that don't have this argument type.
132         *
133         * <p>By default, this is {@link SuggestionProviders#ASK_SERVER}, in order to use the full argument type's
134         * suggestions. However, if the fallback type provides its own suggestions that meet requirements, this can be explicitly set to null</p>
135         *
136         * @param suggestions Provider for suggestions that will be sent to the client.
137         * @return this
138         */
139        public abstract Builder<T> fallbackSuggestions(final @Nullable SuggestionProvider<?> suggestions);
140
141        abstract ServerArgumentType<T> build();
142
143        /**
144         * Complete the builder and register the argument with the Vanilla {@link ArgumentTypes} registry.
145         *
146         * @return the constructed argument type data.
147         */
148        @SuppressWarnings("unchecked")
149        public ServerArgumentType<T> register() {
150            final ServerArgumentType<T> value = build();
151            ArgumentTypes.register(value.id().toString(), (Class<T>) value.type(), value.serializer());
152            ServerArgumentTypes.register(value);
153            return value;
154        }
155
156    }
157}