1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-16 14:37:39 +00:00

Compare commits

..

54 Commits

Author SHA1 Message Date
SquidDev
71563a52ff Let's make this a proper release 2020-10-04 11:31:06 +01:00
SquidDev
0c6e7b5db5 Merge branch 'mc-1.15.x' into mc-1.16.x 2020-10-04 11:24:42 +01:00
SquidDev
334ca65482 Bump to 1.93.0 2020-10-04 11:19:43 +01:00
Jonathan Coates
8472112fc1 Don't propagate adjacent redstone signals for computers (#549)
Minecraft propagates "strong" redstone signals (such as those directly
from comparators or repeaters) through solid blocks. This includes
computers, which is a little annoying as it means one cannot feed
redstone wire from one side and a repeater from another.

This changes computers to not propagate strong redstone signals, in the
same way transparent blocks like glass do.

Closes #548.
2020-10-04 11:14:22 +01:00
SquidDev
84036d97d9 Fix io.open documentation
Well, that was silly.
2020-10-02 21:21:53 +01:00
Weblate
0832974725 Translations for Swedish
Co-authored-by: David Isaksson <davidisaksson93@gmail.com>
2020-09-30 08:25:57 +00:00
SquidDev
6cee4efcd3 Fix incorrect open container check
Was this always broken, or did it happen in a Minecraft update? Don't
know, but it's a very silly mistake either way. Fixes #544
2020-09-24 17:47:30 +01:00
SquidDev
6f868849ab Use tags to check if something is a dye
We half did this already, just needed to change a couple of checks.
Closes #541.
2020-09-16 21:27:59 +01:00
SquidDev
275ca58a82 HTTP rules now allow filtering by port
The HTTP filtering system becomes even more complex! Though in this
case, it's pretty minimal, and definitely worth doing.

For instance, the following rule will allow connecting to localhost on
port :8080.

    [[http.rules]]
    host = "127.0.0.1"
    port = 8080
    action = "allow"

    # Other rules as before.

Closes #540
2020-09-15 22:05:27 +01:00
SquidDev
87393e8aef Fix additional - in docs
Why isn't this automatically stripped! Bad squid.
2020-09-13 17:56:12 +01:00
SquidDev
86bf57e3cd My inability to spell will be immortalsied in the changelog 2020-09-12 11:03:18 +01:00
SquidDev
72c1d451fe Mark the release as beta-quality 2020-09-12 10:47:19 +01:00
SquidDev
8b4a01df27 Update to Minecraft 1.16.3
I hope the Fabric folks now realise this is gonna be a race of who can
update first :p. Either way, this was a very easy update - only changes
were due to unrelated Forge changes.
2020-09-12 10:45:59 +01:00
SquidDev
d0a973fa46 Merge branch 'mc-1.15.x' into mc-1.16.x 2020-09-12 09:29:21 +01:00
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
SquidDev
26c12ac1a9 Bump version to 1.91.1 2020-09-04 17:29:35 +01:00
SquidDev
2c67849b35 Fix NPE when turtles interact with an entity
Closes #531
2020-08-27 17:17:03 +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
7809a2eddd Merge branch 'mc-1.15.x' into mc-1.16.x 2020-08-23 15:46:17 +01: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
e8e9294fdf Correctly check for success or consume
No, I don't really know what the difference is either :). Closes #518.
2020-08-22 19:28:02 +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
99581e1f40 Initial update to 1.16.2
Seems to load fine, but not done any proper testing.
2020-08-14 22:00:03 +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
SquidDev
29646a7f61 Bump version to 1.90.3 2020-07-27 19:07:06 +01:00
SquidDev
50d2712581 Resolve CC's save location to the world dir
Fixes #509
2020-07-27 19:04:57 +01:00
SquidDev
3093f882d8 Fix selected slot now showing in the turtle GUI 2020-07-27 18:37:07 +01:00
SquidDev
e5cf0d1c61 Update mappings 2020-07-27 18:26:42 +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
SquidDev
6b102a8142 Merge branch 'mc-1.15.x' into mc-1.16.x 2020-07-25 12:08:33 +01:00
SquidDev
ac7979fb46 Bump for 1.90.2 2020-07-25 11:53:46 +01:00
SquidDev
c8a6888a2f Fix styles not being saved
Styles have been changed to be immutable, meaning that we were never
updating them! Fixes #499.
2020-07-25 11:19:04 +01:00
SquidDev
9ce33f8a3f Add back missing override of getPositionVec
This was removed in the initial update (46595e73df)
because I got terribly confused over mappings and I forgot to add it
back.

Fixes #505
2020-07-25 10:56:50 +01:00
SquidDev
d51851e763 Use FML's scan data to gather annotations
We can just scrape them from the @AutoService annotation, which saves us
having to duplicate any work. Hopefully fixes #501, but I haven't tested
in a non-dev environment yet.
2020-07-23 22:41:20 +01:00
BlackDragon-B
fb70a1a998 Added Windows thing. (#500) 2020-07-18 18:59:52 +01:00
72 changed files with 707 additions and 230 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

@@ -10,7 +10,7 @@ do use the issue templates - they provide a useful hint on what information to p
## Developing
In order to develop CC: Tweaked, you'll need to download the source code and then run it. This is a pretty simple
process.
process. When building on Windows, Use `gradlew.bat` instead of `./gradlew`.
- **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked`
- **Setup Forge:** `./gradlew build`

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

@@ -409,7 +409,7 @@ curseforge {
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
project {
id = '282001'
releaseType = 'alpha'
releaseType = 'release'
changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})."
relations {
@@ -487,7 +487,7 @@ githubRelease {
.takeWhile { it != 'Type "help changelog" to see the full version history.' }
.join("\n").trim()
}
prerelease true
prerelease false
}
def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"]

View File

@@ -1,7 +1,7 @@
# Mod properties
mod_version=1.90.1
mod_version=1.93.0
# Minecraft properties (update mods.toml when changing)
mc_version=1.16.1
forge_version=32.0.69
mappings_version=20200707-1.16.1
mc_version=1.16.3
forge_version=34.0.1
mappings_version=20200723-1.16.1

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

@@ -8,6 +8,7 @@ package dan200.computercraft;
import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.core.apis.http.options.Action;
import dan200.computercraft.core.apis.http.options.AddressRule;
import dan200.computercraft.core.asm.GenericSource;
import dan200.computercraft.shared.Config;
import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
@@ -16,6 +17,7 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
import dan200.computercraft.shared.turtle.upgrades.*;
import dan200.computercraft.shared.util.ServiceUtil;
import net.minecraftforge.fml.common.Mod;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -37,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",
@@ -60,10 +63,10 @@ public final class ComputerCraft
public static boolean httpWebsocketEnabled = true;
public static List<AddressRule> httpRules = Collections.unmodifiableList( Stream.concat(
Stream.of( DEFAULT_HTTP_DENY )
.map( x -> AddressRule.parse( x, Action.DENY.toPartial() ) )
.map( x -> AddressRule.parse( x, null, Action.DENY.toPartial() ) )
.filter( Objects::nonNull ),
Stream.of( DEFAULT_HTTP_ALLOW )
.map( x -> AddressRule.parse( x, Action.ALLOW.toPartial() ) )
.map( x -> AddressRule.parse( x, null, Action.ALLOW.toPartial() ) )
.filter( Objects::nonNull )
).collect( Collectors.toList() ) );
@@ -133,5 +136,6 @@ public final class ComputerCraft
{
Config.setup();
Registry.setup();
GenericSource.setup( () -> ServiceUtil.loadServicesForge( GenericSource.class ) );
}
}

View File

@@ -54,7 +54,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
public static InputStream getResourceFile( String domain, String subPath )
{
IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().func_240970_h_();
IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().getResourceManager();
try
{
return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream();
@@ -97,7 +97,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
@Override
public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath )
{
IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().func_240970_h_();
IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().getResourceManager();
ResourceMount mount = ResourceMount.get( domain, subPath, manager );
return mount.exists( "" ) ? mount : null;
}

View File

@@ -91,13 +91,13 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Containe
terminalWrapper = new WidgetWrapper( terminal, MARGIN + BORDER + guiLeft, MARGIN + BORDER + guiTop, termPxWidth, termPxHeight );
children.add( terminalWrapper );
setFocused( terminalWrapper );
setListener( terminalWrapper );
}
@Override
public void removed()
public void onClose()
{
super.removed();
super.onClose();
children.remove( terminal );
terminal = null;
minecraft.keyboardListener.enableRepeatEvents( false );
@@ -114,16 +114,16 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Containe
public boolean keyPressed( int key, int scancode, int modifiers )
{
// Forward the tab key to the terminal, rather than moving between controls.
if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminalWrapper )
if( key == GLFW.GLFW_KEY_TAB && getListener() != null && getListener() == terminalWrapper )
{
return getFocused().keyPressed( key, scancode, modifiers );
return getListener().keyPressed( key, scancode, modifiers );
}
return super.keyPressed( key, scancode, modifiers );
}
@Override
public void func_230450_a_( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY )
public void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY )
{
// Draw terminal
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
@@ -147,12 +147,12 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Containe
@Override
public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
{
return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ))
return (getListener() != null && getListener().mouseDragged( x, y, button, deltaX, deltaY ))
|| super.mouseDragged( x, y, button, deltaX, deltaY );
}
@Override
protected void func_230451_b_( @Nonnull MatrixStack transform, int mouseX, int mouseY )
protected void drawGuiContainerForegroundLayer( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels.
}

View File

@@ -25,7 +25,7 @@ public class GuiDiskDrive extends ContainerScreen<ContainerDiskDrive>
}
@Override
protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
protected void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bindTexture( BACKGROUND );

View File

@@ -33,7 +33,7 @@ public class GuiPrinter extends ContainerScreen<ContainerPrinter>
}*/
@Override
protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
protected void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bindTexture( BACKGROUND );

View File

@@ -15,7 +15,6 @@ import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.TransformationMatrix;
import net.minecraft.util.text.ITextComponent;
import org.lwjgl.glfw.GLFW;
@@ -25,8 +24,6 @@ import static dan200.computercraft.client.render.PrintoutRenderer.*;
public class GuiPrintout extends ContainerScreen<ContainerHeldItem>
{
private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix();
private final boolean m_book;
private final int m_pages;
private final TextBuffer[] m_text;
@@ -94,7 +91,7 @@ public class GuiPrintout extends ContainerScreen<ContainerHeldItem>
}
@Override
protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
protected void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
// Draw the printout
RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
@@ -116,11 +113,10 @@ public class GuiPrintout extends ContainerScreen<ContainerHeldItem>
setBlitOffset( getBlitOffset() + 1 );
super.render( stack, mouseX, mouseY, partialTicks );
func_230459_a_( stack, mouseX, mouseY );
}
@Override
protected void func_230451_b_( @Nonnull MatrixStack transform, int mouseX, int mouseY )
protected void drawGuiContainerForegroundLayer( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels.
}

View File

@@ -64,13 +64,13 @@ public class GuiTurtle extends ContainerScreen<ContainerTurtle>
terminalWrapper = new WidgetWrapper( terminal, 2 + 8 + guiLeft, 2 + 8 + guiTop, termPxWidth, termPxHeight );
children.add( terminalWrapper );
setFocused( terminalWrapper );
setListener( terminalWrapper );
}
@Override
public void removed()
public void onClose()
{
super.removed();
super.onClose();
children.remove( terminal );
terminal = null;
minecraft.keyboardListener.enableRepeatEvents( false );
@@ -87,41 +87,38 @@ public class GuiTurtle extends ContainerScreen<ContainerTurtle>
public boolean keyPressed( int key, int scancode, int modifiers )
{
// Forward the tab key to the terminal, rather than moving between controls.
if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminalWrapper )
if( key == GLFW.GLFW_KEY_TAB && getListener() != null && getListener() == terminalWrapper )
{
return getFocused().keyPressed( key, scancode, modifiers );
return getListener().keyPressed( key, scancode, modifiers );
}
return super.keyPressed( key, scancode, modifiers );
}
private void drawSelectionSlot( boolean advanced )
{
// Draw selection slot
int slot = m_container.getSelectedSlot();
if( slot >= 0 )
{
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
int slotX = slot % 4;
int slotY = slot / 4;
minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
// TODO: blit( guiLeft + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, guiTop + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, 0, 217, 24, 24 );
}
}
@Override
protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
protected void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
// Draw term
boolean advanced = m_family == ComputerFamily.ADVANCED;
ResourceLocation texture = m_family == ComputerFamily.ADVANCED ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL;
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
// Draw border/inventory
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
minecraft.getTextureManager().bindTexture( texture );
blit( transform, guiLeft, guiTop, 0, 0, xSize, ySize );
drawSelectionSlot( advanced );
// Draw selection slot
int slot = m_container.getSelectedSlot();
if( slot >= 0 )
{
int slotX = slot % 4;
int slotY = slot / 4;
blit( transform,
guiLeft + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18,
guiTop + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18,
0, 217, 24, 24
);
}
}
@Override
@@ -135,12 +132,12 @@ public class GuiTurtle extends ContainerScreen<ContainerTurtle>
@Override
public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
{
return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ))
return (getListener() != null && getListener().mouseDragged( x, y, button, deltaX, deltaY ))
|| super.mouseDragged( x, y, button, deltaX, deltaY );
}
@Override
protected void func_230451_b_( @Nonnull MatrixStack transform, int mouseX, int mouseY )
protected void drawGuiContainerForegroundLayer( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels.
}

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

@@ -24,14 +24,14 @@ public class CheckUrl extends Resource<CheckUrl>
private final IAPIEnvironment environment;
private final String address;
private final String host;
private final URI uri;
public CheckUrl( ResourceGroup<CheckUrl> limiter, IAPIEnvironment environment, String address, URI uri )
{
super( limiter );
this.environment = environment;
this.address = address;
host = uri.getHost();
this.uri = uri;
}
public void run()
@@ -47,8 +47,9 @@ public class CheckUrl extends Resource<CheckUrl>
try
{
InetSocketAddress netAddress = NetworkUtils.getAddress( host, 80, false );
NetworkUtils.getOptions( host, netAddress );
boolean ssl = uri.getScheme().equalsIgnoreCase( "https" );
InetSocketAddress netAddress = NetworkUtils.getAddress( uri, ssl );
NetworkUtils.getOptions( uri.getHost(), netAddress );
if( tryClose() ) environment.queueEvent( EVENT, address, true );
}

View File

@@ -19,6 +19,7 @@ import io.netty.handler.ssl.SslContextBuilder;
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManagerFactory;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.KeyStore;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
@@ -99,6 +100,21 @@ public final class NetworkUtils
}
}
/**
* Create a {@link InetSocketAddress} from a {@link java.net.URI}.
*
* Note, this may require a DNS lookup, and so should not be executed on the main CC thread.
*
* @param uri The URI to fetch.
* @param ssl Whether to connect with SSL. This is used to find the default port if not otherwise specified.
* @return The resolved address.
* @throws HTTPRequestException If the host is not malformed.
*/
public static InetSocketAddress getAddress( URI uri, boolean ssl ) throws HTTPRequestException
{
return getAddress( uri.getHost(), uri.getPort(), ssl );
}
/**
* Create a {@link InetSocketAddress} from the resolved {@code host} and port.
*
@@ -128,7 +144,7 @@ public final class NetworkUtils
*/
public static Options getOptions( String host, InetSocketAddress address ) throws HTTPRequestException
{
Options options = AddressRule.apply( ComputerCraft.httpRules, host, address.getAddress() );
Options options = AddressRule.apply( ComputerCraft.httpRules, host, address );
if( options.action == Action.DENY ) throw new HTTPRequestException( "Domain not permitted" );
return options;
}

View File

@@ -12,6 +12,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.regex.Pattern;
/**
@@ -52,17 +53,23 @@ public final class AddressRule
private final HostRange ip;
private final Pattern domainPattern;
private final Integer port;
private final PartialOptions partial;
private AddressRule( @Nullable HostRange ip, @Nullable Pattern domainPattern, @Nonnull PartialOptions partial )
private AddressRule(
@Nullable HostRange ip,
@Nullable Pattern domainPattern,
@Nullable Integer port,
@Nonnull PartialOptions partial )
{
this.ip = ip;
this.domainPattern = domainPattern;
this.partial = partial;
this.port = port;
}
@Nullable
public static AddressRule parse( String filter, @Nonnull PartialOptions partial )
public static AddressRule parse( String filter, @Nullable Integer port, @Nonnull PartialOptions partial )
{
int cidr = filter.indexOf( '/' );
if( cidr >= 0 )
@@ -117,24 +124,27 @@ public final class AddressRule
size -= 8;
}
return new AddressRule( new HostRange( minBytes, maxBytes ), null, partial );
return new AddressRule( new HostRange( minBytes, maxBytes ), null, port, partial );
}
else
{
Pattern pattern = Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" );
return new AddressRule( null, pattern, partial );
return new AddressRule( null, pattern, port, partial );
}
}
/**
* Determine whether the given address matches a series of patterns.
*
* @param domain The domain to match
* @param address The address to check.
* @param domain The domain to match
* @param socketAddress The address to check.
* @return Whether it matches any of these patterns.
*/
private boolean matches( String domain, InetAddress address )
private boolean matches( String domain, InetSocketAddress socketAddress )
{
InetAddress address = socketAddress.getAddress();
if( port != null && port != socketAddress.getPort() ) return false;
if( domainPattern != null )
{
if( domainPattern.matcher( domain ).matches() ) return true;
@@ -155,7 +165,7 @@ public final class AddressRule
return ip != null && ip.contains( address );
}
public static Options apply( Iterable<? extends AddressRule> rules, String domain, InetAddress address )
public static Options apply( Iterable<? extends AddressRule> rules, String domain, InetSocketAddress address )
{
PartialOptions options = null;
boolean hasMany = false;

View File

@@ -49,12 +49,14 @@ public class AddressRuleConfig
public static boolean checkRule( UnmodifiableConfig builder )
{
String hostObj = get( builder, "host", String.class ).orElse( null );
Integer port = get( builder, "port", Number.class ).map( Number::intValue ).orElse( null );
return hostObj != null && checkEnum( builder, "action", Action.class )
&& check( builder, "port", Number.class )
&& check( builder, "timeout", Number.class )
&& check( builder, "max_upload", Number.class )
&& check( builder, "max_download", Number.class )
&& check( builder, "websocket_message", Number.class )
&& AddressRule.parse( hostObj, PartialOptions.DEFAULT ) != null;
&& AddressRule.parse( hostObj, port, PartialOptions.DEFAULT ) != null;
}
@Nullable
@@ -64,6 +66,7 @@ public class AddressRuleConfig
if( hostObj == null ) return null;
Action action = getEnum( builder, "action", Action.class ).orElse( null );
Integer port = get( builder, "port", Number.class ).map( Number::intValue ).orElse( null );
Integer timeout = get( builder, "timeout", Number.class ).map( Number::intValue ).orElse( null );
Long maxUpload = get( builder, "max_upload", Number.class ).map( Number::longValue ).orElse( null );
Long maxDownload = get( builder, "max_download", Number.class ).map( Number::longValue ).orElse( null );
@@ -77,7 +80,7 @@ public class AddressRuleConfig
websocketMessage
);
return AddressRule.parse( hostObj, options );
return AddressRule.parse( hostObj, port, options );
}
private static <T> boolean check( UnmodifiableConfig config, String field, Class<T> klass )

View File

@@ -136,7 +136,7 @@ public class HttpRequest extends Resource<HttpRequest>
try
{
boolean ssl = uri.getScheme().equalsIgnoreCase( "https" );
InetSocketAddress socketAddress = NetworkUtils.getAddress( uri.getHost(), uri.getPort(), ssl );
InetSocketAddress socketAddress = NetworkUtils.getAddress( uri, ssl );
Options options = NetworkUtils.getOptions( uri.getHost(), socketAddress );
SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null;

View File

@@ -129,8 +129,7 @@ public class Websocket extends Resource<Websocket>
try
{
boolean ssl = uri.getScheme().equalsIgnoreCase( "wss" );
InetSocketAddress socketAddress = NetworkUtils.getAddress( uri.getHost(), uri.getPort(), ssl );
InetSocketAddress socketAddress = NetworkUtils.getAddress( uri, ssl );
Options options = NetworkUtils.getOptions( uri.getHost(), socketAddress );
SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null;

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.core.asm;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
import dan200.computercraft.shared.util.ServiceUtil;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull;
@@ -16,11 +17,12 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import java.util.stream.Stream;
/**
* A generic source of {@link LuaMethod} functions. This allows for injecting methods onto objects you do not own.
@@ -42,6 +44,18 @@ public interface GenericSource
@Nonnull
ResourceLocation id();
/**
* Register a stream of generic sources.
*
* @param sources The source of generic methods.
* @see ServiceUtil For ways to load this. Sadly {@link java.util.ServiceLoader} is broken under Forge, but we don't
* want to add a hard-dep on Forge within core either.
*/
static void setup( Supplier<Stream<GenericSource>> sources )
{
GenericMethod.sources = sources;
}
/**
* A generic method is a method belonging to a {@link GenericSource} with a known target.
*/
@@ -51,6 +65,7 @@ public interface GenericSource
final LuaFunction annotation;
final Class<?> target;
static Supplier<Stream<GenericSource>> sources;
private static List<GenericMethod> cache;
GenericMethod( Method method, LuaFunction annotation, Class<?> target )
@@ -68,10 +83,16 @@ public interface GenericSource
static List<GenericMethod> all()
{
if( cache != null ) return cache;
return cache = StreamSupport
.stream( ServiceLoader.load( GenericSource.class, GenericSource.class.getClassLoader() ).spliterator(), false )
if( sources == null )
{
ComputerCraft.log.warn( "Getting GenericMethods without a provider" );
return cache = Collections.emptyList();
}
return cache = sources.get()
.flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) )
.map( method -> {
.map( method ->
{
LuaFunction annotation = method.getAnnotation( LuaFunction.class );
if( annotation == null ) return null;

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

@@ -7,7 +7,6 @@
package dan200.computercraft.data;
import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import net.minecraft.data.BlockTagsProvider;
import net.minecraft.data.DataGenerator;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@@ -24,6 +23,6 @@ public class Generators
DataGenerator generator = event.getGenerator();
generator.addProvider( new Recipes( generator ) );
generator.addProvider( new LootTables( generator ) );
generator.addProvider( new Tags( generator, new BlockTagsProvider( generator ) ) );
generator.addProvider( new Tags( generator, event.getExistingFileHelper() ) );
}
}

View File

@@ -15,6 +15,7 @@ import net.minecraft.item.Item;
import net.minecraft.tags.ITag;
import net.minecraft.tags.ItemTags;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.data.ExistingFileHelper;
import static dan200.computercraft.data.Tags.CCTags.*;
@@ -30,24 +31,24 @@ public class Tags extends ItemTagsProvider
public static final ITag.INamedTag<Item> MONITOR = item( "monitor" );
}
public Tags( DataGenerator generator, BlockTagsProvider tags )
public Tags( DataGenerator generator, ExistingFileHelper helper )
{
super( generator, tags );
super( generator, new BlockTagsProvider( generator, ComputerCraft.MOD_ID, helper ), ComputerCraft.MOD_ID, helper );
}
@Override
protected void registerTags()
{
func_240522_a_( COMPUTER ).func_240534_a_(
getOrCreateBuilder( COMPUTER ).add(
Registry.ModItems.COMPUTER_NORMAL.get(),
Registry.ModItems.COMPUTER_ADVANCED.get(),
Registry.ModItems.COMPUTER_COMMAND.get()
);
func_240522_a_( TURTLE ).func_240534_a_( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() );
func_240522_a_( WIRED_MODEM ).func_240534_a_( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() );
func_240522_a_( MONITOR ).func_240534_a_( Registry.ModItems.MONITOR_NORMAL.get(), Registry.ModItems.MONITOR_ADVANCED.get() );
getOrCreateBuilder( TURTLE ).add( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() );
getOrCreateBuilder( WIRED_MODEM ).add( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() );
getOrCreateBuilder( MONITOR ).add( Registry.ModItems.MONITOR_NORMAL.get(), Registry.ModItems.MONITOR_ADVANCED.get() );
func_240522_a_( PIGLIN_LOVED ).func_240534_a_(
getOrCreateBuilder( PIGLIN_LOVED ).add(
Registry.ModItems.COMPUTER_ADVANCED.get(), Registry.ModItems.TURTLE_ADVANCED.get(),
Registry.ModItems.WIRELESS_MODEM_ADVANCED.get(), Registry.ModItems.POCKET_COMPUTER_ADVANCED.get(),
Registry.ModItems.MONITOR_ADVANCED.get()

View File

@@ -289,11 +289,11 @@ public final class CommandComputerCraft
// Append the computer instance
if( serverComputer == null )
{
out.func_230529_a_( text( "?" ) );
out.append( text( "?" ) );
}
else
{
out.func_230529_a_( link(
out.append( link(
text( Integer.toString( serverComputer.getInstanceID() ) ),
"/computercraft dump " + serverComputer.getInstanceID(),
translate( "commands.computercraft.dump.action" )
@@ -301,20 +301,20 @@ public final class CommandComputerCraft
}
// And ID
out.func_240702_b_( " (id " + computerId + ")" );
out.appendString( " (id " + computerId + ")" );
// And, if we're a player, some useful links
if( serverComputer != null && UserLevel.OP.test( source ) && isPlayer( source ) )
{
out
.func_240702_b_( " " )
.func_230529_a_( link(
.appendString( " " )
.append( link(
text( "\u261b" ),
"/computercraft tp " + serverComputer.getInstanceID(),
translate( "commands.computercraft.tp.action" )
) )
.func_240702_b_( " " )
.func_230529_a_( link(
.appendString( " " )
.append( link(
text( "\u20e2" ),
"/computercraft view " + serverComputer.getInstanceID(),
translate( "commands.computercraft.view.action" )

View File

@@ -12,6 +12,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.command.CommandSource;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.util.text.event.ClickEvent;
import net.minecraft.util.text.event.HoverEvent;
@@ -57,10 +58,8 @@ public final class CommandCopy
public static ITextComponent createCopyText( String text )
{
StringTextComponent name = new StringTextComponent( text );
name.getStyle()
return new StringTextComponent( text ).mergeStyle( Style.EMPTY
.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, PREFIX + text ) )
.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) );
return name;
.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) ) );
}
}

View File

@@ -175,11 +175,11 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
String usage = dispatcher.getSmartUsage( temp, context.getSource() ).get( node ).substring( node.getName().length() );
IFormattableTextComponent output = new StringTextComponent( "" )
.func_230529_a_( coloured( "/" + command + usage, HEADER ) )
.func_240702_b_( " " )
.func_230529_a_( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) )
.func_240702_b_( "\n" )
.func_230529_a_( translate( "commands." + id + ".desc" ) );
.append( coloured( "/" + command + usage, HEADER ) )
.appendString( " " )
.append( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) )
.appendString( "\n" )
.append( translate( "commands." + id + ".desc" ) );
for( CommandNode<CommandSource> child : node.getChildren() )
{
@@ -188,16 +188,16 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
continue;
}
output.func_240702_b_( "\n" );
output.appendString( "\n" );
IFormattableTextComponent component = coloured( child.getName(), NAME );
component.getStyle().setClickEvent( new ClickEvent(
ClickEvent.Action.SUGGEST_COMMAND,
"/" + command + " " + child.getName()
) );
output.func_230529_a_( component );
output.append( component );
output.func_240702_b_( " - " ).func_230529_a_( translate( "commands." + id + "." + child.getName() + ".synopsis" ) );
output.appendString( " - " ).append( translate( "commands." + id + "." + child.getName() + ".synopsis" ) );
}
return output;

View File

@@ -21,14 +21,12 @@ public final class ChatHelpers
public static IFormattableTextComponent coloured( String text, TextFormatting colour )
{
IFormattableTextComponent component = new StringTextComponent( text == null ? "" : text );
component.getStyle().setFormatting( colour );
return component;
return new StringTextComponent( text == null ? "" : text ).mergeStyle( colour );
}
public static <T extends IFormattableTextComponent> T coloured( T component, TextFormatting colour )
{
component.getStyle().setFormatting( colour );
component.mergeStyle( colour );
return component;
}
@@ -52,7 +50,7 @@ public final class ChatHelpers
IFormattableTextComponent component = new StringTextComponent( "" );
for( ITextComponent child : children )
{
component.func_230529_a_( child );
component.append( child );
}
return component;
}
@@ -74,11 +72,11 @@ public final class ChatHelpers
{
Style style = component.getStyle();
if( style.getColor() == null ) style.setFormatting( TextFormatting.YELLOW );
style.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ) );
style.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) );
if( style.getColor() == null ) style = style.setFormatting( TextFormatting.YELLOW );
style = style.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ) );
style = style.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) );
return component;
return component.setStyle( style );
}
public static IFormattableTextComponent header( String text )

View File

@@ -79,12 +79,12 @@ public interface TableFormatter
StringTextComponent line = new StringTextComponent( "" );
for( int i = 0; i < columns - 1; i++ )
{
line.func_230529_a_( headers[i] );
line.append( headers[i] );
ITextComponent padding = getPadding( headers[i], maxWidths[i] );
if( padding != null ) line.func_230529_a_( padding );
line.func_230529_a_( SEPARATOR );
if( padding != null ) line.append( padding );
line.append( SEPARATOR );
}
line.func_230529_a_( headers[columns - 1] );
line.append( headers[columns - 1] );
writeLine( rowId++, line );
@@ -100,12 +100,12 @@ public interface TableFormatter
StringTextComponent line = new StringTextComponent( "" );
for( int i = 0; i < columns - 1; i++ )
{
line.func_230529_a_( row[i] );
line.append( row[i] );
ITextComponent padding = getPadding( row[i], maxWidths[i] );
if( padding != null ) line.func_230529_a_( padding );
line.func_230529_a_( SEPARATOR );
if( padding != null ) line.append( padding );
line.append( SEPARATOR );
}
line.func_230529_a_( row[columns - 1] );
line.append( row[columns - 1] );
writeLine( rowId++, line );
}

View File

@@ -25,7 +25,9 @@ import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fml.RegistryObject;
@@ -138,6 +140,7 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
public void onBlockHarvested( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull PlayerEntity player )
{
if( !(world instanceof ServerWorld) ) return;
ServerWorld serverWorld = (ServerWorld) world;
// We drop the item here instead of doing it in the harvest method, as we should
// drop computers for creative players too.
@@ -146,19 +149,19 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
if( tile instanceof TileComputerBase )
{
TileComputerBase computer = (TileComputerBase) tile;
LootContext.Builder context = new LootContext.Builder( (ServerWorld) world )
LootContext.Builder context = new LootContext.Builder( serverWorld )
.withRandom( world.rand )
.withParameter( LootParameters.POSITION, pos )
.withParameter( LootParameters.field_237457_g_, Vector3d.copyCentered( pos ) )
.withParameter( LootParameters.TOOL, player.getHeldItemMainhand() )
.withParameter( LootParameters.THIS_ENTITY, player )
.withNullableParameter( LootParameters.BLOCK_ENTITY, tile )
.withParameter( LootParameters.BLOCK_ENTITY, tile )
.withDynamicDrop( DROP, ( ctx, out ) -> out.accept( getItem( computer ) ) );
for( ItemStack item : state.getDrops( context ) )
{
spawnAsEntity( world, pos, item );
}
state.spawnAdditionalDrops( world, pos, player.getHeldItemMainhand() );
state.spawnAdditionalDrops( serverWorld, pos, player.getHeldItemMainhand() );
}
}
@@ -180,4 +183,10 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
if( label != null ) computer.setLabel( label );
}
}
@Override
public boolean shouldCheckWeakPower( BlockState state, IWorldReader world, BlockPos pos, Direction side )
{
return false;
}
}

View File

@@ -43,7 +43,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte
if( id >= 0 )
{
list.add( new TranslationTextComponent( "gui.computercraft.tooltip.computer_id", id )
.func_240699_a_( TextFormatting.GRAY ) );
.mergeStyle( TextFormatting.GRAY ) );
}
}
}

View File

@@ -69,7 +69,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem
if( id >= 0 )
{
list.add( new TranslationTextComponent( "gui.computercraft.tooltip.disk_id", id )
.func_240699_a_( TextFormatting.GRAY ) );
.mergeStyle( TextFormatting.GRAY ) );
}
}
}

View File

@@ -14,10 +14,8 @@ import net.minecraft.util.text.StringTextComponent;
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}.
@@ -52,7 +50,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
{
@@ -73,7 +71,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 ) )
{
@@ -144,7 +164,7 @@ public class ItemData
enchants.ensureCapacity( enchants.size() + rawEnchants.size() );
for( Map.Entry<Enchantment, Integer> entry : EnchantmentHelper.func_226652_a_( rawEnchants ).entrySet() )
for( Map.Entry<Enchantment, Integer> entry : EnchantmentHelper.deserializeEnchantments( rawEnchants ).entrySet() )
{
Enchantment enchantment = entry.getKey();
Integer level = entry.getValue();

View File

@@ -207,9 +207,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable
Direction facing = state.get( MODEM ).getFacing();
if( facing == null ) return true;
BlockPos offsetPos = pos.offset( facing );
BlockState offsetState = world.getBlockState( offsetPos );
return hasSolidSide( offsetState, world, offsetPos, facing.getOpposite() );
return hasEnoughSolidSide( world, pos.offset( facing ), facing.getOpposite() );
}
@Nullable

View File

@@ -217,8 +217,8 @@ public class TileWiredModemFull extends TileGeneric
StringTextComponent base = new StringTextComponent( "" );
for( int i = 0; i < names.size(); i++ )
{
if( i > 0 ) base.func_240702_b_( ", " );
base.func_230529_a_( CommandCopy.createCopyText( names.get( i ) ) );
if( i > 0 ) base.appendString( ", " );
base.append( CommandCopy.createCopyText( names.get( i ) ) );
}
player.sendStatusMessage( new TranslationTextComponent( kind, base ), false );

View File

@@ -80,12 +80,10 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable
@Override
@Deprecated
public boolean isValidPosition( BlockState state, IWorldReader world, BlockPos pos )
public boolean isValidPosition( BlockState state, @Nonnull IWorldReader world, BlockPos pos )
{
Direction facing = state.get( FACING );
BlockPos offsetPos = pos.offset( facing );
BlockState offsetState = world.getBlockState( offsetPos );
return hasSolidSide( offsetState, world, offsetPos, facing.getOpposite() );
return hasEnoughSolidSide( world, pos.offset( facing ), facing.getOpposite() );
}
@Nullable

View File

@@ -13,7 +13,6 @@ import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.DyeItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIntArray;
import net.minecraft.util.IntArray;
@@ -95,7 +94,7 @@ public class ContainerPrinter extends Container
else
{
// Transfer from inventory to printer
if( stack.getItem() instanceof DyeItem )
if( TilePrinter.isInk( stack ) )
{
if( !mergeItemStack( stack, 0, 1, false ) ) return ItemStack.EMPTY;
}

View File

@@ -300,9 +300,9 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
}
}
private static boolean isInk( @Nonnull ItemStack stack )
static boolean isInk( @Nonnull ItemStack stack )
{
return stack.getItem() instanceof DyeItem;
return ColourUtils.getStackColour( stack ) != null;
}
private static boolean isPaper( @Nonnull ItemStack stack )
@@ -321,7 +321,8 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
private boolean inputPage()
{
ItemStack inkStack = m_inventory.get( 0 );
if( !isInk( inkStack ) ) return false;
DyeColor dye = ColourUtils.getStackColour( inkStack );
if( dye == null ) return false;
for( int i = 1; i < 7; i++ )
{
@@ -329,8 +330,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
if( paperStack.isEmpty() || !isPaper( paperStack ) ) continue;
// Setup the new page
DyeColor dye = ColourUtils.getStackColour( inkStack );
m_page.setTextColour( dye != null ? dye.getId() : 15 );
m_page.setTextColour( dye.getId() );
m_page.clear();
if( paperStack.getItem() instanceof ItemPrintout )
@@ -403,7 +403,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
setInventorySlotContents( i, ItemStack.EMPTY );
// Spawn the item in the world
WorldUtil.dropItemStack( stack, getWorld(), Vector3d.func_237491_b_( getPos() ).add( 0.5, 0.75, 0.5 ) );
WorldUtil.dropItemStack( stack, getWorld(), Vector3d.copy( getPos() ).add( 0.5, 0.75, 0.5 ) );
}
}
}

View File

@@ -163,7 +163,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
if( entity != null )
{
setWorld( entity.getEntityWorld() );
setPosition( entity.func_233580_cy_() );
setPosition( entity.getPosition() );
}
// If a new entity has picked it up then rebroadcast the terminal to them

View File

@@ -190,7 +190,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
if( id >= 0 )
{
list.add( new TranslationTextComponent( "gui.computercraft.tooltip.computer_id", id )
.func_240699_a_( TextFormatting.GRAY ) );
.mergeStyle( TextFormatting.GRAY ) );
}
}
}

View File

@@ -71,7 +71,7 @@ public final class ComputerCraftProxyCommon
private static void registerCondition( String name, LootConditionType serializer )
{
Registry.register( Registry.field_239704_ba_, new ResourceLocation( ComputerCraft.MOD_ID, name ), serializer );
Registry.register( Registry.LOOT_CONDITION_TYPE, new ResourceLocation( ComputerCraft.MOD_ID, name ), serializer );
}
private static void registerProviders()

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

@@ -238,7 +238,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
cancelResult = hitEntity.applyPlayerInteraction( turtlePlayer, hitPos, Hand.MAIN_HAND );
}
if( cancelResult == ActionResultType.SUCCESS )
if( cancelResult.isSuccessOrConsume() )
{
placed = true;
}
@@ -246,7 +246,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
{
// See EntityPlayer.interactOn
cancelResult = ForgeHooks.onInteractEntity( turtlePlayer, hitEntity, Hand.MAIN_HAND );
if( cancelResult == ActionResultType.SUCCESS )
if( cancelResult != null && cancelResult.isSuccessOrConsume() )
{
placed = true;
}
@@ -353,17 +353,15 @@ public class TurtlePlaceCommand implements ITurtleCommand
TileEntity existingTile = turtle.getWorld().getTileEntity( position );
// See PlayerInteractionManager.processRightClickBlock
// TODO: ^ Check we're still consistent.
PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, Hand.MAIN_HAND, position, side );
if( !event.isCanceled() )
{
if( item.onItemUseFirst( stack, context ) == ActionResultType.SUCCESS )
if( item.onItemUseFirst( stack, context ).isSuccessOrConsume() )
{
placed = true;
turtlePlayer.loadInventory( stackCopy );
}
else if( event.getUseItem() != Event.Result.DENY &&
stackCopy.onItemUse( context ) == ActionResultType.SUCCESS )
else if( event.getUseItem() != Event.Result.DENY && stackCopy.onItemUse( context ).isSuccessOrConsume() )
{
placed = true;
turtlePlayer.loadInventory( stackCopy );
@@ -373,14 +371,14 @@ public class TurtlePlaceCommand implements ITurtleCommand
if( !placed && (item instanceof BucketItem || item instanceof BoatItem || item instanceof LilyPadItem || item instanceof GlassBottleItem) )
{
ActionResultType actionResult = ForgeHooks.onItemRightClick( turtlePlayer, Hand.MAIN_HAND );
if( actionResult == ActionResultType.SUCCESS )
if( actionResult != null && actionResult.isSuccessOrConsume() )
{
placed = true;
}
else if( actionResult == null )
{
ActionResult<ItemStack> result = stackCopy.useItemRightClick( turtle.getWorld(), turtlePlayer, Hand.MAIN_HAND );
if( result.getType() == ActionResultType.SUCCESS && !ItemStack.areItemStacksEqual( stack, result.getResult() ) )
if( result.getType().isSuccessOrConsume() && !ItemStack.areItemStacksEqual( stack, result.getResult() ) )
{
placed = true;
turtlePlayer.loadInventory( result.getResult() );

View File

@@ -25,6 +25,7 @@ import net.minecraft.tileentity.SignTileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.util.FakePlayer;
@@ -54,11 +55,10 @@ public final class TurtlePlayer extends FakePlayer
private void setState( ITurtleAccess turtle )
{
if( openContainer != null )
if( openContainer != container )
{
ComputerCraft.log.warn( "Turtle has open container ({})", openContainer );
openContainer.onContainerClosed( this );
openContainer = null;
closeContainer();
}
BlockPos position = turtle.getPosition();
@@ -129,6 +129,12 @@ public final class TurtlePlayer extends FakePlayer
return Registry.ModEntities.TURTLE_PLAYER.get();
}
@Override
public Vector3d getPositionVec()
{
return new Vector3d( getPosX(), getPosY(), getPosZ() );
}
@Override
public float getEyeHeight( @Nonnull Pose pose )
{

View File

@@ -149,7 +149,7 @@ public class TurtleTool extends AbstractTurtleUpgrade
boolean attacked = false;
if( !hitEntity.hitByEntity( turtlePlayer ) )
{
float damage = (float) turtlePlayer.func_233637_b_( Attributes.ATTACK_DAMAGE );
float damage = (float) turtlePlayer.getAttributeValue( Attributes.ATTACK_DAMAGE );
damage *= getDamageMultiplier();
if( damage > 0.0f )
{

View File

@@ -40,6 +40,8 @@ public final class ColourUtils
public static DyeColor getStackColour( ItemStack stack )
{
if( stack.isEmpty() ) return null;
for( int i = 0; i < DYES.length; i++ )
{
ITag<Item> dye = DYES[i];

View File

@@ -41,9 +41,7 @@ public final class DropConsumer
remainingDrops = new ArrayList<>();
dropEntity = entity;
dropWorld = entity.world;
dropBounds = new AxisAlignedBB( entity.func_233580_cy_() ).grow( 2, 2, 2 );
entity.captureDrops( new ArrayList<>() );
dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 );
}
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

@@ -65,11 +65,6 @@ public class FakeNetHandler extends ServerPlayNetHandler
{
}
@Override
public void handleRecipeBookUpdate( @Nonnull CRecipeInfoPacket packet )
{
}
@Override
public void handleSeenAdvancements( @Nonnull CSeenAdvancementsPacket packet )
{

View File

@@ -10,6 +10,7 @@ import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import dan200.computercraft.ComputerCraft;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.storage.FolderName;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
import java.io.File;
@@ -25,6 +26,7 @@ import java.util.Map;
public final class IDAssigner
{
private static final FolderName FOLDER = new FolderName( ComputerCraft.MOD_ID );
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final Type ID_TOKEN = new TypeToken<Map<String, Integer>>()
{
@@ -40,9 +42,7 @@ public final class IDAssigner
public static File getDir()
{
File root = ServerLifecycleHooks.getCurrentServer().getDataDirectory();
// TODO: File worldDirectory = server.getWorld( World.field_234918_g_ ).getSaveHandler().getWorldDirectory();
return new File( root, ComputerCraft.MOD_ID );
return ServerLifecycleHooks.getCurrentServer().func_240776_a_( FOLDER ).toFile();
}
private static MinecraftServer getCachedServer()

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

@@ -20,6 +20,6 @@ public final class RecordUtil
public static void playRecord( SoundEvent record, String recordInfo, World world, BlockPos pos )
{
NetworkMessage packet = record != null ? new PlayRecordClientMessage( pos, record, recordInfo ) : new PlayRecordClientMessage( pos );
NetworkHandler.sendToAllAround( packet, world, Vector3d.func_237489_a_( pos ), 64 );
NetworkHandler.sendToAllAround( packet, world, Vector3d.copyCentered( pos ), 64 );
}
}

View File

@@ -0,0 +1,63 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.util;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import net.minecraftforge.fml.ModList;
import org.objectweb.asm.Type;
import java.util.List;
import java.util.ServiceLoader;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public final class ServiceUtil
{
private static final Type AUTO_SERVICE = Type.getType( "Lcom/google/auto/service/AutoService;" );
private ServiceUtil()
{
}
public static <T> Stream<T> loadServices( Class<T> target )
{
return StreamSupport.stream( ServiceLoader.load( target, ServiceUtil.class.getClassLoader() ).spliterator(), false );
}
public static <T> Stream<T> loadServicesForge( Class<T> target )
{
Type type = Type.getType( target );
ClassLoader loader = ComputerCraftAPI.class.getClassLoader();
return ModList.get().getAllScanData().stream()
.flatMap( x -> x.getAnnotations().stream() )
.filter( x -> x.getAnnotationType().equals( AUTO_SERVICE ) )
.filter( x -> {
Object value = x.getAnnotationData().get( "value" );
return value instanceof List<?> && ((List<?>) value).contains( type );
} )
.flatMap( x -> {
try
{
Class<?> klass = loader.loadClass( x.getClassType().getClassName() );
if( !target.isAssignableFrom( klass ) )
{
ComputerCraft.log.error( "{} is not a subtype of {}", x.getClassType().getClassName(), target.getName() );
return Stream.empty();
}
Class<? extends T> casted = klass.asSubclass( target );
return Stream.of( casted.newInstance() );
}
catch( ReflectiveOperationException e )
{
ComputerCraft.log.error( "Cannot load {}", x.getClassType(), e );
return Stream.empty();
}
} );
}
}

View File

@@ -2,3 +2,6 @@
public net.minecraft.client.renderer.FirstPersonRenderer func_178100_c(F)F # getMapAngleFromPitch
public net.minecraft.client.renderer.FirstPersonRenderer func_228401_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;IFFLnet/minecraft/util/HandSide;)V # renderArmFirstPerson
public net.minecraft.client.renderer.FirstPersonRenderer func_228403_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;ILnet/minecraft/util/HandSide;)V # renderArm
# ClientTableFormatter
public net.minecraft.client.gui.NewChatGui func_146234_a(Lnet/minecraft/util/text/ITextComponent;I)V # printChatMessageWithOptionalDeletion
public net.minecraft.client.gui.NewChatGui func_146242_c(I)V # deleteChatLine

View File

@@ -1,5 +1,5 @@
modLoader="javafml"
loaderVersion="[32,33)"
loaderVersion="[34,35)"
issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues"
displayURL="https://github.com/SquidDev-CC/CC-Tweaked"
@@ -7,6 +7,7 @@ logoFile="pack.png"
credits="Created by Daniel Ratcliffe (@DanTwoHundred)"
authors="Daniel Ratcliffe, Aaron Mills, SquidDev"
license="ComputerCraft Public License (https://raw.githubusercontent.com/dan200/ComputerCraft/master/LICENSE)"
[[mods]]
modId="computercraft"
@@ -19,6 +20,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a
[[dependencies.computercraft]]
modId="forge"
mandatory=true
versionRange="[32.0.69,33)"
versionRange="[34.0.1,35)"
ordering="NONE"
side="BOTH"

View File

@@ -1,14 +1,14 @@
{
"block.computercraft.computer_normal": "Dator",
"block.computercraft.computer_advanced": "Avancerad Dator",
"block.computercraft.computer_command": "Kommando Dator",
"block.computercraft.computer_command": "Kommandodator",
"block.computercraft.disk_drive": "Diskettläsare",
"block.computercraft.printer": "Skrivare",
"block.computercraft.speaker": "Högtalare",
"block.computercraft.monitor_normal": "Skärm",
"block.computercraft.monitor_advanced": "Avancerad Skärm",
"block.computercraft.wireless_modem_normal": "Trådlöst Modem",
"block.computercraft.wireless_modem_advanced": "Ender Modem",
"block.computercraft.wireless_modem_advanced": "Endermodem",
"block.computercraft.wired_modem": "Trådat Modem",
"block.computercraft.cable": "Nätverkskabel",
"block.computercraft.wired_modem_full": "Trådat Modem",
@@ -38,5 +38,76 @@
"upgrade.computercraft.speaker.adjective": "Högljudd",
"chat.computercraft.wired_modem.peripheral_connected": "Kringutrustning \"%s\" är kopplad till nätverket",
"chat.computercraft.wired_modem.peripheral_disconnected": "Kringutrustning \"%s\" är frånkopplad från nätverket",
"gui.computercraft.tooltip.copy": "Kopiera till urklipp"
"gui.computercraft.tooltip.copy": "Kopiera till urklipp",
"gui.computercraft.tooltip.disk_id": "Diskett-ID: %s",
"gui.computercraft.tooltip.computer_id": "Dator-ID: %s",
"tracking_field.computercraft.coroutines_dead.name": "Coroutines borttagna",
"tracking_field.computercraft.coroutines_created.name": "Coroutines skapade",
"tracking_field.computercraft.websocket_outgoing.name": "Websocket utgående",
"tracking_field.computercraft.websocket_incoming.name": "Websocket ingående",
"tracking_field.computercraft.http_download.name": "HTTP-nedladdning",
"tracking_field.computercraft.http_upload.name": "HTTP-uppladdning",
"tracking_field.computercraft.http.name": "HTTP-förfrågningar",
"tracking_field.computercraft.turtle.name": "Turtle-operationer",
"tracking_field.computercraft.fs.name": "Filsystemoperationer",
"tracking_field.computercraft.peripheral.name": "Samtal till kringutrustning",
"tracking_field.computercraft.server_time.name": "Serveraktivitetstid",
"tracking_field.computercraft.server_count.name": "Antal serveruppgifter",
"tracking_field.computercraft.max.name": "Max tid",
"tracking_field.computercraft.average.name": "Genomsnittlig tid",
"tracking_field.computercraft.total.name": "Total tid",
"tracking_field.computercraft.tasks.name": "Uppgifter",
"argument.computercraft.argument_expected": "Argument förväntas",
"argument.computercraft.tracking_field.no_field": "Okänt fält '%s'",
"argument.computercraft.computer.many_matching": "Flera datorer matchar '%s' (%s träffar)",
"argument.computercraft.computer.no_matching": "Inga datorer matchar '%s'",
"commands.computercraft.generic.additional_rows": "%d ytterligare rader…",
"commands.computercraft.generic.exception": "Ohanterat felfall (%s)",
"commands.computercraft.generic.no": "N",
"commands.computercraft.generic.yes": "J",
"commands.computercraft.generic.position": "%s, %s, %s",
"commands.computercraft.generic.no_position": "<no pos>",
"commands.computercraft.queue.desc": "Skicka ett computer_command event till en kommandodator, skicka vidare ytterligare argument. Detta är mestadels utformat för kartmarkörer som fungerar som en mer datorvänlig version av /trigger. Alla spelare kan köra kommandot, vilket sannolikt skulle göras genom en textkomponents klick-event.",
"commands.computercraft.queue.synopsis": "Skicka ett computer_command event till en kommandodator",
"commands.computercraft.reload.done": "Konfiguration omladdad",
"commands.computercraft.reload.desc": "Ladda om ComputerCrafts konfigurationsfil",
"commands.computercraft.reload.synopsis": "Ladda om ComputerCrafts konfigurationsfil",
"commands.computercraft.track.dump.computer": "Dator",
"commands.computercraft.track.dump.no_timings": "Inga tidtagningar tillgängliga",
"commands.computercraft.track.dump.desc": "Dumpa de senaste resultaten av datorspårning.",
"commands.computercraft.track.dump.synopsis": "Dumpa de senaste spårningsresultaten",
"commands.computercraft.track.stop.not_enabled": "Spårar för tillfället inga datorer",
"commands.computercraft.track.stop.action": "Klicka för att stoppa spårning",
"commands.computercraft.track.stop.desc": "Stoppa spårning av alla datorers körtider och eventräkningar",
"commands.computercraft.track.stop.synopsis": "Stoppa spårning för alla datorer",
"commands.computercraft.track.start.stop": "Kör %s för att stoppa spårning och visa resultaten",
"commands.computercraft.track.start.desc": "Börja spåra alla dators körtider och eventräkningar. Detta kommer återställa resultaten från tidigare körningar.",
"commands.computercraft.track.start.synopsis": "Starta spårning för alla datorer",
"commands.computercraft.track.desc": "Spåra hur länge datorer exekverar, och även hur många event de hanterar. Detta presenterar information på liknande sätt som /forge track och kan vara användbart för att undersöka lagg.",
"commands.computercraft.track.synopsis": "Spåra körningstider för denna dator.",
"commands.computercraft.view.not_player": "Kan inte öppna terminalen för en ickespelare",
"commands.computercraft.view.action": "Titta på denna dator",
"commands.computercraft.view.desc": "Öppna datorns terminal för att möjligöra fjärrstyrning. Detta ger inte tillgång till turtlens inventory. Du kan ange en dators instans-id (t.ex. 123) eller dator-id (t.ex. #123).",
"commands.computercraft.view.synopsis": "Titta på datorns terminal.",
"commands.computercraft.tp.not_there": "Kan inte hitta datorn i världen",
"commands.computercraft.tp.not_player": "Kan inte öppna terminalen för en ickespelare",
"commands.computercraft.tp.action": "Teleportera till den här datorn",
"commands.computercraft.tp.desc": "Teleportera till datorns position. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").",
"commands.computercraft.tp.synopsis": "Teleportera till en specifik dator.",
"commands.computercraft.turn_on.done": "Startade %s/%s datorer",
"commands.computercraft.turn_on.desc": "Starta de listade datorerna eller alla om ingen anges. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").",
"commands.computercraft.turn_on.synopsis": "Starta på datorer på distans.",
"commands.computercraft.shutdown.done": "Stängde av %s/%s datorer",
"commands.computercraft.dump.desc": "Visa status för alla datorer eller specifik information för en dator. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").",
"commands.computercraft.shutdown.desc": "Stäng av de listade datorerna eller alla om ingen anges. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").",
"commands.computercraft.shutdown.synopsis": "Stäng av datorer på distans.",
"commands.computercraft.dump.action": "Visa mer information om den här datorn",
"commands.computercraft.dump.synopsis": "Visa status för datorer.",
"commands.computercraft.help.no_command": "Inget sådant kommando '%s'",
"commands.computercraft.help.no_children": "%s har inget underkommando",
"commands.computercraft.help.desc": "Visa detta hjälpmeddelande",
"commands.computercraft.help.synopsis": "Tillhandahåll hjälp för ett specifikt kommando",
"commands.computercraft.desc": "/computercraft kommandot tillhandahåller olika debugging- och administrationsverktyg för att kontrollera och interagera med datorer.",
"commands.computercraft.synopsis": "Olika kommandon för att kontrollera datorer.",
"itemGroup.computercraft": "ComputerCraft"
}

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

@@ -289,7 +289,7 @@ end
-- The `mode` string can be any of the following:
-- - **"r"**: Read mode
-- - **"w"**: Write mode
-- - **"w"**: Append mode
-- - **"a"**: Append mode
--
-- The mode may also have a `b` at the end, which opens the file in "binary
-- mode". This allows you to read binary files, as well as seek within a file.

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

@@ -440,7 +440,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
end
--- Get the buffered contents of a line in this window.
---
--
-- @tparam number y The y position of the line to get.
-- @treturn string The textual content of this line.
-- @treturn string The text colours of this line, suitable for use with @{term.blit}.

View File

@@ -1,3 +1,53 @@
# New features in CC: Tweaked 1.93.0
* Update Swedish translations (Granddave).
* Printers use item tags to check dyes.
* HTTP rules may now be targetted for a specific port.
* Don't propagate adjacent redstone signals through computers.
And several bug fixes:
* Fix NPEs when turtles interact with containers.
# 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 sheared by turtles.
# New features in CC: Tweaked 1.91.1
* Fix crash when turtles interact with an entity.
# 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)
* Update to 1.16.2
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)
* Fix turtles placing buckets multiple times.
# New features in CC: Tweaked 1.90.3
* Fix the selected slot indicator missing from the turtle GUI.
* Ensure we load/save computer data from the world directory, rather than a global one.
# New features in CC: Tweaked 1.90.2
* Fix generic peripherals not being registered outside a dev environment.
* Fix `turtle.attack()` failing.
* Correctly set styles for the output of `/computercraft` commands.
# New features in CC: Tweaked 1.90.1
* Update to Forge 32.0.69

View File

@@ -1,5 +1,11 @@
New features in CC: Tweaked 1.90.1
New features in CC: Tweaked 1.93.0
* Update to Forge 32.0.69
* Update Swedish translations (Granddave).
* Printers use item tags to check dyes.
* HTTP rules may now be targetted for a specific port.
* Don't propagate adjacent redstone signals through computers.
And several bug fixes:
* Fix NPEs when turtles interact with containers.
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

@@ -1,6 +1,6 @@
{
"pack": {
"pack_format": 4,
"pack_format": 6,
"description": "CC: Tweaked"
}
}

View File

@@ -0,0 +1,34 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.apis.http.options;
import org.junit.jupiter.api.Test;
import java.net.InetSocketAddress;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class AddressRuleTest
{
@Test
public void matchesPort()
{
Iterable<AddressRule> rules = Collections.singletonList( AddressRule.parse(
"127.0.0.1", 8080,
new PartialOptions( Action.ALLOW, null, null, null, null )
) );
assertEquals( apply( rules, "localhost", 8080 ).action, Action.ALLOW );
assertEquals( apply( rules, "localhost", 8081 ).action, Action.DENY );
}
private Options apply( Iterable<AddressRule> rules, String host, int port )
{
return AddressRule.apply( rules, host, new InetSocketAddress( host, port ) );
}
}

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)