mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-11-03 23:22:59 +00:00 
			
		
		
		
	Compare commits
	
		
			18 Commits
		
	
	
		
			v1.20.1-1.
			...
			v1.20.1-1.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					dd7e8fcefc | ||
| 
						 | 
					29c8f96912 | ||
| 
						 | 
					b9267ecbfc | ||
| 
						 | 
					9d2c2db22b | ||
| 
						 | 
					6660966320 | ||
| 
						 | 
					16324e1eac | ||
| 
						 | 
					32f5c38485 | ||
| 
						 | 
					01fe949b3e | ||
| 
						 | 
					c03fce275e | ||
| 
						 | 
					0998acaa82 | ||
| 
						 | 
					12a44fed6f | ||
| 
						 | 
					0a8d505323 | ||
| 
						 | 
					237a0ac3bb | ||
| 
						 | 
					b185d088b3 | ||
| 
						 | 
					051c70a731 | ||
| 
						 | 
					2e2f308ff3 | ||
| 
						 | 
					0f123b5efd | ||
| 
						 | 
					88cb03be6b | 
@@ -6,7 +6,7 @@
 | 
			
		||||
# See https://pre-commit.com/hooks.html for more hooks
 | 
			
		||||
repos:
 | 
			
		||||
- repo: https://github.com/pre-commit/pre-commit-hooks
 | 
			
		||||
  rev: v4.4.0
 | 
			
		||||
  rev: v5.0.0
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: trailing-whitespace
 | 
			
		||||
  - id: end-of-file-fixer
 | 
			
		||||
 
 | 
			
		||||
@@ -84,7 +84,6 @@ sourceSets.all {
 | 
			
		||||
 | 
			
		||||
        options.errorprone {
 | 
			
		||||
            check("InvalidBlockTag", CheckSeverity.OFF) // Broken by @cc.xyz
 | 
			
		||||
            check("InvalidParam", CheckSeverity.OFF) // Broken by records.
 | 
			
		||||
            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)
 | 
			
		||||
 
 | 
			
		||||
@@ -92,7 +92,10 @@ SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
        <module name="InvalidJavadocPosition" />
 | 
			
		||||
        <module name="JavadocBlockTagLocation" />
 | 
			
		||||
        <module name="JavadocMethod"/>
 | 
			
		||||
        <module name="JavadocType"/>
 | 
			
		||||
        <module name="JavadocType">
 | 
			
		||||
            <!-- Seems to complain about @hidden!? -->
 | 
			
		||||
            <property name="allowUnknownTags" value="true" />
 | 
			
		||||
        </module>
 | 
			
		||||
        <module name="JavadocStyle">
 | 
			
		||||
            <property name="checkHtml" value="false" />
 | 
			
		||||
        </module>
 | 
			
		||||
@@ -143,7 +146,10 @@ SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
        <module name="NoWhitespaceAfter">
 | 
			
		||||
            <property name="tokens" value="AT,INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP,METHOD_REF" />
 | 
			
		||||
        </module>
 | 
			
		||||
        <module name="NoWhitespaceBefore" />
 | 
			
		||||
        <module name="NoWhitespaceBefore">
 | 
			
		||||
            <!-- Allow whitespace before "..." for @Nullable annotations -->
 | 
			
		||||
            <property name="tokens" value="COMMA,SEMI,POST_INC,POST_DEC,LABELED_STAT" />
 | 
			
		||||
        </module>
 | 
			
		||||
        <!-- TODO: Decide on an OperatorWrap style. -->
 | 
			
		||||
        <module name="ParenPad" />
 | 
			
		||||
        <module name="SeparatorWrap">
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error
 | 
			
		||||
 | 
			
		||||
# Mod properties
 | 
			
		||||
isUnstable=false
 | 
			
		||||
modVersion=1.114.4
 | 
			
		||||
modVersion=1.115.1
 | 
			
		||||
 | 
			
		||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
 | 
			
		||||
mcVersion=1.20.1
 | 
			
		||||
 
 | 
			
		||||
@@ -29,9 +29,9 @@ checkerFramework = "3.42.0"
 | 
			
		||||
cobalt = { strictly = "0.9.5" }
 | 
			
		||||
commonsCli = "1.6.0"
 | 
			
		||||
jetbrainsAnnotations = "24.1.0"
 | 
			
		||||
jsr305 = "3.0.2"
 | 
			
		||||
jspecify = "1.0.0"
 | 
			
		||||
jzlib = "1.1.3"
 | 
			
		||||
kotlin = "2.1.0"
 | 
			
		||||
kotlin = "2.1.10"
 | 
			
		||||
kotlin-coroutines = "1.10.1"
 | 
			
		||||
nightConfig = "3.8.1"
 | 
			
		||||
 | 
			
		||||
@@ -46,7 +46,7 @@ oculus = "1.2.5"
 | 
			
		||||
rei = "12.0.626"
 | 
			
		||||
rubidium = "0.6.1"
 | 
			
		||||
sodium = "mc1.20-0.4.10"
 | 
			
		||||
create-forge = "0.5.1.f-33"
 | 
			
		||||
create-forge = "6.0.0-9"
 | 
			
		||||
create-fabric = "0.5.1-f-build.1467+mc1.20.1"
 | 
			
		||||
 | 
			
		||||
# Testing
 | 
			
		||||
@@ -58,9 +58,9 @@ jmh = "1.37"
 | 
			
		||||
 | 
			
		||||
# Build tools
 | 
			
		||||
cctJavadoc = "1.8.3"
 | 
			
		||||
checkstyle = "10.14.1"
 | 
			
		||||
errorProne-core = "2.27.0"
 | 
			
		||||
errorProne-plugin = "3.1.0"
 | 
			
		||||
checkstyle = "10.21.2"
 | 
			
		||||
errorProne-core = "2.36.0"
 | 
			
		||||
errorProne-plugin = "4.1.0"
 | 
			
		||||
fabric-loom = "1.9.2"
 | 
			
		||||
githubRelease = "2.5.2"
 | 
			
		||||
gradleVersions = "0.50.0"
 | 
			
		||||
@@ -69,7 +69,7 @@ illuaminate = "0.1.0-74-gf1551d5"
 | 
			
		||||
lwjgl = "3.3.3"
 | 
			
		||||
minotaur = "2.8.7"
 | 
			
		||||
modDevGradle = "2.0.74"
 | 
			
		||||
nullAway = "0.10.25"
 | 
			
		||||
nullAway = "0.12.3"
 | 
			
		||||
shadow = "8.3.1"
 | 
			
		||||
spotless = "6.23.3"
 | 
			
		||||
taskTree = "2.1.1"
 | 
			
		||||
@@ -89,7 +89,7 @@ fastutil = { module = "it.unimi.dsi:fastutil", version.ref = "fastutil" }
 | 
			
		||||
forgeSpi = { module = "net.minecraftforge:forgespi", version.ref = "forgeSpi" }
 | 
			
		||||
guava = { module = "com.google.guava:guava", version.ref = "guava" }
 | 
			
		||||
jetbrainsAnnotations = { module = "org.jetbrains:annotations", version.ref = "jetbrainsAnnotations" }
 | 
			
		||||
jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" }
 | 
			
		||||
jspecify = { module = "org.jspecify:jspecify", version.ref = "jspecify" }
 | 
			
		||||
jzlib = { module = "com.jcraft:jzlib", version.ref = "jzlib" }
 | 
			
		||||
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
 | 
			
		||||
kotlin-platform = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
 | 
			
		||||
@@ -178,7 +178,7 @@ taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
 | 
			
		||||
versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
 | 
			
		||||
 | 
			
		||||
[bundles]
 | 
			
		||||
annotations = ["jsr305", "checkerFramework", "jetbrainsAnnotations"]
 | 
			
		||||
annotations = ["checkerFramework", "jetbrainsAnnotations", "jspecify"]
 | 
			
		||||
kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
 | 
			
		||||
 | 
			
		||||
# Minecraft
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,8 @@ import net.minecraft.client.resources.model.ModelResourceLocation;
 | 
			
		||||
import net.minecraft.client.resources.model.UnbakedModel;
 | 
			
		||||
import net.minecraft.nbt.CompoundTag;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,7 @@ import net.minecraft.client.Minecraft;
 | 
			
		||||
import net.minecraft.nbt.CompoundTag;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.joml.Matrix4f;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
final class TurtleUpgradeModellers {
 | 
			
		||||
    private static final Transformation leftTransform = getMatrixFor(-0.4065f);
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,7 @@ import net.minecraft.client.resources.model.ModelManager;
 | 
			
		||||
import net.minecraft.client.resources.model.ModelResourceLocation;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import org.jetbrains.annotations.ApiStatus;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
@ApiStatus.Internal
 | 
			
		||||
public interface ClientPlatformHelper {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
 | 
			
		||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
 | 
			
		||||
import dan200.computercraft.impl.Services;
 | 
			
		||||
import org.jetbrains.annotations.ApiStatus;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Backing interface for {@link ComputerCraftAPIClient}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,7 @@ import net.minecraft.core.Direction;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The static entry point to the ComputerCraft API.
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,8 @@ package dan200.computercraft.api.detail;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,7 @@ import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.minecraft.world.level.block.entity.BlockEntity;
 | 
			
		||||
import net.minecraft.world.level.block.state.BlockState;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A reference to a block in the world, used by block detail providers.
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ import java.util.Map;
 | 
			
		||||
 *
 | 
			
		||||
 * @param <T> The type of object that this provider can provide details for.
 | 
			
		||||
 * @see DetailRegistry
 | 
			
		||||
 * @see dan200.computercraft.api.detail An overview of the detail system.
 | 
			
		||||
 */
 | 
			
		||||
@FunctionalInterface
 | 
			
		||||
public interface DetailProvider<T> {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ import java.util.Map;
 | 
			
		||||
 * also in this package.
 | 
			
		||||
 *
 | 
			
		||||
 * @param <T> The type of object that this registry provides details for.
 | 
			
		||||
 * @see dan200.computercraft.api.detail An overview of the detail system.
 | 
			
		||||
 */
 | 
			
		||||
@ApiStatus.NonExtendable
 | 
			
		||||
public interface DetailRegistry<T> {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,9 @@ public class VanillaDetailRegistries {
 | 
			
		||||
     * <p>
 | 
			
		||||
     * This instance's {@link DetailRegistry#getBasicDetails(Object)} is thread safe (assuming the stack is immutable)
 | 
			
		||||
     * and may be called from the computer thread.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * This does not have special handling for {@linkplain ItemStack#isEmpty() empty item stacks}, and so the returned
 | 
			
		||||
     * details will be an empty stack of air. Callers should generally check for empty stacks before calling this.
 | 
			
		||||
     */
 | 
			
		||||
    public static final DetailRegistry<ItemStack> ITEM_STACK = ComputerCraftAPIService.get().getItemStackDetailRegistry();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,48 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The detail system provides a standard way for mods to return descriptions of common game objects, such as blocks or
 | 
			
		||||
 * items, as well as registering additional detail to be included in those descriptions.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * For instance, the built-in {@code turtle.getItemDetail()} method uses
 | 
			
		||||
 * {@linkplain dan200.computercraft.api.detail.VanillaDetailRegistries#ITEM_STACK in order to provide information about}
 | 
			
		||||
 * the selected item:
 | 
			
		||||
 *
 | 
			
		||||
 * <pre class="language language-lua">{@code
 | 
			
		||||
 * local item = turtle.getItemDetail(nil, true)
 | 
			
		||||
 * --[[
 | 
			
		||||
 * item = {
 | 
			
		||||
 *   name = "minecraft:wheat",
 | 
			
		||||
 *   displayName = "Wheat",
 | 
			
		||||
 *   count = 1,
 | 
			
		||||
 *   maxCount = 64,
 | 
			
		||||
 *   tags = {},
 | 
			
		||||
 * }
 | 
			
		||||
 * ]]
 | 
			
		||||
 * }</pre>
 | 
			
		||||
 *
 | 
			
		||||
 * <h2>Built-in detail providers</h2>
 | 
			
		||||
 * While you can define your own detail providers (perhaps for types from your own mod), CC comes with several built-in
 | 
			
		||||
 * detail registries for vanilla and mod-loader objects:
 | 
			
		||||
 *
 | 
			
		||||
 * <ul>
 | 
			
		||||
 *     <li>{@link dan200.computercraft.api.detail.VanillaDetailRegistries}, for vanilla objects</li>
 | 
			
		||||
 *     <li>{@code dan200.computercraft.api.detail.ForgeDetailRegistries} for Forge-specific objects</li>
 | 
			
		||||
 *     <li>{@code dan200.computercraft.api.detail.FabricDetailRegistries} for Fabric-specific objects</li>
 | 
			
		||||
 * </ul>
 | 
			
		||||
 *
 | 
			
		||||
 * <h2>Example: Returning details from methods</h2>
 | 
			
		||||
 * Here we define a {@code getHeldItem()} method for pocket computers which finds the currently held item of the player
 | 
			
		||||
 * and returns it to the user using {@link dan200.computercraft.api.detail.VanillaDetailRegistries#ITEM_STACK} and
 | 
			
		||||
 * {@link dan200.computercraft.api.detail.DetailRegistry#getDetails(java.lang.Object)}.
 | 
			
		||||
 *
 | 
			
		||||
 * {@snippet class=com.example.examplemod.ExamplePocketPeripheral region=details}
 | 
			
		||||
 *
 | 
			
		||||
 * <h2>Example: Registering custom detail registries</h2>
 | 
			
		||||
 * Here we define a new detail provider for items that includes the nutrition and saturation values in the returned object.
 | 
			
		||||
 *
 | 
			
		||||
 * {@snippet class=com.example.examplemod.ExampleMod region=details}
 | 
			
		||||
 */
 | 
			
		||||
package dan200.computercraft.api.detail;
 | 
			
		||||
@@ -9,8 +9,7 @@ import dan200.computercraft.api.peripheral.IComputerAccess;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import org.jetbrains.annotations.ApiStatus;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An interface passed to {@link ILuaAPIFactory} in order to provide additional information
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,7 @@
 | 
			
		||||
package dan200.computercraft.api.lua;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.api.ComputerCraftAPI;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Construct an {@link ILuaAPI} for a computer.
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,7 @@ import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import net.minecraft.sounds.SoundEvent;
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents an item that can be placed in a disk drive and used by a Computer.
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,7 @@
 | 
			
		||||
package dan200.computercraft.api.media;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This interface is used to provide {@link IMedia} implementations for {@link ItemStack}.
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.api.media;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.impl.ComputerCraftAPIService;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.stream.Stream;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The contents of a page (or book) created by a ComputerCraft printer.
 | 
			
		||||
 *
 | 
			
		||||
 * @since 1.115
 | 
			
		||||
 */
 | 
			
		||||
@Nullable
 | 
			
		||||
public interface PrintoutContents {
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the (possibly empty) title for this printout.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The title of this printout.
 | 
			
		||||
     */
 | 
			
		||||
    String getTitle();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the text contents of this printout, as a sequence of lines.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * The lines in the printout may include blank lines at the end of the document, as well as trailing spaces on each
 | 
			
		||||
     * line.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The text contents of this printout.
 | 
			
		||||
     */
 | 
			
		||||
    Stream<String> getTextLines();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the printout contents for a particular stack.
 | 
			
		||||
     *
 | 
			
		||||
     * @param stack The stack to get the contents for.
 | 
			
		||||
     * @return The printout contents, or {@code null} if this is not a printout item.
 | 
			
		||||
     */
 | 
			
		||||
    static @Nullable PrintoutContents get(ItemStack stack) {
 | 
			
		||||
        return ComputerCraftAPIService.get().getPrintoutContents(stack);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -14,8 +14,8 @@ import net.minecraft.world.entity.Entity;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.phys.Vec3;
 | 
			
		||||
import org.jetbrains.annotations.ApiStatus;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -7,8 +7,7 @@ package dan200.computercraft.api.pocket;
 | 
			
		||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
			
		||||
import dan200.computercraft.api.upgrades.UpgradeBase;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A peripheral which can be equipped to the back side of a pocket computer.
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,7 @@ import net.minecraft.world.Container;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import org.jetbrains.annotations.ApiStatus;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The interface passed to turtle by turtles, providing methods that they can call.
 | 
			
		||||
 
 | 
			
		||||
@@ -9,8 +9,8 @@ import dan200.computercraft.api.upgrades.UpgradeBase;
 | 
			
		||||
import net.minecraft.core.Direction;
 | 
			
		||||
import net.minecraft.nbt.CompoundTag;
 | 
			
		||||
import net.minecraft.world.item.Items;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.function.BiFunction;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,7 @@
 | 
			
		||||
package dan200.computercraft.api.turtle;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.core.Direction;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Used to indicate the result of executing a turtle command.
 | 
			
		||||
@@ -60,9 +59,9 @@ public final class TurtleCommandResult {
 | 
			
		||||
 | 
			
		||||
    private final boolean success;
 | 
			
		||||
    private final @Nullable String errorMessage;
 | 
			
		||||
    private final @Nullable Object[] results;
 | 
			
		||||
    private final @Nullable Object @Nullable [] results;
 | 
			
		||||
 | 
			
		||||
    private TurtleCommandResult(boolean success, @Nullable String errorMessage, @Nullable Object[] results) {
 | 
			
		||||
    private TurtleCommandResult(boolean success, @Nullable String errorMessage, @Nullable Object @Nullable [] results) {
 | 
			
		||||
        this.success = success;
 | 
			
		||||
        this.errorMessage = errorMessage;
 | 
			
		||||
        this.results = results;
 | 
			
		||||
@@ -92,8 +91,7 @@ public final class TurtleCommandResult {
 | 
			
		||||
     *
 | 
			
		||||
     * @return The command's result, or {@code null} if it was a failure.
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public Object[] getResults() {
 | 
			
		||||
    public @Nullable Object @Nullable [] getResults() {
 | 
			
		||||
        return results;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,8 +18,8 @@ import net.minecraft.world.entity.ai.attributes.Attributes;
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.block.Block;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -9,8 +9,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
 | 
			
		||||
import net.minecraft.nbt.CompoundTag;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jetbrains.annotations.Contract;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An upgrade (i.e. a {@link ITurtleUpgrade}) and its current upgrade data.
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,8 @@ import net.minecraft.data.PackOutput;
 | 
			
		||||
import net.minecraft.resources.ResourceKey;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.concurrent.CompletableFuture;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import dan200.computercraft.api.filesystem.WritableMount;
 | 
			
		||||
import dan200.computercraft.api.lua.GenericSource;
 | 
			
		||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
 | 
			
		||||
import dan200.computercraft.api.media.MediaProvider;
 | 
			
		||||
import dan200.computercraft.api.media.PrintoutContents;
 | 
			
		||||
import dan200.computercraft.api.network.PacketNetwork;
 | 
			
		||||
import dan200.computercraft.api.network.wired.WiredElement;
 | 
			
		||||
import dan200.computercraft.api.network.wired.WiredNode;
 | 
			
		||||
@@ -27,8 +28,7 @@ import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import org.jetbrains.annotations.ApiStatus;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Backing interface for {@link ComputerCraftAPI}
 | 
			
		||||
@@ -75,6 +75,9 @@ public interface ComputerCraftAPIService {
 | 
			
		||||
 | 
			
		||||
    DetailRegistry<BlockReference> getBlockInWorldDetailRegistry();
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    PrintoutContents getPrintoutContents(ItemStack stack);
 | 
			
		||||
 | 
			
		||||
    final class Instance {
 | 
			
		||||
        static final @Nullable ComputerCraftAPIService INSTANCE;
 | 
			
		||||
        static final @Nullable Throwable ERROR;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,7 @@ import net.minecraft.resources.ResourceKey;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jetbrains.annotations.ApiStatus;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Abstraction layer for Forge and Fabric. See implementations for more details.
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@
 | 
			
		||||
package dan200.computercraft.impl;
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.annotations.ApiStatus;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@
 | 
			
		||||
package dan200.computercraft.impl;
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.annotations.ApiStatus;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.ServiceLoader;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,6 @@ dependencies {
 | 
			
		||||
    clientApi(clientClasses(project(":common-api")))
 | 
			
		||||
 | 
			
		||||
    compileOnly(libs.bundles.externalMods.common)
 | 
			
		||||
    compileOnly(variantOf(libs.create.forge) { classifier("slim") }) { isTransitive = false }
 | 
			
		||||
    clientCompileOnly(variantOf(libs.emi) { classifier("api") })
 | 
			
		||||
 | 
			
		||||
    annotationProcessorEverywhere(libs.autoService)
 | 
			
		||||
 
 | 
			
		||||
@@ -38,8 +38,8 @@ import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.block.state.BlockState;
 | 
			
		||||
import net.minecraft.world.phys.BlockHitResult;
 | 
			
		||||
import net.minecraft.world.phys.HitResult;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -46,8 +46,8 @@ import net.minecraft.world.entity.LivingEntity;
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.ItemLike;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.function.BiConsumer;
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,8 @@ import net.minecraft.client.gui.components.ChatComponent;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.util.Mth;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -26,11 +26,11 @@ import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.world.entity.player.Inventory;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.lwjgl.glfw.GLFW;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.ByteBuffer;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,8 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite;
 | 
			
		||||
import net.minecraft.client.renderer.texture.TextureManager;
 | 
			
		||||
import net.minecraft.client.resources.TextureAtlasHolder;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.stream.Stream;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,9 @@ import net.minecraft.client.gui.screens.Screen;
 | 
			
		||||
import net.minecraft.client.gui.screens.inventory.MenuAccess;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.world.entity.player.Inventory;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.lwjgl.glfw.GLFW;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,8 @@ import net.minecraft.client.gui.components.MultiLineLabel;
 | 
			
		||||
import net.minecraft.client.gui.screens.Screen;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
 | 
			
		||||
 
 | 
			
		||||
@@ -149,6 +149,7 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
 | 
			
		||||
        // Skip rendering labels.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("ArrayRecordComponent")
 | 
			
		||||
    record PrintoutInfo(int pages, boolean book, TextBuffer[] text, TextBuffer[] colour) {
 | 
			
		||||
        public static final PrintoutInfo DEFAULT;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,8 @@ import net.minecraft.client.gui.components.Button;
 | 
			
		||||
import net.minecraft.client.gui.components.Tooltip;
 | 
			
		||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.function.Supplier;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -72,7 +72,7 @@ public class TerminalWidget extends AbstractWidget {
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean charTyped(char ch, int modifiers) {
 | 
			
		||||
        var terminalChar = StringUtil.unicodeToTerminal(ch);
 | 
			
		||||
        if (StringUtil.isTypableChar(terminalChar)) computer.charTyped(terminalChar);
 | 
			
		||||
        if (StringUtil.isTypableChar(terminalChar)) computer.charTyped((byte) terminalChar);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,97 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.client.model;
 | 
			
		||||
 | 
			
		||||
import com.mojang.blaze3d.vertex.PoseStack;
 | 
			
		||||
import com.mojang.blaze3d.vertex.VertexConsumer;
 | 
			
		||||
import dan200.computercraft.api.ComputerCraftAPI;
 | 
			
		||||
import dan200.computercraft.client.pocket.PocketComputerData;
 | 
			
		||||
import dan200.computercraft.client.render.CustomLecternRenderer;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
 | 
			
		||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
 | 
			
		||||
import net.minecraft.client.model.geom.ModelPart;
 | 
			
		||||
import net.minecraft.client.model.geom.PartPose;
 | 
			
		||||
import net.minecraft.client.model.geom.builders.CubeListBuilder;
 | 
			
		||||
import net.minecraft.client.model.geom.builders.MeshDefinition;
 | 
			
		||||
import net.minecraft.client.renderer.LightTexture;
 | 
			
		||||
import net.minecraft.client.renderer.MultiBufferSource;
 | 
			
		||||
import net.minecraft.client.renderer.RenderType;
 | 
			
		||||
import net.minecraft.client.resources.model.Material;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.util.FastColor;
 | 
			
		||||
import net.minecraft.world.inventory.InventoryMenu;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A model for {@linkplain PocketComputerItem pocket computers} placed on a lectern.
 | 
			
		||||
 *
 | 
			
		||||
 * @see CustomLecternRenderer
 | 
			
		||||
 */
 | 
			
		||||
public class LecternPocketModel {
 | 
			
		||||
    public static final ResourceLocation TEXTURE_NORMAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_normal");
 | 
			
		||||
    public static final ResourceLocation TEXTURE_ADVANCED = new ResourceLocation(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_advanced");
 | 
			
		||||
    public static final ResourceLocation TEXTURE_COLOUR = new ResourceLocation(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_colour");
 | 
			
		||||
    public static final ResourceLocation TEXTURE_FRAME = new ResourceLocation(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_frame");
 | 
			
		||||
    public static final ResourceLocation TEXTURE_LIGHT = new ResourceLocation(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_light");
 | 
			
		||||
 | 
			
		||||
    private static final Material MATERIAL_NORMAL = new Material(InventoryMenu.BLOCK_ATLAS, TEXTURE_NORMAL);
 | 
			
		||||
    private static final Material MATERIAL_ADVANCED = new Material(InventoryMenu.BLOCK_ATLAS, TEXTURE_ADVANCED);
 | 
			
		||||
    private static final Material MATERIAL_COLOUR = new Material(InventoryMenu.BLOCK_ATLAS, TEXTURE_COLOUR);
 | 
			
		||||
    private static final Material MATERIAL_FRAME = new Material(InventoryMenu.BLOCK_ATLAS, TEXTURE_FRAME);
 | 
			
		||||
    private static final Material MATERIAL_LIGHT = new Material(InventoryMenu.BLOCK_ATLAS, TEXTURE_LIGHT);
 | 
			
		||||
 | 
			
		||||
    // The size of the terminal within the model.
 | 
			
		||||
    public static final float TERM_WIDTH = 12.0f / 32.0f;
 | 
			
		||||
    public static final float TERM_HEIGHT = 14.0f / 32.0f;
 | 
			
		||||
 | 
			
		||||
    // The size of the texture. The texture is 36x36, but is at 2x resolution.
 | 
			
		||||
    private static final int TEXTURE_WIDTH = 48 / 2;
 | 
			
		||||
    private static final int TEXTURE_HEIGHT = 48 / 2;
 | 
			
		||||
 | 
			
		||||
    private final ModelPart root;
 | 
			
		||||
 | 
			
		||||
    public LecternPocketModel() {
 | 
			
		||||
        root = buildPages();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static ModelPart buildPages() {
 | 
			
		||||
        var mesh = new MeshDefinition();
 | 
			
		||||
        var parts = mesh.getRoot();
 | 
			
		||||
        parts.addOrReplaceChild(
 | 
			
		||||
            "root",
 | 
			
		||||
            CubeListBuilder.create().texOffs(0, 0).addBox(0f, -5.0f, -4.0f, 1f, 10.0f, 8.0f),
 | 
			
		||||
            PartPose.ZERO
 | 
			
		||||
        );
 | 
			
		||||
        return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void render(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int colour) {
 | 
			
		||||
        int red = FastColor.ARGB32.red(colour), green = FastColor.ARGB32.green(colour), blue = FastColor.ARGB32.blue(colour), alpha = FastColor.ARGB32.alpha(colour);
 | 
			
		||||
        root.render(poseStack, buffer, packedLight, packedOverlay, red / 255.0f, green / 255.0f, blue / 255.0f, alpha / 255.0f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Render the pocket computer model.
 | 
			
		||||
     *
 | 
			
		||||
     * @param poseStack     The current pose stack.
 | 
			
		||||
     * @param bufferSource  The buffer source to draw to.
 | 
			
		||||
     * @param packedLight   The current light level.
 | 
			
		||||
     * @param packedOverlay The overlay texture (used for entity hurt animation).
 | 
			
		||||
     * @param family        The computer family.
 | 
			
		||||
     * @param frameColour   The pocket computer's {@linkplain PocketComputerItem#getColour(ItemStack) colour}.
 | 
			
		||||
     * @param lightColour   The pocket computer's {@linkplain PocketComputerData#getLightState() light colour}.
 | 
			
		||||
     */
 | 
			
		||||
    public void render(PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay, ComputerFamily family, int frameColour, int lightColour) {
 | 
			
		||||
        if (frameColour != -1) {
 | 
			
		||||
            root.render(poseStack, MATERIAL_FRAME.buffer(bufferSource, RenderType::entityCutout), packedLight, packedOverlay, 1, 1, 1, 1);
 | 
			
		||||
            render(poseStack, MATERIAL_COLOUR.buffer(bufferSource, RenderType::entityCutout), packedLight, packedOverlay, frameColour);
 | 
			
		||||
        } else {
 | 
			
		||||
            var buffer = (family == ComputerFamily.ADVANCED ? MATERIAL_ADVANCED : MATERIAL_NORMAL).buffer(bufferSource, RenderType::entityCutout);
 | 
			
		||||
            root.render(poseStack, buffer, packedLight, packedOverlay, 1, 1, 1, 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        render(poseStack, MATERIAL_LIGHT.buffer(bufferSource, RenderType::entityCutout), LightTexture.FULL_BRIGHT, packedOverlay, lightColour);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -13,8 +13,8 @@ import net.minecraft.client.resources.model.BakedModel;
 | 
			
		||||
import net.minecraft.core.Direction;
 | 
			
		||||
import org.joml.Matrix4f;
 | 
			
		||||
import org.joml.Vector4f;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,8 @@ import net.minecraft.client.Minecraft;
 | 
			
		||||
import net.minecraft.client.resources.model.BakedModel;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,8 @@ import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.sounds.SoundEvent;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,7 @@ import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.network.protocol.Packet;
 | 
			
		||||
import net.minecraft.network.protocol.game.ServerGamePacketListener;
 | 
			
		||||
import net.minecraft.sounds.SoundEvent;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
public interface ClientPlatformHelper extends dan200.computercraft.impl.client.ClientPlatformHelper {
 | 
			
		||||
    static ClientPlatformHelper get() {
 | 
			
		||||
@@ -39,7 +38,7 @@ public interface ClientPlatformHelper extends dan200.computercraft.impl.client.C
 | 
			
		||||
     * @param overlayLight  The current overlay light.
 | 
			
		||||
     * @param tints         Block colour tints to apply to the model.
 | 
			
		||||
     */
 | 
			
		||||
    void renderBakedModel(PoseStack transform, MultiBufferSource buffers, BakedModel model, int lightmapCoord, int overlayLight, @Nullable int[] tints);
 | 
			
		||||
    void renderBakedModel(PoseStack transform, MultiBufferSource buffers, BakedModel model, int lightmapCoord, int overlayLight, int @Nullable [] tints);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Play a record at a particular position.
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@ import dan200.computercraft.shared.computer.terminal.TerminalState;
 | 
			
		||||
import dan200.computercraft.shared.network.client.PocketComputerDataMessage;
 | 
			
		||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,7 @@ import dan200.computercraft.shared.computer.core.ComputerState;
 | 
			
		||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
 | 
			
		||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
 | 
			
		||||
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Clientside data about a pocket computer.
 | 
			
		||||
 
 | 
			
		||||
@@ -6,15 +6,28 @@ package dan200.computercraft.client.render;
 | 
			
		||||
 | 
			
		||||
import com.mojang.blaze3d.vertex.PoseStack;
 | 
			
		||||
import com.mojang.math.Axis;
 | 
			
		||||
import dan200.computercraft.client.model.LecternPocketModel;
 | 
			
		||||
import dan200.computercraft.client.model.LecternPrintoutModel;
 | 
			
		||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
 | 
			
		||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
 | 
			
		||||
import dan200.computercraft.core.terminal.Terminal;
 | 
			
		||||
import dan200.computercraft.core.util.Colour;
 | 
			
		||||
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
 | 
			
		||||
import dan200.computercraft.shared.media.items.PrintoutItem;
 | 
			
		||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
 | 
			
		||||
import dan200.computercraft.shared.util.ARGB32;
 | 
			
		||||
import net.minecraft.client.renderer.MultiBufferSource;
 | 
			
		||||
import net.minecraft.client.renderer.RenderType;
 | 
			
		||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
 | 
			
		||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
 | 
			
		||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
 | 
			
		||||
import net.minecraft.client.renderer.blockentity.LecternRenderer;
 | 
			
		||||
import net.minecraft.world.level.block.LecternBlock;
 | 
			
		||||
import net.minecraft.world.phys.Vec3;
 | 
			
		||||
 | 
			
		||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
 | 
			
		||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
 | 
			
		||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A block entity renderer for our {@linkplain CustomLecternBlockEntity lectern}.
 | 
			
		||||
@@ -22,10 +35,17 @@ import net.minecraft.world.level.block.LecternBlock;
 | 
			
		||||
 * This largely follows {@link LecternRenderer}, but with support for multiple types of item.
 | 
			
		||||
 */
 | 
			
		||||
public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternBlockEntity> {
 | 
			
		||||
    private static final int POCKET_TERMINAL_RENDER_DISTANCE = 32;
 | 
			
		||||
 | 
			
		||||
    private final BlockEntityRenderDispatcher berDispatcher;
 | 
			
		||||
    private final LecternPrintoutModel printoutModel;
 | 
			
		||||
    private final LecternPocketModel pocketModel;
 | 
			
		||||
 | 
			
		||||
    public CustomLecternRenderer(BlockEntityRendererProvider.Context context) {
 | 
			
		||||
        berDispatcher = context.getBlockEntityRenderDispatcher();
 | 
			
		||||
 | 
			
		||||
        printoutModel = new LecternPrintoutModel();
 | 
			
		||||
        pocketModel = new LecternPocketModel();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -44,8 +64,46 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
 | 
			
		||||
            } else {
 | 
			
		||||
                printoutModel.renderPages(poseStack, vertexConsumer, packedLight, packedOverlay, PrintoutItem.getPageCount(item));
 | 
			
		||||
            }
 | 
			
		||||
        } else if (item.getItem() instanceof PocketComputerItem pocket) {
 | 
			
		||||
            var computer = ClientPocketComputers.get(item);
 | 
			
		||||
 | 
			
		||||
            pocketModel.render(
 | 
			
		||||
                poseStack, buffer, packedLight, packedOverlay, pocket.getFamily(), pocket.getColour(item),
 | 
			
		||||
                ARGB32.opaque(computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState())
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Jiggle the terminal about a bit, so (0, 0) is in the top left of the model's terminal hole.
 | 
			
		||||
            poseStack.mulPose(Axis.YP.rotationDegrees(90f));
 | 
			
		||||
            poseStack.translate(-0.5 * LecternPocketModel.TERM_WIDTH, 0.5 * LecternPocketModel.TERM_HEIGHT + 1f / 32.0f, 1 / 16.0f);
 | 
			
		||||
            poseStack.mulPose(Axis.XP.rotationDegrees(180));
 | 
			
		||||
 | 
			
		||||
            // Either render the terminal or a black screen, depending on how close we are.
 | 
			
		||||
            var terminal = computer == null ? null : computer.getTerminal();
 | 
			
		||||
            var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(poseStack, buffer.getBuffer(RenderTypes.TERMINAL));
 | 
			
		||||
            if (terminal != null && Vec3.atCenterOf(lectern.getBlockPos()).closerThan(berDispatcher.camera.getPosition(), POCKET_TERMINAL_RENDER_DISTANCE)) {
 | 
			
		||||
                renderPocketTerminal(poseStack, quadEmitter, terminal);
 | 
			
		||||
            } else {
 | 
			
		||||
                FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, LecternPocketModel.TERM_WIDTH, LecternPocketModel.TERM_HEIGHT);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        poseStack.popPose();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void renderPocketTerminal(PoseStack poseStack, FixedWidthFontRenderer.QuadEmitter quadEmitter, Terminal terminal) {
 | 
			
		||||
        var width = terminal.getWidth() * FONT_WIDTH;
 | 
			
		||||
        var height = terminal.getHeight() * FONT_HEIGHT;
 | 
			
		||||
 | 
			
		||||
        // Scale the terminal down to fit in the available space.
 | 
			
		||||
        var scaleX = LecternPocketModel.TERM_WIDTH / (width + MARGIN * 2);
 | 
			
		||||
        var scaleY = LecternPocketModel.TERM_HEIGHT / (height + MARGIN * 2);
 | 
			
		||||
        var scale = Math.min(scaleX, scaleY);
 | 
			
		||||
        poseStack.scale(scale, scale, -1.0f);
 | 
			
		||||
 | 
			
		||||
        // Convert the model dimensions to terminal space, then find out how large the margin should be.
 | 
			
		||||
        var marginX = ((LecternPocketModel.TERM_WIDTH / scale) - width) / 2;
 | 
			
		||||
        var marginY = ((LecternPocketModel.TERM_HEIGHT / scale) - height) / 2;
 | 
			
		||||
 | 
			
		||||
        FixedWidthFontRenderer.drawTerminal(quadEmitter, marginX, marginY, terminal, marginY, marginY, marginX, marginX);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,8 @@ import net.minecraft.client.renderer.entity.ItemRenderer;
 | 
			
		||||
import net.minecraft.client.resources.model.BakedModel;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.joml.Vector4f;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -39,7 +39,7 @@ public final class ModelRenderer {
 | 
			
		||||
     * @param overlayLight  The current overlay light.
 | 
			
		||||
     * @param tints         Block colour tints to apply to the model.
 | 
			
		||||
     */
 | 
			
		||||
    public static void renderQuads(PoseStack transform, VertexConsumer buffer, List<BakedQuad> quads, int lightmapCoord, int overlayLight, @Nullable int[] tints) {
 | 
			
		||||
    public static void renderQuads(PoseStack transform, VertexConsumer buffer, List<BakedQuad> quads, int lightmapCoord, int overlayLight, int @Nullable [] tints) {
 | 
			
		||||
        var matrix = transform.last();
 | 
			
		||||
        var inverted = matrix.pose().determinant() < 0;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,8 @@ import net.minecraft.client.renderer.RenderType;
 | 
			
		||||
import net.minecraft.client.renderer.ShaderInstance;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.server.packs.resources.ResourceProvider;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.function.BiConsumer;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,7 @@ import net.minecraft.client.resources.model.BakedModel;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.world.phys.BlockHitResult;
 | 
			
		||||
import net.minecraft.world.phys.HitResult;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
 | 
			
		||||
    private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_colour");
 | 
			
		||||
@@ -127,7 +126,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
 | 
			
		||||
        transform.popPose();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void renderModel(PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, ResourceLocation modelLocation, @Nullable int[] tints) {
 | 
			
		||||
    private void renderModel(PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, ResourceLocation modelLocation, int @Nullable [] tints) {
 | 
			
		||||
        var modelManager = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getModelManager();
 | 
			
		||||
        renderModel(transform, buffers, lightmapCoord, overlayLight, ClientPlatformHelper.get().getModel(modelManager, modelLocation), tints);
 | 
			
		||||
    }
 | 
			
		||||
@@ -143,7 +142,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
 | 
			
		||||
     * @param tints         Tints for the quads, as an array of RGB values.
 | 
			
		||||
     * @see net.minecraft.client.renderer.block.ModelBlockRenderer#renderModel
 | 
			
		||||
     */
 | 
			
		||||
    private void renderModel(PoseStack transform, MultiBufferSource renderer, int lightmapCoord, int overlayLight, BakedModel model, @Nullable int[] tints) {
 | 
			
		||||
    private void renderModel(PoseStack transform, MultiBufferSource renderer, int lightmapCoord, int overlayLight, BakedModel model, int @Nullable [] tints) {
 | 
			
		||||
        ClientPlatformHelper.get().renderBakedModel(transform, renderer, model, lightmapCoord, overlayLight, tints);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,11 +27,11 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
 | 
			
		||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
 | 
			
		||||
import org.joml.Matrix3f;
 | 
			
		||||
import org.joml.Matrix4f;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.lwjgl.opengl.GL11;
 | 
			
		||||
import org.lwjgl.opengl.GL20;
 | 
			
		||||
import org.lwjgl.opengl.GL31;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.nio.ByteBuffer;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,12 +11,12 @@ import dan200.computercraft.client.render.vbo.DirectVertexBuffer;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.lwjgl.opengl.GL11;
 | 
			
		||||
import org.lwjgl.opengl.GL15;
 | 
			
		||||
import org.lwjgl.opengl.GL30;
 | 
			
		||||
import org.lwjgl.opengl.GL31;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,12 +14,12 @@ import dan200.computercraft.core.terminal.TextBuffer;
 | 
			
		||||
import dan200.computercraft.core.util.Colour;
 | 
			
		||||
import net.minecraft.client.renderer.ShaderInstance;
 | 
			
		||||
import net.minecraft.server.packs.resources.ResourceProvider;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.lwjgl.opengl.GL13;
 | 
			
		||||
import org.lwjgl.opengl.GL31;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.ByteBuffer;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ public final class FixedWidthFontRenderer {
 | 
			
		||||
    static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
 | 
			
		||||
 | 
			
		||||
    private static final int BLACK = FastColor.ARGB32.color(255, byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()));
 | 
			
		||||
    private static final float Z_OFFSET = 1e-3f;
 | 
			
		||||
    private static final float Z_OFFSET = 1e-4f;
 | 
			
		||||
 | 
			
		||||
    private FixedWidthFontRenderer() {
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -10,9 +10,9 @@ import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
 | 
			
		||||
import net.minecraft.client.sounds.AudioStream;
 | 
			
		||||
import net.minecraft.client.sounds.SoundEngine;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.lwjgl.BufferUtils;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import javax.sound.sampled.AudioFormat;
 | 
			
		||||
import java.nio.ByteBuffer;
 | 
			
		||||
import java.nio.ByteOrder;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,7 @@ import dan200.computercraft.shared.peripheral.speaker.EncodedAudio;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
 | 
			
		||||
import net.minecraft.client.Minecraft;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An instance of a speaker, which is either playing a {@link DfpwmStream} stream or a normal sound.
 | 
			
		||||
@@ -25,7 +24,7 @@ public class SpeakerInstance {
 | 
			
		||||
    SpeakerInstance() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void pushAudio(EncodedAudio buffer) {
 | 
			
		||||
    private void pushAudio(EncodedAudio buffer, float volume) {
 | 
			
		||||
        var sound = this.sound;
 | 
			
		||||
 | 
			
		||||
        var stream = currentStream;
 | 
			
		||||
@@ -33,18 +32,30 @@ public class SpeakerInstance {
 | 
			
		||||
        var exhausted = stream.isEmpty();
 | 
			
		||||
        stream.push(buffer);
 | 
			
		||||
 | 
			
		||||
        // If we've got nothing left in the buffer, enqueue an additional one just in case.
 | 
			
		||||
        if (exhausted && sound != null && sound.stream == stream && stream.channel != null && stream.executor != null) {
 | 
			
		||||
        if (sound == null) return;
 | 
			
		||||
 | 
			
		||||
        var volumeChanged = sound.setVolume(volume);
 | 
			
		||||
 | 
			
		||||
        if ((exhausted || volumeChanged) && sound.stream == stream && stream.channel != null && stream.executor != null) {
 | 
			
		||||
            var actualStream = sound.stream;
 | 
			
		||||
            stream.executor.execute(() -> {
 | 
			
		||||
                var channel = Nullability.assertNonNull(actualStream.channel);
 | 
			
		||||
                if (!channel.stopped()) channel.pumpBuffers(1);
 | 
			
		||||
                if (channel.stopped()) return;
 | 
			
		||||
 | 
			
		||||
                // If we've got nothing left in the buffer, enqueue an additional one just in case.
 | 
			
		||||
                if (exhausted) channel.pumpBuffers(1);
 | 
			
		||||
 | 
			
		||||
                // Update the attenuation if the volume has changed: SoundEngine.tickNonPaused updates the volume
 | 
			
		||||
                // itself, but leaves the attenuation unchanged. We mirror the logic of SoundEngine.play here.
 | 
			
		||||
                if (volumeChanged) {
 | 
			
		||||
                    channel.linearAttenuation(Math.max(volume, 1) * sound.getSound().getAttenuationDistance());
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void playAudio(SpeakerPosition position, float volume, EncodedAudio buffer) {
 | 
			
		||||
        pushAudio(buffer);
 | 
			
		||||
        pushAudio(buffer, volume);
 | 
			
		||||
 | 
			
		||||
        var soundManager = Minecraft.getInstance().getSoundManager();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,8 @@ import net.minecraft.client.sounds.SoundBufferLibrary;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.sounds.SoundSource;
 | 
			
		||||
import net.minecraft.world.entity.Entity;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.concurrent.CompletableFuture;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -83,4 +83,10 @@ public class SpeakerSound extends AbstractSoundInstance implements TickableSound
 | 
			
		||||
    public @Nullable AudioStream getStream() {
 | 
			
		||||
        return stream;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean setVolume(float volume) {
 | 
			
		||||
        if (volume == this.volume) return false;
 | 
			
		||||
        this.volume = volume;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import dan200.computercraft.api.turtle.ITurtleAccess;
 | 
			
		||||
import dan200.computercraft.api.turtle.TurtleSide;
 | 
			
		||||
import dan200.computercraft.shared.turtle.upgrades.TurtleModem;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ package dan200.computercraft.data;
 | 
			
		||||
 | 
			
		||||
import com.mojang.serialization.Codec;
 | 
			
		||||
import dan200.computercraft.client.gui.GuiSprites;
 | 
			
		||||
import dan200.computercraft.client.model.LecternPocketModel;
 | 
			
		||||
import dan200.computercraft.client.model.LecternPrintoutModel;
 | 
			
		||||
import dan200.computercraft.shared.turtle.inventory.UpgradeSlot;
 | 
			
		||||
import net.minecraft.client.renderer.texture.atlas.SpriteSource;
 | 
			
		||||
@@ -54,7 +55,9 @@ public final class DataProviders {
 | 
			
		||||
            out.accept(new ResourceLocation("blocks"), makeSprites(Stream.of(
 | 
			
		||||
                UpgradeSlot.LEFT_UPGRADE,
 | 
			
		||||
                UpgradeSlot.RIGHT_UPGRADE,
 | 
			
		||||
                LecternPrintoutModel.TEXTURE
 | 
			
		||||
                LecternPrintoutModel.TEXTURE,
 | 
			
		||||
                LecternPocketModel.TEXTURE_NORMAL, LecternPocketModel.TEXTURE_ADVANCED,
 | 
			
		||||
                LecternPocketModel.TEXTURE_COLOUR, LecternPocketModel.TEXTURE_FRAME, LecternPocketModel.TEXTURE_LIGHT
 | 
			
		||||
            )));
 | 
			
		||||
            out.accept(GuiSprites.SPRITE_SHEET, makeSprites(
 | 
			
		||||
                Stream.of(GuiSprites.TURTLE_NORMAL_SELECTED_SLOT, GuiSprites.TURTLE_ADVANCED_SELECTED_SLOT),
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@ import net.minecraft.nbt.CompoundTag;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.util.GsonHelper;
 | 
			
		||||
import net.minecraft.world.item.crafting.RecipeSerializer;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import dan200.computercraft.api.lua.Coerced;
 | 
			
		||||
import dan200.computercraft.api.lua.ILuaAPI;
 | 
			
		||||
import dan200.computercraft.api.lua.LuaFunction;
 | 
			
		||||
import dan200.computercraft.api.turtle.ITurtleAccess;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An example API that will be available on every turtle. This demonstrates both registering an API, and how to write
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package com.example.examplemod;
 | 
			
		||||
import com.example.examplemod.data.TurtleDataProvider;
 | 
			
		||||
import com.example.examplemod.peripheral.FurnacePeripheral;
 | 
			
		||||
import dan200.computercraft.api.ComputerCraftAPI;
 | 
			
		||||
import dan200.computercraft.api.detail.VanillaDetailRegistries;
 | 
			
		||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -34,6 +35,16 @@ public final class ExampleMod {
 | 
			
		||||
        ComputerCraftAPI.registerGenericSource(new FurnacePeripheral());
 | 
			
		||||
        // @end region=generic_source
 | 
			
		||||
 | 
			
		||||
        // @start region=details
 | 
			
		||||
        VanillaDetailRegistries.ITEM_STACK.addProvider((out, stack) -> {
 | 
			
		||||
            var food = stack.getItem().getFoodProperties();
 | 
			
		||||
            if (food == null) return;
 | 
			
		||||
 | 
			
		||||
            out.put("saturation", food.getSaturationModifier());
 | 
			
		||||
            out.put("nutrition", food.getNutrition());
 | 
			
		||||
        });
 | 
			
		||||
        // @end region=details
 | 
			
		||||
 | 
			
		||||
        ExampleAPI.register();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,49 @@
 | 
			
		||||
package com.example.examplemod;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.api.detail.DetailRegistry;
 | 
			
		||||
import dan200.computercraft.api.detail.VanillaDetailRegistries;
 | 
			
		||||
import dan200.computercraft.api.lua.LuaFunction;
 | 
			
		||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
			
		||||
import dan200.computercraft.api.pocket.IPocketAccess;
 | 
			
		||||
import net.minecraft.world.InteractionHand;
 | 
			
		||||
import net.minecraft.world.entity.LivingEntity;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An example peripheral for pocket computers. This currently doesn't have an associated upgrade — it mostly exists to
 | 
			
		||||
 * demonstrate other functionality.
 | 
			
		||||
 */
 | 
			
		||||
public class ExamplePocketPeripheral implements IPeripheral {
 | 
			
		||||
    private final IPocketAccess pocket;
 | 
			
		||||
 | 
			
		||||
    public ExamplePocketPeripheral(IPocketAccess pocket) {
 | 
			
		||||
        this.pocket = pocket;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getType() {
 | 
			
		||||
        return "example";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * An example of using {@linkplain DetailRegistry detail registries} to get the current player's held item.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The item details, or {@code null} if the player is not holding an item.
 | 
			
		||||
     */
 | 
			
		||||
    // @start region=details
 | 
			
		||||
    @LuaFunction(mainThread = true)
 | 
			
		||||
    public final @Nullable Map<String, ?> getHeldItem() {
 | 
			
		||||
        if (!(pocket.getEntity() instanceof LivingEntity entity)) return null;
 | 
			
		||||
 | 
			
		||||
        var heldItem = entity.getItemInHand(InteractionHand.MAIN_HAND);
 | 
			
		||||
        return heldItem.isEmpty() ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(heldItem);
 | 
			
		||||
    }
 | 
			
		||||
    // @end region=details
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(@Nullable IPeripheral other) {
 | 
			
		||||
        return other instanceof ExamplePocketPeripheral o && pocket == o.pocket;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,7 +3,7 @@ package com.example.examplemod.peripheral;
 | 
			
		||||
import dan200.computercraft.api.lua.LuaFunction;
 | 
			
		||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
			
		||||
import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A peripheral that adds a {@code getFuel()} method to brewing stands. This demonstrates the usage of
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import dan200.computercraft.api.lua.LuaFunction;
 | 
			
		||||
import dan200.computercraft.api.peripheral.AttachedComputerSet;
 | 
			
		||||
import dan200.computercraft.api.peripheral.IComputerAccess;
 | 
			
		||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A peripheral that tracks what computers it is attached to.
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,11 @@
 | 
			
		||||
  "sources": [
 | 
			
		||||
    {"type": "minecraft:single", "resource": "computercraft:gui/turtle_upgrade_left"},
 | 
			
		||||
    {"type": "minecraft:single", "resource": "computercraft:gui/turtle_upgrade_right"},
 | 
			
		||||
    {"type": "minecraft:single", "resource": "computercraft:entity/printout"}
 | 
			
		||||
    {"type": "minecraft:single", "resource": "computercraft:entity/printout"},
 | 
			
		||||
    {"type": "minecraft:single", "resource": "computercraft:entity/pocket_computer_normal"},
 | 
			
		||||
    {"type": "minecraft:single", "resource": "computercraft:entity/pocket_computer_advanced"},
 | 
			
		||||
    {"type": "minecraft:single", "resource": "computercraft:entity/pocket_computer_colour"},
 | 
			
		||||
    {"type": "minecraft:single", "resource": "computercraft:entity/pocket_computer_frame"},
 | 
			
		||||
    {"type": "minecraft:single", "resource": "computercraft:entity/pocket_computer_light"}
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import dan200.computercraft.api.filesystem.Mount;
 | 
			
		||||
import dan200.computercraft.api.filesystem.WritableMount;
 | 
			
		||||
import dan200.computercraft.api.lua.GenericSource;
 | 
			
		||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
 | 
			
		||||
import dan200.computercraft.api.media.MediaProvider;
 | 
			
		||||
import dan200.computercraft.api.media.PrintoutContents;
 | 
			
		||||
import dan200.computercraft.api.network.PacketNetwork;
 | 
			
		||||
import dan200.computercraft.api.network.wired.WiredElement;
 | 
			
		||||
import dan200.computercraft.api.network.wired.WiredNode;
 | 
			
		||||
@@ -26,6 +26,7 @@ import dan200.computercraft.shared.computer.core.ResourceMount;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ServerContext;
 | 
			
		||||
import dan200.computercraft.shared.details.BlockDetails;
 | 
			
		||||
import dan200.computercraft.shared.details.ItemDetails;
 | 
			
		||||
import dan200.computercraft.shared.media.items.PrintoutItem;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.core.Direction;
 | 
			
		||||
import net.minecraft.core.Registry;
 | 
			
		||||
@@ -34,11 +35,12 @@ import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.util.stream.Stream;
 | 
			
		||||
 | 
			
		||||
public abstract class AbstractComputerCraftAPI implements ComputerCraftAPIService {
 | 
			
		||||
    private final DetailRegistry<ItemStack> itemStackDetails = new DetailRegistryImpl<>(ItemDetails::fillBasic);
 | 
			
		||||
@@ -90,11 +92,6 @@ public abstract class AbstractComputerCraftAPI implements ComputerCraftAPIServic
 | 
			
		||||
        return BundledRedstone.getDefaultOutput(world, pos, side);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public final void registerMediaProvider(MediaProvider provider) {
 | 
			
		||||
        MediaProviders.register(provider);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public final PacketNetwork getWirelessNetwork(MinecraftServer server) {
 | 
			
		||||
        return ServerContext.get(server).wirelessNetwork();
 | 
			
		||||
@@ -134,4 +131,21 @@ public abstract class AbstractComputerCraftAPI implements ComputerCraftAPIServic
 | 
			
		||||
    public final DetailRegistry<BlockReference> getBlockInWorldDetailRegistry() {
 | 
			
		||||
        return blockDetails;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @Nullable PrintoutContents getPrintoutContents(ItemStack stack) {
 | 
			
		||||
        return stack.getItem() instanceof PrintoutItem ? new PrintoutContentsImpl(stack) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public record PrintoutContentsImpl(ItemStack stack) implements PrintoutContents {
 | 
			
		||||
        @Override
 | 
			
		||||
        public String getTitle() {
 | 
			
		||||
            return PrintoutItem.getTitle(stack);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public Stream<String> getTextLines() {
 | 
			
		||||
            return Stream.of(PrintoutItem.getText(stack));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,46 +0,0 @@
 | 
			
		||||
// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: LicenseRef-CCPL
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.impl;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.api.media.IMedia;
 | 
			
		||||
import dan200.computercraft.api.media.MediaProvider;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.LinkedHashSet;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
public final class MediaProviders {
 | 
			
		||||
    private static final Logger LOG = LoggerFactory.getLogger(MediaProviders.class);
 | 
			
		||||
 | 
			
		||||
    private static final Set<MediaProvider> providers = new LinkedHashSet<>();
 | 
			
		||||
 | 
			
		||||
    private MediaProviders() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static synchronized void register(MediaProvider provider) {
 | 
			
		||||
        Objects.requireNonNull(provider, "provider cannot be null");
 | 
			
		||||
        providers.add(provider);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static @Nullable IMedia get(ItemStack stack) {
 | 
			
		||||
        if (stack.isEmpty()) return null;
 | 
			
		||||
 | 
			
		||||
        // Try the handlers in order:
 | 
			
		||||
        for (var mediaProvider : providers) {
 | 
			
		||||
            try {
 | 
			
		||||
                var media = mediaProvider.getMedia(stack);
 | 
			
		||||
                if (media != null) return media;
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                // Mod misbehaved, ignore it
 | 
			
		||||
                LOG.error("Media provider " + mediaProvider + " errored.", e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -18,10 +18,10 @@ import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
 | 
			
		||||
import net.minecraft.util.GsonHelper;
 | 
			
		||||
import net.minecraft.util.profiling.ProfilerFiller;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,11 +5,10 @@
 | 
			
		||||
package dan200.computercraft.impl.network.wired;
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.annotations.Contract;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Verifies certain elements of a network are well-formed.
 | 
			
		||||
 * <p>
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@
 | 
			
		||||
package dan200.computercraft.impl.network.wired;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.api.network.wired.WiredNode;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,8 @@ import dan200.computercraft.api.network.wired.WiredNetwork;
 | 
			
		||||
import dan200.computercraft.api.network.wired.WiredNode;
 | 
			
		||||
import dan200.computercraft.api.network.wired.WiredSender;
 | 
			
		||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 
 | 
			
		||||
@@ -30,8 +30,8 @@ import net.minecraft.world.level.storage.loot.BuiltInLootTables;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.LootPool;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.entries.LootTableReference;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.function.BiConsumer;
 | 
			
		||||
 | 
			
		||||
@@ -101,7 +101,7 @@ public final class CommonHooks {
 | 
			
		||||
        BuiltInLootTables.VILLAGE_CARTOGRAPHER
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    public static @Nullable LootPool.Builder getExtraLootPool(ResourceLocation lootTable) {
 | 
			
		||||
    public static LootPool.@Nullable Builder getExtraLootPool(ResourceLocation lootTable) {
 | 
			
		||||
        if (!lootTable.getNamespace().equals("minecraft") || !TREASURE_DISK_LOOT_TABLES.contains(lootTable)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,8 @@ import dan200.computercraft.api.component.ComputerComponents;
 | 
			
		||||
import dan200.computercraft.api.detail.DetailProvider;
 | 
			
		||||
import dan200.computercraft.api.detail.VanillaDetailRegistries;
 | 
			
		||||
import dan200.computercraft.api.media.IMedia;
 | 
			
		||||
import dan200.computercraft.api.network.wired.WiredElement;
 | 
			
		||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
			
		||||
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
 | 
			
		||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
 | 
			
		||||
import dan200.computercraft.api.upgrades.UpgradeData;
 | 
			
		||||
@@ -43,15 +45,14 @@ import dan200.computercraft.shared.details.ItemDetails;
 | 
			
		||||
import dan200.computercraft.shared.integration.PermissionRegistry;
 | 
			
		||||
import dan200.computercraft.shared.lectern.CustomLecternBlock;
 | 
			
		||||
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
 | 
			
		||||
import dan200.computercraft.shared.media.MountMedia;
 | 
			
		||||
import dan200.computercraft.shared.media.PrintoutMenu;
 | 
			
		||||
import dan200.computercraft.shared.media.items.DiskItem;
 | 
			
		||||
import dan200.computercraft.shared.media.items.PrintoutItem;
 | 
			
		||||
import dan200.computercraft.shared.media.items.RecordMedia;
 | 
			
		||||
import dan200.computercraft.shared.media.items.TreasureDiskItem;
 | 
			
		||||
import dan200.computercraft.shared.media.items.*;
 | 
			
		||||
import dan200.computercraft.shared.media.recipes.DiskRecipe;
 | 
			
		||||
import dan200.computercraft.shared.media.recipes.PrintoutRecipe;
 | 
			
		||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
 | 
			
		||||
import dan200.computercraft.shared.network.container.ContainerData;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlock;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlockEntity;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveMenu;
 | 
			
		||||
@@ -94,6 +95,7 @@ import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
 | 
			
		||||
import net.minecraft.commands.synchronization.SingletonArgumentInfo;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.core.Direction;
 | 
			
		||||
import net.minecraft.core.cauldron.CauldronInteraction;
 | 
			
		||||
import net.minecraft.core.registries.Registries;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
@@ -103,6 +105,7 @@ import net.minecraft.world.item.*;
 | 
			
		||||
import net.minecraft.world.item.crafting.CustomRecipe;
 | 
			
		||||
import net.minecraft.world.item.crafting.RecipeSerializer;
 | 
			
		||||
import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer;
 | 
			
		||||
import net.minecraft.world.level.ItemLike;
 | 
			
		||||
import net.minecraft.world.level.block.Block;
 | 
			
		||||
import net.minecraft.world.level.block.SoundType;
 | 
			
		||||
import net.minecraft.world.level.block.entity.BlockEntity;
 | 
			
		||||
@@ -112,6 +115,7 @@ import net.minecraft.world.level.block.state.BlockState;
 | 
			
		||||
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
 | 
			
		||||
import net.minecraft.world.level.material.MapColor;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.function.BiFunction;
 | 
			
		||||
@@ -462,12 +466,6 @@ public final class ModRegistry {
 | 
			
		||||
        // Register bundled power providers
 | 
			
		||||
        ComputerCraftAPI.registerBundledRedstoneProvider(new DefaultBundledRedstoneProvider());
 | 
			
		||||
        ComputerCraftAPI.registerRefuelHandler(new FurnaceRefuelHandler());
 | 
			
		||||
        ComputerCraftAPI.registerMediaProvider(stack -> {
 | 
			
		||||
            var item = stack.getItem();
 | 
			
		||||
            if (item instanceof IMedia media) return media;
 | 
			
		||||
            if (item instanceof RecordItem) return RecordMedia.INSTANCE;
 | 
			
		||||
            return null;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        ComputerCraftAPI.registerAPIFactory(computer -> {
 | 
			
		||||
            var turtle = computer.getComponent(ComputerComponents.TURTLE);
 | 
			
		||||
@@ -497,6 +495,76 @@ public final class ModRegistry {
 | 
			
		||||
        CauldronInteraction.WATER.put(Items.TURTLE_ADVANCED.get(), TurtleItem.CAULDRON_INTERACTION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Register our peripherals.
 | 
			
		||||
     *
 | 
			
		||||
     * @param peripherals The object to register our peripheral capability/lookups with.
 | 
			
		||||
     */
 | 
			
		||||
    public static void registerPeripherals(BlockComponent<IPeripheral, Direction> peripherals) {
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.COMPUTER_NORMAL.get(), (b, d) -> b.peripheral());
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.COMPUTER_ADVANCED.get(), (b, d) -> b.peripheral());
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.TURTLE_NORMAL.get(), (b, d) -> b.peripheral());
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.TURTLE_ADVANCED.get(), (b, d) -> b.peripheral());
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.SPEAKER.get(), (b, d) -> b.peripheral());
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.PRINTER.get(), (b, d) -> b.peripheral());
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.DISK_DRIVE.get(), (b, d) -> b.peripheral());
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.MONITOR_NORMAL.get(), (b, d) -> b.peripheral());
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), (b, d) -> b.peripheral());
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.WIRELESS_MODEM_NORMAL.get(), WirelessModemBlockEntity::getPeripheral);
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.WIRELESS_MODEM_ADVANCED.get(), WirelessModemBlockEntity::getPeripheral);
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.WIRED_MODEM_FULL.get(), WiredModemFullBlockEntity::getPeripheral);
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.CABLE.get(), CableBlockEntity::getPeripheral);
 | 
			
		||||
        peripherals.registerForBlockEntity(ModRegistry.BlockEntities.REDSTONE_RELAY.get(), (b, d) -> b.peripheral());
 | 
			
		||||
 | 
			
		||||
        peripherals.registerForBlockEntity(BlockEntityType.COMMAND_BLOCK, (b, d) -> Config.enableCommandBlock ? new CommandBlockPeripheral(b) : null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void registerWiredElements(BlockComponent<WiredElement, Direction> wiredElements) {
 | 
			
		||||
        wiredElements.registerForBlockEntity(ModRegistry.BlockEntities.WIRED_MODEM_FULL.get(), (b, d) -> b.getElement());
 | 
			
		||||
        wiredElements.registerForBlockEntity(ModRegistry.BlockEntities.CABLE.get(), CableBlockEntity::getWiredElement);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Register our custom {@link IMedia} implementations.
 | 
			
		||||
     *
 | 
			
		||||
     * @param media The object to register our media capabilities/lookups with.
 | 
			
		||||
     */
 | 
			
		||||
    public static void registerMedia(ItemComponent<IMedia> media) {
 | 
			
		||||
        media.registerForItems((s, c) -> MountMedia.COMPUTER,
 | 
			
		||||
            ModRegistry.Items.COMPUTER_NORMAL.get(), ModRegistry.Items.COMPUTER_ADVANCED.get(),
 | 
			
		||||
            ModRegistry.Items.TURTLE_NORMAL.get(), ModRegistry.Items.TURTLE_ADVANCED.get(),
 | 
			
		||||
            ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get()
 | 
			
		||||
        );
 | 
			
		||||
        media.registerForItems((s, c) -> MountMedia.DISK, ModRegistry.Items.DISK.get());
 | 
			
		||||
        media.registerForItems((s, c) -> TreasureDiskMedia.INSTANCE, ModRegistry.Items.TREASURE_DISK.get());
 | 
			
		||||
        media.registerFallback((stack, ctx) -> {
 | 
			
		||||
            if (stack.getItem() instanceof IMedia m) return m;
 | 
			
		||||
            if (stack.getItem() instanceof RecordItem) return RecordMedia.INSTANCE;
 | 
			
		||||
            return null;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * An abstraction for registering capabilities/block lookups for blocks and block entities.
 | 
			
		||||
     *
 | 
			
		||||
     * @param <T> The type of the component.
 | 
			
		||||
     * @param <C> The context parameter to the component.
 | 
			
		||||
     */
 | 
			
		||||
    public interface BlockComponent<T, C extends @Nullable Object> {
 | 
			
		||||
        <B extends BlockEntity> void registerForBlockEntity(BlockEntityType<B> blockEntityType, BiFunction<? super B, C, @Nullable T> provider);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * An abstraction for registering capabilities/block lookups for items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param <T> The type of the component.
 | 
			
		||||
     */
 | 
			
		||||
    public interface ItemComponent<T> {
 | 
			
		||||
        void registerForItems(BiFunction<ItemStack, @Nullable Void, @Nullable T> provider, ItemLike... items);
 | 
			
		||||
 | 
			
		||||
        void registerFallback(BiFunction<ItemStack, @Nullable Void, @Nullable T> provider);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) {
 | 
			
		||||
        out.accept(turtle.create(-1, null, -1, null, null, 0, null));
 | 
			
		||||
        TurtleUpgrades.getVanillaUpgrades()
 | 
			
		||||
 
 | 
			
		||||
@@ -34,8 +34,8 @@ import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.minecraft.world.phys.Vec3;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,8 +22,8 @@ import net.minecraft.network.chat.ComponentContents;
 | 
			
		||||
import net.minecraft.network.chat.MutableComponent;
 | 
			
		||||
import net.minecraft.world.phys.AABB;
 | 
			
		||||
import net.minecraft.world.phys.Vec3;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.concurrent.CompletableFuture;
 | 
			
		||||
import java.util.function.Function;
 | 
			
		||||
@@ -43,11 +43,11 @@ public record ComputerSelector(
 | 
			
		||||
    @Nullable String label,
 | 
			
		||||
    @Nullable ComputerFamily family,
 | 
			
		||||
    @Nullable AABB bounds,
 | 
			
		||||
    @Nullable MinMaxBounds.Doubles range
 | 
			
		||||
    MinMaxBounds.@Nullable Doubles range
 | 
			
		||||
) {
 | 
			
		||||
    private static final ComputerSelector all = new ComputerSelector("@c[]", OptionalInt.empty(), null, OptionalInt.empty(), null, null, null, null);
 | 
			
		||||
 | 
			
		||||
    private static UuidArgument uuidArgument = UuidArgument.uuid();
 | 
			
		||||
    private static final UuidArgument uuidArgument = UuidArgument.uuid();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A {@link ComputerSelector} which matches all computers.
 | 
			
		||||
@@ -279,7 +279,7 @@ public record ComputerSelector(
 | 
			
		||||
        private @Nullable String label;
 | 
			
		||||
        private @Nullable ComputerFamily family;
 | 
			
		||||
        private @Nullable AABB bounds;
 | 
			
		||||
        private @Nullable MinMaxBounds.Doubles range;
 | 
			
		||||
        private MinMaxBounds.@Nullable Doubles range;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static final Map<String, Option> options;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,8 @@ import com.mojang.brigadier.context.CommandContext;
 | 
			
		||||
import com.mojang.brigadier.tree.CommandNode;
 | 
			
		||||
import dan200.computercraft.shared.command.arguments.RepeatArgumentType;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.function.Predicate;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,8 @@ import net.minecraft.ChatFormatting;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.network.chat.ClickEvent;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.function.Predicate;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,7 @@ import net.minecraft.network.chat.ClickEvent;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.network.chat.HoverEvent;
 | 
			
		||||
import net.minecraft.network.chat.MutableComponent;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Various helpers for building chat messages.
 | 
			
		||||
 
 | 
			
		||||
@@ -7,8 +7,7 @@ package dan200.computercraft.shared.command.text;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
public class ServerTableFormatter implements TableFormatter {
 | 
			
		||||
    private final CommandSourceStack source;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,15 +11,15 @@ import dan200.computercraft.shared.network.server.ServerNetworking;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.server.level.ServerPlayer;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class TableBuilder {
 | 
			
		||||
    private final String id;
 | 
			
		||||
    private int columns = -1;
 | 
			
		||||
    private final @Nullable Component[] headers;
 | 
			
		||||
    private final Component @Nullable [] headers;
 | 
			
		||||
    private final ArrayList<Component[]> rows = new ArrayList<>();
 | 
			
		||||
    private int additional;
 | 
			
		||||
 | 
			
		||||
@@ -72,8 +72,7 @@ public class TableBuilder {
 | 
			
		||||
        return columns;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public Component[] getHeaders() {
 | 
			
		||||
    public Component @Nullable [] getHeaders() {
 | 
			
		||||
        return headers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,8 +7,7 @@ package dan200.computercraft.shared.command.text;
 | 
			
		||||
import net.minecraft.ChatFormatting;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import static dan200.computercraft.shared.command.text.ChatHelpers.coloured;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,7 @@ import net.minecraft.world.level.block.state.BlockState;
 | 
			
		||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
 | 
			
		||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
 | 
			
		||||
import net.minecraft.world.phys.BlockHitResult;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A block which has a container and can be placed in a horizontal direction.
 | 
			
		||||
 
 | 
			
		||||
@@ -36,8 +36,8 @@ import net.minecraft.world.level.block.state.BlockState;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.LootParams;
 | 
			
		||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
 | 
			
		||||
import net.minecraft.world.phys.BlockHitResult;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntity> extends HorizontalDirectionalBlock implements IBundledRedstoneBlock, EntityBlock {
 | 
			
		||||
 
 | 
			
		||||
@@ -34,8 +34,8 @@ import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
 | 
			
		||||
import net.minecraft.world.level.block.entity.BlockEntity;
 | 
			
		||||
import net.minecraft.world.level.block.entity.BlockEntityType;
 | 
			
		||||
import net.minecraft.world.level.block.state.BlockState;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,7 @@ import net.minecraft.world.level.block.state.StateDefinition;
 | 
			
		||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
 | 
			
		||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
 | 
			
		||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
public class ComputerBlock<T extends ComputerBlockEntity> extends AbstractComputerBlock<T> {
 | 
			
		||||
    public static final EnumProperty<ComputerState> STATE = EnumProperty.create("state", ComputerState.class);
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,7 @@ import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.inventory.AbstractContainerMenu;
 | 
			
		||||
import net.minecraft.world.level.block.entity.BlockEntityType;
 | 
			
		||||
import net.minecraft.world.level.block.state.BlockState;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
public class ComputerBlockEntity extends AbstractComputerBlockEntity {
 | 
			
		||||
    private @Nullable IPeripheral peripheral;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,8 +7,7 @@ package dan200.computercraft.shared.computer.blocks;
 | 
			
		||||
import dan200.computercraft.api.lua.LuaFunction;
 | 
			
		||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
			
		||||
import dan200.computercraft.core.apis.OSAPI;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A computer or turtle wrapped as a peripheral.
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,8 @@ import dan200.computercraft.core.apis.IAPIEnvironment;
 | 
			
		||||
import dan200.computercraft.core.computer.ApiLifecycle;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -29,8 +29,8 @@ import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.inventory.AbstractContainerMenu;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
@@ -214,7 +214,7 @@ public class ServerComputer implements ComputerEnvironment, ComputerEvents.Recei
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public final void queueEvent(String event, @Nullable Object[] arguments) {
 | 
			
		||||
    public final void queueEvent(String event, @Nullable Object @Nullable [] arguments) {
 | 
			
		||||
        computer.queueEvent(event, arguments);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,8 @@ package dan200.computercraft.shared.computer.core;
 | 
			
		||||
 | 
			
		||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 | 
			
		||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
public class ServerComputerRegistry {
 | 
			
		||||
 
 | 
			
		||||
@@ -26,10 +26,10 @@ import dan200.computercraft.shared.util.IDAssigner;
 | 
			
		||||
import net.minecraft.SharedConstants;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.world.level.storage.LevelResource;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 
 | 
			
		||||
@@ -21,8 +21,8 @@ import net.minecraft.world.inventory.ContainerData;
 | 
			
		||||
import net.minecraft.world.inventory.MenuType;
 | 
			
		||||
import net.minecraft.world.inventory.SimpleContainerData;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.function.Predicate;
 | 
			
		||||
 | 
			
		||||
public abstract class AbstractComputerMenu extends AbstractContainerMenu implements ComputerMenu {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,23 +4,18 @@
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.computer.items;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.api.ComputerCraftAPI;
 | 
			
		||||
import dan200.computercraft.api.filesystem.Mount;
 | 
			
		||||
import dan200.computercraft.api.media.IMedia;
 | 
			
		||||
import dan200.computercraft.shared.computer.blocks.AbstractComputerBlock;
 | 
			
		||||
import dan200.computercraft.shared.config.Config;
 | 
			
		||||
import net.minecraft.ChatFormatting;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import net.minecraft.world.item.BlockItem;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.item.TooltipFlag;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public abstract class AbstractComputerItem extends BlockItem implements IComputerItem, IMedia {
 | 
			
		||||
public abstract class AbstractComputerItem extends BlockItem implements IComputerItem {
 | 
			
		||||
    public AbstractComputerItem(AbstractComputerBlock<?> block, Properties settings) {
 | 
			
		||||
        super(block, settings);
 | 
			
		||||
    }
 | 
			
		||||
@@ -40,20 +35,4 @@ public abstract class AbstractComputerItem extends BlockItem implements ICompute
 | 
			
		||||
    public @Nullable String getLabel(ItemStack stack) {
 | 
			
		||||
        return IComputerItem.super.getLabel(stack);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean setLabel(ItemStack stack, @Nullable String label) {
 | 
			
		||||
        if (label != null) {
 | 
			
		||||
            stack.setHoverName(Component.literal(label));
 | 
			
		||||
        } else {
 | 
			
		||||
            stack.resetHoverName();
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
 | 
			
		||||
        var id = getComputerID(stack);
 | 
			
		||||
        return id >= 0 ? ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + id, Config.computerSpaceLimit) : null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,10 @@
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.computer.items;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.api.filesystem.Mount;
 | 
			
		||||
import dan200.computercraft.shared.computer.blocks.ComputerBlock;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.item.context.BlockPlaceContext;
 | 
			
		||||
import net.minecraft.world.level.block.state.BlockState;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A {@link ComputerItem} which prevents players placing it without permission.
 | 
			
		||||
@@ -29,10 +26,4 @@ public class CommandComputerItem extends ComputerItem {
 | 
			
		||||
        var player = context.getPlayer();
 | 
			
		||||
        return player != null && !player.canUseGameMasterBlocks() ? null : super.getPlacementState(context);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
 | 
			
		||||
        // Don't allow command computers to be mounted in disk drives.
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user