Copy inventories

I’m trying to make blocks with inventories move with the ship in my Starships plugin, but it doesn’t seem to be working. The signs and block movements work but the items in a container just drop and it seems like they don’t drop as much as was put in the blocks in the first place. Also, I’m not really sure why they drop at all since I have the BlockChangeFlag set to NONE. Movement code:

UPDATE: entity.copyFrom() is apparently causing an exception

[14:47:05 ERROR] [Sponge]: The Scheduler tried to run the task starships-S-1 owned by Plugin{id=starships, name=Starships, version=1.0, source=mods\Starships.jar}, but an error occured.
java.lang.IllegalStateException
at com.google.common.base.Preconditions.checkState(Preconditions.java:161) ~[minecraft_server.1.10.2.jar:?]
at org.spongepowered.api.data.DataTransactionResult$Builder.build(DataTransactionResult.java:640) ~[DataTransactionResult$Builder.class:1.10.2-5.0.0-BETA-124]
at org.spongepowered.api.data.value.mutable.CompositeValueStore.offer(CompositeValueStore.java:548) ~[CompositeValueStore.class:1.10.2-5.0.0-BETA-124]
at net.minecraft.tileentity.TileEntity.copyFrom(SourceFile:302) ~[aqk.class:?]
at net.minecraft.tileentity.TileEntity.copyFrom(SourceFile:61) ~[aqk.class:?]
at org.spongepowered.api.data.value.mutable.CompositeValueStore.copyFrom(CompositeValueStore.java:640) ~[CompositeValueStore.class:1.10.2-5.0.0-BETA-124]
at com.miclesworkshop.starships.starship.Starship.translate(Starship.java:121) ~[Starship.class:?]
at com.miclesworkshop.starships.managers.StarshipManager.lambda$0(StarshipManager.java:58) ~[StarshipManager.class:?]
at org.spongepowered.api.scheduler.Task$Builder.lambda$execute$17(Task.java:138) ~[Task$Builder.class:1.10.2-5.0.0-BETA-124]
at org.spongepowered.common.scheduler.SchedulerBase.lambda$startTask$619(SchedulerBase.java:177) ~[SchedulerBase.class:1.10.2-5.0.0-BETA-124]
at org.spongepowered.common.scheduler.SyncScheduler.executeTaskRunnable(SyncScheduler.java:66) ~[SyncScheduler.class:1.10.2-5.0.0-BETA-124]
at org.spongepowered.common.scheduler.SchedulerBase.startTask(SchedulerBase.java:174) ~[SchedulerBase.class:1.10.2-5.0.0-BETA-124]
at org.spongepowered.common.scheduler.SchedulerBase.processTask(SchedulerBase.java:160) ~[SchedulerBase.class:1.10.2-5.0.0-BETA-124]
at java.util.concurrent.ConcurrentHashMap$ValuesView.forEach(Unknown Source) [?:1.8.0_92]
at org.spongepowered.common.scheduler.SchedulerBase.runTick(SchedulerBase.java:104) [SchedulerBase.class:1.10.2-5.0.0-BETA-124]
at org.spongepowered.common.scheduler.SyncScheduler.tick(SyncScheduler.java:41) [SyncScheduler.class:1.10.2-5.0.0-BETA-124]
at org.spongepowered.common.scheduler.SpongeScheduler.tickSyncScheduler(SpongeScheduler.java:191) [SpongeScheduler.class:1.10.2-5.0.0-BETA-124]
at net.minecraft.server.dedicated.DedicatedServer.handler$onTick$0(SourceFile:90) [ld.class:?]
at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(SourceFile:340) [ld.class:?]
at net.minecraft.server.MinecraftServer.func_71217_p(SourceFile:554) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.run(SourceFile:458) [MinecraftServer.class:?]
at java.lang.Thread.run(Unknown Source) [?:1.8.0_92]

Is that code being called from an async task? If it is, there’s your problem.

It’s not an async task.

Sponge.getScheduler().createTaskBuilder().intervalTicks((long) (2.0)).execute(() -> {
-snip-
ship.translate(new Vector3i(dx, dy, dz));
-snip-
}).submit(StarshipsPlugin.getInstance());

that shows that it’s not async I think, too :stuck_out_tongue:

I think it only throws the exception sometimes, and after that, everything breaks and it throws an exception every time. EDIT: nvm

I made it use snapshots, so now it copies sign data and inventory data by itself, but the items still drop from the original block’s inventory when it breaks

public void translate(Vector3i vector) {
    synchronized (blockList) {
        Location<?> obstructingBlock;
        if ((obstructingBlock = isObstructed(vector)) != null) {
            pilot.sendMessage(Text.of("Path is obstructed at " + obstructingBlock.getPosition() + " by "
                    + obstructingBlock.getBlockType()));
            return;
        }
        for (StarshipLocation location : blockList) {
            Location<?> blockLocation = pilot.getWorld().getLocation(location.getX(), location.getY(),
                    location.getZ());
            BlockState block = blockLocation.getBlock().copy();
            if (block.getType() == BlockTypes.AIR) {
                blockList.remove(location);
                continue;
            }
            blockList.remove(location);
            location.setX(location.getX() + vector.getX());
            location.setY(location.getY() + vector.getY());
            location.setZ(location.getZ() + vector.getZ());
            newStates.put(location, blockLocation.createSnapshot());
            blockLocation.setBlockType(BlockTypes.AIR, BlockChangeFlag.NONE,
                    Cause.of(NamedCause.owner(StarshipsPlugin.getInstance().getContainer())));
        }
        for (StarshipLocation location : newStates.keySet()) {
            Location<?> blockLocation = pilot.getWorld().getLocation(location.getX(), location.getY(),
                    location.getZ());
            blockList.add(location);
            blockLocation.restoreSnapshot(newStates.get(location), true, BlockChangeFlag.NONE,
                    Cause.of(NamedCause.owner(StarshipsPlugin.getInstance().getContainer())));
        }
        Vector3d velocity = pilot.getVelocity();
        pilot.setLocation(pilot.getLocation().add(vector));
        pilot.setVelocity(velocity);
        newStates.clear();
    }
}

EDIT: Is it possible to just clear the inventory of the block?
EDIT 2: Is it faster to use snapshots or setBlock?

I tried this:

            if(blockLocation.getTileEntity().isPresent() && blockLocation.getTileEntity().get() instanceof TileEntityCarrier)
            {
                TileEntityCarrier carrier = (TileEntityCarrier) blockLocation.getTileEntity().get();
                carrier.getInventory().clear();
            }

And I get this:

java.lang.AbstractMethodError: Method net/minecraft/tileentity/TileEntityDropper.clear()V is abstract

EDIT: I also get this for dispensers
EDIT 2: Chests work :stuck_out_tongue:

This is because it’s not implemented yet. What your attempted requires parts of the Inventory API that are incomplete. As far as I know, you can only interact with Player inventories atm.

EDIT: I haven’t checked chests…they may have been implemented recently…

2 Likes

Ok. Chests work too, apparently :stuck_out_tongue: Does this mean I should just not allow droppers/dispensers on ships for now?

Could I simply remove the tile entity data somehow?