1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-17 15:07:38 +00:00

Compare commits

...

12 Commits

Author SHA1 Message Date
Jonathan Coates
209b1ddbf9 Bump CC:T to 1.111.0 2024-05-28 18:19:13 +01:00
Jonathan Coates
0c9f9a8652 Warn when Optifine is installed
We keep getting bug reports on 1.20.1 about an Optifine bug that causes
Forge's capabilities to not work (#1458). The cause of this bug is not
immediately visible to users, and can be very confusing when hit.

Optifine have not released a fix for this bug (despite it being reported
a year ago), and we continue to receive bug reports about it.

Nobody likes it when mods complain about other mods. So much Minecraft
drama can be traced back to this, and it's a slippery slope to go down.
I've tried to keep this as unobtrusive as possible — it's just a chat
message at world join, and it'll turn off if the bug is fixed.
2024-05-28 18:10:50 +01:00
Jonathan Coates
862d92785e Don't expose a menu provider for computers
We can't safely use this anyway (as custom data is not sent), so better
not to expose it at all. Fixes #1844.
2024-05-28 09:47:12 +01:00
Jonathan Coates
d48b85d50c Add r+/w+ support to io library 2024-05-26 10:16:33 +01:00
Jonathan Coates
4d619de357 Don't publish Gradle module metadata for common
Fixes #1842
2024-05-26 09:34:10 +01:00
Daniel Ratcliffe
57c289f173 Allow planks to be used for building in "adventure" 2024-05-25 10:04:45 +01:00
Jonathan Coates
f63f85921f Fix missing quotes in the settings example 2024-05-19 08:38:41 +01:00
Jonathan Coates
c7e49d1929 Use RecordItem.getDisplayName to get audio title
Rather than constructing the component manually. This should be more
compatible with mods that override getDisplayName.
2024-05-09 22:54:03 +01:00
Jonathan Coates
1e214f329e Build docs for all MC versions 2024-05-06 09:59:09 +01:00
Jonathan Coates
de930c8d09 Split up turtle textures (#1813)
Turtles currently read their textures from a single 128x128 sprite
sheet. Most of this texture is unused which means we end up wasting a
lot of the block texture atlas[^1].

This change splits up the turtle textures into individual 32x32
textures[^2], one for each side, and then an additional backpack
texture.

I'm very sorry to any resource pack artists out there. The
tools/update-resources.py script will update existing packs, but does
not (currently) handle non-standard resolutions.

[^1]: It used to be worse: https://github.com/dan200/ComputerCraft/issues/145

[^2]: Turtle textures are a bit weird, in that they mostly *look* 16x16,
  but have some detail in places.
2024-04-30 20:58:07 +00:00
Weblate
735e7ce09b Translations for Italian
Co-authored-by: Alessandro <ale.proto00@gmail.com>
2024-04-29 19:00:14 +00:00
Jonathan Coates
6e9799316a Update ErrorProne 2024-04-28 18:32:19 +01:00
84 changed files with 358 additions and 151 deletions

View File

@@ -3,8 +3,7 @@ name: Build documentation
on:
push:
branches:
- mc-1.19.x
- mc-1.20.x
- mc-*
jobs:
make_doc:

View File

@@ -94,9 +94,8 @@ sourceSets.all {
check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally
// Too many false positives right now. Maybe we need an indirection for it later on.
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("AlreadyChecked", CheckSeverity.OFF) // Seems to be broken?
check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty

View File

@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.io.File
import java.io.IOException
import java.net.URI
import java.net.URL
import java.util.regex.Pattern
abstract class CCTweakedExtension(
@@ -226,12 +225,12 @@ abstract class CCTweakedExtension(
* where possible.
*/
fun downloadFile(label: String, url: String): File {
val url = URL(url)
val path = File(url.path)
val uri = URI(url)
val path = File(uri.path)
project.repositories.ivy {
name = label
setUrl(URI(url.protocol, 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 {
artifact("[artifact].[ext]")
}

View File

@@ -98,7 +98,6 @@ abstract class MergeTrees : DefaultTask() {
}
val sharedFiles = files.entries.asSequence().filter { (_, v) -> v.found == sources.size }.map { (k, _) -> k }.toList()
println(sharedFiles)
// Copy shared files to the common directory
fsOperations.sync {

View File

@@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error
# Mod properties
isUnstable=false
modVersion=1.110.3
modVersion=1.111.0
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
mcVersion=1.20.1

View File

@@ -57,7 +57,7 @@ jmh = "1.37"
cctJavadoc = "1.8.2"
checkstyle = "10.14.1"
curseForgeGradle = "1.0.14"
errorProne-core = "2.23.0"
errorProne-core = "2.27.0"
errorProne-plugin = "3.1.0"
fabric-loom = "1.6.7"
forgeGradle = "6.0.21"

View File

@@ -127,3 +127,5 @@ val runData by tasks.registering(MergeTrees::class) {
}
}
}
tasks.withType(GenerateModuleMetadata::class).configureEach { isEnabled = false }

View File

@@ -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"
}
}

View File

@@ -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"
}
}

View File

@@ -38,6 +38,9 @@ import static net.minecraft.data.models.model.TextureMapping.getBlockTexture;
class BlockModelProvider {
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(
Optional.of(new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/computer_on")),
@@ -58,7 +61,7 @@ class BlockModelProvider {
private static final ModelTemplate TURTLE = new ModelTemplate(
Optional.of(new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_base")),
Optional.empty(),
TextureSlot.TEXTURE
TextureSlot.FRONT, TextureSlot.BACK, TextureSlot.TOP, TextureSlot.BOTTOM, LEFT, RIGHT, BACKPACK
);
private static final ModelTemplate TURTLE_UPGRADE_LEFT = new ModelTemplate(
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) {
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(
MultiVariantGenerator.multiVariant(block, Variant.variant().with(VariantProperties.MODEL, model))
.with(createHorizontalFacingDispatch())

View File

@@ -18,7 +18,6 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
@@ -196,13 +195,6 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Nullable
@Override
@Deprecated
public MenuProvider getMenuProvider(BlockState state, Level level, BlockPos pos) {
return level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer ? computer : null;
}
@Override
@Nullable
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {

View File

@@ -5,7 +5,6 @@
package dan200.computercraft.shared.media.items;
import dan200.computercraft.api.media.IMedia;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.RecordItem;
@@ -13,7 +12,7 @@ import net.minecraft.world.item.RecordItem;
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 static final RecordMedia INSTANCE = new RecordMedia();
@@ -29,16 +28,12 @@ public final class RecordMedia implements IMedia {
@Override
public @Nullable String getAudioTitle(ItemStack stack) {
var item = stack.getItem();
if (!(item instanceof RecordItem)) return null;
return Component.translatable(item.getDescriptionId() + ".desc").getString();
return item instanceof RecordItem record ? record.getDisplayName().getString() : null;
}
@Override
public @Nullable SoundEvent getAudio(ItemStack stack) {
var item = stack.getItem();
if (!(item instanceof RecordItem)) return null;
return ((RecordItem) item).getSound();
return item instanceof RecordItem record ? record.getSound() : null;
}
}

View File

@@ -13,8 +13,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.ArrayList;
@@ -29,8 +27,6 @@ import java.util.Objects;
* @param <C> A platform-specific type, used for the invalidation callback.
*/
public final class GenericPeripheralProvider<C extends Runnable> {
private static final Logger LOG = LoggerFactory.getLogger(GenericPeripheralProvider.class);
private final List<ComponentLookup<? super C>> lookups = new ArrayList<>();
/**

View File

@@ -33,7 +33,6 @@ public final class IDAssigner {
private final Path idFile;
private final Path newIdFile;
private boolean atomicMove = true;
private @Nullable Map<String, Integer> ids;
public IDAssigner(Path path) {

View File

@@ -4,6 +4,7 @@
package dan200.computercraft.shared.util;
import com.google.errorprone.annotations.Keep;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ChunkLevel;
@@ -132,6 +133,7 @@ public final class TickScheduler {
/**
* The current state of this token.
*/
@Keep
private volatile State $state = State.IDLE;
public Token(BlockEntity owner) {

View File

@@ -218,5 +218,18 @@
"upgrade.minecraft.diamond_hoe.adjective": "Contadina",
"upgrade.minecraft.diamond_pickaxe.adjective": "Minatrice",
"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"
}

View File

@@ -2,30 +2,30 @@
"parent": "block/block",
"render_type": "translucent",
"textures": {
"particle": "#texture"
"particle": "#front"
},
"elements": [
{
"from": [ 2, 2, 2 ],
"to": [ 14, 14, 13 ],
"faces": {
"down": { "uv": [ 5.75, 2.75, 2.75, 0 ], "texture": "#texture" },
"up": { "uv": [ 8.75, 0, 5.75, 2.75 ], "texture": "#texture" },
"north": { "uv": [ 11.5, 5.75, 8.5, 2.75 ], "texture": "#texture" },
"south": { "uv": [ 5.75, 5.75, 2.75, 2.75 ], "texture": "#texture" },
"west": { "uv": [ 8.5, 5.75, 5.75, 2.75 ], "texture": "#texture" },
"east": { "uv": [ 2.75, 5.75, 0, 2.75 ], "texture": "#texture" }
"down": { "uv": [ 0, 0, 12, 11 ], "texture": "#bottom" },
"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": [ 11.75, 0.5, 9.25, 0 ], "texture": "#texture" },
"up": { "uv": [ 14.25, 0, 11.75, 0.5 ], "texture": "#texture" },
"south": { "uv": [ 11.75, 2.25, 9.25, 0.5 ], "texture": "#texture" },
"west": { "uv": [ 12.25, 2.25, 11.75, 0.5 ], "texture": "#texture" },
"east": { "uv": [ 9.25, 2.25, 8.75, 0.5 ], "texture": "#texture" }
"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" }
}
}
]

View File

@@ -1,53 +1,67 @@
{
"parent": "computercraft:block/turtle_base",
"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": [
{
"from": [ 2, 2, 2 ],
"to": [ 14, 14, 13 ],
"faces": {
"down": { "uv": [ 5.75, 8.5, 2.75, 5.75 ], "texture": "#texture", "tintindex": 0 },
"up": { "uv": [ 8.75, 5.75, 5.75, 8.5 ], "texture": "#texture", "tintindex": 0 },
"north": { "uv": [ 11.5, 11.5, 8.5, 8.5 ], "texture": "#texture", "tintindex": 0 },
"south": { "uv": [ 5.75, 11.5, 2.75, 8.5 ], "texture": "#texture", "tintindex": 0 },
"west": { "uv": [ 8.5, 11.5, 5.75, 8.555 ], "texture": "#texture", "tintindex": 0 },
"east": { "uv": [ 2.75, 11.5, 0, 8.5 ], "texture": "#texture", "tintindex": 0 }
"down": { "uv": [ 0, 0, 12, 11 ], "texture": "#body_bottom", "tintindex": 0 },
"up": { "uv": [ 0, 0, 12, 11 ], "texture": "#body_top", "tintindex": 0 },
"north": { "uv": [ 0, 0, 12, 12 ], "texture": "#body_front", "tintindex": 0 },
"south": { "uv": [ 0, 0, 12, 12 ], "texture": "#body_back", "tintindex": 0 },
"west": { "uv": [ 0, 0, 11, 12 ], "texture": "#body_left", "tintindex": 0 },
"east": { "uv": [ 0, 0, 11, 12 ], "texture": "#body_right", "tintindex": 0 }
}
},
{
"from": [ 3, 6, 13 ],
"to": [ 13, 13, 15 ],
"faces": {
"down": { "uv": [ 11.75, 6.25, 9.25, 5.75 ], "texture": "#texture", "tintindex": 0 },
"up": { "uv": [ 14.25, 5.75, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 },
"south": { "uv": [ 11.75, 8, 9.25, 6.25 ], "texture": "#texture", "tintindex": 0 },
"west": { "uv": [ 12.25, 8, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 },
"east": { "uv": [ 9.25, 8, 8.75, 6.25 ], "texture": "#texture", "tintindex": 0 }
"down": { "uv": [ 2, 9, 12, 11 ], "texture": "#body_backpack", "tintindex": 0 },
"up": { "uv": [ 2, 0, 12, 2 ], "texture": "#body_backpack", "tintindex": 0 },
"south": { "uv": [ 2, 2, 12, 9 ], "texture": "#body_backpack", "tintindex": 0 },
"west": { "uv": [ 0, 2, 2, 9 ], "texture": "#body_backpack", "tintindex": 0 },
"east": { "uv": [ 12, 2, 14, 9 ], "texture": "#body_backpack", "tintindex": 0 }
}
},
{
"from": [ 2, 2, 2 ],
"to": [ 14, 14, 13 ],
"faces": {
"down": { "uv": [ 5.75, 2.75, 2.75, 0 ], "texture": "#texture" },
"up": { "uv": [ 8.75, 0, 5.75, 2.75 ], "texture": "#texture" },
"north": { "uv": [ 11.5, 5.75, 8.5, 2.75 ], "texture": "#texture" },
"south": { "uv": [ 5.75, 5.75, 2.75, 2.75 ], "texture": "#texture" },
"west": { "uv": [ 8.5, 5.75, 5.75, 2.75 ], "texture": "#texture" },
"east": { "uv": [ 2.75, 5.75, 0, 2.75 ], "texture": "#texture" }
"down": { "uv": [ 0, 0, 12, 11 ], "texture": "#frame_bottom" },
"up": { "uv": [ 0, 0, 12, 11 ], "texture": "#frame_top" },
"north": { "uv": [ 0, 0, 12, 12 ], "texture": "#frame_front" },
"south": { "uv": [ 0, 0, 12, 12 ], "texture": "#frame_back" },
"west": { "uv": [ 0, 0, 11, 12 ], "texture": "#frame_left" },
"east": { "uv": [ 0, 0, 11, 12 ], "texture": "#frame_right" }
}
},
{
"from": [ 3, 6, 13 ],
"to": [ 13, 13, 15 ],
"faces": {
"down": { "uv": [ 11.75, 0.5, 9.25, 0 ], "texture": "#texture" },
"up": { "uv": [ 14.25, 0, 11.75, 0.5 ], "texture": "#texture" },
"south": { "uv": [ 11.75, 2.25, 9.25, 0.5 ], "texture": "#texture" },
"west": { "uv": [ 12.25, 2.25, 11.75, 0.5 ], "texture": "#texture" },
"east": { "uv": [ 9.25, 2.25, 8.75, 0.5 ], "texture": "#texture" }
"down": { "uv": [ 2, 9, 12, 11 ], "texture": "#frame_backpack" },
"up": { "uv": [ 2, 0, 12, 2 ], "texture": "#frame_backpack" },
"south": { "uv": [ 2, 2, 12, 9 ], "texture": "#frame_backpack" },
"west": { "uv": [ 0, 2, 2, 9 ], "texture": "#frame_backpack" },
"east": { "uv": [ 12, 2, 14, 9 ], "texture": "#frame_backpack" }
}
}
]

View File

@@ -1,6 +1,35 @@
{
"parent": "computercraft:block/turtle_overlay",
"parent": "block/block",
"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" }
}
}
]
}

View File

@@ -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" }
}
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 596 B

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 154 B

View File

@@ -42,6 +42,7 @@ class GameTestSequenceMixin {
}
@Shadow
@SuppressWarnings("unused")
private void tick(long tick) {
}
}

View File

@@ -38,7 +38,7 @@ class MinecraftMixin implements MinecraftExtensions {
private final AtomicBoolean isStable = new AtomicBoolean(false);
@Inject(method = "runTick", at = @At("TAIL"))
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private void updateStable(boolean render, CallbackInfo ci) {
isStable.set(
level != null && player != null &&

View File

@@ -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.
*/
@Overwrite
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private void askForBackup(Screen screen, String level, boolean customised, Runnable action) {
action.run();
}

View File

@@ -309,10 +309,10 @@ public class FSAPI implements ILuaAPI {
* <p>
* The {@code mode} string can be any of the following:
* <ul>
* <li><strong>"r"</strong>: Read mode</li>
* <li><strong>"w"</strong>: Write 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>: Read mode.</li>
* <li><strong>"w"</strong>: Write 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>"w+"</strong>: Update mode, all data is erased.</li>
* </ul>
* <p>

View File

@@ -365,24 +365,26 @@ end
-- or [`nil`], plus an error message.
--
-- The `mode` string can be any of the following:
-- - **"r"**: Read mode
-- - **"w"**: Write mode
-- - **"a"**: Append mode
-- - **"r"**: Read mode.
-- - **"w"**: Write 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
-- 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[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[2] nil In case of an error.
-- @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)
expect(1, filename, "string")
expect(2, mode, "string", "nil")
local sMode = mode and mode:gsub("%+", "") or "r"
local file, err = fs.open(filename, sMode)
local file, err = fs.open(filename, mode or "r")
if not file then return nil, err end
return make_file(file)

View File

@@ -149,7 +149,7 @@ function isOpen(modem)
end
--[[- 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.
Assuming the target was in range and also had a correctly opened modem, the

View File

@@ -19,7 +19,7 @@ When a computer starts, it reads the current value of settings from the
settings.define("my.setting", {
description = "An example setting",
default = 123,
type = number,
type = "number",
})
print("my.setting = " .. settings.get("my.setting")) -- 123

View File

@@ -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
* Update several translations (PatriikPlays).

View File

@@ -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:
* Fix some errors missing source positions.
* Correctly handle multiple threads sending websocket messages at once.
* 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.
Type "help changelog" to see the full version history.

View File

@@ -108,6 +108,7 @@ local items = {
},
["some planks"] = {
aliases = { "planks", "wooden planks", "wood planks" },
material = true,
desc = "You could easily craft these planks into sticks.",
},
["some sticks"] = {

View File

@@ -329,4 +329,19 @@ describe("The io library", function()
expect(read_all(file)):eq("alo\n " .. t .. " ;end of file\n")
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)

View File

@@ -27,7 +27,7 @@ class GameRendererMixin {
private Map<String, ShaderInstance> shaders;
@Inject(method = "reloadShaders", at = @At(value = "TAIL"))
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private void onReloadShaders(ResourceProvider resourceManager, CallbackInfo ci) {
try {
ClientRegistry.registerShaders(resourceManager, (shader, callback) -> {

View File

@@ -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),
cancellable = true
)
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
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)) {
ci.cancel();

View File

@@ -19,7 +19,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ItemInHandRenderer.class)
class ItemInHandRendererMixin {
@Inject(method = "renderArmWithItem", at = @At("HEAD"), cancellable = true)
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private void onRenderItem(
AbstractClientPlayer player, float partialTicks, float pitch, InteractionHand hand, float swingProgress, ItemStack stack,
float equippedProgress, PoseStack transform, MultiBufferSource buffer, int combinedLight, CallbackInfo ci

View File

@@ -25,13 +25,13 @@ class MinecraftMixin {
private ReloadableResourceManager resourceManager;
@Inject(method = "clearLevel(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At("HEAD"))
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private void clearLevel(Screen screen, CallbackInfo ci) {
ClientHooks.onWorldUnload();
}
@Inject(method = "setLevel", at = @At("HEAD"))
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private void setLevel(ClientLevel screen, CallbackInfo ci) {
ClientHooks.onWorldUnload();
}
@@ -44,6 +44,7 @@ class MinecraftMixin {
ordinal = 0
)
)
@SuppressWarnings("unused")
public void beforeInitialResourceReload(GameConfig gameConfig, CallbackInfo ci) {
ClientRegistry.registerReloadListeners(resourceManager::registerReloadListener, (Minecraft) (Object) this);
}

View File

@@ -31,7 +31,7 @@ class MultiPlayerGameModeMixin {
cancellable = true,
locals = LocalCapture.CAPTURE_FAILHARD
)
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
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);
}

View File

@@ -26,13 +26,13 @@ class SoundEngineMixin {
private static SoundEngine self;
@Inject(method = "play", at = @At(value = "HEAD"))
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private void playSound(SoundInstance sound, CallbackInfo ci) {
self = (SoundEngine) (Object) this;
}
@Inject(at = @At("TAIL"), method = "method_19755")
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private static void onStream(AudioStream stream, Channel channel, CallbackInfo ci) {
SpeakerManager.onPlayStreaming(assertNonNull(self), channel, stream);
}

View File

@@ -29,13 +29,13 @@ class ChunkMapMixin {
ServerLevel level;
@Inject(method = "playerLoadedChunk", at = @At("TAIL"))
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private void onPlayerLoadedChunk(ServerPlayer player, MutableObject<ClientboundLevelChunkWithLightPacket> packetCache, LevelChunk chunk, CallbackInfo callback) {
CommonHooks.onChunkWatch(chunk, player);
}
@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) {
CommonHooks.onChunkTicketLevelChanged(level, chunkPos, oldLevel, newLevel);
}

View File

@@ -20,7 +20,7 @@ class EntityMixin {
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"),
cancellable = true
)
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private void spawnAtLocation(ItemStack stack, float yOffset, CallbackInfoReturnable<ItemEntity> cb) {
if (CommonHooks.onLivingDrop((Entity) (Object) this, stack)) cb.setReturnValue(null);
}

View File

@@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ItemEntity.class)
abstract class ItemEntityMixin {
@Inject(method = "tick", at = @At("HEAD"))
@SuppressWarnings("UnusedMethod")
@SuppressWarnings("unused")
private void onTick(CallbackInfo ci) {
var stack = getItem();
if (stack.getItem() instanceof PocketComputerItem pocket) {

View File

@@ -21,7 +21,7 @@ import java.util.function.Predicate;
@Mixin(TagsProvider.class)
class TagsProviderMixin {
@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) {
var element = ((TagEntryAccessor) tag).computercraft$elementOrTag();
if (element.tag() && element.id().getNamespace().equals("minecraft")) cir.setReturnValue(false);

View File

@@ -8,6 +8,7 @@ import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.command.CommandComputerCraft;
import dan200.computercraft.shared.computer.blocks.ComputerBlockEntity;
import dan200.computercraft.shared.config.Config;
import dan200.computercraft.shared.integration.Optifine;
import dan200.computercraft.shared.network.client.UpgradesLoadedMessage;
import dan200.computercraft.shared.network.server.ServerNetworking;
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral;
@@ -29,6 +30,7 @@ import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraftforge.event.*;
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.level.ChunkEvent;
import net.minecraftforge.event.level.ChunkTicketLevelUpdatedEvent;
import net.minecraftforge.event.level.ChunkWatchEvent;
@@ -61,6 +63,11 @@ public class ForgeCommonHooks {
CommonHooks.onServerStarting(event.getServer());
}
@SubscribeEvent
public static void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
Optifine.warnAboutOptifine(event.getEntity()::sendSystemMessage);
}
@SubscribeEvent
public static void onServerStopped(ServerStoppedEvent event) {
CommonHooks.onServerStopped();

View File

@@ -0,0 +1,84 @@
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.integration;
import dan200.computercraft.core.util.Nullability;
import dan200.computercraft.shared.Capabilities;
import dan200.computercraft.shared.ModRegistry;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.function.Consumer;
/**
* Detect whether Optifine is installed.
*/
public final class Optifine {
private static final boolean LOADED;
static {
boolean loaded;
try {
Class.forName("optifine.Installer", false, Optifine.class.getClassLoader());
loaded = true;
} catch (ReflectiveOperationException | LinkageError ignore) {
loaded = false;
}
LOADED = loaded;
}
private Optifine() {
}
public static boolean isLoaded() {
return LOADED;
}
/**
* This rant probably should be in a commit message, but sometimes I want it visible in the code.
* <p>
* There is a long-standing Optifine issue (<a href="https://github.com/sp614x/optifine/issues/7549">#7549</a>,
* <a href="https://github.com/sp614x/optifine/issues/7395">#7395</a>) that causes a block entity's
* {@link BlockEntity#gatherCapabilities()} not to be called. This causes peripherals to not show up for block
* entities.
* <p>
* While the bug is marked as fixed, there has not been a release since, and it continues to affect users a year
* after being reported. This is a frequent problem with Optifine (see also <a href="https://github.com/sp614x/optifine/issues/7127">#7127</a>
* and <a href="https://github.com/sp614x/optifine/issues/7261">#7261</a> which I <em>still</em> get bug reports
* about), and this doesn't seem likely to change any time soon.
* <p>
* The ideal situation would be that any time the game starts with Optifine, we delete it from the mods folder.
* That's probably a little uncouth (and a pain to get working on Windows), so instead we try to detect the bug in
* question and print a message in chat whenever a player joins.
*
* @param send The object to send a message too.
*/
public static void warnAboutOptifine(Consumer<Component> send) {
if (!Optifine.isLoaded()) return;
var computer = Nullability.assertNonNull(ModRegistry.BlockEntities.COMPUTER_NORMAL.get().create(
BlockPos.ZERO, ModRegistry.Blocks.COMPUTER_NORMAL.get().defaultBlockState()
));
if (computer.getCapability(Capabilities.CAPABILITY_PERIPHERAL).isPresent()) return;
send.accept(
Component.literal("")
.append(Component.literal("(CC: Tweaked) ").withStyle(ChatFormatting.GRAY))
.append(Component.literal("[WARNING] ").withStyle(ChatFormatting.RED))
.append("It looks like you're running Optifine. This has an ")
.append(Component.literal("unfixed issue").withStyle(s -> s
.withColor(ChatFormatting.BLUE).withUnderlined(true)
.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://github.com/sp614x/optifine/issues/7549"))
))
.append(" which causes issues with many modded block entities, including those added by CC: Tweaked. " +
"Please replace Optifine with an alternative shader mod such as Oculus.")
);
}
}

51
tools/update-resources.py Normal file → Executable file
View File

@@ -76,6 +76,45 @@ def unstitch_corners(input_file: pathlib.Path, family: str):
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:
spec = argparse.ArgumentParser()
spec.add_argument("dir", type=pathlib.Path)
@@ -97,6 +136,18 @@ def main() -> None:
unstitch_corners(path, family)
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:
print("No files were transformed")
return