1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-14 20:20:30 +00:00

Merge branch 'mc-1.15.x' into mc-1.16.x

This commit is contained in:
Jonathan Coates 2021-04-24 11:50:23 +01:00
commit f387730b88
19 changed files with 482 additions and 247 deletions

View File

@ -4,7 +4,7 @@ buildscript {
mavenCentral()
maven {
name = "forge"
url = "https://files.minecraftforge.net/maven"
url = "https://maven.minecraftforge.net"
}
maven {
name = "Sponge (Mixin)"
@ -14,7 +14,7 @@ buildscript {
}
dependencies {
classpath 'com.google.code.gson:gson:2.8.1'
classpath 'net.minecraftforge.gradle:ForgeGradle:4.1.3'
classpath 'net.minecraftforge.gradle:ForgeGradle:4.1.9'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT'
}
@ -23,6 +23,7 @@ buildscript {
plugins {
id "checkstyle"
id "jacoco"
id "maven-publish"
id "com.github.hierynomus.license" version "0.15.0"
id "com.matthewprenger.cursegradle" version "1.4.0"
id "com.github.breadmoirai.github-release" version "2.2.12"
@ -31,8 +32,6 @@ plugins {
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'org.spongepowered.mixin'
apply plugin: 'maven-publish'
apply plugin: 'maven'
version = mod_version
@ -43,6 +42,9 @@ java {
toolchain {
languageVersion = JavaLanguageVersion.of(8)
}
withSourcesJar()
withJavadocJar()
}
minecraft {
@ -127,7 +129,6 @@ repositories {
configurations {
shade
compile.extendsFrom shade
deployerJars
cctJavadoc
}
@ -153,8 +154,7 @@ dependencies {
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72'
testImplementation 'org.jetbrains.kotlin:kotlin-reflect:1.3.72'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0"
testAnnotationProcessor 'org.spongepowered:mixin:0.8.2:processor'
cctJavadoc 'cc.tweaked:cct-javadoc:1.3.0'
}
@ -183,8 +183,6 @@ task luaJavadoc(type: Javadoc) {
}
jar {
dependsOn javadoc
manifest {
attributes(["Specification-Title": "computercraft",
"Specification-Vendor": "SquidDev",
@ -195,10 +193,6 @@ jar {
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")])
}
from (sourceSets.main.allSource) {
include "dan200/computercraft/api/**/*.java"
}
from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
}
@ -568,51 +562,41 @@ curseforge {
publishing {
publications {
mavenJava(MavenPublication) {
maven(MavenPublication) {
from components.java
// artifact sourceJar
}
}
}
uploadArchives {
repositories {
if(project.hasProperty('mavenUploadUrl')) {
mavenDeployer {
configuration = configurations.deployerJars
repository(url: project.property('mavenUploadUrl')) {
authentication(
userName: project.property('mavenUploadUser'),
privateKey: project.property('mavenUploadKey'))
}
pom.project {
name 'CC: Tweaked'
packaging 'jar'
description 'CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.'
url 'https://github.com/SquidDev-CC/CC-Tweaked'
pom {
name = 'CC: Tweaked'
description = 'CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.'
url = 'https://github.com/SquidDev-CC/CC-Tweaked'
scm {
url 'https://github.com/SquidDev-CC/CC-Tweaked.git'
url = 'https://github.com/SquidDev-CC/CC-Tweaked.git'
}
issueManagement {
system 'github'
url 'https://github.com/SquidDev-CC/CC-Tweaked/issues'
system = 'github'
url = 'https://github.com/SquidDev-CC/CC-Tweaked/issues'
}
licenses {
license {
name 'ComputerCraft Public License, Version 1.0'
url 'https://github.com/SquidDev-CC/CC-Tweaked/blob/master/LICENSE'
distribution 'repo'
name = 'ComputerCraft Public License, Version 1.0'
url = 'https://github.com/SquidDev-CC/CC-Tweaked/blob/mc-1.15.x/LICENSE'
}
}
}
}
}
pom.whenConfigured { pom ->
pom.dependencies.clear()
repositories {
if (project.hasProperty("mavenUser")) {
maven {
name = "SquidDev"
url = "https://squiddev.cc/maven"
credentials {
username = project.property("mavenUser") as String
password = project.property("mavenPass") as String
}
}
}
@ -643,7 +627,7 @@ githubRelease {
prerelease false
}
def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"]
def uploadTasks = ["publish", "curseforge", "githubRelease"]
uploadTasks.forEach { tasks.getByName(it).dependsOn checkRelease }
task uploadAll(dependsOn: uploadTasks) {

View File

@ -1 +1,13 @@
--[[- Craft a recipe based on the turtle's inventory.
The turtle's inventory should set up like a crafting grid. For instance, to
craft sticks, slots 1 and 5 should contain sticks. _All_ other slots should be
empty, including those outside the crafting "grid".
@tparam[opt=64] number limit The maximum number of crafting steps to run.
@throws When limit is less than 1 or greater than 64.
@treturn[1] true If crafting succeeds.
@treturn[2] false If crafting fails.
@treturn string A string describing why crafting failed.
]]
function craft(limit) end

View File

@ -88,27 +88,16 @@
;; Suppress warnings for currently undocumented modules.
(at
(; Java APIs
/doc/stub/http.lua
/doc/stub/os.lua
/doc/stub/turtle.lua
/doc/stub/global.lua
; Java generated APIs
/build/docs/luaJavadoc/turtle.lua
; Peripherals
/build/docs/luaJavadoc/drive.lua
/build/docs/luaJavadoc/speaker.lua
/build/docs/luaJavadoc/printer.lua
; Generic peripherals
/build/docs/luaJavadoc/fluid_storage.lua
; Lua APIs
(; Lua APIs
/src/main/resources/*/computercraft/lua/rom/apis/io.lua
/src/main/resources/*/computercraft/lua/rom/apis/window.lua)
(linters -doc:undocumented -doc:undocumented-arg -doc:undocumented-return))
;; Suppress warnings for the BIOS using its own deprecated members for now.
(at /src/main/resources/*/computercraft/lua/bios.lua
;; Suppress warnings for various APIs using its own deprecated members.
(at
(/src/main/resources/*/computercraft/lua/bios.lua
/src/main/resources/*/computercraft/lua/rom/apis/turtle/turtle.lua)
(linters -var:deprecated))
(at /src/test/resources/test-rom

View File

@ -98,7 +98,9 @@ public final class ComputerCraftAPI
* resource folder onto a computer's file system.
*
* The files in this mount will be a combination of files in all mod jar, and data packs that contain
* resources with the same domain and path.
* resources with the same domain and path. For instance, ComputerCraft's resources are stored in
* "/data/computercraft/lua/rom". We construct a mount for that with
* {@code createResourceMount("computercraft", "lua/rom")}.
*
* @param domain The domain under which to look for resources. eg: "mymod".
* @param subPath The subPath under which to look for resources. eg: "lua/myfiles".

View File

@ -103,9 +103,13 @@ public final class ResourceMount implements IMount
private void load()
{
boolean hasAny = false;
String existingNamespace = null;
FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) );
for( ResourceLocation file : manager.listResources( subPath, s -> true ) )
{
existingNamespace = file.getNamespace();
if( !file.getNamespace().equals( namespace ) ) continue;
String localPath = FileSystem.toLocal( file.getPath(), subPath );
@ -114,6 +118,15 @@ public final class ResourceMount implements IMount
}
root = hasAny ? newRoot : null;
if( !hasAny )
{
ComputerCraft.log.warn( "Cannot find any files under /data/{}/{} for resource mount.", namespace, subPath );
if( newRoot != null )
{
ComputerCraft.log.warn( "There are files under /data/{}/{} though. Did you get the wrong namespace?", existingNamespace, subPath );
}
}
}
private FileEntry get( String path )

View File

@ -12,46 +12,12 @@ public class TextBuffer
public TextBuffer( char c, int length )
{
text = new char[length];
for( int i = 0; i < length; i++ )
{
text[i] = c;
}
this.fill( c );
}
public TextBuffer( String text )
{
this( text, 1 );
}
public TextBuffer( String text, int repetitions )
{
int textLength = text.length();
this.text = new char[textLength * repetitions];
for( int i = 0; i < repetitions; i++ )
{
for( int j = 0; j < textLength; j++ )
{
this.text[j + i * textLength] = text.charAt( j );
}
}
}
public TextBuffer( TextBuffer text )
{
this( text, 1 );
}
public TextBuffer( TextBuffer text, int repetitions )
{
int textLength = text.length();
this.text = new char[textLength * repetitions];
for( int i = 0; i < repetitions; i++ )
{
for( int j = 0; j < textLength; j++ )
{
this.text[j + i * textLength] = text.charAt( j );
}
}
this.text = text.toCharArray();
}
public int length()
@ -59,39 +25,16 @@ public class TextBuffer
return text.length;
}
public String read()
{
return read( 0, text.length );
}
public String read( int start )
{
return read( start, text.length );
}
public String read( int start, int end )
{
start = Math.max( start, 0 );
end = Math.min( end, text.length );
int textLength = Math.max( end - start, 0 );
return new String( text, start, textLength );
}
public void write( String text )
{
write( text, 0, text.length() );
write( text, 0 );
}
public void write( String text, int start )
{
write( text, start, start + text.length() );
}
public void write( String text, int start, int end )
{
int pos = start;
start = Math.max( start, 0 );
end = Math.min( end, pos + text.length() );
int end = Math.min( start + text.length(), pos + text.length() );
end = Math.min( end, this.text.length );
for( int i = start; i < end; i++ )
{
@ -101,23 +44,10 @@ public class TextBuffer
public void write( TextBuffer text )
{
write( text, 0, text.length() );
}
public void write( TextBuffer text, int start )
int end = Math.min( text.length(), this.text.length );
for( int i = 0; i < end; i++ )
{
write( text, start, start + text.length() );
}
public void write( TextBuffer text, int start, int end )
{
int pos = start;
start = Math.max( start, 0 );
end = Math.min( end, pos + text.length() );
end = Math.min( end, this.text.length );
for( int i = start; i < end; i++ )
{
this.text[i] = text.charAt( i - pos );
this.text[i] = text.charAt( i );
}
}
@ -126,11 +56,6 @@ public class TextBuffer
fill( c, 0, text.length );
}
public void fill( char c, int start )
{
fill( c, start, text.length );
}
public void fill( char c, int start, int end )
{
start = Math.max( start, 0 );
@ -141,52 +66,6 @@ public class TextBuffer
}
}
public void fill( String text )
{
fill( text, 0, this.text.length );
}
public void fill( String text, int start )
{
fill( text, start, this.text.length );
}
public void fill( String text, int start, int end )
{
int pos = start;
start = Math.max( start, 0 );
end = Math.min( end, this.text.length );
int textLength = text.length();
for( int i = start; i < end; i++ )
{
this.text[i] = text.charAt( (i - pos) % textLength );
}
}
public void fill( TextBuffer text )
{
fill( text, 0, this.text.length );
}
public void fill( TextBuffer text, int start )
{
fill( text, start, this.text.length );
}
public void fill( TextBuffer text, int start, int end )
{
int pos = start;
start = Math.max( start, 0 );
end = Math.min( end, this.text.length );
int textLength = text.length();
for( int i = start; i < end; i++ )
{
this.text[i] = text.charAt( (i - pos) % textLength );
}
}
public char charAt( int i )
{
return text[i];

View File

@ -114,10 +114,10 @@ public class JEIComputerCraft implements IModPlugin
*/
private static final ISubtypeInterpreter turtleSubtype = stack -> {
Item item = stack.getItem();
if( !(item instanceof ITurtleItem) ) return "";
if( !(item instanceof ITurtleItem) ) return ISubtypeInterpreter.NONE;
ITurtleItem turtle = (ITurtleItem) item;
StringBuilder name = new StringBuilder();
StringBuilder name = new StringBuilder( "turtle:" );
// Add left and right upgrades to the identifier
ITurtleUpgrade left = turtle.getUpgrade( stack, TurtleSide.LEFT );
@ -134,9 +134,9 @@ public class JEIComputerCraft implements IModPlugin
*/
private static final ISubtypeInterpreter pocketSubtype = stack -> {
Item item = stack.getItem();
if( !(item instanceof ItemPocketComputer) ) return "";
if( !(item instanceof ItemPocketComputer) ) return ISubtypeInterpreter.NONE;
StringBuilder name = new StringBuilder();
StringBuilder name = new StringBuilder( "pocket:" );
// Add the upgrade to the identifier
IPocketUpgrade upgrade = ItemPocketComputer.getUpgrade( stack );
@ -150,11 +150,11 @@ public class JEIComputerCraft implements IModPlugin
*/
private static final ISubtypeInterpreter diskSubtype = stack -> {
Item item = stack.getItem();
if( !(item instanceof ItemDisk) ) return "";
if( !(item instanceof ItemDisk) ) return ISubtypeInterpreter.NONE;
ItemDisk disk = (ItemDisk) item;
int colour = disk.getColour( stack );
return colour == -1 ? "" : String.format( "%06x", colour );
return colour == -1 ? ISubtypeInterpreter.NONE : String.format( "%06x", colour );
};
}

View File

@ -200,7 +200,7 @@ class RecipeResolver implements IRecipeManagerPlugin
for( UpgradeInfo upgrade : upgrades )
{
ItemStack craftingStack = upgrade.stack;
if( !craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && upgrade.upgrade.isItemSuitable( stack ) )
if( craftingStack.isEmpty() || craftingStack.getItem() != stack.getItem() || !upgrade.upgrade.isItemSuitable( stack ) )
{
continue;
}
@ -319,13 +319,6 @@ class RecipeResolver implements IRecipeManagerPlugin
super( ID, null, width, height, input, output );
}
@Nonnull
@Override
public ResourceLocation getId()
{
return null;
}
@Nonnull
@Override
public IRecipeSerializer<?> getSerializer()

View File

@ -45,6 +45,19 @@ public class FluidMethods implements GenericSource
return new ResourceLocation( ForgeVersion.MOD_ID, "fluid" );
}
/**
* Get all "tanks" in this fluid storage.
*
* Each tank either contains some amount of fluid or is empty. Tanks with fluids inside will return some basic
* information about the fluid, including its name and amount.
*
* The returned table is sparse, and so empty tanks will be `nil` - it is recommended to loop over using `pairs`
* rather than `ipairs`.
*
* @param fluids The current fluid handler.
* @return All tanks.
* @cc.treturn { (table|nil)... } All tanks in this fluid storage.
*/
@LuaFunction( mainThread = true )
public static Map<Integer, Map<String, ?>> tanks( IFluidHandler fluids )
{
@ -59,6 +72,22 @@ public class FluidMethods implements GenericSource
return result;
}
/**
* Move a fluid from one fluid container to another connected one.
*
* This allows you to pull fluid in the current fluid container to another container <em>on the same wired
* network</em>. Both containers must attached to wired modems which are connected via a cable.
*
* @param from Container to move fluid from.
* @param computer The current computer.
* @param toName The name of the peripheral/container to push to. This is the string given to @{peripheral.wrap},
* and displayed by the wired modem.
* @param limit The maximum amount of fluid to move.
* @param fluidName The fluid to move. If not given, an arbitrary fluid will be chosen.
* @return The amount of moved fluid.
* @throws LuaException If the peripheral to transfer to doesn't exist or isn't an fluid container.
* @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral.
*/
@LuaFunction( mainThread = true )
public static int pushFluid(
IFluidHandler from, IComputerAccess computer,
@ -84,6 +113,22 @@ public class FluidMethods implements GenericSource
: moveFluid( from, new FluidStack( fluid, actualLimit ), to );
}
/**
* Move a fluid from a connected fluid container into this oneone.
*
* This allows you to pull fluid in the current fluid container from another container <em>on the same wired
* network</em>. Both containers must attached to wired modems which are connected via a cable.
*
* @param to Container to move fluid to.
* @param computer The current computer.
* @param fromName The name of the peripheral/container to push to. This is the string given to @{peripheral.wrap},
* and displayed by the wired modem.
* @param limit The maximum amount of fluid to move.
* @param fluidName The fluid to move. If not given, an arbitrary fluid will be chosen.
* @return The amount of moved fluid.
* @throws LuaException If the peripheral to transfer to doesn't exist or isn't an fluid container.
* @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral.
*/
@LuaFunction( mainThread = true )
public static int pullFluid(
IFluidHandler to, IComputerAccess computer,

View File

@ -65,8 +65,8 @@ public class InventoryMethods implements GenericSource
* {@link dan200.computercraft.shared.turtle.apis.TurtleAPI#getItemDetail} includes. More information can be fetched
* with {@link #getItemDetail}.
*
* The table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs` rather than
* `ipairs`.
* The returned table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs`
* rather than `ipairs`.
*
* @param inventory The current inventory.
* @return All items in this inventory.

View File

@ -371,18 +371,36 @@ public class TurtleAPI implements ILuaAPI
return trackCommand( new TurtleDetectCommand( InteractDirection.DOWN ) );
}
/**
* Check if the block in front of the turtle is equal to the item in the currently selected slot.
*
* @return If the block and item are equal.
* @cc.treturn boolean If the block and item are equal.
*/
@LuaFunction
public final MethodResult compare()
{
return trackCommand( new TurtleCompareCommand( InteractDirection.FORWARD ) );
}
/**
* Check if the block above the turtle is equal to the item in the currently selected slot.
*
* @return If the block and item are equal.
* @cc.treturn boolean If the block and item are equal.
*/
@LuaFunction
public final MethodResult compareUp()
{
return trackCommand( new TurtleCompareCommand( InteractDirection.UP ) );
}
/**
* Check if the block below the turtle is equal to the item in the currently selected slot.
*
* @return If the block and item are equal.
* @cc.treturn boolean If the block and item are equal.
*/
@LuaFunction
public final MethodResult compareDown()
{
@ -478,12 +496,57 @@ public class TurtleAPI implements ILuaAPI
return trackCommand( new TurtleSuckCommand( InteractDirection.DOWN, checkCount( count ) ) );
}
/**
* Get the maximum amount of fuel this turtle currently holds.
*
* @return The fuel level, or "unlimited".
* @cc.treturn [1] number The current amount of fuel a turtle this turtle has.
* @cc.treturn [2] "unlimited" If turtles do not consume fuel when moving.
* @see #getFuelLimit()
* @see #refuel(Optional)
*/
@LuaFunction
public final Object getFuelLevel()
{
return turtle.isFuelNeeded() ? turtle.getFuelLevel() : "unlimited";
}
/**
* Refuel this turtle.
*
* While most actions a turtle can perform (such as digging or placing blocks), moving consumes fuel from the
* turtle's internal buffer. If a turtle has no fuel, it will not move.
*
* {@link #refuel} refuels the turtle, consuming fuel items (such as coal or lava buckets) from the currently
* selected slot and converting them into energy. This finishes once the turtle is fully refuelled or all items have
* been consumed.
*
* @param countA The maximum number of items to consume. One can pass `0` to check if an item is combustable or not.
* @return If this turtle could be refuelled.
* @throws LuaException If the refuel count is out of range.
* @cc.treturn [1] true If the turtle was refuelled.
* @cc.treturn [2] false If the turtle was not refuelled.
* @cc.treturn [2] string The reason the turtle was not refuelled (
* @cc.usage Refuel a turtle from the currently selected slot.
* <pre>{@code
* local level = turtle.getFuelLevel()
* if new_level == "unlimited" then error("Turtle does not need fuel", 0) end
*
* local ok, err = turtle.refuel()
* if ok then
* local new_level = turtle.getFuelLevel()
* print(("Refuelled %d, current level is %d"):format(new_level - level, new_level))
* else
* printError(err)
* end}</pre>
* @cc.usage Check if the current item is a valid fuel source.
* <pre>{@code
* local is_fuel, reason = turtle.refuel(0)
* if not is_fuel then printError(reason) end
* }</pre>
* @see #getFuelLevel()
* @see #getFuelLimit()
*/
@LuaFunction
public final MethodResult refuel( Optional<Integer> countA ) throws LuaException
{
@ -492,12 +555,30 @@ public class TurtleAPI implements ILuaAPI
return trackCommand( new TurtleRefuelCommand( count ) );
}
/**
* Compare the item in the currently selected slot to the item in another slot.
*
* @param slot The slot to compare to.
* @return If the items are the same.
* @throws LuaException If the slot is out of range.
* @cc.treturn boolean If the two items are equal.
*/
@LuaFunction
public final MethodResult compareTo( int slot ) throws LuaException
{
return trackCommand( new TurtleCompareToCommand( checkSlot( slot ) ) );
}
/**
* Move an item from the selected slot to another one.
*
* @param slotArg The slot to move this item to.
* @param countArg The maximum number of items to move.
* @return If the item was moved or not.
* @throws LuaException If the slot is out of range.
* @throws LuaException If the number of items is out of range.
* @cc.treturn boolean If some items were successfully moved.
*/
@LuaFunction
public final MethodResult transferTo( int slotArg, Optional<Integer> countArg ) throws LuaException
{
@ -518,18 +599,55 @@ public class TurtleAPI implements ILuaAPI
return turtle.getSelectedSlot() + 1;
}
/**
* Get the maximum amount of fuel this turtle can hold.
*
* By default, normal turtles have a limit of 20,000 and advanced turtles of 100,000.
*
* @return The limit, or "unlimited".
* @cc.treturn [1] number The maximum amount of fuel a turtle can hold.
* @cc.treturn [2] "unlimited" If turtles do not consume fuel when moving.
* @see #getFuelLevel()
* @see #refuel(Optional)
*/
@LuaFunction
public final Object getFuelLimit()
{
return turtle.isFuelNeeded() ? turtle.getFuelLimit() : "unlimited";
}
/**
* Equip (or unequip) an item on the left side of this turtle.
*
* This finds the item in the currently selected slot and attempts to equip it to the left side of the turtle. The
* previous upgrade is removed and placed into the turtle's inventory. If there is no item in the slot, the previous
* upgrade is removed, but no new one is equipped.
*
* @return Whether an item was equiped or not.
* @cc.treturn [1] true If the item was equipped.
* @cc.treturn [2] false If we could not equip the item.
* @cc.treturn [2] string The reason equipping this item failed.
* @see #equipRight()
*/
@LuaFunction
public final MethodResult equipLeft()
{
return trackCommand( new TurtleEquipCommand( TurtleSide.LEFT ) );
}
/**
* Equip (or unequip) an item on the right side of this turtle.
*
* This finds the item in the currently selected slot and attempts to equip it to the right side of the turtle. The
* previous upgrade is removed and placed into the turtle's inventory. If there is no item in the slot, the previous
* upgrade is removed, but no new one is equipped.
*
* @return Whether an item was equiped or not.
* @cc.treturn [1] true If the item was equipped.
* @cc.treturn [2] false If we could not equip the item.
* @cc.treturn [2] string The reason equipping this item failed.
* @see #equipRight()
*/
@LuaFunction
public final MethodResult equipRight()
{

View File

@ -137,6 +137,15 @@ handleMetatable = {
return handle.seek(whence, offset)
end,
--[[- Sets the buffering mode for an output file.
This has no effect under ComputerCraft, and exists with compatility
with base Lua.
@tparam string mode The buffering mode.
@tparam[opt] number size The size of the buffer.
@see file:setvbuf Lua's documentation for `setvbuf`.
@deprecated This has no effect in CC.
]]
setvbuf = function(self, mode, size) end,
--- Write one or more values to the file

View File

@ -132,7 +132,17 @@ function drawLine(startX, startY, endX, endY, colour)
return
end
local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY)
local minX = math.min(startX, endX)
local maxX, minY, maxY
if minX == startX then
minY = startY
maxX = endX
maxY = endY
else
minY = endY
maxX = startX
maxY = startY
end
-- TODO: clip to screen rectangle?

View File

@ -161,7 +161,9 @@ end
-- @tparam string name The name of the peripheral to wrap.
-- @treturn table|nil The table containing the peripheral's methods, or `nil` if
-- there is no peripheral present with the given name.
-- @usage peripheral.wrap("top").open(1)
-- @usage Open the modem on the top of this computer.
--
-- peripheral.wrap("top").open(1)
function wrap(name)
expect(1, name, "string")
@ -183,16 +185,25 @@ function wrap(name)
return result
end
--- Find all peripherals of a specific type, and return the
-- @{peripheral.wrap|wrapped} peripherals.
--
-- @tparam string ty The type of peripheral to look for.
-- @tparam[opt] function(name:string, wrapped:table):boolean filter A
-- filter function, which takes the peripheral's name and wrapped table
-- and returns if it should be included in the result.
-- @treturn table... 0 or more wrapped peripherals matching the given filters.
-- @usage { peripheral.find("monitor") }
-- @usage peripheral.find("modem", rednet.open)
--[[- Find all peripherals of a specific type, and return the
@{peripheral.wrap|wrapped} peripherals.
@tparam string ty The type of peripheral to look for.
@tparam[opt] function(name:string, wrapped:table):boolean filter A
filter function, which takes the peripheral's name and wrapped table
and returns if it should be included in the result.
@treturn table... 0 or more wrapped peripherals matching the given filters.
@usage Find all monitors and store them in a table, writing "Hello" on each one.
local monitors = { peripheral.find("monitor") }
for _, monitor in pairs(monitors) do
monitor.write("Hello")
end
@usage This abuses the `filter` argument to call @{rednet.open} on every modem.
peripheral.find("modem", rednet.open)
]]
function find(ty, filter)
expect(1, ty, "string")
expect(2, filter, "function", "nil")

View File

@ -10,6 +10,7 @@ end
--
-- Generally you should not need to use this table - it only exists for
-- backwards compatibility reasons.
-- @deprecated
native = turtle.native or turtle
local function addCraftMethod(object)

View File

@ -1,23 +1,28 @@
--- Provides a "pretty printer", for rendering data structures in an
-- aesthetically pleasing manner.
--
-- In order to display something using @{cc.pretty}, you build up a series of
-- @{Doc|documents}. These behave a little bit like strings; you can concatenate
-- them together and then print them to the screen.
--
-- However, documents also allow you to control how they should be printed. There
-- are several functions (such as @{nest} and @{group}) which allow you to control
-- the "layout" of the document. When you come to display the document, the 'best'
-- (most compact) layout is used.
--
-- @module cc.pretty
-- @usage Print a table to the terminal
-- local pretty = require "cc.pretty"
-- pretty.print(pretty.pretty({ 1, 2, 3 }))
--
-- @usage Build a custom document and display it
-- local pretty = require "cc.pretty"
-- pretty.print(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
--[[- Provides a "pretty printer", for rendering data structures in an
aesthetically pleasing manner.
In order to display something using @{cc.pretty}, you build up a series of
@{Doc|documents}. These behave a little bit like strings; you can concatenate
them together and then print them to the screen.
However, documents also allow you to control how they should be printed. There
are several functions (such as @{nest} and @{group}) which allow you to control
the "layout" of the document. When you come to display the document, the 'best'
(most compact) layout is used.
The structure of this module is based on [A Prettier Printer][prettier].
[prettier]: https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf "A Prettier Printer"
@module cc.pretty
@usage Print a table to the terminal
local pretty = require "cc.pretty"
pretty.print(pretty.pretty({ 1, 2, 3 }))
@usage Build a custom document and display it
local pretty = require "cc.pretty"
pretty.print(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
]]
local expect = require "cc.expect"
local expect, field = expect.expect, expect.field

View File

@ -801,6 +801,7 @@ while bRunning do
end
else
bMenu = false
term.setCursorBlink(true)
redrawMenu()
end
end

View File

@ -0,0 +1,150 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.terminal;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class TextBufferTest
{
@Test
void testStringConstructor()
{
TextBuffer textBuffer = new TextBuffer( "test" );
assertEquals( "test", textBuffer.toString() );
}
@Test
void testCharRepetitionConstructor()
{
TextBuffer textBuffer = new TextBuffer( 'a', 5 );
assertEquals( "aaaaa", textBuffer.toString() );
}
@Test
void testLength()
{
TextBuffer textBuffer = new TextBuffer( "test" );
assertEquals( 4, textBuffer.length() );
}
@Test
void testWrite()
{
TextBuffer textBuffer = new TextBuffer( ' ', 4 );
textBuffer.write( "test" );
assertEquals( "test", textBuffer.toString() );
}
@Test
void testWriteTextBuffer()
{
TextBuffer source = new TextBuffer( "test" );
TextBuffer target = new TextBuffer( " " );
target.write( source );
assertEquals( "test", target.toString() );
}
@Test
void testWriteFromPos()
{
TextBuffer textBuffer = new TextBuffer( "test" );
textBuffer.write( "il", 1 );
assertEquals( "tilt", textBuffer.toString() );
}
@Test
void testWriteOutOfBounds()
{
TextBuffer textBuffer = new TextBuffer( "test" );
textBuffer.write( "abcdefghijklmnop", -5 );
assertEquals( "fghi", textBuffer.toString() );
}
@Test
void testWriteOutOfBounds2()
{
TextBuffer textBuffer = new TextBuffer( " " );
textBuffer.write( "Hello, world!", -3 );
assertEquals( "lo, world! ", textBuffer.toString() );
}
@Test
void testFill()
{
TextBuffer textBuffer = new TextBuffer( "test" );
textBuffer.fill( 'c' );
assertEquals( "cccc", textBuffer.toString() );
}
@Test
void testFillSubstring()
{
TextBuffer textBuffer = new TextBuffer( "test" );
textBuffer.fill( 'c', 1, 3 );
assertEquals( "tcct", textBuffer.toString() );
}
@Test
void testFillOutOfBounds()
{
TextBuffer textBuffer = new TextBuffer( "test" );
textBuffer.fill( 'c', -5, 5 );
assertEquals( "cccc", textBuffer.toString() );
}
@Test
void testCharAt()
{
TextBuffer textBuffer = new TextBuffer( "test" );
assertEquals( 'e', textBuffer.charAt( 1 ) );
}
@Test
void testSetChar()
{
TextBuffer textBuffer = new TextBuffer( "test" );
textBuffer.setChar( 2, 'n' );
assertEquals( "tent", textBuffer.toString() );
}
@Test
void testSetCharWithNegativeIndex()
{
TextBuffer textBuffer = new TextBuffer( "test" );
textBuffer.setChar( -5, 'n' );
assertEquals( "test", textBuffer.toString(), "Buffer should not change after setting char with negative index." );
}
@Test
void testSetCharWithIndexBeyondBufferEnd()
{
TextBuffer textBuffer = new TextBuffer( "test" );
textBuffer.setChar( 10, 'n' );
assertEquals( "test", textBuffer.toString(), "Buffer should not change after setting char beyond buffer end." );
}
@Test
void testMultipleOperations()
{
TextBuffer textBuffer = new TextBuffer( ' ', 5 );
textBuffer.setChar( 0, 'H' );
textBuffer.setChar( 1, 'e' );
textBuffer.setChar( 2, 'l' );
textBuffer.write( "lo", 3 );
assertEquals( "Hello", textBuffer.toString(), "TextBuffer failed to persist over multiple operations." );
}
@Test
void testEmptyBuffer()
{
TextBuffer textBuffer = new TextBuffer( "" );
// exception on writing to empty buffer would fail the test
textBuffer.write( "test" );
assertEquals( "", textBuffer.toString() );
}
}

View File

@ -67,6 +67,19 @@ describe("The paintutils library", function()
{ " ", "000", "ffe" },
})
end)
it("draws a line going diagonally from bottom left", function()
local w = with_window(3, 3, function()
term.setBackgroundColour(colours.red)
paintutils.drawLine(1, 3, 3, 1)
end)
window_eq(w, {
{ " ", "000", "ffe" },
{ " ", "000", "fef" },
{ " ", "000", "eff" },
})
end)
end)
describe("paintutils.drawBox", function()