/**
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();
}
}
}