From c2524c56899eaa382f5ede511099eec6b0edf039 Mon Sep 17 00:00:00 2001 From: Raoul Van den Berge Date: Sat, 29 Oct 2016 14:44:52 +0200 Subject: [PATCH] Add disk manipulator model. Still needs to be more generic. --- .../storage/fluid/FluidStorageNBT.java | 4 + .../apiimpl/storage/item/ItemStorageNBT.java | 4 + .../block/BlockDiskManipulator.java | 16 ++ .../refinedstorage/block/BlockNode.java | 2 +- .../container/ContainerDiskManipulator.java | 14 +- .../refinedstorage/proxy/ProxyClient.java | 17 ++ .../render/BakedModelDiskDrive.java | 6 +- .../render/BakedModelDiskManipulator.java | 178 ++++++++++++++++++ .../refinedstorage/render/ModelDiskDrive.java | 6 +- .../render/ModelDiskManipulator.java | 64 +++++++ .../refinedstorage/tile/TileDiskDrive.java | 46 ++--- .../tile/TileDiskManipulator.java | 118 ++++++++---- .../blockstates/disk_manipulator.json | 47 ----- .../{disk_drive_disk_full.json => disk.json} | 48 ++--- ...sconnected.json => disk_disconnected.json} | 42 ++--- .../{disk_drive_disk.json => disk_full.json} | 42 ++--- .../block/disk_manipulator_connected.json | 50 +++++ .../block/disk_manipulator_disconnected.json | 50 +++++ .../blocks/{disk_drive_disk.png => disk.png} | Bin ...disconnected.png => disk_disconnected.png} | Bin ...disk_drive_disk_full.png => disk_full.png} | Bin .../textures/blocks/side_borderless.png | Bin 560 -> 0 bytes .../textures/gui/disk_manipulator.png | Bin 3561 -> 3496 bytes 23 files changed, 574 insertions(+), 180 deletions(-) create mode 100755 src/main/java/com/raoulvdberge/refinedstorage/render/BakedModelDiskManipulator.java create mode 100755 src/main/java/com/raoulvdberge/refinedstorage/render/ModelDiskManipulator.java delete mode 100755 src/main/resources/assets/refinedstorage/blockstates/disk_manipulator.json rename src/main/resources/assets/refinedstorage/models/block/{disk_drive_disk_full.json => disk.json} (77%) rename src/main/resources/assets/refinedstorage/models/block/{disk_drive_disk_disconnected.json => disk_disconnected.json} (78%) rename src/main/resources/assets/refinedstorage/models/block/{disk_drive_disk.json => disk_full.json} (78%) create mode 100755 src/main/resources/assets/refinedstorage/models/block/disk_manipulator_connected.json create mode 100755 src/main/resources/assets/refinedstorage/models/block/disk_manipulator_disconnected.json rename src/main/resources/assets/refinedstorage/textures/blocks/{disk_drive_disk.png => disk.png} (100%) rename src/main/resources/assets/refinedstorage/textures/blocks/{disk_drive_disk_disconnected.png => disk_disconnected.png} (100%) rename src/main/resources/assets/refinedstorage/textures/blocks/{disk_drive_disk_full.png => disk_full.png} (100%) delete mode 100755 src/main/resources/assets/refinedstorage/textures/blocks/side_borderless.png diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/fluid/FluidStorageNBT.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/fluid/FluidStorageNBT.java index c65b66077..1c0e66318 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/fluid/FluidStorageNBT.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/fluid/FluidStorageNBT.java @@ -181,6 +181,10 @@ public abstract class FluidStorageNBT implements IFluidStorage { return capacity; } + public boolean isFull() { + return getStored() == getCapacity(); + } + public NBTTagCompound getTag() { return tag; } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/item/ItemStorageNBT.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/item/ItemStorageNBT.java index 4b4e62612..be1b360a9 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/item/ItemStorageNBT.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/item/ItemStorageNBT.java @@ -224,6 +224,10 @@ public abstract class ItemStorageNBT implements IItemStorage { return capacity; } + public boolean isFull() { + return getStored() == getCapacity(); + } + public NBTTagCompound getTag() { return tag; } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/block/BlockDiskManipulator.java b/src/main/java/com/raoulvdberge/refinedstorage/block/BlockDiskManipulator.java index 45b8d6ac4..0cb75c125 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/block/BlockDiskManipulator.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/block/BlockDiskManipulator.java @@ -2,7 +2,9 @@ package com.raoulvdberge.refinedstorage.block; import com.raoulvdberge.refinedstorage.RS; import com.raoulvdberge.refinedstorage.RSGui; +import com.raoulvdberge.refinedstorage.render.PropertyObject; import com.raoulvdberge.refinedstorage.tile.TileDiskManipulator; +import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -10,11 +12,15 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraftforge.common.property.IExtendedBlockState; import javax.annotation.Nullable; public class BlockDiskManipulator extends BlockNode { + public static final PropertyObject DISK_STATE = new PropertyObject<>("disk_state", Integer[].class); + public BlockDiskManipulator() { super("disk_manipulator"); } @@ -33,6 +39,16 @@ public class BlockDiskManipulator extends BlockNode { return true; } + @Override + protected BlockStateContainer.Builder createBlockStateBuilder() { + return super.createBlockStateBuilder().add(DISK_STATE); + } + + @Override + public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) { + return ((IExtendedBlockState) super.getExtendedState(state, world, pos)).withProperty(DISK_STATE, ((TileDiskManipulator) world.getTileEntity(pos)).getDiskState()); + } + @Override public void breakBlock(World world, BlockPos pos, IBlockState state) { ((TileDiskManipulator) world.getTileEntity(pos)).onBreak(); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/block/BlockNode.java b/src/main/java/com/raoulvdberge/refinedstorage/block/BlockNode.java index 971f58d83..6e38770b2 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/block/BlockNode.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/block/BlockNode.java @@ -14,7 +14,7 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; public abstract class BlockNode extends BlockBase { - private static final PropertyBool CONNECTED = PropertyBool.create("connected"); + public static final PropertyBool CONNECTED = PropertyBool.create("connected"); public BlockNode(String name) { super(name); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/container/ContainerDiskManipulator.java b/src/main/java/com/raoulvdberge/refinedstorage/container/ContainerDiskManipulator.java index 887c9a02b..dacf8c6bd 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/container/ContainerDiskManipulator.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/container/ContainerDiskManipulator.java @@ -15,12 +15,12 @@ public class ContainerDiskManipulator extends ContainerBase { addSlotToContainer(new SlotItemHandler(manipulator.getUpgrades(), i, 187, 6 + (i * 18))); } - for (int i = 0; i < 6; ++i) { - addSlotToContainer(new SlotItemHandler(manipulator.getInputDisks(), i, 26 + (i % 2 * 18), ((i / 2) * 18) + 57)); + for (int i = 0; i < 3; ++i) { + addSlotToContainer(new SlotItemHandler(manipulator.getInputDisks(), i, 44, 57 + (i * 18))); } - for (int i = 0; i < 6; ++i) { - addSlotToContainer(new SlotItemHandler(manipulator.getOutputDisks(), i, 116 + (i % 2 * 18), ((i / 2) * 18) + 57)); + for (int i = 0; i < 3; ++i) { + addSlotToContainer(new SlotItemHandler(manipulator.getOutputDisks(), i, 116, 57 + (i * 18))); } for (int i = 0; i < 9; ++i) { @@ -39,12 +39,12 @@ public class ContainerDiskManipulator extends ContainerBase { if (slot != null && slot.getHasStack()) { stack = slot.getStack(); - if (index < 4 + 12) { - if (!mergeItemStack(stack, 4 + 12 + 9, inventorySlots.size(), false)) { + if (index < 4 + 6) { + if (!mergeItemStack(stack, 4 + 6 + 9, inventorySlots.size(), false)) { return null; } } else if (!mergeItemStack(stack, 0, 16, false)) { - return mergeItemStackToSpecimen(stack, 4 + 12, 4 + 12 + 9); + return mergeItemStackToSpecimen(stack, 4 + 6, 4 + 6 + 9); } if (stack.stackSize == 0) { diff --git a/src/main/java/com/raoulvdberge/refinedstorage/proxy/ProxyClient.java b/src/main/java/com/raoulvdberge/refinedstorage/proxy/ProxyClient.java index b2d603eaa..384119dc7 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/proxy/ProxyClient.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/proxy/ProxyClient.java @@ -10,6 +10,7 @@ import com.raoulvdberge.refinedstorage.item.*; import com.raoulvdberge.refinedstorage.network.MessageGridCraftingPreviewResponse; import com.raoulvdberge.refinedstorage.render.BakedModelPattern; import com.raoulvdberge.refinedstorage.render.ModelDiskDrive; +import com.raoulvdberge.refinedstorage.render.ModelDiskManipulator; import com.raoulvdberge.refinedstorage.tile.TileController; import mcmultipart.client.multipart.ModelMultipartContainer; import mcmultipart.raytrace.PartMOP; @@ -215,6 +216,22 @@ public class ProxyClient extends ProxyCommon { } }); + ModelLoaderRegistry.registerLoader(new ICustomModelLoader() { + @Override + public boolean accepts(ResourceLocation modelLocation) { + return modelLocation.getResourceDomain().equals(RS.ID) && modelLocation.getResourcePath().equals("disk_manipulator"); + } + + @Override + public IModel loadModel(ResourceLocation modelLocation) throws Exception { + return new ModelDiskManipulator(); + } + + @Override + public void onResourceManagerReload(IResourceManager resourceManager) { + } + }); + ModelLoader.setCustomStateMapper(RSBlocks.CONTROLLER, new StateMap.Builder().ignore(BlockController.TYPE).build()); ModelLoader.setCustomMeshDefinition(Item.getItemFromBlock(RSBlocks.CONTROLLER), stack -> { diff --git a/src/main/java/com/raoulvdberge/refinedstorage/render/BakedModelDiskDrive.java b/src/main/java/com/raoulvdberge/refinedstorage/render/BakedModelDiskDrive.java index aa776a310..6827f5964 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/render/BakedModelDiskDrive.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/render/BakedModelDiskDrive.java @@ -111,12 +111,12 @@ public class BakedModelDiskDrive implements IBakedModel { Vector3f trans = model.transformation.getTranslation(); if (facing == EnumFacing.NORTH || facing == EnumFacing.SOUTH) { - trans.x += (((float) x * 7F) / 16F) * (facing == EnumFacing.NORTH ? -1 : 1); + trans.x += ((2F / 16F) + ((float) x * 7F) / 16F) * (facing == EnumFacing.NORTH ? -1 : 1); } else if (facing == EnumFacing.EAST || facing == EnumFacing.WEST) { - trans.z += (((float) x * 7F) / 16F) * (facing == EnumFacing.EAST ? -1 : 1); + trans.z += ((2F / 16F) + ((float) x * 7F) / 16F) * (facing == EnumFacing.EAST ? -1 : 1); } - trans.y -= ((float) y * 3F) / 16F; + trans.y -= (2F / 16F) + ((float) y * 3F) / 16F; model.transformation = new TRSRTransformation(trans, model.transformation.getLeftRot(), model.transformation.getScale(), model.transformation.getRightRot()); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/render/BakedModelDiskManipulator.java b/src/main/java/com/raoulvdberge/refinedstorage/render/BakedModelDiskManipulator.java new file mode 100755 index 000000000..9551dd15b --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/render/BakedModelDiskManipulator.java @@ -0,0 +1,178 @@ +package com.raoulvdberge.refinedstorage.render; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.raoulvdberge.refinedstorage.block.BlockBase; +import com.raoulvdberge.refinedstorage.block.BlockDiskManipulator; +import com.raoulvdberge.refinedstorage.tile.TileDiskDrive; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms; +import net.minecraft.client.renderer.block.model.ItemOverrideList; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.model.TRSRTransformation; +import net.minecraftforge.common.property.IExtendedBlockState; + +import javax.annotation.Nullable; +import javax.vecmath.Vector3f; +import java.util.*; + +public class BakedModelDiskManipulator implements IBakedModel { + private class CacheKey { + private IBlockState state; + private EnumFacing side; + private Integer[] diskState; + + CacheKey(IBlockState state, @Nullable EnumFacing side, Integer[] diskState) { + this.state = state; + this.side = side; + this.diskState = diskState; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + CacheKey cacheKey = (CacheKey) o; + + if (!state.equals(cacheKey.state)) { + return false; + } + + if (side != cacheKey.side) { + return false; + } + + return Arrays.equals(diskState, cacheKey.diskState); + } + + @Override + public int hashCode() { + int result = state.hashCode(); + result = 31 * result + (side != null ? side.hashCode() : 0); + result = 31 * result + Arrays.hashCode(diskState); + return result; + } + } + + private IBakedModel baseConnected; + private IBakedModel baseDisconnected; + private Map modelsConnected = new HashMap<>(); + private Map modelsDisconnected = new HashMap<>(); + private Map>> disks = new HashMap<>(); + + private LoadingCache> cache = CacheBuilder.newBuilder().build(new CacheLoader>() { + @Override + public List load(CacheKey key) throws Exception { + EnumFacing facing = key.state.getValue(BlockBase.DIRECTION); + + List quads = (key.state.getValue(BlockDiskManipulator.CONNECTED) ? modelsConnected : modelsDisconnected).get(facing).getQuads(key.state, key.side, 0); + + for (int i = 0; i < 6; ++i) { + if (key.diskState[i] != TileDiskDrive.DISK_STATE_NONE) { + quads.addAll(disks.get(facing).get(key.diskState[i]).get(i).getQuads(key.state, key.side, 0)); + } + } + + return quads; + } + }); + + public BakedModelDiskManipulator(IBakedModel baseConnected, IBakedModel baseDisconnected, IBakedModel disk, IBakedModel diskFull, IBakedModel diskDisconnected) { + this.baseConnected = baseConnected; + this.baseDisconnected = baseDisconnected; + + for (EnumFacing facing : EnumFacing.HORIZONTALS) { + modelsConnected.put(facing, new BakedModelTRSR(baseConnected, facing)); + modelsDisconnected.put(facing, new BakedModelTRSR(baseDisconnected, facing)); + + disks.put(facing, new HashMap<>()); + + disks.get(facing).put(TileDiskDrive.DISK_STATE_NORMAL, new ArrayList<>()); + disks.get(facing).put(TileDiskDrive.DISK_STATE_FULL, new ArrayList<>()); + disks.get(facing).put(TileDiskDrive.DISK_STATE_DISCONNECTED, new ArrayList<>()); + + initDiskModels(disk, TileDiskDrive.DISK_STATE_NORMAL, facing); + initDiskModels(diskFull, TileDiskDrive.DISK_STATE_FULL, facing); + initDiskModels(diskDisconnected, TileDiskDrive.DISK_STATE_DISCONNECTED, facing); + } + } + + private void initDiskModels(IBakedModel disk, int type, EnumFacing facing) { + for (int x = 0; x < 2; ++x) { + for (int y = 0; y < 3; ++y) { + BakedModelTRSR model = new BakedModelTRSR(disk, facing); + + Vector3f trans = model.transformation.getTranslation(); + + if (facing == EnumFacing.NORTH || facing == EnumFacing.SOUTH) { + trans.x += (2F / 16F + ((float) x * 7F) / 16F) * (facing == EnumFacing.NORTH ? -1 : 1); + } else if (facing == EnumFacing.EAST || facing == EnumFacing.WEST) { + trans.z += (2F / 16F + ((float) x * 7F) / 16F) * (facing == EnumFacing.EAST ? -1 : 1); + } + + trans.y -= (6F / 16F) + (3F * y) / 16F; + + model.transformation = new TRSRTransformation(trans, model.transformation.getLeftRot(), model.transformation.getScale(), model.transformation.getRightRot()); + + disks.get(facing).get(type).add(model); + } + } + } + + @Override + public List getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) { + if (!(state instanceof IExtendedBlockState)) { + return baseDisconnected.getQuads(state, side, rand); + } + + Integer[] diskState = ((IExtendedBlockState) state).getValue(BlockDiskManipulator.DISK_STATE); + + if (diskState == null) { + return baseDisconnected.getQuads(state, side, rand); + } + + CacheKey key = new CacheKey(((IExtendedBlockState) state).getClean(), side, diskState); + cache.refresh(key); + return cache.getUnchecked(key); + } + + @Override + public boolean isAmbientOcclusion() { + return baseDisconnected.isAmbientOcclusion(); + } + + @Override + public boolean isGui3d() { + return baseDisconnected.isGui3d(); + } + + @Override + public boolean isBuiltInRenderer() { + return baseDisconnected.isBuiltInRenderer(); + } + + @Override + public TextureAtlasSprite getParticleTexture() { + return baseDisconnected.getParticleTexture(); + } + + @Override + public ItemCameraTransforms getItemCameraTransforms() { + return baseDisconnected.getItemCameraTransforms(); + } + + @Override + public ItemOverrideList getOverrides() { + return baseDisconnected.getOverrides(); + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/render/ModelDiskDrive.java b/src/main/java/com/raoulvdberge/refinedstorage/render/ModelDiskDrive.java index e04aef4a1..c2b4efc2a 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/render/ModelDiskDrive.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/render/ModelDiskDrive.java @@ -15,9 +15,9 @@ import java.util.Collections; public class ModelDiskDrive implements IModel { private static final ResourceLocation MODEL_BASE = new ResourceLocation("refinedstorage:block/disk_drive"); - private static final ResourceLocation MODEL_DISK = new ResourceLocation("refinedstorage:block/disk_drive_disk"); - private static final ResourceLocation MODEL_DISK_FULL = new ResourceLocation("refinedstorage:block/disk_drive_disk_full"); - private static final ResourceLocation MODEL_DISK_DISCONNECTED = new ResourceLocation("refinedstorage:block/disk_drive_disk_disconnected"); + private static final ResourceLocation MODEL_DISK = new ResourceLocation("refinedstorage:block/disk"); + private static final ResourceLocation MODEL_DISK_FULL = new ResourceLocation("refinedstorage:block/disk_full"); + private static final ResourceLocation MODEL_DISK_DISCONNECTED = new ResourceLocation("refinedstorage:block/disk_disconnected"); @Override public Collection getDependencies() { diff --git a/src/main/java/com/raoulvdberge/refinedstorage/render/ModelDiskManipulator.java b/src/main/java/com/raoulvdberge/refinedstorage/render/ModelDiskManipulator.java new file mode 100755 index 000000000..fdee1099a --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/render/ModelDiskManipulator.java @@ -0,0 +1,64 @@ +package com.raoulvdberge.refinedstorage.render; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.IModel; +import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.common.model.IModelState; +import net.minecraftforge.common.model.TRSRTransformation; + +import java.util.Collection; +import java.util.Collections; + +public class ModelDiskManipulator implements IModel { + private static final ResourceLocation MODEL_BASE_CONNECTED = new ResourceLocation("refinedstorage:block/disk_manipulator_connected"); + private static final ResourceLocation MODEL_BASE_DISCONNECTED = new ResourceLocation("refinedstorage:block/disk_manipulator_disconnected"); + private static final ResourceLocation MODEL_DISK = new ResourceLocation("refinedstorage:block/disk"); + private static final ResourceLocation MODEL_DISK_FULL = new ResourceLocation("refinedstorage:block/disk_full"); + private static final ResourceLocation MODEL_DISK_DISCONNECTED = new ResourceLocation("refinedstorage:block/disk_disconnected"); + + @Override + public Collection getDependencies() { + return Lists.newArrayList(MODEL_BASE_CONNECTED, MODEL_BASE_DISCONNECTED); + } + + @Override + public Collection getTextures() { + return Collections.emptyList(); + } + + @Override + public IBakedModel bake(IModelState state, VertexFormat format, Function bakedTextureGetter) { + IModel baseModelConnected, baseModelDisconnected; + IModel diskModel; + IModel diskModelFull; + IModel diskModelDisconnected; + + try { + baseModelConnected = ModelLoaderRegistry.getModel(MODEL_BASE_CONNECTED); + baseModelDisconnected = ModelLoaderRegistry.getModel(MODEL_BASE_DISCONNECTED); + diskModel = ModelLoaderRegistry.getModel(MODEL_DISK); + diskModelFull = ModelLoaderRegistry.getModel(MODEL_DISK_FULL); + diskModelDisconnected = ModelLoaderRegistry.getModel(MODEL_DISK_DISCONNECTED); + } catch (Exception e) { + throw new Error("Unable to load disk manipulator models", e); + } + + return new BakedModelDiskManipulator( + baseModelConnected.bake(state, format, bakedTextureGetter), + baseModelDisconnected.bake(state, format, bakedTextureGetter), + diskModel.bake(state, format, bakedTextureGetter), + diskModelFull.bake(state, format, bakedTextureGetter), + diskModelDisconnected.bake(state, format, bakedTextureGetter) + ); + } + + @Override + public IModelState getDefaultState() { + return TRSRTransformation.identity(); + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/tile/TileDiskDrive.java b/src/main/java/com/raoulvdberge/refinedstorage/tile/TileDiskDrive.java index 37ec69f37..db5b3af6c 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/tile/TileDiskDrive.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/tile/TileDiskDrive.java @@ -85,10 +85,6 @@ public class TileDiskDrive extends TileNode implements IItemStorageProvider, IFl updateBlock(); } } - - public boolean isFull() { - return getStored() == getCapacity(); - } } public class FluidStorage extends FluidStorageNBT { @@ -136,10 +132,6 @@ public class TileDiskDrive extends TileNode implements IItemStorageProvider, IFl updateBlock(); } } - - public boolean isFull() { - return getStored() == getCapacity(); - } } private static final String NBT_PRIORITY = "Priority"; @@ -210,9 +202,7 @@ public class TileDiskDrive extends TileNode implements IItemStorageProvider, IFl dataManager.addWatchedParameter(VOID_EXCESS); dataManager.addWatchedParameter(ACCESS_TYPE); - for (int i = 0; i < 8; ++i) { - diskState[i] = DISK_STATE_NONE; - } + initDiskState(diskState); } @Override @@ -338,7 +328,24 @@ public class TileDiskDrive extends TileNode implements IItemStorageProvider, IFl public NBTTagCompound writeUpdate(NBTTagCompound tag) { super.writeUpdate(tag); - for (int i = 0; i < 8; ++i) { + writeDiskState(tag, 8, connected, itemStorages, fluidStorages); + + return tag; + } + + @Override + public void readUpdate(NBTTagCompound tag) { + super.readUpdate(tag); + + readDiskState(tag, diskState); + } + + public Integer[] getDiskState() { + return diskState; + } + + public static void writeDiskState(NBTTagCompound tag, int disks, boolean connected, ItemStorageNBT[] itemStorages, FluidStorageNBT[] fluidStorages) { + for (int i = 0; i < disks; ++i) { int state = DISK_STATE_NONE; if (itemStorages[i] != null || fluidStorages[i] != null) { @@ -355,21 +362,18 @@ public class TileDiskDrive extends TileNode implements IItemStorageProvider, IFl tag.setInteger(String.format(NBT_DISK_STATE, i), state); } - - return tag; } - @Override - public void readUpdate(NBTTagCompound tag) { - super.readUpdate(tag); - - for (int i = 0; i < 8; ++i) { + public static void readDiskState(NBTTagCompound tag, Integer[] diskState) { + for (int i = 0; i < diskState.length; ++i) { diskState[i] = tag.getInteger(String.format(NBT_DISK_STATE, i)); } } - public Integer[] getDiskState() { - return diskState; + public static void initDiskState(Integer[] diskState) { + for (int i = 0; i < diskState.length; ++i) { + diskState[i] = DISK_STATE_NONE; + } } @Override diff --git a/src/main/java/com/raoulvdberge/refinedstorage/tile/TileDiskManipulator.java b/src/main/java/com/raoulvdberge/refinedstorage/tile/TileDiskManipulator.java index 79285ef88..57d3fd967 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/tile/TileDiskManipulator.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/tile/TileDiskManipulator.java @@ -67,22 +67,19 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte private ItemStorage[] itemStorages = new ItemStorage[6]; private FluidStorage[] fluidStorages = new FluidStorage[6]; - public TileDiskManipulator() { - dataManager.addWatchedParameter(COMPARE); - dataManager.addWatchedParameter(MODE); - dataManager.addWatchedParameter(TYPE); - dataManager.addWatchedParameter(IO_MODE); - } + private Integer[] diskState = new Integer[6]; private ItemHandlerUpgrade upgrades = new ItemHandlerUpgrade(4, this, ItemUpgrade.TYPE_SPEED, ItemUpgrade.TYPE_STACK); - private ItemHandlerBasic inputDisks = new ItemHandlerBasic(6, this, IItemValidator.STORAGE_DISK) { + private ItemHandlerBasic inputDisks = new ItemHandlerBasic(3, this, IItemValidator.STORAGE_DISK) { @Override protected void onContentsChanged(int slot) { super.onContentsChanged(slot); if (FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) { RSUtils.constructFromDrive(getStackInSlot(slot), slot, itemStorages, fluidStorages, ItemStorage::new, FluidStorage::new); + + updateBlock(); } } @@ -100,11 +97,26 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte } }; - private ItemHandlerBasic outputDisks = new ItemHandlerBasic(6, this, IItemValidator.STORAGE_DISK); + private ItemHandlerBasic outputDisks = new ItemHandlerBasic(3, this, IItemValidator.STORAGE_DISK) { + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + + if (FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) { + RSUtils.constructFromDrive(getStackInSlot(slot), 3 + slot, itemStorages, fluidStorages, ItemStorage::new, FluidStorage::new); + + updateBlock(); + } + } + }; public class ItemStorage extends ItemStorageNBT { + private boolean wasFull; + public ItemStorage(ItemStack disk) { super(disk.getTagCompound(), EnumItemStorageType.getById(disk.getItemDamage()).getCapacity(), TileDiskManipulator.this); + + wasFull = isFull(); } @Override @@ -129,11 +141,26 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte return super.extractItem(stack, size, flags); } + + @Override + public void onStorageChanged() { + super.onStorageChanged(); + + if (wasFull != isFull()) { + wasFull = isFull(); + + updateBlock(); + } + } } public class FluidStorage extends FluidStorageNBT { + private boolean wasFull; + public FluidStorage(ItemStack disk) { super(disk.getTagCompound(), EnumFluidStorageType.getById(disk.getItemDamage()).getCapacity(), TileDiskManipulator.this); + + wasFull = isFull(); } @Override @@ -158,11 +185,31 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte return super.extractFluid(stack, size, flags); } + + @Override + public void onStorageChanged() { + super.onStorageChanged(); + + if (wasFull != isFull()) { + wasFull = isFull(); + + updateBlock(); + } + } } private ItemHandlerBasic itemFilters = new ItemHandlerBasic(9, this); private ItemHandlerFluid fluidFilters = new ItemHandlerFluid(9, this); + public TileDiskManipulator() { + dataManager.addWatchedParameter(COMPARE); + dataManager.addWatchedParameter(MODE); + dataManager.addWatchedParameter(TYPE); + dataManager.addWatchedParameter(IO_MODE); + + TileDiskDrive.initDiskState(diskState); + } + @Override public int getEnergyUsage() { return RS.INSTANCE.config.diskManipulatorUsage + upgrades.getEnergyUsage(); @@ -180,11 +227,11 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte } int slot = 0; if (type == IType.ITEMS) { - while (slot < itemStorages.length && itemStorages[slot] == null) { + while (slot < 3 && itemStorages[slot] == null) { slot++; } - if (slot == itemStorages.length) { + if (slot == 3) { return; } @@ -196,11 +243,11 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte extractFromNetwork(storage, slot); } } else if (type == IType.FLUIDS) { - while (slot < fluidStorages.length && fluidStorages[slot] == null) { + while (slot < 3 && fluidStorages[slot] == null) { slot++; } - if (slot == fluidStorages.length) { + if (slot == 3) { return; } @@ -378,15 +425,15 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte ItemStack disk = inputDisks.getStackInSlot(slot); if (disk != null) { int i = 0; - while (i < 6 && outputDisks.getStackInSlot(i) != null) { + while (i < 3 && outputDisks.getStackInSlot(i) != null) { i++; } - if (i == 6) { + if (i == 3) { return; } - if (slot < 6) { + if (slot < 3) { if (itemStorages[slot] != null) { itemStorages[slot].writeToNBT(); itemStorages[slot] = null; @@ -453,24 +500,11 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte public void read(NBTTagCompound tag) { super.read(tag); - // Backwards Compatibility - ItemHandlerBasic oldDisks = new ItemHandlerBasic(12, this, IItemValidator.STORAGE_DISK); - RSUtils.readItems(oldDisks, 0, tag); - for (int i = 0; i < 12; ++i) { - ItemStack stack = oldDisks.extractItem(i, 1, false); - if (stack != null) { - if (i < 6) { - inputDisks.insertItem(i, stack, false); - } else { - outputDisks.insertItem(i, stack, false); - } - } - } - RSUtils.readItems(itemFilters, 1, tag); RSUtils.readItems(fluidFilters, 2, tag); RSUtils.readItems(upgrades, 3, tag); - RSUtils.readItems(outputDisks, 4, tag); + RSUtils.readItems(inputDisks, 4, tag); + RSUtils.readItems(outputDisks, 5, tag); if (tag.hasKey(NBT_COMPARE)) { compare = tag.getInteger(NBT_COMPARE); @@ -495,11 +529,11 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte onBreak(); - RSUtils.writeItems(inputDisks, 0, tag); RSUtils.writeItems(itemFilters, 1, tag); RSUtils.writeItems(fluidFilters, 2, tag); RSUtils.writeItems(upgrades, 3, tag); - RSUtils.writeItems(outputDisks, 4, tag); + RSUtils.writeItems(inputDisks, 4, tag); + RSUtils.writeItems(outputDisks, 5, tag); tag.setInteger(NBT_COMPARE, compare); tag.setInteger(NBT_MODE, mode); @@ -509,6 +543,26 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte return tag; } + @Override + public NBTTagCompound writeUpdate(NBTTagCompound tag) { + super.writeUpdate(tag); + + TileDiskDrive.writeDiskState(tag, 6, connected, itemStorages, fluidStorages); + + return tag; + } + + @Override + public void readUpdate(NBTTagCompound tag) { + super.readUpdate(tag); + + TileDiskDrive.readDiskState(tag, diskState); + } + + public Integer[] getDiskState() { + return diskState; + } + @Override public IItemHandler getDrops() { return new CombinedInvWrapper(inputDisks, outputDisks, upgrades); diff --git a/src/main/resources/assets/refinedstorage/blockstates/disk_manipulator.json b/src/main/resources/assets/refinedstorage/blockstates/disk_manipulator.json deleted file mode 100755 index 1859a9db7..000000000 --- a/src/main/resources/assets/refinedstorage/blockstates/disk_manipulator.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "forge_marker": 1, - "defaults": { - "model": "orientable", - "textures": { - "side": "refinedstorage:blocks/side", - "top": "refinedstorage:blocks/side", - "front": "refinedstorage:blocks/disk_manipulator_disconnected" - } - }, - "variants": { - "inventory": [ - { - "y": 0 - } - ], - "connected": { - "true": { - "textures": { - "front": "refinedstorage:blocks/disk_manipulator_connected" - } - }, - "false": { - } - }, - "direction": { - "north": { - "y": 0 - }, - "east": { - "y": 90 - }, - "south": { - "y": 180 - }, - "west": { - "y": 270 - }, - "up": { - "x": 270 - }, - "down": { - "x": 90 - } - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/refinedstorage/models/block/disk_drive_disk_full.json b/src/main/resources/assets/refinedstorage/models/block/disk.json similarity index 77% rename from src/main/resources/assets/refinedstorage/models/block/disk_drive_disk_full.json rename to src/main/resources/assets/refinedstorage/models/block/disk.json index bee481873..b569d609c 100755 --- a/src/main/resources/assets/refinedstorage/models/block/disk_drive_disk_full.json +++ b/src/main/resources/assets/refinedstorage/models/block/disk.json @@ -1,24 +1,24 @@ { - "__comment": "Model made by CyanideX", + "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", "textures": { - "disk": "refinedstorage:blocks/disk_drive_disk_full" - }, + "0": "refinedstorage:blocks/disk" + }, "elements": [ { "name": "disk", "from": [ - 9.0, - 12.0, + 11.0, + 14.0, -1.0 ], "to": [ - 14.0, - 14.0, + 16.0, + 16.0, 0.0 ], "faces": { "north": { - "texture": "#disk", + "texture": "#0", "uv": [ 3.0, 0.0, @@ -27,7 +27,7 @@ ] }, "east": { - "texture": "#disk", + "texture": "#0", "uv": [ 2.0, 0.0, @@ -36,7 +36,7 @@ ] }, "south": { - "texture": "#disk", + "texture": "#0", "uv": [ 9.0, 0.0, @@ -45,7 +45,7 @@ ] }, "west": { - "texture": "#disk", + "texture": "#0", "uv": [ 8.0, 0.0, @@ -54,7 +54,7 @@ ] }, "up": { - "texture": "#disk", + "texture": "#0", "uv": [ 3.0, 2.0, @@ -63,7 +63,7 @@ ] }, "down": { - "texture": "#disk", + "texture": "#0", "uv": [ 3.0, 3.0, @@ -72,22 +72,22 @@ ] } } - }, + }, { "name": "led", "from": [ - 10.0, - 11.95, + 12.0, + 13.95, -1.05 ], "to": [ - 11.0, 13.0, + 15.0, -0.10000000000000009 ], "faces": { "north": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -96,7 +96,7 @@ ] }, "east": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -105,7 +105,7 @@ ] }, "south": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -114,7 +114,7 @@ ] }, "west": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -123,7 +123,7 @@ ] }, "up": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -132,7 +132,7 @@ ] }, "down": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -141,6 +141,6 @@ ] } } - } + } ] } \ No newline at end of file diff --git a/src/main/resources/assets/refinedstorage/models/block/disk_drive_disk_disconnected.json b/src/main/resources/assets/refinedstorage/models/block/disk_disconnected.json similarity index 78% rename from src/main/resources/assets/refinedstorage/models/block/disk_drive_disk_disconnected.json rename to src/main/resources/assets/refinedstorage/models/block/disk_disconnected.json index c85e9786b..36197d7d6 100755 --- a/src/main/resources/assets/refinedstorage/models/block/disk_drive_disk_disconnected.json +++ b/src/main/resources/assets/refinedstorage/models/block/disk_disconnected.json @@ -1,24 +1,24 @@ { - "__comment": "Model made by CyanideX", + "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", "textures": { - "disk": "refinedstorage:blocks/disk_drive_disk_disconnected" + "0": "refinedstorage:blocks/disk_disconnected" }, "elements": [ { "name": "disk", "from": [ - 9.0, - 12.0, + 11.0, + 14.0, -1.0 ], "to": [ - 14.0, - 14.0, + 16.0, + 16.0, 0.0 ], "faces": { "north": { - "texture": "#disk", + "texture": "#0", "uv": [ 3.0, 0.0, @@ -27,7 +27,7 @@ ] }, "east": { - "texture": "#disk", + "texture": "#0", "uv": [ 2.0, 0.0, @@ -36,7 +36,7 @@ ] }, "south": { - "texture": "#disk", + "texture": "#0", "uv": [ 9.0, 0.0, @@ -45,7 +45,7 @@ ] }, "west": { - "texture": "#disk", + "texture": "#0", "uv": [ 8.0, 0.0, @@ -54,7 +54,7 @@ ] }, "up": { - "texture": "#disk", + "texture": "#0", "uv": [ 3.0, 2.0, @@ -63,7 +63,7 @@ ] }, "down": { - "texture": "#disk", + "texture": "#0", "uv": [ 3.0, 3.0, @@ -76,18 +76,18 @@ { "name": "led", "from": [ - 10.0, - 11.95, + 12.0, + 13.95, -1.05 ], "to": [ - 11.0, 13.0, + 15.0, -0.10000000000000009 ], "faces": { "north": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -96,7 +96,7 @@ ] }, "east": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -105,7 +105,7 @@ ] }, "south": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -114,7 +114,7 @@ ] }, "west": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -123,7 +123,7 @@ ] }, "up": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -132,7 +132,7 @@ ] }, "down": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, diff --git a/src/main/resources/assets/refinedstorage/models/block/disk_drive_disk.json b/src/main/resources/assets/refinedstorage/models/block/disk_full.json similarity index 78% rename from src/main/resources/assets/refinedstorage/models/block/disk_drive_disk.json rename to src/main/resources/assets/refinedstorage/models/block/disk_full.json index d4c8564fe..26068c216 100755 --- a/src/main/resources/assets/refinedstorage/models/block/disk_drive_disk.json +++ b/src/main/resources/assets/refinedstorage/models/block/disk_full.json @@ -1,24 +1,24 @@ { - "__comment": "Model made by CyanideX", + "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", "textures": { - "disk": "refinedstorage:blocks/disk_drive_disk" + "0": "refinedstorage:blocks/disk_full" }, "elements": [ { "name": "disk", "from": [ - 9.0, - 12.0, + 11.0, + 14.0, -1.0 ], "to": [ - 14.0, - 14.0, + 16.0, + 16.0, 0.0 ], "faces": { "north": { - "texture": "#disk", + "texture": "#0", "uv": [ 3.0, 0.0, @@ -27,7 +27,7 @@ ] }, "east": { - "texture": "#disk", + "texture": "#0", "uv": [ 2.0, 0.0, @@ -36,7 +36,7 @@ ] }, "south": { - "texture": "#disk", + "texture": "#0", "uv": [ 9.0, 0.0, @@ -45,7 +45,7 @@ ] }, "west": { - "texture": "#disk", + "texture": "#0", "uv": [ 8.0, 0.0, @@ -54,7 +54,7 @@ ] }, "up": { - "texture": "#disk", + "texture": "#0", "uv": [ 3.0, 2.0, @@ -63,7 +63,7 @@ ] }, "down": { - "texture": "#disk", + "texture": "#0", "uv": [ 3.0, 3.0, @@ -76,18 +76,18 @@ { "name": "led", "from": [ - 10.0, - 11.95, + 12.0, + 13.95, -1.05 ], "to": [ - 11.0, 13.0, + 15.0, -0.10000000000000009 ], "faces": { "north": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -96,7 +96,7 @@ ] }, "east": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -105,7 +105,7 @@ ] }, "south": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -114,7 +114,7 @@ ] }, "west": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -123,7 +123,7 @@ ] }, "up": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, @@ -132,7 +132,7 @@ ] }, "down": { - "texture": "#disk", + "texture": "#0", "uv": [ 14.0, 1.0, diff --git a/src/main/resources/assets/refinedstorage/models/block/disk_manipulator_connected.json b/src/main/resources/assets/refinedstorage/models/block/disk_manipulator_connected.json new file mode 100755 index 000000000..313db060a --- /dev/null +++ b/src/main/resources/assets/refinedstorage/models/block/disk_manipulator_connected.json @@ -0,0 +1,50 @@ +{ + "parent": "block/block", + "textures": { + "particle": "refinedstorage:blocks/disk_manipulator_connected", + "front": "refinedstorage:blocks/disk_manipulator_connected", + "bottom": "refinedstorage:blocks/side", + "top": "refinedstorage:blocks/side", + "side": "refinedstorage:blocks/side" + }, + "elements": [ + { + "from": [ + 0, + 0, + 0 + ], + "to": [ + 16, + 16, + 16 + ], + "faces": { + "down": { + "texture": "#bottom", + "cullface": "down" + }, + "up": { + "texture": "#top", + "cullface": "up" + }, + "north": { + "texture": "#front", + "cullface": "north" + }, + "south": { + "texture": "#side", + "cullface": "south" + }, + "west": { + "texture": "#side", + "cullface": "west" + }, + "east": { + "texture": "#side", + "cullface": "east" + } + } + } + ] +} diff --git a/src/main/resources/assets/refinedstorage/models/block/disk_manipulator_disconnected.json b/src/main/resources/assets/refinedstorage/models/block/disk_manipulator_disconnected.json new file mode 100755 index 000000000..d8398f25a --- /dev/null +++ b/src/main/resources/assets/refinedstorage/models/block/disk_manipulator_disconnected.json @@ -0,0 +1,50 @@ +{ + "parent": "block/block", + "textures": { + "particle": "refinedstorage:blocks/disk_manipulator_disconnected", + "front": "refinedstorage:blocks/disk_manipulator_disconnected", + "bottom": "refinedstorage:blocks/side", + "top": "refinedstorage:blocks/side", + "side": "refinedstorage:blocks/side" + }, + "elements": [ + { + "from": [ + 0, + 0, + 0 + ], + "to": [ + 16, + 16, + 16 + ], + "faces": { + "down": { + "texture": "#bottom", + "cullface": "down" + }, + "up": { + "texture": "#top", + "cullface": "up" + }, + "north": { + "texture": "#front", + "cullface": "north" + }, + "south": { + "texture": "#side", + "cullface": "south" + }, + "west": { + "texture": "#side", + "cullface": "west" + }, + "east": { + "texture": "#side", + "cullface": "east" + } + } + } + ] +} diff --git a/src/main/resources/assets/refinedstorage/textures/blocks/disk_drive_disk.png b/src/main/resources/assets/refinedstorage/textures/blocks/disk.png similarity index 100% rename from src/main/resources/assets/refinedstorage/textures/blocks/disk_drive_disk.png rename to src/main/resources/assets/refinedstorage/textures/blocks/disk.png diff --git a/src/main/resources/assets/refinedstorage/textures/blocks/disk_drive_disk_disconnected.png b/src/main/resources/assets/refinedstorage/textures/blocks/disk_disconnected.png similarity index 100% rename from src/main/resources/assets/refinedstorage/textures/blocks/disk_drive_disk_disconnected.png rename to src/main/resources/assets/refinedstorage/textures/blocks/disk_disconnected.png diff --git a/src/main/resources/assets/refinedstorage/textures/blocks/disk_drive_disk_full.png b/src/main/resources/assets/refinedstorage/textures/blocks/disk_full.png similarity index 100% rename from src/main/resources/assets/refinedstorage/textures/blocks/disk_drive_disk_full.png rename to src/main/resources/assets/refinedstorage/textures/blocks/disk_full.png diff --git a/src/main/resources/assets/refinedstorage/textures/blocks/side_borderless.png b/src/main/resources/assets/refinedstorage/textures/blocks/side_borderless.png deleted file mode 100755 index a13ebe94fcf7b2c82d36c0d5eb6a14fe35e22820..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 560 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 ECvLMc4FCWD literal 3561 zcmds44N%f&7=Qm1W8tM%WM4+PX2~owi$WJi)XbBW6jR69jS;%8>#CbTDHtv-Ue@yqoZPsd*( z&%VB8+`D%U@@sFV>-imhRf%Dhp=NXL7d=?_^P63tZD4>X@8gp*4>@+OWu+XV_LI%f z=(dUTsFn5Hlw+xQdBLv3Zig^h&K~Z?j=rzZAwSuZb1!{Ao{jB6u+;earxW|h8VAu_ z!$f#f%g`UrBKSGj&8~a=e&&^<+_udYJo(k@L&J8s7q>ZMb8GkR-|1N&`-5}w;(`cO zzR4}z4oXXY^GWgfWID209kan%S#!sA33icH-Z;(qF;orS^s2caBaKfKDHWxBt~7b~D8u5Dnn=}!I5QdO5siienc8Jn0ds+{@bb&k=CC=R z1z~v@wp`-SF7p;Phu1B~%l9%saWLZD6PK;t;n5tvu;n-%*?mjVd(eeJ6{xhf=|_B2 z^Egt??%ES@VijKQNCNHX0joef%CpcAggXlxqmypZO~c20jZ&XZ;v^P<1GIGqGW?P6 z(b$qn*o1=wjv6)M!dZxB3dGWshoR`Vx#`DZFVsPbTrMJrs0>iYn^!0N2HZyz>)2t8 zXAoYb71U}M6GT%{rsXq$A{d#RQ9jx5C1y=KOtAHg*9R(%ta3Szx)djDc;&Twy*Ydw zWoWSEgSdg|vg^`{(v(b}2veGco>;4o^R8KNPa#P^-CLq8FtHoO^!SCBSRb|23}2#3 zGN#-af~Z=ZD%KB%8~rE{t_U%@HFlURkWt?=dUD_ri6{FUrYBr0)f5c3MZ>kc9HBUkbUyPp?*N5bF<(7Bpz(lN4bO5By8Q)x{l3?QUbo#8#{ zR#%S~Y?)I8d^?qb=sXO^M;p6eS~daBCl63dLl6A5Ld8c<L={Zsw?E~w5zQSrH&$$T1*rl)8RIc1d z5c#L+l?oCGJlH$q=<#`8PAD@*&gl8fK8XHAT-ENSjT~5xY?cyR6h4&UISt{v4hwif zK8q<+Pv_no;wL{?fX&^KI!wC+lI(*B)*&0Q1F3WYN1N-m?$f14e*BreT$Em5K%VK$ zYzzxViEOztWT(YTka8m)GLqYJoxf@3XQ4r#`r!*#JYF9Ec*I=0MkOnT8F~g(Is7?n z6AMjqlD(cGCI*(4!Ax%)xZI|x6=`5SEvwWMK$|~0_A&yn?O?h;>{^M)ePAWsR!YNi zG`Vkdkzp-(Y53BMuUDOA(lR1hDKe_DAj1GEuxD@y0ZW>oRs|Zx?AY9Ah1P|?VsrSU zo7URloPBlcD=C9@dw$g2z(i~5s4pa+uvVW?hh4X=#W1?;Tz03m_~Zv}@UYgeHv^&X z1>*Pxm&i&n>RtIliD9h#+=qLll8r~WZOKhWos>pr=v_sw7TtV1puYj{rTcQe&29D% zTZxjUvAlB-)#)I#Nar^XHJQ4ehh35kEIaU37xb0}{y*@Z1eZWyrQCRGBGG+aSK+u) z7h?e>fr?Cm-_h>=V$ef`{ZM%e4IMw_zx3~Xya&5V4WoQnML*RwOr3_>pa+Hp{IE1;&u>~LTyg*a