mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-08-06 22:04:39 +00:00
Merge branch 'mc-1.20.x' into mc-1.21.x
This commit is contained in:
commit
8f4d4038f6
@ -1,16 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package cc.tweaked.gradle
|
|
||||||
|
|
||||||
import groovy.util.Node
|
|
||||||
import groovy.util.NodeList
|
|
||||||
|
|
||||||
object XmlUtil {
|
|
||||||
fun findChild(node: Node, name: String): Node? = when (val child = node.get(name)) {
|
|
||||||
is Node -> child
|
|
||||||
is NodeList -> child.singleOrNull() as Node?
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
@ -58,11 +58,11 @@ junitPlatform = "1.11.4"
|
|||||||
jmh = "1.37"
|
jmh = "1.37"
|
||||||
|
|
||||||
# Build tools
|
# Build tools
|
||||||
cctJavadoc = "1.8.3"
|
cctJavadoc = "1.8.4"
|
||||||
checkstyle = "10.21.2"
|
checkstyle = "10.21.2"
|
||||||
errorProne-core = "2.36.0"
|
errorProne-core = "2.36.0"
|
||||||
errorProne-plugin = "4.1.0"
|
errorProne-plugin = "4.1.0"
|
||||||
fabric-loom = "1.9.2"
|
fabric-loom = "1.10.3"
|
||||||
githubRelease = "2.5.2"
|
githubRelease = "2.5.2"
|
||||||
gradleVersions = "0.50.0"
|
gradleVersions = "0.50.0"
|
||||||
ideaExt = "1.1.7"
|
ideaExt = "1.1.7"
|
||||||
@ -75,7 +75,7 @@ shadow = "8.3.1"
|
|||||||
spotless = "6.23.3"
|
spotless = "6.23.3"
|
||||||
taskTree = "2.1.1"
|
taskTree = "2.1.1"
|
||||||
teavm = "0.11.0-SQUID.1"
|
teavm = "0.11.0-SQUID.1"
|
||||||
vanillaExtract = "0.2.0"
|
vanillaExtract = "0.2.1"
|
||||||
versionCatalogUpdate = "0.8.1"
|
versionCatalogUpdate = "0.8.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
@ -51,10 +51,10 @@ public abstract class ComponentDetailProvider<T> implements DetailProvider<DataC
|
|||||||
* This method is always called on the server thread, so it is safe to interact with the world here, but you should
|
* This method is always called on the server thread, so it is safe to interact with the world here, but you should
|
||||||
* take care to avoid long blocking operations as this will stall the server and other computers.
|
* take care to avoid long blocking operations as this will stall the server and other computers.
|
||||||
*
|
*
|
||||||
* @param data The full details to be returned for this item stack. New properties should be added to this map.
|
* @param data The full details to be returned for this item stack. New properties should be added to this map.
|
||||||
* @param item The component to provide details for.
|
* @param component The component to provide details for.
|
||||||
*/
|
*/
|
||||||
public abstract void provideComponentDetails(Map<? super String, Object> data, T item);
|
public abstract void provideComponentDetails(Map<? super String, Object> data, T component);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void provideDetails(Map<? super String, Object> data, DataComponentHolder holder) {
|
public final void provideDetails(Map<? super String, Object> data, DataComponentHolder holder) {
|
||||||
|
@ -52,6 +52,8 @@ import net.minecraft.world.item.ItemStack;
|
|||||||
import net.minecraft.world.item.component.DyedItemColor;
|
import net.minecraft.world.item.component.DyedItemColor;
|
||||||
import net.minecraft.world.level.ItemLike;
|
import net.minecraft.world.level.ItemLike;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -69,6 +71,8 @@ import java.util.function.Supplier;
|
|||||||
* @see ModRegistry The common registry for actual game objects.
|
* @see ModRegistry The common registry for actual game objects.
|
||||||
*/
|
*/
|
||||||
public final class ClientRegistry {
|
public final class ClientRegistry {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ClientRegistry.class);
|
||||||
|
|
||||||
private ClientRegistry() {
|
private ClientRegistry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +196,18 @@ public final class ClientRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
|
public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
|
||||||
RenderTypes.registerShaders(resources, load);
|
RenderTypes.registerShaders(resources, (name, create, onLoaded) -> {
|
||||||
|
ShaderInstance shader;
|
||||||
|
try {
|
||||||
|
shader = create.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Failed to load {}", name, e);
|
||||||
|
onLoaded.accept(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
load.accept(shader, onLoaded);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private record UnclampedPropertyFunction(
|
private record UnclampedPropertyFunction(
|
||||||
|
@ -12,6 +12,7 @@ import dan200.computercraft.client.pocket.ClientPocketComputers;
|
|||||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
import dan200.computercraft.core.util.Colour;
|
import dan200.computercraft.core.util.Colour;
|
||||||
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
|
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutData;
|
import dan200.computercraft.shared.media.items.PrintoutData;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||||
@ -59,9 +60,9 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
|
|||||||
poseStack.translate(0, -0.125f, 0);
|
poseStack.translate(0, -0.125f, 0);
|
||||||
|
|
||||||
var item = lectern.getItem();
|
var item = lectern.getItem();
|
||||||
if (item.getItem() instanceof PrintoutItem printout) {
|
if (item.getItem() instanceof PrintoutItem) {
|
||||||
var vertexConsumer = LecternPrintoutModel.MATERIAL.buffer(buffer, RenderType::entitySolid);
|
var vertexConsumer = LecternPrintoutModel.MATERIAL.buffer(buffer, RenderType::entitySolid);
|
||||||
if (printout.getType() == PrintoutItem.Type.BOOK) {
|
if (item.is(ModRegistry.Items.PRINTED_BOOK.get())) {
|
||||||
printoutModel.renderBook(poseStack, vertexConsumer, packedLight, packedOverlay);
|
printoutModel.renderBook(poseStack, vertexConsumer, packedLight, packedOverlay);
|
||||||
} else {
|
} else {
|
||||||
printoutModel.renderPages(poseStack, vertexConsumer, packedLight, packedOverlay, PrintoutData.getOrEmpty(item).pages());
|
printoutModel.renderPages(poseStack, vertexConsumer, packedLight, packedOverlay, PrintoutData.getOrEmpty(item).pages());
|
||||||
|
@ -8,7 +8,6 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutData;
|
import dan200.computercraft.shared.media.items.PrintoutData;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||||
@ -53,7 +52,7 @@ public final class PrintoutItemRenderer extends ItemMapLikeRenderer {
|
|||||||
var pageData = stack.getOrDefault(ModRegistry.DataComponents.PRINTOUT.get(), PrintoutData.EMPTY);
|
var pageData = stack.getOrDefault(ModRegistry.DataComponents.PRINTOUT.get(), PrintoutData.EMPTY);
|
||||||
|
|
||||||
var pages = pageData.pages();
|
var pages = pageData.pages();
|
||||||
var book = ((PrintoutItem) stack.getItem()).getType() == PrintoutItem.Type.BOOK;
|
var book = stack.is(ModRegistry.Items.PRINTED_BOOK.get());
|
||||||
|
|
||||||
double width = LINE_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2;
|
double width = LINE_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2;
|
||||||
double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2;
|
double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2;
|
||||||
|
@ -16,11 +16,11 @@ import net.minecraft.client.renderer.RenderType;
|
|||||||
import net.minecraft.client.renderer.ShaderInstance;
|
import net.minecraft.client.renderer.ShaderInstance;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.packs.resources.ResourceProvider;
|
import net.minecraft.server.packs.resources.ResourceProvider;
|
||||||
|
import org.apache.commons.io.function.IOSupplier;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,9 +68,12 @@ public class RenderTypes {
|
|||||||
return Objects.requireNonNull(GameRenderer.getRendertypeTextShader(), "Text shader has not been registered");
|
return Objects.requireNonNull(GameRenderer.getRendertypeTextShader(), "Text shader has not been registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
|
public interface ShaderLoader {
|
||||||
load.accept(
|
void tryLoad(String name, IOSupplier<ShaderInstance> create, Consumer<@Nullable ShaderInstance> accept) throws IOException;
|
||||||
new MonitorTextureBufferShader(
|
}
|
||||||
|
|
||||||
|
public static void registerShaders(ResourceProvider resources, ShaderLoader load) throws IOException {
|
||||||
|
load.tryLoad("monitor shader", () -> new MonitorTextureBufferShader(
|
||||||
resources,
|
resources,
|
||||||
ComputerCraftAPI.MOD_ID + "/monitor_tbo",
|
ComputerCraftAPI.MOD_ID + "/monitor_tbo",
|
||||||
MONITOR_TBO.format()
|
MONITOR_TBO.format()
|
||||||
|
@ -284,11 +284,11 @@ public final class ModRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final RegistryEntry<PrintoutItem> PRINTED_PAGE = REGISTRY.register("printed_page",
|
public static final RegistryEntry<PrintoutItem> PRINTED_PAGE = REGISTRY.register("printed_page",
|
||||||
() -> new PrintoutItem(printoutProperties(), PrintoutItem.Type.PAGE));
|
() -> new PrintoutItem(printoutProperties()));
|
||||||
public static final RegistryEntry<PrintoutItem> PRINTED_PAGES = REGISTRY.register("printed_pages",
|
public static final RegistryEntry<PrintoutItem> PRINTED_PAGES = REGISTRY.register("printed_pages",
|
||||||
() -> new PrintoutItem(printoutProperties(), PrintoutItem.Type.PAGES));
|
() -> new PrintoutItem(printoutProperties()));
|
||||||
public static final RegistryEntry<PrintoutItem> PRINTED_BOOK = REGISTRY.register("printed_book",
|
public static final RegistryEntry<PrintoutItem> PRINTED_BOOK = REGISTRY.register("printed_book",
|
||||||
() -> new PrintoutItem(printoutProperties(), PrintoutItem.Type.BOOK));
|
() -> new PrintoutItem(printoutProperties()));
|
||||||
|
|
||||||
public static final RegistryEntry<BlockItem> SPEAKER = ofBlock(Blocks.SPEAKER, BlockItem::new);
|
public static final RegistryEntry<BlockItem> SPEAKER = ofBlock(Blocks.SPEAKER, BlockItem::new);
|
||||||
public static final RegistryEntry<BlockItem> DISK_DRIVE = ofBlock(Blocks.DISK_DRIVE, BlockItem::new);
|
public static final RegistryEntry<BlockItem> DISK_DRIVE = ofBlock(Blocks.DISK_DRIVE, BlockItem::new);
|
||||||
|
@ -20,17 +20,8 @@ import net.minecraft.world.level.Level;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class PrintoutItem extends Item {
|
public class PrintoutItem extends Item {
|
||||||
public enum Type {
|
public PrintoutItem(Properties settings) {
|
||||||
PAGE,
|
|
||||||
PAGES,
|
|
||||||
BOOK
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Type type;
|
|
||||||
|
|
||||||
public PrintoutItem(Properties settings, Type type) {
|
|
||||||
super(settings);
|
super(settings);
|
||||||
this.type = type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -49,8 +40,4 @@ public class PrintoutItem extends Item {
|
|||||||
}
|
}
|
||||||
return new InteractionResultHolder<>(InteractionResult.sidedSuccess(world.isClientSide), stack);
|
return new InteractionResultHolder<>(InteractionResult.sidedSuccess(world.isClientSide), stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -170,8 +170,7 @@ public final class PrinterBlockEntity extends AbstractContainerBlockEntity imple
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean isPaper(ItemStack stack) {
|
static boolean isPaper(ItemStack stack) {
|
||||||
var item = stack.getItem();
|
return stack.is(Items.PAPER) || stack.is(ModRegistry.Items.PRINTED_PAGE.get());
|
||||||
return item == Items.PAPER || item == ModRegistry.Items.PRINTED_PAGE.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canInputPage() {
|
private boolean canInputPage() {
|
||||||
|
@ -13,7 +13,9 @@ import dan200.computercraft.core.metrics.Metrics;
|
|||||||
import dan200.computercraft.core.metrics.MetricsObserver;
|
import dan200.computercraft.core.metrics.MetricsObserver;
|
||||||
import dan200.computercraft.shared.peripheral.generic.methods.AbstractInventoryMethods;
|
import dan200.computercraft.shared.peripheral.generic.methods.AbstractInventoryMethods;
|
||||||
import dan200.computercraft.shared.turtle.core.*;
|
import dan200.computercraft.shared.turtle.core.*;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -659,6 +661,7 @@ public class TurtleAPI implements ILuaAPI {
|
|||||||
* @cc.treturn [2] string The reason equipping this item failed.
|
* @cc.treturn [2] string The reason equipping this item failed.
|
||||||
* @cc.since 1.6
|
* @cc.since 1.6
|
||||||
* @see #equipRight()
|
* @see #equipRight()
|
||||||
|
* @see #getEquippedLeft()
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult equipLeft() {
|
public final MethodResult equipLeft() {
|
||||||
@ -678,12 +681,45 @@ public class TurtleAPI implements ILuaAPI {
|
|||||||
* @cc.treturn [2] string The reason equipping this item failed.
|
* @cc.treturn [2] string The reason equipping this item failed.
|
||||||
* @cc.since 1.6
|
* @cc.since 1.6
|
||||||
* @see #equipLeft()
|
* @see #equipLeft()
|
||||||
|
* @see #getEquippedRight()
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult equipRight() {
|
public final MethodResult equipRight() {
|
||||||
return trackCommand(new TurtleEquipCommand(TurtleSide.RIGHT));
|
return trackCommand(new TurtleEquipCommand(TurtleSide.RIGHT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the upgrade currently equipped on the left of the turtle.
|
||||||
|
* <p>
|
||||||
|
* This returns information about the currently equipped item, in the same form as
|
||||||
|
* {@link #getItemDetail(ILuaContext, Optional, Optional)}.
|
||||||
|
*
|
||||||
|
* @return Details about the currently equipped item, or {@code nil} if no upgrade is equipped.
|
||||||
|
* @see #equipLeft()
|
||||||
|
* @cc.since 1.116.0
|
||||||
|
*/
|
||||||
|
@LuaFunction(mainThread = true)
|
||||||
|
public final @Nullable Map<?, ?> getEquippedLeft() {
|
||||||
|
var upgrade = turtle.getUpgradeWithData(TurtleSide.LEFT);
|
||||||
|
return upgrade == null ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(upgrade.getUpgradeItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the upgrade currently equipped on the right of the turtle.
|
||||||
|
* <p>
|
||||||
|
* This returns information about the currently equipped item, in the same form as
|
||||||
|
* {@link #getItemDetail(ILuaContext, Optional, Optional)}.
|
||||||
|
*
|
||||||
|
* @return Details about the currently equipped item, or {@code nil} if no upgrade is equipped.
|
||||||
|
* @see #equipRight()
|
||||||
|
* @cc.since 1.116.0
|
||||||
|
*/
|
||||||
|
@LuaFunction(mainThread = true)
|
||||||
|
public final @Nullable Map<?, ?> getEquippedRight() {
|
||||||
|
var upgrade = turtle.getUpgradeWithData(TurtleSide.RIGHT);
|
||||||
|
return upgrade == null ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(upgrade.getUpgradeItem());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about the block in front of the turtle.
|
* Get information about the block in front of the turtle.
|
||||||
*
|
*
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"parent": "computercraft:block/turtle_base",
|
"parent": "computercraft:block/turtle_base",
|
||||||
"textures": {
|
"textures": {
|
||||||
"texture": "computercraft:block/turtle_colour",
|
"particle": "computercraft:block/turtle_colour_body_front",
|
||||||
"body_back": "computercraft:block/turtle_colour_body_back",
|
"body_back": "computercraft:block/turtle_colour_body_back",
|
||||||
"body_backpack": "computercraft:block/turtle_colour_body_backpack",
|
"body_backpack": "computercraft:block/turtle_colour_body_backpack",
|
||||||
"body_bottom": "computercraft:block/turtle_colour_body_bottom",
|
"body_bottom": "computercraft:block/turtle_colour_body_bottom",
|
||||||
|
@ -27,6 +27,11 @@ public class ItemStackMatcher extends TypeSafeMatcher<ItemStack> {
|
|||||||
description.appendValue(stack).appendValue(stack.getComponentsPatch());
|
description.appendValue(stack).appendValue(stack.getComponentsPatch());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void describeMismatchSafely(ItemStack item, Description description) {
|
||||||
|
description.appendText("was ").appendValue(stack).appendValue(stack.getComponentsPatch());
|
||||||
|
}
|
||||||
|
|
||||||
public static Matcher<ItemStack> isStack(ItemStack stack) {
|
public static Matcher<ItemStack> isStack(ItemStack stack) {
|
||||||
return new ItemStackMatcher(stack);
|
return new ItemStackMatcher(stack);
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,20 @@
|
|||||||
package dan200.computercraft.gametest
|
package dan200.computercraft.gametest
|
||||||
|
|
||||||
import dan200.computercraft.gametest.api.*
|
import dan200.computercraft.gametest.api.*
|
||||||
|
import dan200.computercraft.shared.ModRegistry
|
||||||
|
import dan200.computercraft.shared.media.items.PrintoutData
|
||||||
|
import dan200.computercraft.shared.util.DataComponentUtil
|
||||||
|
import dan200.computercraft.test.shared.ItemStackMatcher.isStack
|
||||||
|
import net.minecraft.gametest.framework.GameTest
|
||||||
import net.minecraft.gametest.framework.GameTestGenerator
|
import net.minecraft.gametest.framework.GameTestGenerator
|
||||||
import net.minecraft.gametest.framework.GameTestHelper
|
import net.minecraft.gametest.framework.GameTestHelper
|
||||||
import net.minecraft.gametest.framework.TestFunction
|
import net.minecraft.gametest.framework.TestFunction
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
import org.hamcrest.MatcherAssert.assertThat
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import java.util.function.Supplier
|
||||||
|
|
||||||
class Printout_Test {
|
class Printout_Test {
|
||||||
/**
|
/**
|
||||||
@ -56,4 +67,54 @@ class Printout_Test {
|
|||||||
|
|
||||||
thenExecute { helper.level.dayTime = Times.NOON }
|
thenExecute { helper.level.dayTime = Times.NOON }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GameTest(template = "default")
|
||||||
|
fun Craft_pages(helper: GameTestHelper) = helper.immediate {
|
||||||
|
// Assert that crafting with only one page fails
|
||||||
|
helper.assertNotCraftable(ItemStack(ModRegistry.Items.PRINTED_PAGE.get()), ItemStack(Items.STRING))
|
||||||
|
|
||||||
|
// Assert that crafting with no pages fails
|
||||||
|
helper.assertNotCraftable(ItemStack(Items.PAPER), ItemStack(Items.PAPER), ItemStack(Items.STRING))
|
||||||
|
|
||||||
|
// Assert that crafting with a book fails
|
||||||
|
helper.assertNotCraftable(ItemStack(ModRegistry.Items.PRINTED_PAGE.get()), ItemStack(ModRegistry.Items.PRINTED_BOOK.get()), ItemStack(Items.STRING))
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
helper.craftItem(
|
||||||
|
createPrintoutOf(ModRegistry.Items.PRINTED_PAGE, "First"),
|
||||||
|
createPrintoutOf(ModRegistry.Items.PRINTED_PAGES, "First"),
|
||||||
|
ItemStack(Items.STRING),
|
||||||
|
),
|
||||||
|
isStack(createPrintoutOf(ModRegistry.Items.PRINTED_PAGES, "First", 2)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@GameTest(template = "default")
|
||||||
|
fun Craft_book(helper: GameTestHelper) = helper.immediate {
|
||||||
|
// Assert that crafting with no pages fails
|
||||||
|
helper.assertNotCraftable(ItemStack(Items.PAPER), ItemStack(Items.PAPER), ItemStack(Items.STRING), ItemStack(Items.LEATHER))
|
||||||
|
|
||||||
|
// Assert that crafting with only one page works
|
||||||
|
assertEquals(
|
||||||
|
ModRegistry.Items.PRINTED_BOOK.get(),
|
||||||
|
helper.craftItem(ItemStack(ModRegistry.Items.PRINTED_PAGE.get()), ItemStack(Items.STRING), ItemStack(Items.LEATHER)).item,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
helper.craftItem(
|
||||||
|
createPrintoutOf(ModRegistry.Items.PRINTED_PAGE, "First"),
|
||||||
|
createPrintoutOf(ModRegistry.Items.PRINTED_PAGES, "First"),
|
||||||
|
ItemStack(Items.STRING),
|
||||||
|
ItemStack(Items.LEATHER),
|
||||||
|
),
|
||||||
|
isStack(createPrintoutOf(ModRegistry.Items.PRINTED_BOOK, "First", 2)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createPrintoutOf(item: Supplier<out Item>, title: String, pages: Int = 1): ItemStack {
|
||||||
|
val line =
|
||||||
|
PrintoutData.Line(" ".repeat(PrintoutData.LINE_LENGTH), 'b'.toString().repeat(PrintoutData.LINE_LENGTH))
|
||||||
|
val lines = List(PrintoutData.LINES_PER_PAGE * pages) { line }
|
||||||
|
return DataComponentUtil.createStack(item.get(), ModRegistry.DataComponents.PRINTOUT.get(), PrintoutData(title, lines))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,16 @@ package dan200.computercraft.gametest
|
|||||||
|
|
||||||
import com.mojang.authlib.GameProfile
|
import com.mojang.authlib.GameProfile
|
||||||
import dan200.computercraft.gametest.api.Structures
|
import dan200.computercraft.gametest.api.Structures
|
||||||
|
import dan200.computercraft.gametest.api.craftItem
|
||||||
import dan200.computercraft.gametest.api.sequence
|
import dan200.computercraft.gametest.api.sequence
|
||||||
import dan200.computercraft.shared.ModRegistry
|
import dan200.computercraft.shared.ModRegistry
|
||||||
import net.minecraft.core.NonNullList
|
|
||||||
import net.minecraft.core.component.DataComponentPatch
|
import net.minecraft.core.component.DataComponentPatch
|
||||||
import net.minecraft.core.component.DataComponents
|
import net.minecraft.core.component.DataComponents
|
||||||
import net.minecraft.gametest.framework.GameTest
|
import net.minecraft.gametest.framework.GameTest
|
||||||
import net.minecraft.gametest.framework.GameTestAssertException
|
|
||||||
import net.minecraft.gametest.framework.GameTestHelper
|
import net.minecraft.gametest.framework.GameTestHelper
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.Items
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraft.world.item.component.ResolvableProfile
|
import net.minecraft.world.item.component.ResolvableProfile
|
||||||
import net.minecraft.world.item.crafting.CraftingInput
|
|
||||||
import net.minecraft.world.item.crafting.RecipeType
|
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -31,16 +28,10 @@ class Recipe_Test {
|
|||||||
@GameTest(template = Structures.DEFAULT)
|
@GameTest(template = Structures.DEFAULT)
|
||||||
fun Craft_result_has_nbt(context: GameTestHelper) = context.sequence {
|
fun Craft_result_has_nbt(context: GameTestHelper) = context.sequence {
|
||||||
thenExecute {
|
thenExecute {
|
||||||
val items = NonNullList.withSize(3 * 3, ItemStack.EMPTY)
|
val result = context.craftItem(
|
||||||
items[0] = ItemStack(Items.SKELETON_SKULL)
|
ItemStack(Items.SKELETON_SKULL),
|
||||||
items[1] = ItemStack(ModRegistry.Items.COMPUTER_ADVANCED.get())
|
ItemStack(ModRegistry.Items.COMPUTER_ADVANCED.get()),
|
||||||
val container = CraftingInput.of(3, 3, items)
|
)
|
||||||
|
|
||||||
val recipe = context.level.server.recipeManager
|
|
||||||
.getRecipeFor(RecipeType.CRAFTING, container, context.level)
|
|
||||||
.orElseThrow { GameTestAssertException("No recipe matches") }
|
|
||||||
|
|
||||||
val result = recipe.value.assemble(container, context.level.registryAccess())
|
|
||||||
|
|
||||||
val profile = GameProfile(UUID.fromString("f3c8d69b-0776-4512-8434-d1b2165909eb"), "dan200")
|
val profile = GameProfile(UUID.fromString("f3c8d69b-0776-4512-8434-d1b2165909eb"), "dan200")
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ package dan200.computercraft.gametest
|
|||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI
|
import dan200.computercraft.api.ComputerCraftAPI
|
||||||
import dan200.computercraft.api.ComputerCraftTags
|
import dan200.computercraft.api.ComputerCraftTags
|
||||||
import dan200.computercraft.api.detail.BasicItemDetailProvider
|
import dan200.computercraft.api.detail.ComponentDetailProvider
|
||||||
import dan200.computercraft.api.detail.VanillaDetailRegistries
|
import dan200.computercraft.api.detail.VanillaDetailRegistries
|
||||||
import dan200.computercraft.api.lua.ObjectArguments
|
import dan200.computercraft.api.lua.ObjectArguments
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade
|
import dan200.computercraft.api.turtle.ITurtleUpgrade
|
||||||
@ -18,7 +18,7 @@ import dan200.computercraft.gametest.core.TestHooks
|
|||||||
import dan200.computercraft.mixin.gametest.GameTestHelperAccessor
|
import dan200.computercraft.mixin.gametest.GameTestHelperAccessor
|
||||||
import dan200.computercraft.mixin.gametest.GameTestInfoAccessor
|
import dan200.computercraft.mixin.gametest.GameTestInfoAccessor
|
||||||
import dan200.computercraft.shared.ModRegistry
|
import dan200.computercraft.shared.ModRegistry
|
||||||
import dan200.computercraft.shared.media.items.PrintoutItem
|
import dan200.computercraft.shared.media.items.PrintoutData
|
||||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock
|
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock
|
||||||
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant
|
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant
|
||||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlock
|
import dan200.computercraft.shared.peripheral.monitor.MonitorBlock
|
||||||
@ -453,16 +453,16 @@ class Turtle_Test {
|
|||||||
thenExecute {
|
thenExecute {
|
||||||
VanillaDetailRegistries.ITEM_STACK.addProvider(
|
VanillaDetailRegistries.ITEM_STACK.addProvider(
|
||||||
object :
|
object :
|
||||||
BasicItemDetailProvider<PrintoutItem>("printout", PrintoutItem::class.java) {
|
ComponentDetailProvider<PrintoutData>("printout", ModRegistry.DataComponents.PRINTOUT.get()) {
|
||||||
override fun provideDetails(data: MutableMap<in String, Any>, stack: ItemStack, item: PrintoutItem) {
|
override fun provideComponentDetails(data: MutableMap<in String, Any>, component: PrintoutData) {
|
||||||
data["type"] = item.type.toString().lowercase()
|
data["pages"] = component.pages()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
thenOnComputer {
|
thenOnComputer {
|
||||||
val details = getTurtleItemDetail(detailed = true)
|
val details = getTurtleItemDetail(detailed = true)
|
||||||
assertEquals(mapOf("type" to "page"), details["printout"]) {
|
assertEquals(mapOf("pages" to 1), details["printout"]) {
|
||||||
"Printout information is returned (whole map is $details)"
|
"Printout information is returned (whole map is $details)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import dan200.computercraft.test.shared.ItemStackMatcher.isStack
|
|||||||
import net.minecraft.commands.arguments.blocks.BlockInput
|
import net.minecraft.commands.arguments.blocks.BlockInput
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
|
import net.minecraft.core.NonNullList
|
||||||
import net.minecraft.core.registries.BuiltInRegistries
|
import net.minecraft.core.registries.BuiltInRegistries
|
||||||
import net.minecraft.gametest.framework.*
|
import net.minecraft.gametest.framework.*
|
||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
@ -25,6 +26,8 @@ import net.minecraft.world.entity.EntityType
|
|||||||
import net.minecraft.world.item.Item
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.context.UseOnContext
|
import net.minecraft.world.item.context.UseOnContext
|
||||||
|
import net.minecraft.world.item.crafting.CraftingInput
|
||||||
|
import net.minecraft.world.item.crafting.RecipeType
|
||||||
import net.minecraft.world.level.GameType
|
import net.minecraft.world.level.GameType
|
||||||
import net.minecraft.world.level.block.Blocks
|
import net.minecraft.world.level.block.Blocks
|
||||||
import net.minecraft.world.level.block.entity.BarrelBlockEntity
|
import net.minecraft.world.level.block.entity.BarrelBlockEntity
|
||||||
@ -340,6 +343,34 @@ fun GameTestHelper.placeItemAt(stack: ItemStack, pos: BlockPos, direction: Direc
|
|||||||
stack.useOn(UseOnContext(player, InteractionHand.MAIN_HAND, hit))
|
stack.useOn(UseOnContext(player, InteractionHand.MAIN_HAND, hit))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a recipe is not craftable.
|
||||||
|
*/
|
||||||
|
fun GameTestHelper.assertNotCraftable(vararg items: ItemStack) {
|
||||||
|
val container = NonNullList.withSize(3 * 3, ItemStack.EMPTY)
|
||||||
|
for ((i, item) in items.withIndex()) container[i] = item
|
||||||
|
val input = CraftingInput.of(3, 3, container)
|
||||||
|
|
||||||
|
val recipe = level.server.recipeManager.getRecipeFor(RecipeType.CRAFTING, input, level)
|
||||||
|
|
||||||
|
if (recipe.isPresent) fail("Expected no recipe to match $items")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to craft an item.
|
||||||
|
*/
|
||||||
|
fun GameTestHelper.craftItem(vararg items: ItemStack): ItemStack {
|
||||||
|
val container = NonNullList.withSize(3 * 3, ItemStack.EMPTY)
|
||||||
|
for ((i, item) in items.withIndex()) container[i] = item
|
||||||
|
val input = CraftingInput.of(3, 3, container)
|
||||||
|
|
||||||
|
val recipe = level.server.recipeManager
|
||||||
|
.getRecipeFor(RecipeType.CRAFTING, input, level)
|
||||||
|
.orElseThrow { GameTestAssertException("No recipe matches $items") }
|
||||||
|
|
||||||
|
return recipe.value.assemble(input, level.registryAccess())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run a function multiple times until it succeeds.
|
* Run a function multiple times until it succeeds.
|
||||||
*/
|
*/
|
||||||
|
@ -223,6 +223,9 @@ public interface IArguments {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an argument as a table.
|
* Get an argument as a table.
|
||||||
|
* <p>
|
||||||
|
* The returned table may be converted into a {@link LuaTable} (using {@link ObjectLuaTable}) for easier parsing of
|
||||||
|
* table keys.
|
||||||
*
|
*
|
||||||
* @param index The argument number.
|
* @param index The argument number.
|
||||||
* @return The argument's value.
|
* @return The argument's value.
|
||||||
|
@ -7,15 +7,18 @@ package dan200.computercraft.api.lua;
|
|||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static dan200.computercraft.api.lua.LuaValues.*;
|
import static dan200.computercraft.api.lua.LuaValues.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A view of a Lua table, which may be able to access table elements in a more optimised manner than
|
* A view of a Lua table.
|
||||||
* {@link IArguments#getTable(int)}.
|
* <p>
|
||||||
|
* Much like {@link IArguments}, this allows for convenient parsing of fields from a Lua table.
|
||||||
*
|
*
|
||||||
* @param <K> The type of keys in a table, will typically be a wildcard.
|
* @param <K> The type of keys in a table, will typically be a wildcard.
|
||||||
* @param <V> The type of values in a table, will typically be a wildcard.
|
* @param <V> The type of values in a table, will typically be a wildcard.
|
||||||
|
* @see ObjectArguments
|
||||||
*/
|
*/
|
||||||
public interface LuaTable<K, V> extends Map<K, V> {
|
public interface LuaTable<K, V> extends Map<K, V> {
|
||||||
/**
|
/**
|
||||||
@ -29,19 +32,47 @@ public interface LuaTable<K, V> extends Map<K, V> {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array entry as a double.
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value.
|
||||||
|
* @throws LuaException If the value is not a number.
|
||||||
|
* @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN).
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default double getDouble(int index) throws LuaException {
|
||||||
|
Object value = get((double) index);
|
||||||
|
if (!(value instanceof Number number)) throw badTableItem(index, "number", getType(value));
|
||||||
|
return number.doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a table entry as a double.
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value.
|
||||||
|
* @throws LuaException If the value is not a number.
|
||||||
|
* @see #getFiniteDouble(String) if you require this to be finite (i.e. not infinite or NaN).
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default double getDouble(String key) throws LuaException {
|
||||||
|
Object value = get(key);
|
||||||
|
if (!(value instanceof Number number)) throw badField(key, "number", getType(value));
|
||||||
|
return number.doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an array entry as an integer.
|
* Get an array entry as an integer.
|
||||||
*
|
*
|
||||||
* @param index The index in the table, starting at 1.
|
* @param index The index in the table, starting at 1.
|
||||||
* @return The table's value.
|
* @return The entry's value.
|
||||||
* @throws LuaException If the value is not an integer.
|
* @throws LuaException If the value is not an integer.
|
||||||
*/
|
*/
|
||||||
default long getLong(int index) throws LuaException {
|
default long getLong(int index) throws LuaException {
|
||||||
Object value = get((double) index);
|
Object value = get((double) index);
|
||||||
if (!(value instanceof Number number)) throw badTableItem(index, "number", getType(value));
|
if (!(value instanceof Number number)) throw badTableItem(index, "number", getType(value));
|
||||||
|
checkFiniteIndex(index, number.doubleValue());
|
||||||
var asDouble = number.doubleValue();
|
|
||||||
if (!Double.isFinite(asDouble)) throw badTableItem(index, "number", getNumericType(asDouble));
|
|
||||||
return number.longValue();
|
return number.longValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,15 +80,13 @@ public interface LuaTable<K, V> extends Map<K, V> {
|
|||||||
* Get a table entry as an integer.
|
* Get a table entry as an integer.
|
||||||
*
|
*
|
||||||
* @param key The name of the field in the table.
|
* @param key The name of the field in the table.
|
||||||
* @return The table's value.
|
* @return The field's value.
|
||||||
* @throws LuaException If the value is not an integer.
|
* @throws LuaException If the value is not an integer.
|
||||||
*/
|
*/
|
||||||
default long getLong(String key) throws LuaException {
|
default long getLong(String key) throws LuaException {
|
||||||
Object value = get(key);
|
Object value = get(key);
|
||||||
if (!(value instanceof Number number)) throw badField(key, "number", getType(value));
|
if (!(value instanceof Number number)) throw badField(key, "number", getType(value));
|
||||||
|
checkFiniteField(key, number.doubleValue());
|
||||||
var asDouble = number.doubleValue();
|
|
||||||
if (!Double.isFinite(asDouble)) throw badField(key, "number", getNumericType(asDouble));
|
|
||||||
return number.longValue();
|
return number.longValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +94,7 @@ public interface LuaTable<K, V> extends Map<K, V> {
|
|||||||
* Get an array entry as an integer.
|
* Get an array entry as an integer.
|
||||||
*
|
*
|
||||||
* @param index The index in the table, starting at 1.
|
* @param index The index in the table, starting at 1.
|
||||||
* @return The table's value.
|
* @return The entry's value.
|
||||||
* @throws LuaException If the value is not an integer.
|
* @throws LuaException If the value is not an integer.
|
||||||
*/
|
*/
|
||||||
default int getInt(int index) throws LuaException {
|
default int getInt(int index) throws LuaException {
|
||||||
@ -76,13 +105,339 @@ public interface LuaTable<K, V> extends Map<K, V> {
|
|||||||
* Get a table entry as an integer.
|
* Get a table entry as an integer.
|
||||||
*
|
*
|
||||||
* @param key The name of the field in the table.
|
* @param key The name of the field in the table.
|
||||||
* @return The table's value.
|
* @return The field's value.
|
||||||
* @throws LuaException If the value is not an integer.
|
* @throws LuaException If the value is not an integer.
|
||||||
*/
|
*/
|
||||||
default int getInt(String key) throws LuaException {
|
default int getInt(String key) throws LuaException {
|
||||||
return (int) getLong(key);
|
return (int) getLong(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an argument as a finite number (not infinite or NaN).
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value.
|
||||||
|
* @throws LuaException If the value is not finite.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default double getFiniteDouble(int index) throws LuaException {
|
||||||
|
return checkFiniteIndex(index, getDouble(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an argument as a finite number (not infinite or NaN).
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value.
|
||||||
|
* @throws LuaException If the value is not finite.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default double getFiniteDouble(String key) throws LuaException {
|
||||||
|
return checkFiniteField(key, getDouble(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array entry as a boolean.
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value.
|
||||||
|
* @throws LuaException If the value is not a boolean.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default boolean getBoolean(int index) throws LuaException {
|
||||||
|
Object value = get((double) index);
|
||||||
|
if (!(value instanceof Boolean bool)) throw badTableItem(index, "boolean", getType(value));
|
||||||
|
return bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a table entry as a boolean.
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value.
|
||||||
|
* @throws LuaException If the value is not a boolean.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default boolean getBoolean(String key) throws LuaException {
|
||||||
|
Object value = get(key);
|
||||||
|
if (!(value instanceof Boolean bool)) throw badField(key, "boolean", getType(value));
|
||||||
|
return bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array entry as a string.
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value.
|
||||||
|
* @throws LuaException If the value is not a string.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default String getString(int index) throws LuaException {
|
||||||
|
Object value = get((double) index);
|
||||||
|
if (!(value instanceof String string)) throw badTableItem(index, "string", getType(value));
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a table entry as a string.
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value.
|
||||||
|
* @throws LuaException If the value is not a string.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default String getString(String key) throws LuaException {
|
||||||
|
Object value = get(key);
|
||||||
|
if (!(value instanceof String string)) throw badField(key, "string", getType(value));
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array entry as a table.
|
||||||
|
* <p>
|
||||||
|
* The returned table may be converted into a {@link LuaTable} (using {@link ObjectLuaTable}) for easier parsing of
|
||||||
|
* table keys.
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value.
|
||||||
|
* @throws LuaException If the value is not a table.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Map<?, ?> getTable(int index) throws LuaException {
|
||||||
|
Object value = get((double) index);
|
||||||
|
if (!(value instanceof Map<?, ?> table)) throw badTableItem(index, "table", getType(value));
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a table entry as a table.
|
||||||
|
* <p>
|
||||||
|
* The returned table may be converted into a {@link LuaTable} (using {@link ObjectLuaTable}) for easier parsing of
|
||||||
|
* table keys.
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value.
|
||||||
|
* @throws LuaException If the value is not a table.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Map<?, ?> getTable(String key) throws LuaException {
|
||||||
|
Object value = get(key);
|
||||||
|
if (!(value instanceof Map<?, ?> table)) throw badField(key, "table", getType(value));
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array entry as a double.
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not a number.
|
||||||
|
* @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN).
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Double> optDouble(int index) throws LuaException {
|
||||||
|
Object value = get((double) index);
|
||||||
|
if (value == null) return Optional.empty();
|
||||||
|
if (!(value instanceof Number number)) throw badTableItem(index, "number", getType(value));
|
||||||
|
return Optional.of(number.doubleValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a table entry as a double.
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not a number.
|
||||||
|
* @see #getFiniteDouble(String) if you require this to be finite (i.e. not infinite or NaN).
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Double> optDouble(String key) throws LuaException {
|
||||||
|
Object value = get(key);
|
||||||
|
if (value == null) return Optional.empty();
|
||||||
|
if (!(value instanceof Number number)) throw badField(key, "number", getType(value));
|
||||||
|
return Optional.of(number.doubleValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array entry as an integer.
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not an integer.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Long> optLong(int index) throws LuaException {
|
||||||
|
Object value = get((double) index);
|
||||||
|
if (value == null) return Optional.empty();
|
||||||
|
if (!(value instanceof Number number)) throw badTableItem(index, "number", getType(value));
|
||||||
|
checkFiniteIndex(index, number.doubleValue());
|
||||||
|
return Optional.of(number.longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a table entry as an integer.
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not an integer.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Long> optLong(String key) throws LuaException {
|
||||||
|
Object value = get(key);
|
||||||
|
if (value == null) return Optional.empty();
|
||||||
|
if (!(value instanceof Number number)) throw badField(key, "number", getType(value));
|
||||||
|
checkFiniteField(key, number.doubleValue());
|
||||||
|
return Optional.of(number.longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array entry as an integer.
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not an integer.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Integer> optInt(int index) throws LuaException {
|
||||||
|
return optLong(index).map(Long::intValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a table entry as an integer.
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not an integer.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Integer> optInt(String key) throws LuaException {
|
||||||
|
return optLong(key).map(Long::intValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an argument as a finite number (not infinite or NaN).
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not finite.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Double> optFiniteDouble(int index) throws LuaException {
|
||||||
|
var value = optDouble(index);
|
||||||
|
if (value.isPresent()) checkFiniteIndex(index, value.get());
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an argument as a finite number (not infinite or NaN).
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not finite.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Double> optFiniteDouble(String key) throws LuaException {
|
||||||
|
var value = optDouble(key);
|
||||||
|
if (value.isPresent()) checkFiniteField(key, value.get());
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array entry as a boolean.
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not a boolean.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Boolean> optBoolean(int index) throws LuaException {
|
||||||
|
Object value = get((double) index);
|
||||||
|
if (value == null) return Optional.empty();
|
||||||
|
if (!(value instanceof Boolean bool)) throw badTableItem(index, "boolean", getType(value));
|
||||||
|
return Optional.of(bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a table entry as a boolean.
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not a boolean.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Boolean> optBoolean(String key) throws LuaException {
|
||||||
|
Object value = get(key);
|
||||||
|
if (value == null) return Optional.empty();
|
||||||
|
if (!(value instanceof Boolean bool)) throw badField(key, "boolean", getType(value));
|
||||||
|
return Optional.of(bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array entry as a double.
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not a string.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<String> optString(int index) throws LuaException {
|
||||||
|
Object value = get((double) index);
|
||||||
|
if (value == null) return Optional.empty();
|
||||||
|
if (!(value instanceof String string)) throw badTableItem(index, "string", getType(value));
|
||||||
|
return Optional.of(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a table entry as a string.
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not a string.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<String> optString(String key) throws LuaException {
|
||||||
|
Object value = get(key);
|
||||||
|
if (value == null) return Optional.empty();
|
||||||
|
if (!(value instanceof String string)) throw badField(key, "string", getType(value));
|
||||||
|
return Optional.of(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array entry as a table.
|
||||||
|
* <p>
|
||||||
|
* The returned table may be converted into a {@link LuaTable} (using {@link ObjectLuaTable}) for easier parsing of
|
||||||
|
* table keys.
|
||||||
|
*
|
||||||
|
* @param index The index in the table, starting at 1.
|
||||||
|
* @return The entry's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not a table.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Map<?, ?>> optTable(int index) throws LuaException {
|
||||||
|
Object value = get((double) index);
|
||||||
|
if (value == null) return Optional.empty();
|
||||||
|
if (!(value instanceof Map<?, ?> table)) throw badTableItem(index, "table", getType(value));
|
||||||
|
return Optional.of(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a table entry as a table.
|
||||||
|
* <p>
|
||||||
|
* The returned table may be converted into a {@link LuaTable} (using {@link ObjectLuaTable}) for easier parsing of
|
||||||
|
* table keys.
|
||||||
|
*
|
||||||
|
* @param key The name of the field in the table.
|
||||||
|
* @return The field's value, or {@link Optional#empty()} if not present.
|
||||||
|
* @throws LuaException If the value is not a table.
|
||||||
|
* @since 1.116
|
||||||
|
*/
|
||||||
|
default Optional<Map<?, ?>> optTable(String key) throws LuaException {
|
||||||
|
Object value = get(key);
|
||||||
|
if (value == null) return Optional.empty();
|
||||||
|
if (!(value instanceof Map<?, ?> table)) throw badField(key, "table", getType(value));
|
||||||
|
return Optional.of(table);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
default V put(K o, V o2) {
|
default V put(K o, V o2) {
|
||||||
|
@ -97,7 +97,7 @@ public final class LuaValues {
|
|||||||
* @return The constructed exception, which should be thrown immediately.
|
* @return The constructed exception, which should be thrown immediately.
|
||||||
*/
|
*/
|
||||||
public static LuaException badTableItem(int index, String expected, String actual) {
|
public static LuaException badTableItem(int index, String expected, String actual) {
|
||||||
return new LuaException("table item #" + index + " is not " + expected + " (got " + actual + ")");
|
return new LuaException("bad item #" + index + " (" + expected + " expected, got " + actual + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,7 +109,7 @@ public final class LuaValues {
|
|||||||
* @return The constructed exception, which should be thrown immediately.
|
* @return The constructed exception, which should be thrown immediately.
|
||||||
*/
|
*/
|
||||||
public static LuaException badField(String key, String expected, String actual) {
|
public static LuaException badField(String key, String expected, String actual) {
|
||||||
return new LuaException("field " + key + " is not " + expected + " (got " + actual + ")");
|
return new LuaException("bad field '" + key + "' (" + expected + " expected, got " + actual + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,6 +138,16 @@ public final class LuaValues {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double checkFiniteIndex(int index, double value) throws LuaException {
|
||||||
|
if (!Double.isFinite(value)) throw badTableItem(index, "number", getNumericType(value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double checkFiniteField(String key, double value) throws LuaException {
|
||||||
|
if (!Double.isFinite(value)) throw badField(key, "number", getNumericType(value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure a string is a valid enum value.
|
* Ensure a string is a valid enum value.
|
||||||
*
|
*
|
||||||
|
@ -20,7 +20,6 @@ import java.util.Locale;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static dan200.computercraft.core.apis.TableHelper.*;
|
|
||||||
import static dan200.computercraft.core.util.ArgumentHelpers.assertBetween;
|
import static dan200.computercraft.core.util.ArgumentHelpers.assertBetween;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,15 +77,14 @@ public class HTTPAPI implements ILuaAPI {
|
|||||||
Optional<Double> timeoutArg;
|
Optional<Double> timeoutArg;
|
||||||
|
|
||||||
if (args.get(0) instanceof Map) {
|
if (args.get(0) instanceof Map) {
|
||||||
var options = args.getTable(0);
|
var options = new ObjectLuaTable(args.getTable(0));
|
||||||
address = getStringField(options, "url");
|
address = options.getString("url");
|
||||||
var postString = optStringField(options, "body", null);
|
postBody = options.optString("body").map(LuaValues::encode).orElse(null);
|
||||||
postBody = postString == null ? null : LuaValues.encode(postString);
|
headerTable = options.optTable("headers").orElse(Map.of());
|
||||||
headerTable = optTableField(options, "headers", Map.of());
|
binary = options.optBoolean("binary").orElse(false);
|
||||||
binary = optBooleanField(options, "binary", false);
|
requestMethod = options.optString("method").orElse(null);
|
||||||
requestMethod = optStringField(options, "method", null);
|
redirect = options.optBoolean("redirect").orElse(true);
|
||||||
redirect = optBooleanField(options, "redirect", true);
|
timeoutArg = options.optFiniteDouble("timeout");
|
||||||
timeoutArg = optRealField(options, "timeout");
|
|
||||||
} else {
|
} else {
|
||||||
// Get URL and post information
|
// Get URL and post information
|
||||||
address = args.getString(0);
|
address = args.getString(0);
|
||||||
@ -151,10 +149,10 @@ public class HTTPAPI implements ILuaAPI {
|
|||||||
Optional<Double> timeoutArg;
|
Optional<Double> timeoutArg;
|
||||||
|
|
||||||
if (args.get(0) instanceof Map) {
|
if (args.get(0) instanceof Map) {
|
||||||
var options = args.getTable(0);
|
var options = new ObjectLuaTable(args.getTableUnsafe(0));
|
||||||
address = getStringField(options, "url");
|
address = options.getString("url");
|
||||||
headerTable = optTableField(options, "headers", Map.of());
|
headerTable = options.optTable("headers").orElse(Map.of());
|
||||||
timeoutArg = optRealField(options, "timeout");
|
timeoutArg = options.optFiniteDouble("timeout");
|
||||||
} else {
|
} else {
|
||||||
address = args.getString(0);
|
address = args.getString(0);
|
||||||
headerTable = args.optTable(1, Map.of());
|
headerTable = args.optTable(1, Map.of());
|
||||||
|
@ -1,156 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2018 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.core.apis;
|
|
||||||
|
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
|
||||||
import dan200.computercraft.api.lua.LuaValues;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static dan200.computercraft.api.lua.LuaValues.getNumericType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Various helpers for tables.
|
|
||||||
*/
|
|
||||||
public final class TableHelper {
|
|
||||||
private TableHelper() {
|
|
||||||
throw new IllegalStateException("Cannot instantiate singleton " + getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LuaException badKey(String key, String expected, @Nullable Object actual) {
|
|
||||||
return badKey(key, expected, LuaValues.getType(actual));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LuaException badKey(String key, String expected, String actual) {
|
|
||||||
return new LuaException("bad field '" + key + "' (" + expected + " expected, got " + actual + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getNumberField(Map<?, ?> table, String key) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value instanceof Number) {
|
|
||||||
return ((Number) value).doubleValue();
|
|
||||||
} else {
|
|
||||||
throw badKey(key, "number", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getIntField(Map<?, ?> table, String key) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value instanceof Number) {
|
|
||||||
return (int) ((Number) value).longValue();
|
|
||||||
} else {
|
|
||||||
throw badKey(key, "number", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getRealField(Map<?, ?> table, String key) throws LuaException {
|
|
||||||
return checkReal(key, getNumberField(table, key));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean getBooleanField(Map<?, ?> table, String key) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value instanceof Boolean) {
|
|
||||||
return (Boolean) value;
|
|
||||||
} else {
|
|
||||||
throw badKey(key, "boolean", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getStringField(Map<?, ?> table, String key) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value instanceof String) {
|
|
||||||
return (String) value;
|
|
||||||
} else {
|
|
||||||
throw badKey(key, "string", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static Map<Object, Object> getTableField(Map<?, ?> table, String key) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value instanceof Map) {
|
|
||||||
return (Map<Object, Object>) value;
|
|
||||||
} else {
|
|
||||||
throw badKey(key, "table", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double optNumberField(Map<?, ?> table, String key, double def) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value == null) {
|
|
||||||
return def;
|
|
||||||
} else if (value instanceof Number) {
|
|
||||||
return ((Number) value).doubleValue();
|
|
||||||
} else {
|
|
||||||
throw badKey(key, "number", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int optIntField(Map<?, ?> table, String key, int def) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value == null) {
|
|
||||||
return def;
|
|
||||||
} else if (value instanceof Number) {
|
|
||||||
return (int) ((Number) value).longValue();
|
|
||||||
} else {
|
|
||||||
throw badKey(key, "number", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Optional<Double> optRealField(Map<?, ?> table, String key) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value == null) {
|
|
||||||
return Optional.empty();
|
|
||||||
} else {
|
|
||||||
return Optional.of(getRealField(table, key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double optRealField(Map<?, ?> table, String key, double def) throws LuaException {
|
|
||||||
return checkReal(key, optNumberField(table, key, def));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean optBooleanField(Map<?, ?> table, String key, boolean def) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value == null) {
|
|
||||||
return def;
|
|
||||||
} else if (value instanceof Boolean) {
|
|
||||||
return (Boolean) value;
|
|
||||||
} else {
|
|
||||||
throw badKey(key, "boolean", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static String optStringField(Map<?, ?> table, String key, @Nullable String def) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value == null) {
|
|
||||||
return def;
|
|
||||||
} else if (value instanceof String) {
|
|
||||||
return (String) value;
|
|
||||||
} else {
|
|
||||||
throw badKey(key, "string", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static Map<Object, Object> optTableField(Map<?, ?> table, String key, Map<Object, Object> def) throws LuaException {
|
|
||||||
var value = table.get(key);
|
|
||||||
if (value == null) {
|
|
||||||
return def;
|
|
||||||
} else if (value instanceof Map) {
|
|
||||||
return (Map<Object, Object>) value;
|
|
||||||
} else {
|
|
||||||
throw badKey(key, "table", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double checkReal(String key, double value) throws LuaException {
|
|
||||||
if (!Double.isFinite(value)) throw badKey(key, "number", getNumericType(value));
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user