mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-09-02 18:37:55 +00:00
14
.github/workflows/main-ci.yml
vendored
14
.github/workflows/main-ci.yml
vendored
@@ -31,17 +31,3 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: cc-restiched
|
name: cc-restiched
|
||||||
path: build/libs
|
path: build/libs
|
||||||
|
|
||||||
- name: Upload Coverage
|
|
||||||
run: bash <(curl -s https://codecov.io/bash)
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: Lint Lua code
|
|
||||||
run: |
|
|
||||||
test -d bin || mkdir bin
|
|
||||||
test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate
|
|
||||||
chmod +x bin/illuaminate
|
|
||||||
bin/illuaminate lint
|
|
||||||
|
|
||||||
- name: Check whitespace
|
|
||||||
run: python3 tools/check-lines.py
|
|
||||||
|
@@ -43,8 +43,8 @@ If you need help getting started with CC: Tweaked, want to show off your latest
|
|||||||
Main Known issue
|
Main Known issue
|
||||||
* Mods that add blocks that can be used as peripherals for CC:T On forge, dont work with CC:R.
|
* Mods that add blocks that can be used as peripherals for CC:T On forge, dont work with CC:R.
|
||||||
* This is because of the differences between forge and fabric, and that mod devs, to my knowledge have not agreed upon a standard method in which to implement cross compatibility between mods,
|
* This is because of the differences between forge and fabric, and that mod devs, to my knowledge have not agreed upon a standard method in which to implement cross compatibility between mods,
|
||||||
* Storage Peripherals throw a java "StackOverflowError" when using `pushItems()`,
|
* [Fixed (d10f297c): please report if bug persists]</br> ~~Storage Peripherals throw a java "StackOverflowError" when using `pushItems()`,~~
|
||||||
* Work around, you are probably using `pushItems(chest, 1)` or simular. please use `pushItems(chest, 1, nil, 1)`.
|
* ~~Work around, you are probably using `pushItems(chest, 1)` or similar. please use `pushItems(chest, 1, nil, 1)`.~~
|
||||||
|
|
||||||
## Known Working mods that add Peripherals
|
## Known Working mods that add Peripherals
|
||||||
* Please let me know of other mods that work with this one
|
* Please let me know of other mods that work with this one
|
||||||
|
@@ -14,8 +14,8 @@ import net.minecraft.client.render.VertexFormat;
|
|||||||
import net.minecraft.client.render.VertexFormatElement;
|
import net.minecraft.client.render.VertexFormatElement;
|
||||||
import net.minecraft.client.render.VertexFormats;
|
import net.minecraft.client.render.VertexFormats;
|
||||||
import net.minecraft.client.render.model.BakedQuad;
|
import net.minecraft.client.render.model.BakedQuad;
|
||||||
|
import net.minecraft.client.util.math.Vector4f;
|
||||||
import net.minecraft.util.math.Matrix4f;
|
import net.minecraft.util.math.Matrix4f;
|
||||||
import net.minecraft.util.math.Quaternion;
|
|
||||||
|
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
@@ -50,41 +50,31 @@ public final class ModelTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static BakedQuad doTransformQuad(VertexFormat format, BakedQuad quad, Matrix4f transform) {
|
private static BakedQuad doTransformQuad(VertexFormat format, BakedQuad quad, Matrix4f transform) {
|
||||||
int[] vertexData = quad.getVertexData()
|
int[] vertexData = quad.getVertexData().clone();
|
||||||
.clone();
|
|
||||||
int offset = 0;
|
|
||||||
BakedQuad copy = new BakedQuad(vertexData, -1, quad.getFace(), ((BakedQuadAccess)quad).getSprite(), true);
|
BakedQuad copy = new BakedQuad(vertexData, -1, quad.getFace(), ((BakedQuadAccess)quad).getSprite(), true);
|
||||||
for (int i = 0; i < format.getElements()
|
|
||||||
.size(); ++i) // For each vertex element
|
int offsetBytes = 0;
|
||||||
{
|
for (int v = 0; v < 4; ++v) {
|
||||||
VertexFormatElement element = format.getElements()
|
for (VertexFormatElement element : format.getElements()) // For each vertex element
|
||||||
.get(i);
|
|
||||||
if (element.getType() == VertexFormatElement.Type.POSITION && element.getFormat() == VertexFormatElement.Format.FLOAT && element.getSize() == 3) // When we find a position
|
|
||||||
// element
|
|
||||||
{
|
{
|
||||||
for (int j = 0; j < 4; ++j) // For each corner of the quad
|
int start = offsetBytes / Integer.BYTES;
|
||||||
|
if (element.getType() == VertexFormatElement.Type.POSITION && element.getFormat() == VertexFormatElement.Format.FLOAT) // When we find a position element
|
||||||
{
|
{
|
||||||
int start = offset + j * format.getVertexSize();
|
Vector4f pos = new Vector4f(Float.intBitsToFloat(vertexData[start]),
|
||||||
if ((start % 4) == 0) {
|
Float.intBitsToFloat(vertexData[start+1]),
|
||||||
start = start / 4;
|
Float.intBitsToFloat(vertexData[start+2]),
|
||||||
|
1);
|
||||||
|
|
||||||
// Extract the position
|
// Transform the position
|
||||||
Quaternion pos = new Quaternion(Float.intBitsToFloat(vertexData[start]),
|
pos.transform(transform);
|
||||||
Float.intBitsToFloat(vertexData[start + 1]),
|
|
||||||
Float.intBitsToFloat(vertexData[start + 2]),
|
|
||||||
1);
|
|
||||||
|
|
||||||
// Transform the position
|
// Insert the position
|
||||||
transform.multiply(pos);
|
vertexData[start] = Float.floatToRawIntBits(pos.getX());
|
||||||
|
vertexData[start+1] = Float.floatToRawIntBits(pos.getY());
|
||||||
// Insert the position
|
vertexData[start+2] = Float.floatToRawIntBits(pos.getZ());
|
||||||
vertexData[start] = Float.floatToRawIntBits(pos.getX());
|
|
||||||
vertexData[start + 1] = Float.floatToRawIntBits(pos.getY());
|
|
||||||
vertexData[start + 2] = Float.floatToRawIntBits(pos.getZ());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
offsetBytes += element.getSize();
|
||||||
}
|
}
|
||||||
offset += element.getSize();
|
|
||||||
}
|
}
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
@@ -78,9 +78,10 @@ public class TurtleSmartItemModel implements BakedModel {
|
|||||||
Identifier overlay = turtle.getOverlay(stack);
|
Identifier overlay = turtle.getOverlay(stack);
|
||||||
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS;
|
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS;
|
||||||
String label = turtle.getLabel(stack);
|
String label = turtle.getLabel(stack);
|
||||||
boolean flip = label != null && (label.equals("Dinnerbone") || label.equals("Grumm"));
|
// TODO make upside down turtle items render properly (currently inivisible)
|
||||||
// TODO Make TurtleTool render for turtle items again.
|
//boolean flip = label != null && (label.equals("Dinnerbone") || label.equals("Grumm"));
|
||||||
TurtleModelCombination combo = new TurtleModelCombination(colour != -1, !(leftUpgrade instanceof TurtleTool) ? leftUpgrade : null, !(rightUpgrade instanceof TurtleTool) ? rightUpgrade : null, overlay, christmas, flip);
|
boolean flip = false;
|
||||||
|
TurtleModelCombination combo = new TurtleModelCombination(colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip);
|
||||||
|
|
||||||
BakedModel model = TurtleSmartItemModel.this.m_cachedModels.get(combo);
|
BakedModel model = TurtleSmartItemModel.this.m_cachedModels.get(combo);
|
||||||
if (model == null) {
|
if (model == null) {
|
||||||
|
@@ -28,7 +28,6 @@ public class GenericPeripheralProvider
|
|||||||
|
|
||||||
ArrayList<SaturatedMethod> saturated = new ArrayList<>( 0 );
|
ArrayList<SaturatedMethod> saturated = new ArrayList<>( 0 );
|
||||||
|
|
||||||
// This seems to add inventory methods, how???
|
|
||||||
List<NamedMethod<PeripheralMethod>> tileMethods = PeripheralMethod.GENERATOR.getMethods( tile.getClass() );
|
List<NamedMethod<PeripheralMethod>> tileMethods = PeripheralMethod.GENERATOR.getMethods( tile.getClass() );
|
||||||
if( !tileMethods.isEmpty() ) addSaturated( saturated, tile, tileMethods );
|
if( !tileMethods.isEmpty() ) addSaturated( saturated, tile, tileMethods );
|
||||||
|
|
||||||
|
@@ -13,6 +13,8 @@ import dan200.computercraft.api.peripheral.IComputerAccess;
|
|||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.asm.GenericSource;
|
import dan200.computercraft.core.asm.GenericSource;
|
||||||
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
|
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
|
||||||
|
import dan200.computercraft.shared.util.InventoryUtil;
|
||||||
|
import dan200.computercraft.shared.util.ItemStorage;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.ChestBlock;
|
import net.minecraft.block.ChestBlock;
|
||||||
@@ -60,10 +62,7 @@ public class InventoryMethods implements GenericSource
|
|||||||
@LuaFunction( mainThread = true )
|
@LuaFunction( mainThread = true )
|
||||||
public static int size( Inventory inventory )
|
public static int size( Inventory inventory )
|
||||||
{
|
{
|
||||||
// Get appropriate inventory for source peripheral
|
return extractHandler(inventory).size();
|
||||||
inventory = extractHandler(inventory);
|
|
||||||
|
|
||||||
return inventory.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,9 +72,13 @@ public class InventoryMethods implements GenericSource
|
|||||||
* @return The name of this inventory, or {@code nil} if not present.
|
* @return The name of this inventory, or {@code nil} if not present.
|
||||||
*/
|
*/
|
||||||
@LuaFunction( mainThread = true )
|
@LuaFunction( mainThread = true )
|
||||||
public static String name( Nameable inventory )
|
public static String name( Inventory inventory )
|
||||||
{
|
{
|
||||||
return inventory.hasCustomName() ? inventory.getName().asString() : null;
|
if ( inventory instanceof Nameable ) {
|
||||||
|
Nameable i = (Nameable)inventory;
|
||||||
|
return i.hasCustomName() ? i.getName().asString() : null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -95,14 +98,13 @@ public class InventoryMethods implements GenericSource
|
|||||||
@LuaFunction( mainThread = true )
|
@LuaFunction( mainThread = true )
|
||||||
public static Map<Integer, Map<String, ?>> list( Inventory inventory )
|
public static Map<Integer, Map<String, ?>> list( Inventory inventory )
|
||||||
{
|
{
|
||||||
// Get appropriate inventory for source peripheral
|
ItemStorage itemStorage = extractHandler(inventory);
|
||||||
inventory = extractHandler(inventory);
|
|
||||||
|
|
||||||
Map<Integer, Map<String, ?>> result = new HashMap<>();
|
Map<Integer, Map<String, ?>> result = new HashMap<>();
|
||||||
int size = inventory.size();
|
int size = itemStorage.size();
|
||||||
for( int i = 0; i < size; i++ )
|
for( int i = 0; i < size; i++ )
|
||||||
{
|
{
|
||||||
ItemStack stack = inventory.getStack( i );
|
ItemStack stack = itemStorage.getStack( i );
|
||||||
if( !stack.isEmpty() ) result.put( i + 1, ItemData.fillBasic( new HashMap<>( 4 ), stack ) );
|
if( !stack.isEmpty() ) result.put( i + 1, ItemData.fillBasic( new HashMap<>( 4 ), stack ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,12 +124,11 @@ public class InventoryMethods implements GenericSource
|
|||||||
@LuaFunction( mainThread = true )
|
@LuaFunction( mainThread = true )
|
||||||
public static Map<String, ?> getItemDetail( Inventory inventory, int slot ) throws LuaException
|
public static Map<String, ?> getItemDetail( Inventory inventory, int slot ) throws LuaException
|
||||||
{
|
{
|
||||||
// Get appropriate inventory
|
ItemStorage itemStorage = extractHandler(inventory);
|
||||||
inventory = extractHandler(inventory);
|
|
||||||
|
|
||||||
assertBetween( slot, 1, inventory.size(), "Slot out of range (%s)" );
|
assertBetween( slot, 1, itemStorage.size(), "Slot out of range (%s)" );
|
||||||
|
|
||||||
ItemStack stack = inventory.getStack( slot - 1 );
|
ItemStack stack = itemStorage.getStack( slot - 1 );
|
||||||
return stack.isEmpty() ? null : ItemData.fill( new HashMap<>(), stack );
|
return stack.isEmpty() ? null : ItemData.fill( new HashMap<>(), stack );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,23 +163,22 @@ public class InventoryMethods implements GenericSource
|
|||||||
String toName, int fromSlot, Optional<Integer> limit, Optional<Integer> toSlot
|
String toName, int fromSlot, Optional<Integer> limit, Optional<Integer> toSlot
|
||||||
) throws LuaException
|
) throws LuaException
|
||||||
{
|
{
|
||||||
// Get appropriate inventory for source peripheral
|
ItemStorage fromStorage = extractHandler( from );
|
||||||
from = extractHandler(from);
|
|
||||||
|
|
||||||
// Find location to transfer to
|
// Find location to transfer to
|
||||||
IPeripheral location = computer.getAvailablePeripheral( toName );
|
IPeripheral location = computer.getAvailablePeripheral( toName );
|
||||||
if( location == null ) throw new LuaException( "Target '" + toName + "' does not exist" );
|
if( location == null ) throw new LuaException( "Target '" + toName + "' does not exist" );
|
||||||
|
|
||||||
Inventory to = extractHandler( location.getTarget() );
|
ItemStorage toStorage = extractHandler( location.getTarget() );
|
||||||
if( to == null ) throw new LuaException( "Target '" + toName + "' is not an inventory" );
|
if( toStorage == null ) throw new LuaException( "Target '" + toName + "' is not an inventory" );
|
||||||
|
|
||||||
// Validate slots
|
// Validate slots
|
||||||
int actualLimit = limit.orElse( Integer.MAX_VALUE );
|
int actualLimit = limit.orElse( Integer.MAX_VALUE );
|
||||||
assertBetween( fromSlot, 1, from.size(), "From slot out of range (%s)" );
|
assertBetween( fromSlot, 1, fromStorage.size(), "From slot out of range (%s)" );
|
||||||
if( toSlot.isPresent() ) assertBetween( toSlot.get(), 1, to.size(), "To slot out of range (%s)" );
|
if( toSlot.isPresent() ) assertBetween( toSlot.get(), 1, toStorage.size(), "To slot out of range (%s)" );
|
||||||
|
|
||||||
if( actualLimit <= 0 ) return 0;
|
if( actualLimit <= 0 ) return 0;
|
||||||
return moveItem( from, fromSlot - 1, to, toSlot.orElse( 0 ) - 1, actualLimit );
|
return moveItem( fromStorage, fromSlot - 1, toStorage, toSlot.orElse( 0 ) - 1, actualLimit );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -213,55 +213,36 @@ public class InventoryMethods implements GenericSource
|
|||||||
) throws LuaException
|
) throws LuaException
|
||||||
{
|
{
|
||||||
// Get appropriate inventory for source peripheral
|
// Get appropriate inventory for source peripheral
|
||||||
to = extractHandler(to);
|
ItemStorage toStorage = extractHandler( to );
|
||||||
|
|
||||||
// Find location to transfer to
|
// Find location to transfer to
|
||||||
IPeripheral location = computer.getAvailablePeripheral( fromName );
|
IPeripheral location = computer.getAvailablePeripheral( fromName );
|
||||||
if( location == null ) throw new LuaException( "Source '" + fromName + "' does not exist" );
|
if( location == null ) throw new LuaException( "Source '" + fromName + "' does not exist" );
|
||||||
|
|
||||||
Inventory from = extractHandler( location.getTarget() );
|
ItemStorage fromStorage = extractHandler( location.getTarget() );
|
||||||
if( from == null ) throw new LuaException( "Source '" + fromName + "' is not an inventory" );
|
if( fromStorage == null ) throw new LuaException( "Source '" + fromName + "' is not an inventory" );
|
||||||
|
|
||||||
// Validate slots
|
// Validate slots
|
||||||
int actualLimit = limit.orElse( Integer.MAX_VALUE );
|
int actualLimit = limit.orElse( Integer.MAX_VALUE );
|
||||||
assertBetween( fromSlot, 1, from.size(), "From slot out of range (%s)" );
|
assertBetween( fromSlot, 1, fromStorage.size(), "From slot out of range (%s)" );
|
||||||
if( toSlot.isPresent() ) assertBetween( toSlot.get(), 1, to.size(), "To slot out of range (%s)" );
|
if( toSlot.isPresent() ) assertBetween( toSlot.get(), 1, toStorage.size(), "To slot out of range (%s)" );
|
||||||
|
|
||||||
if( actualLimit <= 0 ) return 0;
|
if( actualLimit <= 0 ) return 0;
|
||||||
return moveItem( from, fromSlot - 1, to, toSlot.orElse( 0 ) - 1, actualLimit );
|
return moveItem( fromStorage, fromSlot - 1, toStorage, toSlot.orElse( 0 ) - 1, actualLimit );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the most appropriate inventory from the object
|
|
||||||
* e.g., the correct inventory for a double chest or a sided inventory.
|
|
||||||
*
|
|
||||||
* @param object The handler to move from.
|
|
||||||
* @return The appropriate Inventory.
|
|
||||||
*/
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static Inventory extractHandler( @Nullable Object object )
|
private static ItemStorage extractHandler( @Nullable Object object )
|
||||||
{
|
{
|
||||||
Inventory inventory = null;
|
if ( object instanceof BlockEntity ) {
|
||||||
|
Inventory inventory = InventoryUtil.getInventory((BlockEntity) object);
|
||||||
if (object instanceof BlockEntity ) {
|
if ( inventory != null ) {
|
||||||
BlockEntity blockEntity = (BlockEntity) object;
|
return ItemStorage.wrap(inventory);
|
||||||
World world = blockEntity.getWorld();
|
|
||||||
BlockPos blockPos = blockEntity.getPos();
|
|
||||||
BlockState blockState = world.getBlockState(blockPos);
|
|
||||||
Block block = blockState.getBlock();
|
|
||||||
|
|
||||||
if (block instanceof InventoryProvider) {
|
|
||||||
inventory = ((InventoryProvider)block).getInventory(blockState, world, blockPos);
|
|
||||||
} else if (blockEntity instanceof Inventory) {
|
|
||||||
inventory = (Inventory)blockEntity;
|
|
||||||
if (inventory instanceof ChestBlockEntity && block instanceof ChestBlock) {
|
|
||||||
inventory = ChestBlock.getInventory((ChestBlock) block, blockState, world, blockPos, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return inventory;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -274,109 +255,36 @@ public class InventoryMethods implements GenericSource
|
|||||||
* @param limit The max number to move. {@link Integer#MAX_VALUE} for no limit.
|
* @param limit The max number to move. {@link Integer#MAX_VALUE} for no limit.
|
||||||
* @return The number of items moved.
|
* @return The number of items moved.
|
||||||
*/
|
*/
|
||||||
private static int moveItem( Inventory from, int fromSlot, Inventory to, int toSlot, final int limit )
|
private static int moveItem( ItemStorage from, int fromSlot, ItemStorage to, int toSlot, final int limit )
|
||||||
{
|
{
|
||||||
|
// Moving nothing is easy
|
||||||
/* ORIGINAL FORGE CODE
|
if (limit == 0) {
|
||||||
// See how much we can get out of this slot
|
|
||||||
// ItemStack extracted = from.extractItem( fromSlot, limit, true );
|
|
||||||
if( extracted.isEmpty() ) return 0;
|
|
||||||
|
|
||||||
// Limit the amount to extract
|
|
||||||
int extractCount = Math.min( extracted.getCount(), limit );
|
|
||||||
extracted.setCount( extractCount );
|
|
||||||
|
|
||||||
// ItemStack remainder = toSlot < 0 ? bItemHandlerHelper.insertItem( to, extracted, false ) : to.insertItem( toSlot, extracted, false );
|
|
||||||
int inserted = remainder.isEmpty() ? extractCount : extractCount - remainder.getCount();
|
|
||||||
if( inserted <= 0 ) return 0;
|
|
||||||
|
|
||||||
// Remove the item from the original inventory. Technically this could fail, but there's little we can do
|
|
||||||
// about that.
|
|
||||||
from.extractItem( fromSlot, inserted, false );
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Vanilla minecraft inventory manipulation code
|
|
||||||
Boolean recurse = false;
|
|
||||||
ItemStack source = from.getStack( fromSlot );
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
// If target slot was selected, only push items to that slot.
|
|
||||||
if (toSlot >= 0) {
|
|
||||||
int space = amountStackCanAddFrom(to.getStack(toSlot), source, to);
|
|
||||||
if (space == 0) return 0;
|
|
||||||
count = space;
|
|
||||||
}
|
|
||||||
// If target slot not selected, push items where they will fit, possibly
|
|
||||||
// across slots (by recurring on this method).
|
|
||||||
else if (toSlot < 0) {
|
|
||||||
recurse = true;
|
|
||||||
int[] result = getFirstValidSlotAndSpace(source, to);
|
|
||||||
toSlot = result[0];
|
|
||||||
if(toSlot < 0) return 0;
|
|
||||||
count = result[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Respect slot restrictions
|
|
||||||
if (!to.isValid(toSlot, source)) { return 0; }
|
|
||||||
|
|
||||||
// Compare count available in target ItemStack to limit specified.
|
|
||||||
count = Math.min(count, limit);
|
|
||||||
if (count == 0) return 0;
|
|
||||||
|
|
||||||
// Mutate destination and source ItemStack
|
|
||||||
ItemStack destination = to.getStack(toSlot);
|
|
||||||
if (destination.isEmpty()) {
|
|
||||||
ItemStack newStack = source.copy();
|
|
||||||
newStack.setCount(count);
|
|
||||||
to.setStack(toSlot, newStack);
|
|
||||||
} else {
|
|
||||||
destination.increment(count);
|
|
||||||
}
|
|
||||||
source.decrement(count);
|
|
||||||
if (source.isEmpty()) from.setStack(fromSlot, ItemStack.EMPTY);
|
|
||||||
|
|
||||||
to.markDirty();
|
|
||||||
from.markDirty();
|
|
||||||
|
|
||||||
// Recurse if no explicit destination slot and more items exist in source slot
|
|
||||||
// and limit hasn't been reached. Else, return items moved.
|
|
||||||
if (recurse && !source.isEmpty()) return count + moveItem(from, fromSlot, to, -1, limit - count);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maybe there is a nicer existing way to do this in the minecraft codebase. I couldn't find it.
|
|
||||||
private static int[] getFirstValidSlotAndSpace(ItemStack fromStack, Inventory inventory) {
|
|
||||||
for (int i = 0; i < inventory.size(); i++) {
|
|
||||||
ItemStack stack = inventory.getStack(i);
|
|
||||||
int space = amountStackCanAddFrom(stack, fromStack, inventory);
|
|
||||||
if (space > 0) {
|
|
||||||
return new int[]{i, space};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new int[]{-1, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int amountStackCanAddFrom(ItemStack existingStack, ItemStack fromStack, Inventory inventory) {
|
|
||||||
if (fromStack.isEmpty()) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (existingStack.isEmpty()) {
|
|
||||||
return Math.min(Math.min(existingStack.getMaxCount(),
|
|
||||||
inventory.getMaxCountPerStack()),
|
|
||||||
fromStack.getCount());
|
|
||||||
}
|
|
||||||
else if (InventoryMethods.areItemsEqual(existingStack, fromStack) &&
|
|
||||||
existingStack.isStackable() &&
|
|
||||||
existingStack.getCount() < existingStack.getMaxCount() &&
|
|
||||||
existingStack.getCount() < inventory.getMaxCountPerStack()) {
|
|
||||||
int stackSpace = existingStack.getMaxCount() - existingStack.getCount();
|
|
||||||
int invSpace = inventory.getMaxCountPerStack() - existingStack.getCount();
|
|
||||||
return Math.min(Math.min(stackSpace, invSpace), fromStack.getCount());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean areItemsEqual(ItemStack stack1, ItemStack stack2) {
|
// Get stack to move
|
||||||
return stack1.getItem() == stack2.getItem() && ItemStack.areTagsEqual(stack1, stack2);
|
ItemStack stack = InventoryUtil.takeItems(limit, from, fromSlot, 1, fromSlot);
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int stackCount = stack.getCount();
|
||||||
|
|
||||||
|
// Move items in
|
||||||
|
ItemStack remainder;
|
||||||
|
if (toSlot < 0) {
|
||||||
|
remainder = InventoryUtil.storeItems(stack, to);
|
||||||
|
} else {
|
||||||
|
remainder = InventoryUtil.storeItems(stack, to, toSlot, 1, toSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate items moved
|
||||||
|
int count = stackCount - remainder.getCount();
|
||||||
|
|
||||||
|
if (!remainder.isEmpty()) {
|
||||||
|
// Put the remainder back
|
||||||
|
InventoryUtil.storeItems(remainder, from, fromSlot, 1, fromSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ import dan200.computercraft.shared.util.DirectionUtil;
|
|||||||
import dan200.computercraft.shared.util.DropConsumer;
|
import dan200.computercraft.shared.util.DropConsumer;
|
||||||
import dan200.computercraft.shared.util.InventoryUtil;
|
import dan200.computercraft.shared.util.InventoryUtil;
|
||||||
import dan200.computercraft.shared.util.WorldUtil;
|
import dan200.computercraft.shared.util.WorldUtil;
|
||||||
|
import net.minecraft.item.*;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@@ -29,16 +30,6 @@ import net.minecraft.block.entity.BlockEntity;
|
|||||||
import net.minecraft.block.entity.SignBlockEntity;
|
import net.minecraft.block.entity.SignBlockEntity;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.item.BlockItem;
|
|
||||||
import net.minecraft.item.BoatItem;
|
|
||||||
import net.minecraft.item.BucketItem;
|
|
||||||
import net.minecraft.item.GlassBottleItem;
|
|
||||||
import net.minecraft.item.Item;
|
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraft.item.ItemUsageContext;
|
|
||||||
import net.minecraft.item.LilyPadItem;
|
|
||||||
import net.minecraft.item.SignItem;
|
|
||||||
import net.minecraft.text.LiteralText;
|
import net.minecraft.text.LiteralText;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
@@ -224,27 +215,18 @@ public class TurtlePlaceCommand implements ITurtleCommand {
|
|||||||
// Place on the entity
|
// Place on the entity
|
||||||
boolean placed = false;
|
boolean placed = false;
|
||||||
ActionResult cancelResult = hitEntity.interactAt(turtlePlayer, hitPos, Hand.MAIN_HAND);
|
ActionResult cancelResult = hitEntity.interactAt(turtlePlayer, hitPos, Hand.MAIN_HAND);
|
||||||
if (cancelResult == null) {
|
|
||||||
cancelResult = hitEntity.interactAt(turtlePlayer, hitPos, Hand.MAIN_HAND);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cancelResult != null && cancelResult.isAccepted()) {
|
if (cancelResult != null && cancelResult.isAccepted()) {
|
||||||
placed = true;
|
placed = true;
|
||||||
} else if (hitEntity instanceof LivingEntity) {
|
}
|
||||||
// See EntityPlayer.interactOn
|
else {
|
||||||
cancelResult = stackCopy.useOnEntity(turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND);
|
cancelResult = hitEntity.interact(turtlePlayer, Hand.MAIN_HAND);
|
||||||
if (cancelResult != null && cancelResult.isAccepted()) {
|
if (cancelResult != null && cancelResult.isAccepted()) {
|
||||||
placed = true;
|
placed = true;
|
||||||
} else if (cancelResult == null) {
|
}
|
||||||
if (hitEntity.interact(turtlePlayer, Hand.MAIN_HAND) == ActionResult.CONSUME) {
|
else if (hitEntity instanceof LivingEntity) {
|
||||||
placed = true;
|
placed = stackCopy.useOnEntity(turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND).isAccepted();
|
||||||
} else {
|
if (placed) turtlePlayer.loadInventory(stackCopy);
|
||||||
placed = stackCopy.useOnEntity(turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND)
|
|
||||||
.isAccepted();
|
|
||||||
if (placed) {
|
|
||||||
turtlePlayer.loadInventory(stackCopy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,11 +286,9 @@ public class TurtlePlaceCommand implements ITurtleCommand {
|
|||||||
BlockEntity existingTile = turtle.getWorld()
|
BlockEntity existingTile = turtle.getWorld()
|
||||||
.getBlockEntity(position);
|
.getBlockEntity(position);
|
||||||
|
|
||||||
if (placementContext.canPlace()) {
|
if (stackCopy.useOnBlock(context).isAccepted()) {
|
||||||
if (stackCopy.useOnBlock(context) == ActionResult.SUCCESS) {
|
placed = true;
|
||||||
placed = true;
|
turtlePlayer.loadInventory(stackCopy);
|
||||||
turtlePlayer.loadInventory(stackCopy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!placed && (item instanceof BucketItem || item instanceof BoatItem || item instanceof LilyPadItem || item instanceof GlassBottleItem)) {
|
if (!placed && (item instanceof BucketItem || item instanceof BoatItem || item instanceof LilyPadItem || item instanceof GlassBottleItem)) {
|
||||||
|
@@ -8,6 +8,11 @@ package dan200.computercraft.shared.util;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ChestBlock;
|
||||||
|
import net.minecraft.block.InventoryProvider;
|
||||||
|
import net.minecraft.block.entity.ChestBlockEntity;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
@@ -33,9 +38,20 @@ public final class InventoryUtil {
|
|||||||
// Look for tile with inventory
|
// Look for tile with inventory
|
||||||
int y = pos.getY();
|
int y = pos.getY();
|
||||||
if (y >= 0 && y < world.getHeight()) {
|
if (y >= 0 && y < world.getHeight()) {
|
||||||
BlockEntity tileEntity = world.getBlockEntity(pos);
|
// Check if block is InventoryProvider
|
||||||
if (tileEntity instanceof Inventory) {
|
BlockState blockState = world.getBlockState(pos);
|
||||||
return (Inventory) tileEntity;
|
Block block = blockState.getBlock();
|
||||||
|
if (block instanceof InventoryProvider) {
|
||||||
|
return ((InventoryProvider)block).getInventory(blockState, world, pos);
|
||||||
|
}
|
||||||
|
// Check if block is BlockEntity w/ Inventory
|
||||||
|
if (block.hasBlockEntity()) {
|
||||||
|
BlockEntity tileEntity = world.getBlockEntity(pos);
|
||||||
|
|
||||||
|
Inventory inventory = getInventory(tileEntity);
|
||||||
|
if (inventory != null) {
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +71,23 @@ public final class InventoryUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Inventory getInventory(BlockEntity tileEntity) {
|
||||||
|
World world = tileEntity.getWorld();
|
||||||
|
BlockPos pos = tileEntity.getPos();
|
||||||
|
BlockState blockState = world.getBlockState(pos);
|
||||||
|
Block block = blockState.getBlock();
|
||||||
|
|
||||||
|
if (tileEntity instanceof Inventory) {
|
||||||
|
Inventory inventory = (Inventory)tileEntity;
|
||||||
|
if (inventory instanceof ChestBlockEntity && block instanceof ChestBlock) {
|
||||||
|
return ChestBlock.getInventory((ChestBlock) block, blockState, world, pos, true);
|
||||||
|
}
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static ItemStack storeItems(@Nonnull ItemStack itemstack, ItemStorage inventory, int begin) {
|
public static ItemStack storeItems(@Nonnull ItemStack itemstack, ItemStorage inventory, int begin) {
|
||||||
return storeItems(itemstack, inventory, 0, inventory.size(), begin);
|
return storeItems(itemstack, inventory, 0, inventory.size(), begin);
|
||||||
|
@@ -35,6 +35,9 @@ public interface ItemStorage {
|
|||||||
|
|
||||||
int size();
|
int size();
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
ItemStack getStack(int slot);
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
ItemStack take(int slot, int limit, @Nonnull ItemStack filter, boolean simulate);
|
ItemStack take(int slot, int limit, @Nonnull ItemStack filter, boolean simulate);
|
||||||
|
|
||||||
@@ -57,6 +60,12 @@ public interface ItemStorage {
|
|||||||
return this.inventory.size();
|
return this.inventory.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public ItemStack getStack(int slot) {
|
||||||
|
return this.inventory.getStack(slot);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public ItemStack take(int slot, int limit, @Nonnull ItemStack filter, boolean simulate) {
|
public ItemStack take(int slot, int limit, @Nonnull ItemStack filter, boolean simulate) {
|
||||||
@@ -203,6 +212,15 @@ public interface ItemStorage {
|
|||||||
return this.size;
|
return this.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public ItemStack getStack(int slot) {
|
||||||
|
if (slot < this.start || slot >= this.start + this.size) {
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
return this.parent.getStack(slot - this.start );
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public ItemStack take(int slot, int limit, @Nonnull ItemStack filter, boolean simulate) {
|
public ItemStack take(int slot, int limit, @Nonnull ItemStack filter, boolean simulate) {
|
||||||
|
Reference in New Issue
Block a user