package ic2.api.network; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.relauncher.Side; /** * Provides methods to initiate events and synchronize tile entity fields in SMP. * * The methods are transparent between singleplayer and multiplayer - if a method is called in * singleplayer, the associated callback will be locally executed. The implementation is different * between the client and server versions of IC2. * * You'll usually want to use the server->client methods defined here to synchronize information * which is needed by the clients outside the GUI, such as rendering the block, playing sounds or * producing effects. Anything which is only visible inside the GUI should be synchronized through * the Container class associated to the GUI in Container.updateProgressBar(). */ public final class NetworkHelper { // server -> client /** * Schedule a TileEntity's field to be updated to the clients in range. * * The updater will query the field's value during the next update, updates happen usually * every 2 ticks. If low latency is important use initiateTileEntityEvent instead. * * IC2's network updates have to get triggered every time, it doesn't continuously poll/send * the field value. Just call updateTileEntityField after every change to a field which needs * network synchronization. * * The following field data types are currently supported: * - int, int[], short, short[], byte, byte[], long, long[] * - float, float[], double, double[] * - boolean, boolean[] * - String, String[] * - ItemStack * - NBTBase (includes NBTTagCompound) * - Block, Item, Achievement, Potion, Enchantment * - BlockPos, ChunkCoordIntPair * - TileEntity (does not sync the actual tile entity, instead looks up the tile entity by its position in the client world) * - World (does not sync the actual world, instead looks up the world by its dimension ID) * * Once the update has been processed by the client, it'll call onNetworkUpdate on the client- * side TileEntity if it implements INetworkUpdateListener. * * If this method is being executed on the client (i.e. Singleplayer), it'll just call * INetworkUpdateListener.onNetworkUpdate (if implemented by the te). * * @param te TileEntity to update * @param field Name of the field to update */ public static void updateTileEntityField(TileEntity te, String field) { getNetworkManager(FMLCommonHandler.instance().getEffectiveSide()).updateTileEntityField(te, field); } /** * Immediately send an event for the specified TileEntity to the clients in range. * * If this method is being executed on the client (i.e. Singleplayer), it'll just call * INetworkTileEntityEventListener.onNetworkEvent (if implemented by the te). * * @param te TileEntity to notify, should implement INetworkTileEntityEventListener * @param event Arbitrary integer to represent the event, choosing the values is up to you * @param limitRange Limit the notification range to (currently) 20 blocks instead of the * tracking distance if true */ public static void initiateTileEntityEvent(TileEntity te, int event, boolean limitRange) { getNetworkManager(FMLCommonHandler.instance().getEffectiveSide()).initiateTileEntityEvent(te, event, limitRange); } /** * Immediately send an event for the specified Item to the clients in range. * * The item should implement INetworkItemEventListener to receive the event. * * If this method is being executed on the client (i.e. Singleplayer), it'll just call * INetworkItemEventListener.onNetworkEvent (if implemented by the item). * * @param player EntityPlayer holding the item * @param stack ItemStack containing the item * @param event Arbitrary integer to represent the event, choosing the values is up to you * @param limitRange Limit the notification range to (currently) 20 blocks instead of the * tracking distance if true */ public static void initiateItemEvent(EntityPlayer player, ItemStack stack, int event, boolean limitRange) { getNetworkManager(FMLCommonHandler.instance().getEffectiveSide()).initiateItemEvent(player, stack, event, limitRange); } // client -> server /** * Immediately send an event for the specified TileEntity to the server. * * This method doesn't do anything if executed on the server. * * @param te TileEntity to notify, should implement INetworkClientTileEntityEventListener * @param event Arbitrary integer to represent the event, choosing the values is up to you */ public static void initiateClientTileEntityEvent(TileEntity te, int event) { getNetworkManager(FMLCommonHandler.instance().getEffectiveSide()).initiateClientTileEntityEvent(te, event); } /** * Immediately send an event for the specified Item to the clients in range. * * The item should implement INetworkItemEventListener to receive the event. * * This method doesn't do anything if executed on the server. * * @param stack ItemStack containing the item * @param event Arbitrary integer to represent the event, choosing the values is up to you */ public static void initiateClientItemEvent(ItemStack stack, int event) { getNetworkManager(FMLCommonHandler.instance().getEffectiveSide()).initiateClientItemEvent(stack, event); } /** * This will return the NetworkManager for the given side. * @param side the side to get the NetworkManager for. * @return The NetworkManager for the given side. */ public static INetworkManager getNetworkManager(Side side) { if (side.isClient()) { return clientInstance; } else { return serverInstance; } } private static INetworkManager serverInstance; private static INetworkManager clientInstance; /** * Sets the internal INetworkManager instance. * ONLY IC2 CAN DO THIS!!!!!!! */ public static void setInstance(INetworkManager server, INetworkManager client) { ModContainer mc = Loader.instance().activeModContainer(); if (mc == null || !"IC2".equals(mc.getModId())) { throw new IllegalAccessError(); } serverInstance = server; clientInstance = client; } }