/** Copyright (C) <2015> <coolAlias> This file is part of coolAlias' Zelda Sword Skills Minecraft Mod; as such, you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package zeldaswordskills.network; import io.netty.buffer.ByteBuf; import java.io.IOException; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; import net.minecraftforge.fml.relauncher.Side; import zeldaswordskills.ZSSMain; import com.google.common.base.Throwables; /** * * A wrapper much like the vanilla packet class, allowing use of PacketBuffer's many * useful methods as well as implementing a final version of IMessageHandler which * calls {@link #process(EntityPlayer, Side)} on each received message, letting the * message handle itself rather than having to add an extra class in each one. * */ public abstract class AbstractMessage<T extends AbstractMessage<T>> implements IMessage, IMessageHandler <T, IMessage> { /** * Some PacketBuffer methods throw IOException - default handling propagates the exception. * If an IOException is expected but should not be fatal, handle it within this method. */ protected abstract void read(PacketBuffer buffer) throws IOException; /** * Some PacketBuffer methods throw IOException - default handling propagates the exception. * If an IOException is expected but should not be fatal, handle it within this method. */ protected abstract void write(PacketBuffer buffer) throws IOException; /** * Called on whichever side the message is received; * for bidirectional packets, be sure to check side */ protected abstract void process(EntityPlayer player, Side side); /** * If message is sent to the wrong side, an exception will be thrown during handling * @return True if the message is allowed to be handled on the given side */ protected boolean isValidOnSide(Side side) { return true; } /** * Whether this message requires the main thread to be processed (i.e. it * requires that the world, player, and other objects are in a valid state). */ protected boolean requiresMainThread() { return true; } @Override public void fromBytes(ByteBuf buffer) { try { read(new PacketBuffer(buffer)); } catch (IOException e) { throw Throwables.propagate(e); } } @Override public void toBytes(ByteBuf buffer) { try { write(new PacketBuffer(buffer)); } catch (IOException e) { throw Throwables.propagate(e); } } @Override public final IMessage onMessage(T msg, MessageContext ctx) { if (!msg.isValidOnSide(ctx.side)) { throw new RuntimeException("Invalid side " + ctx.side.name() + " for " + msg.getClass().getSimpleName()); } else if (msg.requiresMainThread()) { checkThreadAndEnqueue(msg, ctx); } else { msg.process(ZSSMain.proxy.getPlayerEntity(ctx), ctx.side); } return null; } /** * Ensures that the message is being handled on the main thread */ private static final <T extends AbstractMessage<T>> void checkThreadAndEnqueue(final AbstractMessage<T> msg, final MessageContext ctx) { ZSSMain.proxy.getThreadFromContext(ctx).addScheduledTask(new Runnable() { public void run() { msg.process(ZSSMain.proxy.getPlayerEntity(ctx), ctx.side); } }); } /** * Messages that can only be sent from the server to the client should use this class */ public static abstract class AbstractClientMessage<T extends AbstractMessage<T>> extends AbstractMessage<T> { @Override protected final boolean isValidOnSide(Side side) { return side.isClient(); } } /** * Messages that can only be sent from the client to the server should use this class */ public static abstract class AbstractServerMessage<T extends AbstractMessage<T>> extends AbstractMessage<T> { @Override protected final boolean isValidOnSide(Side side) { return side.isServer(); } } }