1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-12 11:10:29 +00:00

Move from FMLEventChannel to SimpleNetworkWrapper

- Split each network packet into it's own individual IMessage class.
 - Move the TextTable into separate classes for server and client based
   rendering.
This commit is contained in:
SquidDev 2018-12-29 12:18:05 +00:00
parent f8b328a048
commit 42d3901ee3
45 changed files with 1447 additions and 1093 deletions

View File

@ -41,8 +41,6 @@ import dan200.computercraft.shared.media.items.ItemDiskExpanded;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.network.ComputerCraftPacket;
import dan200.computercraft.shared.network.PacketHandler;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
@ -62,12 +60,9 @@ import dan200.computercraft.shared.util.CreativeTabMain;
import dan200.computercraft.shared.util.IDAssigner;
import dan200.computercraft.shared.wired.CapabilityWiredElement;
import dan200.computercraft.shared.wired.WiredNode;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
@ -82,9 +77,9 @@ import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.*;
import net.minecraftforge.fml.common.network.FMLEventChannel;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.relauncher.Side;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.Logger;
@ -100,7 +95,6 @@ import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.ServiceConfigurationError;
import java.util.function.Function;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@ -253,7 +247,7 @@ public class ComputerCraft
public static ServerComputerRegistry serverComputerRegistry = new ServerComputerRegistry();
// Networking
public static FMLEventChannel networkEventChannel;
public static SimpleNetworkWrapper networkWrapper;
// Creative
public static CreativeTabMain mainCreativeTab;
@ -288,8 +282,7 @@ public class ComputerCraft
loadConfig();
// Setup network
networkEventChannel = NetworkRegistry.INSTANCE.newEventDrivenChannel( "CC" );
networkEventChannel.register( new PacketHandler() );
networkWrapper = NetworkRegistry.INSTANCE.newSimpleChannel( ComputerCraft.MOD_ID );
proxy.preInit();
turtleProxy.preInit();
@ -555,36 +548,24 @@ public class ComputerCraft
return proxy.getWorldDir( world );
}
private static FMLProxyPacket encode( ComputerCraftPacket packet )
public static void sendToPlayer( EntityPlayer player, IMessage packet )
{
PacketBuffer buffer = new PacketBuffer( Unpooled.buffer() );
packet.toBytes( buffer );
return new FMLProxyPacket( buffer, "CC" );
networkWrapper.sendTo( packet, (EntityPlayerMP) player );
}
public static void sendToPlayer( EntityPlayer player, ComputerCraftPacket packet )
public static void sendToAllPlayers( IMessage packet )
{
networkEventChannel.sendTo( encode( packet ), (EntityPlayerMP) player );
networkWrapper.sendToAll( packet );
}
public static void sendToAllPlayers( ComputerCraftPacket packet )
public static void sendToServer( IMessage packet )
{
networkEventChannel.sendToAll( encode( packet ) );
networkWrapper.sendToServer( packet );
}
public static void sendToServer( ComputerCraftPacket packet )
public static void sendToAllAround( IMessage packet, NetworkRegistry.TargetPoint point )
{
networkEventChannel.sendToServer( encode( packet ) );
}
public static void sendToAllAround( ComputerCraftPacket packet, NetworkRegistry.TargetPoint point )
{
networkEventChannel.sendToAllAround( encode( packet ), point );
}
public static void handlePacket( ComputerCraftPacket packet, EntityPlayer player )
{
proxy.handlePacket( packet, player );
networkWrapper.sendToAllAround( packet, point );
}
public static boolean canPlayerUseCommands( EntityPlayer player )

View File

@ -0,0 +1,81 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client;
import dan200.computercraft.shared.command.text.ChatHelpers;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.command.text.TableFormatter;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextFormatting;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
public class ClientTableFormatter implements TableFormatter
{
public static final ClientTableFormatter INSTANCE = new ClientTableFormatter();
private static Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap();
private FontRenderer renderer()
{
return Minecraft.getMinecraft().fontRenderer;
}
@Override
@Nullable
public ITextComponent getPadding( ITextComponent component, int width )
{
int extraWidth = width - getWidth( component );
if( extraWidth <= 0 ) return null;
FontRenderer renderer = renderer();
float spaceWidth = renderer.getCharWidth( ' ' );
int spaces = MathHelper.floor( extraWidth / spaceWidth );
int extra = extraWidth - (int) (spaces * spaceWidth);
return ChatHelpers.coloured( StringUtils.repeat( ' ', spaces ) + StringUtils.repeat( (char) 712, extra ), TextFormatting.GRAY );
}
@Override
public int getColumnPadding()
{
return 3;
}
@Override
public int getWidth( ITextComponent component )
{
return renderer().getStringWidth( component.getFormattedText() );
}
@Override
public void writeLine( int id, ITextComponent component )
{
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion( component, id );
}
@Override
public int display( TableBuilder table )
{
GuiNewChat chat = Minecraft.getMinecraft().ingameGUI.getChatGUI();
int lastHeight = lastHeights.get( table.getId() );
int height = TableFormatter.super.display( table );
lastHeights.put( table.getId(), height );
for( int i = height; i < lastHeight; i++ ) chat.deleteChatLine( i + table.getId() );
return height;
}
}

View File

@ -7,19 +7,19 @@
package dan200.computercraft.client.proxy;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.ClientTableFormatter;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.render.*;
import dan200.computercraft.shared.command.CommandCopy;
import dan200.computercraft.shared.command.ContainerViewComputer;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.network.ComputerCraftPacket;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
@ -30,25 +30,20 @@ import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.util.Colour;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.client.renderer.ItemMeshDefinition;
import net.minecraft.client.renderer.block.model.ModelBakery;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.color.IItemColor;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.IThreadListener;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.World;
import net.minecraftforge.client.ClientCommandHandler;
import net.minecraftforge.client.event.ModelRegistryEvent;
@ -62,15 +57,9 @@ import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{
private static Int2IntOpenHashMap lastCounts = new Int2IntOpenHashMap();
// IComputerCraftProxy implementation
@Override
public void preInit()
{
@ -239,117 +228,6 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
return world.getSaveHandler().getWorldDirectory();
}
@Override
public void handlePacket( final ComputerCraftPacket packet, final EntityPlayer player )
{
switch( packet.m_packetType )
{
case ComputerCraftPacket.ComputerChanged:
case ComputerCraftPacket.ComputerTerminalChanged:
case ComputerCraftPacket.ComputerDeleted:
case ComputerCraftPacket.PlayRecord:
case ComputerCraftPacket.PostChat:
{
// Packet from Server to Client
IThreadListener listener = Minecraft.getMinecraft();
if( listener != null )
{
if( listener.isCallingFromMinecraftThread() )
{
processPacket( packet, player );
}
else
{
listener.addScheduledTask( () -> processPacket( packet, player ) );
}
}
break;
}
default:
{
// Packet from Client to Server
super.handlePacket( packet, player );
break;
}
}
}
private void processPacket( ComputerCraftPacket packet, EntityPlayer player )
{
switch( packet.m_packetType )
{
///////////////////////////////////
// Packets from Server to Client //
///////////////////////////////////
case ComputerCraftPacket.ComputerChanged:
case ComputerCraftPacket.ComputerTerminalChanged:
{
int instanceID = packet.m_dataInt[0];
if( !ComputerCraft.clientComputerRegistry.contains( instanceID ) )
{
ComputerCraft.clientComputerRegistry.add( instanceID, new ClientComputer( instanceID ) );
}
ComputerCraft.clientComputerRegistry.get( instanceID ).handlePacket( packet, player );
break;
}
case ComputerCraftPacket.ComputerDeleted:
{
int instanceID = packet.m_dataInt[0];
if( ComputerCraft.clientComputerRegistry.contains( instanceID ) )
{
ComputerCraft.clientComputerRegistry.remove( instanceID );
}
break;
}
case ComputerCraftPacket.PlayRecord:
{
BlockPos pos = new BlockPos( packet.m_dataInt[0], packet.m_dataInt[1], packet.m_dataInt[2] );
Minecraft mc = Minecraft.getMinecraft();
if( packet.m_dataInt.length > 3 )
{
SoundEvent sound = SoundEvent.REGISTRY.getObjectById( packet.m_dataInt[3] );
mc.world.playRecord( pos, sound );
mc.ingameGUI.setRecordPlayingMessage( packet.m_dataString[0] );
}
else
{
mc.world.playRecord( pos, null );
}
break;
}
case ComputerCraftPacket.PostChat:
{
/*
This allows us to send delete chat messages of the same "category" as the previous one.
It's used by the various /computercraft commands to avoid filling the chat with repetitive
messages.
*/
int id = packet.m_dataInt[0];
ITextComponent[] components = new ITextComponent[packet.m_dataString.length];
for( int i = 0; i < packet.m_dataString.length; i++ )
{
components[i] = ITextComponent.Serializer.jsonToComponent( packet.m_dataString[i] );
}
GuiNewChat chat = Minecraft.getMinecraft().ingameGUI.getChatGUI();
// Keep track of how many lines we wrote last time, deleting any extra ones.
int lastCount = lastCounts.get( id );
for( int i = components.length; i < lastCount; i++ ) chat.deleteChatLine( i + id );
lastCounts.put( id, components.length );
// Add new lines
for( int i = 0; i < components.length; i++ )
{
chat.printChatMessageWithOptionalDeletion( components[i], id + i );
}
break;
}
}
}
private void registerForgeHandlers()
{
MinecraftForge.EVENT_BUS.register( new ForgeHandlers() );
@ -359,6 +237,20 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
MinecraftForge.EVENT_BUS.register( FrameInfo.instance() );
}
@Override
public void playRecordClient( BlockPos pos, SoundEvent record, String info )
{
Minecraft mc = Minecraft.getMinecraft();
mc.world.playRecord( pos, record );
if( info != null ) mc.ingameGUI.setRecordPlayingMessage( info );
}
@Override
public void showTableClient( TableBuilder table )
{
ClientTableFormatter.INSTANCE.display( table );
}
public class ForgeHandlers
{
@SubscribeEvent

View File

@ -1,6 +1,5 @@
package dan200.computercraft.client.render;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Palette;

View File

@ -6,6 +6,7 @@
package dan200.computercraft.server.proxy;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.IComputer;
@ -16,6 +17,8 @@ import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
@ -70,4 +73,14 @@ public class ComputerCraftProxyServer extends ComputerCraftProxyCommon
{
return DimensionManager.getWorld( 0 ).getSaveHandler().getWorldDirectory();
}
@Override
public void playRecordClient( BlockPos pos, SoundEvent record, String info )
{
}
@Override
public void showTableClient( TableBuilder table )
{
}
}

View File

@ -9,8 +9,6 @@ package dan200.computercraft.shared;
import com.google.common.base.Preconditions;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.util.InventoryUtil;
import net.minecraft.item.ItemStack;

View File

@ -9,6 +9,7 @@ import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.core.tracking.TrackingContext;
import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.shared.command.framework.*;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import net.minecraft.command.CommandBase;
@ -26,7 +27,7 @@ import javax.annotation.Nonnull;
import java.util.*;
import java.util.function.Consumer;
import static dan200.computercraft.shared.command.framework.ChatHelpers.*;
import static dan200.computercraft.shared.command.text.ChatHelpers.*;
public final class CommandComputerCraft extends CommandDelegate
{
@ -60,7 +61,7 @@ public final class CommandComputerCraft extends CommandDelegate
{
if( arguments.size() == 0 )
{
TextTable table = new TextTable( DUMP_LIST_ID, "Computer", "On", "Position" );
TableBuilder table = new TableBuilder( DUMP_LIST_ID, "Computer", "On", "Position" );
List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
@ -92,37 +93,37 @@ public final class CommandComputerCraft extends CommandDelegate
for( ServerComputer computer : computers )
{
table.addRow(
table.row(
linkComputer( context, computer, computer.getID() ),
bool( computer.isOn() ),
linkPosition( context, computer )
);
}
table.displayTo( context.getSender() );
table.display( context.getSender() );
}
else if( arguments.size() == 1 )
{
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
TextTable table = new TextTable( DUMP_SINGLE_ID );
table.addRow( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
table.addRow( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
table.addRow( header( "Label" ), text( computer.getLabel() ) );
table.addRow( header( "On" ), bool( computer.isOn() ) );
table.addRow( header( "Position" ), linkPosition( context, computer ) );
table.addRow( header( "Family" ), text( computer.getFamily().toString() ) );
TableBuilder table = new TableBuilder( DUMP_SINGLE_ID );
table.row( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
table.row( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
table.row( header( "Label" ), text( computer.getLabel() ) );
table.row( header( "On" ), bool( computer.isOn() ) );
table.row( header( "Position" ), linkPosition( context, computer ) );
table.row( header( "Family" ), text( computer.getFamily().toString() ) );
for( int i = 0; i < 6; i++ )
{
IPeripheral peripheral = computer.getPeripheral( i );
if( peripheral != null )
{
table.addRow( header( "Peripheral " + Computer.s_sideNames[i] ), text( peripheral.getType() ) );
table.row( header( "Peripheral " + Computer.s_sideNames[i] ), text( peripheral.getType() ) );
}
}
table.displayTo( context.getSender() );
table.display( context.getSender() );
}
else
{
@ -504,9 +505,9 @@ public final class CommandComputerCraft extends CommandDelegate
|| field == TrackingField.AVERAGE_TIME || field == TrackingField.MAX_TIME;
TextTable table = defaultLayout
? new TextTable( TRACK_ID, "Computer", "Tasks", "Total", "Average", "Maximum" )
: new TextTable( TRACK_ID, "Computer", field.displayName() );
TableBuilder table = defaultLayout
? new TableBuilder( TRACK_ID, "Computer", "Tasks", "Total", "Average", "Maximum" )
: new TableBuilder( TRACK_ID, "Computer", field.displayName() );
for( ComputerTracker entry : timings )
{
@ -517,7 +518,7 @@ public final class CommandComputerCraft extends CommandDelegate
if( defaultLayout )
{
table.addRow(
table.row(
computerComponent,
text( entry.getFormatted( TrackingField.TASKS ) ),
text( entry.getFormatted( TrackingField.TOTAL_TIME ) ),
@ -527,11 +528,11 @@ public final class CommandComputerCraft extends CommandDelegate
}
else
{
table.addRow( computerComponent, text( entry.getFormatted( field ) ) );
table.row( computerComponent, text( entry.getFormatted( field ) ) );
}
}
table.displayTo( context.getSender() );
table.display( context.getSender() );
}
private static void withComputers( List<String> selectors, Consumer<Collection<ServerComputer>> action ) throws CommandException

View File

@ -0,0 +1,21 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.common.util.FakePlayer;
public class CommandUtils
{
public static boolean isPlayer( ICommandSender sender )
{
return sender instanceof EntityPlayerMP
&& !(sender instanceof FakePlayer)
&& ((EntityPlayerMP) sender).connection != null;
}
}

View File

@ -2,6 +2,7 @@ package dan200.computercraft.shared.command.framework;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import dan200.computercraft.shared.command.text.ChatHelpers;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;

View File

@ -1,6 +1,7 @@
package dan200.computercraft.shared.command.framework;
import com.google.common.collect.Lists;
import dan200.computercraft.shared.command.text.ChatHelpers;
import joptsimple.internal.Strings;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;

View File

@ -1,147 +0,0 @@
package dan200.computercraft.shared.command.framework;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.common.util.FakePlayer;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
import static dan200.computercraft.shared.command.framework.ChatHelpers.coloured;
/**
* Adapated from Sponge's PaginationCalculator
*/
public class TextFormatter
{
private static final char PADDING_CHAR = '\u02cc';
/**
* Yoinked from FontRenderer
*
* @see net.minecraft.client.gui.FontRenderer#charWidth
* @see net.minecraft.client.gui.FontRenderer#getCharWidth(char)
*/
private static final String CHARACTERS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
private static final int[] CHAR_WIDTHS = new int[] {
6, 6, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 4,
4, 6, 7, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1,
1, 2, 5, 6, 6, 6, 6, 3, 5, 5, 5, 6, 2, 6, 2, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 5, 6, 5, 6,
7, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 6, 6,
3, 6, 6, 6, 6, 6, 5, 6, 6, 2, 6, 5, 3, 6, 6, 6,
6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 5, 2, 5, 7, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 3, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6,
6, 3, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 2, 6, 6,
8, 9, 9, 6, 6, 6, 8, 8, 6, 8, 8, 8, 8, 8, 6, 6,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 9, 9, 9, 5, 9, 9,
8, 7, 7, 8, 7, 8, 8, 8, 7, 8, 8, 7, 9, 9, 6, 7,
7, 7, 7, 7, 9, 6, 7, 8, 7, 6, 6, 9, 7, 6, 7, 1
};
private static final int[] EXTRA_CHARS = new int[] {
'\u20e2', '\u261b',
};
private static final byte[] EXTRA_WIDTHS = new byte[] {
8, 4,
};
public static int getWidth( int codePoint )
{
// Escape codes
if( codePoint == 167 ) return -1;
// Space and non-breaking space
if( codePoint == 32 || codePoint == 160 ) return 4;
// Built-in characters
int nonUnicodeIdx = CHARACTERS.indexOf( codePoint );
if( codePoint > 0 && nonUnicodeIdx != -1 ) return CHAR_WIDTHS[nonUnicodeIdx];
// Other special characters we use.
int extraIdx = Arrays.binarySearch( EXTRA_CHARS, codePoint );
if( extraIdx >= 0 ) return EXTRA_WIDTHS[extraIdx];
return 0;
}
public static int getWidth( ITextComponent component )
{
int total = 0;
if( component instanceof TextComponentString )
{
String contents = component.getUnformattedComponentText();
int bold = component.getStyle().getBold() ? 1 : 0;
for( int i = 0; i < contents.length(); i++ )
{
int cp = contents.charAt( i );
assert cp != '\n';
int width = getWidth( cp );
if( width < 0 )
{
i++;
}
else
{
total += width + bold;
}
}
}
for( ITextComponent child : component.getSiblings() )
{
total += getWidth( child );
}
return total;
}
public static boolean isPlayer( ICommandSender sender )
{
return sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
}
public static int getMaxWidth( ICommandSender sender )
{
return isPlayer( sender ) ? 320 : 80;
}
public static int getWidthFor( ITextComponent component, ICommandSender sender )
{
return isPlayer( sender ) ? getWidth( component ) : component.getUnformattedText().length();
}
public static int getWidthFor( int codepoint, ICommandSender sender )
{
return isPlayer( sender ) ? getWidth( codepoint ) : 1;
}
public static void appendFixedWidth( ITextComponent out, ICommandSender sender, ITextComponent entry, int maxWidth )
{
out.appendSibling( entry );
int width = getWidthFor( entry, sender );
int delta = maxWidth - width;
int spaceWidth = getWidthFor( ' ', sender );
int spaces = delta / spaceWidth;
int extra = delta % spaces;
// Append a fixed number of spaces
if( spaces > 0 ) out.appendSibling( new TextComponentString( StringUtils.repeat( ' ', spaces ) ) );
// Append several minor characters to pad to a full string
if( extra > 0 )
{
out.appendSibling( coloured( StringUtils.repeat( PADDING_CHAR, extra ), TextFormatting.GRAY ) );
}
}
}

View File

@ -1,170 +0,0 @@
package dan200.computercraft.shared.command.framework;
import com.google.common.collect.Lists;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.network.ComputerCraftPacket;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextFormatting;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import static dan200.computercraft.shared.command.framework.ChatHelpers.coloured;
import static dan200.computercraft.shared.command.framework.ChatHelpers.text;
import static dan200.computercraft.shared.command.framework.TextFormatter.*;
public class TextTable
{
private static final ITextComponent SEPARATOR = coloured( "| ", TextFormatting.GRAY );
private static final ITextComponent LINE = text( "\n" );
private final int id;
private int columns = -1;
private final ITextComponent[] header;
private final List<ITextComponent[]> rows = Lists.newArrayList();
public TextTable( int id, @Nonnull ITextComponent... header )
{
this.id = id;
this.header = header;
this.columns = header.length;
}
public TextTable( int id )
{
this.id = id;
this.header = null;
}
public TextTable( int id, @Nonnull String... header )
{
this.id = id;
this.header = new ITextComponent[header.length];
for( int i = 0; i < header.length; i++ )
{
this.header[i] = ChatHelpers.header( header[i] );
}
this.columns = header.length;
}
public void addRow( @Nonnull ITextComponent... row )
{
if( columns == -1 )
{
columns = row.length;
}
else if( row.length != columns )
{
throw new IllegalArgumentException( "Row is the incorrect length" );
}
rows.add( row );
}
public void displayTo( ICommandSender sender )
{
if( columns <= 0 ) return;
int[] maxWidths = new int[columns];
if( header != null )
{
for( int i = 0; i < columns; i++ )
{
maxWidths[i] = getWidthFor( header[i], sender );
}
}
// Limit the number of rows to fit within a single chat window on default Minecraft
// options.
int height = isPlayer( sender ) ? 18 : 100;
int limit = rows.size() <= height ? rows.size() : height - 1;
for( int y = 0; y < limit; y++ )
{
ITextComponent[] row = rows.get( y );
for( int i = 0; i < row.length; i++ )
{
int width = getWidthFor( row[i], sender );
if( width > maxWidths[i] ) maxWidths[i] = width;
}
}
// Add a small amount of extra padding. This defaults to 3 spaces for players
// and 1 for everyone else.
int padding = isPlayer( sender ) ? getWidth( ' ' ) * 3 : 1;
for( int i = 0; i < maxWidths.length; i++ ) maxWidths[i] += padding;
int totalWidth = (columns - 1) * getWidthFor( SEPARATOR, sender );
for( int x : maxWidths ) totalWidth += x;
// TODO: Limit the widths of some entries if totalWidth > maxWidth
List<ITextComponent> out = new ArrayList<>();
if( header != null )
{
TextComponentString line = new TextComponentString( "" );
for( int i = 0; i < columns - 1; i++ )
{
appendFixedWidth( line, sender, header[i], maxWidths[i] );
line.appendSibling( SEPARATOR );
}
line.appendSibling( header[columns - 1] );
out.add( line );
// Round the width up rather than down
int rowCharWidth = getWidthFor( '=', sender );
int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1);
out.add( coloured( StringUtils.repeat( '=', rowWidth ), TextFormatting.GRAY ) );
}
for( int i = 0; i < limit; i++ )
{
TextComponentString line = new TextComponentString( "" );
ITextComponent[] row = rows.get( i );
for( int j = 0; j < columns - 1; j++ )
{
appendFixedWidth( line, sender, row[j], maxWidths[j] );
line.appendSibling( SEPARATOR );
}
line.appendSibling( row[columns - 1] );
out.add( line );
}
if( rows.size() > limit )
{
out.add( coloured( (rows.size() - limit) + " additional rows...", TextFormatting.AQUA ) );
}
if( isPlayer( sender ) && id != 0 )
{
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.PostChat;
packet.m_dataInt = new int[] { id };
String[] lines = packet.m_dataString = new String[out.size()];
for( int i = 0; i < out.size(); i++ )
{
lines[i] = ITextComponent.Serializer.componentToJson( out.get( i ) );
}
ComputerCraft.sendToPlayer( (EntityPlayerMP) sender, packet );
}
else
{
ITextComponent result = new TextComponentString( "" );
for( int i = 0; i < out.size(); i++ )
{
if( i > 0 ) result.appendSibling( LINE );
result.appendSibling( out.get( i ) );
}
sender.sendMessage( result );
}
}
}

View File

@ -1,6 +1,15 @@
package dan200.computercraft.shared.command.framework;
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.text;
import com.google.common.base.Strings;
import dan200.computercraft.shared.command.framework.CommandContext;
import dan200.computercraft.shared.command.framework.CommandRoot;
import dan200.computercraft.shared.command.framework.ISubCommand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.Style;

View File

@ -0,0 +1,51 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.text;
import net.minecraft.command.ICommandSender;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
public class ServerTableFormatter implements TableFormatter
{
private final ICommandSender source;
public ServerTableFormatter( ICommandSender source )
{
this.source = source;
}
@Override
@Nullable
public ITextComponent getPadding( ITextComponent component, int width )
{
int extraWidth = width - getWidth( component );
if( extraWidth <= 0 ) return null;
return new TextComponentString( StringUtils.repeat( ' ', extraWidth ) );
}
@Override
public int getColumnPadding()
{
return 1;
}
@Override
public int getWidth( ITextComponent component )
{
return component.getUnformattedText().length();
}
@Override
public void writeLine( int id, ITextComponent component )
{
source.sendMessage( component );
}
}

View File

@ -0,0 +1,131 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.text;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.command.CommandUtils;
import dan200.computercraft.shared.network.client.ChatTableClientMessage;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.text.ITextComponent;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class TableBuilder
{
private final int id;
private int columns = -1;
private final ITextComponent[] headers;
private final ArrayList<ITextComponent[]> rows = new ArrayList<>();
private int additional;
public TableBuilder( int id, @Nonnull ITextComponent... headers )
{
if( id < 0 ) throw new IllegalArgumentException( "ID must be positive" );
this.id = id;
this.headers = headers;
this.columns = headers.length;
}
public TableBuilder( int id )
{
if( id < 0 ) throw new IllegalArgumentException( "ID must be positive" );
this.id = id;
this.headers = null;
}
public TableBuilder( int id, @Nonnull String... headers )
{
if( id < 0 ) throw new IllegalArgumentException( "ID must be positive" );
this.id = id;
this.headers = new ITextComponent[headers.length];
this.columns = headers.length;
for( int i = 0; i < headers.length; i++ ) this.headers[i] = ChatHelpers.header( headers[i] );
}
public void row( @Nonnull ITextComponent... row )
{
if( columns == -1 ) columns = row.length;
if( row.length != columns ) throw new IllegalArgumentException( "Row is the incorrect length" );
rows.add( row );
}
/**
* Get the unique identifier for this table type.
*
* When showing a table within Minecraft, previous instances of this table with
* the same ID will be removed from chat.
*
* @return This table's type.
*/
public int getId()
{
return id;
}
/**
* Get the number of columns for this table.
*
* This will be the same as {@link #getHeaders()}'s length if it is is non-{@code null},
* otherwise the length of the first column.
*
* @return The number of columns.
*/
public int getColumns()
{
return columns;
}
@Nullable
public ITextComponent[] getHeaders()
{
return headers;
}
@Nonnull
public List<ITextComponent[]> getRows()
{
return rows;
}
public int getAdditional()
{
return additional;
}
/**
* Trim this table to a given height
*
* @param height The desired height.
*/
public void trim( int height )
{
if( rows.size() > height )
{
additional += rows.size() - height;
rows.subList( height, rows.size() ).clear();
}
}
public void display( ICommandSender source )
{
if( CommandUtils.isPlayer( source ) )
{
trim( 18 );
ComputerCraft.sendToPlayer( (EntityPlayerMP) source, new ChatTableClientMessage( this ) );
}
else
{
trim( 100 );
new ServerTableFormatter( source ).display( this );
}
}
}

View File

@ -0,0 +1,122 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.text;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextFormatting;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
import static dan200.computercraft.shared.command.text.ChatHelpers.coloured;
public interface TableFormatter
{
ITextComponent SEPARATOR = coloured( "| ", TextFormatting.GRAY );
ITextComponent HEADER = coloured( "=", TextFormatting.GRAY );
/**
* Get additional padding for the component
*
* @param component The component to pad
* @param width The desired width for the component
* @return The padding for this component, or {@code null} if none is needed.
*/
@Nullable
ITextComponent getPadding( ITextComponent component, int width );
/**
* Get the minimum padding between each column
*
* @return The minimum padding.
*/
int getColumnPadding();
int getWidth( ITextComponent component );
void writeLine( int id, ITextComponent component );
default int display( TableBuilder table )
{
if( table.getColumns() <= 0 ) return 0;
int rowId = table.getId();
int columns = table.getColumns();
int[] maxWidths = new int[columns];
ITextComponent[] headers = table.getHeaders();
if( headers != null )
{
for( int i = 0; i < columns; i++ ) maxWidths[i] = getWidth( headers[i] );
}
for( ITextComponent[] row : table.getRows() )
{
for( int i = 0; i < row.length; i++ )
{
int width = getWidth( row[i] );
if( width > maxWidths[i] ) maxWidths[i] = width;
}
}
// Add a small amount of padding after each column
{
int padding = getColumnPadding();
for( int i = 0; i < maxWidths.length - 1; i++ ) maxWidths[i] += padding;
}
// And comput the total width
int totalWidth = (columns - 1) * getWidth( SEPARATOR );
for( int x : maxWidths ) totalWidth += x;
// TODO: Limit the widths of some entries if totalWidth > maxWidth
if( headers != null )
{
TextComponentString line = new TextComponentString( "" );
for( int i = 0; i < columns - 1; i++ )
{
line.appendSibling( headers[i] );
ITextComponent padding = getPadding( headers[i], maxWidths[i] );
if( padding != null ) line.appendSibling( padding );
line.appendSibling( SEPARATOR );
}
line.appendSibling( headers[columns - 1] );
writeLine( rowId++, line );
// Write a separator line. We round the width up rather than down to make
// it a tad prettier.
int rowCharWidth = getWidth( HEADER );
int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1);
writeLine( rowId++, coloured( StringUtils.repeat( HEADER.getUnformattedText(), rowWidth ), TextFormatting.GRAY ) );
}
for( ITextComponent[] row : table.getRows() )
{
TextComponentString line = new TextComponentString( "" );
for( int i = 0; i < columns - 1; i++ )
{
line.appendSibling( row[i] );
ITextComponent padding = getPadding( row[i], maxWidths[i] );
if( padding != null ) line.appendSibling( padding );
line.appendSibling( SEPARATOR );
}
line.appendSibling( row[columns - 1] );
writeLine( rowId++, line );
}
if( table.getAdditional() > 0 )
{
writeLine( rowId++, coloured( table.getAdditional() + " additional rows...", TextFormatting.AQUA ) );
}
return rowId - table.getId();
}
}

View File

@ -6,8 +6,6 @@
package dan200.computercraft.shared.common;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.network.ComputerCraftPacket;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
@ -27,19 +25,6 @@ import javax.annotation.Nullable;
public abstract class TileGeneric extends TileEntity
{
public void requestTileEntityUpdate()
{
if( getWorld().isRemote )
{
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.RequestTileEntityUpdate;
BlockPos pos = getPos();
packet.m_dataInt = new int[] { pos.getX(), pos.getY(), pos.getZ() };
ComputerCraft.sendToServer( packet );
}
}
public void destroy()
{
}

View File

@ -8,6 +8,7 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.block.material.Material;
@ -46,7 +47,7 @@ public class BlockCommandComputer extends BlockComputerBase
setCreativeTab( ComputerCraft.mainCreativeTab );
setDefaultState( this.blockState.getBaseState()
.withProperty( Properties.FACING, EnumFacing.NORTH )
.withProperty( Properties.STATE, ComputerState.Off )
.withProperty( Properties.STATE, ComputerState.OFF )
);
}
@ -82,22 +83,12 @@ public class BlockCommandComputer extends BlockComputerBase
public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos )
{
TileEntity tile = world.getTileEntity( pos );
if( tile != null && tile instanceof IComputerTile )
if( tile instanceof IComputerTile )
{
IComputer computer = ((IComputerTile) tile).getComputer();
if( computer != null && computer.isOn() )
{
if( computer.isCursorDisplayed() )
{
return state.withProperty( Properties.STATE, ComputerState.Blinking );
}
else
{
return state.withProperty( Properties.STATE, ComputerState.On );
}
}
if( computer != null ) return state.withProperty( Properties.STATE, computer.getState() );
}
return state.withProperty( Properties.STATE, ComputerState.Off );
return state.withProperty( Properties.STATE, ComputerState.OFF );
}
@Override

View File

@ -8,6 +8,7 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.computer.items.ComputerItemFactory;
import dan200.computercraft.shared.computer.items.ItemComputer;
@ -52,7 +53,7 @@ public class BlockComputer extends BlockComputerBase
setDefaultState( this.blockState.getBaseState()
.withProperty( Properties.FACING, EnumFacing.NORTH )
.withProperty( Properties.ADVANCED, false )
.withProperty( Properties.STATE, ComputerState.Off )
.withProperty( Properties.STATE, ComputerState.OFF )
);
}
@ -126,22 +127,12 @@ public class BlockComputer extends BlockComputerBase
public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos )
{
TileEntity tile = world.getTileEntity( pos );
if( tile != null && tile instanceof IComputerTile )
if( tile instanceof IComputerTile )
{
IComputer computer = ((IComputerTile) tile).getComputer();
if( computer != null && computer.isOn() )
{
if( computer.isCursorDisplayed() )
{
return state.withProperty( Properties.STATE, ComputerState.Blinking );
}
else
{
return state.withProperty( Properties.STATE, ComputerState.On );
}
}
if( computer != null ) return state.withProperty( Properties.STATE, computer.getState() );
}
return state.withProperty( Properties.STATE, ComputerState.Off );
return state.withProperty( Properties.STATE, ComputerState.OFF );
}
@Override

View File

@ -9,14 +9,12 @@ package dan200.computercraft.shared.computer.core;
import com.google.common.base.Objects;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.common.ClientTerminal;
import dan200.computercraft.shared.network.ComputerCraftPacket;
import dan200.computercraft.shared.network.INetworkedThing;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.entity.player.EntityPlayer;
import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
import dan200.computercraft.shared.network.server.QueueEventServerMessage;
import dan200.computercraft.shared.network.server.RequestComputerMessage;
import net.minecraft.nbt.NBTTagCompound;
public class ClientComputer extends ClientTerminal
implements IComputer, INetworkedThing
public class ClientComputer extends ClientTerminal implements IComputer
{
private final int m_instanceID;
@ -64,10 +62,7 @@ public class ClientComputer extends ClientTerminal
public void requestState()
{
// Request state from server
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.RequestComputerUpdate;
packet.m_dataInt = new int[] { getInstanceID() };
ComputerCraft.sendToServer( packet );
ComputerCraft.sendToServer( new RequestComputerMessage( getInstanceID() ) );
}
// IComputer
@ -106,54 +101,31 @@ public class ClientComputer extends ClientTerminal
public void turnOn()
{
// Send turnOn to server
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.TurnOn;
packet.m_dataInt = new int[] { m_instanceID };
ComputerCraft.sendToServer( packet );
ComputerCraft.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.TURN_ON ) );
}
@Override
public void shutdown()
{
// Send shutdown to server
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.Shutdown;
packet.m_dataInt = new int[] { m_instanceID };
ComputerCraft.sendToServer( packet );
ComputerCraft.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.SHUTDOWN ) );
}
@Override
public void reboot()
{
// Send reboot to server
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.Reboot;
packet.m_dataInt = new int[] { m_instanceID };
ComputerCraft.sendToServer( packet );
}
@Override
public void queueEvent( String event )
{
queueEvent( event, null );
ComputerCraft.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.REBOOT ) );
}
@Override
public void queueEvent( String event, Object[] arguments )
{
// Send event to server
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.QueueEvent;
packet.m_dataInt = new int[] { m_instanceID };
packet.m_dataString = new String[] { event };
if( arguments != null )
{
packet.m_dataNBT = NBTUtil.encodeObjects( arguments );
}
ComputerCraft.sendToServer( packet );
ComputerCraft.sendToServer( new QueueEventServerMessage( m_instanceID, event, arguments ) );
}
private void readComputerDescription( NBTTagCompound nbttagcompound )
public void setState( int id, String label, ComputerState state, NBTTagCompound userData )
{
int oldID = m_computerID;
String oldLabel = m_label;
@ -161,36 +133,13 @@ public class ClientComputer extends ClientTerminal
boolean oldBlinking = m_blinking;
NBTTagCompound oldUserData = m_userData;
m_computerID = nbttagcompound.getInteger( "id" );
m_label = nbttagcompound.hasKey( "label" ) ? nbttagcompound.getString( "label" ) : null;
m_on = nbttagcompound.getBoolean( "on" );
m_blinking = nbttagcompound.getBoolean( "blinking" );
if( nbttagcompound.hasKey( "userData" ) )
{
m_userData = nbttagcompound.getCompoundTag( "userData" ).copy();
}
else
{
m_userData = null;
}
m_computerID = id;
m_label = label;
m_on = state != ComputerState.OFF;
m_blinking = state == ComputerState.BLINKING;
m_userData = userData;
if( m_computerID != oldID || m_on != oldOn || m_blinking != oldBlinking || !Objects.equal( m_label, oldLabel ) || !Objects.equal( m_userData, oldUserData ) )
{
m_changed = true;
}
}
@Override
public void handlePacket( ComputerCraftPacket packet, EntityPlayer sender )
{
switch( packet.m_packetType )
{
case ComputerCraftPacket.ComputerChanged:
readComputerDescription( packet.m_dataNBT );
break;
case ComputerCraftPacket.ComputerTerminalChanged:
readDescription( packet.m_dataNBT );
break;
}
m_changed |= m_computerID != oldID || m_on != oldOn || m_blinking != oldBlinking
|| !Objects.equal( m_label, oldLabel ) || !Objects.equal( m_userData, oldUserData );
}
}

View File

@ -1,10 +1,10 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.computer.blocks;
package dan200.computercraft.shared.computer.core;
import net.minecraft.util.IStringSerializable;
@ -12,9 +12,9 @@ import javax.annotation.Nonnull;
public enum ComputerState implements IStringSerializable
{
Off( "off" ),
On( "on" ),
Blinking( "blinking" );
OFF( "off" ),
ON( "on" ),
BLINKING( "blinking" );
private String m_name;

View File

@ -26,7 +26,16 @@ public interface IComputer extends ITerminal
void reboot();
void queueEvent( String event );
default void queueEvent( String event )
{
queueEvent( event, null );
}
void queueEvent( String event, Object[] arguments );
default ComputerState getState()
{
if( !isOn() ) return ComputerState.OFF;
return isCursorDisplayed() ? ComputerState.BLINKING : ComputerState.ON;
}
}

View File

@ -16,9 +16,9 @@ import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.shared.common.ServerTerminal;
import dan200.computercraft.shared.network.ComputerCraftPacket;
import dan200.computercraft.shared.network.INetworkedThing;
import dan200.computercraft.shared.util.NBTUtil;
import dan200.computercraft.shared.network.client.ComputerDataClientMessage;
import dan200.computercraft.shared.network.client.ComputerDeletedClientMessage;
import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.Container;
@ -28,11 +28,11 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import java.io.InputStream;
public class ServerComputer extends ServerTerminal
implements IComputer, IComputerEnvironment, INetworkedThing
public class ServerComputer extends ServerTerminal implements IComputer, IComputerEnvironment
{
private final int m_instanceID;
@ -146,24 +146,16 @@ public class ServerComputer extends ServerTerminal
m_changed = true;
}
private ComputerCraftPacket createComputerPacket()
private IMessage createComputerPacket()
{
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.ComputerChanged;
packet.m_dataInt = new int[] { getInstanceID() };
packet.m_dataNBT = new NBTTagCompound();
writeComputerDescription( packet.m_dataNBT );
return packet;
return new ComputerDataClientMessage( this );
}
protected ComputerCraftPacket createTerminalPacket()
protected IMessage createTerminalPacket()
{
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.ComputerTerminalChanged;
packet.m_dataInt = new int[] { getInstanceID() };
packet.m_dataNBT = new NBTTagCompound();
writeDescription( packet.m_dataNBT );
return packet;
NBTTagCompound tagCompound = new NBTTagCompound();
writeDescription( tagCompound );
return new ComputerTerminalClientMessage( getInstanceID(), tagCompound );
}
public void broadcastState( boolean force )
@ -180,7 +172,7 @@ public class ServerComputer extends ServerTerminal
FMLCommonHandler handler = FMLCommonHandler.instance();
if( handler != null )
{
ComputerCraftPacket packet = createTerminalPacket();
IMessage packet = createTerminalPacket();
MinecraftServer server = handler.getMinecraftServerInstance();
for( EntityPlayerMP player : server.getPlayerList().getPlayers() )
{
@ -208,10 +200,7 @@ public class ServerComputer extends ServerTerminal
public void broadcastDelete()
{
// Send deletion to client
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.ComputerDeleted;
packet.m_dataInt = new int[] { getInstanceID() };
ComputerCraft.sendToAllPlayers( packet );
ComputerCraft.sendToAllPlayers( new ComputerDeletedClientMessage( getInstanceID() ) );
}
public IWritableMount getRootMount()
@ -282,13 +271,6 @@ public class ServerComputer extends ServerTerminal
m_computer.reboot();
}
@Override
public void queueEvent( String event )
{
// Queue event
queueEvent( event, null );
}
@Override
public void queueEvent( String event, Object[] arguments )
{
@ -408,67 +390,7 @@ public class ServerComputer extends ServerTerminal
}
}
// INetworkedThing
@Override
public void handlePacket( ComputerCraftPacket packet, EntityPlayer sender )
{
// Allow Computer/Tile updates as they may happen at any time.
if( packet.requiresContainer() && !isInteracting( sender ) )
{
return;
}
// Receive packets sent from the client to the server
switch( packet.m_packetType )
{
case ComputerCraftPacket.TurnOn:
{
// A player has turned the computer on
turnOn();
break;
}
case ComputerCraftPacket.Reboot:
{
// A player has held down ctrl+r
reboot();
break;
}
case ComputerCraftPacket.Shutdown:
{
// A player has held down ctrl+s
shutdown();
break;
}
case ComputerCraftPacket.QueueEvent:
{
// A player has caused a UI event to be fired
String event = packet.m_dataString[0];
Object[] arguments = null;
if( packet.m_dataNBT != null )
{
arguments = NBTUtil.decodeObjects( packet.m_dataNBT );
}
queueEvent( event, arguments );
break;
}
case ComputerCraftPacket.SetLabel:
{
// A player wants to relabel a computer
String label = (packet.m_dataString != null && packet.m_dataString.length >= 1) ? packet.m_dataString[0] : null;
setLabel( label );
break;
}
case ComputerCraftPacket.RequestComputerUpdate:
{
// A player asked for an update on the state of the terminal
sendComputerState( sender );
break;
}
}
}
protected boolean isInteracting( EntityPlayer player )
public boolean isInteracting( EntityPlayer player )
{
if( player == null ) return false;

View File

@ -1,239 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network;
import io.netty.buffer.ByteBuf;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class ComputerCraftPacket
{
// Packet types
// To server
public static final byte TurnOn = 1;
public static final byte Reboot = 2;
public static final byte Shutdown = 3;
public static final byte QueueEvent = 4;
public static final byte RequestComputerUpdate = 5;
public static final byte SetLabel = 6;
public static final byte RequestTileEntityUpdate = 9;
// To client
public static final byte ComputerChanged = 7;
public static final byte ComputerTerminalChanged = 8;
public static final byte ComputerDeleted = 9;
public static final byte PlayRecord = 10;
public static final byte PostChat = 11;
// Packet class
public byte m_packetType;
public String[] m_dataString;
public int[] m_dataInt;
public byte[][] m_dataByte;
public NBTTagCompound m_dataNBT;
public ComputerCraftPacket()
{
m_packetType = 0;
m_dataString = null;
m_dataInt = null;
m_dataByte = null;
m_dataNBT = null;
}
public void toBytes( PacketBuffer buffer )
{
buffer.writeByte( m_packetType );
if( m_dataString != null )
{
buffer.writeByte( m_dataString.length );
}
else
{
buffer.writeByte( 0 );
}
if( m_dataInt != null )
{
buffer.writeByte( m_dataInt.length );
}
else
{
buffer.writeByte( 0 );
}
if( m_dataByte != null )
{
buffer.writeInt( m_dataByte.length );
}
else
{
buffer.writeInt( 0 );
}
if( m_dataString != null )
{
for( String s : m_dataString )
{
if( s != null )
{
try
{
byte[] b = s.getBytes( "UTF-8" );
buffer.writeBoolean( true );
buffer.writeInt( b.length );
buffer.writeBytes( b );
}
catch( UnsupportedEncodingException e )
{
buffer.writeBoolean( false );
}
}
else
{
buffer.writeBoolean( false );
}
}
}
if( m_dataInt != null )
{
for( int i : m_dataInt )
{
buffer.writeInt( i );
}
}
if( m_dataByte != null )
{
for( byte[] bytes : m_dataByte )
{
if( bytes != null )
{
buffer.writeInt( bytes.length );
buffer.writeBytes( bytes );
}
else
{
buffer.writeInt( 0 );
}
}
}
if( m_dataNBT != null )
{
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
CompressedStreamTools.writeCompressed( m_dataNBT, bos );
byte[] bytes = bos.toByteArray();
buffer.writeBoolean( true );
buffer.writeInt( bytes.length );
buffer.writeBytes( bytes );
}
catch( IOException e )
{
buffer.writeBoolean( false );
}
}
else
{
buffer.writeBoolean( false );
}
}
public void fromBytes( ByteBuf buffer )
{
m_packetType = buffer.readByte();
byte nString = buffer.readByte();
byte nInt = buffer.readByte();
int nByte = buffer.readInt();
if( nString == 0 )
{
m_dataString = null;
}
else
{
m_dataString = new String[nString];
for( int k = 0; k < nString; k++ )
{
if( buffer.readBoolean() )
{
int len = buffer.readInt();
byte[] b = new byte[len];
buffer.readBytes( b );
try
{
m_dataString[k] = new String( b, "UTF-8" );
}
catch( UnsupportedEncodingException e )
{
m_dataString[k] = null;
}
}
}
}
if( nInt == 0 )
{
m_dataInt = null;
}
else
{
m_dataInt = new int[nInt];
for( int k = 0; k < nInt; k++ )
{
m_dataInt[k] = buffer.readInt();
}
}
if( nByte == 0 )
{
m_dataByte = null;
}
else
{
m_dataByte = new byte[nByte][];
for( int k = 0; k < nByte; k++ )
{
int length = buffer.readInt();
if( length > 0 )
{
m_dataByte[k] = new byte[length];
buffer.getBytes( buffer.readerIndex(), m_dataByte[k] );
}
}
}
boolean bNBT = buffer.readBoolean();
if( !bNBT )
{
m_dataNBT = null;
}
else
{
int byteLength = buffer.readInt();
byte[] bytes = new byte[byteLength];
buffer.getBytes( buffer.readerIndex(), bytes );
try
{
ByteArrayInputStream bis = new ByteArrayInputStream( bytes );
m_dataNBT = CompressedStreamTools.readCompressed( bis );
}
catch( IOException e )
{
m_dataNBT = null;
}
}
}
/**
* Determine whether this packet requires the player to be interacting with the
* target.
*/
public boolean requiresContainer()
{
return m_packetType != RequestComputerUpdate && m_packetType != RequestTileEntityUpdate;
}
}

View File

@ -1,14 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network;
import net.minecraft.entity.player.EntityPlayer;
public interface INetworkedThing
{
void handlePacket( ComputerCraftPacket packet, EntityPlayer sender );
}

View File

@ -0,0 +1,118 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network;
import dan200.computercraft.ComputerCraft;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.IThreadListener;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import javax.annotation.Nonnull;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
* The base interface for any message which will be sent to the client or server.
*
* @see dan200.computercraft.shared.network.client
* @see dan200.computercraft.shared.network.server
*/
public interface NetworkMessage extends IMessage
{
/**
* The unique identifier for this packet type
*
* @return This packet type's identifier
*/
int getId();
/**
* Write this packet to a buffer.
*
* This may be called on any thread, so this should be a pure operation.
*
* @param buf The buffer to write data to.
*/
void toBytes( @Nonnull PacketBuffer buf );
/**
* Read this packet from a buffer.
*
* This may be called on any thread, so this should be a pure operation.
*
* @param buf The buffer to read data from.
*/
void fromBytes( @Nonnull PacketBuffer buf );
@Override
default void fromBytes( ByteBuf buf )
{
fromBytes( new PacketBuffer( buf ) );
}
@Override
default void toBytes( ByteBuf buf )
{
toBytes( new PacketBuffer( buf ) );
}
/**
* Register a packet, and a thread-safe handler for it.
*
* @param side The side to register this packet handler under
* @param factory The factory for this type of packet.
* @param handler The handler for this type of packet. Note, this may be called on any thread,
* and so should be thread-safe.
*/
@SuppressWarnings( "unchecked" )
static <T extends NetworkMessage> void register(
Side side,
Supplier<T> factory,
BiConsumer<MessageContext, T> handler
)
{
T instance = factory.get();
ComputerCraft.networkWrapper.registerMessage( ( packet, ctx ) -> {
handler.accept( ctx, (T) packet );
return null;
}, instance.getClass(), instance.getId(), side );
}
/**
* Register packet, and a thread-unsafe handler for it.
*
* @param side The side to register this packet handler under
* @param factory The factory for this type of packet.
* @param handler The handler for this type of packet. This will be called on the "main"
* thread (either client or server).
*/
@SuppressWarnings( "unchecked" )
static <T extends NetworkMessage> void registerMainThread(
Side side,
Supplier<T> factory,
BiConsumer<MessageContext, T> handler
)
{
T instance = factory.get();
ComputerCraft.networkWrapper.registerMessage( ( packet, ctx ) -> {
IThreadListener listener = side == Side.CLIENT ? Minecraft.getMinecraft() : ctx.getServerHandler().player.server;
if( listener.isCallingFromMinecraftThread() )
{
handler.accept( ctx, (T) packet );
}
else
{
listener.addScheduledTask( () -> handler.accept( ctx, (T) packet ) );
}
return null;
}, instance.getClass(), instance.getId(), side );
}
}

View File

@ -0,0 +1,24 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network;
public final class NetworkMessages
{
private NetworkMessages()
{
}
public static final int COMPUTER_ACTION_SERVER_MESSAGE = 0;
public static final int QUEUE_EVENT_SERVER_MESSAGE = 1;
public static final int REQUEST_COMPUTER_SERVER_MESSAGE = 2;
public static final int CHAT_TABLE_CLIENT_MESSAGE = 10;
public static final int COMPUTER_DATA_CLIENT_MESSAGE = 11;
public static final int COMPUTER_DELETED_CLIENT_MESSAGE = 12;
public static final int COMPUTER_TERMINAL_CLIENT_MESSAGE = 13;
public static final int PLAY_RECORD_CLIENT_MESSAGE = 14;
}

View File

@ -1,45 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network;
import dan200.computercraft.ComputerCraft;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
public class PacketHandler
{
@SubscribeEvent
public void onClientPacket( FMLNetworkEvent.ClientCustomPacketEvent event )
{
try
{
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.fromBytes( event.getPacket().payload() );
ComputerCraft.handlePacket( packet, null );
}
catch( Exception e )
{
ComputerCraft.log.error( "Error handling packet", e );
}
}
@SubscribeEvent
public void onServerPacket( FMLNetworkEvent.ServerCustomPacketEvent event )
{
try
{
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.fromBytes( event.getPacket().payload() );
ComputerCraft.handlePacket( packet, ((NetHandlerPlayServer) event.getHandler()).player );
}
catch( Exception e )
{
ComputerCraft.log.error( "Error handling packet", e );
}
}
}

View File

@ -0,0 +1,95 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.network.NetworkMessage;
import dan200.computercraft.shared.network.NetworkMessages;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.text.ITextComponent;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.UncheckedIOException;
public class ChatTableClientMessage implements NetworkMessage
{
private TableBuilder table;
public ChatTableClientMessage( TableBuilder table )
{
if( table.getColumns() < 0 ) throw new IllegalStateException( "Cannot send an empty table" );
this.table = table;
}
public ChatTableClientMessage()
{
}
@Override
public int getId()
{
return NetworkMessages.CHAT_TABLE_CLIENT_MESSAGE;
}
public TableBuilder getTable()
{
return table;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
buf.writeVarInt( table.getId() );
buf.writeVarInt( table.getColumns() );
buf.writeBoolean( table.getHeaders() != null );
if( table.getHeaders() != null )
{
for( ITextComponent header : table.getHeaders() ) buf.writeTextComponent( header );
}
buf.writeVarInt( table.getRows().size() );
for( ITextComponent[] row : table.getRows() )
{
for( ITextComponent column : row ) buf.writeTextComponent( column );
}
}
@Override
public void fromBytes( @Nonnull PacketBuffer buf )
{
try
{
int id = buf.readVarInt();
int columns = buf.readVarInt();
TableBuilder table;
if( buf.readBoolean() )
{
ITextComponent[] headers = new ITextComponent[columns];
for( int i = 0; i < columns; i++ ) headers[i] = buf.readTextComponent();
table = new TableBuilder( id, headers );
}
else
{
table = new TableBuilder( id );
}
int rows = buf.readVarInt();
for( int i = 0; i < rows; i++ )
{
ITextComponent[] row = new ITextComponent[columns];
for( int j = 0; j < columns; j++ ) row[j] = buf.readTextComponent();
table.row( row );
}
this.table = table;
}
catch( IOException e )
{
throw new UncheckedIOException( e );
}
}
}

View File

@ -0,0 +1,69 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.client;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.network.NetworkMessage;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.relauncher.Side;
import javax.annotation.Nonnull;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
* A packet, which performs an action on a {@link ClientComputer}.
*/
public abstract class ComputerClientMessage implements NetworkMessage
{
private int instanceId;
public ComputerClientMessage( int instanceId )
{
this.instanceId = instanceId;
}
public ComputerClientMessage()
{
}
public int getInstanceId()
{
return instanceId;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
buf.writeVarInt( instanceId );
}
@Override
public void fromBytes( @Nonnull PacketBuffer buf )
{
instanceId = buf.readVarInt();
}
public ClientComputer getComputer()
{
ClientComputer computer = ComputerCraft.clientComputerRegistry.get( instanceId );
if( computer == null )
{
ComputerCraft.clientComputerRegistry.add( instanceId, computer = new ClientComputer( instanceId ) );
}
return computer;
}
public static <T extends ComputerClientMessage> void register( Supplier<T> factory, BiConsumer<ClientComputer, T> handler )
{
NetworkMessage.registerMainThread( Side.CLIENT, factory, ( context, packet ) -> {
ClientComputer computer = packet.getComputer();
if( computer != null ) handler.accept( computer, packet );
} );
}
}

View File

@ -0,0 +1,95 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.network.NetworkMessages;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.UncheckedIOException;
/**
* Provides additional data about a client computer, such as its ID and current state.
*/
public class ComputerDataClientMessage extends ComputerClientMessage
{
private int computerId;
private ComputerState state;
private String label;
private NBTTagCompound userData;
public ComputerDataClientMessage( ServerComputer computer )
{
super( computer.getInstanceID() );
this.computerId = computer.getID();
this.state = computer.getState();
this.label = computer.getLabel();
this.userData = computer.getUserData();
}
public ComputerDataClientMessage()
{
}
@Override
public int getId()
{
return NetworkMessages.COMPUTER_DATA_CLIENT_MESSAGE;
}
public int getComputerId()
{
return computerId;
}
public ComputerState getState()
{
return state;
}
public String getLabel()
{
return label;
}
public NBTTagCompound getUserData()
{
return userData;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
super.toBytes( buf );
buf.writeVarInt( computerId );
buf.writeEnumValue( state );
buf.writeBoolean( label != null );
if( label != null ) buf.writeString( label );
buf.writeCompoundTag( userData );
}
@Override
public void fromBytes( @Nonnull PacketBuffer buf )
{
super.fromBytes( buf );
computerId = buf.readVarInt();
state = buf.readEnumValue( ComputerState.class );
if( buf.readBoolean() ) label = buf.readString( Short.MAX_VALUE );
try
{
userData = buf.readCompoundTag();
}
catch( IOException e )
{
throw new UncheckedIOException( e );
}
}
}

View File

@ -0,0 +1,27 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.network.NetworkMessages;
public class ComputerDeletedClientMessage extends ComputerClientMessage
{
public ComputerDeletedClientMessage( int instanceId )
{
super( instanceId );
}
public ComputerDeletedClientMessage()
{
}
@Override
public int getId()
{
return NetworkMessages.COMPUTER_DELETED_CLIENT_MESSAGE;
}
}

View File

@ -0,0 +1,62 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.network.NetworkMessages;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.UncheckedIOException;
public class ComputerTerminalClientMessage extends ComputerClientMessage
{
private NBTTagCompound tag;
public ComputerTerminalClientMessage( int instanceId, NBTTagCompound tag )
{
super( instanceId );
this.tag = tag;
}
public ComputerTerminalClientMessage()
{
}
@Override
public int getId()
{
return NetworkMessages.COMPUTER_TERMINAL_CLIENT_MESSAGE;
}
public NBTTagCompound getTag()
{
return tag;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
super.toBytes( buf );
buf.writeCompoundTag( tag ); // TODO: Do we need to compress this?
}
@Override
public void fromBytes( @Nonnull PacketBuffer buf )
{
super.fromBytes( buf );
try
{
tag = buf.readCompoundTag();
}
catch( IOException e )
{
throw new UncheckedIOException( e );
}
}
}

View File

@ -0,0 +1,93 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.network.NetworkMessage;
import dan200.computercraft.shared.network.NetworkMessages;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nonnull;
/**
* Starts or stops a record on the client, depending on if {@link #getSoundEvent()} is {@code null}.
*
* Used by disk drives to play record items.
*
* @see dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive
*/
public class PlayRecordClientMessage implements NetworkMessage
{
private BlockPos pos;
private String name;
private SoundEvent soundEvent;
public PlayRecordClientMessage( BlockPos pos, SoundEvent event, String name )
{
this.pos = pos;
this.name = name;
this.soundEvent = event;
}
public PlayRecordClientMessage( BlockPos pos )
{
this.pos = pos;
}
public PlayRecordClientMessage()
{
}
@Override
public int getId()
{
return NetworkMessages.PLAY_RECORD_CLIENT_MESSAGE;
}
public BlockPos getPos()
{
return pos;
}
public String getName()
{
return name;
}
public SoundEvent getSoundEvent()
{
return soundEvent;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
buf.writeBlockPos( pos );
if( soundEvent == null )
{
buf.writeBoolean( false );
}
else
{
buf.writeBoolean( true );
buf.writeString( name );
buf.writeInt( SoundEvent.REGISTRY.getIDForObject( soundEvent ) );
}
}
@Override
public void fromBytes( @Nonnull PacketBuffer buf )
{
pos = buf.readBlockPos();
if( buf.readBoolean() )
{
name = buf.readString( Short.MAX_VALUE );
soundEvent = SoundEvent.REGISTRY.getObjectById( buf.readInt() );
}
}
}

View File

@ -0,0 +1,59 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.server;
import dan200.computercraft.shared.network.NetworkMessages;
import net.minecraft.network.PacketBuffer;
import javax.annotation.Nonnull;
public class ComputerActionServerMessage extends ComputerServerMessage
{
private Action action;
public ComputerActionServerMessage( int instanceId, Action action )
{
super( instanceId );
this.action = action;
}
public ComputerActionServerMessage()
{
}
@Override
public int getId()
{
return NetworkMessages.COMPUTER_ACTION_SERVER_MESSAGE;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
super.toBytes( buf );
buf.writeEnumValue( action );
}
@Override
public void fromBytes( @Nonnull PacketBuffer buf )
{
super.fromBytes( buf );
action = buf.readEnumValue( Action.class );
}
public Action getAction()
{
return action;
}
public enum Action
{
TURN_ON,
SHUTDOWN,
REBOOT
}
}

View File

@ -0,0 +1,71 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.server;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.network.NetworkMessage;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import javax.annotation.Nonnull;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
* A packet, which performs an action on a {@link ServerComputer}.
*
* This requires that the sending player is interacting with that computer via a
* {@link dan200.computercraft.shared.computer.core.IContainerComputer}.
*/
public abstract class ComputerServerMessage implements NetworkMessage
{
private int instanceId;
public ComputerServerMessage( int instanceId )
{
this.instanceId = instanceId;
}
public ComputerServerMessage()
{
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
buf.writeVarInt( instanceId );
}
@Override
public void fromBytes( @Nonnull PacketBuffer buf )
{
instanceId = buf.readVarInt();
}
public ServerComputer getComputer( MessageContext context )
{
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instanceId );
if( computer == null ) return null;
// Verify the player is interacting with a computer.
EntityPlayer player = context.getServerHandler().player;
if( player == null || !computer.isInteracting( player ) ) return null;
return computer;
}
public static <T extends ComputerServerMessage> void register( Supplier<T> factory, BiConsumer<ServerComputer, T> handler )
{
NetworkMessage.registerMainThread( Side.SERVER, factory, ( context, packet ) -> {
ServerComputer computer = packet.getComputer( context );
if( computer != null ) handler.accept( computer, packet );
} );
}
}

View File

@ -0,0 +1,83 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.server;
import dan200.computercraft.shared.network.NetworkMessages;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.UncheckedIOException;
/**
* Queue an event on a {@link dan200.computercraft.shared.computer.core.ServerComputer}.
*
* @see dan200.computercraft.shared.computer.core.ClientComputer#queueEvent(String)
* @see dan200.computercraft.shared.computer.core.ServerComputer#queueEvent(String)
*/
public class QueueEventServerMessage extends ComputerServerMessage
{
private String event;
private Object[] args;
public QueueEventServerMessage( int instanceId, @Nonnull String event, @Nullable Object[] args )
{
super( instanceId );
this.event = event;
this.args = args;
}
public QueueEventServerMessage()
{
}
@Override
public int getId()
{
return NetworkMessages.QUEUE_EVENT_SERVER_MESSAGE;
}
@Nonnull
public String getEvent()
{
return event;
}
@Nullable
public Object[] getArgs()
{
return args;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
super.toBytes( buf );
buf.writeString( event );
buf.writeCompoundTag( args == null ? null : NBTUtil.encodeObjects( args ) );
}
@Override
public void fromBytes( @Nonnull PacketBuffer buf )
{
super.fromBytes( buf );
event = buf.readString( Short.MAX_VALUE );
try
{
NBTTagCompound args = buf.readCompoundTag();
this.args = args == null ? null : NBTUtil.decodeObjects( args );
}
catch( IOException e )
{
throw new UncheckedIOException( e );
}
}
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.server;
import dan200.computercraft.shared.network.NetworkMessage;
import dan200.computercraft.shared.network.NetworkMessages;
import net.minecraft.network.PacketBuffer;
import javax.annotation.Nonnull;
public class RequestComputerMessage implements NetworkMessage
{
private int instance;
public RequestComputerMessage( int instance )
{
this.instance = instance;
}
public RequestComputerMessage()
{
}
@Override
public int getId()
{
return NetworkMessages.REQUEST_COMPUTER_SERVER_MESSAGE;
}
public int getInstance()
{
return instance;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
buf.writeVarInt( instance );
}
@Override
public void fromBytes( @Nonnull PacketBuffer buf )
{
instance = buf.readVarInt();
}
}

View File

@ -7,7 +7,6 @@
package dan200.computercraft.shared.peripheral.modem.wired;
import com.google.common.base.Objects;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;

View File

@ -6,7 +6,6 @@
package dan200.computercraft.shared.pocket.apis;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;

View File

@ -14,9 +14,9 @@ import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.shared.PocketUpgrades;
import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.computer.blocks.ComputerState;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.items.IComputerItem;
import dan200.computercraft.shared.pocket.apis.PocketAPI;
@ -454,11 +454,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
public ComputerState getState( @Nonnull ItemStack stack )
{
ClientComputer computer = getClientComputer( stack );
if( computer != null && computer.isOn() )
{
return computer.isCursorDisplayed() ? ComputerState.Blinking : ComputerState.On;
}
return ComputerState.Off;
return computer == null ? ComputerState.OFF : computer.getState();
}
@SideOnly( Side.CLIENT )

View File

@ -7,7 +7,6 @@
package dan200.computercraft.shared.pocket.recipes;
import com.google.gson.JsonObject;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.shared.PocketUpgrades;
import dan200.computercraft.shared.computer.core.ComputerFamily;

View File

@ -14,7 +14,6 @@ import dan200.computercraft.shared.PocketUpgrades;
import dan200.computercraft.shared.command.CommandComputerCraft;
import dan200.computercraft.shared.command.ContainerViewComputer;
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.computer.blocks.BlockCommandComputer;
import dan200.computercraft.shared.computer.blocks.BlockComputer;
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
@ -31,7 +30,12 @@ import dan200.computercraft.shared.media.items.ItemDiskExpanded;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.network.ComputerCraftPacket;
import dan200.computercraft.shared.network.NetworkMessage;
import dan200.computercraft.shared.network.client.*;
import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
import dan200.computercraft.shared.network.server.ComputerServerMessage;
import dan200.computercraft.shared.network.server.QueueEventServerMessage;
import dan200.computercraft.shared.network.server.RequestComputerMessage;
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheralProvider;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.DefaultPeripheralProvider;
@ -63,18 +67,15 @@ import net.minecraft.block.Block;
import net.minecraft.command.CommandHandler;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
import net.minecraft.inventory.Container;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumHand;
import net.minecraft.util.IThreadListener;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
@ -92,6 +93,7 @@ import net.minecraftforge.fml.common.network.FMLNetworkEvent;
import net.minecraftforge.fml.common.network.IGuiHandler;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.registries.IForgeRegistry;
import pl.asie.charset.ModCharset;
@ -111,6 +113,7 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
{
registerTileEntities();
registerForgeHandlers();
registerNetwork();
Fixes.register( FMLCommonHandler.instance().getDataFixer() );
if( Loader.isModLoaded( ModCharset.MODID ) ) IntegrationCharset.register();
@ -123,67 +126,6 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
handler.registerCommand( new CommandComputerCraft() );
}
@Override
public void handlePacket( final ComputerCraftPacket packet, final EntityPlayer player )
{
IThreadListener listener = player.getServer();
if( listener != null )
{
if( listener.isCallingFromMinecraftThread() )
{
processPacket( packet, player );
}
else
{
listener.addScheduledTask( () -> processPacket( packet, player ) );
}
}
}
private void processPacket( ComputerCraftPacket packet, EntityPlayer player )
{
switch( packet.m_packetType )
{
///////////////////////////////////
// Packets from Client to Server //
///////////////////////////////////
case ComputerCraftPacket.TurnOn:
case ComputerCraftPacket.Shutdown:
case ComputerCraftPacket.Reboot:
case ComputerCraftPacket.QueueEvent:
case ComputerCraftPacket.RequestComputerUpdate:
case ComputerCraftPacket.SetLabel:
{
int instance = packet.m_dataInt[0];
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance );
if( computer != null )
{
computer.handlePacket( packet, player );
}
break;
}
case ComputerCraftPacket.RequestTileEntityUpdate:
{
int x = packet.m_dataInt[0];
int y = packet.m_dataInt[1];
int z = packet.m_dataInt[2];
BlockPos pos = new BlockPos( x, y, z );
World world = player.getEntityWorld();
TileEntity tileEntity = world.getTileEntity( pos );
if( tileEntity != null && tileEntity instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tileEntity;
SPacketUpdateTileEntity description = generic.getUpdatePacket();
if( description != null )
{
((EntityPlayerMP) player).connection.sendPacket( description );
}
}
break;
}
}
}
@SubscribeEvent
public void registerBlocks( RegistryEvent.Register<Block> event )
{
@ -431,8 +373,53 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
NetworkRegistry.INSTANCE.registerGuiHandler( ComputerCraft.instance, handlers );
}
public class ForgeHandlers implements
IGuiHandler
private void registerNetwork()
{
// Server messages
ComputerServerMessage.register( ComputerActionServerMessage::new, ( computer, packet ) -> {
switch( packet.getAction() )
{
case TURN_ON:
computer.turnOn();
break;
case REBOOT:
computer.reboot();
break;
case SHUTDOWN:
computer.shutdown();
break;
}
} );
ComputerServerMessage.register( QueueEventServerMessage::new, ( computer, packet ) ->
computer.queueEvent( packet.getEvent(), packet.getArgs() ) );
NetworkMessage.registerMainThread( Side.SERVER, RequestComputerMessage::new, ( context, packet ) -> {
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( packet.getInstance() );
if( computer != null ) computer.sendComputerState( context.getServerHandler().player );
} );
// Client messages
NetworkMessage.registerMainThread( Side.CLIENT, PlayRecordClientMessage::new, ( computer, packet ) -> {
playRecordClient( packet.getPos(), packet.getSoundEvent(), packet.getName() );
} );
ComputerClientMessage.register( ComputerDataClientMessage::new, ( computer, packet ) ->
computer.setState( packet.getComputerId(), packet.getLabel(), packet.getState(), packet.getUserData() ) );
ComputerClientMessage.register( ComputerTerminalClientMessage::new, ( computer, packet ) ->
computer.readDescription( packet.getTag() ) );
NetworkMessage.registerMainThread( Side.CLIENT, ComputerDeletedClientMessage::new, ( context, packet ) ->
ComputerCraft.clientComputerRegistry.remove( packet.getInstanceId() ) );
NetworkMessage.registerMainThread( Side.CLIENT, ChatTableClientMessage::new, ( context, packet ) ->
showTableClient( packet.getTable() ) );
}
public class ForgeHandlers implements IGuiHandler
{
private ForgeHandlers()
{

View File

@ -6,10 +6,10 @@
package dan200.computercraft.shared.proxy;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.network.ComputerCraftPacket;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
@ -17,6 +17,8 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import java.io.File;
@ -45,5 +47,7 @@ public interface IComputerCraftProxy
File getWorldDir( World world );
void handlePacket( ComputerCraftPacket packet, EntityPlayer player );
void playRecordClient( BlockPos pos, SoundEvent record, String info );
void showTableClient( TableBuilder table );
}

View File

@ -7,7 +7,7 @@
package dan200.computercraft.shared.util;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.network.ComputerCraftPacket;
import dan200.computercraft.shared.network.client.PlayRecordClientMessage;
import net.minecraft.item.Item;
import net.minecraft.item.ItemRecord;
import net.minecraft.item.ItemStack;
@ -15,6 +15,7 @@ import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import javax.annotation.Nonnull;
@ -22,17 +23,7 @@ public class RecordUtil
{
public static void playRecord( SoundEvent record, String recordInfo, World world, BlockPos pos )
{
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.PlayRecord;
if( record != null )
{
packet.m_dataInt = new int[] { pos.getX(), pos.getY(), pos.getZ(), SoundEvent.REGISTRY.getIDForObject( record ) };
packet.m_dataString = new String[] { recordInfo };
}
else
{
packet.m_dataInt = new int[] { pos.getX(), pos.getY(), pos.getZ() };
}
IMessage packet = record != null ? new PlayRecordClientMessage( pos, record, recordInfo ) : new PlayRecordClientMessage( pos );
NetworkRegistry.TargetPoint point = new NetworkRegistry.TargetPoint( world.provider.getDimension(), pos.getX(), pos.getY(), pos.getZ(), 64 );
ComputerCraft.sendToAllAround( packet, point );