/*
* This file is part of LanternServer, licensed under the MIT License (MIT).
*
* Copyright (c) LanternPowered <https://www.lanternpowered.org>
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.lanternpowered.server.network.vanilla.message.codec.play;
import static org.lanternpowered.server.data.io.store.item.WrittenBookItemTypeObjectSerializer.AUTHOR;
import static org.lanternpowered.server.data.io.store.item.WrittenBookItemTypeObjectSerializer.PAGES;
import static org.lanternpowered.server.data.io.store.item.WrittenBookItemTypeObjectSerializer.TITLE;
import com.flowpowered.math.vector.Vector3i;
import io.netty.handler.codec.CodecException;
import io.netty.handler.codec.EncoderException;
import org.lanternpowered.server.network.buffer.ByteBuffer;
import org.lanternpowered.server.network.buffer.objects.Types;
import org.lanternpowered.server.network.message.Message;
import org.lanternpowered.server.network.message.NullMessage;
import org.lanternpowered.server.network.message.codec.CodecContext;
import org.lanternpowered.server.network.objects.RawItemStack;
import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInChangeItemName;
import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInChangeOffer;
import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInEditBook;
import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInEditCommandBlock;
import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInOutBrand;
import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInOutChannelPayload;
import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInPickItem;
import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInSignBook;
import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayOutOpenBook;
import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayOutStopSound;
import org.spongepowered.api.data.DataView;
import org.spongepowered.api.data.type.HandTypes;
import java.util.List;
public final class CodecPlayInOutCustomPayload extends AbstractCodecPlayInOutCustomPayload {
@Override
protected MessageResult encode0(CodecContext context, Message message) throws CodecException {
if (message instanceof MessagePlayInOutBrand) {
return new MessageResult("MC|Brand", context.byteBufAlloc().buffer().writeString(((MessagePlayInOutBrand) message).getBrand()));
} else if (message instanceof MessagePlayOutOpenBook) {
final ByteBuffer buf = context.byteBufAlloc().buffer();
buf.writeVarInt(((MessagePlayOutOpenBook) message).getHandType() == HandTypes.MAIN_HAND ? 0 : 1);
return new MessageResult("MC|BOpen", buf);
} else if (message instanceof MessagePlayOutStopSound) {
final MessagePlayOutStopSound message0 = (MessagePlayOutStopSound) message;
final ByteBuffer buf = context.byteBufAlloc().buffer();
buf.writeString(message0.getSound() == null ? "" : message0.getSound());
buf.writeString(message0.getCategory() == null ? "" : message0.getCategory().getId());
return new MessageResult("MC|StopSound", buf);
}
throw new EncoderException("Unsupported message type: " + message);
}
@Override
protected Message decode0(CodecContext context, String channel, ByteBuffer content) throws CodecException {
if ("MC|ItemName".equals(channel)) {
return new MessagePlayInChangeItemName(content.readString());
} else if ("MC|TrSel".equals(channel)) {
return new MessagePlayInChangeOffer(content.readInteger());
} else if ("MC|Brand".equals(channel)) {
return new MessagePlayInOutBrand(content.readString());
} else if ("MC|Beacon".equals(channel)) {
// TODO
} else if ("MC|AdvCdm".equals(channel)) {
final byte type = content.readByte();
Vector3i pos = null;
int entityId = 0;
if (type == 0) {
int x = content.readInteger();
int y = content.readInteger();
int z = content.readInteger();
pos = new Vector3i(x, y, z);
} else if (type == 1) {
entityId = content.readInteger();
} else {
throw new CodecException("Unknown modify command message type: " + type);
}
final String command = content.readString();
final boolean shouldTrackOutput = content.readBoolean();
if (pos != null) {
return new MessagePlayInEditCommandBlock.Block(pos, command, shouldTrackOutput);
} else {
return new MessagePlayInEditCommandBlock.Entity(entityId, command, shouldTrackOutput);
}
} else if ("MC|AutoCmd".equals(channel)) {
final int x = content.readInteger();
final int y = content.readInteger();
final int z = content.readInteger();
final String command = content.readString();
final boolean shouldTrackOutput = content.readBoolean();
final MessagePlayInEditCommandBlock.AdvancedBlock.Mode mode =
MessagePlayInEditCommandBlock.AdvancedBlock.Mode.valueOf(content.readString());
final boolean conditional = content.readBoolean();
final boolean automatic = content.readBoolean();
return new MessagePlayInEditCommandBlock.AdvancedBlock(new Vector3i(x, y, z), command, shouldTrackOutput, mode, conditional, automatic);
} else if ("MC|BSign".equals(channel)) {
final RawItemStack rawItemStack = content.read(Types.RAW_ITEM_STACK);
//noinspection ConstantConditions
if (rawItemStack == null) {
throw new CodecException("Signed book may not be null!");
}
final DataView dataView = rawItemStack.getDataView();
if (dataView == null) {
throw new CodecException("Signed book data view (nbt tag) may not be null!");
}
final String author = dataView.getString(AUTHOR).orElseThrow(() -> new CodecException("Signed book author missing!"));
final String title = dataView.getString(TITLE).orElseThrow(() -> new CodecException("Signed book title missing!"));
final List<String> pages = dataView.getStringList(PAGES).orElseThrow(() -> new CodecException("Signed book pages missing!"));
return new MessagePlayInSignBook(author, title, pages);
} else if ("MC|BEdit".equals(channel)) {
final RawItemStack rawItemStack = content.read(Types.RAW_ITEM_STACK);
//noinspection ConstantConditions
if (rawItemStack == null) {
throw new CodecException("Edited book may not be null!");
}
final DataView dataView = rawItemStack.getDataView();
if (dataView == null) {
throw new CodecException("Edited book data view (nbt tag) may not be null!");
}
final List<String> pages = dataView.getStringList(PAGES).orElseThrow(() -> new CodecException("Edited book pages missing!"));
return new MessagePlayInEditBook(pages);
} else if ("MC|Struct".equals(channel)) {
// Something related to structure placing in minecraft 1.9,
// seems like it's something mojang doesn't want to share with use,
// they used this channel to build and save structures
} else if ("MC|PickItem".equals(channel)) {
return new MessagePlayInPickItem(content.readVarInt());
} else if ("FML|HS".equals(channel)) {
throw new CodecException("Received and unexpected message with channel: " + channel);
} else if ("FML".equals(channel)) {
// Fml channel
} else if (channel.startsWith("FML")) {
// A unknown/ignored fml channel
} else {
return new MessagePlayInOutChannelPayload(channel, content);
}
return NullMessage.INSTANCE;
}
}