1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-15 14:07:38 +00:00

Compare commits

...

19 Commits

Author SHA1 Message Date
SquidDev
3ac8dde779 Bump version 2018-07-09 21:02:20 +01:00
SquidDev
17dace979a Merge pull request #562 from SquidDev-CC/ComputerCraft/hotfix/turtle-sign-place
Be a little smarter about our detection of the placed sign
2018-07-09 20:57:42 +01:00
SquidDev
d405316a4b Be a little smarter about our detection of the placed sign
When placing a sign against a tile entity (such as a turtle or chest),
we would consider that block the "placed" one instead, meaning the text
was never set. This solution isn't entirely ideal either, but short of
capturing block snapshots I'm not sure of a better solution.

Fixes #552
2018-07-09 20:53:49 +01:00
SquidDev
7e18f2cead Clear the turtle's inventory on load 2018-07-09 18:22:42 +01:00
SquidDev
000786a1a7 Merge pull request #560 from SquidDev-CC/ComputerCraft/hotfix/turtle-destroy
Rewrite turtle block destroying
2018-07-08 23:01:13 +01:00
SquidDev
0bf13562b9 Provide a more direct way to get the related computer
Effectively shift extracting the computer away from Plethora into CC:T.
Ideally we wouldn't need this at all, but Plethora does some funky
things with tick timings.

See SquidDev-CC/plethora#125
2018-07-08 22:48:50 +01:00
SquidDev
45a189e834 Cache a turtle's fake player
Player construction can get a little expensive, and this is exacerbated
by Sponge. We now cache a turtle's fake player (updating the position
every time it is requested) in order to reduce this overhead.
2018-07-08 15:21:42 +01:00
SquidDev
0ce6f34a09 Rewrite printout rendering
- The current page is always centred when rendering in a GUI, with
   the turned pages moving from the sides.
 - Pages are no longer evenly distributed from the centre - they follow
   an exponential decay curve, so ones further out are closer together
   (a bit like an open book).
 - Render pages and books in item frames/in-hand (rather than just
   single pages).

This currently does some very dirty things with z values in order to
prevent z-fighting. It would be nice to avoid that, though turning off
writing to the z buffer causes issues with the bounding box.
2018-07-07 19:59:20 +01:00
SquidDev
4d984dc5ee Rewrite turtle block destroying
- Try to make drop capturing a little more generic. This now allows for
   capturing a block's drop at a given position, as well as any drop
   within a bounding box (for things which don't play nicely).

 - Use as much of Minecraft's block breaking logic as possible,
   hopefully simplifying things and making it more consistent with other
   mods.
2018-07-06 18:49:15 +01:00
SquidDev
984d358930 Provide .getNameLocal on modems
This provides the local modem's name on the remote network. Let's be
honest, I'll probably end up renaming this soon.
2018-06-29 20:29:04 +01:00
SquidDev
a95893b823 Send the terminal state to the pocket computer's player
As we only send the terminal to players using the GUI, the map interface
was never updated. We now will also send the terminal state to whoever
has the computer in their inventory.

This also marks the terminal as dirty when a new player picks the pocket
computer up, hopefully preventing any desync issues which might occur
then.

Fixes #42.
2018-06-24 19:18:30 +01:00
SquidDev
81aaead032 Improve using /computercraft as a non-player
- Fix text table only showing the first row (fixes #40)
 - Do not emit alignment characters in monospace environments
 - Reduce padding in monospace environments

Also make the output of dump consistent with that of the profiler: we
provide tp and view shortcuts for each computer.
2018-06-22 08:28:36 +01:00
SquidDev
a2083bcff1 Merge pull request #554 from SquidDev-CC/ComputerCraft/hotfix/gui-blemishes
Fix a couple of minor blemishes in the GUI textures
2018-06-19 22:24:32 +01:00
SquidDev
052f2a16dc Fix a couple of minor blemishes in the GUI textures
- Slight airbrush effect for normal turtles. While this is only really
   visible when upping the contrast, it's probably nice to fix.
 - A few off-colour pixels for advanced turtles
2018-06-19 22:18:48 +01:00
SquidDev
fd10ed6f62 Merge pull request #553 from SquidDev-CC/ComputerCraft/feature/fancy-printout
Fancy rendering of printouts
2018-06-19 19:44:51 +01:00
SquidDev
c0bdd4ff1d Add basic support for fancy rendering of printouts
- When held in first-person, single pages are displayed like a map.
 - When placed in an item frame, the page is drawn instead of the actual
   item.
2018-06-18 22:09:24 +01:00
SquidDev
5f0addbc3e Fix variable being declared too late 2018-06-18 19:01:36 +01:00
SquidDev
c9589ad0e7 Allow using any kind of skull for crafting heads
It's possible to acquire any mob head in vanilla, so it's probably best
if we allow any head to be used.
2018-06-02 11:12:29 +01:00
SquidDev
b21c495815 Update the README to be a bit more detailed
- Include a list of features, pretty similar to that on the forum
   thread or CurseForge page.
 - Replace CC: Tweaked with CC:T. After all, who wants to type all of
   that?
2018-05-15 12:27:04 +01:00
38 changed files with 837 additions and 423 deletions

View File

@@ -6,26 +6,42 @@ features of the mod. For a more stable experience, I recommend checking out the
[original mod](https://github.com/dan200/ComputerCraft).
## What?
CC: Tweaked does not aim to create a competing fork of ComputerCraft, nor am I planning to take it in in a vastly
different direction to the original mod. In fact, CC: Tweaked aims to be a nurturing ground for various features, with
a pull request against the original mod being the end goal.
CC: Tweaked (or CC:T for short) does not aim to create a competing fork of ComputerCraft, nor am I planning to take it
in in a vastly different direction to the original mod. In fact, CC:T aims to be a nurturing ground for various
features, with a pull request against the original mod being the end goal.
CC: Tweaked also includes many pull requests from the community which have not yet been merged, offering a large number
CC:T also includes many pull requests from the community which have not yet been merged, offering a large number
of additional bug fixes and features over the original mod.
## Features
CC: Tweaked contains the all features of the latest alpha, as well as numerous fixes, performance improvements and
several additional features. I'd recommend checking out [the releases page](https://github.com/SquidDev-CC/CC-Tweaked/releases)
to see the full changes, but here's a couple of the more interesting changes:
- Replace LuaJ with Cobalt.
- Allow running multiple computers at the same time.
- Websocket support in the HTTP library.
- Wired modems and cables act more like multiparts.
- Add map-like rendering for pocket computers and printed pages/books.
- Adds the `/computercraft` command, offering various diagnostic tools for server owners. This allows operators to
track which computers are hogging resources, turn on and shutdown multiple computers at once and interact with
computers remotely.
- Add full-block wired modems, allowing one to wrap non-solid peripherals (such as turtles, or chests if Plethora is
installed).
## Relation to CCTweaks?
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. However, I do plan
to migrate some features of CCTweaks into CC: Tweaked.
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. That being said,
several features have been included, such as full block modems, the Cobalt runtime and map-like rendering for pocket
computers.
## Contributing
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you do wish to contribute
code, do consider submitting it to the ComputerCraft repository instead.
That being said, in order to start helping develop CC: Tweaked, you'll need to follow these steps:
That being said, in order to start helping develop CC:T, you'll need to follow these steps:
- **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked`
- **Setup Forge:** `./gradlew setupDecompWorkspace`
- **Test your changes:** `./gradlew runClient` (or run the `GradleStart` class from your IDE).
If you want to run CC: Tweaked in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from
`build/libs`.
If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`.

View File

@@ -23,7 +23,7 @@ apply plugin: 'org.ajoberstar.grgit'
apply plugin: 'maven-publish'
apply plugin: 'maven'
version = "1.80pr1.6"
version = "1.80pr1.7"
group = "org.squiddev"
archivesBaseName = "cc-tweaked"

View File

@@ -98,6 +98,7 @@ import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -1124,13 +1125,18 @@ public class ComputerCraft
turtleProxy.addAllUpgradedTurtles( list );
}
public static void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer )
public static void setDropConsumer( Entity entity, Consumer<ItemStack> consumer )
{
turtleProxy.setEntityDropConsumer( entity, consumer );
turtleProxy.setDropConsumer( entity, consumer );
}
public static void clearEntityDropConsumer( Entity entity )
public static void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer )
{
turtleProxy.clearEntityDropConsumer( entity );
turtleProxy.setDropConsumer( world, pos, consumer );
}
public static void clearDropConsumer( )
{
turtleProxy.clearDropConsumer();
}
}

View File

@@ -6,25 +6,19 @@
package dan200.computercraft.client.gui;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Mouse;
import java.io.IOException;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
public class GuiPrintout extends GuiContainer
{
private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/printout.png" );
private static final int xSize = 172;
private static final int ySize = 209;
private final boolean m_book;
private final int m_pages;
private final TextBuffer[] m_text;
@@ -34,23 +28,18 @@ public class GuiPrintout extends GuiContainer
public GuiPrintout( ContainerHeldItem container )
{
super( container );
m_book = (ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book);
String[] text = ItemPrintout.getText( container.getStack() );
m_text = new TextBuffer[ text.length ];
for( int i=0; i<m_text.length; ++i )
{
m_text[i] = new TextBuffer( text[i] );
}
for( int i = 0; i < m_text.length; ++i ) m_text[ i ] = new TextBuffer( text[ i ] );
String[] colours = ItemPrintout.getColours( container.getStack() );
m_colours = new TextBuffer[ colours.length ];
for( int i=0; i<m_colours.length; ++i )
{
m_colours[i] = new TextBuffer( colours[i] );
}
for( int i = 0; i < m_colours.length; ++i ) m_colours[ i ] = new TextBuffer( colours[ i ] );
m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 );
m_page = 0;
m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 );
m_book = ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book;
}
@Override
@@ -78,25 +67,19 @@ public class GuiPrintout extends GuiContainer
}
@Override
protected void keyTyped(char c, int k) throws IOException
protected void keyTyped( char c, int k ) throws IOException
{
super.keyTyped( c, k );
if( k == 205 )
{
// Right
if( m_page < m_pages - 1 )
{
m_page = m_page + 1;
}
if( m_page < m_pages - 1 ) m_page++;
}
else if( k == 203 )
{
// Left
if( m_page > 0 )
{
m_page = m_page - 1;
}
// Left
if( m_page > 0 ) m_page--;
}
}
@@ -106,21 +89,15 @@ public class GuiPrintout extends GuiContainer
super.handleMouseInput();
int mouseWheelChange = Mouse.getEventDWheel();
if (mouseWheelChange < 0)
if( mouseWheelChange < 0 )
{
// Up
if( m_page < m_pages - 1 )
{
m_page = m_page + 1;
}
if( m_page < m_pages - 1 ) m_page++;
}
else if (mouseWheelChange > 0)
else if( mouseWheelChange > 0 )
{
// Down
if( m_page > 0 )
{
m_page = m_page - 1;
}
if( m_page > 0 ) m_page--;
}
}
@@ -135,78 +112,20 @@ public class GuiPrintout extends GuiContainer
}
@Override
public void drawScreen(int mouseX, int mouseY, float f)
public void drawScreen( int mouseX, int mouseY, float f )
{
// Draw background
zLevel = zLevel - 1;
drawDefaultBackground();
zLevel = zLevel + 1;
// Draw the printout
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
this.mc.getTextureManager().bindTexture( background );
int startY = (height - ySize) / 2;
//int startX = (width - xSize) / 2 - (m_page * 8);
int startX = (width - (xSize + (m_pages - 1)*8)) / 2;
if( m_book )
{
// Border
drawTexturedModalRect( startX - 8, startY - 8, xSize + 48, 0, 12, ySize + 24);
drawTexturedModalRect( startX + xSize + (m_pages - 1)*8 - 4, startY - 8, xSize + 48 + 12, 0, 12, ySize + 24);
drawTexturedModalRect( startX, startY - 8, 0, ySize, xSize, 12);
drawTexturedModalRect( startX, startY + ySize - 4, 0, ySize + 12, xSize, 12);
for( int n=1; n<m_pages; ++n )
{
drawTexturedModalRect( startX + xSize + (n-1)*8, startY - 8, 0, ySize, 8, 12);
drawTexturedModalRect( startX + xSize + (n-1)*8, startY + ySize - 4, 0, ySize + 12, 8, 12);
}
}
// Left half
if( m_page == 0 )
{
drawTexturedModalRect( startX, startY, 24, 0, xSize / 2, ySize);
drawTexturedModalRect( startX, startY, 0, 0, 12, ySize);
}
else
{
drawTexturedModalRect( startX, startY, 0, 0, 12, ySize);
for( int n=1; n<m_page; ++n )
{
drawTexturedModalRect( startX + n*8, startY, 12, 0, 12, ySize);
}
drawTexturedModalRect( startX + m_page*8, startY, 24, 0, xSize / 2, ySize);
}
// Right half
if( m_page == (m_pages - 1) )
{
drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize);
drawTexturedModalRect( startX + m_page*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize);
}
else
{
drawTexturedModalRect( startX + (m_pages - 1)*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize);
for( int n=m_pages-2; n>=m_page; --n )
{
drawTexturedModalRect( startX + n*8 + (xSize - 12), startY, 24 + xSize, 0, 12, ySize);
}
drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize);
}
// Draw the text
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer)ComputerCraft.getFixedWidthFontRenderer();
int x = startX + m_page * 8 + 13;
int y = startY + 11;
for( int line=0; line<ItemPrintout.LINES_PER_PAGE; ++line )
{
int lineIdx = ItemPrintout.LINES_PER_PAGE * m_page + line;
if( lineIdx >= 0 && lineIdx < m_text.length )
{
fontRenderer.drawString( m_text[lineIdx], x, y, m_colours[lineIdx], null, 0, 0, false, Palette.DEFAULT );
}
y = y + FixedWidthFontRenderer.FONT_HEIGHT;
}
int startY = (height - Y_SIZE) / 2;
int startX = (width - X_SIZE) / 2;
drawBorder( startX, startY, zLevel, m_page, m_pages, m_book );
drawText( startX + X_TEXT_MARGIN, startY + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours );
}
}

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.client.proxy;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.render.ItemPocketRenderer;
import dan200.computercraft.client.render.ItemPrintoutRenderer;
import dan200.computercraft.client.render.RenderOverlayCable;
import dan200.computercraft.client.render.TileEntityCableRenderer;
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
@@ -497,6 +498,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
MinecraftForge.EVENT_BUS.register( handlers );
MinecraftForge.EVENT_BUS.register( new RenderOverlayCable() );
MinecraftForge.EVENT_BUS.register( new ItemPocketRenderer() );
MinecraftForge.EVENT_BUS.register( new ItemPrintoutRenderer() );
}
public class ForgeHandlers

View File

@@ -0,0 +1,197 @@
package dan200.computercraft.client.render;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.ItemRenderer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumHandSide;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.client.event.RenderItemInFrameEvent;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH;
public class ItemPrintoutRenderer
{
@SubscribeEvent
public void onRenderInHand( RenderSpecificHandEvent event )
{
ItemStack stack = event.getItemStack();
if( stack.getItem() != ComputerCraft.Items.printout ) return;
event.setCanceled( true );
EntityPlayer player = Minecraft.getMinecraft().player;
GlStateManager.pushMatrix();
if( event.getHand() == EnumHand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() )
{
renderPrintoutFirstPersonCentre(
event.getInterpolatedPitch(),
event.getEquipProgress(),
event.getSwingProgress(),
stack
);
}
else
{
renderPrintoutFirstPersonSide(
event.getHand() == EnumHand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(),
event.getEquipProgress(),
event.getSwingProgress(),
stack
);
}
GlStateManager.popMatrix();
}
/**
* Renders a pocket computer to one side of the player.
*
* @param side The side to render on
* @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item
* @param stack The stack to render
* @see ItemRenderer#renderMapFirstPersonSide(float, EnumHandSide, float, ItemStack)
*/
private void renderPrintoutFirstPersonSide( EnumHandSide side, float equipProgress, float swingProgress, ItemStack stack )
{
Minecraft minecraft = Minecraft.getMinecraft();
float offset = side == EnumHandSide.RIGHT ? 1f : -1f;
GlStateManager.translate( offset * 0.125f, -0.125f, 0f );
// If the player is not invisible then render a single arm
if( !minecraft.player.isInvisible() )
{
GlStateManager.pushMatrix();
GlStateManager.rotate( offset * 10f, 0f, 0f, 1f );
minecraft.getItemRenderer().renderArmFirstPerson( equipProgress, swingProgress, side );
GlStateManager.popMatrix();
}
// Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer.
GlStateManager.pushMatrix();
GlStateManager.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
float f1 = MathHelper.sqrt( swingProgress );
float f2 = MathHelper.sin( f1 * (float) Math.PI );
float f3 = -0.5f * f2;
float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) );
float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI );
GlStateManager.translate( offset * f3, f4 - 0.3f * f2, f5 );
GlStateManager.rotate( f2 * -45f, 1f, 0f, 0f );
GlStateManager.rotate( offset * f2 * -30f, 0f, 1f, 0f );
renderPrintoutFirstPerson( stack );
GlStateManager.popMatrix();
}
/**
* Render an item in the middle of the screen
*
* @param pitch The pitch of the player
* @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item
* @param stack The stack to render
* @see ItemRenderer#renderMapFirstPerson(float, float, float)
*/
private void renderPrintoutFirstPersonCentre( float pitch, float equipProgress, float swingProgress, ItemStack stack )
{
ItemRenderer itemRenderer = Minecraft.getMinecraft().getItemRenderer();
// Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer.
float swingRt = MathHelper.sqrt( swingProgress );
float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI );
float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI );
GlStateManager.translate( 0f, -tX / 2f, tZ );
float pitchAngle = itemRenderer.getMapAngleFromPitch( pitch );
GlStateManager.translate( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
GlStateManager.rotate( pitchAngle * -85f, 1f, 0f, 0f );
itemRenderer.renderArms();
float rX = MathHelper.sin( swingRt * (float) Math.PI );
GlStateManager.rotate( rX * 20f, 1f, 0f, 0f );
GlStateManager.scale( 2f, 2f, 2f );
renderPrintoutFirstPerson( stack );
}
private static void renderPrintoutFirstPerson( ItemStack stack )
{
// Setup various transformations. Note that these are partially adapated from the corresponding method
// in ItemRenderer.renderMapFirstPerson
GlStateManager.disableLighting();
GlStateManager.rotate( 180f, 0f, 1f, 0f );
GlStateManager.rotate( 180f, 0f, 0f, 1f );
GlStateManager.scale( 0.42f, 0.42f, -0.42f );
GlStateManager.translate( -0.5f, -0.48f, 0.0f );
drawPrintout( stack );
GlStateManager.enableLighting();
}
@SubscribeEvent
public void onRenderInFrame( RenderItemInFrameEvent event )
{
ItemStack stack = event.getItem();
if( stack.getItem() != ComputerCraft.Items.printout ) return;
event.setCanceled( true );
GlStateManager.disableLighting();
// Move a little bit forward to ensure we're not clipping with the frame
GlStateManager.translate( 0.0f, 0.0f, -0.001f );
GlStateManager.rotate( 180f, 0f, 0f, 1f );
GlStateManager.scale( 0.95f, 0.95f, -0.95f );
GlStateManager.translate( -0.5f, -0.5f, 0.0f );
drawPrintout( stack );
GlStateManager.enableLighting();
}
private static void drawPrintout( ItemStack stack )
{
int pages = ItemPrintout.getPageCount( stack );
boolean book = ItemPrintout.getType( stack ) == ItemPrintout.Type.Book;
double width = LINE_MAX_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2;
double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2;
// Non-books will be left aligned
if( !book ) width += offsetAt( pages );
double visualWidth = width, visualHeight = height;
// Meanwhile books will be centred
if( book )
{
visualWidth += 2 * COVER_SIZE + 2 * offsetAt( pages );
visualHeight += 2 * COVER_SIZE;
}
double max = Math.max( visualHeight, visualWidth );
// Scale the printout to fit correctly.
double scale = 1.0 / max;
GlStateManager.scale( scale, scale, scale );
GlStateManager.translate( (max - width) / 2.0f, (max - height) / 2.0f, 0.0f );
drawBorder( 0, 0, -0.01, 0, pages, book );
drawText( X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) );
}
}

View File

@@ -0,0 +1,162 @@
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;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
public class PrintoutRenderer
{
private static final ResourceLocation BG = new ResourceLocation( "computercraft", "textures/gui/printout.png" );
private static final double BG_SIZE = 256.0;
/**
* Width of a page
*/
public static final int X_SIZE = 172;
/**
* Height of a page
*/
public static final int Y_SIZE = 209;
/**
* Padding between the left and right of a page and the text
*/
public static final int X_TEXT_MARGIN = 13;
/**
* Padding between the top and bottom of a page and the text
*/
public static final int Y_TEXT_MARGIN = 11;
/**
* Width of the extra page texture
*/
private static final int X_FOLD_SIZE = 12;
/**
* Size of the leather cover
*/
public static final int COVER_SIZE = 12;
private static final int COVER_Y = Y_SIZE;
private static final int COVER_X = X_SIZE + 4 * X_FOLD_SIZE;
public static void drawText( int x, int y, int start, TextBuffer[] text, TextBuffer[] colours )
{
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer();
for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line )
{
fontRenderer.drawString( text[ start + line ], x, y + line * FONT_HEIGHT, colours[ start + line ], null, 0, 0, false, Palette.DEFAULT );
}
}
public static void drawText( int x, int y, int start, String[] text, String[] colours )
{
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer();
for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line )
{
fontRenderer.drawString( new TextBuffer( text[ start + line ] ), x, y + line * FONT_HEIGHT, new TextBuffer( colours[ start + line ] ), null, 0, 0, false, Palette.DEFAULT );
}
}
public static void drawBorder( double x, double y, double z, int page, int pages, boolean isBook )
{
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
Minecraft.getMinecraft().getTextureManager().bindTexture( BG );
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX );
int leftPages = page;
int rightPages = pages - page - 1;
if( isBook )
{
// Border
double offset = offsetAt( pages );
final double left = x - 4 - offset;
final double right = x + X_SIZE + offset - 4;
// Left and right border
drawTexture( buffer, left - 4, y - 8, z - 0.02, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 );
drawTexture( buffer, right, y - 8, z - 0.02, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 );
// Draw centre panel (just stretched texture, sorry).
drawTexture( buffer,
x - offset, y, z - 0.02, X_SIZE + offset * 2, Y_SIZE,
COVER_X + COVER_SIZE / 2, COVER_SIZE, COVER_SIZE, Y_SIZE
);
double borderX = left;
while( borderX < right )
{
double thisWidth = Math.min( right - borderX, X_SIZE );
drawTexture( buffer, borderX, y - 8, z - 0.02, 0, COVER_Y, thisWidth, COVER_SIZE );
drawTexture( buffer, borderX, y + Y_SIZE - 4, z - 0.02, 0, COVER_Y + COVER_SIZE, thisWidth, COVER_SIZE );
borderX += thisWidth;
}
}
// Left half
drawTexture( buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2, Y_SIZE );
for( int n = 0; n <= leftPages; n++ )
{
drawTexture( buffer,
x - offsetAt( n ), y, z - 1e-3 * n,
// Use the left "bold" fold for the outermost page
n == leftPages ? 0 : X_FOLD_SIZE, 0,
X_FOLD_SIZE, Y_SIZE
);
}
// Right half
drawTexture( buffer, x + X_SIZE / 2, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2, 0, X_SIZE / 2, Y_SIZE );
for( int n = 0; n <= rightPages; n++ )
{
drawTexture( buffer,
x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3 * n,
// Two folds, then the main page. Use the right "bold" fold for the outermost page.
X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0,
X_FOLD_SIZE, Y_SIZE
);
}
tessellator.draw();
}
private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double u, double v, double width, double height )
{
buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
buffer.pos( x + width, y + height, z ).tex( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
buffer.pos( x + width, y, z ).tex( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex();
buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex();
}
private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double width, double height, double u, double v, double tWidth, double tHeight )
{
buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
buffer.pos( x + width, y + height, z ).tex( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
buffer.pos( x + width, y, z ).tex( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex();
buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex();
}
public static double offsetAt( int page )
{
return 32 * (1 - Math.pow( 1.2, -page ));
}
}

View File

@@ -3,14 +3,17 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.IComputerOwned;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.filesystem.FileSystemException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.Set;
public abstract class ComputerAccess implements IComputerAccess
public abstract class ComputerAccess implements IComputerAccess, IComputerOwned
{
private final IAPIEnvironment m_environment;
private final Set<String> m_mounts = new HashSet<>();
@@ -133,6 +136,13 @@ public abstract class ComputerAccess implements IComputerAccess
m_environment.queueEvent( event, arguments );
}
@Nullable
@Override
public Computer getComputer()
{
return m_environment.getComputer();
}
private String findFreeLocation( String desiredLoc )
{
try

View File

@@ -9,17 +9,19 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.core.computer.IComputerOwned;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.tracking.TrackingField;
public interface IAPIEnvironment
public interface IAPIEnvironment extends IComputerOwned
{
interface IPeripheralChangeListener
{
void onPeripheralChanged( int side, IPeripheral newPeripheral );
}
@Override
Computer getComputer();
int getComputerID();
IComputerEnvironment getComputerEnvironment();

View File

@@ -0,0 +1,9 @@
package dan200.computercraft.core.computer;
import javax.annotation.Nullable;
public interface IComputerOwned
{
@Nullable
Computer getComputer();
}

View File

@@ -20,7 +20,6 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer;
import javax.annotation.Nonnull;
import java.util.*;
@@ -59,7 +58,7 @@ public final class CommandComputerCraft extends CommandDelegate
{
if( arguments.size() == 0 )
{
TextTable table = new TextTable( DUMP_LIST_ID, "Instance", "Id", "On", "Position" );
TextTable table = new TextTable( DUMP_LIST_ID, "Computer", "On", "Position" );
List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
@@ -92,8 +91,7 @@ public final class CommandComputerCraft extends CommandDelegate
for( ServerComputer computer : computers )
{
table.addRow(
linkComputer( computer ),
text( Integer.toString( computer.getID() ) ),
linkComputer( context, computer, computer.getID() ),
bool( computer.isOn() ),
linkPosition( context, computer )
);
@@ -406,13 +404,46 @@ public final class CommandComputerCraft extends CommandDelegate
return root;
}
private static ITextComponent linkComputer( ServerComputer computer )
private static ITextComponent linkComputer( CommandContext context, ServerComputer serverComputer, int computerId )
{
return link(
text( Integer.toString( computer.getInstanceID() ) ),
"/computercraft dump " + computer.getInstanceID(),
"View more info about this computer"
);
ITextComponent out = new TextComponentString( "" );
// Append the computer instance
if( serverComputer == null )
{
out.appendSibling( text( "?" ) );
}
else
{
out.appendSibling( link(
text( Integer.toString( serverComputer.getInstanceID() ) ),
"/computercraft dump " + serverComputer.getInstanceID(),
"View more info about this computer"
) );
}
// And ID
out.appendText( " (id " + computerId + ")" );
// And, if we're a player, some useful links
if( serverComputer != null && UserLevel.OP.canExecute( context ) && context.fromPlayer() )
{
out
.appendText( " " )
.appendSibling( link(
text( "\u261b" ),
"/computercraft tp " + serverComputer.getInstanceID(),
"Teleport to this computer"
) )
.appendText( " " )
.appendSibling( link(
text( "\u20e2" ),
"/computercraft view " + serverComputer.getInstanceID(),
"View this computer"
) );
}
return out;
}
private static ITextComponent linkPosition( CommandContext context, ServerComputer computer )
@@ -459,7 +490,6 @@ public final class CommandComputerCraft extends CommandDelegate
}
ICommandSender sender = context.getSender();
boolean isPlayer = sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
timings.sort( Comparator.<ComputerTracker, Long>comparing( x -> x.get( field ) ).reversed() );
@@ -476,26 +506,7 @@ public final class CommandComputerCraft extends CommandDelegate
Computer computer = entry.getComputer();
ServerComputer serverComputer = computer == null ? null : lookup.get( computer );
ITextComponent computerComponent = new TextComponentString( "" )
.appendSibling( serverComputer == null ? text( "?" ) : linkComputer( serverComputer ) )
.appendText( " (id " + entry.getComputerId() + ")" );
if( serverComputer != null && UserLevel.OP.canExecute( context ) && isPlayer )
{
computerComponent
.appendText( " " )
.appendSibling( link(
text( "\u261b" ),
"/computercraft tp " + serverComputer.getInstanceID(),
"Teleport to this computer"
) )
.appendText( " " )
.appendSibling( link(
text( "\u20e2" ),
"/computercraft view " + serverComputer.getInstanceID(),
"View this computer"
) );
}
ITextComponent computerComponent = linkComputer( context, serverComputer, entry.getComputerId() );
if( defaultLayout )
{

View File

@@ -46,7 +46,7 @@ public final class ComputerSelector
for( int i = 0; i < computers.size(); i++ )
{
if( i > 1 ) builder.append( ", " );
if( i > 0 ) builder.append( ", " );
builder.append( computers.get( i ).getInstanceID() );
}
builder.append( ")" );

View File

@@ -2,7 +2,9 @@ package dan200.computercraft.shared.command.framework;
import com.google.common.collect.Lists;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.common.util.FakePlayer;
import java.util.Collections;
import java.util.List;
@@ -90,4 +92,9 @@ public final class CommandContext
{
return sender;
}
public boolean fromPlayer()
{
return sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
}
}

View File

@@ -17,7 +17,6 @@ import static dan200.computercraft.shared.command.framework.ChatHelpers.coloured
*/
public class TextFormatter
{
private static final int SPACE_WIDTH = 4;
private static final char PADDING_CHAR = '\u02cc';
/**
@@ -54,7 +53,7 @@ public class TextFormatter
8, 4,
};
private static int getWidth( int codePoint )
public static int getWidth( int codePoint )
{
// Escape codes
if( codePoint == 167 ) return -1;
@@ -73,7 +72,7 @@ public class TextFormatter
return 0;
}
private static int getWidth( ITextComponent component )
public static int getWidth( ITextComponent component )
{
int total = 0;
if( component instanceof TextComponentString )
@@ -132,19 +131,17 @@ public class TextFormatter
int width = getWidthFor( entry, sender );
int delta = maxWidth - width;
if( delta > 0 )
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 )
{
int spaces = delta / SPACE_WIDTH;
int extra = delta % SPACE_WIDTH;
// 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 ) );
}
out.appendSibling( coloured( StringUtils.repeat( PADDING_CHAR, extra ), TextFormatting.GRAY ) );
}
}
}

View File

@@ -35,7 +35,7 @@ public class TextTable
this.columns = header.length;
}
public TextTable(int id)
public TextTable( int id )
{
this.id = id;
this.header = null;
@@ -90,14 +90,15 @@ public class TextTable
ITextComponent[] row = rows.get( y );
for( int i = 0; i < row.length; i++ )
{
int width = getWidthFor( row[i], sender ) + 3;
int width = getWidthFor( row[i], sender );
if( width > maxWidths[i] ) maxWidths[i] = width;
}
}
// Add a small amount of extra padding. We include this here instead of the separator to allow
// for "extra" characters
for( int i = 0; i < maxWidths.length; i++ ) maxWidths[i] += 4;
// 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;
@@ -161,7 +162,7 @@ public class TextTable
for( int i = 0; i < out.size(); i++ )
{
if( i > 0 ) result.appendSibling( LINE );
result.appendSibling( out.get( 0 ) );
result.appendSibling( out.get( i ) );
}
sender.sendMessage( result );
}

View File

@@ -54,6 +54,11 @@ public class ServerTerminal implements ITerminal
}
}
protected void markTerminalChanged()
{
m_terminalChanged = true;
}
public void update()
{
m_terminalChangedLastFrame = m_terminalChanged || (m_terminal != null && m_terminal.getChanged());

View File

@@ -154,7 +154,7 @@ public class ServerComputer extends ServerTerminal
return packet;
}
private ComputerCraftPacket createTerminalPacket() {
protected ComputerCraftPacket createTerminalPacket() {
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.ComputerTerminalChanged;
packet.m_dataInt = new int[] { getInstanceID() };
@@ -465,7 +465,7 @@ public class ServerComputer extends ServerTerminal
}
}
private boolean isInteracting( EntityPlayer player )
protected boolean isInteracting( EntityPlayer player )
{
if( player == null ) return false;

View File

@@ -108,10 +108,11 @@ public class TileCable extends TileModemBase
m_node = m_cable.getNode();
return new WiredModemPeripheral( m_cable )
{
@Nonnull
@Override
protected boolean canSeePeripheral( @Nonnull String peripheralName )
protected WiredModemLocalPeripheral getLocalPeripheral()
{
return !peripheralName.equals( m_peripheral.getConnectedName() );
return m_peripheral;
}
@Nonnull

View File

@@ -401,12 +401,14 @@ public class TileWiredModemFull extends TilePeripheralBase
WiredModemPeripheral peripheral = m_modems[side.ordinal()];
if( peripheral == null )
{
WiredModemLocalPeripheral localPeripheral = m_peripherals[side.ordinal()];
peripheral = m_modems[side.ordinal()] = new WiredModemPeripheral( m_element )
{
@Nonnull
@Override
protected boolean canSeePeripheral( @Nonnull String peripheralName )
protected WiredModemLocalPeripheral getLocalPeripheral()
{
return !peripheralName.equals( m_peripherals[side.ordinal()].getConnectedName() );
return localPeripheral;
}
@Nonnull

View File

@@ -10,6 +10,8 @@ import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.network.wired.IWiredSender;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.IComputerOwned;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
@@ -56,7 +58,8 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
return modem.getWorld();
}
protected abstract boolean canSeePeripheral( @Nonnull String peripheralName );
@Nonnull
protected abstract WiredModemLocalPeripheral getLocalPeripheral();
//endregion
//region IPeripheral
@@ -65,13 +68,14 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
public String[] getMethodNames()
{
String[] methods = super.getMethodNames();
String[] newMethods = new String[methods.length + 5];
String[] newMethods = new String[methods.length + 6];
System.arraycopy( methods, 0, newMethods, 0, methods.length );
newMethods[methods.length] = "getNamesRemote";
newMethods[methods.length + 1] = "isPresentRemote";
newMethods[methods.length + 2] = "getTypeRemote";
newMethods[methods.length + 3] = "getMethodsRemote";
newMethods[methods.length + 4] = "callRemote";
newMethods[methods.length + 5] = "getNameLocal";
return newMethods;
}
@@ -135,6 +139,12 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
System.arraycopy( arguments, 2, methodArgs, 0, arguments.length - 2 );
return callMethodRemote( remoteName, context, methodName, methodArgs );
}
case 5:
{
// getNameLocal
String local = getLocalPeripheral().getConnectedName();
return local == null ? null : new Object[]{ local };
}
default:
{
// The regular modem methods
@@ -217,7 +227,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
private void attachPeripheralImpl( String periphName, IPeripheral peripheral )
{
if( !peripheralWrappers.containsKey( periphName ) && canSeePeripheral( periphName ) )
if( !peripheralWrappers.containsKey( periphName ) && !periphName.equals( getLocalPeripheral().getConnectedName() ) )
{
RemotePeripheralWrapper wrapper = new RemotePeripheralWrapper( modem, peripheral, getComputer(), periphName );
peripheralWrappers.put( periphName, wrapper );
@@ -265,7 +275,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
throw new LuaException( "No peripheral: " + remoteName );
}
private static class RemotePeripheralWrapper implements IComputerAccess
private static class RemotePeripheralWrapper implements IComputerAccess, IComputerOwned
{
private final WiredModemElement m_element;
private final IPeripheral m_peripheral;
@@ -400,5 +410,12 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
return m_element.getRemotePeripherals().get( name );
}
}
@Nullable
@Override
public Computer getComputer()
{
return m_computer instanceof IComputerOwned ? ((IComputerOwned) m_computer).getComputer() : null;
}
}
}

View File

@@ -8,6 +8,7 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -138,7 +139,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
{
if( this.m_upgrade == upgrade ) return;
synchronized (this)
synchronized( this )
{
ComputerCraft.Items.pocketComputer.setUpgrade( m_stack, upgrade );
if( m_entity instanceof EntityPlayer ) ((EntityPlayer) m_entity).inventory.markDirty();
@@ -156,6 +157,9 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
setPosition( entity.getPosition() );
}
// If a new entity has picked it up then rebroadcast the terminal to them
if( entity != m_entity && entity instanceof EntityPlayerMP ) markTerminalChanged();
m_entity = entity;
m_stack = stack;
@@ -165,4 +169,19 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
invalidatePeripheral();
}
}
public void broadcastState( boolean force )
{
super.broadcastState( force );
if( (hasTerminalChanged() || force) && m_entity instanceof EntityPlayerMP )
{
// Broadcast the state to the current entity if they're not already interacting with it.
EntityPlayerMP player = (EntityPlayerMP) m_entity;
if( player.connection != null && !isInteracting( player ) )
{
ComputerCraft.sendToPlayer( player, createTerminalPacket() );
}
}
}
}

View File

@@ -21,7 +21,6 @@ import dan200.computercraft.shared.turtle.items.ItemTurtleNormal;
import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
import dan200.computercraft.shared.turtle.upgrades.*;
import dan200.computercraft.shared.util.IEntityDropConsumer;
import dan200.computercraft.shared.util.ImpostorRecipe;
import dan200.computercraft.shared.util.InventoryUtil;
import net.minecraft.block.Block;
@@ -33,33 +32,47 @@ import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.EntityRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.registries.IForgeRegistry;
import javax.annotation.Nonnull;
import java.util.*;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
{
{
private Map<Integer, ITurtleUpgrade> m_legacyTurtleUpgrades;
private Map<String, ITurtleUpgrade> m_turtleUpgrades;
private Map<Entity, IEntityDropConsumer> m_dropConsumers;
private Consumer<ItemStack> dropConsumer;
private WeakReference<World> dropWorld;
private BlockPos dropPos;
private AxisAlignedBB dropBounds;
private WeakReference<Entity> dropEntity;
public CCTurtleProxyCommon()
{
m_legacyTurtleUpgrades = new HashMap<>();
m_turtleUpgrades = new HashMap<>();
m_dropConsumers = new WeakHashMap<>();
}
// ICCTurtleProxy implementation
@Override
@Override
public void preInit()
{
MinecraftForge.EVENT_BUS.register( this );
@@ -75,8 +88,8 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
// RecipeSorter.register( "computercraft:turtle", TurtleRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" );
// RecipeSorter.register( "computercraft:turtle_upgrade", TurtleUpgradeRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" );
}
@Override
@Override
public void init()
{
registerForgeHandlers();
@@ -94,7 +107,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
ComputerCraft.log.error( message );
throw new RuntimeException( message );
}
// Register
registerTurtleUpgradeInternal( upgrade );
}
@@ -110,7 +123,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
{
return m_legacyTurtleUpgrades.get( legacyId );
}
@Override
public ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack stack )
{
@@ -126,7 +139,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
}
catch( Exception e )
{
ComputerCraft.log.error("Error getting computer upgrade item", e);
ComputerCraft.log.error( "Error getting computer upgrade item", e );
}
}
return null;
@@ -148,7 +161,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
return true;
}
}
private void addAllUpgradedTurtles( ComputerFamily family, NonNullList<ItemStack> list )
{
ItemStack basicStack = TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null );
@@ -169,7 +182,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
private void addUpgradedTurtle( ComputerFamily family, ITurtleUpgrade upgrade, List<ItemStack> list )
{
if ( isUpgradeSuitableForFamily( family, upgrade ) )
if( isUpgradeSuitableForFamily( family, upgrade ) )
{
ItemStack stack = TurtleItemFactory.create( -1, null, -1, family, upgrade, null, 0, null );
if( !stack.isEmpty() )
@@ -178,54 +191,58 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
}
}
}
@Override
public void addAllUpgradedTurtles( NonNullList<ItemStack> list )
{
addAllUpgradedTurtles( ComputerFamily.Normal, list );
addAllUpgradedTurtles( ComputerFamily.Advanced, list );
}
@Override
public void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer )
public void setDropConsumer( Entity entity, Consumer<ItemStack> consumer )
{
if( !m_dropConsumers.containsKey( entity ) )
{
boolean captured = entity.captureDrops;
if( !captured )
{
entity.captureDrops = true;
ArrayList<EntityItem> items = entity.capturedDrops;
if( items == null || items.size() == 0 )
{
m_dropConsumers.put( entity, consumer );
}
}
}
}
dropConsumer = consumer;
dropEntity = new WeakReference<>( entity );
dropWorld = new WeakReference<>( entity.world );
dropPos = null;
dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 );
entity.captureDrops = true;
}
@Override
public void clearEntityDropConsumer( Entity entity )
public void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer )
{
if( m_dropConsumers.containsKey( entity ) )
dropConsumer = consumer;
dropEntity = null;
dropWorld = new WeakReference<>( world );
dropPos = pos;
dropBounds = new AxisAlignedBB( pos ).grow( 2, 2, 2 );
}
@Override
public void clearDropConsumer()
{
if( dropEntity != null )
{
boolean captured = entity.captureDrops;
if( captured )
Entity entity = dropEntity.get();
if( entity != null )
{
entity.captureDrops = false;
ArrayList<EntityItem> items = entity.capturedDrops;
if( items != null )
if( entity.capturedDrops != null )
{
dispatchEntityDrops( entity, items );
items.clear();
for( EntityItem entityItem : entity.capturedDrops ) dropConsumer.accept( entityItem.getItem() );
entity.capturedDrops.clear();
}
}
m_dropConsumers.remove( entity );
}
dropConsumer = null;
dropEntity = null;
dropWorld = null;
dropPos = null;
dropBounds = null;
}
private void registerTurtleUpgradeInternal( ITurtleUpgrade upgrade )
@@ -289,7 +306,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
{
IForgeRegistry<Item> registry = event.getRegistry();
registry.register( new ItemTurtleLegacy( ComputerCraft.Blocks.turtle).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ) );
registry.register( new ItemTurtleLegacy( ComputerCraft.Blocks.turtle ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ) );
registry.register( new ItemTurtleNormal( ComputerCraft.Blocks.turtleExpanded ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_expanded" ) ) );
registry.register( new ItemTurtleAdvanced( ComputerCraft.Blocks.turtleAdvanced ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ) ) );
}
@@ -362,7 +379,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
private void registerUpgrades()
{
// Upgrades
ComputerCraft.Upgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 );
ComputerCraft.Upgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 );
registerTurtleUpgradeInternal( ComputerCraft.Upgrades.wirelessModem );
ComputerCraft.Upgrades.craftingTable = new TurtleCraftingTable( 2 );
@@ -447,26 +464,54 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
GameRegistry.registerTileEntity( TileTurtleExpanded.class, ComputerCraft.LOWER_ID + " : " + "turtleex" );
GameRegistry.registerTileEntity( TileTurtleAdvanced.class, ComputerCraft.LOWER_ID + " : " + "turtleadv" );
}
private void registerForgeHandlers()
{
ForgeHandlers handlers = new ForgeHandlers();
MinecraftForge.EVENT_BUS.register( handlers );
}
public class ForgeHandlers
{
private ForgeHandlers()
{
}
// Forge event responses
@SubscribeEvent
private class ForgeHandlers
{
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onEntityLivingDrops( LivingDropsEvent event )
{
dispatchEntityDrops( event.getEntity(), event.getDrops() );
// Capture any mob drops for the current entity
if( dropEntity != null && event.getEntity() == dropEntity.get() )
{
List<EntityItem> drops = event.getDrops();
for( EntityItem entityItem : drops ) dropConsumer.accept( entityItem.getItem() );
drops.clear();
}
}
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onHarvestDrops( BlockEvent.HarvestDropsEvent event )
{
// Capture block drops for the current entity
if( dropWorld != null && dropWorld.get() == event.getWorld()
&& dropPos != null && dropPos.equals( event.getPos() ) )
{
for( ItemStack item : event.getDrops() )
{
if( event.getWorld().rand.nextFloat() < event.getDropChance() ) dropConsumer.accept( item );
}
event.getDrops().clear();
}
}
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onEntitySpawn( EntityJoinWorldEvent event )
{
// Capture any nearby item spawns
if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof EntityItem
&& dropBounds.contains( event.getEntity().getPositionVector() ) )
{
dropConsumer.accept( ((EntityItem) event.getEntity()).getItem() );
event.setCanceled( true );
}
}
@SubscribeEvent
public void onTurtleAction( TurtleActionEvent event) {
if( ComputerCraft.turtleDisabledActions.contains( event.getAction() ) )
@@ -475,18 +520,5 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
}
}
}
private void dispatchEntityDrops( Entity entity, java.util.List<EntityItem> drops )
{
IEntityDropConsumer consumer = m_dropConsumers.get( entity );
if( consumer != null )
{
// All checks have passed, lets dispatch the drops
for(EntityItem entityItem : drops)
{
consumer.consumeDrop( entity, entityItem.getItem() );
}
drops.clear();
}
}
}

View File

@@ -7,12 +7,14 @@
package dan200.computercraft.shared.proxy;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.shared.util.IEntityDropConsumer;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.function.Consumer;
public interface ICCTurtleProxy
{
@@ -25,6 +27,7 @@ public interface ICCTurtleProxy
ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack item );
void addAllUpgradedTurtles( NonNullList<ItemStack> list );
void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer );
void clearEntityDropConsumer( Entity entity );
void setDropConsumer( Entity entity, Consumer<ItemStack> consumer );
void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer );
void clearDropConsumer();
}

View File

@@ -127,6 +127,8 @@ public class TurtleBrain implements ITurtleAccess
private TurtleAnimation m_animation;
private int m_animationProgress;
private int m_lastAnimationProgress;
TurtlePlayer m_cachedPlayer;
public TurtleBrain( TileTurtle turtle )
{

View File

@@ -180,12 +180,12 @@ public class TurtlePlaceCommand implements ITurtleCommand
public static TurtlePlayer createPlayer( ITurtleAccess turtle, BlockPos position, EnumFacing direction )
{
TurtlePlayer turtlePlayer = new TurtlePlayer( turtle );
TurtlePlayer turtlePlayer = TurtlePlayer.get( turtle );
orientPlayer( turtle, turtlePlayer, position, direction );
return turtlePlayer;
}
public static void orientPlayer( ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, EnumFacing direction )
private static void orientPlayer( ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, EnumFacing direction )
{
turtlePlayer.posX = position.getX() + 0.5;
turtlePlayer.posY = position.getY() + 0.5;
@@ -241,7 +241,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
// Start claiming entity drops
Entity hitEntity = hit.getKey();
Vec3d hitPos = hit.getValue();
ComputerCraft.setEntityDropConsumer( hitEntity, ( entity, drop ) ->
ComputerCraft.setDropConsumer( hitEntity, ( drop ) ->
{
ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
if( !remainder.isEmpty() )
@@ -285,7 +285,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
}
// Stop claiming drops
ComputerCraft.clearEntityDropConsumer( hitEntity );
ComputerCraft.clearDropConsumer();
// Put everything we collected into the turtles inventory, then return
ItemStack remainder = turtlePlayer.unloadInventory( turtle );
@@ -382,7 +382,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
// Do the deploying (put everything in the players inventory)
boolean placed = false;
TileEntity existingTile = turtle.getWorld().getTileEntity( position );
// See PlayerInteractionManager.processRightClickBlock
PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, EnumHand.MAIN_HAND, position, side, new Vec3d( hitX, hitY, hitZ ) );
@@ -426,12 +426,11 @@ public class TurtlePlaceCommand implements ITurtleCommand
{
World world = turtle.getWorld();
TileEntity tile = world.getTileEntity( position );
if( tile == null )
if( tile == null || tile == existingTile )
{
BlockPos newPosition = WorldUtil.moveCoords( position, side );
tile = world.getTileEntity( newPosition );
tile = world.getTileEntity( WorldUtil.moveCoords( position, side ) );
}
if( tile != null && tile instanceof TileEntitySign )
if( tile instanceof TileEntitySign )
{
TileEntitySign signTile = (TileEntitySign) tile;
String s = (String)extraArguments[0];

View File

@@ -36,16 +36,31 @@ public class TurtlePlayer extends FakePlayer
"[ComputerCraft]"
);
/**
* Construct a TurtlePlayer which exists in the world
*
* @param world The world the player exists in
* @deprecated This is required by {@link Entity}.
*/
@Deprecated
public TurtlePlayer( World world )
{
super( (WorldServer) world, DEFAULT_PROFILE );
}
public TurtlePlayer( ITurtleAccess turtle )
{
super( (WorldServer) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ));
private TurtlePlayer( ITurtleAccess turtle )
{
super( (WorldServer) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) );
setState( turtle );
}
private static GameProfile getProfile( @Nullable GameProfile profile )
{
return profile != null && profile.isComplete() ? profile : DEFAULT_PROFILE;
}
private void setState( ITurtleAccess turtle )
{
BlockPos position = turtle.getPosition();
posX = position.getX() + 0.5;
posY = position.getY() + 0.5;
@@ -53,11 +68,27 @@ public class TurtlePlayer extends FakePlayer
rotationYaw = turtle.getDirection().getHorizontalAngle();
rotationPitch = 0.0f;
inventory.clear();
}
private static GameProfile getProfile( @Nullable GameProfile profile )
public static TurtlePlayer get( ITurtleAccess access )
{
return profile != null && profile.isComplete() ? profile : DEFAULT_PROFILE;
if( !(access instanceof TurtleBrain) ) return new TurtlePlayer( access );
TurtleBrain brain = (TurtleBrain) access;
TurtlePlayer player = brain.m_cachedPlayer;
if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() )
|| player.getEntityWorld() != access.getWorld() )
{
player = brain.m_cachedPlayer = new TurtlePlayer( brain );
}
else
{
player.setState( access );
}
return player;
}
public void loadInventory( @Nonnull ItemStack currentStack )
@@ -76,7 +107,7 @@ public class TurtlePlayer extends FakePlayer
// Store (or drop) anything else we found
BlockPos dropPosition = turtle.getPosition();
EnumFacing dropDirection = turtle.getDirection().getOpposite();
for( int i=0; i<inventory.getSizeInventory(); ++i )
for( int i = 0; i < inventory.getSizeInventory(); ++i )
{
ItemStack stack = inventory.getStackInSlot( i );
if( !stack.isEmpty() )

View File

@@ -11,13 +11,14 @@ import dan200.computercraft.api.turtle.TurtleCommandResult;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.turtle.TurtleVerb;
import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand;
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
@@ -30,20 +31,16 @@ public class TurtleHoe extends TurtleTool
}
@Override
protected boolean canBreakBlock( World world, BlockPos pos )
protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player )
{
if( super.canBreakBlock( world, pos ) )
{
IBlockState state = world.getBlockState( pos );
Material material = state.getMaterial( );
return
material == Material.PLANTS ||
material == Material.CACTUS ||
material == Material.GOURD ||
material == Material.LEAVES ||
material == Material.VINE;
}
return false;
if( !super.canBreakBlock( state, world, pos, player ) ) return false;
Material material = state.getMaterial();
return material == Material.PLANTS ||
material == Material.CACTUS ||
material == Material.GOURD ||
material == Material.LEAVES ||
material == Material.VINE;
}
@Nonnull

View File

@@ -118,7 +118,7 @@ public class TurtleInventoryCrafting extends InventoryCrafting
}
// Do post-pickup stuff
TurtlePlayer turtlePlayer = new TurtlePlayer( m_turtle );
TurtlePlayer turtlePlayer = TurtlePlayer.get( m_turtle );
result.onCrafting( world, turtlePlayer, numToCraft );
results.add( result );

View File

@@ -11,6 +11,7 @@ import dan200.computercraft.api.turtle.TurtleCommandResult;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.turtle.TurtleVerb;
import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand;
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
@@ -30,26 +31,22 @@ public class TurtleShovel extends TurtleTool
}
@Override
protected boolean canBreakBlock( World world, BlockPos pos )
protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player )
{
if( super.canBreakBlock( world, pos ) )
{
IBlockState state = world.getBlockState( pos );
Material material = state.getMaterial( );
return
material == Material.GROUND ||
material == Material.SAND ||
material == Material.SNOW ||
material == Material.CLAY ||
material == Material.CRAFTED_SNOW ||
material == Material.GRASS ||
material == Material.PLANTS ||
material == Material.CACTUS ||
material == Material.GOURD ||
material == Material.LEAVES ||
material == Material.VINE;
}
return false;
if( !super.canBreakBlock( state, world, pos, player ) ) return false;
Material material = state.getMaterial();
return material == Material.GROUND ||
material == Material.SAND ||
material == Material.SNOW ||
material == Material.CLAY ||
material == Material.CRAFTED_SNOW ||
material == Material.GRASS ||
material == Material.PLANTS ||
material == Material.CACTUS ||
material == Material.GOURD ||
material == Material.LEAVES ||
material == Material.VINE;
}
@Nonnull

View File

@@ -5,11 +5,13 @@
*/
package dan200.computercraft.shared.turtle.upgrades;
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class TurtleSword extends TurtleTool
@@ -20,20 +22,16 @@ public class TurtleSword extends TurtleTool
}
@Override
protected boolean canBreakBlock( World world, BlockPos pos )
protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player )
{
if( super.canBreakBlock( world, pos ) )
{
IBlockState state = world.getBlockState( pos );
Material material = state.getMaterial( );
return
material == Material.PLANTS ||
material == Material.LEAVES ||
material == Material.VINE ||
material == Material.CLOTH ||
material == Material.WEB;
}
return false;
if( !super.canBreakBlock( state, world, pos, player ) ) return false;
Material material = state.getMaterial();
return material == Material.PLANTS ||
material == Material.LEAVES ||
material == Material.VINE ||
material == Material.CLOTH ||
material == Material.WEB;
}
@Override

View File

@@ -23,20 +23,17 @@ import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.entity.Entity;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.item.EntityArmorStand;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.event.entity.player.AttackEntityEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.fml.relauncher.Side;
@@ -45,7 +42,9 @@ import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import javax.vecmath.Matrix4f;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class TurtleTool implements ITurtleUpgrade
{
@@ -104,7 +103,7 @@ public class TurtleTool implements ITurtleUpgrade
@Nonnull
@Override
@SideOnly( Side.CLIENT )
@SideOnly(Side.CLIENT)
public Pair<IBakedModel, Matrix4f> getModel( ITurtleAccess turtle, @Nonnull TurtleSide side )
{
float xOffset = (side == TurtleSide.Left) ? -0.40625f : 0.40625f;
@@ -142,22 +141,15 @@ public class TurtleTool implements ITurtleUpgrade
}
}
protected boolean canBreakBlock( World world, BlockPos pos )
protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player )
{
IBlockState state = world.getBlockState( pos );
Block block = state.getBlock();
return !block.isAir( state, world, pos ) && block != Blocks.BEDROCK && state.getBlockHardness( world, pos ) > -1.0F;
return !block.isAir( state, world, pos )
&& block != Blocks.BEDROCK
&& state.getPlayerRelativeBlockHardness( player, world, pos ) > 0
&& block.canEntityDestroy( state, world, pos, player );
}
protected boolean canHarvestBlock( ITurtleAccess turtleAccess, BlockPos pos )
{
World world = turtleAccess.getWorld();
Block block = world.getBlockState( pos ).getBlock();
TurtlePlayer turtlePlayer = new TurtlePlayer( turtleAccess );
turtlePlayer.loadInventory( m_item.copy() );
return ForgeHooks.canHarvestBlock( block, turtlePlayer, world, pos );
}
protected float getDamageMultiplier()
{
return 3.0f;
@@ -195,20 +187,14 @@ public class TurtleTool implements ITurtleUpgrade
}
// Start claiming entity drops
ComputerCraft.setEntityDropConsumer( hitEntity, ( entity, drop ) ->
{
ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
if( !remainder.isEmpty() )
{
WorldUtil.dropItemStack( remainder, world, position, turtle.getDirection().getOpposite() );
}
} );
List<ItemStack> extra = new ArrayList<>( );
ComputerCraft.setDropConsumer( hitEntity, turtleDropConsumer( turtle, extra ) );
// Attack the entity
boolean attacked = false;
if( !hitEntity.hitByEntity( turtlePlayer ) )
{
float damage = (float)turtlePlayer.getEntityAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getAttributeValue();
float damage = (float) turtlePlayer.getEntityAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getAttributeValue();
damage *= getDamageMultiplier();
if( damage > 0.0f )
{
@@ -234,7 +220,7 @@ public class TurtleTool implements ITurtleUpgrade
}
// Stop claiming drops
ComputerCraft.clearEntityDropConsumer( hitEntity );
stopConsuming( turtle, extra );
// Put everything we collected into the turtles inventory, then return
if( attacked )
@@ -251,70 +237,73 @@ public class TurtleTool implements ITurtleUpgrade
{
// Get ready to dig
World world = turtle.getWorld();
BlockPos position = turtle.getPosition();
BlockPos newPosition = WorldUtil.moveCoords( position, direction );
BlockPos turtlePosition = turtle.getPosition();
BlockPos blockPosition = WorldUtil.moveCoords( turtlePosition, direction );
if( WorldUtil.isBlockInWorld( world, newPosition ) &&
!world.isAirBlock( newPosition ) &&
!WorldUtil.isLiquidBlock( world, newPosition ) )
if( WorldUtil.isBlockInWorld( world, blockPosition ) &&
!world.isAirBlock( blockPosition ) &&
!WorldUtil.isLiquidBlock( world, blockPosition ) )
{
TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, position, direction );
IBlockState state = world.getBlockState( blockPosition );
TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, turtlePosition, direction );
turtlePlayer.loadInventory( m_item.copy() );
if( ComputerCraft.turtlesObeyBlockProtection )
{
// Check spawn protection
if( MinecraftForge.EVENT_BUS.post( new BlockEvent.BreakEvent( world, newPosition, world.getBlockState( newPosition ), turtlePlayer ) ) )
if( MinecraftForge.EVENT_BUS.post( new BlockEvent.BreakEvent( world, blockPosition, state, turtlePlayer ) ) )
{
return TurtleCommandResult.failure( "Cannot break protected block" );
}
if( !ComputerCraft.isBlockEditable( world, newPosition, turtlePlayer ) )
if( !ComputerCraft.isBlockEditable( world, blockPosition, turtlePlayer ) )
{
return TurtleCommandResult.failure( "Cannot break protected block" );
}
}
// Check if we can break the block
if( !canBreakBlock( world, newPosition ) )
if( !canBreakBlock( state, world, blockPosition, turtlePlayer ) )
{
return TurtleCommandResult.failure( "Unbreakable block detected" );
}
// Fire the dig event, checking whether it was cancelled.
TurtleBlockEvent.Dig digEvent = new TurtleBlockEvent.Dig( turtle, turtlePlayer, world, newPosition, world.getBlockState( newPosition ), this, side );
TurtleBlockEvent.Dig digEvent = new TurtleBlockEvent.Dig( turtle, turtlePlayer, world, blockPosition, state, this, side );
if( MinecraftForge.EVENT_BUS.post( digEvent ) )
{
return TurtleCommandResult.failure( digEvent.getFailureMessage() );
}
// Consume the items the block drops
if( canHarvestBlock( turtle, newPosition ) )
{
List<ItemStack> items = getBlockDropped( world, newPosition, turtlePlayer );
if( items != null && items.size() > 0 )
{
for( ItemStack stack : items )
{
ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
if( !remainder.isEmpty() )
{
// If there's no room for the items, drop them
WorldUtil.dropItemStack( remainder, world, position, direction );
}
}
}
}
List<ItemStack> extra = new ArrayList<>( );
ComputerCraft.setDropConsumer( world, blockPosition, turtleDropConsumer( turtle, extra ) );
TileEntity tile = world.getTileEntity( blockPosition );
// Much of this logic comes from PlayerInteractionManager#tryHarvestBlock, so it's a good idea
// to consult there before making any changes.
// Play the destruction sound
world.playEvent( 2001, blockPosition, Block.getStateId( state ) );
// Destroy the block
IBlockState previousState = world.getBlockState( newPosition );
world.playEvent(2001, newPosition, Block.getStateId(previousState));
world.setBlockToAir( newPosition );
boolean canHarvest = state.getBlock().canHarvestBlock( world, blockPosition, turtlePlayer );
boolean canBreak = state.getBlock().removedByPlayer( state, world, blockPosition, turtlePlayer, canHarvest );
if( canBreak ) state.getBlock().onBlockDestroyedByPlayer( world, blockPosition, state );
if( canHarvest )
{
state.getBlock().harvestBlock( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getHeldItemMainhand() );
}
stopConsuming( turtle, extra );
// Remember the previous block
if( turtle instanceof TurtleBrain )
{
TurtleBrain brain = (TurtleBrain)turtle;
brain.saveBlockChange( newPosition, previousState );
TurtleBrain brain = (TurtleBrain) turtle;
brain.saveBlockChange( blockPosition, state );
}
return TurtleCommandResult.success();
@@ -323,22 +312,21 @@ public class TurtleTool implements ITurtleUpgrade
return TurtleCommandResult.failure( "Nothing to dig here" );
}
@SuppressWarnings("deprecation")
private List<ItemStack> getBlockDropped( World world, BlockPos pos, EntityPlayer player )
private Consumer<ItemStack> turtleDropConsumer( ITurtleAccess turtle, List<ItemStack> extra )
{
IBlockState state = world.getBlockState( pos );
Block block = state.getBlock();
// Note, we use the deprecated version as some mods override that instead. Those mods are wrong (TM).
List<ItemStack> drops = block.getDrops( world, pos, world.getBlockState( pos ), 0 );
double chance = ForgeEventFactory.fireBlockHarvesting( drops, world, pos, state, 0, 1, false, player );
for( int i = drops.size() - 1; i >= 0; i-- )
return ( drop ) ->
{
if( world.rand.nextFloat() > chance )
{
drops.remove( i );
}
ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
if( !remainder.isEmpty() ) extra.add( remainder );
};
}
private void stopConsuming( ITurtleAccess turtle, List<ItemStack> extra )
{
ComputerCraft.clearDropConsumer();
for( ItemStack remainder : extra )
{
WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection().getOpposite() );
}
return drops;
}
}

View File

@@ -1,16 +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.util;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
public interface IEntityDropConsumer
{
void consumeDrop( Entity dropper, @Nonnull ItemStack drop );
}

View File

@@ -1,7 +1,7 @@
# RecordMedia (and related methods)
public net.minecraft.item.ItemRecord field_185076_b # sound
public net.minecraft.item.ItemRecord field_185077_c # displayName
# ItemPocketRenderer
# ItemPocketRenderer/ItemPrintoutRenderer
public net.minecraft.client.renderer.ItemRenderer func_187466_c()V # renderArms
public net.minecraft.client.renderer.ItemRenderer func_178100_c(F)F # getMapAngleFromPitch
public net.minecraft.client.renderer.ItemRenderer func_187456_a(FFLnet/minecraft/util/EnumHandSide;)V # renderArmFirstPerson

View File

@@ -325,9 +325,9 @@ local function completeProgram( sLine )
-- Add all subdirectories. We don't include files as they will be added in the block below
local tDirs = fs.complete( sLine, sDir, false, false )
for i = 1, #tDirs do
local sResult = tDirs[i]
if not tSeen[ sResult ] then
local sResult = tDirs[i]
table.insert (tResults, sResult )
table.insert ( tResults, sResult )
tSeen [ sResult ] = true
end
end

View File

@@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "minecraft:skull", "data": 1 },
{ "item": "minecraft:skull", "data": 32767 },
{ "item": "computercraft:peripheral", "data": 2 }
],
"result": {

View File

@@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "minecraft:skull", "data": 1 },
{ "item": "minecraft:skull", "data": 32767 },
{ "item": "computercraft:computer", "data": 0 }
],
"result": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB