1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-11-01 06:03:00 +00:00

Compare commits

..

25 Commits

Author SHA1 Message Date
SquidDev
748ebbe66b Bump to 1.92.0
A tiny release, but there's new features so it's technically a minor
bump.
2020-09-12 09:27:47 +01:00
SquidDev
59de21eae2 Handle tabs when parsing JSON
Fixes #539
2020-09-11 18:02:23 +01:00
SquidDev
50473afea8 Fix Gradle example for depending on CC:T
See #405
2020-09-09 08:39:28 +01:00
SquidDev
37f925de0a Remove references to cc.crzd.me's maven
As CC only exists on 1.12.2, it's a bit meaningless to talk about it on
1.15+!
2020-09-08 18:37:40 +01:00
SquidDev
cefde3f003 Also block 0.0.0.0/8
See MightyPirates/OpenComputers#3356
2020-09-08 18:12:20 +01:00
Weblate
ae6124d1f4 Translations for Vietnamese
Co-authored-by: Boom <boom@flyingpackets.net>
2020-09-08 03:57:52 +00:00
Weblate
7e121ff72f Translations for Vietnamese
Co-authored-by: Boom <boom@flyingpackets.net>
2020-09-07 06:37:58 +00:00
Weblate
5155e18de2 Added translation for Vietnamese
Co-authored-by: Boom <boom@flyingpackets.net>
2020-09-07 03:33:36 +00:00
SquidDev
7365741088 Don't use entity.captureDrops at all.
This really should have been removed in 9e2232d240.
Otherwise we don't drop these items into the world at all. Fixes #537.
2020-09-05 11:02:24 +01:00
JackMacWindows
d5368d0719 Add date-specific MOTDs (like Minecraft) (#533) 2020-09-04 17:35:46 +01:00
Jonathan Coates
04509cefec Merge pull request #529 from Bluenaxela/mc-1.15.x
Pretty sure FileSystemWrapperMount.isDirectory() should call Filesystem.isDir(), not Filesystem.exists()
2020-08-25 08:11:13 +01:00
Bluenaxela
74b9f5dcb0 Fix FileSystemWrapperMount.isDirectory()
Pretty sure FileSystemWrapperMount.isDirectory() should call Filesystem.isDir(), not Filesystem.exists()
2020-08-24 23:55:24 -07:00
SquidDev
183b342071 Bump for 1.91.0 2020-08-23 15:35:58 +01:00
SquidDev
0bb5515055 Fix checkstyle problems 2020-08-22 19:31:49 +01:00
SquidDev
9acfc0316f Expose NBT hashes of items to users
This just uses the same approach as Plethora, so we should have aparity
for .list() now.
2020-08-22 16:09:35 +01:00
SquidDev
29fb0baa09 Use Forge's packet methods for sending SoundEvents
Doesn't fix #515 (arguably makes it worse in the sense that it's more
likely to throw). However it should provide better error reporting, and
make it more clear that it's not CC:T's fault.
2020-08-22 15:31:48 +01:00
R93950X
d5de39ebd4 Fix time formatting (#527)
Fixes #525.

Co-authored-by: R93950X <R93950X@users.noreply.github.com>
2020-08-22 15:17:12 +01:00
SquidDev
0faf76e4bd Fix if statement never being hit
Let's been honest, this bit's probably never been tested, because it
should never happen. Fixes #528.
2020-08-22 15:03:38 +01:00
SquidDev
e8e2ed9fe5 Fix incorrect lower bound in mods.toml
It appears I had failed to update this when last bumping the Forge
version. Closes #521 - we're relying on a feature only added in Forge
31.1.16, and they're using 3.1.14.
2020-08-09 21:51:55 +01:00
SquidDev
9f72448ecd Properly deprecate colors.rgb8 2020-08-04 19:50:36 +01:00
SquidDev
3da3f16deb Fix link to logo 2020-08-04 18:30:22 +01:00
hydraz
0e2ce3c634 Make the key for mtime "modified" in fs.attributes (#512) 2020-07-31 18:39:09 +01:00
SquidDev
fe00e00537 Mention people should include logs 2020-07-31 18:31:47 +01:00
Jonathan Coates
cd879b067f Merge pull request #508 from neumond/mc-1.15.x
Fix JSON serialization of strings
2020-07-25 17:51:46 +01:00
neumond
053cb1b53c Fix JSON serialization of strings
Control characters become escaped as JSON requires
Non-ASCII characters get escaped as well for better interoperability
We assume here that lua strings represent only first 256 code points of unicode
2020-07-25 19:40:06 +03:00
25 changed files with 286 additions and 55 deletions

View File

@@ -12,4 +12,5 @@ labels: bug
## Useful information to include:
- Minecraft version
- CC: Tweaked version
- Logs: These will be located in the `logs/` directory of your Minecraft instance. Please upload them as a gist or directly into this editor.
- Detailed reproduction steps: sometimes I can spot a bug pretty easily, but often it's much more obscure. The more information I have to help reproduce it, the quicker it'll get fixed.

View File

@@ -1,4 +1,4 @@
# ![CC: Tweaked](logo.png)
# ![CC: Tweaked](doc/logo.png)
[![Current build status](https://github.com/SquidDev-CC/CC-Tweaked/workflows/Build/badge.svg)](https://github.com/SquidDev-CC/CC-Tweaked/actions "Current build status") [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge")
CC: Tweaked is a fork of [ComputerCraft](https://github.com/dan200/ComputerCraft), adding programmable computers,
@@ -50,12 +50,12 @@ I'd generally recommend you don't contact me directly (email, DM, etc...) unless
report exploits). You'll get a far quicker response if you ask the whole community!
## Using
If you want to depend on CC: Tweaked, we have a maven repo. However, you should be wary that some functionality is only
exposed by CC:T's API and not vanilla ComputerCraft. If you wish to support all variations of ComputerCraft, I recommend
using [cc.crzd.me's maven](https://cc.crzd.me/maven/) instead.
CC: Tweaked is hosted on my maven repo, and so is relatively simple to depend on. You may wish to add a soft (or hard)
dependency in your `mods.toml` file, with the appropriate version bounds, to ensure that API functionality you depend
on is present.
```groovy
dependencies {
repositories {
maven { url 'https://squiddev.cc/maven/' }
}

View File

@@ -1,5 +1,5 @@
# Mod properties
mod_version=1.90.2
mod_version=1.92.0
# Minecraft properties (update mods.toml when changing)
mc_version=1.15.2

View File

@@ -101,6 +101,9 @@
(linters -doc:unresolved-reference))
(at /src/test/resources/test-rom
; We should still be able to test deprecated members.
(linters -var:deprecated)
(lint
(globals
:max sleep write

View File

@@ -39,6 +39,7 @@ public final class ComputerCraft
public static final String[] DEFAULT_HTTP_ALLOW = new String[] { "*" };
public static final String[] DEFAULT_HTTP_DENY = new String[] {
"127.0.0.0/8",
"0.0.0.0/8",
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",

View File

@@ -479,6 +479,7 @@ public class FSAPI implements ILuaAPI
BasicFileAttributes attributes = fileSystem.getAttributes( path );
Map<String, Object> result = new HashMap<>();
result.put( "modification", getFileTime( attributes.lastModifiedTime() ) );
result.put( "modified", getFileTime( attributes.lastModifiedTime() ) );
result.put( "created", getFileTime( attributes.creationTime() ) );
result.put( "size", attributes.isDirectory() ? 0 : attributes.size() );
result.put( "isDir", attributes.isDirectory() );

View File

@@ -395,14 +395,7 @@ public final class ComputerThread
executor.timeout.hardAbort();
executor.abort();
if( afterHardAbort >= ABORT_TIMEOUT )
{
// If we've hard aborted but we're still not dead, dump the stack trace and interrupt
// the task.
timeoutTask( executor, runner.owner, afterStart );
runner.owner.interrupt();
}
else if( afterHardAbort >= ABORT_TIMEOUT * 2 )
if( afterHardAbort >= ABORT_TIMEOUT * 2 )
{
// If we've hard aborted and interrupted, and we're still not dead, then mark the runner
// as dead, finish off the task, and spawn a new runner.
@@ -421,6 +414,13 @@ public final class ComputerThread
}
}
}
else if( afterHardAbort >= ABORT_TIMEOUT )
{
// If we've hard aborted but we're still not dead, dump the stack trace and interrupt
// the task.
timeoutTask( executor, runner.owner, afterStart );
runner.owner.interrupt();
}
}
}
}

View File

@@ -124,7 +124,7 @@ public class FileSystemWrapperMount implements IFileSystem
{
try
{
return m_filesystem.exists( path );
return m_filesystem.isDir( path );
}
catch( FileSystemException e )
{

View File

@@ -83,9 +83,9 @@ class VarargArguments implements IArguments
public ByteBuffer getBytes( int index ) throws LuaException
{
LuaValue value = varargs.arg( index + 1 );
if( !(value instanceof LuaString) ) throw LuaValues.badArgument( index, "string", value.typeName() );
if( !(value instanceof LuaBaseString) ) throw LuaValues.badArgument( index, "string", value.typeName() );
LuaString str = (LuaString) value;
LuaString str = ((LuaBaseString) value).strvalue();
return ByteBuffer.wrap( str.bytes, str.offset, str.length ).asReadOnlyBuffer();
}
@@ -94,9 +94,9 @@ class VarargArguments implements IArguments
{
LuaValue value = varargs.arg( index + 1 );
if( value.isNil() ) return Optional.empty();
if( !(value instanceof LuaString) ) throw LuaValues.badArgument( index, "string", value.typeName() );
if( !(value instanceof LuaBaseString) ) throw LuaValues.badArgument( index, "string", value.typeName() );
LuaString str = (LuaString) value;
LuaString str = ((LuaBaseString) value).strvalue();
return Optional.of( ByteBuffer.wrap( str.bytes, str.offset, str.length ).asReadOnlyBuffer() );
}
}

View File

@@ -13,10 +13,8 @@ import net.minecraft.util.math.BlockPos;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull;
import java.util.Objects;
/**
* Starts or stops a record on the client, depending on if {@link #soundEvent} is {@code null}.
@@ -51,7 +49,7 @@ public class PlayRecordClientMessage implements NetworkMessage
if( buf.readBoolean() )
{
name = buf.readString( Short.MAX_VALUE );
soundEvent = ForgeRegistries.SOUND_EVENTS.getValue( buf.readResourceLocation() );
soundEvent = buf.readRegistryIdSafe( SoundEvent.class );
}
else
{
@@ -72,7 +70,7 @@ public class PlayRecordClientMessage implements NetworkMessage
{
buf.writeBoolean( true );
buf.writeString( name );
buf.writeResourceLocation( Objects.requireNonNull( soundEvent.getRegistryName(), "Sound is not registered" ) );
buf.writeRegistryId( soundEvent );
}
}

View File

@@ -7,6 +7,8 @@
package dan200.computercraft.shared.peripheral.generic.data;
import com.google.gson.JsonParseException;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.item.EnchantedBookItem;
@@ -22,13 +24,29 @@ import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
/**
* Data providers for items.
*
* We guard using {@link ComputerCraft#genericPeripheral} in several places, as advanced functionality should not be
* exposed for {@code turtle.getItemDetail} when generic peripehrals are disabled.
*/
public class ItemData
{
@Nonnull
public static <T extends Map<? super String, Object>> T fillBasic( @Nonnull T data, @Nonnull ItemStack stack )
public static <T extends Map<? super String, Object>> T fillBasicSafe( @Nonnull T data, @Nonnull ItemStack stack )
{
data.put( "name", DataHelpers.getId( stack.getItem() ) );
data.put( "count", stack.getCount() );
return data;
}
@Nonnull
public static <T extends Map<? super String, Object>> T fillBasic( @Nonnull T data, @Nonnull ItemStack stack )
{
fillBasicSafe( data, stack );
String hash = NBTUtil.getNBTHash( stack.getTag() );
if( hash != null ) data.put( "nbt", hash );
return data;
}
@@ -55,6 +73,8 @@ public class ItemData
data.put( "tags", DataHelpers.getTags( stack.getItem().getTags() ) );
if( !ComputerCraft.genericPeripheral ) return data;
CompoundNBT tag = stack.getTag();
if( tag != null && tag.contains( "display", Constants.NBT.TAG_COMPOUND ) )
{

View File

@@ -605,7 +605,7 @@ public class TurtleAPI implements ILuaAPI
Map<String, Object> table = detailed
? ItemData.fill( new HashMap<>(), stack )
: ItemData.fillBasic( new HashMap<>(), stack );
: ItemData.fillBasicSafe( new HashMap<>(), stack );
TurtleActionEvent event = new TurtleInspectItemEvent( turtle, stack, table, detailed );
if( MinecraftForge.EVENT_BUS.post( event ) ) return new Object[] { false, event.getFailureMessage() };

View File

@@ -42,8 +42,6 @@ public final class DropConsumer
dropEntity = entity;
dropWorld = entity.world;
dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 );
entity.captureDrops( new ArrayList<>() );
}
public static void set( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer )
@@ -86,7 +84,7 @@ public final class DropConsumer
}
}
@SubscribeEvent
@SubscribeEvent( priority = EventPriority.LOW )
public static void onLivingDrops( LivingDropsEvent drops )
{
if( dropEntity == null || drops.getEntity() != dropEntity ) return;

View File

@@ -5,9 +5,19 @@
*/
package dan200.computercraft.shared.util;
import dan200.computercraft.ComputerCraft;
import net.minecraft.nbt.*;
import net.minecraftforge.common.util.Constants;
import org.apache.commons.codec.binary.Hex;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
@@ -159,4 +169,46 @@ public final class NBTUtil
}
return objects;
}
@Nullable
public static String getNBTHash( @Nullable CompoundNBT tag )
{
if( tag == null ) return null;
try
{
MessageDigest digest = MessageDigest.getInstance( "MD5" );
DataOutput output = new DataOutputStream( new DigestOutputStream( digest ) );
CompressedStreamTools.write( tag, output );
byte[] hash = digest.digest();
return new String( Hex.encodeHex( hash ) );
}
catch( NoSuchAlgorithmException | IOException e )
{
ComputerCraft.log.error( "Cannot hash NBT", e );
return null;
}
}
private static final class DigestOutputStream extends OutputStream
{
private final MessageDigest digest;
DigestOutputStream( MessageDigest digest )
{
this.digest = digest;
}
@Override
public void write( @Nonnull byte[] b, int off, int len )
{
digest.update( b, off, len );
}
@Override
public void write( int b )
{
digest.update( (byte) b );
}
}
}

View File

@@ -19,6 +19,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a
[[dependencies.computercraft]]
modId="forge"
mandatory=true
versionRange="[31.0.13,32)"
versionRange="[31.1.41,32)"
ordering="NONE"
side="BOTH"

View File

@@ -0,0 +1,48 @@
{
"gui.computercraft.tooltip.disk_id": "ID của đĩa: %s",
"upgrade.computercraft.speaker.adjective": "Ồn ào",
"upgrade.computercraft.wireless_modem_advanced.adjective": "Ender",
"upgrade.computercraft.wireless_modem_normal.adjective": "Không dây",
"upgrade.minecraft.crafting_table.adjective": "Chế tạo",
"upgrade.minecraft.diamond_hoe.adjective": "Trồng trọt",
"upgrade.minecraft.diamond_axe.adjective": "Đốn",
"upgrade.minecraft.diamond_pickaxe.adjective": "Khai thác",
"upgrade.minecraft.diamond_shovel.adjective": "Đào",
"item.computercraft.pocket_computer_advanced.upgraded": "Máy tính bỏ túi tiên tiến %s",
"item.computercraft.pocket_computer_advanced": "Máy tính bỏ túi tiên tiến",
"item.computercraft.pocket_computer_normal.upgraded": "Máy tính bỏ túi %s",
"item.computercraft.pocket_computer_normal": "Máy tính bỏ túi",
"item.computercraft.printed_book": "Sách in",
"item.computercraft.printed_page": "Trang in",
"item.computercraft.treasure_disk": "Đĩa mềm",
"item.computercraft.disk": "Đĩa mềm",
"block.computercraft.turtle_advanced.upgraded_twice": "Rùa tiên tiến %s %s",
"block.computercraft.turtle_advanced.upgraded": "Rùa tiên tiến %s",
"block.computercraft.turtle_advanced": "Rùa tiên tiến",
"block.computercraft.turtle_normal.upgraded_twice": "Rùa %s %s",
"block.computercraft.turtle_normal.upgraded": "Rùa %s",
"block.computercraft.turtle_normal": "Rùa",
"block.computercraft.wired_modem_full": "Modem có dây",
"block.computercraft.cable": "Dây cáp mạng",
"block.computercraft.wired_modem": "Modem có dây",
"block.computercraft.wireless_modem_advanced": "Modem Ender",
"block.computercraft.wireless_modem_normal": "Modem không dây",
"block.computercraft.monitor_advanced": "Màn hình tiên tiếng",
"block.computercraft.monitor_normal": "Màn hình",
"block.computercraft.speaker": "Loa",
"block.computercraft.printer": "Máy in",
"block.computercraft.disk_drive": "Ỗ đĩa",
"block.computercraft.computer_command": "Máy tính điều khiển",
"block.computercraft.computer_normal": "Máy tính",
"itemGroup.computercraft": "ComputerCraft",
"block.computercraft.computer_advanced": "Máy tính tiên tiến",
"tracking_field.computercraft.websocket_incoming.name": "Websocket đến",
"tracking_field.computercraft.websocket_outgoing.name": "Websocket đi",
"gui.computercraft.tooltip.computer_id": "ID của máy tính: %s",
"tracking_field.computercraft.coroutines_dead.name": "Coroutine bỏ đi",
"tracking_field.computercraft.coroutines_created.name": "Coroutine đã tạo",
"tracking_field.computercraft.http_download.name": "HTTP tải xuống",
"tracking_field.computercraft.http_upload.name": "HTTP tải lên",
"tracking_field.computercraft.http.name": "Yêu cầu HTTP",
"gui.computercraft.tooltip.copy": "Sao chép vào clipboard"
}

View File

@@ -181,9 +181,6 @@ end
--- Either calls @{colors.packRGB} or @{colors.unpackRGB}, depending on how many
-- arguments it receives.
--
-- **Note:** This function is deprecated, and it is recommended you use the
-- specific pack/unpack function directly.
--
-- @tparam[1] number r The red channel, as an argument to @{colors.packRGB}.
-- @tparam[1] number g The green channel, as an argument to @{colors.packRGB}.
-- @tparam[1] number b The blue channel, as an argument to @{colors.packRGB}.
@@ -192,6 +189,7 @@ end
-- @treturn[2] number The red channel, as returned by @{colors.unpackRGB}
-- @treturn[2] number The green channel, as returned by @{colors.unpackRGB}
-- @treturn[2] number The blue channel, as returned by @{colors.unpackRGB}
-- @deprecated Use @{packRGB} or @{unpackRGB} directly.
-- @usage
-- ```lua
-- colors.rgb(0xb23399)

View File

@@ -77,7 +77,7 @@ function formatTime(nTime, bTwentyFourHour)
local nHour = math.floor(nTime)
local nMinute = math.floor((nTime - nHour) * 60)
if sTOD then
return string.format("%d:%02d %s", nHour, nMinute, sTOD)
return string.format("%d:%02d %s", nHour == 0 and 12 or nHour, nMinute, sTOD)
else
return string.format("%d:%02d", nHour, nMinute)
end
@@ -335,6 +335,31 @@ empty_json_array = mk_tbl("[]", "empty_json_array")
-- @see textutils.unserialiseJSON
json_null = mk_tbl("null", "json_null")
local serializeJSONString
do
local function hexify(c)
return ("\\u00%02X"):format(c:byte())
end
local map = {
["\""] = "\\\"",
["\\"] = "\\\\",
["\b"] = "\\b",
["\f"] = "\\f",
["\n"] = "\\n",
["\r"] = "\\r",
["\t"] = "\\t",
}
for i = 0, 0x1f do
local c = string.char(i)
if map[c] == nil then map[c] = hexify(c) end
end
serializeJSONString = function(s)
return ('"%s"'):format(s:gsub("[\0-\x1f\"\\]", map):gsub("[\x7f-\xff]", hexify))
end
end
local function serializeJSONImpl(t, tTracking, bNBTStyle)
local sType = type(t)
if t == empty_json_array then return "[]"
@@ -361,7 +386,7 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle)
if bNBTStyle then
sEntry = tostring(k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle)
else
sEntry = string.format("%q", k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle)
sEntry = serializeJSONString(k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle)
end
if nObjectSize == 0 then
sObjectResult = sObjectResult .. sEntry
@@ -390,7 +415,7 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle)
end
elseif sType == "string" then
return string.format("%q", t)
return serializeJSONString(t)
elseif sType == "number" or sType == "boolean" then
return tostring(t)
@@ -407,7 +432,7 @@ do
--- Skip any whitespace
local function skip(str, pos)
local _, last = find(str, "^[ \n\r\v]+", pos)
local _, last = find(str, "^[ \n\r\t]+", pos)
if last then return last + 1 else return pos end
end
@@ -447,7 +472,7 @@ do
buf[n], n, pos = utf8.char(tonumber(num_str, 16)), n + 1, pos + 6
else
local unesc = escapes[c]
if not unesc then error_at(pos + 1, "Unknown escape character %q.", unesc) end
if not unesc then error_at(pos + 1, "Unknown escape character %q.", c) end
buf[n], n, pos = unesc, n + 1, pos + 2
end
elseif c >= '\x20' then

View File

@@ -1,3 +1,26 @@
# New features in CC: Tweaked 1.92.0
* Bump Cobalt version:
* Add support for the __pairs metamethod.
* string.format now uses the __tostring metamethod.
* Add date-specific MOTDs (MCJack123).
And several bug fixes:
* Correctly handle tabs within textutils.unserailizeJSON.
* Fix sheep not dropping items when sheered by turtles.
# New features in CC: Tweaked 1.91.0
* [Generic peripherals] Expose NBT hashes of items to inventory methods.
* Bump Cobalt version
* Optimise handling of string concatenation.
* Add string.{pack,unpack,packsize} (MCJack123)
And several bug fixes:
* Escape non-ASCII characters in JSON strings (neumond)
* Make field names in fs.attributes more consistent (abby)
* Fix textutils.formatTime correctly handle 12 AM (R93950X)
# New features in CC: Tweaked 1.90.2
* Fix generic peripherals not being registered outside a dev environment.

View File

@@ -1,5 +1,12 @@
New features in CC: Tweaked 1.90.2
New features in CC: Tweaked 1.92.0
* Fix generic peripherals not being registered outside a dev environment.
* Bump Cobalt version:
* Add support for the __pairs metamethod.
* string.format now uses the __tostring metamethod.
* Add date-specific MOTDs (MCJack123).
And several bug fixes:
* Correctly handle tabs within textutils.unserailizeJSON.
* Fix sheep not dropping items when sheered by turtles.
Type "help changelog" to see the full version history.

View File

@@ -1,15 +1,24 @@
local tMotd = {}
local date = os.date("*t")
if date.month == 1 and date.day == 1 then
print("Happy new year!")
elseif date.month == 12 and date.day == 24 then
print("Merry X-mas!")
elseif date.month == 10 and date.day == 31 then
print("OOoooOOOoooo! Spooky!")
else
local tMotd = {}
for sPath in string.gmatch(settings.get("motd.path"), "[^:]+") do
if fs.exists(sPath) then
for sLine in io.lines(sPath) do
table.insert(tMotd, sLine)
for sPath in string.gmatch(settings.get("motd.path"), "[^:]+") do
if fs.exists(sPath) then
for sLine in io.lines(sPath) do
table.insert(tMotd, sLine)
end
end
end
end
if #tMotd == 0 then
print("missingno")
else
print(tMotd[math.random(1, #tMotd)])
if #tMotd == 0 then
print("missingno")
else
print(tMotd[math.random(1, #tMotd)])
end
end

View File

@@ -0,0 +1 @@
[ ]

View File

@@ -208,9 +208,11 @@ describe("The fs library", function()
fail(("Expected created time (%d) to be within 1000ms of now (%d"):format(attributes.created, now))
end
if attributes.modification - now >= 1000 then
fail(("Expected modification time (%d) to be within 1000ms of now (%d"):format(attributes.modification, now))
if attributes.modified - now >= 1000 then
fail(("Expected modified time (%d) to be within 1000ms of now (%d"):format(attributes.modified, now))
end
expect(attributes.modification):eq(attributes.modified)
end)
end)
end)

View File

@@ -12,6 +12,14 @@ describe("The textutils library", function()
expect.error(textutils.formatTime, nil):eq("bad argument #1 (expected number, got nil)")
expect.error(textutils.formatTime, 1, 1):eq("bad argument #2 (expected boolean, got number)")
end)
it("correctly formats 12 o'clock", function()
expect(textutils.formatTime(0, false)):eq("12:00 AM")
expect(textutils.formatTime(0.1, false)):eq("12:06 AM")
expect(textutils.formatTime(0, true)):eq("0:00")
expect(textutils.formatTime(0.1, true)):eq("0:06")
end)
end)
describe("textutils.pagedPrint", function()
@@ -49,7 +57,7 @@ describe("The textutils library", function()
describe("textutils.empty_json_array", function()
it("is immutable", function()
expect.error(function() textutils.empty_json_array[1] = true end)
:str_match("^[^:]+:51: attempt to mutate textutils.empty_json_array$")
:str_match("^[^:]+:%d+: attempt to mutate textutils.empty_json_array$")
end)
end)
@@ -78,6 +86,20 @@ describe("The textutils library", function()
it("serializes null", function()
expect(textutils.serializeJSON(textutils.json_null)):eq("null")
end)
it("serializes strings", function()
expect(textutils.serializeJSON('a')):eq('"a"')
expect(textutils.serializeJSON('"')):eq('"\\""')
expect(textutils.serializeJSON('\\')):eq('"\\\\"')
expect(textutils.serializeJSON('/')):eq('"/"')
expect(textutils.serializeJSON('\b')):eq('"\\b"')
expect(textutils.serializeJSON('\n')):eq('"\\n"')
expect(textutils.serializeJSON(string.char(0))):eq('"\\u0000"')
expect(textutils.serializeJSON(string.char(0x0A))):eq('"\\n"')
expect(textutils.serializeJSON(string.char(0x1D))):eq('"\\u001D"')
expect(textutils.serializeJSON(string.char(0x81))):eq('"\\u0081"')
expect(textutils.serializeJSON(string.char(0xFF))):eq('"\\u00FF"')
end)
end)
describe("textutils.unserializeJSON", function()

View File

@@ -1,14 +1,36 @@
local capture = require "test_helpers".capture_program
describe("The motd program", function()
local function setup_date(month, day)
stub(os, "date", function() return { month = month, day = day } end)
end
it("displays MODT", function()
local file = fs.open("/modt_check.txt", "w")
it("displays MOTD", function()
setup_date(0, 0)
local file = fs.open("/motd_check.txt", "w")
file.write("Hello World!")
file.close()
settings.set("motd.path", "/modt_check.txt")
settings.set("motd.path", "/motd_check.txt")
expect(capture(stub, "motd"))
:matches { ok = true, output = "Hello World!\n", error = "" }
end)
it("displays date-specific MOTD (1/1)", function()
setup_date(1, 1)
expect(capture(stub, "motd"))
:matches { ok = true, output = "Happy new year!\n", error = "" }
end)
it("displays date-specific MOTD (10/31)", function()
setup_date(10, 31)
expect(capture(stub, "motd"))
:matches { ok = true, output = "OOoooOOOoooo! Spooky!\n", error = "" }
end)
it("displays date-specific MOTD (12/24)", function()
setup_date(12, 24)
expect(capture(stub, "motd"))
:matches { ok = true, output = "Merry X-mas!\n", error = "" }
end)
end)