1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-01-28 18:04:47 +00:00

Make printers thread-safe

This commit is contained in:
SquidDev 2019-04-02 12:45:54 +01:00
parent 2ab79cf474
commit cbe6e9b5f5
3 changed files with 178 additions and 224 deletions

View File

@ -51,8 +51,13 @@ public class PrinterPeripheral implements IPeripheral
} }
@Override @Override
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException
{ {
// FIXME: There's a theoretical race condition here between getCurrentPage and then using the page. Ideally
// we'd lock on the page, consume it, and unlock.
// FIXME: None of our page modification functions actually mark the tile as dirty, so the page may not be
// persisted correctly.
switch( method ) switch( method )
{ {
case 0: // write case 0: // write
@ -89,10 +94,13 @@ public class PrinterPeripheral implements IPeripheral
return new Object[] { width, height }; return new Object[] { width, height };
} }
case 4: // newPage case 4: // newPage
return new Object[] { m_printer.startNewPage() }; return context.executeMainThreadTask( () -> new Object[] { m_printer.startNewPage() } );
case 5: // endPage case 5: // endPage
getCurrentPage(); getCurrentPage();
return new Object[] { m_printer.endCurrentPage() }; return context.executeMainThreadTask( () -> {
getCurrentPage();
return new Object[] { m_printer.endCurrentPage() };
} );
case 6: // getInkLevel case 6: // getInkLevel
return new Object[] { m_printer.getInkLevel() }; return new Object[] { m_printer.getInkLevel() };
case 7: case 7:
@ -123,13 +131,11 @@ public class PrinterPeripheral implements IPeripheral
return m_printer; return m_printer;
} }
@Nonnull
private Terminal getCurrentPage() throws LuaException private Terminal getCurrentPage() throws LuaException
{ {
Terminal currentPage = m_printer.getCurrentPage(); Terminal currentPage = m_printer.getCurrentPage();
if( currentPage == null ) if( currentPage == null ) throw new LuaException( "Page not started" );
{
throw new LuaException( "Page not started" );
}
return currentPage; return currentPage;
} }
} }

View File

@ -45,9 +45,9 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
{ {
// Statics // Statics
private static final int[] bottomSlots = new int[] { 7, 8, 9, 10, 11, 12 }; private static final int[] BOTTOM_SLOTS = new int[] { 7, 8, 9, 10, 11, 12 };
private static final int[] topSlots = new int[] { 1, 2, 3, 4, 5, 6 }; private static final int[] TOP_SLOTS = new int[] { 1, 2, 3, 4, 5, 6 };
private static final int[] sideSlots = new int[] { 0 }; private static final int[] SIDE_SLOTS = new int[] { 0 };
// Members // Members
@ -88,18 +88,12 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
} }
// Read inventory // Read inventory
synchronized( m_inventory ) NBTTagList itemList = nbt.getTagList( "Items", Constants.NBT.TAG_COMPOUND );
for( int i = 0; i < itemList.tagCount(); i++ )
{ {
NBTTagList nbttaglist = nbt.getTagList( "Items", Constants.NBT.TAG_COMPOUND ); NBTTagCompound itemTag = itemList.getCompoundTagAt( i );
for( int i = 0; i < nbttaglist.tagCount(); i++ ) int slot = itemTag.getByte( "Slot" ) & 0xff;
{ if( slot < m_inventory.size() ) m_inventory.set( slot, new ItemStack( itemTag ) );
NBTTagCompound itemTag = nbttaglist.getCompoundTagAt( i );
int j = itemTag.getByte( "Slot" ) & 0xff;
if( j < m_inventory.size() )
{
m_inventory.set( j, new ItemStack( itemTag ) );
}
}
} }
} }
@ -116,21 +110,18 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
} }
// Write inventory // Write inventory
synchronized( m_inventory ) NBTTagList itemList = new NBTTagList();
for( int i = 0; i < m_inventory.size(); i++ )
{ {
NBTTagList nbttaglist = new NBTTagList(); ItemStack stack = m_inventory.get( i );
for( int i = 0; i < m_inventory.size(); i++ ) if( stack.isEmpty() ) continue;
{
if( !m_inventory.get( i ).isEmpty() ) NBTTagCompound tag = new NBTTagCompound();
{ tag.setByte( "Slot", (byte) i );
NBTTagCompound tag = new NBTTagCompound(); stack.writeToNBT( tag );
tag.setByte( "Slot", (byte) i ); itemList.appendTag( tag );
m_inventory.get( i ).writeToNBT( tag );
nbttaglist.appendTag( tag );
}
}
nbt.setTag( "Items", nbttaglist );
} }
nbt.setTag( "Items", itemList );
return super.writeToNBT( nbt ); return super.writeToNBT( nbt );
} }
@ -148,7 +139,7 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
return super.shouldRefresh( world, pos, oldState, newState ) || BlockPeripheral.getPeripheralType( newState ) != PeripheralType.Printer; return super.shouldRefresh( world, pos, oldState, newState ) || BlockPeripheral.getPeripheralType( newState ) != PeripheralType.Printer;
} }
public boolean isPrinting() boolean isPrinting()
{ {
return m_printing; return m_printing;
} }
@ -173,73 +164,59 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
@Nonnull @Nonnull
@Override @Override
public ItemStack getStackInSlot( int i ) public ItemStack getStackInSlot( int slot )
{ {
return m_inventory.get( i ); return m_inventory.get( slot );
} }
@Nonnull @Nonnull
@Override @Override
public ItemStack removeStackFromSlot( int i ) public ItemStack removeStackFromSlot( int slot )
{ {
synchronized( m_inventory ) ItemStack result = m_inventory.get( slot );
{ m_inventory.set( slot, ItemStack.EMPTY );
ItemStack result = m_inventory.get( i ); markDirty();
m_inventory.set( i, ItemStack.EMPTY ); updateAnim();
markDirty(); return result;
updateAnim();
return result;
}
} }
@Nonnull @Nonnull
@Override @Override
public ItemStack decrStackSize( int i, int j ) public ItemStack decrStackSize( int slot, int count )
{ {
synchronized( m_inventory ) ItemStack stack = m_inventory.get( slot );
if( stack.isEmpty() ) return ItemStack.EMPTY;
if( stack.getCount() <= count )
{ {
if( m_inventory.get( i ).isEmpty() ) return ItemStack.EMPTY; setInventorySlotContents( slot, ItemStack.EMPTY );
return stack;
if( m_inventory.get( i ).getCount() <= j )
{
ItemStack itemstack = m_inventory.get( i );
m_inventory.set( i, ItemStack.EMPTY );
markDirty();
updateAnim();
return itemstack;
}
ItemStack part = m_inventory.get( i ).splitStack( j );
if( m_inventory.get( i ).isEmpty() )
{
m_inventory.set( i, ItemStack.EMPTY );
updateAnim();
}
markDirty();
return part;
} }
ItemStack part = stack.splitStack( count );
if( m_inventory.get( slot ).isEmpty() )
{
m_inventory.set( slot, ItemStack.EMPTY );
updateAnim();
}
markDirty();
return part;
} }
@Override @Override
public void setInventorySlotContents( int i, @Nonnull ItemStack stack ) public void setInventorySlotContents( int slot, @Nonnull ItemStack stack )
{ {
synchronized( m_inventory ) m_inventory.set( slot, stack );
{ markDirty();
m_inventory.set( i, stack ); updateAnim();
markDirty();
updateAnim();
}
} }
@Override @Override
public void clear() public void clear()
{ {
synchronized( m_inventory ) for( int i = 0; i < m_inventory.size(); i++ ) m_inventory.set( i, ItemStack.EMPTY );
{ markDirty();
for( int i = 0; i < m_inventory.size(); i++ ) m_inventory.set( i, ItemStack.EMPTY ); updateAnim();
markDirty();
updateAnim();
}
} }
@Override @Override
@ -249,7 +226,7 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
{ {
return isInk( stack ); return isInk( stack );
} }
else if( slot >= topSlots[0] && slot <= topSlots[topSlots.length - 1] ) else if( slot >= TOP_SLOTS[0] && slot <= TOP_SLOTS[TOP_SLOTS.length - 1] )
{ {
return isPaper( stack ); return isPaper( stack );
} }
@ -295,11 +272,11 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
switch( side ) switch( side )
{ {
case DOWN: // Bottom (Out tray) case DOWN: // Bottom (Out tray)
return bottomSlots; return BOTTOM_SLOTS;
case UP: // Top (In tray) case UP: // Top (In tray)
return topSlots; return TOP_SLOTS;
default: // Sides (Ink) default: // Sides (Ink)
return sideSlots; return SIDE_SLOTS;
} }
} }
@ -311,14 +288,18 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
return new PrinterPeripheral( this ); return new PrinterPeripheral( this );
} }
public Terminal getCurrentPage() @Nullable
Terminal getCurrentPage()
{ {
return m_printing ? m_page : null; synchronized( m_page )
{
return m_printing ? m_page : null;
}
} }
public boolean startNewPage() boolean startNewPage()
{ {
synchronized( m_inventory ) synchronized( m_page )
{ {
if( !canInputPage() ) return false; if( !canInputPage() ) return false;
if( m_printing && !outputPage() ) return false; if( m_printing && !outputPage() ) return false;
@ -326,49 +307,36 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
} }
} }
public boolean endCurrentPage() boolean endCurrentPage()
{ {
synchronized( m_inventory ) synchronized( m_page )
{ {
if( m_printing && outputPage() ) return m_printing && outputPage();
{
return true;
}
}
return false;
}
public int getInkLevel()
{
synchronized( m_inventory )
{
ItemStack inkStack = m_inventory.get( 0 );
return isInk( inkStack ) ? inkStack.getCount() : 0;
} }
} }
public int getPaperLevel() int getInkLevel()
{
ItemStack inkStack = m_inventory.get( 0 );
return isInk( inkStack ) ? inkStack.getCount() : 0;
}
int getPaperLevel()
{ {
int count = 0; int count = 0;
synchronized( m_inventory ) for( int i = 1; i < 7; i++ )
{ {
for( int i = 1; i < 7; i++ ) ItemStack paperStack = m_inventory.get( i );
{ if( isPaper( paperStack ) ) count += paperStack.getCount();
ItemStack paperStack = m_inventory.get( i );
if( !paperStack.isEmpty() && isPaper( paperStack ) )
{
count += paperStack.getCount();
}
}
} }
return count; return count;
} }
public void setPageTitle( String title ) void setPageTitle( String title )
{ {
if( m_printing ) synchronized( m_page )
{ {
m_pageTitle = title; if( m_printing ) m_pageTitle = title;
} }
} }
@ -385,145 +353,126 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
private boolean canInputPage() private boolean canInputPage()
{ {
synchronized( m_inventory ) ItemStack inkStack = m_inventory.get( 0 );
{ return !inkStack.isEmpty() && isInk( inkStack ) && getPaperLevel() > 0;
ItemStack inkStack = m_inventory.get( 0 );
return !inkStack.isEmpty() && isInk( inkStack ) && getPaperLevel() > 0;
}
} }
private boolean inputPage() private boolean inputPage()
{ {
synchronized( m_inventory ) ItemStack inkStack = m_inventory.get( 0 );
if( !isInk( inkStack ) ) return false;
for( int i = 1; i < 7; i++ )
{ {
ItemStack inkStack = m_inventory.get( 0 ); ItemStack paperStack = m_inventory.get( i );
if( !isInk( inkStack ) ) return false; if( paperStack.isEmpty() || !isPaper( paperStack ) ) continue;
for( int i = 1; i < 7; i++ ) // Setup the new page
int colour = inkStack.getItemDamage();
m_page.setTextColour( colour >= 0 && colour < 16 ? 15 - colour : 15 );
m_page.clear();
if( paperStack.getItem() instanceof ItemPrintout )
{ {
ItemStack paperStack = m_inventory.get( i ); m_pageTitle = ItemPrintout.getTitle( paperStack );
if( !paperStack.isEmpty() && isPaper( paperStack ) ) String[] text = ItemPrintout.getText( paperStack );
String[] textColour = ItemPrintout.getColours( paperStack );
for( int y = 0; y < m_page.getHeight(); y++ )
{ {
// Setup the new page m_page.setLine( y, text[y], textColour[y], "" );
int colour = inkStack.getItemDamage();
m_page.setTextColour( colour >= 0 && colour < 16 ? 15 - colour : 15 );
m_page.clear();
if( paperStack.getItem() instanceof ItemPrintout )
{
m_pageTitle = ItemPrintout.getTitle( paperStack );
String[] text = ItemPrintout.getText( paperStack );
String[] textColour = ItemPrintout.getColours( paperStack );
for( int y = 0; y < m_page.getHeight(); y++ )
{
m_page.setLine( y, text[y], textColour[y], "" );
}
}
else
{
m_pageTitle = "";
}
m_page.setCursorPos( 0, 0 );
// Decrement ink
inkStack.shrink( 1 );
if( inkStack.isEmpty() ) m_inventory.set( 0, ItemStack.EMPTY );
// Decrement paper
paperStack.shrink( 1 );
if( paperStack.isEmpty() )
{
m_inventory.set( i, ItemStack.EMPTY );
updateAnim();
}
markDirty();
m_printing = true;
return true;
} }
} }
return false; else
{
m_pageTitle = "";
}
m_page.setCursorPos( 0, 0 );
// Decrement ink
inkStack.shrink( 1 );
if( inkStack.isEmpty() ) m_inventory.set( 0, ItemStack.EMPTY );
// Decrement paper
paperStack.shrink( 1 );
if( paperStack.isEmpty() )
{
m_inventory.set( i, ItemStack.EMPTY );
updateAnim();
}
markDirty();
m_printing = true;
return true;
} }
return false;
} }
private boolean outputPage() private boolean outputPage()
{ {
synchronized( m_page ) int height = m_page.getHeight();
String[] lines = new String[height];
String[] colours = new String[height];
for( int i = 0; i < height; i++ )
{ {
int height = m_page.getHeight(); lines[i] = m_page.getLine( i ).toString();
String[] lines = new String[height]; colours[i] = m_page.getTextColourLine( i ).toString();
String[] colours = new String[height];
for( int i = 0; i < height; i++ )
{
lines[i] = m_page.getLine( i ).toString();
colours[i] = m_page.getTextColourLine( i ).toString();
}
ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours );
synchronized( m_inventory )
{
for( int slot : bottomSlots )
{
if( m_inventory.get( slot ).isEmpty() )
{
setInventorySlotContents( slot, stack );
m_printing = false;
return true;
}
}
}
return false;
} }
ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours );
for( int slot : BOTTOM_SLOTS )
{
if( m_inventory.get( slot ).isEmpty() )
{
setInventorySlotContents( slot, stack );
m_printing = false;
return true;
}
}
return false;
} }
private void ejectContents() private void ejectContents()
{ {
synchronized( m_inventory ) for( int i = 0; i < 13; i++ )
{ {
for( int i = 0; i < 13; i++ ) ItemStack stack = m_inventory.get( i );
if( !stack.isEmpty() )
{ {
ItemStack stack = m_inventory.get( i ); // Remove the stack from the inventory
if( !stack.isEmpty() ) setInventorySlotContents( i, ItemStack.EMPTY );
{
// Remove the stack from the inventory
setInventorySlotContents( i, ItemStack.EMPTY );
// Spawn the item in the world // Spawn the item in the world
BlockPos pos = getPos(); BlockPos pos = getPos();
double x = pos.getX() + 0.5; double x = pos.getX() + 0.5;
double y = pos.getY() + 0.75; double y = pos.getY() + 0.75;
double z = pos.getZ() + 0.5; double z = pos.getZ() + 0.5;
WorldUtil.dropItemStack( stack, getWorld(), x, y, z ); WorldUtil.dropItemStack( stack, getWorld(), x, y, z );
}
} }
} }
} }
private void updateAnim() private void updateAnim()
{ {
synchronized( m_inventory ) int anim = 0;
for( int i = 1; i < 7; i++ )
{ {
int anim = 0; ItemStack stack = m_inventory.get( i );
for( int i = 1; i < 7; i++ ) if( !stack.isEmpty() && isPaper( stack ) )
{ {
ItemStack stack = m_inventory.get( i ); anim += 1;
if( !stack.isEmpty() && isPaper( stack ) ) break;
{
anim += 1;
break;
}
} }
for( int i = 7; i < 13; i++ )
{
ItemStack stack = m_inventory.get( i );
if( !stack.isEmpty() && isPaper( stack ) )
{
anim += 2;
break;
}
}
setAnim( anim );
} }
for( int i = 7; i < 13; i++ )
{
ItemStack stack = m_inventory.get( i );
if( !stack.isEmpty() && isPaper( stack ) )
{
anim += 2;
break;
}
}
setAnim( anim );
} }
@Override @Override

View File

@ -329,7 +329,7 @@ local tMenuFuncs = {
printer.setPageTitle( sName.." (page "..nPage..")" ) printer.setPageTitle( sName.." (page "..nPage..")" )
end end
while not printer.newPage() do while not printer.newPage() do
if printer.getInkLevel() < 1 then if printer.getInkLevel() < 1 then
sStatus = "Printer out of ink, please refill" sStatus = "Printer out of ink, please refill"
elseif printer.getPaperLevel() < 1 then elseif printer.getPaperLevel() < 1 then
@ -342,7 +342,6 @@ local tMenuFuncs = {
redrawMenu() redrawMenu()
term.redirect( printerTerminal ) term.redirect( printerTerminal )
local timer = os.startTimer(0.5)
sleep(0.5) sleep(0.5)
end end