Merge branch 'mc-1.20.x' into mc-1.20.y
							
								
								
									
										3
									
								
								.github/workflows/make-doc.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -3,8 +3,7 @@ name: Build documentation | |||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     branches: |     branches: | ||||||
|     - mc-1.19.x |     - mc-* | ||||||
|     - mc-1.20.x |  | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   make_doc: |   make_doc: | ||||||
|   | |||||||
| @@ -94,9 +94,8 @@ sourceSets.all { | |||||||
|             check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally |             check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally | ||||||
|             // Too many false positives right now. Maybe we need an indirection for it later on. |             // Too many false positives right now. Maybe we need an indirection for it later on. | ||||||
|             check("ReferenceEquality", CheckSeverity.OFF) |             check("ReferenceEquality", CheckSeverity.OFF) | ||||||
|             check("UnusedVariable", CheckSeverity.OFF) // Too many false positives with records. |             check("EnumOrdinal", CheckSeverity.OFF) // For now. We could replace most of these with EnumMap. | ||||||
|             check("OperatorPrecedence", CheckSeverity.OFF) // For now. |             check("OperatorPrecedence", CheckSeverity.OFF) // For now. | ||||||
|             check("AlreadyChecked", CheckSeverity.OFF) // Seems to be broken? |  | ||||||
|             check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid |             check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid | ||||||
|             check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty |             check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -225,12 +225,12 @@ abstract class CCTweakedExtension( | |||||||
|      * where possible. |      * where possible. | ||||||
|      */ |      */ | ||||||
|     fun downloadFile(label: String, url: String): File { |     fun downloadFile(label: String, url: String): File { | ||||||
|         val url = URI(url) |         val uri = URI(url) | ||||||
|         val path = File(url.path) |         val path = File(uri.path) | ||||||
| 
 | 
 | ||||||
|         project.repositories.ivy { |         project.repositories.ivy { | ||||||
|             name = label |             name = label | ||||||
|             setUrl(URI(url.scheme, url.userInfo, url.host, url.port, path.parent, null, null)) |             setUrl(URI(uri.scheme, uri.userInfo, uri.host, uri.port, path.parent, null, null)) | ||||||
|             patternLayout { |             patternLayout { | ||||||
|                 artifact("[artifact].[ext]") |                 artifact("[artifact].[ext]") | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -98,7 +98,6 @@ abstract class MergeTrees : DefaultTask() { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         val sharedFiles = files.entries.asSequence().filter { (_, v) -> v.found == sources.size }.map { (k, _) -> k }.toList() |         val sharedFiles = files.entries.asSequence().filter { (_, v) -> v.found == sources.size }.map { (k, _) -> k }.toList() | ||||||
|         println(sharedFiles) |  | ||||||
| 
 | 
 | ||||||
|         // Copy shared files to the common directory |         // Copy shared files to the common directory | ||||||
|         fsOperations.sync { |         fsOperations.sync { | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error | |||||||
|  |  | ||||||
| # Mod properties | # Mod properties | ||||||
| isUnstable=true | isUnstable=true | ||||||
| modVersion=1.110.3 | modVersion=1.111.0 | ||||||
|  |  | ||||||
| # Minecraft properties: We want to configure this here so we can read it in settings.gradle | # Minecraft properties: We want to configure this here so we can read it in settings.gradle | ||||||
| mcVersion=1.20.6 | mcVersion=1.20.6 | ||||||
|   | |||||||
| @@ -58,7 +58,7 @@ jmh = "1.37" | |||||||
| cctJavadoc = "1.8.2" | cctJavadoc = "1.8.2" | ||||||
| checkstyle = "10.14.1" | checkstyle = "10.14.1" | ||||||
| curseForgeGradle = "1.1.18" | curseForgeGradle = "1.1.18" | ||||||
| errorProne-core = "2.23.0" | errorProne-core = "2.27.0" | ||||||
| errorProne-plugin = "3.1.0" | errorProne-plugin = "3.1.0" | ||||||
| fabric-loom = "1.6.7" | fabric-loom = "1.6.7" | ||||||
| githubRelease = "2.5.2" | githubRelease = "2.5.2" | ||||||
|   | |||||||
| @@ -129,3 +129,5 @@ val runData by tasks.registering(MergeTrees::class) { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | tasks.withType(GenerateModuleMetadata::class).configureEach { isEnabled = false } | ||||||
|   | |||||||
| @@ -27,7 +27,6 @@ import net.minecraft.client.renderer.MultiBufferSource; | |||||||
| import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; | import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; | ||||||
| import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; | import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; | ||||||
| import net.minecraft.world.phys.AABB; | import net.minecraft.world.phys.AABB; | ||||||
| import org.joml.Matrix3f; |  | ||||||
| import org.joml.Matrix4f; | import org.joml.Matrix4f; | ||||||
| import org.lwjgl.opengl.GL11; | import org.lwjgl.opengl.GL11; | ||||||
| import org.lwjgl.opengl.GL20; | import org.lwjgl.opengl.GL20; | ||||||
| @@ -48,8 +47,6 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl | |||||||
|      */ |      */ | ||||||
|     private static final float MARGIN = (float) (MonitorBlockEntity.RENDER_MARGIN * 1.1); |     private static final float MARGIN = (float) (MonitorBlockEntity.RENDER_MARGIN * 1.1); | ||||||
| 
 | 
 | ||||||
|     private static final Matrix3f IDENTITY_NORMAL = new Matrix3f().identity(); |  | ||||||
| 
 |  | ||||||
|     private static @Nullable ByteBuffer backingBuffer; |     private static @Nullable ByteBuffer backingBuffer; | ||||||
| 
 | 
 | ||||||
|     private static long lastFrame = -1; |     private static long lastFrame = -1; | ||||||
|   | |||||||
| @@ -1 +1,12 @@ | |||||||
| {"parent": "computercraft:block/turtle_base", "textures": {"texture": "computercraft:block/turtle_advanced"}} | { | ||||||
|  |   "parent": "computercraft:block/turtle_base", | ||||||
|  |   "textures": { | ||||||
|  |     "back": "computercraft:block/turtle_advanced_back", | ||||||
|  |     "backpack": "computercraft:block/turtle_advanced_backpack", | ||||||
|  |     "bottom": "computercraft:block/turtle_advanced_bottom", | ||||||
|  |     "front": "computercraft:block/turtle_advanced_front", | ||||||
|  |     "left": "computercraft:block/turtle_advanced_left", | ||||||
|  |     "right": "computercraft:block/turtle_advanced_right", | ||||||
|  |     "top": "computercraft:block/turtle_advanced_top" | ||||||
|  |   } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1 +1,12 @@ | |||||||
| {"parent": "computercraft:block/turtle_base", "textures": {"texture": "computercraft:block/turtle_normal"}} | { | ||||||
|  |   "parent": "computercraft:block/turtle_base", | ||||||
|  |   "textures": { | ||||||
|  |     "back": "computercraft:block/turtle_normal_back", | ||||||
|  |     "backpack": "computercraft:block/turtle_normal_backpack", | ||||||
|  |     "bottom": "computercraft:block/turtle_normal_bottom", | ||||||
|  |     "front": "computercraft:block/turtle_normal_front", | ||||||
|  |     "left": "computercraft:block/turtle_normal_left", | ||||||
|  |     "right": "computercraft:block/turtle_normal_right", | ||||||
|  |     "top": "computercraft:block/turtle_normal_top" | ||||||
|  |   } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -38,6 +38,9 @@ import static net.minecraft.data.models.model.TextureMapping.getBlockTexture; | |||||||
| 
 | 
 | ||||||
| class BlockModelProvider { | class BlockModelProvider { | ||||||
|     private static final TextureSlot CURSOR = TextureSlot.create("cursor"); |     private static final TextureSlot CURSOR = TextureSlot.create("cursor"); | ||||||
|  |     private static final TextureSlot LEFT = TextureSlot.create("left"); | ||||||
|  |     private static final TextureSlot RIGHT = TextureSlot.create("right"); | ||||||
|  |     private static final TextureSlot BACKPACK = TextureSlot.create("backpack"); | ||||||
| 
 | 
 | ||||||
|     private static final ModelTemplate COMPUTER_ON = new ModelTemplate( |     private static final ModelTemplate COMPUTER_ON = new ModelTemplate( | ||||||
|         Optional.of(new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/computer_on")), |         Optional.of(new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/computer_on")), | ||||||
| @@ -58,7 +61,7 @@ class BlockModelProvider { | |||||||
|     private static final ModelTemplate TURTLE = new ModelTemplate( |     private static final ModelTemplate TURTLE = new ModelTemplate( | ||||||
|         Optional.of(new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_base")), |         Optional.of(new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_base")), | ||||||
|         Optional.empty(), |         Optional.empty(), | ||||||
|         TextureSlot.TEXTURE |         TextureSlot.FRONT, TextureSlot.BACK, TextureSlot.TOP, TextureSlot.BOTTOM, LEFT, RIGHT, BACKPACK | ||||||
|     ); |     ); | ||||||
|     private static final ModelTemplate TURTLE_UPGRADE_LEFT = new ModelTemplate( |     private static final ModelTemplate TURTLE_UPGRADE_LEFT = new ModelTemplate( | ||||||
|         Optional.of(new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_upgrade_base_left")), |         Optional.of(new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_upgrade_base_left")), | ||||||
| @@ -167,7 +170,16 @@ class BlockModelProvider { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static void registerTurtle(BlockModelGenerators generators, TurtleBlock block) { |     private static void registerTurtle(BlockModelGenerators generators, TurtleBlock block) { | ||||||
|         var model = TURTLE.create(block, TextureMapping.defaultTexture(block), generators.modelOutput); |         var model = TURTLE.create(block, new TextureMapping() | ||||||
|  |                 .put(TextureSlot.FRONT, getBlockTexture(block, "_front")) | ||||||
|  |                 .put(TextureSlot.BACK, getBlockTexture(block, "_back")) | ||||||
|  |                 .put(TextureSlot.TOP, getBlockTexture(block, "_top")) | ||||||
|  |                 .put(TextureSlot.BOTTOM, getBlockTexture(block, "_bottom")) | ||||||
|  |                 .put(LEFT, getBlockTexture(block, "_left")) | ||||||
|  |                 .put(RIGHT, getBlockTexture(block, "_right")) | ||||||
|  |                 .put(BACKPACK, getBlockTexture(block, "_backpack")), | ||||||
|  |             generators.modelOutput | ||||||
|  |         ); | ||||||
|         generators.blockStateOutput.accept( |         generators.blockStateOutput.accept( | ||||||
|             MultiVariantGenerator.multiVariant(block, Variant.variant().with(VariantProperties.MODEL, model)) |             MultiVariantGenerator.multiVariant(block, Variant.variant().with(VariantProperties.MODEL, model)) | ||||||
|                 .with(createHorizontalFacingDispatch()) |                 .with(createHorizontalFacingDispatch()) | ||||||
|   | |||||||
| @@ -253,7 +253,6 @@ public record ComputerSelector( | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static final class Builder { |     private static final class Builder { | ||||||
|         private OptionalInt instanceId = OptionalInt.empty(); |  | ||||||
|         private @Nullable UUID instanceUuid = null; |         private @Nullable UUID instanceUuid = null; | ||||||
|         private OptionalInt computerId = OptionalInt.empty(); |         private OptionalInt computerId = OptionalInt.empty(); | ||||||
|         private @Nullable String label; |         private @Nullable String label; | ||||||
|   | |||||||
| @@ -5,16 +5,13 @@ | |||||||
| package dan200.computercraft.shared.computer.blocks; | package dan200.computercraft.shared.computer.blocks; | ||||||
| 
 | 
 | ||||||
| import dan200.computercraft.annotations.ForgeOverride; | import dan200.computercraft.annotations.ForgeOverride; | ||||||
| import dan200.computercraft.api.ComputerCraftAPI; |  | ||||||
| import dan200.computercraft.shared.common.IBundledRedstoneBlock; | import dan200.computercraft.shared.common.IBundledRedstoneBlock; | ||||||
| import dan200.computercraft.shared.network.container.ComputerContainerData; | import dan200.computercraft.shared.network.container.ComputerContainerData; | ||||||
| import dan200.computercraft.shared.platform.RegistryEntry; | import dan200.computercraft.shared.platform.RegistryEntry; | ||||||
| import dan200.computercraft.shared.util.BlockEntityHelpers; | import dan200.computercraft.shared.util.BlockEntityHelpers; | ||||||
| import net.minecraft.core.BlockPos; | import net.minecraft.core.BlockPos; | ||||||
| import net.minecraft.core.Direction; | import net.minecraft.core.Direction; | ||||||
| import net.minecraft.resources.ResourceLocation; |  | ||||||
| import net.minecraft.world.InteractionResult; | import net.minecraft.world.InteractionResult; | ||||||
| import net.minecraft.world.MenuProvider; |  | ||||||
| import net.minecraft.world.entity.player.Player; | import net.minecraft.world.entity.player.Player; | ||||||
| import net.minecraft.world.item.ItemStack; | import net.minecraft.world.item.ItemStack; | ||||||
| import net.minecraft.world.level.BlockGetter; | import net.minecraft.world.level.BlockGetter; | ||||||
| @@ -34,8 +31,6 @@ import net.minecraft.world.phys.BlockHitResult; | |||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| 
 | 
 | ||||||
| public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntity> extends HorizontalDirectionalBlock implements IBundledRedstoneBlock, EntityBlock { | public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntity> extends HorizontalDirectionalBlock implements IBundledRedstoneBlock, EntityBlock { | ||||||
|     private static final ResourceLocation DROP = new ResourceLocation(ComputerCraftAPI.MOD_ID, "computer"); |  | ||||||
| 
 |  | ||||||
|     protected final RegistryEntry<BlockEntityType<T>> type; |     protected final RegistryEntry<BlockEntityType<T>> type; | ||||||
|     private final BlockEntityTicker<T> serverTicker = (level, pos, state, computer) -> computer.serverTick(); |     private final BlockEntityTicker<T> serverTicker = (level, pos, state, computer) -> computer.serverTick(); | ||||||
| 
 | 
 | ||||||
| @@ -154,12 +149,6 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit | |||||||
|         return super.updateShape(state, direction, neighborState, level, pos, neighborPos); |         return super.updateShape(state, direction, neighborState, level, pos, neighborPos); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Nullable |  | ||||||
|     @Override |  | ||||||
|     protected MenuProvider getMenuProvider(BlockState state, Level level, BlockPos pos) { |  | ||||||
|         return level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer ? computer : null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |     @Override | ||||||
|     @Nullable |     @Nullable | ||||||
|     public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) { |     public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) { | ||||||
|   | |||||||
| @@ -5,7 +5,6 @@ | |||||||
| package dan200.computercraft.shared.media.items; | package dan200.computercraft.shared.media.items; | ||||||
| 
 | 
 | ||||||
| import dan200.computercraft.api.media.IMedia; | import dan200.computercraft.api.media.IMedia; | ||||||
| import net.minecraft.network.chat.Component; |  | ||||||
| import net.minecraft.sounds.SoundEvent; | import net.minecraft.sounds.SoundEvent; | ||||||
| import net.minecraft.world.item.ItemStack; | import net.minecraft.world.item.ItemStack; | ||||||
| import net.minecraft.world.item.RecordItem; | import net.minecraft.world.item.RecordItem; | ||||||
| @@ -13,7 +12,7 @@ import net.minecraft.world.item.RecordItem; | |||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * An implementation of IMedia for ItemRecords. |  * An implementation of {@link IMedia} for {@link RecordItem}. | ||||||
|  */ |  */ | ||||||
| public final class RecordMedia implements IMedia { | public final class RecordMedia implements IMedia { | ||||||
|     public static final RecordMedia INSTANCE = new RecordMedia(); |     public static final RecordMedia INSTANCE = new RecordMedia(); | ||||||
| @@ -29,16 +28,12 @@ public final class RecordMedia implements IMedia { | |||||||
|     @Override |     @Override | ||||||
|     public @Nullable String getAudioTitle(ItemStack stack) { |     public @Nullable String getAudioTitle(ItemStack stack) { | ||||||
|         var item = stack.getItem(); |         var item = stack.getItem(); | ||||||
|         if (!(item instanceof RecordItem)) return null; |         return item instanceof RecordItem record ? record.getDisplayName().getString() : null; | ||||||
| 
 |  | ||||||
|         return Component.translatable(item.getDescriptionId() + ".desc").getString(); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public @Nullable SoundEvent getAudio(ItemStack stack) { |     public @Nullable SoundEvent getAudio(ItemStack stack) { | ||||||
|         var item = stack.getItem(); |         var item = stack.getItem(); | ||||||
|         if (!(item instanceof RecordItem)) return null; |         return item instanceof RecordItem record ? record.getSound() : null; | ||||||
| 
 |  | ||||||
|         return ((RecordItem) item).getSound(); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -33,7 +33,6 @@ public final class IDAssigner { | |||||||
| 
 | 
 | ||||||
|     private final Path idFile; |     private final Path idFile; | ||||||
|     private final Path newIdFile; |     private final Path newIdFile; | ||||||
|     private boolean atomicMove = true; |  | ||||||
|     private @Nullable Map<String, Integer> ids; |     private @Nullable Map<String, Integer> ids; | ||||||
| 
 | 
 | ||||||
|     public IDAssigner(Path path) { |     public IDAssigner(Path path) { | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ | |||||||
| 
 | 
 | ||||||
| package dan200.computercraft.shared.util; | package dan200.computercraft.shared.util; | ||||||
| 
 | 
 | ||||||
|  | import com.google.errorprone.annotations.Keep; | ||||||
| import net.minecraft.core.BlockPos; | import net.minecraft.core.BlockPos; | ||||||
| import net.minecraft.resources.ResourceKey; | import net.minecraft.resources.ResourceKey; | ||||||
| import net.minecraft.server.level.ChunkLevel; | import net.minecraft.server.level.ChunkLevel; | ||||||
| @@ -132,6 +133,7 @@ public final class TickScheduler { | |||||||
|         /** |         /** | ||||||
|          * The current state of this token. |          * The current state of this token. | ||||||
|          */ |          */ | ||||||
|  |         @Keep | ||||||
|         private volatile State $state = State.IDLE; |         private volatile State $state = State.IDLE; | ||||||
| 
 | 
 | ||||||
|         public Token(BlockEntity owner) { |         public Token(BlockEntity owner) { | ||||||
|   | |||||||
| @@ -218,5 +218,18 @@ | |||||||
|     "upgrade.minecraft.diamond_hoe.adjective": "Contadina", |     "upgrade.minecraft.diamond_hoe.adjective": "Contadina", | ||||||
|     "upgrade.minecraft.diamond_pickaxe.adjective": "Minatrice", |     "upgrade.minecraft.diamond_pickaxe.adjective": "Minatrice", | ||||||
|     "upgrade.minecraft.diamond_shovel.adjective": "Scavatrice", |     "upgrade.minecraft.diamond_shovel.adjective": "Scavatrice", | ||||||
|     "upgrade.minecraft.diamond_sword.adjective": "Da Combattimento" |     "upgrade.minecraft.diamond_sword.adjective": "Da Combattimento", | ||||||
|  |     "tag.item.computercraft.computer": "Computer", | ||||||
|  |     "tag.item.computercraft.wired_modem": "Modem cablati", | ||||||
|  |     "argument.computercraft.computer.distance": "Distanza dall'entità", | ||||||
|  |     "argument.computercraft.computer.family": "Famiglia computer", | ||||||
|  |     "argument.computercraft.computer.id": "ID computer", | ||||||
|  |     "argument.computercraft.computer.instance": "ID istanza unica", | ||||||
|  |     "argument.computercraft.computer.label": "Etichetta computer", | ||||||
|  |     "argument.computercraft.unknown_computer_family": "Famiglia computer '%s' sconosciuta", | ||||||
|  |     "gui.computercraft.config.disabled_generic_methods": "Metodi generici disattivati", | ||||||
|  |     "gui.computercraft.config.disabled_generic_methods.tooltip": "Una lista di metodi generici o sorgenti di metodi da disattivare. I metodi generici sono\nmetodi aggiunti a blocchi/entità blocchi quando non c'è un provider della periferica esplicito.\nQuesto include metodi dell'inventario (ad es. inventory.getItemDetail, inventory.pushItems) e,\nse su Forge, i metodi fluid_storage e energy_storage.\nI metodi in questa lista possono essere sia un gruppo intero di metodi (computer:inventory)\no un singolo metodo (computer:inventory#pushItems).\n", | ||||||
|  |     "tag.item.computercraft.monitor": "Monitor", | ||||||
|  |     "tag.item.computercraft.turtle": "Tartarughe", | ||||||
|  |     "tracking_field.computercraft.java_allocation.name": "Allocazioni Java" | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,30 +2,30 @@ | |||||||
|     "parent": "block/block", |     "parent": "block/block", | ||||||
|     "render_type": "translucent", |     "render_type": "translucent", | ||||||
|     "textures": { |     "textures": { | ||||||
|         "particle": "#texture" |         "particle": "#front" | ||||||
|     }, |     }, | ||||||
|     "elements": [ |     "elements": [ | ||||||
|         { |         { | ||||||
|             "from": [ 2, 2, 2 ], |             "from": [ 2, 2, 2 ], | ||||||
|             "to": [ 14, 14, 13 ], |             "to": [ 14, 14, 13 ], | ||||||
|             "faces": { |             "faces": { | ||||||
|                 "down": { "uv": [ 5.75, 2.75, 2.75, 0 ], "texture": "#texture" }, |                 "down": { "uv": [ 0, 0, 12, 11 ], "texture": "#bottom" }, | ||||||
|                 "up": { "uv": [ 8.75, 0, 5.75, 2.75 ], "texture": "#texture" }, |                 "up": { "uv": [ 0, 0, 12, 11 ], "texture": "#top" }, | ||||||
|                 "north": { "uv": [ 11.5, 5.75, 8.5, 2.75 ], "texture": "#texture" }, |                 "north": { "uv": [ 0, 0, 12, 12 ], "texture": "#front" }, | ||||||
|                 "south": { "uv": [ 5.75, 5.75, 2.75, 2.75 ], "texture": "#texture" }, |                 "south": { "uv": [ 0, 0, 12, 12 ], "texture": "#back" }, | ||||||
|                 "west": { "uv": [ 8.5, 5.75, 5.75, 2.75 ], "texture": "#texture" }, |                 "west": { "uv": [ 0, 0, 11, 12 ], "texture": "#left" }, | ||||||
|                 "east": { "uv": [ 2.75, 5.75, 0, 2.75 ], "texture": "#texture" } |                 "east": { "uv": [ 0, 0, 11, 12 ], "texture": "#right" } | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "from": [ 3, 6, 13 ], |             "from": [ 3, 6, 13 ], | ||||||
|             "to": [ 13, 13, 15 ], |             "to": [ 13, 13, 15 ], | ||||||
|             "faces": { |             "faces": { | ||||||
|                 "down": { "uv": [ 11.75, 0.5, 9.25, 0 ], "texture": "#texture" }, |                 "down": { "uv": [ 2, 9, 12, 11 ], "texture": "#backpack" }, | ||||||
|                 "up": { "uv": [ 14.25, 0, 11.75, 0.5 ], "texture": "#texture" }, |                 "up": { "uv": [ 2, 0, 12, 2 ], "texture": "#backpack" }, | ||||||
|                 "south": { "uv": [ 11.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, |                 "south": { "uv": [ 2, 2, 12, 9 ], "texture": "#backpack" }, | ||||||
|                 "west": { "uv": [ 12.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, |                 "west": { "uv": [ 0, 2, 2, 9 ], "texture": "#backpack" }, | ||||||
|                 "east": { "uv": [ 9.25, 2.25, 8.75, 0.5 ], "texture": "#texture" } |                 "east": { "uv": [ 12, 2, 14, 9 ], "texture": "#backpack" } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     ] |     ] | ||||||
|   | |||||||
| @@ -1,53 +1,67 @@ | |||||||
| { | { | ||||||
|     "parent": "computercraft:block/turtle_base", |     "parent": "computercraft:block/turtle_base", | ||||||
|     "textures": { |     "textures": { | ||||||
|         "texture": "computercraft:block/turtle_colour" |         "texture": "computercraft:block/turtle_colour", | ||||||
|  |         "body_back": "computercraft:block/turtle_colour_body_back", | ||||||
|  |         "body_backpack": "computercraft:block/turtle_colour_body_backpack", | ||||||
|  |         "body_bottom": "computercraft:block/turtle_colour_body_bottom", | ||||||
|  |         "body_front": "computercraft:block/turtle_colour_body_front", | ||||||
|  |         "body_left": "computercraft:block/turtle_colour_body_left", | ||||||
|  |         "body_right": "computercraft:block/turtle_colour_body_right", | ||||||
|  |         "body_top": "computercraft:block/turtle_colour_body_top", | ||||||
|  |         "frame_back": "computercraft:block/turtle_colour_frame_back", | ||||||
|  |         "frame_backpack": "computercraft:block/turtle_colour_frame_backpack", | ||||||
|  |         "frame_bottom": "computercraft:block/turtle_colour_frame_bottom", | ||||||
|  |         "frame_front": "computercraft:block/turtle_colour_frame_front", | ||||||
|  |         "frame_left": "computercraft:block/turtle_colour_frame_left", | ||||||
|  |         "frame_right": "computercraft:block/turtle_colour_frame_right", | ||||||
|  |         "frame_top": "computercraft:block/turtle_colour_frame_top" | ||||||
|     }, |     }, | ||||||
|     "elements": [ |     "elements": [ | ||||||
|         { |         { | ||||||
|             "from": [ 2, 2, 2 ], |             "from": [ 2, 2, 2 ], | ||||||
|             "to": [ 14, 14, 13 ], |             "to": [ 14, 14, 13 ], | ||||||
|             "faces": { |             "faces": { | ||||||
|                 "down": { "uv": [ 5.75, 8.5, 2.75, 5.75 ], "texture": "#texture", "tintindex": 0 }, |                 "down": { "uv": [ 0, 0, 12, 11 ], "texture": "#body_bottom", "tintindex": 0 }, | ||||||
|                 "up": { "uv": [ 8.75, 5.75, 5.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, |                 "up": { "uv": [ 0, 0, 12, 11 ], "texture": "#body_top", "tintindex": 0 }, | ||||||
|                 "north": { "uv": [ 11.5, 11.5, 8.5, 8.5 ], "texture": "#texture", "tintindex": 0 }, |                 "north": { "uv": [ 0, 0, 12, 12 ], "texture": "#body_front", "tintindex": 0 }, | ||||||
|                 "south": { "uv": [ 5.75, 11.5, 2.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, |                 "south": { "uv": [ 0, 0, 12, 12 ], "texture": "#body_back", "tintindex": 0 }, | ||||||
|                 "west": { "uv": [ 8.5, 11.5, 5.75, 8.555 ], "texture": "#texture", "tintindex": 0 }, |                 "west": { "uv": [ 0, 0, 11, 12 ], "texture": "#body_left", "tintindex": 0 }, | ||||||
|                 "east": { "uv": [ 2.75, 11.5, 0, 8.5 ], "texture": "#texture", "tintindex": 0 } |                 "east": { "uv": [ 0, 0, 11, 12 ], "texture": "#body_right", "tintindex": 0 } | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "from": [ 3, 6, 13 ], |             "from": [ 3, 6, 13 ], | ||||||
|             "to": [ 13, 13, 15 ], |             "to": [ 13, 13, 15 ], | ||||||
|             "faces": { |             "faces": { | ||||||
|                 "down": { "uv": [ 11.75, 6.25, 9.25, 5.75 ], "texture": "#texture", "tintindex": 0 }, |                 "down": { "uv": [ 2, 9, 12, 11 ], "texture": "#body_backpack", "tintindex": 0 }, | ||||||
|                 "up": { "uv": [ 14.25, 5.75, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 }, |                 "up": { "uv": [ 2, 0, 12, 2 ], "texture": "#body_backpack", "tintindex": 0 }, | ||||||
|                 "south": { "uv": [ 11.75, 8, 9.25, 6.25 ], "texture": "#texture", "tintindex": 0 }, |                 "south": { "uv": [ 2, 2, 12, 9 ], "texture": "#body_backpack", "tintindex": 0 }, | ||||||
|                 "west": { "uv": [ 12.25, 8, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 }, |                 "west": { "uv": [ 0, 2, 2, 9 ], "texture": "#body_backpack", "tintindex": 0 }, | ||||||
|                 "east": { "uv": [ 9.25, 8, 8.75, 6.25 ], "texture": "#texture", "tintindex": 0 } |                 "east": { "uv": [ 12, 2, 14, 9 ], "texture": "#body_backpack", "tintindex": 0 } | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "from": [ 2, 2, 2 ], |             "from": [ 2, 2, 2 ], | ||||||
|             "to": [ 14, 14, 13 ], |             "to": [ 14, 14, 13 ], | ||||||
|             "faces": { |             "faces": { | ||||||
|                 "down": { "uv": [ 5.75, 2.75, 2.75, 0 ], "texture": "#texture" }, |                 "down": { "uv": [ 0, 0, 12, 11 ], "texture": "#frame_bottom" }, | ||||||
|                 "up": { "uv": [ 8.75, 0, 5.75, 2.75 ], "texture": "#texture" }, |                 "up": { "uv": [ 0, 0, 12, 11 ], "texture": "#frame_top" }, | ||||||
|                 "north": { "uv": [ 11.5, 5.75, 8.5, 2.75 ], "texture": "#texture" }, |                 "north": { "uv": [ 0, 0, 12, 12 ], "texture": "#frame_front" }, | ||||||
|                 "south": { "uv": [ 5.75, 5.75, 2.75, 2.75 ], "texture": "#texture" }, |                 "south": { "uv": [ 0, 0, 12, 12 ], "texture": "#frame_back" }, | ||||||
|                 "west": { "uv": [ 8.5, 5.75, 5.75, 2.75 ], "texture": "#texture" }, |                 "west": { "uv": [ 0, 0, 11, 12 ], "texture": "#frame_left" }, | ||||||
|                 "east": { "uv": [ 2.75, 5.75, 0, 2.75 ], "texture": "#texture" } |                 "east": { "uv": [ 0, 0, 11, 12 ], "texture": "#frame_right" } | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "from": [ 3, 6, 13 ], |             "from": [ 3, 6, 13 ], | ||||||
|             "to": [ 13, 13, 15 ], |             "to": [ 13, 13, 15 ], | ||||||
|             "faces": { |             "faces": { | ||||||
|                 "down": { "uv": [ 11.75, 0.5, 9.25, 0 ], "texture": "#texture" }, |                 "down": { "uv": [ 2, 9, 12, 11 ], "texture": "#frame_backpack" }, | ||||||
|                 "up": { "uv": [ 14.25, 0, 11.75, 0.5 ], "texture": "#texture" }, |                 "up": { "uv": [ 2, 0, 12, 2 ], "texture": "#frame_backpack" }, | ||||||
|                 "south": { "uv": [ 11.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, |                 "south": { "uv": [ 2, 2, 12, 9 ], "texture": "#frame_backpack" }, | ||||||
|                 "west": { "uv": [ 12.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, |                 "west": { "uv": [ 0, 2, 2, 9 ], "texture": "#frame_backpack" }, | ||||||
|                 "east": { "uv": [ 9.25, 2.25, 8.75, 0.5 ], "texture": "#texture" } |                 "east": { "uv": [ 12, 2, 14, 9 ], "texture": "#frame_backpack" } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     ] |     ] | ||||||
|   | |||||||
| @@ -1,6 +1,35 @@ | |||||||
| { | { | ||||||
|     "parent": "computercraft:block/turtle_overlay", |     "parent": "block/block", | ||||||
|     "textures": { |     "textures": { | ||||||
|         "texture": "computercraft:block/turtle_elf_overlay" |       "back": "computercraft:block/turtle_elf_overlay_back", | ||||||
|     } |       "backpack": "computercraft:block/turtle_elf_overlay_backpack", | ||||||
| } |       "front": "computercraft:block/turtle_elf_overlay_front", | ||||||
|  |       "left": "computercraft:block/turtle_elf_overlay_left", | ||||||
|  |       "right": "computercraft:block/turtle_elf_overlay_right", | ||||||
|  |       "top": "computercraft:block/turtle_elf_overlay_top" | ||||||
|  |     }, | ||||||
|  |     "elements": [ | ||||||
|  |         { | ||||||
|  |             "from": [ 2, 2, 2 ], | ||||||
|  |             "to": [ 14, 14, 13 ], | ||||||
|  |             "faces": { | ||||||
|  |                 "up": { "uv": [ 0, 0, 12, 11 ], "texture": "#top" }, | ||||||
|  |                 "north": { "uv": [ 0, 0, 12, 12 ], "texture": "#front" }, | ||||||
|  |                 "south": { "uv": [ 0, 0, 12, 12 ], "texture": "#back" }, | ||||||
|  |                 "west": { "uv": [ 0, 0, 11, 12 ], "texture": "#left" }, | ||||||
|  |                 "east": { "uv": [ 0, 0, 11, 12 ], "texture": "#right" } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "from": [ 3, 6, 13 ], | ||||||
|  |             "to": [ 13, 13, 15 ], | ||||||
|  |             "faces": { | ||||||
|  |                 "down": { "uv": [ 2, 9, 12, 11 ], "texture": "#backpack" }, | ||||||
|  |                 "up": { "uv": [ 2, 0, 12, 2 ], "texture": "#backpack" }, | ||||||
|  |                 "south": { "uv": [ 2, 2, 12, 9 ], "texture": "#backpack" }, | ||||||
|  |                 "west": { "uv": [ 0, 2, 2, 9 ], "texture": "#backpack" }, | ||||||
|  |                 "east": { "uv": [ 12, 2, 14, 9 ], "texture": "#backpack" } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  |   } | ||||||
|   | |||||||
| @@ -1,43 +0,0 @@ | |||||||
| { |  | ||||||
|     "parent": "block/block", |  | ||||||
|     "textures": { |  | ||||||
|         "particle": "#texture" |  | ||||||
|     }, |  | ||||||
|     "elements": [ |  | ||||||
|         { |  | ||||||
|             "from": [ 2, 2, 2 ], |  | ||||||
|             "to": [ 14, 14, 13 ], |  | ||||||
|             "faces": { |  | ||||||
|                 "down": { "uv": [ 2.75, 0, 5.75, 2.75 ], "texture": "#texture" }, |  | ||||||
|                 "up": { "uv": [ 5.75, 0, 8.75, 2.75 ], "texture": "#texture" }, |  | ||||||
|                 "north": { "uv": [ 8.5, 5.75, 11.5, 2.75 ], "texture": "#texture" }, |  | ||||||
|                 "south": { "uv": [ 2.75, 5.75, 5.75, 2.75 ], "texture": "#texture" }, |  | ||||||
|                 "west": { "uv": [ 0, 5.75, 2.75, 2.75 ], "texture": "#texture" }, |  | ||||||
|                 "east": { "uv": [ 5.75, 5.75, 8.5, 2.75 ], "texture": "#texture" } |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         { |  | ||||||
|             "from": [ 3, 6, 13 ], |  | ||||||
|             "to": [ 13, 13, 15 ], |  | ||||||
|             "faces": { |  | ||||||
|                 "down": { "uv": [ 9.25, 0, 11.75, 0.5 ], "texture": "#texture" }, |  | ||||||
|                 "up": { "uv": [ 11.75, 0, 14.25, 0.5 ], "texture": "#texture" }, |  | ||||||
|                 "south": { "uv": [ 9.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, |  | ||||||
|                 "west": { "uv": [ 8.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, |  | ||||||
|                 "east": { "uv": [ 11.75, 2.25, 12.25, 0.5 ], "texture": "#texture" } |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         { |  | ||||||
|             "from": [ 1.5, 1.5, 1.5 ], |  | ||||||
|             "to": [ 14.5, 14.5, 13.5 ], |  | ||||||
|             "faces": { |  | ||||||
|                 "down": { "uv": [ 2.75, 8, 5.75, 10.75 ], "texture": "#texture" }, |  | ||||||
|                 "up": { "uv": [ 5.75, 8, 8.75, 10.75 ], "texture": "#texture" }, |  | ||||||
|                 "north": { "uv": [ 8.5, 13.75, 11.5, 10.75 ], "texture": "#texture" }, |  | ||||||
|                 "south": { "uv": [ 2.75, 13.75, 5.75, 10.75 ], "texture": "#texture" }, |  | ||||||
|                 "west": { "uv": [ 0, 13.75, 2.75, 10.75 ], "texture": "#texture" }, |  | ||||||
|                 "east": { "uv": [ 5.75, 13.75, 8.5, 10.75 ], "texture": "#texture" } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     ] |  | ||||||
| } |  | ||||||
| Before Width: | Height: | Size: 1.6 KiB | 
| After Width: | Height: | Size: 533 B | 
| After Width: | Height: | Size: 489 B | 
| After Width: | Height: | Size: 421 B | 
| After Width: | Height: | Size: 495 B | 
| After Width: | Height: | Size: 502 B | 
| After Width: | Height: | Size: 517 B | 
| After Width: | Height: | Size: 490 B | 
| Before Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 258 B | 
| After Width: | Height: | Size: 229 B | 
| After Width: | Height: | Size: 361 B | 
| After Width: | Height: | Size: 247 B | 
| After Width: | Height: | Size: 292 B | 
| After Width: | Height: | Size: 253 B | 
| After Width: | Height: | Size: 168 B | 
| After Width: | Height: | Size: 235 B | 
| After Width: | Height: | Size: 191 B | 
| After Width: | Height: | Size: 233 B | 
| After Width: | Height: | Size: 203 B | 
| After Width: | Height: | Size: 225 B | 
| After Width: | Height: | Size: 184 B | 
| After Width: | Height: | Size: 185 B | 
| Before Width: | Height: | Size: 1.6 KiB | 
| After Width: | Height: | Size: 338 B | 
| After Width: | Height: | Size: 483 B | 
| After Width: | Height: | Size: 234 B | 
| After Width: | Height: | Size: 233 B | 
| After Width: | Height: | Size: 272 B | 
| After Width: | Height: | Size: 590 B | 
| Before Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 397 B | 
| After Width: | Height: | Size: 287 B | 
| After Width: | Height: | Size: 350 B | 
| After Width: | Height: | Size: 410 B | 
| After Width: | Height: | Size: 408 B | 
| After Width: | Height: | Size: 393 B | 
| After Width: | Height: | Size: 340 B | 
| Before Width: | Height: | Size: 596 B After Width: | Height: | Size: 186 B | 
| Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 154 B | 
| @@ -42,6 +42,7 @@ class GameTestSequenceMixin { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Shadow |     @Shadow | ||||||
|  |     @SuppressWarnings("unused") | ||||||
|     private void tick(long tick) { |     private void tick(long tick) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ class MinecraftMixin implements MinecraftExtensions { | |||||||
|     private final AtomicBoolean isStable = new AtomicBoolean(false); |     private final AtomicBoolean isStable = new AtomicBoolean(false); | ||||||
| 
 | 
 | ||||||
|     @Inject(method = "runTick", at = @At("TAIL")) |     @Inject(method = "runTick", at = @At("TAIL")) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void updateStable(boolean render, CallbackInfo ci) { |     private void updateStable(boolean render, CallbackInfo ci) { | ||||||
|         isStable.set( |         isStable.set( | ||||||
|             level != null && player != null && |             level != null && player != null && | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ public class WorldOpenFlowsMixin { | |||||||
|      * @reason Makes it easier to run tests. We can switch to an @Inject if this becomes a problem. |      * @reason Makes it easier to run tests. We can switch to an @Inject if this becomes a problem. | ||||||
|      */ |      */ | ||||||
|     @Overwrite |     @Overwrite | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void askForBackup(LevelStorageSource.LevelStorageAccess access, boolean customised, Runnable load, Runnable cancel) { |     private void askForBackup(LevelStorageSource.LevelStorageAccess access, boolean customised, Runnable load, Runnable cancel) { | ||||||
|         load.run(); |         load.run(); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -309,10 +309,10 @@ public class FSAPI implements ILuaAPI { | |||||||
|      * <p> |      * <p> | ||||||
|      * The {@code mode} string can be any of the following: |      * The {@code mode} string can be any of the following: | ||||||
|      * <ul> |      * <ul> | ||||||
|      * <li><strong>"r"</strong>: Read mode</li> |      * <li><strong>"r"</strong>: Read mode.</li> | ||||||
|      * <li><strong>"w"</strong>: Write mode</li> |      * <li><strong>"w"</strong>: Write mode.</li> | ||||||
|      * <li><strong>"a"</strong>: Append mode</li> |      * <li><strong>"a"</strong>: Append mode.</li> | ||||||
|      * <li><strong>"r+"</strong>: Update mode (allows reading and writing), all data is preserved</li> |      * <li><strong>"r+"</strong>: Update mode (allows reading and writing), all data is preserved.</li> | ||||||
|      * <li><strong>"w+"</strong>: Update mode, all data is erased.</li> |      * <li><strong>"w+"</strong>: Update mode, all data is erased.</li> | ||||||
|      * </ul> |      * </ul> | ||||||
|      * <p> |      * <p> | ||||||
|   | |||||||
| @@ -365,24 +365,26 @@ end | |||||||
| -- or [`nil`], plus an error message. | -- or [`nil`], plus an error message. | ||||||
| -- | -- | ||||||
| -- The `mode` string can be any of the following: | -- The `mode` string can be any of the following: | ||||||
| --  - **"r"**: Read mode | --  - **"r"**: Read mode. | ||||||
| --  - **"w"**: Write mode | --  - **"w"**: Write mode. | ||||||
| --  - **"a"**: Append mode | --  - **"a"**: Append mode. | ||||||
|  | --  - **"r+"**: Update mode (allows reading and writing), all data is preserved. | ||||||
|  | --  - **"w+"**: Update mode, all data is erased. | ||||||
| -- | -- | ||||||
| -- The mode may also have a `b` at the end, which opens the file in "binary | -- The mode may also have a `b` at the end, which opens the file in "binary | ||||||
| -- mode". This allows you to read binary files, as well as seek within a file. | -- mode". This has no impact on functionality. | ||||||
| -- | -- | ||||||
| -- @tparam string filename The name of the file to open. | -- @tparam string filename The name of the file to open. | ||||||
| -- @tparam[opt] string mode The mode to open the file with. This defaults to `rb`. | -- @tparam[opt] string mode The mode to open the file with. This defaults to `r`. | ||||||
| -- @treturn[1] Handle The opened file. | -- @treturn[1] Handle The opened file. | ||||||
| -- @treturn[2] nil In case of an error. | -- @treturn[2] nil In case of an error. | ||||||
| -- @treturn[2] string The reason the file could not be opened. | -- @treturn[2] string The reason the file could not be opened. | ||||||
|  | -- @changed 1.111.0 Add support for `r+` and `w+`. | ||||||
| function open(filename, mode) | function open(filename, mode) | ||||||
|     expect(1, filename, "string") |     expect(1, filename, "string") | ||||||
|     expect(2, mode, "string", "nil") |     expect(2, mode, "string", "nil") | ||||||
|  |  | ||||||
|     local sMode = mode and mode:gsub("%+", "") or "r" |     local file, err = fs.open(filename, mode or "r") | ||||||
|     local file, err = fs.open(filename, sMode) |  | ||||||
|     if not file then return nil, err end |     if not file then return nil, err end | ||||||
|  |  | ||||||
|     return make_file(file) |     return make_file(file) | ||||||
|   | |||||||
| @@ -149,7 +149,7 @@ function isOpen(modem) | |||||||
| end | end | ||||||
|  |  | ||||||
| --[[- Allows a computer or turtle with an attached modem to send a message | --[[- Allows a computer or turtle with an attached modem to send a message | ||||||
| intended for a sycomputer with a specific ID. At least one such modem must first | intended for a computer with a specific ID. At least one such modem must first | ||||||
| be [opened][`rednet.open`] before sending is possible. | be [opened][`rednet.open`] before sending is possible. | ||||||
|  |  | ||||||
| Assuming the target was in range and also had a correctly opened modem, the | Assuming the target was in range and also had a correctly opened modem, the | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ When a computer starts, it reads the current value of settings from the | |||||||
|     settings.define("my.setting", { |     settings.define("my.setting", { | ||||||
|         description = "An example setting", |         description = "An example setting", | ||||||
|         default = 123, |         default = 123, | ||||||
|         type = number, |         type = "number", | ||||||
|     }) |     }) | ||||||
|     print("my.setting = " .. settings.get("my.setting")) -- 123 |     print("my.setting = " .. settings.get("my.setting")) -- 123 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,3 +1,15 @@ | |||||||
|  | # New features in CC: Tweaked 1.111.0 | ||||||
|  | 
 | ||||||
|  | * Update several translations (Ale32bit). | ||||||
|  | * Split up turtle textures into individual textures. | ||||||
|  | * Add `r+`/`w+` support to the `io` library. | ||||||
|  | * Warn when capabilities are not registered and Optifine is installed. | ||||||
|  | 
 | ||||||
|  | Several bug fixes: | ||||||
|  | * Allow planks to be used for building in "adventure" (dan200). | ||||||
|  | * Fix `disk.getAudioTitle()` returning untranslated strings for some modded discs. | ||||||
|  | * Fix crash when right clicking turtles in spectator. | ||||||
|  | 
 | ||||||
| # New features in CC: Tweaked 1.110.3 | # New features in CC: Tweaked 1.110.3 | ||||||
| 
 | 
 | ||||||
| * Update several translations (PatriikPlays). | * Update several translations (PatriikPlays). | ||||||
|   | |||||||
| @@ -1,9 +1,13 @@ | |||||||
| New features in CC: Tweaked 1.110.3 | New features in CC: Tweaked 1.111.0 | ||||||
| 
 | 
 | ||||||
| * Update several translations (PatriikPlays). | * Update several translations (Ale32bit). | ||||||
|  | * Split up turtle textures into individual textures. | ||||||
|  | * Add `r+`/`w+` support to the `io` library. | ||||||
|  | * Warn when capabilities are not registered and Optifine is installed. | ||||||
| 
 | 
 | ||||||
| Several bug fixes: | Several bug fixes: | ||||||
| * Fix some errors missing source positions. | * Allow planks to be used for building in "adventure" (dan200). | ||||||
| * Correctly handle multiple threads sending websocket messages at once. | * Fix `disk.getAudioTitle()` returning untranslated strings for some modded discs. | ||||||
|  | * Fix crash when right clicking turtles in spectator. | ||||||
| 
 | 
 | ||||||
| Type "help changelog" to see the full version history. | Type "help changelog" to see the full version history. | ||||||
|   | |||||||
| @@ -108,6 +108,7 @@ local items = { | |||||||
|     }, |     }, | ||||||
|     ["some planks"] = { |     ["some planks"] = { | ||||||
|         aliases = { "planks", "wooden planks", "wood planks" }, |         aliases = { "planks", "wooden planks", "wood planks" }, | ||||||
|  |         material = true, | ||||||
|         desc = "You could easily craft these planks into sticks.", |         desc = "You could easily craft these planks into sticks.", | ||||||
|     }, |     }, | ||||||
|     ["some sticks"] = { |     ["some sticks"] = { | ||||||
|   | |||||||
| @@ -329,4 +329,19 @@ describe("The io library", function() | |||||||
|             expect(read_all(file)):eq("alo\n " .. t .. " ;end of file\n") |             expect(read_all(file)):eq("alo\n " .. t .. " ;end of file\n") | ||||||
|         end) |         end) | ||||||
|     end) |     end) | ||||||
|  |  | ||||||
|  |     describe("read/write handles", function() | ||||||
|  |         it("can read and write to a file", function() | ||||||
|  |             write_file(file, "an example file") | ||||||
|  |  | ||||||
|  |             local handle = io.open(file, "r+") | ||||||
|  |             expect(handle:read(3)):eq("an ") | ||||||
|  |  | ||||||
|  |             handle:write("exciting file") | ||||||
|  |             expect(handle:seek("cur")):eq(16) | ||||||
|  |  | ||||||
|  |             handle:seek("set", 0) | ||||||
|  |             expect(handle:read("*a")):eq("an exciting file") | ||||||
|  |         end) | ||||||
|  |     end) | ||||||
| end) | end) | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ class GameRendererMixin { | |||||||
|     private Map<String, ShaderInstance> shaders; |     private Map<String, ShaderInstance> shaders; | ||||||
| 
 | 
 | ||||||
|     @Inject(method = "reloadShaders", at = @At(value = "TAIL")) |     @Inject(method = "reloadShaders", at = @At(value = "TAIL")) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void onReloadShaders(ResourceProvider resourceManager, CallbackInfo ci) { |     private void onReloadShaders(ResourceProvider resourceManager, CallbackInfo ci) { | ||||||
|         try { |         try { | ||||||
|             ClientRegistry.registerShaders(resourceManager, (shader, callback) -> { |             ClientRegistry.registerShaders(resourceManager, (shader, callback) -> { | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ class ItemFrameRendererMixin { | |||||||
|         at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 2, shift = At.Shift.AFTER), |         at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 2, shift = At.Shift.AFTER), | ||||||
|         cancellable = true |         cancellable = true | ||||||
|     ) |     ) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void render(ItemFrame entity, float yaw, float partialTicks, PoseStack pose, MultiBufferSource buffers, int light, CallbackInfo ci) { |     private void render(ItemFrame entity, float yaw, float partialTicks, PoseStack pose, MultiBufferSource buffers, int light, CallbackInfo ci) { | ||||||
|         if (ClientHooks.onRenderItemFrame(pose, buffers, entity, entity.getItem(), light)) { |         if (ClientHooks.onRenderItemFrame(pose, buffers, entity, entity.getItem(), light)) { | ||||||
|             ci.cancel(); |             ci.cancel(); | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; | |||||||
| @Mixin(ItemInHandRenderer.class) | @Mixin(ItemInHandRenderer.class) | ||||||
| class ItemInHandRendererMixin { | class ItemInHandRendererMixin { | ||||||
|     @Inject(method = "renderArmWithItem", at = @At("HEAD"), cancellable = true) |     @Inject(method = "renderArmWithItem", at = @At("HEAD"), cancellable = true) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void onRenderItem( |     private void onRenderItem( | ||||||
|         AbstractClientPlayer player, float partialTicks, float pitch, InteractionHand hand, float swingProgress, ItemStack stack, |         AbstractClientPlayer player, float partialTicks, float pitch, InteractionHand hand, float swingProgress, ItemStack stack, | ||||||
|         float equippedProgress, PoseStack transform, MultiBufferSource buffer, int combinedLight, CallbackInfo ci |         float equippedProgress, PoseStack transform, MultiBufferSource buffer, int combinedLight, CallbackInfo ci | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ class MinecraftMixin { | |||||||
|     private ReloadableResourceManager resourceManager; |     private ReloadableResourceManager resourceManager; | ||||||
| 
 | 
 | ||||||
|     @Inject(method = "updateLevelInEngines", at = @At("HEAD")) |     @Inject(method = "updateLevelInEngines", at = @At("HEAD")) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void updateLevelInEngines(ClientLevel screen, CallbackInfo ci) { |     private void updateLevelInEngines(ClientLevel screen, CallbackInfo ci) { | ||||||
|         ClientHooks.onWorldUnload(); |         ClientHooks.onWorldUnload(); | ||||||
|     } |     } | ||||||
| @@ -37,7 +37,7 @@ class MinecraftMixin { | |||||||
|             ordinal = 0 |             ordinal = 0 | ||||||
|         ) |         ) | ||||||
|     ) |     ) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void beforeInitialResourceReload(GameConfig gameConfig, CallbackInfo ci) { |     private void beforeInitialResourceReload(GameConfig gameConfig, CallbackInfo ci) { | ||||||
|         ClientRegistry.registerReloadListeners(resourceManager::registerReloadListener, (Minecraft) (Object) this); |         ClientRegistry.registerReloadListeners(resourceManager::registerReloadListener, (Minecraft) (Object) this); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -31,7 +31,7 @@ class MultiPlayerGameModeMixin { | |||||||
|         cancellable = true, |         cancellable = true, | ||||||
|         locals = LocalCapture.CAPTURE_FAILHARD |         locals = LocalCapture.CAPTURE_FAILHARD | ||||||
|     ) |     ) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void onBlockBreak(BlockPos pos, CallbackInfoReturnable<Boolean> cir, Level level, BlockState state, Block block) { |     private void onBlockBreak(BlockPos pos, CallbackInfoReturnable<Boolean> cir, Level level, BlockState state, Block block) { | ||||||
|         if (!FabricCommonHooks.onBlockDestroy(level, minecraft.player, pos, state, null)) cir.setReturnValue(true); |         if (!FabricCommonHooks.onBlockDestroy(level, minecraft.player, pos, state, null)) cir.setReturnValue(true); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -26,13 +26,13 @@ class SoundEngineMixin { | |||||||
|     private static SoundEngine self; |     private static SoundEngine self; | ||||||
| 
 | 
 | ||||||
|     @Inject(method = "play", at = @At(value = "HEAD")) |     @Inject(method = "play", at = @At(value = "HEAD")) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void playSound(SoundInstance sound, CallbackInfo ci) { |     private void playSound(SoundInstance sound, CallbackInfo ci) { | ||||||
|         self = (SoundEngine) (Object) this; |         self = (SoundEngine) (Object) this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Inject(at = @At("TAIL"), method = "method_19755") |     @Inject(at = @At("TAIL"), method = "method_19755") | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private static void onStream(AudioStream stream, Channel channel, CallbackInfo ci) { |     private static void onStream(AudioStream stream, Channel channel, CallbackInfo ci) { | ||||||
|         SpeakerManager.onPlayStreaming(assertNonNull(self), channel, stream); |         SpeakerManager.onPlayStreaming(assertNonNull(self), channel, stream); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ class ChunkMapMixin { | |||||||
|     ServerLevel level; |     ServerLevel level; | ||||||
| 
 | 
 | ||||||
|     @Inject(method = "updateChunkScheduling", at = @At("HEAD")) |     @Inject(method = "updateChunkScheduling", at = @At("HEAD")) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void onUpdateChunkScheduling(long chunkPos, int newLevel, @Nullable ChunkHolder holder, int oldLevel, CallbackInfoReturnable<ChunkHolder> callback) { |     private void onUpdateChunkScheduling(long chunkPos, int newLevel, @Nullable ChunkHolder holder, int oldLevel, CallbackInfoReturnable<ChunkHolder> callback) { | ||||||
|         CommonHooks.onChunkTicketLevelChanged(level, chunkPos, oldLevel, newLevel); |         CommonHooks.onChunkTicketLevelChanged(level, chunkPos, oldLevel, newLevel); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ class EntityMixin { | |||||||
|         at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"), |         at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"), | ||||||
|         cancellable = true |         cancellable = true | ||||||
|     ) |     ) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void spawnAtLocation(ItemStack stack, float yOffset, CallbackInfoReturnable<ItemEntity> cb) { |     private void spawnAtLocation(ItemStack stack, float yOffset, CallbackInfoReturnable<ItemEntity> cb) { | ||||||
|         if (CommonHooks.onLivingDrop((Entity) (Object) this, stack)) cb.setReturnValue(null); |         if (CommonHooks.onLivingDrop((Entity) (Object) this, stack)) cb.setReturnValue(null); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; | |||||||
| @Mixin(ItemEntity.class) | @Mixin(ItemEntity.class) | ||||||
| abstract class ItemEntityMixin { | abstract class ItemEntityMixin { | ||||||
|     @Inject(method = "tick", at = @At("HEAD")) |     @Inject(method = "tick", at = @At("HEAD")) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private void onTick(CallbackInfo ci) { |     private void onTick(CallbackInfo ci) { | ||||||
|         var stack = getItem(); |         var stack = getItem(); | ||||||
|         if (stack.getItem() instanceof PocketComputerItem pocket) { |         if (stack.getItem() instanceof PocketComputerItem pocket) { | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ import java.util.function.Predicate; | |||||||
| @Mixin(TagsProvider.class) | @Mixin(TagsProvider.class) | ||||||
| class TagsProviderMixin { | class TagsProviderMixin { | ||||||
|     @Inject(at = @At("HEAD"), method = "method_49658", cancellable = true) |     @Inject(at = @At("HEAD"), method = "method_49658", cancellable = true) | ||||||
|     @SuppressWarnings("UnusedMethod") |     @SuppressWarnings("unused") | ||||||
|     private static void onVerifyPresent(Predicate<?> predicate1, Predicate<?> predicate2, TagEntry tag, CallbackInfoReturnable<Boolean> cir) { |     private static void onVerifyPresent(Predicate<?> predicate1, Predicate<?> predicate2, TagEntry tag, CallbackInfoReturnable<Boolean> cir) { | ||||||
|         var element = ((TagEntryAccessor) tag).computercraft$elementOrTag(); |         var element = ((TagEntryAccessor) tag).computercraft$elementOrTag(); | ||||||
|         if (element.tag() && element.id().getNamespace().equals("minecraft")) cir.setReturnValue(false); |         if (element.tag() && element.id().getNamespace().equals("minecraft")) cir.setReturnValue(false); | ||||||
|   | |||||||
							
								
								
									
										51
									
								
								tools/update-resources.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| @@ -76,6 +76,45 @@ def unstitch_corners(input_file: pathlib.Path, family: str): | |||||||
|         sidebar.save(output_dir / f"sidebar_{family}.png") |         sidebar.save(output_dir / f"sidebar_{family}.png") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def unstitch_turtle(input_file: pathlib.Path, family: str, *, dy: int = 0): | ||||||
|  |     input = Image.open(input_file) | ||||||
|  |     output_dir = input_file.parent | ||||||
|  |  | ||||||
|  |     fragments = [ | ||||||
|  |         ("bottom", 22, 0, 24, 22, Image.Transpose.ROTATE_180), | ||||||
|  |         ("top", 46, 0, 24, 22, Image.Transpose.FLIP_LEFT_RIGHT), | ||||||
|  |         ("right", 0, 22, 22, 24, Image.Transpose.ROTATE_180), | ||||||
|  |         ("back", 22, 22, 24, 24, Image.Transpose.ROTATE_180), | ||||||
|  |         ("left", 46, 22, 22, 24, Image.Transpose.ROTATE_180), | ||||||
|  |         ("front", 68, 22, 24, 24, Image.Transpose.ROTATE_180), | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |     for suffix, x, y, w, h, transform in fragments: | ||||||
|  |         if family == "elf_overlay" and suffix == "bottom": | ||||||
|  |             continue | ||||||
|  |  | ||||||
|  |         slice = input.crop(box(x, dy + y, w, h)).transpose(transform) | ||||||
|  |  | ||||||
|  |         fragment = Image.new("RGBA", (32, 32)) | ||||||
|  |         fragment.paste(slice) | ||||||
|  |         fragment.save(output_dir / f"turtle_{family}_{suffix}.png") | ||||||
|  |  | ||||||
|  |     backpack = Image.new("RGBA", (32, 32)) | ||||||
|  |     backpack.paste( | ||||||
|  |         input.crop(box(70, dy + 4, 28, 14)).transpose(Image.Transpose.ROTATE_180), | ||||||
|  |         (0, 4), | ||||||
|  |     ) | ||||||
|  |     backpack.paste( | ||||||
|  |         input.crop(box(74, dy + 0, 20, 4)).transpose(Image.Transpose.ROTATE_180), | ||||||
|  |         (4, 18), | ||||||
|  |     ) | ||||||
|  |     backpack.paste( | ||||||
|  |         input.crop(box(94, dy + 0, 20, 4)).transpose(Image.Transpose.FLIP_LEFT_RIGHT), | ||||||
|  |         (4, 0), | ||||||
|  |     ) | ||||||
|  |     backpack.save(output_dir / f"turtle_{family}_backpack.png") | ||||||
|  |  | ||||||
|  |  | ||||||
| def main() -> None: | def main() -> None: | ||||||
|     spec = argparse.ArgumentParser() |     spec = argparse.ArgumentParser() | ||||||
|     spec.add_argument("dir", type=pathlib.Path) |     spec.add_argument("dir", type=pathlib.Path) | ||||||
| @@ -97,6 +136,18 @@ def main() -> None: | |||||||
|             unstitch_corners(path, family) |             unstitch_corners(path, family) | ||||||
|             transformed.append(path) |             transformed.append(path) | ||||||
|  |  | ||||||
|  |     for family in ("normal", "advanced", "elf_overlay"): | ||||||
|  |         path = texture_path / "block" / f"turtle_{family}.png" | ||||||
|  |         if path.exists(): | ||||||
|  |             unstitch_turtle(path, family) | ||||||
|  |             transformed.append(path) | ||||||
|  |  | ||||||
|  |     path = texture_path / "block" / f"turtle_colour.png" | ||||||
|  |     if path.exists(): | ||||||
|  |         unstitch_turtle(path, "colour_frame") | ||||||
|  |         unstitch_turtle(path, "colour_body", dy=46) | ||||||
|  |         transformed.append(path) | ||||||
|  |  | ||||||
|     if len(transformed) == 0: |     if len(transformed) == 0: | ||||||
|         print("No files were transformed") |         print("No files were transformed") | ||||||
|         return |         return | ||||||
|   | |||||||
 Jonathan Coates
					Jonathan Coates