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.impl;
018
019import com.google.auto.value.AutoValue;
020import com.google.common.collect.ImmutableSet;
021import io.netty.buffer.Unpooled;
022import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
023import net.fabricmc.fabric.api.networking.v1.PacketSender;
024import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
025import net.minecraft.network.PacketByteBuf;
026import net.minecraft.util.Identifier;
027import org.checkerframework.checker.nullness.qual.NonNull;
028
029import java.util.Set;
030
031/**
032 * A packet sent client to server, to let the server know which optional argument types are available on the server.
033 *
034 * <p>This packet is sent by players on join, before the command tree is sent to the client.</p>
035 */
036@AutoValue
037public abstract class RegisteredArgumentTypesC2SPacket {
038    public static final Identifier ID = Colonel.id("registered-args");
039
040    public static void register() {
041        ServerPlayNetworking.registerGlobalReceiver(ID, (server, player, handler, buffer, responder) -> {
042            final RegisteredArgumentTypesC2SPacket pkt = RegisteredArgumentTypesC2SPacket.of(buffer);
043            server.execute(() -> { // on main thread
044                ServerArgumentTypes.setKnownArgumentTypes(player, pkt.idents());
045            });
046        });
047    }
048
049    public static RegisteredArgumentTypesC2SPacket of(final Set<Identifier> idents) {
050        return new AutoValue_RegisteredArgumentTypesC2SPacket(ImmutableSet.copyOf(idents));
051    }
052
053    public static RegisteredArgumentTypesC2SPacket of(final @NonNull PacketByteBuf buf) {
054        final int length = buf.readVarInt();
055        final ImmutableSet.Builder<Identifier> items = ImmutableSet.builder();
056        for(int i = 0; i < length; ++i) {
057            items.add(buf.readIdentifier());
058        }
059        return of(items.build());
060    }
061
062    /**
063     * Get the registered identifiers.
064     *
065     * <p>Every identifier represents an argument type registered in {@link ServerArgumentTypes}</p>
066     *
067     * @return an unmodifiable list of argument type identifiers
068     */
069    public abstract Set<Identifier> idents();
070
071    public final void toPacket(final PacketByteBuf buffer) {
072        buffer.writeVarInt(idents().size());
073        for (Identifier id : idents()) {
074            buffer.writeIdentifier(id);
075        }
076    }
077
078    /**
079     * Send the client's list of identifiers to the server.
080     */
081    public final void sendTo(final PacketSender sender) {
082        if (ClientPlayNetworking.canSend(ID)) {
083            final PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer(idents().size() * 8));
084            toPacket(buffer);
085            sender.sendPacket(ID, buffer);
086        }
087    }
088}