/* * This file is part of NeptuneVanilla, licensed under the MIT License (MIT). * * Copyright (c) 2015-2017, Jamie Mansfield <https://github.com/jamierocks> * * 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.neptunepowered.vanilla.factory; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import net.canarymod.api.DataWatcher; import net.canarymod.api.chat.ChatComponent; import net.canarymod.api.entity.Entity; import net.canarymod.api.entity.XPOrb; import net.canarymod.api.entity.hanging.Painting; import net.canarymod.api.entity.living.LivingBase; import net.canarymod.api.entity.living.humanoid.Human; import net.canarymod.api.entity.living.humanoid.Player; import net.canarymod.api.factory.PacketFactory; import net.canarymod.api.inventory.Item; import net.canarymod.api.nbt.CompoundTag; import net.canarymod.api.packet.InvalidPacketConstructionException; import net.canarymod.api.packet.Packet; import net.canarymod.api.potion.PotionEffect; import net.canarymod.api.statistics.Stat; import net.canarymod.api.world.Chunk; import net.canarymod.api.world.blocks.BlockType; import net.canarymod.api.world.position.Position; import net.canarymod.api.world.position.Vector3D; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.play.server.S02PacketChat; import net.minecraft.network.play.server.S03PacketTimeUpdate; import net.minecraft.network.play.server.S04PacketEntityEquipment; import net.minecraft.network.play.server.S05PacketSpawnPosition; import net.minecraft.network.play.server.S06PacketUpdateHealth; import net.minecraft.network.play.server.S08PacketPlayerPosLook; import net.minecraft.network.play.server.S09PacketHeldItemChange; import net.minecraft.network.play.server.S0APacketUseBed; import net.minecraft.network.play.server.S0BPacketAnimation; import net.minecraft.network.play.server.S0DPacketCollectItem; import net.minecraft.network.play.server.S12PacketEntityVelocity; import net.minecraft.network.play.server.S1FPacketSetExperience; import net.minecraft.network.play.server.S2BPacketChangeGameState; import net.minecraft.network.play.server.S2CPacketSpawnGlobalEntity; import net.minecraft.network.play.server.S2EPacketCloseWindow; import net.minecraft.network.play.server.S2FPacketSetSlot; import net.minecraft.network.play.server.S33PacketUpdateSign; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; import net.minecraft.network.play.server.S36PacketSignEditorOpen; import net.minecraft.util.BlockPos; import net.minecraft.util.ChatComponentText; import net.minecraft.util.IChatComponent; import org.apache.commons.lang3.NotImplementedException; import java.util.List; import java.util.Map; import java.util.function.Predicate; public class NeptunePacketFactory implements PacketFactory { private final static String TOO_FEW_ARGUMENTS = "Not enough arguments (Expected: %d Got: %d)", INVALID_ARGUMENT = "Argument at index: '%d' does not match a valid type. (Expected: '%s' Got: '%s')"; protected NeptunePacketFactory() {} @Override public Packet createPacket(int id, Object... args) throws InvalidPacketConstructionException { if (args == null || args.length < 1) { throw new IllegalArgumentException("Arguments cannot be null or empty!"); } switch (id) { case 0: throw new InvalidPacketConstructionException(id, "KeepAlive", "Keep Alive packets should only be handled by the server!"); case 1: throw new InvalidPacketConstructionException(id, "JoinGame", "Join Game packets should only be handled by the server!"); case 2: this.check(2, "Chat", 1, args, this.test(ChatComponent.class)); return this.chat((ChatComponent) args[0]); case 3: this.check(3, "UpdateTime", 2, args, this.test(Long.class), this.test(Long.class)); return this.updateTime((Long) args[0], (Long) args[1]); case 4: this.check(4, "EntityEquipment", 3, args, this.test(Integer.class), this.test(Integer.class), this.test(Item.class)); return this.entityEquipment((Integer) args[0], (Integer) args[1], (Item) args[2]); case 5: this.check(5, "SpawnPosition", 3, args, this.test(Integer.class), this.test(Integer.class), this.test(Integer.class)); return this.spawnPosition((Integer) args[0], (Integer) args[1], (Integer) args[2]); } return null; } @Override public Packet chat(ChatComponent chatComponent) { return (Packet) new S02PacketChat((IChatComponent) chatComponent); } @Override public Packet updateTime(long worldAge, long time) { return (Packet) new S03PacketTimeUpdate(worldAge, time, false); } @Override public Packet entityEquipment(int entityID, int slot, Item item) { return (Packet) new S04PacketEntityEquipment(entityID, slot, (ItemStack) item); } @Override public Packet spawnPosition(int x, int y, int z) { return (Packet) new S05PacketSpawnPosition(new BlockPos(x, y, z)); } @Override public Packet updateHealth(float health, int foodLevel, float saturation) { return (Packet) new S06PacketUpdateHealth(health, foodLevel, saturation); } @Override public Packet playerPositionLook(double x, double y, double z, float yaw, float pitch, boolean onGround) { return (Packet) new S08PacketPlayerPosLook(x, y, z, yaw, pitch, Sets.newHashSet()); } @Override public Packet heldItemChange(int slot) { return (Packet) new S09PacketHeldItemChange(slot); } @Override public Packet useBed(Player player, int x, int y, int z) { return (Packet) new S0APacketUseBed((EntityPlayer) player, new BlockPos(x, y, z)); } @Override public Packet animation(Player player, int animation) { return (Packet) new S0BPacketAnimation((net.minecraft.entity.Entity) player, animation); } @Override public Packet spawnPlayer(Human human) { return null; } @Override public Packet collectItem(int entityItemID, int collectorID) { return (Packet) new S0DPacketCollectItem(entityItemID, collectorID); } @Override public Packet spawnObject(Entity entity, int objectID) { return null; } @Override public Packet spawnObject(Entity entity, int objectID, int throwerID) { return null; } @Override public Packet spawnMob(LivingBase livingbase) { return null; } @Override public Packet spawnPainting(Painting painting) { return null; } @Override public Packet spawnXPOrb(XPOrb xporb) { return null; } @Override public Packet entityVelocity(int entityID, double motX, double motY, double motZ) { return (Packet) new S12PacketEntityVelocity(entityID, motX, motY, motZ); } @Override public Packet destroyEntities(int... ids) { return null; } @Override public Packet entityRelativeMove(int entityID, byte x, byte y, byte z) { return null; } @Override public Packet entityLook(int entityID, byte yaw, byte pitch) { return null; } @Override public Packet entityLookRelativeMove(int entityID, byte x, byte y, byte z, byte yaw, byte pitch) { return null; } @Override public Packet entityTeleport(Entity entity) { return null; } @Override public Packet entityTeleport(int entityID, int x, int y, int z, byte yaw, byte pitch) { return null; } @Override public Packet entityStatus(int entityID, byte status) { return null; } @Override public Packet attachEntity(int leashId, Entity attaching, Entity vehicle) { return null; } @Override public Packet entityMetaData(int entityID, DataWatcher watcher) { return null; } @Override public Packet entityEffect(int entityID, PotionEffect effect) { return null; } @Override public Packet removeEntityEffect(int entityID, PotionEffect effect) { return null; } @Override public Packet setExperience(float bar, int level, int totalXp) { return (Packet) new S1FPacketSetExperience(bar, level, totalXp); } @Override public Packet chunkData(Chunk chunk, boolean initialize, int bitflag) { return null; } @Override public Packet multiBlockChange(int size, short[] blocks, Chunk chunk) { return null; } @Override public Packet blockChange(int x, int y, int z, int typeId, int data) { return null; } @Override public Packet blockChange(int x, int y, int z, BlockType type) { return null; } @Override public Packet blockAction(int x, int y, int z, int targetId, int stat1, int stat2) { throw new NotImplementedException("A Minecraft Update has broken this construction!"); } @Override public Packet blockBreakAnimation(int entityId, int x, int y, int z, int state) { return null; } @Override public Packet mapChunkBulk(List<Chunk> chunks) { return null; } @Override public Packet explosion(double explodeX, double explodeY, double explodeZ, float power, List<Position> affectedPositions, Vector3D playerVelocity) { return null; } @Override public Packet effect(int sfxID, int x, int y, int z, int aux, boolean disableRelVol) { return null; } @Override public Packet soundEffect(String name, double x, double y, double z, float volume, float pitch) { return null; } @Override public Packet particles(String name, float x, float y, float z, float velocityX, float velocityY, float velocityZ, float speed, int quantity) { return null; } @Override public Packet changeGameState(int state, int mode) { return (Packet) new S2BPacketChangeGameState(state, mode); } @Override public Packet spawnGlobalEntity(Entity entity) { return (Packet) new S2CPacketSpawnGlobalEntity((net.minecraft.entity.Entity) entity); } @Override public Packet openWindow(int windowId, int type, String title, int slots, boolean useTitle) { throw new NotImplementedException("A Minecraft Update has broken this construction!"); } @Override public Packet closeWindow(int windowId) { return (Packet) new S2EPacketCloseWindow(windowId); } @Override public Packet setSlot(int windowId, int slotId, Item item) { return (Packet) new S2FPacketSetSlot(windowId, slotId, (ItemStack) item); } @Override public Packet setWindowItems(int windowId, List<Item> items) { return null; } @Override public Packet updateWindowProperty(int windowId, int bar, int value) { return null; } @Override public Packet updateSign(int x, int y, int z, String[] text) { final List<ChatComponentText> texts = Lists.newArrayList(); for (String t : text) { texts.add(new ChatComponentText(t)); } return (Packet) new S33PacketUpdateSign(null, new BlockPos(x, y, z), texts.toArray(new ChatComponentText[texts.size()])); } @Override public Packet maps(short mapID, byte[] data) { return null; } @Override public Packet updateTileEntity(int x, int y, int z, int action, CompoundTag compoundTag) { return (Packet) new S35PacketUpdateTileEntity(new BlockPos(x, y, z), action, (NBTTagCompound) compoundTag); } @Override public Packet signEditorOpen(int x, int y, int z) { return (Packet) new S36PacketSignEditorOpen(new BlockPos(x, y, z)); } @Override public Packet statistics(Map<Stat, Integer> stats) { return null; } @Override public Packet playerListItem(String name, boolean connected, int ping) { throw new NotImplementedException("A Minecraft Update has broken this construction!"); } private void check(int packetId, String packetName, int minParams, Object[] args, ArgumentPredicate... tests) throws InvalidPacketConstructionException { if (args.length < minParams) { throw new InvalidPacketConstructionException(packetId, packetName, String.format(TOO_FEW_ARGUMENTS, minParams, args.length)); } for (int test = 0; test < tests.length; test++) { if (!tests[test].test(args[test].getClass())) { throw new InvalidPacketConstructionException(packetId, packetName, String.format(INVALID_ARGUMENT, test, tests[test].getType(), args[test].getClass().getSimpleName())); } } } private <T> ArgumentPredicate<T> test(Class<T> type) { return new ArgumentPredicate<T>() { @Override public Class<T> getType() { return type; } @Override public boolean test(T t) { return type.isAssignableFrom(t.getClass()); } }; } private interface ArgumentPredicate<T> extends Predicate<T> { Class<T> getType(); } }