mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-16 22:47:38 +00:00
Compare commits
69 Commits
v1.80pr1.5
...
v1.80pr1.8
Author | SHA1 | Date | |
---|---|---|---|
![]() |
efa57521c7 | ||
![]() |
4700f8831b | ||
![]() |
9428bee316 | ||
![]() |
89c7183a1d | ||
![]() |
d2a9e7e458 | ||
![]() |
1774f1a079 | ||
![]() |
de1307913b | ||
![]() |
093132533d | ||
![]() |
0685be6bfa | ||
![]() |
f40733e9a6 | ||
![]() |
a3d1cff298 | ||
![]() |
b8957cab5c | ||
![]() |
3ac8dde779 | ||
![]() |
17dace979a | ||
![]() |
d405316a4b | ||
![]() |
7e18f2cead | ||
![]() |
000786a1a7 | ||
![]() |
0bf13562b9 | ||
![]() |
45a189e834 | ||
![]() |
0ce6f34a09 | ||
![]() |
4d984dc5ee | ||
![]() |
984d358930 | ||
![]() |
a95893b823 | ||
![]() |
81aaead032 | ||
![]() |
a2083bcff1 | ||
![]() |
052f2a16dc | ||
![]() |
fd10ed6f62 | ||
![]() |
c0bdd4ff1d | ||
![]() |
5f0addbc3e | ||
![]() |
c9589ad0e7 | ||
![]() |
b21c495815 | ||
![]() |
18429c50f9 | ||
![]() |
7ec8ddcf7d | ||
![]() |
5bf9f9e3c5 | ||
![]() |
e4164ee9a1 | ||
![]() |
b522af3075 | ||
![]() |
8775052dee | ||
![]() |
c0c5d57e10 | ||
![]() |
4c2e97b1af | ||
![]() |
f17df15117 | ||
![]() |
bfbb18bdfc | ||
![]() |
cac65ef755 | ||
![]() |
a42793024b | ||
![]() |
7dbc4e6455 | ||
![]() |
a0d71cb3ad | ||
![]() |
83546d0acb | ||
![]() |
e2f9ddd534 | ||
![]() |
911e404bfa | ||
![]() |
bfeafe163f | ||
![]() |
6cf32f1f74 | ||
![]() |
04f162ef25 | ||
![]() |
b2aa390ae1 | ||
![]() |
6ca61f000f | ||
![]() |
20a47a7f88 | ||
![]() |
e2e6946c92 | ||
![]() |
abe917cd54 | ||
![]() |
a1d77ab8e7 | ||
![]() |
c8db671409 | ||
![]() |
52641b7bea | ||
![]() |
3e751ee94a | ||
![]() |
2b28cc3558 | ||
![]() |
f9761388b1 | ||
![]() |
d28694eb57 | ||
![]() |
d758895578 | ||
![]() |
043d5f00ca | ||
![]() |
36878e75b7 | ||
![]() |
914df8b0c7 | ||
![]() |
5eadf5533d | ||
![]() |
1ef7c8e8db |
16
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Report some misbehaviour in the mod
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
## Before reporting
|
||||||
|
- Search for the bug both here and [on the ComputerCraft issues page](https://github.com/dan200/ComputerCraft/issues?utf8=%E2%9C%93&q=is%3Aissue+)
|
||||||
|
- If possible, try to reproduce on vanilla ComputerCraft. If it still occurs, [report on the ComputerCraft repo](https://github.com/dan200/ComputerCraft/issues/new) instead.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Useful information to include:
|
||||||
|
- Minecraft version
|
||||||
|
- CC: Tweaked version
|
||||||
|
- Detailed reproduction steps!** Sometimes I can spot a bug pretty easily, but often it's much more obscure. Anything you can give which will help reproduce it means it'll get fixed quicker.
|
15
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
15
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea or improvement
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
## Before reporting
|
||||||
|
- Search for the suggestion both here and [on the ComputerCraft issues page](https://github.com/dan200/ComputerCraft/issues?utf8=%E2%9C%93&q=is%3Aissue+). It's possible someone's suggested it before!
|
||||||
|
- Unless something is specific to CC:Tweaked, try to [suggest them on the ComputerCraft repo](https://github.com/dan200/ComputerCraft/issues/new). There's a lot more people watching it, so it allows the wider community to contribute.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Useful information to include:
|
||||||
|
- Explanation of how the feature/change chould work.
|
||||||
|
- Some rationale/use case for a feature. I'd like to keep CC:T as minimal
|
9
.github/pull_request_template.md
vendored
Normal file
9
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<!--
|
||||||
|
Unless this feature is specific to CC:Tweaked, try to [target the original ComputerCraft repo](https://github.com/dan200/ComputerCraft/) instead. There's a lot more people watching it, so it allows the wider community to contribute.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Useful information to include:
|
||||||
|
- Brief explanation of the changes you've made.
|
||||||
|
- Rationale of why this change has been made/reasoning behind it.
|
||||||
|
|
||||||
|
The more information you can provide, the easier it is to review something now _and_ to see why a change was made, when the code needs updating in the future.
|
36
README.md
36
README.md
@@ -6,26 +6,42 @@ features of the mod. For a more stable experience, I recommend checking out the
|
|||||||
[original mod](https://github.com/dan200/ComputerCraft).
|
[original mod](https://github.com/dan200/ComputerCraft).
|
||||||
|
|
||||||
## What?
|
## What?
|
||||||
CC: Tweaked does not aim to create a competing fork of ComputerCraft, nor am I planning to take it in in a vastly
|
CC: Tweaked (or CC:T for short) does not aim to create a competing fork of ComputerCraft, nor am I planning to take it
|
||||||
different direction to the original mod. In fact, CC: Tweaked aims to be a nurturing ground for various features, with
|
in in a vastly different direction to the original mod. In fact, CC:T aims to be a nurturing ground for various
|
||||||
a pull request against the original mod being the end goal.
|
features, with a pull request against the original mod being the end goal.
|
||||||
|
|
||||||
CC: Tweaked also includes many pull requests from the community which have not yet been merged, offering a large number
|
CC:T also includes many pull requests from the community which have not yet been merged, offering a large number
|
||||||
of additional bug fixes and features over the original mod.
|
of additional bug fixes and features over the original mod.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
CC: Tweaked contains the all features of the latest alpha, as well as numerous fixes, performance improvements and
|
||||||
|
several additional features. I'd recommend checking out [the releases page](https://github.com/SquidDev-CC/CC-Tweaked/releases)
|
||||||
|
to see the full changes, but here's a couple of the more interesting changes:
|
||||||
|
|
||||||
|
- Replace LuaJ with Cobalt.
|
||||||
|
- Allow running multiple computers at the same time.
|
||||||
|
- Websocket support in the HTTP library.
|
||||||
|
- Wired modems and cables act more like multiparts.
|
||||||
|
- Add map-like rendering for pocket computers and printed pages/books.
|
||||||
|
- Adds the `/computercraft` command, offering various diagnostic tools for server owners. This allows operators to
|
||||||
|
track which computers are hogging resources, turn on and shutdown multiple computers at once and interact with
|
||||||
|
computers remotely.
|
||||||
|
- Add full-block wired modems, allowing one to wrap non-solid peripherals (such as turtles, or chests if Plethora is
|
||||||
|
installed).
|
||||||
|
|
||||||
## Relation to CCTweaks?
|
## Relation to CCTweaks?
|
||||||
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. However, I do plan
|
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. That being said,
|
||||||
to migrate some features of CCTweaks into CC: Tweaked.
|
several features have been included, such as full block modems, the Cobalt runtime and map-like rendering for pocket
|
||||||
|
computers.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you do wish to contribute
|
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you do wish to contribute
|
||||||
code, do consider submitting it to the ComputerCraft repository instead.
|
code, do consider submitting it to the ComputerCraft repository instead.
|
||||||
|
|
||||||
That being said, in order to start helping develop CC: Tweaked, you'll need to follow these steps:
|
That being said, in order to start helping develop CC:T, you'll need to follow these steps:
|
||||||
|
|
||||||
- **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked`
|
- **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked`
|
||||||
- **Setup Forge:** `./gradlew setupDecompWorkspace`
|
- **Setup Forge:** `./gradlew setupDecompWorkspace`
|
||||||
- **Test your changes:** `./gradlew runClient` (or run the `GradleStart` class from your IDE).
|
- **Test your changes:** `./gradlew runClient` (or run the `GradleStart` class from your IDE).
|
||||||
|
|
||||||
If you want to run CC: Tweaked in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from
|
If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`.
|
||||||
`build/libs`.
|
|
||||||
|
77
build.gradle
77
build.gradle
@@ -15,18 +15,20 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.matthewprenger.cursegradle' version '1.0.9'
|
id 'com.matthewprenger.cursegradle' version '1.0.10'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'net.minecraftforge.gradle.forge'
|
apply plugin: 'net.minecraftforge.gradle.forge'
|
||||||
apply plugin: 'org.ajoberstar.grgit'
|
apply plugin: 'org.ajoberstar.grgit'
|
||||||
|
apply plugin: 'maven-publish'
|
||||||
|
apply plugin: 'maven'
|
||||||
|
|
||||||
version = "1.80pr1.5"
|
version = "1.80pr1.8"
|
||||||
group = "org.squiddev"
|
group = "org.squiddev"
|
||||||
archivesBaseName = "cc-tweaked"
|
archivesBaseName = "cc-tweaked"
|
||||||
|
|
||||||
minecraft {
|
minecraft {
|
||||||
version = "1.12-14.21.1.2387"
|
version = "1.12.2-14.23.4.2749"
|
||||||
runDir = "run"
|
runDir = "run"
|
||||||
replace '${version}', project.version
|
replace '${version}', project.version
|
||||||
|
|
||||||
@@ -35,7 +37,7 @@ minecraft {
|
|||||||
// stable_# stables are built at the discretion of the MCP team.
|
// stable_# stables are built at the discretion of the MCP team.
|
||||||
// Use non-default mappings at your own risk. they may not allways work.
|
// Use non-default mappings at your own risk. they may not allways work.
|
||||||
// simply re-run your setup task after changing the mappings to update your workspace.
|
// simply re-run your setup task after changing the mappings to update your workspace.
|
||||||
mappings = "snapshot_20170629"
|
mappings = "snapshot_20180724"
|
||||||
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
|
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,19 +50,27 @@ repositories {
|
|||||||
name = "squiddev"
|
name = "squiddev"
|
||||||
url = "https://dl.bintray.com/squiddev/maven"
|
url = "https://dl.bintray.com/squiddev/maven"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ivy { artifactPattern "https://asie.pl/files/mods/Charset/LibOnly/[module]-[revision](-[classifier]).[ext]" }
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
shade
|
shade
|
||||||
compile.extendsFrom shade
|
compile.extendsFrom shade
|
||||||
|
deployerJars
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
deobfProvided "mezz.jei:jei_1.12:4.7.5.86:api"
|
deobfProvided "mezz.jei:jei_1.12.2:4.8.5.159:api"
|
||||||
runtime "mezz.jei:jei_1.12:4.7.5.86"
|
deobfProvided "pl.asie:Charset-Lib:0.5.4.6"
|
||||||
shade 'org.squiddev:Cobalt:0.3.1'
|
|
||||||
|
runtime "mezz.jei:jei_1.12.2:4.8.5.159"
|
||||||
|
|
||||||
|
shade 'org.squiddev:Cobalt:0.3.2'
|
||||||
|
|
||||||
testCompile 'junit:junit:4.11'
|
testCompile 'junit:junit:4.11'
|
||||||
|
|
||||||
|
deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
javadoc {
|
javadoc {
|
||||||
@@ -125,6 +135,59 @@ curseforge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
mavenJava(MavenPublication) {
|
||||||
|
from components.java
|
||||||
|
artifact sourceJar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadArchives {
|
||||||
|
repositories {
|
||||||
|
if(project.hasProperty('mavenUploadUrl')) {
|
||||||
|
mavenDeployer {
|
||||||
|
configuration = configurations.deployerJars
|
||||||
|
|
||||||
|
repository(url: project.property('mavenUploadUrl')) {
|
||||||
|
authentication(
|
||||||
|
userName: project.property('mavenUploadUser'),
|
||||||
|
privateKey: project.property('mavenUploadKey'))
|
||||||
|
}
|
||||||
|
|
||||||
|
pom.project {
|
||||||
|
name 'CC: Tweaked'
|
||||||
|
packaging 'jar'
|
||||||
|
description 'A fork of ComputerCraft which aims to provide earlier access to the more experimental and in-development features of the mod.'
|
||||||
|
url 'https://github.com/SquidDev-CC/CC-Tweaked'
|
||||||
|
|
||||||
|
scm {
|
||||||
|
url 'https://github.com/dan200/ComputerCraft.git'
|
||||||
|
}
|
||||||
|
|
||||||
|
issueManagement {
|
||||||
|
system 'github'
|
||||||
|
url 'https://github.com/dan200/ComputerCraft/issues'
|
||||||
|
}
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name 'ComputerCraft Public License, Version 1.0'
|
||||||
|
url 'https://github.com/dan200/ComputerCraft/blob/master/LICENSE'
|
||||||
|
distribution 'repo'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pom.whenConfigured { pom ->
|
||||||
|
pom.dependencies.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gradle.projectsEvaluated {
|
gradle.projectsEvaluated {
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
options.compilerArgs << "-Xlint"
|
options.compilerArgs << "-Xlint"
|
||||||
|
1
settings.gradle
Normal file
1
settings.gradle
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = 'cc-tweaked'
|
@@ -16,7 +16,6 @@ import dan200.computercraft.api.media.IMediaProvider;
|
|||||||
import dan200.computercraft.api.network.IPacketNetwork;
|
import dan200.computercraft.api.network.IPacketNetwork;
|
||||||
import dan200.computercraft.api.network.wired.IWiredElement;
|
import dan200.computercraft.api.network.wired.IWiredElement;
|
||||||
import dan200.computercraft.api.network.wired.IWiredNode;
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||||
import dan200.computercraft.api.network.wired.IWiredProvider;
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
||||||
import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
|
import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
|
||||||
@@ -29,6 +28,7 @@ import dan200.computercraft.core.filesystem.ComboMount;
|
|||||||
import dan200.computercraft.core.filesystem.FileMount;
|
import dan200.computercraft.core.filesystem.FileMount;
|
||||||
import dan200.computercraft.core.filesystem.JarMount;
|
import dan200.computercraft.core.filesystem.JarMount;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
|
import dan200.computercraft.core.tracking.Tracking;
|
||||||
import dan200.computercraft.shared.command.CommandComputer;
|
import dan200.computercraft.shared.command.CommandComputer;
|
||||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||||
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
|
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
|
||||||
@@ -61,6 +61,7 @@ import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
|
|||||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||||
import dan200.computercraft.shared.turtle.upgrades.*;
|
import dan200.computercraft.shared.turtle.upgrades.*;
|
||||||
import dan200.computercraft.shared.util.*;
|
import dan200.computercraft.shared.util.*;
|
||||||
|
import dan200.computercraft.shared.wired.CapabilityWiredElement;
|
||||||
import dan200.computercraft.shared.wired.WiredNode;
|
import dan200.computercraft.shared.wired.WiredNode;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
@@ -69,6 +70,7 @@ import net.minecraft.entity.player.EntityPlayerMP;
|
|||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.network.PacketBuffer;
|
import net.minecraft.network.PacketBuffer;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.util.NonNullList;
|
import net.minecraft.util.NonNullList;
|
||||||
@@ -96,6 +98,7 @@ import java.net.MalformedURLException;
|
|||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
@@ -266,7 +269,6 @@ public class ComputerCraft
|
|||||||
private static List<ITurtlePermissionProvider> permissionProviders = new ArrayList<>();
|
private static List<ITurtlePermissionProvider> permissionProviders = new ArrayList<>();
|
||||||
private static final Map<String, IPocketUpgrade> pocketUpgrades = new HashMap<>();
|
private static final Map<String, IPocketUpgrade> pocketUpgrades = new HashMap<>();
|
||||||
private static final Set<ILuaAPIFactory> apiFactories = new LinkedHashSet<>();
|
private static final Set<ILuaAPIFactory> apiFactories = new LinkedHashSet<>();
|
||||||
private static final Set<IWiredProvider> wiredProviders = new LinkedHashSet<>();
|
|
||||||
|
|
||||||
// Implementation
|
// Implementation
|
||||||
@Mod.Instance( value = ComputerCraft.MOD_ID )
|
@Mod.Instance( value = ComputerCraft.MOD_ID )
|
||||||
@@ -461,8 +463,7 @@ public class ComputerCraft
|
|||||||
@Mod.EventHandler
|
@Mod.EventHandler
|
||||||
public void onServerStarting( FMLServerStartingEvent event )
|
public void onServerStarting( FMLServerStartingEvent event )
|
||||||
{
|
{
|
||||||
event.registerServerCommand( new CommandComputer() );
|
proxy.initServer( event.getServer() );
|
||||||
event.registerServerCommand( new CommandComputerCraft() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mod.EventHandler
|
@Mod.EventHandler
|
||||||
@@ -472,6 +473,7 @@ public class ComputerCraft
|
|||||||
{
|
{
|
||||||
ComputerCraft.serverComputerRegistry.reset();
|
ComputerCraft.serverComputerRegistry.reset();
|
||||||
WirelessNetwork.resetNetworks();
|
WirelessNetwork.resetNetworks();
|
||||||
|
Tracking.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,6 +484,7 @@ public class ComputerCraft
|
|||||||
{
|
{
|
||||||
ComputerCraft.serverComputerRegistry.reset();
|
ComputerCraft.serverComputerRegistry.reset();
|
||||||
WirelessNetwork.resetNetworks();
|
WirelessNetwork.resetNetworks();
|
||||||
|
Tracking.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,11 +736,6 @@ public class ComputerCraft
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerWiredProvider( IWiredProvider provider )
|
|
||||||
{
|
|
||||||
if( provider != null ) wiredProviders.add( provider );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IWiredNode createWiredNodeForElement( IWiredElement element )
|
public static IWiredNode createWiredNodeForElement( IWiredElement element )
|
||||||
{
|
{
|
||||||
return new WiredNode( element );
|
return new WiredNode( element );
|
||||||
@@ -766,20 +764,10 @@ public class ComputerCraft
|
|||||||
|
|
||||||
public static IWiredElement getWiredElementAt( IBlockAccess world, BlockPos pos, EnumFacing side )
|
public static IWiredElement getWiredElementAt( IBlockAccess world, BlockPos pos, EnumFacing side )
|
||||||
{
|
{
|
||||||
// Try the handlers in order:
|
TileEntity tile = world.getTileEntity( pos );
|
||||||
for( IWiredProvider provider : wiredProviders )
|
return tile != null && tile.hasCapability( CapabilityWiredElement.CAPABILITY, side )
|
||||||
{
|
? tile.getCapability( CapabilityWiredElement.CAPABILITY, side )
|
||||||
try
|
: null;
|
||||||
{
|
|
||||||
IWiredElement element = provider.getElement( world, pos, side );
|
|
||||||
if( element != null ) return element;
|
|
||||||
}
|
|
||||||
catch( Exception e )
|
|
||||||
{
|
|
||||||
ComputerCraft.log.error( "Wired element provider " + provider + " errored.", e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side )
|
public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side )
|
||||||
@@ -1137,13 +1125,18 @@ public class ComputerCraft
|
|||||||
turtleProxy.addAllUpgradedTurtles( list );
|
turtleProxy.addAllUpgradedTurtles( list );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer )
|
public static void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer )
|
||||||
{
|
{
|
||||||
turtleProxy.setEntityDropConsumer( entity, consumer );
|
turtleProxy.setDropConsumer( entity, consumer );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clearEntityDropConsumer( Entity entity )
|
public static void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer )
|
||||||
{
|
{
|
||||||
turtleProxy.clearEntityDropConsumer( entity );
|
turtleProxy.setDropConsumer( world, pos, consumer );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ItemStack> clearDropConsumer( )
|
||||||
|
{
|
||||||
|
return turtleProxy.clearDropConsumer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,6 @@ import dan200.computercraft.api.media.IMediaProvider;
|
|||||||
import dan200.computercraft.api.network.IPacketNetwork;
|
import dan200.computercraft.api.network.IPacketNetwork;
|
||||||
import dan200.computercraft.api.network.wired.IWiredElement;
|
import dan200.computercraft.api.network.wired.IWiredElement;
|
||||||
import dan200.computercraft.api.network.wired.IWiredNode;
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||||
import dan200.computercraft.api.network.wired.IWiredProvider;
|
|
||||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
||||||
@@ -332,26 +331,6 @@ public final class ComputerCraftAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a peripheral handler to convert blocks into {@link IPeripheral} implementations.
|
|
||||||
*
|
|
||||||
* @param handler The peripheral provider to register.
|
|
||||||
* @see dan200.computercraft.api.peripheral.IPeripheral
|
|
||||||
* @see dan200.computercraft.api.peripheral.IPeripheralProvider
|
|
||||||
*/
|
|
||||||
public static void registerWiredProvider( @Nonnull IWiredProvider handler )
|
|
||||||
{
|
|
||||||
findCC();
|
|
||||||
if ( computerCraft_registerWiredProvider != null)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
computerCraft_registerWiredProvider.invoke( null, handler );
|
|
||||||
} catch (Exception e){
|
|
||||||
// It failed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new wired node for a given wired element
|
* Construct a new wired node for a given wired element
|
||||||
*
|
*
|
||||||
@@ -453,9 +432,6 @@ public final class ComputerCraftAPI
|
|||||||
computerCraft_registerAPIFactory = findCCMethod( "registerAPIFactory", new Class<?>[] {
|
computerCraft_registerAPIFactory = findCCMethod( "registerAPIFactory", new Class<?>[] {
|
||||||
ILuaAPIFactory.class
|
ILuaAPIFactory.class
|
||||||
} );
|
} );
|
||||||
computerCraft_registerWiredProvider = findCCMethod( "registerWiredProvider", new Class<?>[] {
|
|
||||||
IWiredProvider.class
|
|
||||||
} );
|
|
||||||
computerCraft_createWiredNodeForElement = findCCMethod( "createWiredNodeForElement", new Class<?>[] {
|
computerCraft_createWiredNodeForElement = findCCMethod( "createWiredNodeForElement", new Class<?>[] {
|
||||||
IWiredElement.class
|
IWiredElement.class
|
||||||
} );
|
} );
|
||||||
@@ -499,7 +475,6 @@ public final class ComputerCraftAPI
|
|||||||
private static Method computerCraft_registerPocketUpgrade = null;
|
private static Method computerCraft_registerPocketUpgrade = null;
|
||||||
private static Method computerCraft_getWirelessNetwork = null;
|
private static Method computerCraft_getWirelessNetwork = null;
|
||||||
private static Method computerCraft_registerAPIFactory = null;
|
private static Method computerCraft_registerAPIFactory = null;
|
||||||
private static Method computerCraft_registerWiredProvider = null;
|
|
||||||
private static Method computerCraft_createWiredNodeForElement = null;
|
private static Method computerCraft_createWiredNodeForElement = null;
|
||||||
private static Method computerCraft_getWiredElementAt = null;
|
private static Method computerCraft_getWiredElementAt = null;
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,8 @@
|
|||||||
package dan200.computercraft.api.network.wired;
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object which may be part of a wired network.
|
* An object which may be part of a wired network.
|
||||||
@@ -14,30 +11,11 @@ import java.util.Map;
|
|||||||
* as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant
|
* as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant
|
||||||
* for its lifespan.
|
* for its lifespan.
|
||||||
*
|
*
|
||||||
* Elements are generally tied to a block or tile entity in world. One should either register an {@link IWiredProvider}
|
* Elements are generally tied to a block or tile entity in world. In such as case, one should provide the
|
||||||
* or implement {@link IWiredElementTile} on your tile entity.
|
* {@link IWiredElement} capability for the appropriate sides.
|
||||||
*
|
|
||||||
* @see IWiredProvider
|
|
||||||
* @see ComputerCraftAPI#registerWiredProvider(IWiredProvider)
|
|
||||||
* @see IWiredElementTile
|
|
||||||
*/
|
*/
|
||||||
public interface IWiredElement extends IWiredSender
|
public interface IWiredElement extends IWiredSender
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Fetch the peripherals this network element provides.
|
|
||||||
*
|
|
||||||
* This is only called when initially attaching to a network and after a call to {@link IWiredNode#invalidate()}}, so
|
|
||||||
* one does not <em>need</em> to cache the return value.
|
|
||||||
*
|
|
||||||
* @return The peripherals this node provides.
|
|
||||||
* @see IWiredNode#invalidate()
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
default Map<String, IPeripheral> getPeripherals()
|
|
||||||
{
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when objects on the network change. This may occur when network nodes are added or removed, or when
|
* Called when objects on the network change. This may occur when network nodes are added or removed, or when
|
||||||
* peripherals change.
|
* peripherals change.
|
||||||
|
@@ -1,22 +0,0 @@
|
|||||||
package dan200.computercraft.api.network.wired;
|
|
||||||
|
|
||||||
import net.minecraft.util.EnumFacing;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link net.minecraft.tileentity.TileEntity} which provides a {@link IWiredElement}. This acts
|
|
||||||
* as a simpler alternative to a full-blown {@link IWiredProvider}.
|
|
||||||
*/
|
|
||||||
public interface IWiredElementTile
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the wired element of this tile for a given side.
|
|
||||||
*
|
|
||||||
* @param side The side to get the network element from.
|
|
||||||
* @return A network element, or {@code null} if there is no element here.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
IWiredElement getWiredElement( @Nonnull EnumFacing side );
|
|
||||||
}
|
|
@@ -1,6 +1,9 @@
|
|||||||
package dan200.computercraft.api.network.wired;
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series
|
* A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series
|
||||||
@@ -51,7 +54,8 @@ public interface IWiredNetwork
|
|||||||
/**
|
/**
|
||||||
* Sever all connections this node has, removing it from this network.
|
* Sever all connections this node has, removing it from this network.
|
||||||
*
|
*
|
||||||
* This should only be used on the server thread.
|
* This should only be used on the server thread. You should only call this on nodes
|
||||||
|
* that your network element owns.
|
||||||
*
|
*
|
||||||
* @param node The node to remove
|
* @param node The node to remove
|
||||||
* @return Whether this node was removed from the network. One cannot remove a node from a network where it is the
|
* @return Whether this node was removed from the network. One cannot remove a node from a network where it is the
|
||||||
@@ -62,13 +66,15 @@ public interface IWiredNetwork
|
|||||||
boolean remove( @Nonnull IWiredNode node );
|
boolean remove( @Nonnull IWiredNode node );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark this node's peripherals as having changed.
|
* Update the peripherals a node provides.
|
||||||
*
|
*
|
||||||
* This should only be used on the server thread.
|
* This should only be used on the server thread. You should only call this on nodes
|
||||||
|
* that your network element owns.
|
||||||
*
|
*
|
||||||
* @param node The node to mark as invalid.
|
* @param node The node to attach peripherals for.
|
||||||
|
* @param peripherals The new peripherals for this node.
|
||||||
* @throws IllegalArgumentException If the node is not in the network.
|
* @throws IllegalArgumentException If the node is not in the network.
|
||||||
* @see IWiredElement#getPeripherals()
|
* @see IWiredNode#updatePeripherals(Map)
|
||||||
*/
|
*/
|
||||||
void invalidate( @Nonnull IWiredNode node );
|
void updatePeripherals( @Nonnull IWiredNode node, @Nonnull Map<String, IPeripheral> peripherals );
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
package dan200.computercraft.api.network.wired;
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
import dan200.computercraft.api.network.IPacketNetwork;
|
import dan200.computercraft.api.network.IPacketNetwork;
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wired nodes act as a layer between {@link IWiredElement}s and {@link IWiredNetwork}s.
|
* Wired nodes act as a layer between {@link IWiredElement}s and {@link IWiredNetwork}s.
|
||||||
@@ -72,7 +74,8 @@ public interface IWiredNode extends IPacketNetwork
|
|||||||
/**
|
/**
|
||||||
* Sever all connections this node has, removing it from this network.
|
* Sever all connections this node has, removing it from this network.
|
||||||
*
|
*
|
||||||
* This should only be used on the server thread.
|
* This should only be used on the server thread. You should only call this on nodes
|
||||||
|
* that your network element owns.
|
||||||
*
|
*
|
||||||
* @return Whether this node was removed from the network. One cannot remove a node from a network where it is the
|
* @return Whether this node was removed from the network. One cannot remove a node from a network where it is the
|
||||||
* only element.
|
* only element.
|
||||||
@@ -87,12 +90,14 @@ public interface IWiredNode extends IPacketNetwork
|
|||||||
/**
|
/**
|
||||||
* Mark this node's peripherals as having changed.
|
* Mark this node's peripherals as having changed.
|
||||||
*
|
*
|
||||||
* This should only be used on the server thread.
|
* This should only be used on the server thread. You should only call this on nodes
|
||||||
|
* that your network element owns.
|
||||||
*
|
*
|
||||||
* @see IWiredElement#getPeripherals()
|
* @param peripherals The new peripherals for this node.
|
||||||
|
* @see IWiredNetwork#updatePeripherals(IWiredNode, Map)
|
||||||
*/
|
*/
|
||||||
default void invalidate()
|
default void updatePeripherals( @Nonnull Map<String, IPeripheral> peripherals )
|
||||||
{
|
{
|
||||||
getNetwork().invalidate( this );
|
getNetwork().updatePeripherals( this, peripherals );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,29 +0,0 @@
|
|||||||
package dan200.computercraft.api.network.wired;
|
|
||||||
|
|
||||||
import net.minecraft.util.EnumFacing;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.world.IBlockAccess;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch or create an {@link IWiredElement} for a block at a given position.
|
|
||||||
*
|
|
||||||
* @see dan200.computercraft.api.ComputerCraftAPI#registerWiredProvider(IWiredProvider)
|
|
||||||
* @see IWiredElementTile
|
|
||||||
*/
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface IWiredProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Extract a wired network element from a block location.
|
|
||||||
*
|
|
||||||
* @param world The world the block is in.
|
|
||||||
* @param pos The position the block is at.
|
|
||||||
* @param side The side to get the network element from.
|
|
||||||
* @return A network element, or {@code null} if there is not an element here you'd like to handle.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
IWiredElement getElement( @Nonnull IBlockAccess world, @Nonnull BlockPos pos, @Nonnull EnumFacing side );
|
|
||||||
}
|
|
@@ -6,25 +6,19 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
|
||||||
import dan200.computercraft.core.terminal.TextBuffer;
|
import dan200.computercraft.core.terminal.TextBuffer;
|
||||||
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
|
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
|
||||||
import dan200.computercraft.shared.media.items.ItemPrintout;
|
import dan200.computercraft.shared.media.items.ItemPrintout;
|
||||||
import dan200.computercraft.shared.util.Palette;
|
|
||||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
import org.lwjgl.input.Mouse;
|
import org.lwjgl.input.Mouse;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static dan200.computercraft.client.render.PrintoutRenderer.*;
|
||||||
|
|
||||||
public class GuiPrintout extends GuiContainer
|
public class GuiPrintout extends GuiContainer
|
||||||
{
|
{
|
||||||
private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/printout.png" );
|
|
||||||
|
|
||||||
private static final int xSize = 172;
|
|
||||||
private static final int ySize = 209;
|
|
||||||
|
|
||||||
private final boolean m_book;
|
private final boolean m_book;
|
||||||
private final int m_pages;
|
private final int m_pages;
|
||||||
private final TextBuffer[] m_text;
|
private final TextBuffer[] m_text;
|
||||||
@@ -34,23 +28,18 @@ public class GuiPrintout extends GuiContainer
|
|||||||
public GuiPrintout( ContainerHeldItem container )
|
public GuiPrintout( ContainerHeldItem container )
|
||||||
{
|
{
|
||||||
super( container );
|
super( container );
|
||||||
m_book = (ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book);
|
|
||||||
|
|
||||||
String[] text = ItemPrintout.getText( container.getStack() );
|
String[] text = ItemPrintout.getText( container.getStack() );
|
||||||
m_text = new TextBuffer[ text.length ];
|
m_text = new TextBuffer[ text.length ];
|
||||||
for( int i=0; i<m_text.length; ++i )
|
for( int i = 0; i < m_text.length; ++i ) m_text[ i ] = new TextBuffer( text[ i ] );
|
||||||
{
|
|
||||||
m_text[i] = new TextBuffer( text[i] );
|
|
||||||
}
|
|
||||||
String[] colours = ItemPrintout.getColours( container.getStack() );
|
String[] colours = ItemPrintout.getColours( container.getStack() );
|
||||||
m_colours = new TextBuffer[ colours.length ];
|
m_colours = new TextBuffer[ colours.length ];
|
||||||
for( int i=0; i<m_colours.length; ++i )
|
for( int i = 0; i < m_colours.length; ++i ) m_colours[ i ] = new TextBuffer( colours[ i ] );
|
||||||
{
|
|
||||||
m_colours[i] = new TextBuffer( colours[i] );
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 );
|
|
||||||
m_page = 0;
|
m_page = 0;
|
||||||
|
m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 );
|
||||||
|
m_book = ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -78,25 +67,19 @@ public class GuiPrintout extends GuiContainer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void keyTyped(char c, int k) throws IOException
|
protected void keyTyped( char c, int k ) throws IOException
|
||||||
{
|
{
|
||||||
super.keyTyped( c, k );
|
super.keyTyped( c, k );
|
||||||
|
|
||||||
if( k == 205 )
|
if( k == 205 )
|
||||||
{
|
{
|
||||||
// Right
|
// Right
|
||||||
if( m_page < m_pages - 1 )
|
if( m_page < m_pages - 1 ) m_page++;
|
||||||
{
|
|
||||||
m_page = m_page + 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if( k == 203 )
|
else if( k == 203 )
|
||||||
{
|
{
|
||||||
// Left
|
// Left
|
||||||
if( m_page > 0 )
|
if( m_page > 0 ) m_page--;
|
||||||
{
|
|
||||||
m_page = m_page - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,21 +89,15 @@ public class GuiPrintout extends GuiContainer
|
|||||||
super.handleMouseInput();
|
super.handleMouseInput();
|
||||||
|
|
||||||
int mouseWheelChange = Mouse.getEventDWheel();
|
int mouseWheelChange = Mouse.getEventDWheel();
|
||||||
if (mouseWheelChange < 0)
|
if( mouseWheelChange < 0 )
|
||||||
{
|
{
|
||||||
// Up
|
// Up
|
||||||
if( m_page < m_pages - 1 )
|
if( m_page < m_pages - 1 ) m_page++;
|
||||||
{
|
|
||||||
m_page = m_page + 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (mouseWheelChange > 0)
|
else if( mouseWheelChange > 0 )
|
||||||
{
|
{
|
||||||
// Down
|
// Down
|
||||||
if( m_page > 0 )
|
if( m_page > 0 ) m_page--;
|
||||||
{
|
|
||||||
m_page = m_page - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,78 +112,20 @@ public class GuiPrintout extends GuiContainer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawScreen(int mouseX, int mouseY, float f)
|
public void drawScreen( int mouseX, int mouseY, float f )
|
||||||
{
|
{
|
||||||
// Draw background
|
// Draw background
|
||||||
|
zLevel = zLevel - 1;
|
||||||
drawDefaultBackground();
|
drawDefaultBackground();
|
||||||
|
zLevel = zLevel + 1;
|
||||||
|
|
||||||
// Draw the printout
|
// Draw the printout
|
||||||
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
|
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||||
this.mc.getTextureManager().bindTexture( background );
|
|
||||||
|
|
||||||
int startY = (height - ySize) / 2;
|
|
||||||
//int startX = (width - xSize) / 2 - (m_page * 8);
|
|
||||||
int startX = (width - (xSize + (m_pages - 1)*8)) / 2;
|
|
||||||
|
|
||||||
if( m_book )
|
|
||||||
{
|
|
||||||
// Border
|
|
||||||
drawTexturedModalRect( startX - 8, startY - 8, xSize + 48, 0, 12, ySize + 24);
|
|
||||||
drawTexturedModalRect( startX + xSize + (m_pages - 1)*8 - 4, startY - 8, xSize + 48 + 12, 0, 12, ySize + 24);
|
|
||||||
|
|
||||||
drawTexturedModalRect( startX, startY - 8, 0, ySize, xSize, 12);
|
|
||||||
drawTexturedModalRect( startX, startY + ySize - 4, 0, ySize + 12, xSize, 12);
|
|
||||||
for( int n=1; n<m_pages; ++n )
|
|
||||||
{
|
|
||||||
drawTexturedModalRect( startX + xSize + (n-1)*8, startY - 8, 0, ySize, 8, 12);
|
|
||||||
drawTexturedModalRect( startX + xSize + (n-1)*8, startY + ySize - 4, 0, ySize + 12, 8, 12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Left half
|
|
||||||
if( m_page == 0 )
|
|
||||||
{
|
|
||||||
drawTexturedModalRect( startX, startY, 24, 0, xSize / 2, ySize);
|
|
||||||
drawTexturedModalRect( startX, startY, 0, 0, 12, ySize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
drawTexturedModalRect( startX, startY, 0, 0, 12, ySize);
|
|
||||||
for( int n=1; n<m_page; ++n )
|
|
||||||
{
|
|
||||||
drawTexturedModalRect( startX + n*8, startY, 12, 0, 12, ySize);
|
|
||||||
}
|
|
||||||
drawTexturedModalRect( startX + m_page*8, startY, 24, 0, xSize / 2, ySize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right half
|
|
||||||
if( m_page == (m_pages - 1) )
|
|
||||||
{
|
|
||||||
drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize);
|
|
||||||
drawTexturedModalRect( startX + m_page*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
drawTexturedModalRect( startX + (m_pages - 1)*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize);
|
|
||||||
for( int n=m_pages-2; n>=m_page; --n )
|
|
||||||
{
|
|
||||||
drawTexturedModalRect( startX + n*8 + (xSize - 12), startY, 24 + xSize, 0, 12, ySize);
|
|
||||||
}
|
|
||||||
drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the text
|
int startY = (height - Y_SIZE) / 2;
|
||||||
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer)ComputerCraft.getFixedWidthFontRenderer();
|
int startX = (width - X_SIZE) / 2;
|
||||||
int x = startX + m_page * 8 + 13;
|
|
||||||
int y = startY + 11;
|
drawBorder( startX, startY, zLevel, m_page, m_pages, m_book );
|
||||||
for( int line=0; line<ItemPrintout.LINES_PER_PAGE; ++line )
|
drawText( startX + X_TEXT_MARGIN, startY + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours );
|
||||||
{
|
|
||||||
int lineIdx = ItemPrintout.LINES_PER_PAGE * m_page + line;
|
|
||||||
if( lineIdx >= 0 && lineIdx < m_text.length )
|
|
||||||
{
|
|
||||||
fontRenderer.drawString( m_text[lineIdx], x, y, m_colours[lineIdx], null, 0, 0, false, Palette.DEFAULT );
|
|
||||||
}
|
|
||||||
y = y + FixedWidthFontRenderer.FONT_HEIGHT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -210,7 +210,7 @@ public class CCTurtleProxyClient extends CCTurtleProxyCommon
|
|||||||
private static class TurtleItemColour implements IItemColor
|
private static class TurtleItemColour implements IItemColor
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public int getColorFromItemstack( @Nonnull ItemStack stack, int tintIndex )
|
public int colorMultiplier( @Nonnull ItemStack stack, int tintIndex )
|
||||||
{
|
{
|
||||||
if( tintIndex == 0 )
|
if( tintIndex == 0 )
|
||||||
{
|
{
|
||||||
|
@@ -9,6 +9,7 @@ package dan200.computercraft.client.proxy;
|
|||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.client.gui.*;
|
import dan200.computercraft.client.gui.*;
|
||||||
import dan200.computercraft.client.render.ItemPocketRenderer;
|
import dan200.computercraft.client.render.ItemPocketRenderer;
|
||||||
|
import dan200.computercraft.client.render.ItemPrintoutRenderer;
|
||||||
import dan200.computercraft.client.render.RenderOverlayCable;
|
import dan200.computercraft.client.render.RenderOverlayCable;
|
||||||
import dan200.computercraft.client.render.TileEntityCableRenderer;
|
import dan200.computercraft.client.render.TileEntityCableRenderer;
|
||||||
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
|
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
|
||||||
@@ -34,8 +35,10 @@ import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
|
|||||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||||
import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera;
|
import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera;
|
||||||
import dan200.computercraft.shared.util.Colour;
|
import dan200.computercraft.shared.util.Colour;
|
||||||
|
import gnu.trove.map.hash.TIntIntHashMap;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiNewChat;
|
||||||
import net.minecraft.client.renderer.ItemMeshDefinition;
|
import net.minecraft.client.renderer.ItemMeshDefinition;
|
||||||
import net.minecraft.client.renderer.block.model.ModelBakery;
|
import net.minecraft.client.renderer.block.model.ModelBakery;
|
||||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||||
@@ -50,6 +53,7 @@ import net.minecraft.util.IThreadListener;
|
|||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraft.util.SoundEvent;
|
import net.minecraft.util.SoundEvent;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.text.ITextComponent;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.client.event.ModelRegistryEvent;
|
import net.minecraftforge.client.event.ModelRegistryEvent;
|
||||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||||
@@ -71,6 +75,8 @@ import java.util.List;
|
|||||||
|
|
||||||
public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
||||||
{
|
{
|
||||||
|
private static TIntIntHashMap lastCounts = new TIntIntHashMap();
|
||||||
|
|
||||||
private long m_tick;
|
private long m_tick;
|
||||||
private long m_renderFrame;
|
private long m_renderFrame;
|
||||||
private FixedWidthFontRenderer m_fixedWidthFontRenderer;
|
private FixedWidthFontRenderer m_fixedWidthFontRenderer;
|
||||||
@@ -384,6 +390,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
|||||||
case ComputerCraftPacket.ComputerTerminalChanged:
|
case ComputerCraftPacket.ComputerTerminalChanged:
|
||||||
case ComputerCraftPacket.ComputerDeleted:
|
case ComputerCraftPacket.ComputerDeleted:
|
||||||
case ComputerCraftPacket.PlayRecord:
|
case ComputerCraftPacket.PlayRecord:
|
||||||
|
case ComputerCraftPacket.PostChat:
|
||||||
{
|
{
|
||||||
// Packet from Server to Client
|
// Packet from Server to Client
|
||||||
IThreadListener listener = Minecraft.getMinecraft();
|
IThreadListener listener = Minecraft.getMinecraft();
|
||||||
@@ -450,6 +457,36 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
|||||||
{
|
{
|
||||||
mc.world.playRecord( pos, null );
|
mc.world.playRecord( pos, null );
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ComputerCraftPacket.PostChat:
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
This allows us to send delete chat messages of the same "category" as the previous one.
|
||||||
|
It's used by the various /computercraft commands to avoid filling the chat with repetitive
|
||||||
|
messages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int id = packet.m_dataInt[0];
|
||||||
|
ITextComponent[] components = new ITextComponent[packet.m_dataString.length];
|
||||||
|
for( int i = 0; i < packet.m_dataString.length; i++ )
|
||||||
|
{
|
||||||
|
components[i] = ITextComponent.Serializer.jsonToComponent( packet.m_dataString[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiNewChat chat = Minecraft.getMinecraft().ingameGUI.getChatGUI();
|
||||||
|
|
||||||
|
// Keep track of how many lines we wrote last time, deleting any extra ones.
|
||||||
|
int lastCount = lastCounts.get( id );
|
||||||
|
for( int i = components.length; i < lastCount; i++ ) chat.deleteChatLine( i + id );
|
||||||
|
lastCounts.put( id, components.length );
|
||||||
|
|
||||||
|
// Add new lines
|
||||||
|
for( int i = 0; i < components.length; i++ )
|
||||||
|
{
|
||||||
|
chat.printChatMessageWithOptionalDeletion( components[i], id + i );
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -461,6 +498,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
|||||||
MinecraftForge.EVENT_BUS.register( handlers );
|
MinecraftForge.EVENT_BUS.register( handlers );
|
||||||
MinecraftForge.EVENT_BUS.register( new RenderOverlayCable() );
|
MinecraftForge.EVENT_BUS.register( new RenderOverlayCable() );
|
||||||
MinecraftForge.EVENT_BUS.register( new ItemPocketRenderer() );
|
MinecraftForge.EVENT_BUS.register( new ItemPocketRenderer() );
|
||||||
|
MinecraftForge.EVENT_BUS.register( new ItemPrintoutRenderer() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ForgeHandlers
|
public class ForgeHandlers
|
||||||
@@ -569,7 +607,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getColorFromItemstack( @Nonnull ItemStack stack, int layer )
|
public int colorMultiplier( @Nonnull ItemStack stack, int layer )
|
||||||
{
|
{
|
||||||
return layer == 0 ? 0xFFFFFF : disk.getColour( stack );
|
return layer == 0 ? 0xFFFFFF : disk.getColour( stack );
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,197 @@
|
|||||||
|
package dan200.computercraft.client.render;
|
||||||
|
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.shared.media.items.ItemPrintout;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.ItemRenderer;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraft.util.EnumHandSide;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraftforge.client.event.RenderItemInFrameEvent;
|
||||||
|
import net.minecraftforge.client.event.RenderSpecificHandEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
|
||||||
|
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||||
|
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
|
||||||
|
import static dan200.computercraft.client.render.PrintoutRenderer.*;
|
||||||
|
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
|
||||||
|
import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH;
|
||||||
|
|
||||||
|
public class ItemPrintoutRenderer
|
||||||
|
{
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onRenderInHand( RenderSpecificHandEvent event )
|
||||||
|
{
|
||||||
|
ItemStack stack = event.getItemStack();
|
||||||
|
if( stack.getItem() != ComputerCraft.Items.printout ) return;
|
||||||
|
|
||||||
|
event.setCanceled( true );
|
||||||
|
|
||||||
|
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||||
|
|
||||||
|
GlStateManager.pushMatrix();
|
||||||
|
if( event.getHand() == EnumHand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() )
|
||||||
|
{
|
||||||
|
renderPrintoutFirstPersonCentre(
|
||||||
|
event.getInterpolatedPitch(),
|
||||||
|
event.getEquipProgress(),
|
||||||
|
event.getSwingProgress(),
|
||||||
|
stack
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
renderPrintoutFirstPersonSide(
|
||||||
|
event.getHand() == EnumHand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(),
|
||||||
|
event.getEquipProgress(),
|
||||||
|
event.getSwingProgress(),
|
||||||
|
stack
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GlStateManager.popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a pocket computer to one side of the player.
|
||||||
|
*
|
||||||
|
* @param side The side to render on
|
||||||
|
* @param equipProgress The equip progress of this item
|
||||||
|
* @param swingProgress The swing progress of this item
|
||||||
|
* @param stack The stack to render
|
||||||
|
* @see ItemRenderer#renderMapFirstPersonSide(float, EnumHandSide, float, ItemStack)
|
||||||
|
*/
|
||||||
|
private void renderPrintoutFirstPersonSide( EnumHandSide side, float equipProgress, float swingProgress, ItemStack stack )
|
||||||
|
{
|
||||||
|
Minecraft minecraft = Minecraft.getMinecraft();
|
||||||
|
float offset = side == EnumHandSide.RIGHT ? 1f : -1f;
|
||||||
|
GlStateManager.translate( offset * 0.125f, -0.125f, 0f );
|
||||||
|
|
||||||
|
// If the player is not invisible then render a single arm
|
||||||
|
if( !minecraft.player.isInvisible() )
|
||||||
|
{
|
||||||
|
GlStateManager.pushMatrix();
|
||||||
|
GlStateManager.rotate( offset * 10f, 0f, 0f, 1f );
|
||||||
|
minecraft.getItemRenderer().renderArmFirstPerson( equipProgress, swingProgress, side );
|
||||||
|
GlStateManager.popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the appropriate transformations. This is just copied from the
|
||||||
|
// corresponding method in ItemRenderer.
|
||||||
|
GlStateManager.pushMatrix();
|
||||||
|
GlStateManager.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
|
||||||
|
float f1 = MathHelper.sqrt( swingProgress );
|
||||||
|
float f2 = MathHelper.sin( f1 * (float) Math.PI );
|
||||||
|
float f3 = -0.5f * f2;
|
||||||
|
float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) );
|
||||||
|
float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI );
|
||||||
|
GlStateManager.translate( offset * f3, f4 - 0.3f * f2, f5 );
|
||||||
|
GlStateManager.rotate( f2 * -45f, 1f, 0f, 0f );
|
||||||
|
GlStateManager.rotate( offset * f2 * -30f, 0f, 1f, 0f );
|
||||||
|
|
||||||
|
renderPrintoutFirstPerson( stack );
|
||||||
|
|
||||||
|
GlStateManager.popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render an item in the middle of the screen
|
||||||
|
*
|
||||||
|
* @param pitch The pitch of the player
|
||||||
|
* @param equipProgress The equip progress of this item
|
||||||
|
* @param swingProgress The swing progress of this item
|
||||||
|
* @param stack The stack to render
|
||||||
|
* @see ItemRenderer#renderMapFirstPerson(float, float, float)
|
||||||
|
*/
|
||||||
|
private void renderPrintoutFirstPersonCentre( float pitch, float equipProgress, float swingProgress, ItemStack stack )
|
||||||
|
{
|
||||||
|
ItemRenderer itemRenderer = Minecraft.getMinecraft().getItemRenderer();
|
||||||
|
|
||||||
|
// Setup the appropriate transformations. This is just copied from the
|
||||||
|
// corresponding method in ItemRenderer.
|
||||||
|
float swingRt = MathHelper.sqrt( swingProgress );
|
||||||
|
float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI );
|
||||||
|
float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI );
|
||||||
|
GlStateManager.translate( 0f, -tX / 2f, tZ );
|
||||||
|
float pitchAngle = itemRenderer.getMapAngleFromPitch( pitch );
|
||||||
|
GlStateManager.translate( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
|
||||||
|
GlStateManager.rotate( pitchAngle * -85f, 1f, 0f, 0f );
|
||||||
|
itemRenderer.renderArms();
|
||||||
|
float rX = MathHelper.sin( swingRt * (float) Math.PI );
|
||||||
|
GlStateManager.rotate( rX * 20f, 1f, 0f, 0f );
|
||||||
|
GlStateManager.scale( 2f, 2f, 2f );
|
||||||
|
|
||||||
|
renderPrintoutFirstPerson( stack );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void renderPrintoutFirstPerson( ItemStack stack )
|
||||||
|
{
|
||||||
|
// Setup various transformations. Note that these are partially adapated from the corresponding method
|
||||||
|
// in ItemRenderer.renderMapFirstPerson
|
||||||
|
GlStateManager.disableLighting();
|
||||||
|
|
||||||
|
GlStateManager.rotate( 180f, 0f, 1f, 0f );
|
||||||
|
GlStateManager.rotate( 180f, 0f, 0f, 1f );
|
||||||
|
GlStateManager.scale( 0.42f, 0.42f, -0.42f );
|
||||||
|
GlStateManager.translate( -0.5f, -0.48f, 0.0f );
|
||||||
|
|
||||||
|
drawPrintout( stack );
|
||||||
|
|
||||||
|
GlStateManager.enableLighting();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onRenderInFrame( RenderItemInFrameEvent event )
|
||||||
|
{
|
||||||
|
ItemStack stack = event.getItem();
|
||||||
|
if( stack.getItem() != ComputerCraft.Items.printout ) return;
|
||||||
|
|
||||||
|
event.setCanceled( true );
|
||||||
|
|
||||||
|
GlStateManager.disableLighting();
|
||||||
|
|
||||||
|
// Move a little bit forward to ensure we're not clipping with the frame
|
||||||
|
GlStateManager.translate( 0.0f, 0.0f, -0.001f );
|
||||||
|
GlStateManager.rotate( 180f, 0f, 0f, 1f );
|
||||||
|
GlStateManager.scale( 0.95f, 0.95f, -0.95f );
|
||||||
|
GlStateManager.translate( -0.5f, -0.5f, 0.0f );
|
||||||
|
|
||||||
|
drawPrintout( stack );
|
||||||
|
|
||||||
|
GlStateManager.enableLighting();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawPrintout( ItemStack stack )
|
||||||
|
{
|
||||||
|
int pages = ItemPrintout.getPageCount( stack );
|
||||||
|
boolean book = ItemPrintout.getType( stack ) == ItemPrintout.Type.Book;
|
||||||
|
|
||||||
|
double width = LINE_MAX_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2;
|
||||||
|
double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2;
|
||||||
|
|
||||||
|
// Non-books will be left aligned
|
||||||
|
if( !book ) width += offsetAt( pages );
|
||||||
|
|
||||||
|
double visualWidth = width, visualHeight = height;
|
||||||
|
|
||||||
|
// Meanwhile books will be centred
|
||||||
|
if( book )
|
||||||
|
{
|
||||||
|
visualWidth += 2 * COVER_SIZE + 2 * offsetAt( pages );
|
||||||
|
visualHeight += 2 * COVER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
double max = Math.max( visualHeight, visualWidth );
|
||||||
|
|
||||||
|
// Scale the printout to fit correctly.
|
||||||
|
double scale = 1.0 / max;
|
||||||
|
GlStateManager.scale( scale, scale, scale );
|
||||||
|
GlStateManager.translate( (max - width) / 2.0f, (max - height) / 2.0f, 0.0f );
|
||||||
|
|
||||||
|
drawBorder( 0, 0, -0.01, 0, pages, book );
|
||||||
|
drawText( X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) );
|
||||||
|
}
|
||||||
|
}
|
@@ -189,7 +189,7 @@ public final class ModelTransformer
|
|||||||
private BakedQuadBuilder( VertexFormat format )
|
private BakedQuadBuilder( VertexFormat format )
|
||||||
{
|
{
|
||||||
this.format = format;
|
this.format = format;
|
||||||
this.vertexData = new int[ format.getNextOffset() ];
|
this.vertexData = new int[ format.getSize() ];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
@@ -0,0 +1,169 @@
|
|||||||
|
package dan200.computercraft.client.render;
|
||||||
|
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||||
|
import dan200.computercraft.core.terminal.TextBuffer;
|
||||||
|
import dan200.computercraft.shared.util.Palette;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.BufferBuilder;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.Tessellator;
|
||||||
|
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||||
|
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
|
||||||
|
|
||||||
|
public class PrintoutRenderer
|
||||||
|
{
|
||||||
|
private static final ResourceLocation BG = new ResourceLocation( "computercraft", "textures/gui/printout.png" );
|
||||||
|
private static final double BG_SIZE = 256.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Width of a page
|
||||||
|
*/
|
||||||
|
public static final int X_SIZE = 172;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Height of a page
|
||||||
|
*/
|
||||||
|
public static final int Y_SIZE = 209;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Padding between the left and right of a page and the text
|
||||||
|
*/
|
||||||
|
public static final int X_TEXT_MARGIN = 13;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Padding between the top and bottom of a page and the text
|
||||||
|
*/
|
||||||
|
public static final int Y_TEXT_MARGIN = 11;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Width of the extra page texture
|
||||||
|
*/
|
||||||
|
private static final int X_FOLD_SIZE = 12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of the leather cover
|
||||||
|
*/
|
||||||
|
public static final int COVER_SIZE = 12;
|
||||||
|
|
||||||
|
private static final int COVER_Y = Y_SIZE;
|
||||||
|
private static final int COVER_X = X_SIZE + 4 * X_FOLD_SIZE;
|
||||||
|
|
||||||
|
public static void drawText( int x, int y, int start, TextBuffer[] text, TextBuffer[] colours )
|
||||||
|
{
|
||||||
|
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer();
|
||||||
|
|
||||||
|
for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line )
|
||||||
|
{
|
||||||
|
fontRenderer.drawString( text[ start + line ], x, y + line * FONT_HEIGHT, colours[ start + line ], null, 0, 0, false, Palette.DEFAULT );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drawText( int x, int y, int start, String[] text, String[] colours )
|
||||||
|
{
|
||||||
|
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||||
|
GlStateManager.enableBlend();
|
||||||
|
GlStateManager.enableTexture2D();
|
||||||
|
|
||||||
|
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer();
|
||||||
|
|
||||||
|
for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line )
|
||||||
|
{
|
||||||
|
fontRenderer.drawString( new TextBuffer( text[ start + line ] ), x, y + line * FONT_HEIGHT, new TextBuffer( colours[ start + line ] ), null, 0, 0, false, Palette.DEFAULT );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drawBorder( double x, double y, double z, int page, int pages, boolean isBook )
|
||||||
|
{
|
||||||
|
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||||
|
GlStateManager.enableBlend();
|
||||||
|
GlStateManager.enableTexture2D();
|
||||||
|
|
||||||
|
Minecraft.getMinecraft().getTextureManager().bindTexture( BG );
|
||||||
|
|
||||||
|
Tessellator tessellator = Tessellator.getInstance();
|
||||||
|
BufferBuilder buffer = tessellator.getBuffer();
|
||||||
|
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX );
|
||||||
|
|
||||||
|
int leftPages = page;
|
||||||
|
int rightPages = pages - page - 1;
|
||||||
|
|
||||||
|
if( isBook )
|
||||||
|
{
|
||||||
|
// Border
|
||||||
|
double offset = offsetAt( pages );
|
||||||
|
final double left = x - 4 - offset;
|
||||||
|
final double right = x + X_SIZE + offset - 4;
|
||||||
|
|
||||||
|
// Left and right border
|
||||||
|
drawTexture( buffer, left - 4, y - 8, z - 0.02, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 );
|
||||||
|
drawTexture( buffer, right, y - 8, z - 0.02, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 );
|
||||||
|
|
||||||
|
// Draw centre panel (just stretched texture, sorry).
|
||||||
|
drawTexture( buffer,
|
||||||
|
x - offset, y, z - 0.02, X_SIZE + offset * 2, Y_SIZE,
|
||||||
|
COVER_X + COVER_SIZE / 2, COVER_SIZE, COVER_SIZE, Y_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
double borderX = left;
|
||||||
|
while( borderX < right )
|
||||||
|
{
|
||||||
|
double thisWidth = Math.min( right - borderX, X_SIZE );
|
||||||
|
drawTexture( buffer, borderX, y - 8, z - 0.02, 0, COVER_Y, thisWidth, COVER_SIZE );
|
||||||
|
drawTexture( buffer, borderX, y + Y_SIZE - 4, z - 0.02, 0, COVER_Y + COVER_SIZE, thisWidth, COVER_SIZE );
|
||||||
|
borderX += thisWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left half
|
||||||
|
drawTexture( buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2, Y_SIZE );
|
||||||
|
for( int n = 0; n <= leftPages; n++ )
|
||||||
|
{
|
||||||
|
drawTexture( buffer,
|
||||||
|
x - offsetAt( n ), y, z - 1e-3 * n,
|
||||||
|
// Use the left "bold" fold for the outermost page
|
||||||
|
n == leftPages ? 0 : X_FOLD_SIZE, 0,
|
||||||
|
X_FOLD_SIZE, Y_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right half
|
||||||
|
drawTexture( buffer, x + X_SIZE / 2, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2, 0, X_SIZE / 2, Y_SIZE );
|
||||||
|
for( int n = 0; n <= rightPages; n++ )
|
||||||
|
{
|
||||||
|
drawTexture( buffer,
|
||||||
|
x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3 * n,
|
||||||
|
// Two folds, then the main page. Use the right "bold" fold for the outermost page.
|
||||||
|
X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0,
|
||||||
|
X_FOLD_SIZE, Y_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
tessellator.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double u, double v, double width, double height )
|
||||||
|
{
|
||||||
|
buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
|
||||||
|
buffer.pos( x + width, y + height, z ).tex( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
|
||||||
|
buffer.pos( x + width, y, z ).tex( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex();
|
||||||
|
buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double width, double height, double u, double v, double tWidth, double tHeight )
|
||||||
|
{
|
||||||
|
buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
|
||||||
|
buffer.pos( x + width, y + height, z ).tex( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
|
||||||
|
buffer.pos( x + width, y, z ).tex( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex();
|
||||||
|
buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double offsetAt( int page )
|
||||||
|
{
|
||||||
|
return 32 * (1 - Math.pow( 1.2, -page ));
|
||||||
|
}
|
||||||
|
}
|
@@ -71,7 +71,7 @@ public class TileEntityCableRenderer extends TileEntitySpecialRenderer<TileCable
|
|||||||
buffer.setTranslation( x - pos.getX(), y - pos.getY(), z - pos.getZ() );
|
buffer.setTranslation( x - pos.getX(), y - pos.getY(), z - pos.getZ() );
|
||||||
buffer.noColor();
|
buffer.noColor();
|
||||||
|
|
||||||
ForgeHooksClient.setRenderLayer( block.getBlockLayer() );
|
ForgeHooksClient.setRenderLayer( block.getRenderLayer() );
|
||||||
|
|
||||||
// See BlockRendererDispatcher#renderBlockDamage
|
// See BlockRendererDispatcher#renderBlockDamage
|
||||||
TextureAtlasSprite breakingTexture = mc.getTextureMapBlocks().getAtlasSprite( "minecraft:blocks/destroy_stage_" + destroyStage );
|
TextureAtlasSprite breakingTexture = mc.getTextureMapBlocks().getAtlasSprite( "minecraft:blocks/destroy_stage_" + destroyStage );
|
||||||
|
@@ -18,6 +18,7 @@ import dan200.computercraft.shared.util.Palette;
|
|||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.BufferBuilder;
|
import net.minecraft.client.renderer.BufferBuilder;
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.OpenGlHelper;
|
||||||
import net.minecraft.client.renderer.Tessellator;
|
import net.minecraft.client.renderer.Tessellator;
|
||||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||||
@@ -47,19 +48,20 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
|
|
||||||
if( originTerminal == null ) return;
|
if( originTerminal == null ) return;
|
||||||
TileMonitor origin = originTerminal.getOrigin();
|
TileMonitor origin = originTerminal.getOrigin();
|
||||||
|
BlockPos monitorPos = monitor.getPos();
|
||||||
|
|
||||||
// Ensure each monitor is rendered only once
|
// Ensure each monitor terminal is rendered only once. We allow rendering a specific tile
|
||||||
|
// multiple times in a single frame to ensure compatibility with shaders which may run a
|
||||||
|
// pass multiple times.
|
||||||
long renderFrame = ComputerCraft.getRenderFrame();
|
long renderFrame = ComputerCraft.getRenderFrame();
|
||||||
if( originTerminal.lastRenderFrame == renderFrame )
|
if( originTerminal.lastRenderFrame == renderFrame && !monitorPos.equals( originTerminal.lastRenderPos ) )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
originTerminal.lastRenderFrame = renderFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockPos monitorPos = monitor.getPos();
|
originTerminal.lastRenderFrame = renderFrame;
|
||||||
|
originTerminal.lastRenderPos = monitorPos;
|
||||||
|
|
||||||
BlockPos originPos = origin.getPos();
|
BlockPos originPos = origin.getPos();
|
||||||
posX += originPos.getX() - monitorPos.getX();
|
posX += originPos.getX() - monitorPos.getX();
|
||||||
posY += originPos.getY() - monitorPos.getY();
|
posY += originPos.getY() - monitorPos.getY();
|
||||||
@@ -96,6 +98,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
|
|
||||||
// Draw the contents
|
// Draw the contents
|
||||||
GlStateManager.depthMask( false );
|
GlStateManager.depthMask( false );
|
||||||
|
OpenGlHelper.setLightmapTextureCoords( OpenGlHelper.lightmapTexUnit, 0xFF, 0xFF );
|
||||||
GlStateManager.disableLighting();
|
GlStateManager.disableLighting();
|
||||||
mc.entityRenderer.disableLightmap();
|
mc.entityRenderer.disableLightmap();
|
||||||
try
|
try
|
||||||
|
@@ -3,14 +3,17 @@ package dan200.computercraft.core.apis;
|
|||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
|
import dan200.computercraft.core.computer.Computer;
|
||||||
|
import dan200.computercraft.core.computer.IComputerOwned;
|
||||||
import dan200.computercraft.core.filesystem.FileSystem;
|
import dan200.computercraft.core.filesystem.FileSystem;
|
||||||
import dan200.computercraft.core.filesystem.FileSystemException;
|
import dan200.computercraft.core.filesystem.FileSystemException;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public abstract class ComputerAccess implements IComputerAccess
|
public abstract class ComputerAccess implements IComputerAccess, IComputerOwned
|
||||||
{
|
{
|
||||||
private final IAPIEnvironment m_environment;
|
private final IAPIEnvironment m_environment;
|
||||||
private final Set<String> m_mounts = new HashSet<>();
|
private final Set<String> m_mounts = new HashSet<>();
|
||||||
@@ -133,6 +136,13 @@ public abstract class ComputerAccess implements IComputerAccess
|
|||||||
m_environment.queueEvent( event, arguments );
|
m_environment.queueEvent( event, arguments );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Computer getComputer()
|
||||||
|
{
|
||||||
|
return m_environment.getComputer();
|
||||||
|
}
|
||||||
|
|
||||||
private String findFreeLocation( String desiredLoc )
|
private String findFreeLocation( String desiredLoc )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@@ -15,6 +15,7 @@ import dan200.computercraft.core.apis.handles.EncodedInputHandle;
|
|||||||
import dan200.computercraft.core.apis.handles.EncodedOutputHandle;
|
import dan200.computercraft.core.apis.handles.EncodedOutputHandle;
|
||||||
import dan200.computercraft.core.filesystem.FileSystem;
|
import dan200.computercraft.core.filesystem.FileSystem;
|
||||||
import dan200.computercraft.core.filesystem.FileSystemException;
|
import dan200.computercraft.core.filesystem.FileSystemException;
|
||||||
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -88,6 +89,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
// list
|
// list
|
||||||
String path = getString( args, 0 );
|
String path = getString( args, 0 );
|
||||||
|
m_env.addTrackingChange( TrackingField.FS_OPS );
|
||||||
try {
|
try {
|
||||||
String[] results = m_fileSystem.list( path );
|
String[] results = m_fileSystem.list( path );
|
||||||
Map<Object,Object> table = new HashMap<>();
|
Map<Object,Object> table = new HashMap<>();
|
||||||
@@ -162,6 +164,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
// makeDir
|
// makeDir
|
||||||
String path = getString( args, 0 );
|
String path = getString( args, 0 );
|
||||||
try {
|
try {
|
||||||
|
m_env.addTrackingChange( TrackingField.FS_OPS );
|
||||||
m_fileSystem.makeDir( path );
|
m_fileSystem.makeDir( path );
|
||||||
return null;
|
return null;
|
||||||
} catch( FileSystemException e ) {
|
} catch( FileSystemException e ) {
|
||||||
@@ -174,6 +177,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
String path = getString( args, 0 );
|
String path = getString( args, 0 );
|
||||||
String dest = getString( args, 1 );
|
String dest = getString( args, 1 );
|
||||||
try {
|
try {
|
||||||
|
m_env.addTrackingChange( TrackingField.FS_OPS );
|
||||||
m_fileSystem.move( path, dest );
|
m_fileSystem.move( path, dest );
|
||||||
return null;
|
return null;
|
||||||
} catch( FileSystemException e ) {
|
} catch( FileSystemException e ) {
|
||||||
@@ -186,6 +190,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
String path = getString( args, 0 );
|
String path = getString( args, 0 );
|
||||||
String dest = getString( args, 1 );
|
String dest = getString( args, 1 );
|
||||||
try {
|
try {
|
||||||
|
m_env.addTrackingChange( TrackingField.FS_OPS );
|
||||||
m_fileSystem.copy( path, dest );
|
m_fileSystem.copy( path, dest );
|
||||||
return null;
|
return null;
|
||||||
} catch( FileSystemException e ) {
|
} catch( FileSystemException e ) {
|
||||||
@@ -197,6 +202,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
// delete
|
// delete
|
||||||
String path = getString( args, 0 );
|
String path = getString( args, 0 );
|
||||||
try {
|
try {
|
||||||
|
m_env.addTrackingChange( TrackingField.FS_OPS );
|
||||||
m_fileSystem.delete( path );
|
m_fileSystem.delete( path );
|
||||||
return null;
|
return null;
|
||||||
} catch( FileSystemException e ) {
|
} catch( FileSystemException e ) {
|
||||||
@@ -208,6 +214,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
// open
|
// open
|
||||||
String path = getString( args, 0 );
|
String path = getString( args, 0 );
|
||||||
String mode = getString( args, 1 );
|
String mode = getString( args, 1 );
|
||||||
|
m_env.addTrackingChange( TrackingField.FS_OPS );
|
||||||
try {
|
try {
|
||||||
switch( mode )
|
switch( mode )
|
||||||
{
|
{
|
||||||
@@ -288,6 +295,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
// find
|
// find
|
||||||
String path = getString( args, 0 );
|
String path = getString( args, 0 );
|
||||||
try {
|
try {
|
||||||
|
m_env.addTrackingChange( TrackingField.FS_OPS );
|
||||||
String[] results = m_fileSystem.find( path );
|
String[] results = m_fileSystem.find( path );
|
||||||
Map<Object,Object> table = new HashMap<>();
|
Map<Object,Object> table = new HashMap<>();
|
||||||
for(int i=0; i<results.length; ++i ) {
|
for(int i=0; i<results.length; ++i ) {
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.core.apis;
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.api.lua.ILuaAPI;
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
@@ -21,9 +22,14 @@ import java.util.*;
|
|||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
||||||
|
import static dan200.computercraft.core.apis.TableHelper.*;
|
||||||
|
|
||||||
public class HTTPAPI implements ILuaAPI
|
public class HTTPAPI implements ILuaAPI
|
||||||
{
|
{
|
||||||
|
private static final Set<String> HTTP_METHODS = ImmutableSet.of(
|
||||||
|
"GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE"
|
||||||
|
);
|
||||||
|
|
||||||
private final IAPIEnvironment m_apiEnvironment;
|
private final IAPIEnvironment m_apiEnvironment;
|
||||||
private final List<Future<?>> m_httpTasks;
|
private final List<Future<?>> m_httpTasks;
|
||||||
private final Set<Closeable> m_closeables;
|
private final Set<Closeable> m_closeables;
|
||||||
@@ -38,7 +44,7 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
@Override
|
@Override
|
||||||
public String[] getNames()
|
public String[] getNames()
|
||||||
{
|
{
|
||||||
return new String[] {
|
return new String[]{
|
||||||
"http"
|
"http"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -59,7 +65,7 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutdown( )
|
public void shutdown()
|
||||||
{
|
{
|
||||||
synchronized( m_httpTasks )
|
synchronized( m_httpTasks )
|
||||||
{
|
{
|
||||||
@@ -89,7 +95,7 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
@Override
|
@Override
|
||||||
public String[] getMethodNames()
|
public String[] getMethodNames()
|
||||||
{
|
{
|
||||||
return new String[] {
|
return new String[]{
|
||||||
"request",
|
"request",
|
||||||
"checkURL",
|
"checkURL",
|
||||||
"websocket",
|
"websocket",
|
||||||
@@ -101,52 +107,68 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
switch( method )
|
switch( method )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0: // request
|
||||||
{
|
{
|
||||||
// request
|
String urlString, postString, requestMethod;
|
||||||
// Get URL
|
Map<Object, Object> headerTable;
|
||||||
String urlString = getString( args, 0 );
|
boolean binary, redirect;
|
||||||
|
|
||||||
// Get POST
|
if( args.length >= 1 && args[0] instanceof Map )
|
||||||
String postString = optString( args, 1, null );
|
|
||||||
|
|
||||||
// Get Headers
|
|
||||||
Map<String, String> headers = null;
|
|
||||||
Map<Object, Object> table = optTable( args, 2, null );
|
|
||||||
if( table != null )
|
|
||||||
{
|
{
|
||||||
headers = new HashMap<>( table.size() );
|
Map<?, ?> options = (Map) args[0];
|
||||||
for( Object key : table.keySet() )
|
urlString = getStringField( options, "url" );
|
||||||
|
postString = optStringField( options, "body", null );
|
||||||
|
headerTable = optTableField( options, "headers", null );
|
||||||
|
binary = optBooleanField( options, "binary", false );
|
||||||
|
requestMethod = optStringField( options, "method", null );
|
||||||
|
redirect = optBooleanField( options, "redirect", true );
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Get URL and post information
|
||||||
|
urlString = getString( args, 0 );
|
||||||
|
postString = optString( args, 1, null );
|
||||||
|
headerTable = optTable( args, 2, null );
|
||||||
|
binary = optBoolean( args, 3, false );
|
||||||
|
requestMethod = null;
|
||||||
|
redirect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> headers = null;
|
||||||
|
if( headerTable != null )
|
||||||
|
{
|
||||||
|
headers = new HashMap<>( headerTable.size() );
|
||||||
|
for( Object key : headerTable.keySet() )
|
||||||
{
|
{
|
||||||
Object value = table.get( key );
|
Object value = headerTable.get( key );
|
||||||
if( key instanceof String && value instanceof String )
|
if( key instanceof String && value instanceof String )
|
||||||
{
|
{
|
||||||
headers.put( (String)key, (String)value );
|
headers.put( (String) key, (String) value );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get binary
|
|
||||||
boolean binary = false;
|
if( requestMethod != null && !HTTP_METHODS.contains( requestMethod ) )
|
||||||
if( args.length >= 4 )
|
|
||||||
{
|
{
|
||||||
binary = args[ 3 ] != null && !args[ 3 ].equals( Boolean.FALSE );
|
throw new LuaException( "Unsupported HTTP method" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the request
|
// Make the request
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
URL url = HTTPRequest.checkURL( urlString );
|
URL url = HTTPRequest.checkURL( urlString );
|
||||||
HTTPRequest request = new HTTPRequest( m_apiEnvironment, urlString, url, postString, headers, binary );
|
HTTPRequest request = new HTTPRequest( m_apiEnvironment, urlString, url, postString, headers, binary, requestMethod, redirect );
|
||||||
synchronized( m_httpTasks )
|
synchronized( m_httpTasks )
|
||||||
{
|
{
|
||||||
m_httpTasks.add( HTTPExecutor.EXECUTOR.submit( request ) );
|
m_httpTasks.add( HTTPExecutor.EXECUTOR.submit( request ) );
|
||||||
}
|
}
|
||||||
return new Object[] { true };
|
return new Object[]{ true };
|
||||||
}
|
}
|
||||||
catch( HTTPRequestException e )
|
catch( HTTPRequestException e )
|
||||||
{
|
{
|
||||||
return new Object[] { false, e.getMessage() };
|
return new Object[]{ false, e.getMessage() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
@@ -164,11 +186,11 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
m_httpTasks.add( HTTPExecutor.EXECUTOR.submit( check ) );
|
m_httpTasks.add( HTTPExecutor.EXECUTOR.submit( check ) );
|
||||||
}
|
}
|
||||||
return new Object[] { true };
|
return new Object[]{ true };
|
||||||
}
|
}
|
||||||
catch( HTTPRequestException e )
|
catch( HTTPRequestException e )
|
||||||
{
|
{
|
||||||
return new Object[] { false, e.getMessage() };
|
return new Object[]{ false, e.getMessage() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 2: // websocket
|
case 2: // websocket
|
||||||
@@ -201,11 +223,11 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
m_httpTasks.add( connector );
|
m_httpTasks.add( connector );
|
||||||
}
|
}
|
||||||
return new Object[] { true };
|
return new Object[]{ true };
|
||||||
}
|
}
|
||||||
catch( HTTPRequestException e )
|
catch( HTTPRequestException e )
|
||||||
{
|
{
|
||||||
return new Object[] { false, e.getMessage() };
|
return new Object[]{ false, e.getMessage() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@@ -9,16 +9,19 @@ package dan200.computercraft.core.apis;
|
|||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.computer.Computer;
|
import dan200.computercraft.core.computer.Computer;
|
||||||
import dan200.computercraft.core.computer.IComputerEnvironment;
|
import dan200.computercraft.core.computer.IComputerEnvironment;
|
||||||
|
import dan200.computercraft.core.computer.IComputerOwned;
|
||||||
import dan200.computercraft.core.filesystem.FileSystem;
|
import dan200.computercraft.core.filesystem.FileSystem;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
|
|
||||||
public interface IAPIEnvironment
|
public interface IAPIEnvironment extends IComputerOwned
|
||||||
{
|
{
|
||||||
interface IPeripheralChangeListener
|
interface IPeripheralChangeListener
|
||||||
{
|
{
|
||||||
void onPeripheralChanged( int side, IPeripheral newPeripheral );
|
void onPeripheralChanged( int side, IPeripheral newPeripheral );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
Computer getComputer();
|
Computer getComputer();
|
||||||
int getComputerID();
|
int getComputerID();
|
||||||
IComputerEnvironment getComputerEnvironment();
|
IComputerEnvironment getComputerEnvironment();
|
||||||
@@ -42,4 +45,11 @@ public interface IAPIEnvironment
|
|||||||
|
|
||||||
String getLabel();
|
String getLabel();
|
||||||
void setLabel( String label );
|
void setLabel( String label );
|
||||||
|
|
||||||
|
void addTrackingChange( TrackingField field, long change );
|
||||||
|
|
||||||
|
default void addTrackingChange( TrackingField field )
|
||||||
|
{
|
||||||
|
addTrackingChange( field, 1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@ import dan200.computercraft.api.peripheral.IPeripheral;
|
|||||||
import dan200.computercraft.core.computer.Computer;
|
import dan200.computercraft.core.computer.Computer;
|
||||||
import dan200.computercraft.core.computer.ComputerThread;
|
import dan200.computercraft.core.computer.ComputerThread;
|
||||||
import dan200.computercraft.core.computer.ITask;
|
import dan200.computercraft.core.computer.ITask;
|
||||||
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -109,6 +110,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
}
|
}
|
||||||
if( method >= 0 )
|
if( method >= 0 )
|
||||||
{
|
{
|
||||||
|
m_environment.addTrackingChange( TrackingField.PERIPHERAL_OPS );
|
||||||
return m_peripheral.callMethod( this, context, method, arguments );
|
return m_peripheral.callMethod( this, context, method, arguments );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
214
src/main/java/dan200/computercraft/core/apis/TableHelper.java
Normal file
214
src/main/java/dan200/computercraft/core/apis/TableHelper.java
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various helpers for tables
|
||||||
|
*/
|
||||||
|
public final class TableHelper
|
||||||
|
{
|
||||||
|
private TableHelper()
|
||||||
|
{
|
||||||
|
throw new IllegalStateException( "Cannot instantiate singleton " + getClass().getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static LuaException badKey( @Nonnull String key, @Nonnull String expected, @Nullable Object actual )
|
||||||
|
{
|
||||||
|
return badKey( key, expected, ArgumentHelper.getType( actual ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static LuaException badKey( @Nonnull String key, @Nonnull String expected, @Nonnull String actual )
|
||||||
|
{
|
||||||
|
return new LuaException( "bad field '" + key + "' (" + expected + " expected, got " + actual + ")" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getNumberField( @Nonnull Map<?, ?> table, @Nonnull String key ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = table.get( key );
|
||||||
|
if( value instanceof Number )
|
||||||
|
{
|
||||||
|
return ((Number) value).doubleValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badKey( key, "number", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getIntField( @Nonnull Map<?, ?> table, @Nonnull String key ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = table.get( key );
|
||||||
|
if( value instanceof Number )
|
||||||
|
{
|
||||||
|
return (int) ((Number) value).longValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badKey( key, "number", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getRealField( @Nonnull Map<?, ?> table, @Nonnull String key ) throws LuaException
|
||||||
|
{
|
||||||
|
return checkReal( key, getNumberField( table, key ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getBooleanField( @Nonnull Map<?, ?> table, @Nonnull String key ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = table.get( key );
|
||||||
|
if( value instanceof Boolean )
|
||||||
|
{
|
||||||
|
return (Boolean) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badKey( key, "boolean", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static String getStringField( @Nonnull Map<?, ?> table, @Nonnull String key ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = table.get( key );
|
||||||
|
if( value instanceof String )
|
||||||
|
{
|
||||||
|
return (String) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badKey( key, "string", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "unchecked" )
|
||||||
|
@Nonnull
|
||||||
|
public static Map<Object, Object> getTableField( @Nonnull Map<?, ?> table, @Nonnull String key ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = table.get( key );
|
||||||
|
if( value instanceof Map )
|
||||||
|
{
|
||||||
|
return (Map<Object, Object>) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badKey( key, "table", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double optNumberField( @Nonnull Map<?, ?> table, @Nonnull String key, double def ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = table.get( key );
|
||||||
|
if( value == null )
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
else if( value instanceof Number )
|
||||||
|
{
|
||||||
|
return ((Number) value).doubleValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badKey( key, "number", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int optIntField( @Nonnull Map<?, ?> table, @Nonnull String key, int def ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = table.get( key );
|
||||||
|
if( value == null )
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
else if( value instanceof Number )
|
||||||
|
{
|
||||||
|
return (int) ((Number) value).longValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badKey( key, "number", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double optRealField( @Nonnull Map<?, ?> table, @Nonnull String key, double def ) throws LuaException
|
||||||
|
{
|
||||||
|
return checkReal( key, optNumberField( table, key, def ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean optBooleanField( @Nonnull Map<?, ?> table, @Nonnull String key, boolean def ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = table.get( key );
|
||||||
|
if( value == null )
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
else if( value instanceof Boolean )
|
||||||
|
{
|
||||||
|
return (Boolean) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badKey( key, "boolean", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String optStringField( @Nonnull Map<?, ?> table, @Nonnull String key, String def ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = table.get( key );
|
||||||
|
if( value == null )
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
else if( value instanceof String )
|
||||||
|
{
|
||||||
|
return (String) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badKey( key, "string", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "unchecked" )
|
||||||
|
public static Map<Object, Object> optTableField( @Nonnull Map<?, ?> table, @Nonnull String key, Map<Object, Object> def ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = table.get( key );
|
||||||
|
if( value == null )
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
else if( value instanceof Map )
|
||||||
|
{
|
||||||
|
return (Map<Object, Object>) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badKey( key, "table", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double checkReal( @Nonnull String key, double value ) throws LuaException
|
||||||
|
{
|
||||||
|
if( Double.isNaN( value ) )
|
||||||
|
{
|
||||||
|
throw badKey( key, "number", "nan" );
|
||||||
|
}
|
||||||
|
else if( value == Double.POSITIVE_INFINITY )
|
||||||
|
{
|
||||||
|
throw badKey( key, "number", "inf" );
|
||||||
|
}
|
||||||
|
else if( value == Double.NEGATIVE_INFINITY )
|
||||||
|
{
|
||||||
|
throw badKey( key, "number", "-inf" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -5,6 +5,7 @@ import dan200.computercraft.api.lua.ILuaContext;
|
|||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -13,6 +14,8 @@ import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
|
|||||||
|
|
||||||
public class BinaryInputHandle extends HandleGeneric
|
public class BinaryInputHandle extends HandleGeneric
|
||||||
{
|
{
|
||||||
|
private static final int BUFFER_SIZE = 8192;
|
||||||
|
|
||||||
private final InputStream m_stream;
|
private final InputStream m_stream;
|
||||||
|
|
||||||
public BinaryInputHandle( InputStream reader )
|
public BinaryInputHandle( InputStream reader )
|
||||||
@@ -45,16 +48,46 @@ public class BinaryInputHandle extends HandleGeneric
|
|||||||
if( args.length > 0 && args[ 0 ] != null )
|
if( args.length > 0 && args[ 0 ] != null )
|
||||||
{
|
{
|
||||||
int count = getInt( args, 0 );
|
int count = getInt( args, 0 );
|
||||||
if( count <= 0 || count >= 1024 * 16 )
|
if( count < 0 )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Count out of range" );
|
// Whilst this may seem absurd to allow reading 0 bytes, PUC Lua it so
|
||||||
|
// it seems best to remain somewhat consistent.
|
||||||
|
throw new LuaException( "Cannot read a negative number of bytes" );
|
||||||
}
|
}
|
||||||
|
else if( count <= BUFFER_SIZE )
|
||||||
|
{
|
||||||
|
// If we've got a small count, then allocate that and read it.
|
||||||
|
byte[] bytes = new byte[ count ];
|
||||||
|
int read = m_stream.read( bytes );
|
||||||
|
|
||||||
byte[] bytes = new byte[ count ];
|
if( read < 0 ) return null;
|
||||||
count = m_stream.read( bytes );
|
if( read < count ) bytes = Arrays.copyOf( bytes, read );
|
||||||
if( count < 0 ) return null;
|
return new Object[] { bytes };
|
||||||
if( count < bytes.length ) bytes = Arrays.copyOf( bytes, count );
|
}
|
||||||
return new Object[] { bytes };
|
else
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[ BUFFER_SIZE ];
|
||||||
|
|
||||||
|
// Read the initial set of bytes, failing if none are read.
|
||||||
|
int read = m_stream.read( buffer, 0, Math.min( buffer.length, count ) );
|
||||||
|
if( read == -1 ) return null;
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream( read );
|
||||||
|
count -= read;
|
||||||
|
out.write( buffer, 0, read );
|
||||||
|
|
||||||
|
// Otherwise read until we either reach the limit or we no longer consume
|
||||||
|
// the full buffer.
|
||||||
|
while( read >= buffer.length && count > 0 )
|
||||||
|
{
|
||||||
|
read = m_stream.read( buffer, 0, Math.min( BUFFER_SIZE, count ) );
|
||||||
|
if( read == -1 ) break;
|
||||||
|
count -= read;
|
||||||
|
out.write( buffer, 0, read );
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Object[] { out.toByteArray() };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -6,10 +6,12 @@ import dan200.computercraft.api.lua.LuaException;
|
|||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
import static dan200.computercraft.core.apis.ArgumentHelper.optInt;
|
||||||
|
|
||||||
public class EncodedInputHandle extends HandleGeneric
|
public class EncodedInputHandle extends HandleGeneric
|
||||||
{
|
{
|
||||||
|
private static final int BUFFER_SIZE = 8192;
|
||||||
|
|
||||||
private final BufferedReader m_reader;
|
private final BufferedReader m_reader;
|
||||||
|
|
||||||
public EncodedInputHandle( BufferedReader reader )
|
public EncodedInputHandle( BufferedReader reader )
|
||||||
@@ -111,15 +113,45 @@ public class EncodedInputHandle extends HandleGeneric
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
int count = optInt( args, 0, 1 );
|
int count = optInt( args, 0, 1 );
|
||||||
if( count <= 0 || count >= 1024 * 16 )
|
if( count < 0 )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Count out of range" );
|
// Whilst this may seem absurd to allow reading 0 characters, PUC Lua it so
|
||||||
|
// it seems best to remain somewhat consistent.
|
||||||
|
throw new LuaException( "Cannot read a negative number of characters" );
|
||||||
|
}
|
||||||
|
else if( count <= BUFFER_SIZE )
|
||||||
|
{
|
||||||
|
// If we've got a small count, then allocate that and read it.
|
||||||
|
char[] chars = new char[ count ];
|
||||||
|
int read = m_reader.read( chars );
|
||||||
|
|
||||||
|
return read < 0 ? null : new Object[] { new String( chars, 0, read ) };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If we've got a large count, read in bunches of 8192.
|
||||||
|
char[] buffer = new char[ BUFFER_SIZE ];
|
||||||
|
|
||||||
|
// Read the initial set of characters, failing if none are read.
|
||||||
|
int read = m_reader.read( buffer, 0, Math.min( buffer.length, count ) );
|
||||||
|
if( read == -1 ) return null;
|
||||||
|
|
||||||
|
StringBuilder out = new StringBuilder( read );
|
||||||
|
count -= read;
|
||||||
|
out.append( buffer, 0, read );
|
||||||
|
|
||||||
|
// Otherwise read until we either reach the limit or we no longer consume
|
||||||
|
// the full buffer.
|
||||||
|
while( read >= BUFFER_SIZE && count > 0 )
|
||||||
|
{
|
||||||
|
read = m_reader.read( buffer, 0, Math.min( BUFFER_SIZE, count ) );
|
||||||
|
if( read == -1 ) break;
|
||||||
|
count -= read;
|
||||||
|
out.append( buffer, 0, read );
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Object[] { out.toString() };
|
||||||
}
|
}
|
||||||
char[] bytes = new char[ count ];
|
|
||||||
count = m_reader.read( bytes );
|
|
||||||
if( count < 0 ) return null;
|
|
||||||
String str = new String( bytes, 0, count );
|
|
||||||
return new Object[] { str };
|
|
||||||
}
|
}
|
||||||
catch( IOException e )
|
catch( IOException e )
|
||||||
{
|
{
|
||||||
|
@@ -15,6 +15,7 @@ import dan200.computercraft.api.lua.LuaException;
|
|||||||
import dan200.computercraft.core.apis.IAPIEnvironment;
|
import dan200.computercraft.core.apis.IAPIEnvironment;
|
||||||
import dan200.computercraft.core.apis.handles.BinaryInputHandle;
|
import dan200.computercraft.core.apis.handles.BinaryInputHandle;
|
||||||
import dan200.computercraft.core.apis.handles.EncodedInputHandle;
|
import dan200.computercraft.core.apis.handles.EncodedInputHandle;
|
||||||
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@@ -78,8 +79,10 @@ public class HTTPRequest implements Runnable
|
|||||||
private final String m_postText;
|
private final String m_postText;
|
||||||
private final Map<String, String> m_headers;
|
private final Map<String, String> m_headers;
|
||||||
private boolean m_binary;
|
private boolean m_binary;
|
||||||
|
private final String m_method;
|
||||||
|
private final boolean m_followRedirects;
|
||||||
|
|
||||||
public HTTPRequest( IAPIEnvironment environment, String urlString, URL url, final String postText, final Map<String, String> headers, boolean binary ) throws HTTPRequestException
|
public HTTPRequest( IAPIEnvironment environment, String urlString, URL url, final String postText, final Map<String, String> headers, boolean binary, final String method, final boolean followRedirects ) throws HTTPRequestException
|
||||||
{
|
{
|
||||||
m_environment = environment;
|
m_environment = environment;
|
||||||
m_urlString = urlString;
|
m_urlString = urlString;
|
||||||
@@ -87,6 +90,8 @@ public class HTTPRequest implements Runnable
|
|||||||
m_binary = binary;
|
m_binary = binary;
|
||||||
m_postText = postText;
|
m_postText = postText;
|
||||||
m_headers = headers;
|
m_headers = headers;
|
||||||
|
m_method = method;
|
||||||
|
m_followRedirects = followRedirects;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -101,7 +106,7 @@ public class HTTPRequest implements Runnable
|
|||||||
{
|
{
|
||||||
// Queue the failure event if not.
|
// Queue the failure event if not.
|
||||||
String error = e.getMessage();
|
String error = e.getMessage();
|
||||||
m_environment.queueEvent( "http_failure", new Object[] { m_urlString, error == null ? "Could not connect" : error, null } );
|
m_environment.queueEvent( "http_failure", new Object[]{ m_urlString, error == null ? "Could not connect" : error, null } );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +124,8 @@ public class HTTPRequest implements Runnable
|
|||||||
{
|
{
|
||||||
connection.setRequestMethod( "GET" );
|
connection.setRequestMethod( "GET" );
|
||||||
}
|
}
|
||||||
|
if( m_method != null ) connection.setRequestMethod( m_method );
|
||||||
|
connection.setInstanceFollowRedirects( m_followRedirects );
|
||||||
|
|
||||||
// Set headers
|
// Set headers
|
||||||
connection.setRequestProperty( "accept-charset", "UTF-8" );
|
connection.setRequestProperty( "accept-charset", "UTF-8" );
|
||||||
@@ -134,6 +141,11 @@ public class HTTPRequest implements Runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add request size and count to the tracker before opening the connection
|
||||||
|
m_environment.addTrackingChange( TrackingField.HTTP_REQUESTS );
|
||||||
|
m_environment.addTrackingChange( TrackingField.HTTP_UPLOAD,
|
||||||
|
getHeaderSize( connection.getRequestProperties() ) + (m_postText == null ? 0 : m_postText.length()) );
|
||||||
|
|
||||||
// Send POST text
|
// Send POST text
|
||||||
if( m_postText != null )
|
if( m_postText != null )
|
||||||
{
|
{
|
||||||
@@ -178,6 +190,9 @@ public class HTTPRequest implements Runnable
|
|||||||
headers.put( header.getKey(), joiner.join( header.getValue() ) );
|
headers.put( header.getKey(), joiner.join( header.getValue() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_environment.addTrackingChange( TrackingField.HTTP_DOWNLOAD,
|
||||||
|
getHeaderSize( connection.getHeaderFields() ) + result.length );
|
||||||
|
|
||||||
InputStream contents = new ByteArrayInputStream( result );
|
InputStream contents = new ByteArrayInputStream( result );
|
||||||
ILuaObject stream = wrapStream(
|
ILuaObject stream = wrapStream(
|
||||||
m_binary ? new BinaryInputHandle( contents ) : new EncodedInputHandle( contents, connection.getContentEncoding() ),
|
m_binary ? new BinaryInputHandle( contents ) : new EncodedInputHandle( contents, connection.getContentEncoding() ),
|
||||||
@@ -189,17 +204,17 @@ public class HTTPRequest implements Runnable
|
|||||||
// Queue the appropriate event.
|
// Queue the appropriate event.
|
||||||
if( responseSuccess )
|
if( responseSuccess )
|
||||||
{
|
{
|
||||||
m_environment.queueEvent( "http_success", new Object[] { m_urlString, stream } );
|
m_environment.queueEvent( "http_success", new Object[]{ m_urlString, stream } );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_environment.queueEvent( "http_failure", new Object[] { m_urlString, "Could not connect", stream } );
|
m_environment.queueEvent( "http_failure", new Object[]{ m_urlString, "Could not connect", stream } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch( IOException e )
|
catch( IOException e )
|
||||||
{
|
{
|
||||||
// There was an error
|
// There was an error
|
||||||
m_environment.queueEvent( "http_failure", new Object[] { m_urlString, "Could not connect", null } );
|
m_environment.queueEvent( "http_failure", new Object[]{ m_urlString, "Could not connect", null } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,8 +224,8 @@ public class HTTPRequest implements Runnable
|
|||||||
final int methodOffset = oldMethods.length;
|
final int methodOffset = oldMethods.length;
|
||||||
|
|
||||||
final String[] newMethods = Arrays.copyOf( oldMethods, oldMethods.length + 2 );
|
final String[] newMethods = Arrays.copyOf( oldMethods, oldMethods.length + 2 );
|
||||||
newMethods[ methodOffset + 0 ] = "getResponseCode";
|
newMethods[methodOffset + 0] = "getResponseCode";
|
||||||
newMethods[ methodOffset + 1 ] = "getResponseHeaders";
|
newMethods[methodOffset + 1] = "getResponseHeaders";
|
||||||
|
|
||||||
return new ILuaObject()
|
return new ILuaObject()
|
||||||
{
|
{
|
||||||
@@ -233,12 +248,12 @@ public class HTTPRequest implements Runnable
|
|||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
// getResponseCode
|
// getResponseCode
|
||||||
return new Object[] { responseCode };
|
return new Object[]{ responseCode };
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// getResponseHeaders
|
// getResponseHeaders
|
||||||
return new Object[] { responseHeaders };
|
return new Object[]{ responseHeaders };
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -248,4 +263,15 @@ public class HTTPRequest implements Runnable
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static long getHeaderSize( Map<String, List<String>> headers )
|
||||||
|
{
|
||||||
|
long size = 0;
|
||||||
|
for( Map.Entry<String, List<String>> header : headers.entrySet() )
|
||||||
|
{
|
||||||
|
size += header.getKey() == null ? 0 : header.getKey().length();
|
||||||
|
for( String value : header.getValue() ) size += value == null ? 0 : value.length() + 1;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@ import dan200.computercraft.api.lua.ILuaObject;
|
|||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.core.apis.HTTPAPI;
|
import dan200.computercraft.core.apis.HTTPAPI;
|
||||||
import dan200.computercraft.core.apis.IAPIEnvironment;
|
import dan200.computercraft.core.apis.IAPIEnvironment;
|
||||||
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
@@ -71,7 +72,7 @@ public class WebsocketConnection extends SimpleChannelInboundHandler<Object> imp
|
|||||||
private void onClosed()
|
private void onClosed()
|
||||||
{
|
{
|
||||||
close( true );
|
close( true );
|
||||||
computer.queueEvent( CLOSE_EVENT, new Object[] { url } );
|
computer.queueEvent( CLOSE_EVENT, new Object[]{ url } );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -102,7 +103,7 @@ public class WebsocketConnection extends SimpleChannelInboundHandler<Object> imp
|
|||||||
if( !handshaker.isHandshakeComplete() )
|
if( !handshaker.isHandshakeComplete() )
|
||||||
{
|
{
|
||||||
handshaker.finishHandshake( ch, (FullHttpResponse) msg );
|
handshaker.finishHandshake( ch, (FullHttpResponse) msg );
|
||||||
computer.queueEvent( SUCCESS_EVENT, new Object[] { url, this } );
|
computer.queueEvent( SUCCESS_EVENT, new Object[]{ url, this } );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,14 +116,19 @@ public class WebsocketConnection extends SimpleChannelInboundHandler<Object> imp
|
|||||||
WebSocketFrame frame = (WebSocketFrame) msg;
|
WebSocketFrame frame = (WebSocketFrame) msg;
|
||||||
if( frame instanceof TextWebSocketFrame )
|
if( frame instanceof TextWebSocketFrame )
|
||||||
{
|
{
|
||||||
computer.queueEvent( MESSAGE_EVENT, new Object[] { url, ((TextWebSocketFrame) frame).text() } );
|
String data = ((TextWebSocketFrame) frame).text();
|
||||||
|
|
||||||
|
computer.addTrackingChange( TrackingField.WEBSOCKET_INCOMING, data.length() );
|
||||||
|
computer.queueEvent( MESSAGE_EVENT, new Object[]{ url, data } );
|
||||||
}
|
}
|
||||||
else if( frame instanceof BinaryWebSocketFrame )
|
else if( frame instanceof BinaryWebSocketFrame )
|
||||||
{
|
{
|
||||||
ByteBuf data = frame.content();
|
ByteBuf data = frame.content();
|
||||||
byte[] converted = new byte[ data.readableBytes() ];
|
byte[] converted = new byte[data.readableBytes()];
|
||||||
data.readBytes( converted );
|
data.readBytes( converted );
|
||||||
computer.queueEvent( MESSAGE_EVENT, new Object[] { url, data } );
|
|
||||||
|
computer.addTrackingChange( TrackingField.WEBSOCKET_INCOMING, converted.length );
|
||||||
|
computer.queueEvent( MESSAGE_EVENT, new Object[]{ url, converted } );
|
||||||
}
|
}
|
||||||
else if( frame instanceof CloseWebSocketFrame )
|
else if( frame instanceof CloseWebSocketFrame )
|
||||||
{
|
{
|
||||||
@@ -135,7 +141,7 @@ public class WebsocketConnection extends SimpleChannelInboundHandler<Object> imp
|
|||||||
public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause )
|
public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause )
|
||||||
{
|
{
|
||||||
ctx.close();
|
ctx.close();
|
||||||
computer.queueEvent( FAILURE_EVENT, new Object[] {
|
computer.queueEvent( FAILURE_EVENT, new Object[]{
|
||||||
url,
|
url,
|
||||||
cause instanceof WebSocketHandshakeException ? cause.getMessage() : "Could not connect"
|
cause instanceof WebSocketHandshakeException ? cause.getMessage() : "Could not connect"
|
||||||
} );
|
} );
|
||||||
@@ -145,7 +151,7 @@ public class WebsocketConnection extends SimpleChannelInboundHandler<Object> imp
|
|||||||
@Override
|
@Override
|
||||||
public String[] getMethodNames()
|
public String[] getMethodNames()
|
||||||
{
|
{
|
||||||
return new String[] { "receive", "send", "close" };
|
return new String[]{ "receive", "send", "close" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -159,15 +165,16 @@ public class WebsocketConnection extends SimpleChannelInboundHandler<Object> imp
|
|||||||
{
|
{
|
||||||
checkOpen();
|
checkOpen();
|
||||||
Object[] event = context.pullEvent( MESSAGE_EVENT );
|
Object[] event = context.pullEvent( MESSAGE_EVENT );
|
||||||
if( event.length >= 3 && Objects.equal( event[ 1 ], url ) )
|
if( event.length >= 3 && Objects.equal( event[1], url ) )
|
||||||
{
|
{
|
||||||
return new Object[] { event[ 2 ] };
|
return new Object[]{ event[2] };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
checkOpen();
|
checkOpen();
|
||||||
String text = arguments.length > 0 && arguments[ 0 ] != null ? arguments[ 0 ].toString() : "";
|
String text = arguments.length > 0 && arguments[0] != null ? arguments[0].toString() : "";
|
||||||
|
computer.addTrackingChange( TrackingField.WEBSOCKET_OUTGOING, text.length() );
|
||||||
channel.writeAndFlush( new TextWebSocketFrame( text ) );
|
channel.writeAndFlush( new TextWebSocketFrame( text ) );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ import io.netty.handler.codec.http.HttpObjectAggregator;
|
|||||||
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
|
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
|
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
|
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
|
||||||
|
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SslContextBuilder;
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ import java.security.KeyStore;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Provides functionality to verify and connect to a remote websocket.
|
* Provides functionality to verify and connect to a remote websocket.
|
||||||
*/
|
*/
|
||||||
public final class WebsocketConnector
|
public final class WebsocketConnector
|
||||||
@@ -177,7 +178,7 @@ public final class WebsocketConnector
|
|||||||
httpHeaders.add( header.getKey(), header.getValue() );
|
httpHeaders.add( header.getKey(), header.getValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker( uri, WebSocketVersion.V13, null, false, httpHeaders );
|
WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker( uri, WebSocketVersion.V13, null, true, httpHeaders );
|
||||||
final WebsocketConnection connection = new WebsocketConnection( environment, api, handshaker, address );
|
final WebsocketConnection connection = new WebsocketConnection( environment, api, handshaker, address );
|
||||||
|
|
||||||
new Bootstrap()
|
new Bootstrap()
|
||||||
@@ -190,7 +191,12 @@ public final class WebsocketConnector
|
|||||||
{
|
{
|
||||||
ChannelPipeline p = ch.pipeline();
|
ChannelPipeline p = ch.pipeline();
|
||||||
if( ssl != null ) p.addLast( ssl.newHandler( ch.alloc(), uri.getHost(), port ) );
|
if( ssl != null ) p.addLast( ssl.newHandler( ch.alloc(), uri.getHost(), port ) );
|
||||||
p.addLast( new HttpClientCodec(), new HttpObjectAggregator( 8192 ), connection );
|
p.addLast(
|
||||||
|
new HttpClientCodec(),
|
||||||
|
new HttpObjectAggregator( 8192 ),
|
||||||
|
WebSocketClientCompressionHandler.INSTANCE,
|
||||||
|
connection
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} )
|
} )
|
||||||
.remoteAddress( socketAddress )
|
.remoteAddress( socketAddress )
|
||||||
|
@@ -20,6 +20,8 @@ import dan200.computercraft.core.filesystem.FileSystemException;
|
|||||||
import dan200.computercraft.core.lua.CobaltLuaMachine;
|
import dan200.computercraft.core.lua.CobaltLuaMachine;
|
||||||
import dan200.computercraft.core.lua.ILuaMachine;
|
import dan200.computercraft.core.lua.ILuaMachine;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
|
import dan200.computercraft.core.tracking.Tracking;
|
||||||
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -167,6 +169,12 @@ public class Computer
|
|||||||
m_computer.setLabel( label );
|
m_computer.setLabel( label );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTrackingChange( TrackingField field, long change )
|
||||||
|
{
|
||||||
|
Tracking.addValue( m_computer, field, change );
|
||||||
|
}
|
||||||
|
|
||||||
public void onPeripheralChanged( int side, IPeripheral peripheral )
|
public void onPeripheralChanged( int side, IPeripheral peripheral )
|
||||||
{
|
{
|
||||||
synchronized( m_computer.m_peripherals )
|
synchronized( m_computer.m_peripherals )
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
package dan200.computercraft.core.computer;
|
package dan200.computercraft.core.computer;
|
||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.core.tracking.Tracking;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -68,17 +69,17 @@ public class ComputerThread
|
|||||||
s_stopped = false;
|
s_stopped = false;
|
||||||
if( s_threads == null || s_threads.length != ComputerCraft.computer_threads )
|
if( s_threads == null || s_threads.length != ComputerCraft.computer_threads )
|
||||||
{
|
{
|
||||||
s_threads = new Thread[ ComputerCraft.computer_threads ];
|
s_threads = new Thread[ComputerCraft.computer_threads];
|
||||||
}
|
}
|
||||||
|
|
||||||
SecurityManager manager = System.getSecurityManager();
|
SecurityManager manager = System.getSecurityManager();
|
||||||
final ThreadGroup group = manager == null ? Thread.currentThread().getThreadGroup() : manager.getThreadGroup();
|
final ThreadGroup group = manager == null ? Thread.currentThread().getThreadGroup() : manager.getThreadGroup();
|
||||||
for( int i = 0; i < s_threads.length; i++ )
|
for( int i = 0; i < s_threads.length; i++ )
|
||||||
{
|
{
|
||||||
Thread thread = s_threads[ i ];
|
Thread thread = s_threads[i];
|
||||||
if( thread == null || !thread.isAlive() )
|
if( thread == null || !thread.isAlive() )
|
||||||
{
|
{
|
||||||
thread = s_threads[ i ] = new Thread( group, new TaskExecutor(), "ComputerCraft-Computer-Manager-" + s_ManagerCounter.getAndIncrement() );
|
thread = s_threads[i] = new Thread( group, new TaskExecutor(), "ComputerCraft-Computer-Manager-" + s_ManagerCounter.getAndIncrement() );
|
||||||
thread.setDaemon( true );
|
thread.setDaemon( true );
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
@@ -223,6 +224,23 @@ public class ComputerThread
|
|||||||
// Interrupt the thread
|
// Interrupt the thread
|
||||||
if( !done )
|
if( !done )
|
||||||
{
|
{
|
||||||
|
StringBuilder builder = new StringBuilder( "Terminating " );
|
||||||
|
if( computer != null )
|
||||||
|
{
|
||||||
|
builder.append( "computer " ).append( computer.getID() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.append( "unknown computer" );
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.append( ". Thread is currently running" );
|
||||||
|
for( StackTraceElement element : thread.getStackTrace() )
|
||||||
|
{
|
||||||
|
builder.append( "\n at " ).append( element );
|
||||||
|
}
|
||||||
|
ComputerCraft.log.error( builder.toString() );
|
||||||
|
|
||||||
thread.interrupt();
|
thread.interrupt();
|
||||||
thread = null;
|
thread = null;
|
||||||
runner = null;
|
runner = null;
|
||||||
@@ -233,8 +251,8 @@ public class ComputerThread
|
|||||||
{
|
{
|
||||||
long stop = System.nanoTime();
|
long stop = System.nanoTime();
|
||||||
Computer computer = task.getOwner();
|
Computer computer = task.getOwner();
|
||||||
if( computer != null ) ComputerTimeTracker.addTiming( computer, stop - start );
|
if( computer != null ) Tracking.addTaskTiming( computer, stop - start );
|
||||||
|
|
||||||
// Re-add it back onto the queue or remove it
|
// Re-add it back onto the queue or remove it
|
||||||
synchronized( s_taskLock )
|
synchronized( s_taskLock )
|
||||||
{
|
{
|
||||||
|
@@ -1,116 +0,0 @@
|
|||||||
package dan200.computercraft.core.computer;
|
|
||||||
|
|
||||||
import com.google.common.collect.MapMaker;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tracks timing information about computers, including how long they ran for
|
|
||||||
* and the number of events they handled.
|
|
||||||
*
|
|
||||||
* Note that this <em>will</em> track computers which have been deleted (hence
|
|
||||||
* the presence of {@link #timingLookup} and {@link #timings}
|
|
||||||
*/
|
|
||||||
public class ComputerTimeTracker
|
|
||||||
{
|
|
||||||
public static class Timings
|
|
||||||
{
|
|
||||||
private final WeakReference<Computer> computer;
|
|
||||||
private final int computerId;
|
|
||||||
|
|
||||||
private int tasks;
|
|
||||||
|
|
||||||
private long totalTime;
|
|
||||||
private long maxTime;
|
|
||||||
|
|
||||||
public Timings( @Nonnull Computer computer )
|
|
||||||
{
|
|
||||||
this.computer = new WeakReference<>( computer );
|
|
||||||
this.computerId = computer.getID();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Computer getComputer()
|
|
||||||
{
|
|
||||||
return computer.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getComputerId()
|
|
||||||
{
|
|
||||||
return computerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTasks()
|
|
||||||
{
|
|
||||||
return tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalTime()
|
|
||||||
{
|
|
||||||
return totalTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getMaxTime()
|
|
||||||
{
|
|
||||||
return maxTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getAverage()
|
|
||||||
{
|
|
||||||
return totalTime / (double) tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update( long time )
|
|
||||||
{
|
|
||||||
tasks++;
|
|
||||||
totalTime += time;
|
|
||||||
if( time > maxTime ) maxTime = time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean tracking;
|
|
||||||
private static final List<Timings> timings = new ArrayList<>();
|
|
||||||
private static final Map<Computer, Timings> timingLookup = new MapMaker().weakKeys().makeMap();
|
|
||||||
|
|
||||||
public synchronized static void start()
|
|
||||||
{
|
|
||||||
tracking = true;
|
|
||||||
|
|
||||||
timings.clear();
|
|
||||||
timingLookup.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized static boolean stop()
|
|
||||||
{
|
|
||||||
if( !tracking ) return false;
|
|
||||||
|
|
||||||
tracking = false;
|
|
||||||
timingLookup.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized List<Timings> getTimings()
|
|
||||||
{
|
|
||||||
return new ArrayList<>( timings );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void addTiming( Computer computer, long time )
|
|
||||||
{
|
|
||||||
if( !tracking ) return;
|
|
||||||
|
|
||||||
Timings timings = ComputerTimeTracker.timingLookup.get( computer );
|
|
||||||
if( timings == null )
|
|
||||||
{
|
|
||||||
timings = new Timings( computer );
|
|
||||||
timingLookup.put( computer, timings );
|
|
||||||
ComputerTimeTracker.timings.add( timings );
|
|
||||||
}
|
|
||||||
|
|
||||||
timings.update( time );
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,9 @@
|
|||||||
|
package dan200.computercraft.core.computer;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public interface IComputerOwned
|
||||||
|
{
|
||||||
|
@Nullable
|
||||||
|
Computer getComputer();
|
||||||
|
}
|
@@ -6,14 +6,17 @@
|
|||||||
|
|
||||||
package dan200.computercraft.core.computer;
|
package dan200.computercraft.core.computer;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import dan200.computercraft.core.tracking.Tracking;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
public class MainThread
|
public class MainThread
|
||||||
{
|
{
|
||||||
private static final int MAX_TASKS_PER_TICK = 1000;
|
private static final int MAX_TASKS_PER_TICK = 1000;
|
||||||
private static final int MAX_TASKS_TOTAL = 50000;
|
private static final int MAX_TASKS_TOTAL = 50000;
|
||||||
|
|
||||||
private static final LinkedList<ITask> m_outstandingTasks = new LinkedList<>();
|
private static final Queue<ITask> m_outstandingTasks = new ArrayDeque<>();
|
||||||
private static final Object m_nextUnusedTaskIDLock = new Object();
|
private static final Object m_nextUnusedTaskIDLock = new Object();
|
||||||
private static long m_nextUnusedTaskID = 0;
|
private static long m_nextUnusedTaskID = 0;
|
||||||
|
|
||||||
@@ -31,7 +34,7 @@ public class MainThread
|
|||||||
{
|
{
|
||||||
if( m_outstandingTasks.size() < MAX_TASKS_TOTAL )
|
if( m_outstandingTasks.size() < MAX_TASKS_TOTAL )
|
||||||
{
|
{
|
||||||
m_outstandingTasks.addLast( task );
|
m_outstandingTasks.offer( task );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,14 +49,17 @@ public class MainThread
|
|||||||
ITask task = null;
|
ITask task = null;
|
||||||
synchronized( m_outstandingTasks )
|
synchronized( m_outstandingTasks )
|
||||||
{
|
{
|
||||||
if( m_outstandingTasks.size() > 0 )
|
task = m_outstandingTasks.poll();
|
||||||
{
|
|
||||||
task = m_outstandingTasks.removeFirst();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if( task != null )
|
if( task != null )
|
||||||
{
|
{
|
||||||
|
long start = System.nanoTime();
|
||||||
task.execute();
|
task.execute();
|
||||||
|
|
||||||
|
long stop = System.nanoTime();
|
||||||
|
Computer computer = task.getOwner();
|
||||||
|
if( computer != null ) Tracking.addServerTiming( computer, stop - start );
|
||||||
|
|
||||||
++tasksThisTick;
|
++tasksThisTick;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@@ -0,0 +1,117 @@
|
|||||||
|
package dan200.computercraft.core.tracking;
|
||||||
|
|
||||||
|
import dan200.computercraft.core.computer.Computer;
|
||||||
|
import gnu.trove.map.hash.TObjectLongHashMap;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
public class ComputerTracker
|
||||||
|
{
|
||||||
|
private final WeakReference<Computer> computer;
|
||||||
|
private final int computerId;
|
||||||
|
|
||||||
|
private long tasks;
|
||||||
|
private long totalTime;
|
||||||
|
private long maxTime;
|
||||||
|
|
||||||
|
private long serverCount;
|
||||||
|
private long serverTime;
|
||||||
|
|
||||||
|
private final TObjectLongHashMap<TrackingField> fields;
|
||||||
|
|
||||||
|
public ComputerTracker( Computer computer )
|
||||||
|
{
|
||||||
|
this.computer = new WeakReference<>( computer );
|
||||||
|
this.computerId = computer.getID();
|
||||||
|
this.fields = new TObjectLongHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ComputerTracker( ComputerTracker timings )
|
||||||
|
{
|
||||||
|
this.computer = timings.computer;
|
||||||
|
this.computerId = timings.computerId;
|
||||||
|
|
||||||
|
this.tasks = timings.tasks;
|
||||||
|
this.totalTime = timings.totalTime;
|
||||||
|
this.maxTime = timings.maxTime;
|
||||||
|
|
||||||
|
this.serverCount = timings.serverCount;
|
||||||
|
this.serverTime = timings.serverTime;
|
||||||
|
|
||||||
|
this.fields = new TObjectLongHashMap<>( timings.fields );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Computer getComputer()
|
||||||
|
{
|
||||||
|
return computer.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getComputerId()
|
||||||
|
{
|
||||||
|
return computerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTasks()
|
||||||
|
{
|
||||||
|
return tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalTime()
|
||||||
|
{
|
||||||
|
return totalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMaxTime()
|
||||||
|
{
|
||||||
|
return maxTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getAverage()
|
||||||
|
{
|
||||||
|
return totalTime / tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTaskTiming( long time )
|
||||||
|
{
|
||||||
|
tasks++;
|
||||||
|
totalTime += time;
|
||||||
|
if( time > maxTime ) maxTime = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addMainTiming( long time )
|
||||||
|
{
|
||||||
|
serverCount++;
|
||||||
|
serverTime += time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addValue( TrackingField field, long change )
|
||||||
|
{
|
||||||
|
synchronized( fields )
|
||||||
|
{
|
||||||
|
fields.adjustOrPutValue( field, change, change );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long get( TrackingField field )
|
||||||
|
{
|
||||||
|
if( field == TrackingField.TASKS ) return tasks;
|
||||||
|
if( field == TrackingField.MAX_TIME ) return maxTime;
|
||||||
|
if( field == TrackingField.TOTAL_TIME ) return totalTime;
|
||||||
|
if( field == TrackingField.AVERAGE_TIME ) return tasks == 0 ? 0 : totalTime / tasks;
|
||||||
|
|
||||||
|
if( field == TrackingField.SERVER_COUNT ) return serverCount;
|
||||||
|
if( field == TrackingField.SERVER_TIME ) return serverTime;
|
||||||
|
|
||||||
|
synchronized( fields )
|
||||||
|
{
|
||||||
|
return fields.get( field );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFormatted( TrackingField field )
|
||||||
|
{
|
||||||
|
return field.format( get( field ) );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,49 @@
|
|||||||
|
package dan200.computercraft.core.tracking;
|
||||||
|
|
||||||
|
import dan200.computercraft.core.computer.Computer;
|
||||||
|
|
||||||
|
public interface Tracker
|
||||||
|
{
|
||||||
|
@Deprecated
|
||||||
|
default void addTiming( Computer computer, long time )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report how long a task executed on the computer thread took.
|
||||||
|
*
|
||||||
|
* Computer thread tasks include events or a computer being turned on/off.
|
||||||
|
*
|
||||||
|
* @param computer The computer processing this task
|
||||||
|
* @param time The time taken for this task.
|
||||||
|
*/
|
||||||
|
default void addTaskTiming( Computer computer, long time )
|
||||||
|
{
|
||||||
|
//noinspection deprecation
|
||||||
|
addTiming( computer, time );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report how long a task executed on the server thread took.
|
||||||
|
*
|
||||||
|
* Server tasks include actions performed by peripherals.
|
||||||
|
*
|
||||||
|
* @param computer The computer processing this task
|
||||||
|
* @param time The time taken for this task.
|
||||||
|
*/
|
||||||
|
default void addServerTiming( Computer computer, long time )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment an arbitrary field by some value. Implementations may track how often this is called
|
||||||
|
* as well as the change, to compute some level of "average".
|
||||||
|
*
|
||||||
|
* @param computer The computer to increment
|
||||||
|
* @param field The field to increment.
|
||||||
|
* @param change The amount to increment said field by.
|
||||||
|
*/
|
||||||
|
default void addValue( Computer computer, TrackingField field, long change )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,80 @@
|
|||||||
|
package dan200.computercraft.core.tracking;
|
||||||
|
|
||||||
|
import dan200.computercraft.core.computer.Computer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class Tracking
|
||||||
|
{
|
||||||
|
static final AtomicInteger tracking = new AtomicInteger( 0 );
|
||||||
|
|
||||||
|
private static final Object lock = new Object();
|
||||||
|
private static final HashMap<UUID, TrackingContext> contexts = new HashMap<>();
|
||||||
|
private static final List<Tracker> trackers = new ArrayList<>();
|
||||||
|
|
||||||
|
public static TrackingContext getContext( UUID uuid )
|
||||||
|
{
|
||||||
|
synchronized( lock )
|
||||||
|
{
|
||||||
|
TrackingContext context = contexts.get( uuid );
|
||||||
|
if( context == null ) contexts.put( uuid, context = new TrackingContext() );
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void add( Tracker tracker )
|
||||||
|
{
|
||||||
|
synchronized( lock )
|
||||||
|
{
|
||||||
|
trackers.add( tracker );
|
||||||
|
tracking.incrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addTaskTiming( Computer computer, long time )
|
||||||
|
{
|
||||||
|
if( tracking.get() == 0 ) return;
|
||||||
|
|
||||||
|
synchronized( contexts )
|
||||||
|
{
|
||||||
|
for( TrackingContext context : contexts.values() ) context.addTaskTiming( computer, time );
|
||||||
|
for( Tracker tracker : trackers ) tracker.addTaskTiming( computer, time );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addServerTiming( Computer computer, long time )
|
||||||
|
{
|
||||||
|
if( tracking.get() == 0 ) return;
|
||||||
|
|
||||||
|
synchronized( contexts )
|
||||||
|
{
|
||||||
|
for( TrackingContext context : contexts.values() ) context.addServerTiming( computer, time );
|
||||||
|
for( Tracker tracker : trackers ) tracker.addServerTiming( computer, time );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addValue( Computer computer, TrackingField field, long change )
|
||||||
|
{
|
||||||
|
if( tracking.get() == 0 ) return;
|
||||||
|
|
||||||
|
synchronized( lock )
|
||||||
|
{
|
||||||
|
for( TrackingContext context : contexts.values() ) context.addValue( computer, field, change );
|
||||||
|
for( Tracker tracker : trackers ) tracker.addValue( computer, field, change );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void reset()
|
||||||
|
{
|
||||||
|
synchronized( lock )
|
||||||
|
{
|
||||||
|
contexts.clear();
|
||||||
|
trackers.clear();
|
||||||
|
tracking.set( 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,111 @@
|
|||||||
|
package dan200.computercraft.core.tracking;
|
||||||
|
|
||||||
|
import com.google.common.collect.MapMaker;
|
||||||
|
import dan200.computercraft.core.computer.Computer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks timing information about computers, including how long they ran for
|
||||||
|
* and the number of events they handled.
|
||||||
|
*
|
||||||
|
* Note that this <em>will</em> track computers which have been deleted (hence
|
||||||
|
* the presence of {@link #timingLookup} and {@link #timings}
|
||||||
|
*/
|
||||||
|
public class TrackingContext implements Tracker
|
||||||
|
{
|
||||||
|
private boolean tracking = false;
|
||||||
|
|
||||||
|
private final List<ComputerTracker> timings = new ArrayList<>();
|
||||||
|
private final Map<Computer, ComputerTracker> timingLookup = new MapMaker().weakKeys().makeMap();
|
||||||
|
|
||||||
|
public synchronized void start()
|
||||||
|
{
|
||||||
|
if( !tracking ) Tracking.tracking.incrementAndGet();
|
||||||
|
tracking = true;
|
||||||
|
|
||||||
|
timings.clear();
|
||||||
|
timingLookup.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean stop()
|
||||||
|
{
|
||||||
|
if( !tracking ) return false;
|
||||||
|
|
||||||
|
Tracking.tracking.decrementAndGet();
|
||||||
|
tracking = false;
|
||||||
|
timingLookup.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized List<ComputerTracker> getImmutableTimings()
|
||||||
|
{
|
||||||
|
ArrayList<ComputerTracker> timings = new ArrayList<>( this.timings.size() );
|
||||||
|
for( ComputerTracker timing : this.timings ) timings.add( new ComputerTracker( timing ) );
|
||||||
|
return timings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized List<ComputerTracker> getTimings()
|
||||||
|
{
|
||||||
|
return new ArrayList<>( timings );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTaskTiming( Computer computer, long time )
|
||||||
|
{
|
||||||
|
if( !tracking ) return;
|
||||||
|
|
||||||
|
synchronized( this )
|
||||||
|
{
|
||||||
|
ComputerTracker computerTimings = timingLookup.get( computer );
|
||||||
|
if( computerTimings == null )
|
||||||
|
{
|
||||||
|
computerTimings = new ComputerTracker( computer );
|
||||||
|
timingLookup.put( computer, computerTimings );
|
||||||
|
timings.add( computerTimings );
|
||||||
|
}
|
||||||
|
|
||||||
|
computerTimings.addTaskTiming( time );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addServerTiming( Computer computer, long time )
|
||||||
|
{
|
||||||
|
if( !tracking ) return;
|
||||||
|
|
||||||
|
synchronized( this )
|
||||||
|
{
|
||||||
|
ComputerTracker computerTimings = timingLookup.get( computer );
|
||||||
|
if( computerTimings == null )
|
||||||
|
{
|
||||||
|
computerTimings = new ComputerTracker( computer );
|
||||||
|
timingLookup.put( computer, computerTimings );
|
||||||
|
timings.add( computerTimings );
|
||||||
|
}
|
||||||
|
|
||||||
|
computerTimings.addMainTiming( time );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addValue( Computer computer, TrackingField field, long change )
|
||||||
|
{
|
||||||
|
if( !tracking ) return;
|
||||||
|
|
||||||
|
synchronized( this )
|
||||||
|
{
|
||||||
|
ComputerTracker computerTimings = timingLookup.get( computer );
|
||||||
|
if( computerTimings == null )
|
||||||
|
{
|
||||||
|
computerTimings = new ComputerTracker( computer );
|
||||||
|
timingLookup.put( computer, computerTimings );
|
||||||
|
timings.add( computerTimings );
|
||||||
|
}
|
||||||
|
|
||||||
|
computerTimings.addValue( field, change );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,88 @@
|
|||||||
|
package dan200.computercraft.core.tracking;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.LongFunction;
|
||||||
|
|
||||||
|
public class TrackingField
|
||||||
|
{
|
||||||
|
private static final Map<String, TrackingField> fields = new HashMap<>();
|
||||||
|
|
||||||
|
public static final TrackingField TASKS = TrackingField.of( "tasks", "Tasks", x -> String.format( "%4d", x ) );
|
||||||
|
public static final TrackingField TOTAL_TIME = TrackingField.of( "total", "Total time", x -> String.format( "%7.1fms", x / 1e6 ) );
|
||||||
|
public static final TrackingField AVERAGE_TIME = TrackingField.of( "average", "Average time", x -> String.format( "%4.1fms", x / 1e6 ) );
|
||||||
|
public static final TrackingField MAX_TIME = TrackingField.of( "max", "Max time", x -> String.format( "%5.1fms", x / 1e6 ) );
|
||||||
|
|
||||||
|
public static final TrackingField SERVER_COUNT = TrackingField.of( "server_count", "Server task count", x -> String.format( "%4d", x ) );
|
||||||
|
public static final TrackingField SERVER_TIME = TrackingField.of( "server_time", "Server task time", x -> String.format( "%7.1fms", x / 1e6 ) );
|
||||||
|
|
||||||
|
public static final TrackingField PERIPHERAL_OPS = TrackingField.of( "peripheral", "Peripheral calls", TrackingField::formatDefault );
|
||||||
|
public static final TrackingField FS_OPS = TrackingField.of( "fs", "Filesystem operations", TrackingField::formatDefault );
|
||||||
|
public static final TrackingField TURTLE_OPS = TrackingField.of( "turtle", "Turtle operations", TrackingField::formatDefault );
|
||||||
|
|
||||||
|
public static final TrackingField HTTP_REQUESTS = TrackingField.of( "http", "HTTP requests", TrackingField::formatDefault );
|
||||||
|
public static final TrackingField HTTP_UPLOAD = TrackingField.of( "http_upload", "HTTP upload", TrackingField::formatBytes );
|
||||||
|
public static final TrackingField HTTP_DOWNLOAD = TrackingField.of( "http_download", "HTTT download", TrackingField::formatBytes );
|
||||||
|
|
||||||
|
public static final TrackingField WEBSOCKET_INCOMING = TrackingField.of( "websocket_incoming", "Websocket incoming", TrackingField::formatBytes );
|
||||||
|
public static final TrackingField WEBSOCKET_OUTGOING = TrackingField.of( "websocket_outgoing", "Websocket outgoing", TrackingField::formatBytes );
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final String displayName;
|
||||||
|
private final LongFunction<String> format;
|
||||||
|
|
||||||
|
public String id()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String displayName()
|
||||||
|
{
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrackingField( String id, String displayName, LongFunction<String> format )
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String format( long value )
|
||||||
|
{
|
||||||
|
return format.apply( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrackingField of( String id, String displayName, LongFunction<String> format )
|
||||||
|
{
|
||||||
|
TrackingField field = new TrackingField( id, displayName, format );
|
||||||
|
fields.put( id, field );
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, TrackingField> fields()
|
||||||
|
{
|
||||||
|
return Collections.unmodifiableMap( fields );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatDefault( long value )
|
||||||
|
{
|
||||||
|
return String.format( "%6d", value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* So technically a kibibyte, but let's not argue here.
|
||||||
|
*/
|
||||||
|
private static final int KILOBYTE_SIZE = 1024;
|
||||||
|
|
||||||
|
private static final String SI_PREFIXES = "KMGT";
|
||||||
|
|
||||||
|
private static String formatBytes( long bytes )
|
||||||
|
{
|
||||||
|
if( bytes < 1024 ) return String.format( "%10d B", bytes );
|
||||||
|
int exp = (int) (Math.log( bytes ) / Math.log( KILOBYTE_SIZE ));
|
||||||
|
if( exp > SI_PREFIXES.length() ) exp = SI_PREFIXES.length();
|
||||||
|
return String.format( "%10.1f %siB", bytes / Math.pow( KILOBYTE_SIZE, exp ), SI_PREFIXES.charAt( exp - 1 ) );
|
||||||
|
}
|
||||||
|
}
|
@@ -4,9 +4,13 @@ import com.google.common.collect.Sets;
|
|||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.computer.Computer;
|
import dan200.computercraft.core.computer.Computer;
|
||||||
import dan200.computercraft.core.computer.ComputerTimeTracker;
|
import dan200.computercraft.core.tracking.ComputerTracker;
|
||||||
|
import dan200.computercraft.core.tracking.Tracking;
|
||||||
|
import dan200.computercraft.core.tracking.TrackingContext;
|
||||||
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
import dan200.computercraft.shared.command.framework.*;
|
import dan200.computercraft.shared.command.framework.*;
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
|
import net.minecraft.command.CommandBase;
|
||||||
import net.minecraft.command.CommandException;
|
import net.minecraft.command.CommandException;
|
||||||
import net.minecraft.command.ICommandSender;
|
import net.minecraft.command.ICommandSender;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
@@ -16,15 +20,21 @@ import net.minecraft.util.math.BlockPos;
|
|||||||
import net.minecraft.util.text.ITextComponent;
|
import net.minecraft.util.text.ITextComponent;
|
||||||
import net.minecraft.util.text.TextComponentString;
|
import net.minecraft.util.text.TextComponentString;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.util.FakePlayer;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static dan200.computercraft.shared.command.framework.ChatHelpers.*;
|
import static dan200.computercraft.shared.command.framework.ChatHelpers.*;
|
||||||
|
|
||||||
public final class CommandComputerCraft extends CommandDelegate
|
public final class CommandComputerCraft extends CommandDelegate
|
||||||
{
|
{
|
||||||
|
public static final UUID SYSTEM_UUID = new UUID( 0, 0 );
|
||||||
|
|
||||||
|
private static final int DUMP_LIST_ID = 5373952;
|
||||||
|
private static final int DUMP_SINGLE_ID = 1844510720;
|
||||||
|
private static final int TRACK_ID = 373882880;
|
||||||
|
|
||||||
public CommandComputerCraft()
|
public CommandComputerCraft()
|
||||||
{
|
{
|
||||||
super( create() );
|
super( create() );
|
||||||
@@ -49,7 +59,7 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
{
|
{
|
||||||
if( arguments.size() == 0 )
|
if( arguments.size() == 0 )
|
||||||
{
|
{
|
||||||
TextTable table = new TextTable( "Instance", "Id", "On", "Position" );
|
TextTable table = new TextTable( DUMP_LIST_ID, "Computer", "On", "Position" );
|
||||||
|
|
||||||
List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
|
List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
|
||||||
|
|
||||||
@@ -82,8 +92,7 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
for( ServerComputer computer : computers )
|
for( ServerComputer computer : computers )
|
||||||
{
|
{
|
||||||
table.addRow(
|
table.addRow(
|
||||||
linkComputer( computer ),
|
linkComputer( context, computer, computer.getID() ),
|
||||||
text( Integer.toString( computer.getID() ) ),
|
|
||||||
bool( computer.isOn() ),
|
bool( computer.isOn() ),
|
||||||
linkPosition( context, computer )
|
linkPosition( context, computer )
|
||||||
);
|
);
|
||||||
@@ -95,7 +104,7 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
{
|
{
|
||||||
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
|
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
|
||||||
|
|
||||||
TextTable table = new TextTable();
|
TextTable table = new TextTable( DUMP_SINGLE_ID );
|
||||||
table.addRow( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
|
table.addRow( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
|
||||||
table.addRow( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
|
table.addRow( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
|
||||||
table.addRow( header( "Label" ), text( computer.getLabel() ) );
|
table.addRow( header( "Label" ), text( computer.getLabel() ) );
|
||||||
@@ -139,26 +148,15 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
@Override
|
@Override
|
||||||
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
{
|
{
|
||||||
Set<ServerComputer> computers = Sets.newHashSet();
|
withComputers( arguments, computers -> {
|
||||||
if( arguments.size() > 0 )
|
int shutdown = 0;
|
||||||
{
|
for( ServerComputer computer : computers )
|
||||||
for( String arg : arguments )
|
|
||||||
{
|
{
|
||||||
computers.addAll( ComputerSelector.getComputers( arg ) );
|
if( computer.isOn() ) shutdown++;
|
||||||
|
computer.unload();
|
||||||
}
|
}
|
||||||
}
|
context.getSender().sendMessage( text( "Shutdown " + shutdown + " / " + computers.size() + " computers" ) );
|
||||||
else
|
} );
|
||||||
{
|
|
||||||
computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() );
|
|
||||||
}
|
|
||||||
|
|
||||||
int shutdown = 0;
|
|
||||||
for( ServerComputer computer : computers )
|
|
||||||
{
|
|
||||||
if( computer.isOn() ) shutdown++;
|
|
||||||
computer.unload();
|
|
||||||
}
|
|
||||||
context.getSender().sendMessage( text( "Shutdown " + shutdown + " / " + computers.size() + " computers" ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@@ -180,26 +178,15 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
@Override
|
@Override
|
||||||
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
{
|
{
|
||||||
Set<ServerComputer> computers = Sets.newHashSet();
|
withComputers( arguments, computers -> {
|
||||||
if( arguments.size() > 0 )
|
int on = 0;
|
||||||
{
|
for( ServerComputer computer : computers )
|
||||||
for( String arg : arguments )
|
|
||||||
{
|
{
|
||||||
computers.addAll( ComputerSelector.getComputers( arg ) );
|
if( !computer.isOn() ) on++;
|
||||||
|
computer.turnOn();
|
||||||
}
|
}
|
||||||
}
|
context.getSender().sendMessage( text( "Turned on " + on + " / " + computers.size() + " computers" ) );
|
||||||
else
|
} );
|
||||||
{
|
|
||||||
computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() );
|
|
||||||
}
|
|
||||||
|
|
||||||
int on = 0;
|
|
||||||
for( ServerComputer computer : computers )
|
|
||||||
{
|
|
||||||
if( !computer.isOn() ) on++;
|
|
||||||
computer.turnOn();
|
|
||||||
}
|
|
||||||
context.getSender().sendMessage( text( "Turned on " + on + " / " + computers.size() + " computers" ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@@ -311,7 +298,7 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
@Override
|
@Override
|
||||||
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments )
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments )
|
||||||
{
|
{
|
||||||
ComputerTimeTracker.start();
|
getTimingContext( context ).start();
|
||||||
|
|
||||||
String stopCommand = "/" + context.parent().getFullPath() + " stop";
|
String stopCommand = "/" + context.parent().getFullPath() + " stop";
|
||||||
context.getSender().sendMessage( list(
|
context.getSender().sendMessage( list(
|
||||||
@@ -330,23 +317,54 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
@Override
|
@Override
|
||||||
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
{
|
{
|
||||||
if( !ComputerTimeTracker.stop() ) throw new CommandException( "Tracking not enabled" );
|
TrackingContext timings = getTimingContext( context );
|
||||||
displayTimings( context );
|
if( !timings.stop() ) throw new CommandException( "Tracking not enabled" );
|
||||||
|
displayTimings( context, timings.getImmutableTimings(), TrackingField.AVERAGE_TIME );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
track.register( new SubCommandBase(
|
track.register( new SubCommandBase(
|
||||||
"dump", "Dump the latest track results", UserLevel.OWNER_OP,
|
"dump", "[kind]", "Dump the latest track results", UserLevel.OWNER_OP,
|
||||||
"Dump the latest results of computer tracking."
|
"Dump the latest results of computer tracking."
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
{
|
{
|
||||||
displayTimings( context );
|
TrackingField field = TrackingField.AVERAGE_TIME;
|
||||||
|
if( arguments.size() >= 1 )
|
||||||
|
{
|
||||||
|
field = TrackingField.fields().get( arguments.get( 0 ) );
|
||||||
|
if( field == null ) throw new CommandException( "Unknown field '" + arguments.get( 0 ) + "'" );
|
||||||
|
}
|
||||||
|
|
||||||
|
displayTimings( context, getTimingContext( context ).getImmutableTimings(), field );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
|
||||||
|
{
|
||||||
|
if( arguments.size() == 1 )
|
||||||
|
{
|
||||||
|
String match = arguments.get( 0 );
|
||||||
|
|
||||||
|
List<String> out = new ArrayList<>();
|
||||||
|
for( String key : TrackingField.fields().keySet() )
|
||||||
|
{
|
||||||
|
if( CommandBase.doesStringStartWith( match, key ) ) out.add( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
out.sort( Comparator.naturalOrder() );
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return super.getCompletion( context, arguments );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
root.register( new SubCommandBase(
|
root.register( new SubCommandBase(
|
||||||
"reload", "Reload the ComputerCraft config file", UserLevel.OWNER_OP,
|
"reload", "Reload the ComputerCraft config file", UserLevel.OWNER_OP,
|
||||||
"Reload the ComputerCraft config file"
|
"Reload the ComputerCraft config file"
|
||||||
@@ -365,13 +383,46 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ITextComponent linkComputer( ServerComputer computer )
|
private static ITextComponent linkComputer( CommandContext context, ServerComputer serverComputer, int computerId )
|
||||||
{
|
{
|
||||||
return link(
|
ITextComponent out = new TextComponentString( "" );
|
||||||
text( Integer.toString( computer.getInstanceID() ) ),
|
|
||||||
"/computercraft dump " + computer.getInstanceID(),
|
// Append the computer instance
|
||||||
"View more info about this computer"
|
if( serverComputer == null )
|
||||||
);
|
{
|
||||||
|
out.appendSibling( text( "?" ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.appendSibling( link(
|
||||||
|
text( Integer.toString( serverComputer.getInstanceID() ) ),
|
||||||
|
"/computercraft dump " + serverComputer.getInstanceID(),
|
||||||
|
"View more info about this computer"
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// And ID
|
||||||
|
out.appendText( " (id " + computerId + ")" );
|
||||||
|
|
||||||
|
// And, if we're a player, some useful links
|
||||||
|
if( serverComputer != null && UserLevel.OP.canExecute( context ) && context.fromPlayer() )
|
||||||
|
{
|
||||||
|
out
|
||||||
|
.appendText( " " )
|
||||||
|
.appendSibling( link(
|
||||||
|
text( "\u261b" ),
|
||||||
|
"/computercraft tp " + serverComputer.getInstanceID(),
|
||||||
|
"Teleport to this computer"
|
||||||
|
) )
|
||||||
|
.appendText( " " )
|
||||||
|
.appendSibling( link(
|
||||||
|
text( "\u20e2" ),
|
||||||
|
"/computercraft view " + serverComputer.getInstanceID(),
|
||||||
|
"View this computer"
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ITextComponent linkPosition( CommandContext context, ServerComputer computer )
|
private static ITextComponent linkPosition( CommandContext context, ServerComputer computer )
|
||||||
@@ -390,13 +441,22 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void displayTimings( CommandContext context ) throws CommandException
|
private static TrackingContext getTimingContext( CommandContext context )
|
||||||
{
|
{
|
||||||
List<ComputerTimeTracker.Timings> timings = ComputerTimeTracker.getTimings();
|
Entity entity = context.getSender().getCommandSenderEntity();
|
||||||
if( timings.isEmpty() ) throw new CommandException( "No timings available" );
|
if( entity instanceof EntityPlayerMP )
|
||||||
|
{
|
||||||
|
return Tracking.getContext( entity.getUniqueID() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Tracking.getContext( SYSTEM_UUID );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
timings.sort( Comparator.comparing( ComputerTimeTracker.Timings::getAverage ).reversed() );
|
private static void displayTimings( CommandContext context, List<ComputerTracker> timings, TrackingField field ) throws CommandException
|
||||||
TextTable table = new TextTable( "Computer", "Tasks", "Total", "Average", "Maximum" );
|
{
|
||||||
|
if( timings.isEmpty() ) throw new CommandException( "No timings available" );
|
||||||
|
|
||||||
Map<Computer, ServerComputer> lookup = new HashMap<>();
|
Map<Computer, ServerComputer> lookup = new HashMap<>();
|
||||||
int maxId = 0, maxInstance = 0;
|
int maxId = 0, maxInstance = 0;
|
||||||
@@ -408,44 +468,65 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
if( server.getID() > maxId ) maxId = server.getID();
|
if( server.getID() > maxId ) maxId = server.getID();
|
||||||
}
|
}
|
||||||
|
|
||||||
ICommandSender sender = context.getSender();
|
timings.sort( Comparator.<ComputerTracker, Long>comparing( x -> x.get( field ) ).reversed() );
|
||||||
boolean isPlayer = sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
|
|
||||||
|
|
||||||
for( ComputerTimeTracker.Timings entry : timings )
|
boolean defaultLayout = field == TrackingField.TASKS || field == TrackingField.TOTAL_TIME
|
||||||
|
|| field == TrackingField.AVERAGE_TIME || field == TrackingField.MAX_TIME;
|
||||||
|
|
||||||
|
|
||||||
|
TextTable table = defaultLayout
|
||||||
|
? new TextTable( TRACK_ID, "Computer", "Tasks", "Total", "Average", "Maximum" )
|
||||||
|
: new TextTable( TRACK_ID, "Computer", field.displayName() );
|
||||||
|
|
||||||
|
for( ComputerTracker entry : timings )
|
||||||
{
|
{
|
||||||
Computer computer = entry.getComputer();
|
Computer computer = entry.getComputer();
|
||||||
ServerComputer serverComputer = computer == null ? null : lookup.get( computer );
|
ServerComputer serverComputer = computer == null ? null : lookup.get( computer );
|
||||||
|
|
||||||
ITextComponent computerComponent = new TextComponentString( "" )
|
ITextComponent computerComponent = linkComputer( context, serverComputer, entry.getComputerId() );
|
||||||
.appendSibling( serverComputer == null ? text( "?" ) : linkComputer( serverComputer ) )
|
|
||||||
.appendText( " (id " + entry.getComputerId() + ")" );
|
|
||||||
|
|
||||||
if( serverComputer != null && UserLevel.OP.canExecute( context ) && isPlayer )
|
if( defaultLayout )
|
||||||
{
|
{
|
||||||
computerComponent
|
table.addRow(
|
||||||
.appendText( " " )
|
computerComponent,
|
||||||
.appendSibling( link(
|
text( entry.getFormatted( TrackingField.TASKS ) ),
|
||||||
text( "\u261b" ),
|
text( entry.getFormatted( TrackingField.TOTAL_TIME ) ),
|
||||||
"/computercraft tp " + serverComputer.getInstanceID(),
|
text( entry.getFormatted( TrackingField.AVERAGE_TIME ) ),
|
||||||
"Teleport to this computer"
|
text( entry.getFormatted( TrackingField.MAX_TIME ) )
|
||||||
) )
|
);
|
||||||
.appendText( " " )
|
}
|
||||||
.appendSibling( link(
|
else
|
||||||
text( "\u20e2" ),
|
{
|
||||||
"/computercraft view " + serverComputer.getInstanceID(),
|
table.addRow( computerComponent, text( entry.getFormatted( field ) ) );
|
||||||
"View this computer"
|
|
||||||
) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table.addRow(
|
|
||||||
computerComponent,
|
|
||||||
formatted( "%4d", entry.getTasks() ),
|
|
||||||
text( String.format( "%7.1f", entry.getTotalTime() / 1e6 ) + "ms" ),
|
|
||||||
text( String.format( "%4.1f", entry.getAverage() / 1e6 ) + "ms" ),
|
|
||||||
text( String.format( "%5.1f", entry.getMaxTime() / 1e6 ) + "ms" )
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table.displayTo( context.getSender() );
|
table.displayTo( context.getSender() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void withComputers( List<String> selectors, Consumer<Collection<ServerComputer>> action ) throws CommandException
|
||||||
|
{
|
||||||
|
Set<ServerComputer> computers = Sets.newHashSet();
|
||||||
|
List<String> failed = new ArrayList<>();
|
||||||
|
if( selectors.isEmpty() )
|
||||||
|
{
|
||||||
|
computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( String selector : selectors )
|
||||||
|
{
|
||||||
|
List<ServerComputer> selected = ComputerSelector.getComputers( selector );
|
||||||
|
computers.addAll( selected );
|
||||||
|
if( selected.isEmpty() ) failed.add( selector );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action.accept( computers );
|
||||||
|
|
||||||
|
if( !failed.isEmpty() )
|
||||||
|
{
|
||||||
|
throw new CommandException( "Could not find computers matching " + String.join( ", ", failed ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,30 +12,22 @@ import java.util.function.Predicate;
|
|||||||
|
|
||||||
public final class ComputerSelector
|
public final class ComputerSelector
|
||||||
{
|
{
|
||||||
private static List<ServerComputer> getComputers( Predicate<ServerComputer> predicate, String selector ) throws CommandException
|
private static List<ServerComputer> getComputers( Predicate<ServerComputer> predicate ) throws CommandException
|
||||||
{
|
{
|
||||||
// We copy it to prevent concurrent modifications.
|
// We copy it to prevent concurrent modifications.
|
||||||
List<ServerComputer> computers = Lists.newArrayList( ComputerCraft.serverComputerRegistry.getComputers() );
|
ArrayList<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
|
||||||
List<ServerComputer> candidates = Lists.newArrayList();
|
computers.removeIf( predicate.negate() );
|
||||||
for( ServerComputer searchComputer : computers )
|
return computers;
|
||||||
{
|
|
||||||
if( predicate.test( searchComputer ) ) candidates.add( searchComputer );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( candidates.isEmpty() )
|
|
||||||
{
|
|
||||||
throw new CommandException( "No computer matching " + selector );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return candidates;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ServerComputer getComputer( String selector ) throws CommandException
|
public static ServerComputer getComputer( String selector ) throws CommandException
|
||||||
{
|
{
|
||||||
List<ServerComputer> computers = getComputers( selector );
|
List<ServerComputer> computers = getComputers( selector );
|
||||||
if( computers.size() == 1 )
|
if( computers.size() == 0 )
|
||||||
|
{
|
||||||
|
throw new CommandException( "No computer matching " + selector );
|
||||||
|
}
|
||||||
|
else if( computers.size() == 1 )
|
||||||
{
|
{
|
||||||
return computers.get( 0 );
|
return computers.get( 0 );
|
||||||
}
|
}
|
||||||
@@ -46,7 +38,7 @@ public final class ComputerSelector
|
|||||||
|
|
||||||
for( int i = 0; i < computers.size(); i++ )
|
for( int i = 0; i < computers.size(); i++ )
|
||||||
{
|
{
|
||||||
if( i > 1 ) builder.append( ", " );
|
if( i > 0 ) builder.append( ", " );
|
||||||
builder.append( computers.get( i ).getInstanceID() );
|
builder.append( computers.get( i ).getInstanceID() );
|
||||||
}
|
}
|
||||||
builder.append( ")" );
|
builder.append( ")" );
|
||||||
@@ -71,17 +63,17 @@ public final class ComputerSelector
|
|||||||
throw new CommandException( "'" + selector + "' is not a valid number" );
|
throw new CommandException( "'" + selector + "' is not a valid number" );
|
||||||
}
|
}
|
||||||
|
|
||||||
return getComputers( x -> x.getID() == id, selector );
|
return getComputers( x -> x.getID() == id );
|
||||||
}
|
}
|
||||||
else if( selector.length() > 0 && selector.charAt( 0 ) == '@' )
|
else if( selector.length() > 0 && selector.charAt( 0 ) == '@' )
|
||||||
{
|
{
|
||||||
String label = selector.substring( 1 );
|
String label = selector.substring( 1 );
|
||||||
return getComputers( x -> Objects.equals( label, x.getLabel() ), selector );
|
return getComputers( x -> Objects.equals( label, x.getLabel() ) );
|
||||||
}
|
}
|
||||||
else if( selector.length() > 0 && selector.charAt( 0 ) == '~' )
|
else if( selector.length() > 0 && selector.charAt( 0 ) == '~' )
|
||||||
{
|
{
|
||||||
String familyName = selector.substring( 1 );
|
String familyName = selector.substring( 1 );
|
||||||
return getComputers( x -> x.getFamily().name().equalsIgnoreCase( familyName ), selector );
|
return getComputers( x -> x.getFamily().name().equalsIgnoreCase( familyName ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -96,14 +88,7 @@ public final class ComputerSelector
|
|||||||
}
|
}
|
||||||
|
|
||||||
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance );
|
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance );
|
||||||
if( computer == null )
|
return computer == null ? Collections.emptyList() : Collections.singletonList( computer );
|
||||||
{
|
|
||||||
throw new CommandException( "No such computer for instance id " + instance );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Collections.singletonList( computer );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,7 +2,9 @@ package dan200.computercraft.shared.command.framework;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import net.minecraft.command.ICommandSender;
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -90,4 +92,9 @@ public final class CommandContext
|
|||||||
{
|
{
|
||||||
return sender;
|
return sender;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean fromPlayer()
|
||||||
|
{
|
||||||
|
return sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,147 @@
|
|||||||
|
package dan200.computercraft.shared.command.framework;
|
||||||
|
|
||||||
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.util.text.ITextComponent;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
|
import net.minecraft.util.text.TextFormatting;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static dan200.computercraft.shared.command.framework.ChatHelpers.coloured;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapated from Sponge's PaginationCalculator
|
||||||
|
*/
|
||||||
|
public class TextFormatter
|
||||||
|
{
|
||||||
|
private static final char PADDING_CHAR = '\u02cc';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yoinked from FontRenderer
|
||||||
|
*
|
||||||
|
* @see net.minecraft.client.gui.FontRenderer#charWidth
|
||||||
|
* @see net.minecraft.client.gui.FontRenderer#getCharWidth(char)
|
||||||
|
*/
|
||||||
|
private static final String CHARACTERS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
|
||||||
|
private static final int[] CHAR_WIDTHS = new int[]{
|
||||||
|
6, 6, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 4,
|
||||||
|
4, 6, 7, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 2, 5, 6, 6, 6, 6, 3, 5, 5, 5, 6, 2, 6, 2, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 5, 6, 5, 6,
|
||||||
|
7, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 6, 6,
|
||||||
|
3, 6, 6, 6, 6, 6, 5, 6, 6, 2, 6, 5, 3, 6, 6, 6,
|
||||||
|
6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 5, 2, 5, 7, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 3, 6, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6,
|
||||||
|
6, 3, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 2, 6, 6,
|
||||||
|
8, 9, 9, 6, 6, 6, 8, 8, 6, 8, 8, 8, 8, 8, 6, 6,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 9, 9, 9, 5, 9, 9,
|
||||||
|
8, 7, 7, 8, 7, 8, 8, 8, 7, 8, 8, 7, 9, 9, 6, 7,
|
||||||
|
7, 7, 7, 7, 9, 6, 7, 8, 7, 6, 6, 9, 7, 6, 7, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int[] EXTRA_CHARS = new int[]{
|
||||||
|
'\u20e2', '\u261b',
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final byte[] EXTRA_WIDTHS = new byte[]{
|
||||||
|
8, 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static int getWidth( int codePoint )
|
||||||
|
{
|
||||||
|
// Escape codes
|
||||||
|
if( codePoint == 167 ) return -1;
|
||||||
|
|
||||||
|
// Space and non-breaking space
|
||||||
|
if( codePoint == 32 || codePoint == 160 ) return 4;
|
||||||
|
|
||||||
|
// Built-in characters
|
||||||
|
int nonUnicodeIdx = CHARACTERS.indexOf( codePoint );
|
||||||
|
if( codePoint > 0 && nonUnicodeIdx != -1 ) return CHAR_WIDTHS[nonUnicodeIdx];
|
||||||
|
|
||||||
|
// Other special characters we use.
|
||||||
|
int extraIdx = Arrays.binarySearch( EXTRA_CHARS, codePoint );
|
||||||
|
if( extraIdx >= 0 ) return EXTRA_WIDTHS[extraIdx];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getWidth( ITextComponent component )
|
||||||
|
{
|
||||||
|
int total = 0;
|
||||||
|
if( component instanceof TextComponentString )
|
||||||
|
{
|
||||||
|
String contents = component.getUnformattedComponentText();
|
||||||
|
|
||||||
|
int bold = component.getStyle().getBold() ? 1 : 0;
|
||||||
|
for( int i = 0; i < contents.length(); i++ )
|
||||||
|
{
|
||||||
|
int cp = contents.charAt( i );
|
||||||
|
assert cp != '\n';
|
||||||
|
int width = getWidth( cp );
|
||||||
|
if( width < 0 )
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
total += width + bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for( ITextComponent child : component.getSiblings() )
|
||||||
|
{
|
||||||
|
total += getWidth( child );
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPlayer( ICommandSender sender )
|
||||||
|
{
|
||||||
|
return sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getMaxWidth( ICommandSender sender )
|
||||||
|
{
|
||||||
|
return isPlayer( sender ) ? 320 : 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getWidthFor( ITextComponent component, ICommandSender sender )
|
||||||
|
{
|
||||||
|
return isPlayer( sender ) ? getWidth( component ) : component.getUnformattedText().length();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getWidthFor( int codepoint, ICommandSender sender )
|
||||||
|
{
|
||||||
|
return isPlayer( sender ) ? getWidth( codepoint ) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void appendFixedWidth( ITextComponent out, ICommandSender sender, ITextComponent entry, int maxWidth )
|
||||||
|
{
|
||||||
|
out.appendSibling( entry );
|
||||||
|
|
||||||
|
int width = getWidthFor( entry, sender );
|
||||||
|
int delta = maxWidth - width;
|
||||||
|
|
||||||
|
int spaceWidth = getWidthFor( ' ', sender );
|
||||||
|
int spaces = delta / spaceWidth;
|
||||||
|
int extra = delta % spaces;
|
||||||
|
|
||||||
|
// Append a fixed number of spaces
|
||||||
|
if( spaces > 0 ) out.appendSibling( new TextComponentString( StringUtils.repeat( ' ', spaces ) ) );
|
||||||
|
|
||||||
|
// Append several minor characters to pad to a full string
|
||||||
|
if( extra > 0 )
|
||||||
|
{
|
||||||
|
out.appendSibling( coloured( StringUtils.repeat( PADDING_CHAR, extra ), TextFormatting.GRAY ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,113 +1,49 @@
|
|||||||
package dan200.computercraft.shared.command.framework;
|
package dan200.computercraft.shared.command.framework;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.shared.network.ComputerCraftPacket;
|
||||||
import net.minecraft.command.ICommandSender;
|
import net.minecraft.command.ICommandSender;
|
||||||
import net.minecraft.entity.player.EntityPlayerMP;
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
import net.minecraft.util.text.ITextComponent;
|
import net.minecraft.util.text.ITextComponent;
|
||||||
import net.minecraft.util.text.TextComponentString;
|
import net.minecraft.util.text.TextComponentString;
|
||||||
import net.minecraft.util.text.TextFormatting;
|
import net.minecraft.util.text.TextFormatting;
|
||||||
import net.minecraftforge.common.util.FakePlayer;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static dan200.computercraft.shared.command.framework.ChatHelpers.coloured;
|
import static dan200.computercraft.shared.command.framework.ChatHelpers.coloured;
|
||||||
import static dan200.computercraft.shared.command.framework.ChatHelpers.text;
|
import static dan200.computercraft.shared.command.framework.ChatHelpers.text;
|
||||||
|
import static dan200.computercraft.shared.command.framework.TextFormatter.*;
|
||||||
|
|
||||||
public class TextTable
|
public class TextTable
|
||||||
{
|
{
|
||||||
private static final String CHARACTERS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
|
private static final ITextComponent SEPARATOR = coloured( "| ", TextFormatting.GRAY );
|
||||||
private static final int[] CHAR_WIDTHS = new int[]{
|
|
||||||
6, 6, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 4,
|
|
||||||
4, 6, 7, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 2, 5, 6, 6, 6, 6, 3, 5, 5, 5, 6, 2, 6, 2, 6,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 5, 6, 5, 6,
|
|
||||||
7, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 6, 6,
|
|
||||||
3, 6, 6, 6, 6, 6, 5, 6, 6, 2, 6, 5, 3, 6, 6, 6,
|
|
||||||
6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 5, 2, 5, 7, 6,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 3, 6, 6,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6,
|
|
||||||
6, 3, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 2, 6, 6,
|
|
||||||
8, 9, 9, 6, 6, 6, 8, 8, 6, 8, 8, 8, 8, 8, 6, 6,
|
|
||||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 9, 9, 9, 5, 9, 9,
|
|
||||||
8, 7, 7, 8, 7, 8, 8, 8, 7, 8, 8, 7, 9, 9, 6, 7,
|
|
||||||
7, 7, 7, 7, 9, 6, 7, 8, 7, 6, 6, 9, 7, 6, 7, 1
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final ITextComponent SEPARATOR = coloured( " | ", TextFormatting.GRAY );
|
|
||||||
private static final ITextComponent LINE = text( "\n" );
|
private static final ITextComponent LINE = text( "\n" );
|
||||||
|
|
||||||
private static int getWidth( char character, ICommandSender sender )
|
private final int id;
|
||||||
{
|
|
||||||
if( sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer) )
|
|
||||||
{
|
|
||||||
// Use font widths here.
|
|
||||||
if( character == 167 )
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if( character == 32 )
|
|
||||||
{
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
else if( CHARACTERS.indexOf( character ) != -1 )
|
|
||||||
{
|
|
||||||
return CHAR_WIDTHS[character];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Eh, close enough.
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getWidth( ITextComponent text, ICommandSender sender )
|
|
||||||
{
|
|
||||||
int sum = 0;
|
|
||||||
String chars = text.getUnformattedText();
|
|
||||||
for( int i = 0; i < chars.length(); i++ )
|
|
||||||
{
|
|
||||||
sum += getWidth( chars.charAt( i ), sender );
|
|
||||||
}
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isPlayer( ICommandSender sender )
|
|
||||||
{
|
|
||||||
return sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getMaxWidth( ICommandSender sender )
|
|
||||||
{
|
|
||||||
return isPlayer( sender ) ? 320 : 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int columns = -1;
|
private int columns = -1;
|
||||||
private final ITextComponent[] header;
|
private final ITextComponent[] header;
|
||||||
private final List<ITextComponent[]> rows = Lists.newArrayList();
|
private final List<ITextComponent[]> rows = Lists.newArrayList();
|
||||||
|
|
||||||
public TextTable( @Nonnull ITextComponent... header )
|
public TextTable( int id, @Nonnull ITextComponent... header )
|
||||||
{
|
{
|
||||||
|
this.id = id;
|
||||||
this.header = header;
|
this.header = header;
|
||||||
this.columns = header.length;
|
this.columns = header.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextTable()
|
public TextTable( int id )
|
||||||
{
|
{
|
||||||
header = null;
|
this.id = id;
|
||||||
|
this.header = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextTable( @Nonnull String... header )
|
public TextTable( int id, @Nonnull String... header )
|
||||||
{
|
{
|
||||||
|
this.id = id;
|
||||||
this.header = new ITextComponent[header.length];
|
this.header = new ITextComponent[header.length];
|
||||||
for( int i = 0; i < header.length; i++ )
|
for( int i = 0; i < header.length; i++ )
|
||||||
{
|
{
|
||||||
@@ -134,128 +70,101 @@ public class TextTable
|
|||||||
{
|
{
|
||||||
if( columns <= 0 ) return;
|
if( columns <= 0 ) return;
|
||||||
|
|
||||||
final int maxWidth = getMaxWidth( sender );
|
|
||||||
|
|
||||||
int[] minWidths = new int[columns];
|
|
||||||
int[] maxWidths = new int[columns];
|
int[] maxWidths = new int[columns];
|
||||||
int[] rowWidths = new int[columns];
|
|
||||||
|
|
||||||
if( header != null )
|
if( header != null )
|
||||||
{
|
{
|
||||||
for( int i = 0; i < columns; i++ )
|
for( int i = 0; i < columns; i++ )
|
||||||
{
|
{
|
||||||
maxWidths[i] = minWidths[i] = getWidth( header[i], sender );
|
maxWidths[i] = getWidthFor( header[i], sender );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit the number of rows to something sensible.
|
// Limit the number of rows to fit within a single chat window on default Minecraft
|
||||||
int limit = isPlayer( sender ) ? 30 : 100;
|
// options.
|
||||||
if( limit > rows.size() ) limit = rows.size();
|
int height = isPlayer( sender ) ? 18 : 100;
|
||||||
|
int limit = rows.size() <= height ? rows.size() : height - 1;
|
||||||
|
|
||||||
for( int y = 0; y < limit; y++ )
|
for( int y = 0; y < limit; y++ )
|
||||||
{
|
{
|
||||||
ITextComponent[] row = rows.get( y );
|
ITextComponent[] row = rows.get( y );
|
||||||
for( int i = 0; i < row.length; i++ )
|
for( int i = 0; i < row.length; i++ )
|
||||||
{
|
{
|
||||||
int width = getWidth( row[i], sender );
|
int width = getWidthFor( row[i], sender );
|
||||||
rowWidths[i] += width;
|
if( width > maxWidths[i] ) maxWidths[i] = width;
|
||||||
if( width > maxWidths[i] )
|
|
||||||
{
|
|
||||||
maxWidths[i] = width;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the average width
|
// Add a small amount of extra padding. This defaults to 3 spaces for players
|
||||||
for( int i = 0; i < columns; i++ )
|
// and 1 for everyone else.
|
||||||
{
|
int padding = isPlayer( sender ) ? getWidth( ' ' ) * 3 : 1;
|
||||||
rowWidths[i] = Math.max( rowWidths[i], rows.size() );
|
for( int i = 0; i < maxWidths.length; i++ ) maxWidths[i] += padding;
|
||||||
}
|
|
||||||
|
|
||||||
int totalWidth = (columns - 1) * getWidth( SEPARATOR, sender );
|
int totalWidth = (columns - 1) * getWidthFor( SEPARATOR, sender );
|
||||||
for( int x : maxWidths ) totalWidth += x;
|
for( int x : maxWidths ) totalWidth += x;
|
||||||
|
|
||||||
// TODO: Limit the widths of some entries if totalWidth > maxWidth
|
// TODO: Limit the widths of some entries if totalWidth > maxWidth
|
||||||
|
|
||||||
ITextComponent out = new TextComponentString( "" );
|
List<ITextComponent> out = new ArrayList<>();
|
||||||
|
|
||||||
if( header != null )
|
if( header != null )
|
||||||
{
|
{
|
||||||
for( int i = 0; i < columns; i++ )
|
TextComponentString line = new TextComponentString( "" );
|
||||||
|
for( int i = 0; i < columns - 1; i++ )
|
||||||
{
|
{
|
||||||
if( i != 0 ) out.appendSibling( SEPARATOR );
|
appendFixedWidth( line, sender, header[i], maxWidths[i] );
|
||||||
appendFixed( out, sender, header[i], maxWidths[i] );
|
line.appendSibling( SEPARATOR );
|
||||||
}
|
}
|
||||||
out.appendSibling( LINE );
|
line.appendSibling( header[columns - 1] );
|
||||||
|
out.add( line );
|
||||||
|
|
||||||
// Round the width up rather than down
|
// Round the width up rather than down
|
||||||
int rowCharWidth = getWidth( '=', sender );
|
int rowCharWidth = getWidthFor( '=', sender );
|
||||||
int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1);
|
int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1);
|
||||||
out.appendSibling( coloured( StringUtils.repeat( '=', rowWidth ), TextFormatting.GRAY ) );
|
out.add( coloured( StringUtils.repeat( '=', rowWidth ), TextFormatting.GRAY ) );
|
||||||
out.appendSibling( LINE );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for( int i = 0; i < limit; i++ )
|
for( int i = 0; i < limit; i++ )
|
||||||
{
|
{
|
||||||
|
TextComponentString line = new TextComponentString( "" );
|
||||||
ITextComponent[] row = rows.get( i );
|
ITextComponent[] row = rows.get( i );
|
||||||
if( i != 0 ) out.appendSibling( LINE );
|
for( int j = 0; j < columns - 1; j++ )
|
||||||
for( int j = 0; j < columns; j++ )
|
|
||||||
{
|
{
|
||||||
if( j != 0 ) out.appendSibling( SEPARATOR );
|
appendFixedWidth( line, sender, row[j], maxWidths[j] );
|
||||||
appendFixed( out, sender, row[j], maxWidths[j] );
|
line.appendSibling( SEPARATOR );
|
||||||
}
|
}
|
||||||
|
line.appendSibling( row[columns - 1] );
|
||||||
|
out.add( line );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( limit != rows.size() )
|
if( rows.size() > limit )
|
||||||
{
|
{
|
||||||
out.appendSibling( LINE );
|
out.add( coloured( (rows.size() - limit) + " additional rows...", TextFormatting.AQUA ) );
|
||||||
out.appendSibling( coloured( (rows.size() - limit) + " additional rows...", TextFormatting.AQUA ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.sendMessage( out );
|
if( isPlayer( sender ) && id != 0 )
|
||||||
}
|
|
||||||
|
|
||||||
private static void appendFixed( ITextComponent out, ICommandSender sender, ITextComponent entry, int maxWidth )
|
|
||||||
{
|
|
||||||
int length = getWidth( entry, sender );
|
|
||||||
int delta = length - maxWidth;
|
|
||||||
if( delta < 0 )
|
|
||||||
{
|
{
|
||||||
// Convert to overflow;
|
ComputerCraftPacket packet = new ComputerCraftPacket();
|
||||||
delta = -delta;
|
packet.m_packetType = ComputerCraftPacket.PostChat;
|
||||||
|
packet.m_dataInt = new int[]{ id };
|
||||||
|
|
||||||
// We have to remove some padding as there is a padding added between formatted and unformatted text
|
String[] lines = packet.m_dataString = new String[out.size()];
|
||||||
if( !entry.getStyle().isEmpty() && isPlayer( sender ) ) delta -= 1;
|
for( int i = 0; i < out.size(); i++ )
|
||||||
|
|
||||||
out.appendSibling( entry );
|
|
||||||
|
|
||||||
int spaceWidth = getWidth( ' ', sender );
|
|
||||||
|
|
||||||
int spaces = delta / spaceWidth;
|
|
||||||
int missing = delta % spaceWidth;
|
|
||||||
spaces -= missing;
|
|
||||||
|
|
||||||
ITextComponent component = new TextComponentString( StringUtils.repeat( ' ', spaces < 0 ? 0 : spaces ) );
|
|
||||||
if( missing > 0 )
|
|
||||||
{
|
{
|
||||||
ITextComponent bold = new TextComponentString( StringUtils.repeat( ' ', missing ) );
|
lines[i] = ITextComponent.Serializer.componentToJson( out.get( i ) );
|
||||||
bold.getStyle().setBold( true );
|
|
||||||
component.appendSibling( bold );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.appendSibling( component );
|
ComputerCraft.sendToPlayer( (EntityPlayerMP) sender, packet );
|
||||||
}
|
|
||||||
else if( delta > 0 )
|
|
||||||
{
|
|
||||||
out.appendSibling( entry );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out.appendSibling( entry );
|
ITextComponent result = new TextComponentString( "" );
|
||||||
|
for( int i = 0; i < out.size(); i++ )
|
||||||
// We have to add some padding as we expect a padding between formatted and unformatted text
|
{
|
||||||
// and there won't be.
|
if( i > 0 ) result.appendSibling( LINE );
|
||||||
if( entry.getStyle().isEmpty() && isPlayer( sender ) ) out.appendText( " " );
|
result.appendSibling( out.get( i ) );
|
||||||
|
}
|
||||||
|
sender.sendMessage( result );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,7 +36,7 @@ public abstract class BlockGeneric extends Block implements
|
|||||||
protected BlockGeneric( Material material )
|
protected BlockGeneric( Material material )
|
||||||
{
|
{
|
||||||
super( material );
|
super( material );
|
||||||
this.isBlockContainer = true;
|
this.hasTileEntity = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract IBlockState getDefaultBlockState( int damage, EnumFacing placedSide );
|
protected abstract IBlockState getDefaultBlockState( int damage, EnumFacing placedSide );
|
||||||
|
@@ -86,7 +86,7 @@ public class ColourableRecipe extends IForgeRegistryEntry.Impl<IRecipe> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isHidden()
|
public boolean isDynamic()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -54,6 +54,11 @@ public class ServerTerminal implements ITerminal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void markTerminalChanged()
|
||||||
|
{
|
||||||
|
m_terminalChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
public void update()
|
public void update()
|
||||||
{
|
{
|
||||||
m_terminalChangedLastFrame = m_terminalChanged || (m_terminal != null && m_terminal.getChanged());
|
m_terminalChangedLastFrame = m_terminalChanged || (m_terminal != null && m_terminal.getChanged());
|
||||||
|
@@ -42,7 +42,7 @@ public class BlockCommandComputer extends BlockComputerBase
|
|||||||
super( Material.IRON );
|
super( Material.IRON );
|
||||||
setBlockUnbreakable();
|
setBlockUnbreakable();
|
||||||
setResistance( 6000000.0F );
|
setResistance( 6000000.0F );
|
||||||
setUnlocalizedName( "computercraft:command_computer" );
|
setTranslationKey( "computercraft:command_computer" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
setDefaultState( this.blockState.getBaseState()
|
setDefaultState( this.blockState.getBaseState()
|
||||||
.withProperty( Properties.FACING, EnumFacing.NORTH )
|
.withProperty( Properties.FACING, EnumFacing.NORTH )
|
||||||
@@ -62,7 +62,7 @@ public class BlockCommandComputer extends BlockComputerBase
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public IBlockState getStateFromMeta( int meta )
|
public IBlockState getStateFromMeta( int meta )
|
||||||
{
|
{
|
||||||
EnumFacing dir = EnumFacing.getFront( meta & 0x7 );
|
EnumFacing dir = EnumFacing.byIndex( meta & 0x7 );
|
||||||
if( dir.getAxis() == EnumFacing.Axis.Y )
|
if( dir.getAxis() == EnumFacing.Axis.Y )
|
||||||
{
|
{
|
||||||
dir = EnumFacing.NORTH;
|
dir = EnumFacing.NORTH;
|
||||||
|
@@ -44,7 +44,7 @@ public class BlockComputer extends BlockComputerBase
|
|||||||
{
|
{
|
||||||
super( Material.ROCK );
|
super( Material.ROCK );
|
||||||
setHardness( 2.0f );
|
setHardness( 2.0f );
|
||||||
setUnlocalizedName( "computercraft:computer" );
|
setTranslationKey( "computercraft:computer" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
setDefaultState( this.blockState.getBaseState()
|
setDefaultState( this.blockState.getBaseState()
|
||||||
.withProperty( Properties.FACING, EnumFacing.NORTH )
|
.withProperty( Properties.FACING, EnumFacing.NORTH )
|
||||||
@@ -65,7 +65,7 @@ public class BlockComputer extends BlockComputerBase
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public IBlockState getStateFromMeta( int meta )
|
public IBlockState getStateFromMeta( int meta )
|
||||||
{
|
{
|
||||||
EnumFacing dir = EnumFacing.getFront( meta & 0x7 );
|
EnumFacing dir = EnumFacing.byIndex( meta & 0x7 );
|
||||||
if( dir.getAxis() == EnumFacing.Axis.Y )
|
if( dir.getAxis() == EnumFacing.Axis.Y )
|
||||||
{
|
{
|
||||||
dir = EnumFacing.NORTH;
|
dir = EnumFacing.NORTH;
|
||||||
|
@@ -154,7 +154,7 @@ public class ServerComputer extends ServerTerminal
|
|||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ComputerCraftPacket createTerminalPacket() {
|
protected ComputerCraftPacket createTerminalPacket() {
|
||||||
ComputerCraftPacket packet = new ComputerCraftPacket();
|
ComputerCraftPacket packet = new ComputerCraftPacket();
|
||||||
packet.m_packetType = ComputerCraftPacket.ComputerTerminalChanged;
|
packet.m_packetType = ComputerCraftPacket.ComputerTerminalChanged;
|
||||||
packet.m_dataInt = new int[] { getInstanceID() };
|
packet.m_dataInt = new int[] { getInstanceID() };
|
||||||
@@ -465,7 +465,7 @@ public class ServerComputer extends ServerTerminal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isInteracting( EntityPlayer player )
|
protected boolean isInteracting( EntityPlayer player )
|
||||||
{
|
{
|
||||||
if( player == null ) return false;
|
if( player == null ) return false;
|
||||||
|
|
||||||
|
@@ -24,7 +24,7 @@ public class ItemCommandComputer extends ItemComputer
|
|||||||
super( block );
|
super( block );
|
||||||
setMaxStackSize( 64 );
|
setMaxStackSize( 64 );
|
||||||
setHasSubtypes( true );
|
setHasSubtypes( true );
|
||||||
setUnlocalizedName( "computercraft:command_computer" );
|
setTranslationKey( "computercraft:command_computer" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,7 +33,7 @@ public class ItemComputer extends ItemComputerBase
|
|||||||
super( block );
|
super( block );
|
||||||
setMaxStackSize( 64 );
|
setMaxStackSize( 64 );
|
||||||
setHasSubtypes( true );
|
setHasSubtypes( true );
|
||||||
setUnlocalizedName( "computercraft:computer" );
|
setTranslationKey( "computercraft:computer" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ public class ItemComputer extends ItemComputerBase
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUnlocalizedName( @Nonnull ItemStack stack )
|
public String getTranslationKey( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
switch( getFamily( stack ) )
|
switch( getFamily( stack ) )
|
||||||
{
|
{
|
||||||
|
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.shared.integration.charset;
|
||||||
|
|
||||||
|
import dan200.computercraft.shared.common.TileGeneric;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
|
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||||
|
import pl.asie.charset.api.wires.IBundledEmitter;
|
||||||
|
import pl.asie.charset.api.wires.IBundledReceiver;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static dan200.computercraft.shared.integration.charset.IntegrationCharset.CAPABILITY_EMITTER;
|
||||||
|
import static dan200.computercraft.shared.integration.charset.IntegrationCharset.CAPABILITY_RECEIVER;
|
||||||
|
|
||||||
|
final class BundledCapabilityProvider implements ICapabilityProvider
|
||||||
|
{
|
||||||
|
private final TileGeneric tile;
|
||||||
|
private IBundledReceiver receiver;
|
||||||
|
private IBundledEmitter[] emitters;
|
||||||
|
|
||||||
|
BundledCapabilityProvider( TileGeneric tile )
|
||||||
|
{
|
||||||
|
this.tile = tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing side )
|
||||||
|
{
|
||||||
|
return capability == CAPABILITY_EMITTER || capability == CAPABILITY_RECEIVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public <T> T getCapability( @Nonnull Capability<T> capability, @Nullable EnumFacing side )
|
||||||
|
{
|
||||||
|
if( capability == CAPABILITY_RECEIVER )
|
||||||
|
{
|
||||||
|
IBundledReceiver receiver = this.receiver;
|
||||||
|
if( receiver == null ) receiver = this.receiver = tile::onNeighbourChange;
|
||||||
|
|
||||||
|
return CAPABILITY_RECEIVER.cast( receiver );
|
||||||
|
}
|
||||||
|
else if( capability == CAPABILITY_EMITTER )
|
||||||
|
{
|
||||||
|
IBundledEmitter[] emitters = this.emitters;
|
||||||
|
if( emitters == null ) emitters = this.emitters = new IBundledEmitter[7];
|
||||||
|
|
||||||
|
int index = side == null ? 6 : side.getIndex();
|
||||||
|
IBundledEmitter emitter = emitters[index];
|
||||||
|
if( emitter == null )
|
||||||
|
{
|
||||||
|
if( side == null )
|
||||||
|
{
|
||||||
|
emitter = emitters[index] = () -> {
|
||||||
|
int flags = 0;
|
||||||
|
for( EnumFacing facing : EnumFacing.VALUES ) flags |= tile.getBundledRedstoneOutput( facing );
|
||||||
|
return toBytes( flags );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emitter = emitters[index] = () -> toBytes( tile.getBundledRedstoneOutput( side ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
return CAPABILITY_EMITTER.cast( emitter );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] toBytes( int flag )
|
||||||
|
{
|
||||||
|
byte[] channels = new byte[16];
|
||||||
|
for( int i = 0; i < 16; i++ ) channels[i] = (flag & (1 << i)) == 0 ? (byte) 0 : 15;
|
||||||
|
return channels;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.shared.integration.charset;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static dan200.computercraft.shared.integration.charset.IntegrationCharset.CAPABILITY_EMITTER;
|
||||||
|
|
||||||
|
public class BundledRedstoneProvider implements IBundledRedstoneProvider
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
|
||||||
|
{
|
||||||
|
TileEntity tile = world.getTileEntity( pos );
|
||||||
|
if( tile == null || !tile.hasCapability( CAPABILITY_EMITTER, side ) ) return -1;
|
||||||
|
|
||||||
|
byte[] signal = tile.getCapability( CAPABILITY_EMITTER, side ).getBundledSignal();
|
||||||
|
if( signal == null ) return -1;
|
||||||
|
|
||||||
|
int flag = 0;
|
||||||
|
for( int i = 0; i < signal.length; i++ ) flag |= signal[i] > 0 ? (1 << i) : 0;
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.shared.integration.charset;
|
||||||
|
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.shared.common.TileGeneric;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
|
import net.minecraftforge.common.capabilities.CapabilityInject;
|
||||||
|
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import pl.asie.charset.api.wires.IBundledEmitter;
|
||||||
|
import pl.asie.charset.api.wires.IBundledReceiver;
|
||||||
|
|
||||||
|
public final class IntegrationCharset
|
||||||
|
{
|
||||||
|
private static final ResourceLocation CAPABILITY_KEY = new ResourceLocation( ComputerCraft.MOD_ID, "charset" );
|
||||||
|
|
||||||
|
@CapabilityInject( IBundledEmitter.class )
|
||||||
|
public static final Capability<IBundledEmitter> CAPABILITY_EMITTER = null;
|
||||||
|
|
||||||
|
@CapabilityInject( IBundledReceiver.class )
|
||||||
|
public static final Capability<IBundledReceiver> CAPABILITY_RECEIVER = null;
|
||||||
|
|
||||||
|
private IntegrationCharset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register()
|
||||||
|
{
|
||||||
|
if( CAPABILITY_EMITTER == null || CAPABILITY_RECEIVER == null ) return;
|
||||||
|
|
||||||
|
MinecraftForge.EVENT_BUS.register( new IntegrationCharset() );
|
||||||
|
ComputerCraftAPI.registerBundledRedstoneProvider( new BundledRedstoneProvider() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void attachGenericCapabilities( AttachCapabilitiesEvent<TileEntity> event)
|
||||||
|
{
|
||||||
|
TileEntity tile = event.getObject();
|
||||||
|
if(tile instanceof TileGeneric)
|
||||||
|
{
|
||||||
|
event.addCapability( CAPABILITY_KEY, new BundledCapabilityProvider( (TileGeneric) tile ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -33,7 +33,7 @@ public class ItemDiskLegacy extends Item
|
|||||||
{
|
{
|
||||||
setMaxStackSize( 1 );
|
setMaxStackSize( 1 );
|
||||||
setHasSubtypes( true );
|
setHasSubtypes( true );
|
||||||
setUnlocalizedName( "computercraft:disk" );
|
setTranslationKey( "computercraft:disk" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,15 +54,7 @@ public class ItemDiskLegacy extends Item
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
public static ItemStack createFromIDAndColour( int id, String label, int colour )
|
public static ItemStack createFromIDAndColour( int id, String label, int colour )
|
||||||
{
|
{
|
||||||
if( colour != Colour.Blue.getHex() )
|
return ItemDiskExpanded.createFromIDAndColour( id, label, colour );
|
||||||
{
|
|
||||||
return ItemDiskExpanded.createFromIDAndColour( id, label, colour );
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemStack stack = new ItemStack( ComputerCraft.Items.disk, 1 );
|
|
||||||
ComputerCraft.Items.disk.setDiskID( stack, id );
|
|
||||||
ComputerCraft.Items.disk.setLabel( stack, label );
|
|
||||||
return stack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDiskID( @Nonnull ItemStack stack )
|
public int getDiskID( @Nonnull ItemStack stack )
|
||||||
|
@@ -39,7 +39,7 @@ public class ItemPrintout extends Item
|
|||||||
{
|
{
|
||||||
setMaxStackSize( 1 );
|
setMaxStackSize( 1 );
|
||||||
setHasSubtypes( true );
|
setHasSubtypes( true );
|
||||||
setUnlocalizedName( "computercraft:page" );
|
setTranslationKey( "computercraft:page" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ public class ItemPrintout extends Item
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUnlocalizedName( @Nonnull ItemStack stack )
|
public String getTranslationKey( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
Type type = getType( stack );
|
Type type = getType( stack );
|
||||||
switch( type )
|
switch( type )
|
||||||
|
@@ -34,7 +34,7 @@ public class ItemTreasureDisk extends Item
|
|||||||
{
|
{
|
||||||
setMaxStackSize( 1 );
|
setMaxStackSize( 1 );
|
||||||
setHasSubtypes( true );
|
setHasSubtypes( true );
|
||||||
setUnlocalizedName( "computercraft:treasure_disk" );
|
setTranslationKey( "computercraft:treasure_disk" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -91,7 +91,7 @@ public class DiskRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements IRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isHidden()
|
public boolean isDynamic()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -33,7 +33,7 @@ public class PrintoutRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isHidden()
|
public boolean isDynamic()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,7 @@ public class ComputerCraftPacket
|
|||||||
public static final byte ComputerTerminalChanged = 8;
|
public static final byte ComputerTerminalChanged = 8;
|
||||||
public static final byte ComputerDeleted = 9;
|
public static final byte ComputerDeleted = 9;
|
||||||
public static final byte PlayRecord = 10;
|
public static final byte PlayRecord = 10;
|
||||||
|
public static final byte PostChat = 11;
|
||||||
|
|
||||||
// Packet class
|
// Packet class
|
||||||
public byte m_packetType;
|
public byte m_packetType;
|
||||||
|
@@ -55,7 +55,7 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
public BlockCable()
|
public BlockCable()
|
||||||
{
|
{
|
||||||
setHardness( 1.5f );
|
setHardness( 1.5f );
|
||||||
setUnlocalizedName( "computercraft:cable" );
|
setTranslationKey( "computercraft:cable" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
setDefaultState( this.blockState.getBaseState()
|
setDefaultState( this.blockState.getBaseState()
|
||||||
.withProperty( Properties.MODEM, BlockCableModemVariant.None )
|
.withProperty( Properties.MODEM, BlockCableModemVariant.None )
|
||||||
@@ -94,12 +94,12 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
if( meta < 6 )
|
if( meta < 6 )
|
||||||
{
|
{
|
||||||
state = state.withProperty( Properties.CABLE, BlockCableCableVariant.NONE );
|
state = state.withProperty( Properties.CABLE, BlockCableCableVariant.NONE );
|
||||||
state = state.withProperty( Properties.MODEM, BlockCableModemVariant.fromFacing( EnumFacing.getFront( meta ) ) );
|
state = state.withProperty( Properties.MODEM, BlockCableModemVariant.fromFacing( EnumFacing.byIndex( meta ) ) );
|
||||||
}
|
}
|
||||||
else if( meta < 12 )
|
else if( meta < 12 )
|
||||||
{
|
{
|
||||||
state = state.withProperty( Properties.CABLE, BlockCableCableVariant.ANY );
|
state = state.withProperty( Properties.CABLE, BlockCableCableVariant.ANY );
|
||||||
state = state.withProperty( Properties.MODEM, BlockCableModemVariant.fromFacing( EnumFacing.getFront( meta - 6 ) ) );
|
state = state.withProperty( Properties.MODEM, BlockCableModemVariant.fromFacing( EnumFacing.byIndex( meta - 6 ) ) );
|
||||||
}
|
}
|
||||||
else if( meta == 13 )
|
else if( meta == 13 )
|
||||||
{
|
{
|
||||||
@@ -296,7 +296,7 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result == null ? null : new RayTraceResult( result.hitVec.addVector( pos.getX(), pos.getY(), pos.getZ() ), result.sideHit, pos );
|
return result == null ? null : new RayTraceResult( result.hitVec.add( pos.getX(), pos.getY(), pos.getZ() ), result.sideHit, pos );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -332,7 +332,8 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
item = PeripheralItemFactory.create( PeripheralType.Cable, null, 1 );
|
item = PeripheralItemFactory.create( PeripheralType.Cable, null, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
cable.networkChanged();
|
cable.modemChanged();
|
||||||
|
cable.connectionsChanged();
|
||||||
if( !world.isRemote && !player.capabilities.isCreativeMode ) dropItem( world, pos, item );
|
if( !world.isRemote && !player.capabilities.isCreativeMode ) dropItem( world, pos, item );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -382,7 +383,7 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
TileCable cable = (TileCable) tile;
|
TileCable cable = (TileCable) tile;
|
||||||
if( cable.getPeripheralType() != PeripheralType.WiredModem )
|
if( cable.getPeripheralType() != PeripheralType.WiredModem )
|
||||||
{
|
{
|
||||||
cable.networkChanged();
|
cable.connectionsChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,7 +44,7 @@ public class BlockPeripheral extends BlockPeripheralBase
|
|||||||
public BlockPeripheral()
|
public BlockPeripheral()
|
||||||
{
|
{
|
||||||
setHardness( 2.0f );
|
setHardness( 2.0f );
|
||||||
setUnlocalizedName( "computercraft:peripheral" );
|
setTranslationKey( "computercraft:peripheral" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
setDefaultState( this.blockState.getBaseState()
|
setDefaultState( this.blockState.getBaseState()
|
||||||
.withProperty( Properties.FACING, EnumFacing.NORTH )
|
.withProperty( Properties.FACING, EnumFacing.NORTH )
|
||||||
@@ -55,7 +55,7 @@ public class BlockPeripheral extends BlockPeripheralBase
|
|||||||
@Override
|
@Override
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@SideOnly( Side.CLIENT)
|
@SideOnly( Side.CLIENT)
|
||||||
public BlockRenderLayer getBlockLayer()
|
public BlockRenderLayer getRenderLayer()
|
||||||
{
|
{
|
||||||
return BlockRenderLayer.CUTOUT;
|
return BlockRenderLayer.CUTOUT;
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ public class BlockPeripheral extends BlockPeripheralBase
|
|||||||
if( meta >= 2 && meta <= 5 )
|
if( meta >= 2 && meta <= 5 )
|
||||||
{
|
{
|
||||||
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveEmpty );
|
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveEmpty );
|
||||||
state = state.withProperty( Properties.FACING, EnumFacing.getFront( meta ) );
|
state = state.withProperty( Properties.FACING, EnumFacing.byIndex( meta ) );
|
||||||
}
|
}
|
||||||
else if( meta <= 9 )
|
else if( meta <= 9 )
|
||||||
{
|
{
|
||||||
@@ -93,7 +93,7 @@ public class BlockPeripheral extends BlockPeripheralBase
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.WirelessModemOff );
|
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.WirelessModemOff );
|
||||||
state = state.withProperty( Properties.FACING, EnumFacing.getFront( meta - 4 ) );
|
state = state.withProperty( Properties.FACING, EnumFacing.byIndex( meta - 4 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( meta == 10 )
|
else if( meta == 10 )
|
||||||
@@ -651,7 +651,7 @@ public class BlockPeripheral extends BlockPeripheralBase
|
|||||||
public boolean causesSuffocation(IBlockState state)
|
public boolean causesSuffocation(IBlockState state)
|
||||||
{
|
{
|
||||||
// This normally uses the default state
|
// This normally uses the default state
|
||||||
return blockMaterial.blocksMovement() && state.isOpaqueCube();
|
return material.blocksMovement() && state.isOpaqueCube();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -34,7 +34,7 @@ public class BlockWiredModemFull extends BlockPeripheralBase
|
|||||||
public BlockWiredModemFull()
|
public BlockWiredModemFull()
|
||||||
{
|
{
|
||||||
setHardness( 1.5f );
|
setHardness( 1.5f );
|
||||||
setUnlocalizedName( "computercraft:wired_modem_full" );
|
setTranslationKey( "computercraft:wired_modem_full" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
setDefaultState( blockState.getBaseState()
|
setDefaultState( blockState.getBaseState()
|
||||||
.withProperty( Properties.MODEM_ON, false )
|
.withProperty( Properties.MODEM_ON, false )
|
||||||
|
@@ -21,7 +21,7 @@ public class ItemAdvancedModem extends ItemPeripheralBase
|
|||||||
public ItemAdvancedModem( Block block )
|
public ItemAdvancedModem( Block block )
|
||||||
{
|
{
|
||||||
super( block );
|
super( block );
|
||||||
setUnlocalizedName( "computercraft:advanced_modem" );
|
setTranslationKey( "computercraft:advanced_modem" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -28,7 +28,7 @@ public class ItemCable extends ItemPeripheralBase
|
|||||||
public ItemCable( Block block )
|
public ItemCable( Block block )
|
||||||
{
|
{
|
||||||
super( block );
|
super( block );
|
||||||
setUnlocalizedName( "computercraft:cable" );
|
setTranslationKey( "computercraft:cable" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,8 +98,8 @@ public class ItemCable extends ItemPeripheralBase
|
|||||||
TileEntity tile = world.getTileEntity( pos );
|
TileEntity tile = world.getTileEntity( pos );
|
||||||
if( tile != null && tile instanceof TileCable )
|
if( tile != null && tile instanceof TileCable )
|
||||||
{
|
{
|
||||||
TileCable cable = (TileCable)tile;
|
TileCable cable = (TileCable) tile;
|
||||||
cable.networkChanged();
|
cable.connectionsChanged();
|
||||||
}
|
}
|
||||||
return EnumActionResult.SUCCESS;
|
return EnumActionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,8 @@ public class ItemCable extends ItemPeripheralBase
|
|||||||
if( tile != null && tile instanceof TileCable )
|
if( tile != null && tile instanceof TileCable )
|
||||||
{
|
{
|
||||||
TileCable cable = (TileCable)tile;
|
TileCable cable = (TileCable)tile;
|
||||||
cable.networkChanged();
|
cable.modemChanged();
|
||||||
|
cable.connectionsChanged();
|
||||||
}
|
}
|
||||||
return EnumActionResult.SUCCESS;
|
return EnumActionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -153,7 +154,8 @@ public class ItemCable extends ItemPeripheralBase
|
|||||||
if( tile != null && tile instanceof TileCable )
|
if( tile != null && tile instanceof TileCable )
|
||||||
{
|
{
|
||||||
TileCable cable = (TileCable)tile;
|
TileCable cable = (TileCable)tile;
|
||||||
cable.networkChanged();
|
cable.modemChanged();
|
||||||
|
cable.connectionsChanged();
|
||||||
}
|
}
|
||||||
return EnumActionResult.SUCCESS;
|
return EnumActionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,7 @@ public class ItemPeripheral extends ItemPeripheralBase
|
|||||||
public ItemPeripheral( Block block )
|
public ItemPeripheral( Block block )
|
||||||
{
|
{
|
||||||
super( block );
|
super( block );
|
||||||
setUnlocalizedName( "computercraft:peripheral" );
|
setTranslationKey( "computercraft:peripheral" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -59,7 +59,7 @@ public abstract class ItemPeripheralBase extends ItemBlock implements IPeriphera
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUnlocalizedName( @Nonnull ItemStack stack )
|
public String getTranslationKey( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
PeripheralType type = getPeripheralType( stack );
|
PeripheralType type = getPeripheralType( stack );
|
||||||
switch( type )
|
switch( type )
|
||||||
|
@@ -143,7 +143,7 @@ public abstract class TilePeripheralBase extends TileGeneric
|
|||||||
super.readFromNBT(nbttagcompound);
|
super.readFromNBT(nbttagcompound);
|
||||||
if( nbttagcompound.hasKey( "dir" ) )
|
if( nbttagcompound.hasKey( "dir" ) )
|
||||||
{
|
{
|
||||||
m_dir = EnumFacing.getFront( nbttagcompound.getInteger( "dir" ) );
|
m_dir = EnumFacing.byIndex( nbttagcompound.getInteger( "dir" ) );
|
||||||
}
|
}
|
||||||
if( nbttagcompound.hasKey( "anim" ) )
|
if( nbttagcompound.hasKey( "anim" ) )
|
||||||
{
|
{
|
||||||
@@ -174,7 +174,7 @@ public abstract class TilePeripheralBase extends TileGeneric
|
|||||||
public void readDescription( @Nonnull NBTTagCompound nbttagcompound )
|
public void readDescription( @Nonnull NBTTagCompound nbttagcompound )
|
||||||
{
|
{
|
||||||
super.readDescription( nbttagcompound );
|
super.readDescription( nbttagcompound );
|
||||||
m_dir = EnumFacing.getFront( nbttagcompound.getInteger( "dir" ) );
|
m_dir = EnumFacing.byIndex( nbttagcompound.getInteger( "dir" ) );
|
||||||
m_anim = nbttagcompound.getInteger( "anim" );
|
m_anim = nbttagcompound.getInteger( "anim" );
|
||||||
if( nbttagcompound.hasKey( "label" ) )
|
if( nbttagcompound.hasKey( "label" ) )
|
||||||
{
|
{
|
||||||
|
@@ -62,9 +62,9 @@ public class DiskDrivePeripheral implements IPeripheral
|
|||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
// isPresent
|
// isDiskPresent
|
||||||
return new Object[] {
|
return new Object[] {
|
||||||
m_diskDrive.getDiskStack() != null
|
!m_diskDrive.getDiskStack().isEmpty()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
|
@@ -422,6 +422,7 @@ public class TileDiskDrive extends TilePeripheralBase
|
|||||||
return new DiskDrivePeripheral( this );
|
return new DiskDrivePeripheral( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
public ItemStack getDiskStack()
|
public ItemStack getDiskStack()
|
||||||
{
|
{
|
||||||
synchronized( this )
|
synchronized( this )
|
||||||
@@ -604,8 +605,8 @@ public class TileDiskDrive extends TilePeripheralBase
|
|||||||
if( !destroyed )
|
if( !destroyed )
|
||||||
{
|
{
|
||||||
EnumFacing dir = getDirection();
|
EnumFacing dir = getDirection();
|
||||||
xOff = dir.getFrontOffsetX();
|
xOff = dir.getXOffset();
|
||||||
zOff = dir.getFrontOffsetZ();
|
zOff = dir.getZOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockPos pos = getPos();
|
BlockPos pos = getPos();
|
||||||
|
@@ -33,7 +33,7 @@ public class BlockAdvancedModem extends BlockPeripheralBase
|
|||||||
public BlockAdvancedModem()
|
public BlockAdvancedModem()
|
||||||
{
|
{
|
||||||
setHardness( 2.0f );
|
setHardness( 2.0f );
|
||||||
setUnlocalizedName( "computercraft:advanced_modem" );
|
setTranslationKey( "computercraft:advanced_modem" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
setDefaultState( this.blockState.getBaseState()
|
setDefaultState( this.blockState.getBaseState()
|
||||||
.withProperty( Properties.FACING, EnumFacing.NORTH )
|
.withProperty( Properties.FACING, EnumFacing.NORTH )
|
||||||
@@ -54,7 +54,7 @@ public class BlockAdvancedModem extends BlockPeripheralBase
|
|||||||
public IBlockState getStateFromMeta( int meta )
|
public IBlockState getStateFromMeta( int meta )
|
||||||
{
|
{
|
||||||
IBlockState state = getDefaultState();
|
IBlockState state = getDefaultState();
|
||||||
state = state.withProperty( Properties.FACING, EnumFacing.getFront( meta ) );
|
state = state.withProperty( Properties.FACING, EnumFacing.byIndex( meta ) );
|
||||||
state = state.withProperty( Properties.ON, false );
|
state = state.withProperty( Properties.ON, false );
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@@ -16,10 +16,7 @@ import dan200.computercraft.shared.peripheral.PeripheralType;
|
|||||||
import dan200.computercraft.shared.peripheral.common.BlockCable;
|
import dan200.computercraft.shared.peripheral.common.BlockCable;
|
||||||
import dan200.computercraft.shared.peripheral.common.BlockCableModemVariant;
|
import dan200.computercraft.shared.peripheral.common.BlockCableModemVariant;
|
||||||
import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory;
|
import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory;
|
||||||
import dan200.computercraft.shared.util.IDAssigner;
|
import dan200.computercraft.shared.wired.CapabilityWiredElement;
|
||||||
import dan200.computercraft.shared.util.PeripheralUtil;
|
|
||||||
import dan200.computercraft.api.network.wired.IWiredElementTile;
|
|
||||||
import net.minecraft.block.Block;
|
|
||||||
import net.minecraft.block.state.IBlockState;
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
@@ -31,15 +28,15 @@ import net.minecraft.util.math.BlockPos;
|
|||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.text.TextComponentTranslation;
|
import net.minecraft.util.text.TextComponentTranslation;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.File;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class TileCable extends TileModemBase implements IWiredElementTile
|
public class TileCable extends TileModemBase
|
||||||
{
|
{
|
||||||
public static final double MIN = 0.375;
|
public static final double MIN = 0.375;
|
||||||
public static final double MAX = 1 - MIN;
|
public static final double MAX = 1 - MIN;
|
||||||
@@ -75,26 +72,13 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
public Vec3d getPosition()
|
public Vec3d getPosition()
|
||||||
{
|
{
|
||||||
BlockPos pos = m_entity.getPos();
|
BlockPos pos = m_entity.getPos();
|
||||||
return new Vec3d( (double) pos.getX() + 0.5, (double) pos.getY() + 0.5, (double) pos.getZ() + 0.5 );
|
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public Map<String, IPeripheral> getPeripherals()
|
|
||||||
{
|
|
||||||
IPeripheral peripheral = m_entity.getConnectedPeripheral();
|
|
||||||
return peripheral != null
|
|
||||||
? Collections.singletonMap( m_entity.getConnectedPeripheralName(), peripheral )
|
|
||||||
: Collections.emptyMap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void attachPeripheral( String name, IPeripheral peripheral )
|
protected void attachPeripheral( String name, IPeripheral peripheral )
|
||||||
{
|
{
|
||||||
if( !name.equals( m_entity.getConnectedPeripheralName() ) )
|
((WiredModemPeripheral) m_entity.m_modem).attachPeripheral( name, peripheral );
|
||||||
{
|
|
||||||
((WiredModemPeripheral) m_entity.m_modem).attachPeripheral( name, peripheral );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -107,9 +91,9 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
// Members
|
// Members
|
||||||
|
|
||||||
private boolean m_peripheralAccessAllowed;
|
private boolean m_peripheralAccessAllowed;
|
||||||
private int m_attachedPeripheralID;
|
private WiredModemLocalPeripheral m_peripheral = new WiredModemLocalPeripheral();
|
||||||
|
|
||||||
private boolean m_destroyed;
|
private boolean m_destroyed = false;
|
||||||
|
|
||||||
private boolean m_hasDirection = false;
|
private boolean m_hasDirection = false;
|
||||||
private boolean m_connectionsFormed = false;
|
private boolean m_connectionsFormed = false;
|
||||||
@@ -117,14 +101,6 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
private WiredModemElement m_cable;
|
private WiredModemElement m_cable;
|
||||||
private IWiredNode m_node;
|
private IWiredNode m_node;
|
||||||
|
|
||||||
public TileCable()
|
|
||||||
{
|
|
||||||
m_peripheralAccessAllowed = false;
|
|
||||||
m_attachedPeripheralID = -1;
|
|
||||||
|
|
||||||
m_destroyed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ModemPeripheral createPeripheral()
|
protected ModemPeripheral createPeripheral()
|
||||||
{
|
{
|
||||||
@@ -132,6 +108,13 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
m_node = m_cable.getNode();
|
m_node = m_cable.getNode();
|
||||||
return new WiredModemPeripheral( m_cable )
|
return new WiredModemPeripheral( m_cable )
|
||||||
{
|
{
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
protected WiredModemLocalPeripheral getLocalPeripheral()
|
||||||
|
{
|
||||||
|
return m_peripheral;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Vec3d getPosition()
|
public Vec3d getPosition()
|
||||||
@@ -287,12 +270,32 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
((BlockGeneric) getBlockType()).dropItem( getWorld(), getPos(), PeripheralItemFactory.create( PeripheralType.WiredModem, getLabel(), 1 ) );
|
((BlockGeneric) getBlockType()).dropItem( getWorld(), getPos(), PeripheralItemFactory.create( PeripheralType.WiredModem, getLabel(), 1 ) );
|
||||||
setLabel( null );
|
setLabel( null );
|
||||||
setBlockState( getBlockState().withProperty( BlockCable.Properties.MODEM, BlockCableModemVariant.None ) );
|
setBlockState( getBlockState().withProperty( BlockCable.Properties.MODEM, BlockCableModemVariant.None ) );
|
||||||
networkChanged();
|
modemChanged();
|
||||||
|
connectionsChanged();
|
||||||
|
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !world.isRemote && m_peripheralAccessAllowed )
|
||||||
|
{
|
||||||
|
if( m_peripheral.attach( world, getPos(), dir ) ) updateConnectedPeripherals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
|
||||||
|
{
|
||||||
|
super.onNeighbourTileEntityChange( neighbour );
|
||||||
|
if( !world.isRemote && m_peripheralAccessAllowed )
|
||||||
|
{
|
||||||
|
EnumFacing facing = getDirection();
|
||||||
|
if( getPos().offset( facing ).equals( neighbour ) )
|
||||||
|
{
|
||||||
|
if( m_peripheral.attach( world, getPos(), facing ) ) updateConnectedPeripherals();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AxisAlignedBB getModemBounds()
|
public AxisAlignedBB getModemBounds()
|
||||||
@@ -395,9 +398,9 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
if( !getWorld().isRemote )
|
if( !getWorld().isRemote )
|
||||||
{
|
{
|
||||||
// On server, we interacted if a peripheral was found
|
// On server, we interacted if a peripheral was found
|
||||||
String oldPeriphName = getConnectedPeripheralName();
|
String oldPeriphName = m_peripheral.getConnectedName();
|
||||||
togglePeripheralAccess();
|
togglePeripheralAccess();
|
||||||
String periphName = getConnectedPeripheralName();
|
String periphName = m_peripheral.getConnectedName();
|
||||||
|
|
||||||
if( !Objects.equal( periphName, oldPeriphName ) )
|
if( !Objects.equal( periphName, oldPeriphName ) )
|
||||||
{
|
{
|
||||||
@@ -432,7 +435,7 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
// Read properties
|
// Read properties
|
||||||
super.readFromNBT( nbttagcompound );
|
super.readFromNBT( nbttagcompound );
|
||||||
m_peripheralAccessAllowed = nbttagcompound.getBoolean( "peripheralAccess" );
|
m_peripheralAccessAllowed = nbttagcompound.getBoolean( "peripheralAccess" );
|
||||||
m_attachedPeripheralID = nbttagcompound.getInteger( "peripheralID" );
|
m_peripheral.readNBT( nbttagcompound, "" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@@ -442,7 +445,7 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
// Write properties
|
// Write properties
|
||||||
nbttagcompound = super.writeToNBT( nbttagcompound );
|
nbttagcompound = super.writeToNBT( nbttagcompound );
|
||||||
nbttagcompound.setBoolean( "peripheralAccess", m_peripheralAccessAllowed );
|
nbttagcompound.setBoolean( "peripheralAccess", m_peripheralAccessAllowed );
|
||||||
nbttagcompound.setInteger( "peripheralID", m_attachedPeripheralID );
|
m_peripheral.writeNBT( nbttagcompound, "" );
|
||||||
return nbttagcompound;
|
return nbttagcompound;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,27 +473,31 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
{
|
{
|
||||||
if( !m_connectionsFormed )
|
if( !m_connectionsFormed )
|
||||||
{
|
{
|
||||||
networkChanged();
|
|
||||||
if( m_peripheralAccessAllowed ) m_node.invalidate();
|
|
||||||
m_connectionsFormed = true;
|
m_connectionsFormed = true;
|
||||||
|
|
||||||
|
connectionsChanged();
|
||||||
|
if( m_peripheralAccessAllowed )
|
||||||
|
{
|
||||||
|
m_peripheral.attach( world, pos, m_dir );
|
||||||
|
updateConnectedPeripherals();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void networkChanged()
|
public void connectionsChanged()
|
||||||
{
|
{
|
||||||
if( getWorld().isRemote ) return;
|
if( getWorld().isRemote ) return;
|
||||||
|
|
||||||
if( modemChanged() ) m_node.invalidate();
|
|
||||||
|
|
||||||
IBlockState state = getBlockState();
|
IBlockState state = getBlockState();
|
||||||
World world = getWorld();
|
World world = getWorld();
|
||||||
BlockPos current = getPos();
|
BlockPos current = getPos();
|
||||||
for( EnumFacing facing : EnumFacing.VALUES )
|
for( EnumFacing facing : EnumFacing.VALUES )
|
||||||
{
|
{
|
||||||
if( !world.isBlockLoaded( pos ) ) continue;
|
BlockPos offset = current.offset( facing );
|
||||||
|
if( !world.isBlockLoaded( offset ) ) continue;
|
||||||
IWiredElement element = ComputerCraft.getWiredElementAt( world, current.offset( facing ), facing.getOpposite() );
|
|
||||||
|
IWiredElement element = ComputerCraft.getWiredElementAt( world, offset, facing.getOpposite() );
|
||||||
if( element == null ) continue;
|
if( element == null ) continue;
|
||||||
|
|
||||||
if( BlockCable.canConnectIn( state, facing ) )
|
if( BlockCable.canConnectIn( state, facing ) )
|
||||||
@@ -506,27 +513,19 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean modemChanged()
|
public void modemChanged()
|
||||||
{
|
{
|
||||||
if( getWorld().isRemote ) return false;
|
if( getWorld().isRemote ) return;
|
||||||
|
|
||||||
boolean requiresUpdate = false;
|
|
||||||
|
|
||||||
PeripheralType type = getPeripheralType();
|
PeripheralType type = getPeripheralType();
|
||||||
if( type == PeripheralType.Cable )
|
|
||||||
{
|
|
||||||
m_attachedPeripheralID = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( type != PeripheralType.WiredModemWithCable && m_peripheralAccessAllowed )
|
if( type != PeripheralType.WiredModemWithCable && m_peripheralAccessAllowed )
|
||||||
{
|
{
|
||||||
m_peripheralAccessAllowed = false;
|
m_peripheralAccessAllowed = false;
|
||||||
requiresUpdate = true;
|
m_peripheral.detach();
|
||||||
|
m_node.updatePeripherals( Collections.emptyMap() );
|
||||||
markDirty();
|
markDirty();
|
||||||
updateAnim();
|
updateAnim();
|
||||||
}
|
}
|
||||||
|
|
||||||
return requiresUpdate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private stuff
|
// private stuff
|
||||||
@@ -534,61 +533,34 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
{
|
{
|
||||||
if( !m_peripheralAccessAllowed )
|
if( !m_peripheralAccessAllowed )
|
||||||
{
|
{
|
||||||
|
m_peripheral.attach( world, getPos(), getDirection() );
|
||||||
|
if( !m_peripheral.hasPeripheral() ) return;
|
||||||
|
|
||||||
m_peripheralAccessAllowed = true;
|
m_peripheralAccessAllowed = true;
|
||||||
if( getConnectedPeripheral() == null )
|
m_node.updatePeripherals( m_peripheral.toMap() );
|
||||||
{
|
|
||||||
m_peripheralAccessAllowed = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
m_peripheral.detach();
|
||||||
|
|
||||||
m_peripheralAccessAllowed = false;
|
m_peripheralAccessAllowed = false;
|
||||||
|
m_node.updatePeripherals( Collections.emptyMap() );
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAnim();
|
updateAnim();
|
||||||
m_node.invalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getConnectedPeripheralName()
|
private void updateConnectedPeripherals()
|
||||||
{
|
{
|
||||||
IPeripheral periph = getConnectedPeripheral();
|
Map<String, IPeripheral> peripherals = m_peripheral.toMap();
|
||||||
if( periph != null )
|
if( peripherals.isEmpty() )
|
||||||
{
|
{
|
||||||
String type = periph.getType();
|
// If there are no peripherals then disable access and update the display state.
|
||||||
if( m_attachedPeripheralID < 0 )
|
m_peripheralAccessAllowed = false;
|
||||||
{
|
updateAnim();
|
||||||
m_attachedPeripheralID = IDAssigner.getNextIDFromFile( new File(
|
|
||||||
ComputerCraft.getWorldDir( getWorld() ),
|
|
||||||
"computer/lastid_" + type + ".txt"
|
|
||||||
) );
|
|
||||||
}
|
|
||||||
return type + "_" + m_attachedPeripheralID;
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IPeripheral getConnectedPeripheral()
|
m_node.updatePeripherals( peripherals );
|
||||||
{
|
|
||||||
if( m_peripheralAccessAllowed )
|
|
||||||
{
|
|
||||||
if( getPeripheralType() == PeripheralType.WiredModemWithCable )
|
|
||||||
{
|
|
||||||
EnumFacing facing = getDirection();
|
|
||||||
BlockPos neighbour = getPos().offset( facing );
|
|
||||||
IPeripheral peripheral = getPeripheral( getWorld(), neighbour, facing.getOpposite() );
|
|
||||||
return peripheral == null || peripheral instanceof WiredModemPeripheral ? null : peripheral;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IPeripheral getPeripheral( World world, BlockPos pos, EnumFacing facing )
|
|
||||||
{
|
|
||||||
Block block = world.getBlockState( pos ).getBlock();
|
|
||||||
if( block == ComputerCraft.Blocks.wiredModemFull || block == ComputerCraft.Blocks.cable ) return null;
|
|
||||||
|
|
||||||
return PeripheralUtil.getPeripheral( world, pos, facing );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -597,13 +569,25 @@ public class TileCable extends TileModemBase implements IWiredElementTile
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// IWiredElement tile
|
// IWiredElement capability
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing facing )
|
||||||
|
{
|
||||||
|
if( capability == CapabilityWiredElement.CAPABILITY ) return BlockCable.canConnectIn( getBlockState(), facing );
|
||||||
|
return super.hasCapability( capability, facing );
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public IWiredElement getWiredElement( @Nonnull EnumFacing side )
|
public <T> T getCapability( @Nonnull Capability<T> capability, @Nullable EnumFacing facing )
|
||||||
{
|
{
|
||||||
return BlockCable.canConnectIn( getBlockState(), side ) ? m_cable : null;
|
if( capability == CapabilityWiredElement.CAPABILITY )
|
||||||
|
{
|
||||||
|
return BlockCable.canConnectIn( getBlockState(), facing ) ? CapabilityWiredElement.CAPABILITY.cast( m_cable ) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getCapability( capability, facing );
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPeripheralTile
|
// IPeripheralTile
|
||||||
|
@@ -9,12 +9,11 @@ package dan200.computercraft.shared.peripheral.modem;
|
|||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.api.network.wired.IWiredElement;
|
import dan200.computercraft.api.network.wired.IWiredElement;
|
||||||
import dan200.computercraft.api.network.wired.IWiredElementTile;
|
|
||||||
import dan200.computercraft.api.network.wired.IWiredNode;
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.shared.peripheral.common.BlockCable;
|
import dan200.computercraft.shared.peripheral.common.BlockCable;
|
||||||
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
|
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
|
||||||
import dan200.computercraft.shared.util.IDAssigner;
|
import dan200.computercraft.shared.wired.CapabilityWiredElement;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
@@ -23,13 +22,13 @@ import net.minecraft.util.math.BlockPos;
|
|||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.text.TextComponentTranslation;
|
import net.minecraft.util.text.TextComponentTranslation;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.util.Constants;
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.File;
|
import javax.annotation.Nullable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class TileWiredModemFull extends TilePeripheralBase implements IWiredElementTile
|
public class TileWiredModemFull extends TilePeripheralBase
|
||||||
{
|
{
|
||||||
private static class FullElement extends WiredModemElement
|
private static class FullElement extends WiredModemElement
|
||||||
{
|
{
|
||||||
@@ -46,10 +45,7 @@ public class TileWiredModemFull extends TilePeripheralBase implements IWiredElem
|
|||||||
for( int i = 0; i < 6; i++ )
|
for( int i = 0; i < 6; i++ )
|
||||||
{
|
{
|
||||||
WiredModemPeripheral modem = m_entity.m_modems[i];
|
WiredModemPeripheral modem = m_entity.m_modems[i];
|
||||||
if( modem != null && !name.equals( m_entity.getCachedPeripheralName( EnumFacing.VALUES[i] ) ) )
|
if( modem != null ) modem.attachPeripheral( name, peripheral );
|
||||||
{
|
|
||||||
modem.attachPeripheral( name, peripheral );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,37 +73,29 @@ public class TileWiredModemFull extends TilePeripheralBase implements IWiredElem
|
|||||||
BlockPos pos = m_entity.getPos();
|
BlockPos pos = m_entity.getPos();
|
||||||
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public Map<String, IPeripheral> getPeripherals()
|
|
||||||
{
|
|
||||||
return m_entity.getPeripherals();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private WiredModemPeripheral[] m_modems = new WiredModemPeripheral[6];
|
private WiredModemPeripheral[] m_modems = new WiredModemPeripheral[6];
|
||||||
|
|
||||||
private boolean m_peripheralAccessAllowed = false;
|
private boolean m_peripheralAccessAllowed = false;
|
||||||
private int[] m_attachedPeripheralIDs = new int[6];
|
private WiredModemLocalPeripheral[] m_peripherals = new WiredModemLocalPeripheral[6];
|
||||||
private String[] m_attachedPeripheralTypes = new String[6];
|
|
||||||
|
|
||||||
private boolean m_destroyed = false;
|
private boolean m_destroyed = false;
|
||||||
private boolean m_connectionsFormed = false;
|
private boolean m_connectionsFormed = false;
|
||||||
|
|
||||||
private final WiredModemElement m_element = new FullElement( this );
|
private final WiredModemElement m_element = new FullElement( this );
|
||||||
private final IWiredNode node = m_element.getNode();
|
private final IWiredNode m_node = m_element.getNode();
|
||||||
|
|
||||||
public TileWiredModemFull()
|
public TileWiredModemFull()
|
||||||
{
|
{
|
||||||
Arrays.fill( m_attachedPeripheralIDs, -1 );
|
for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i] = new WiredModemLocalPeripheral();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void remove()
|
private void remove()
|
||||||
{
|
{
|
||||||
if( world == null || !world.isRemote )
|
if( world == null || !world.isRemote )
|
||||||
{
|
{
|
||||||
node.remove();
|
m_node.remove();
|
||||||
m_connectionsFormed = false;
|
m_connectionsFormed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,18 +141,29 @@ public class TileWiredModemFull extends TilePeripheralBase implements IWiredElem
|
|||||||
{
|
{
|
||||||
if( !world.isRemote && m_peripheralAccessAllowed )
|
if( !world.isRemote && m_peripheralAccessAllowed )
|
||||||
{
|
{
|
||||||
Map<String, IPeripheral> updated = getPeripherals();
|
boolean hasChanged = false;
|
||||||
|
for( EnumFacing facing : EnumFacing.VALUES )
|
||||||
if( updated.isEmpty() )
|
|
||||||
{
|
{
|
||||||
// If there are no peripherals then disable access and update the display state.
|
hasChanged |= m_peripherals[facing.ordinal()].attach( world, getPos(), facing );
|
||||||
m_peripheralAccessAllowed = false;
|
|
||||||
updateAnim();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always invalidate the node: it's more accurate than checking if the peripherals
|
if( hasChanged ) updateConnectedPeripherals();
|
||||||
// have changed
|
}
|
||||||
node.invalidate();
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
|
||||||
|
{
|
||||||
|
if( !world.isRemote && m_peripheralAccessAllowed )
|
||||||
|
{
|
||||||
|
for( EnumFacing facing : EnumFacing.VALUES )
|
||||||
|
{
|
||||||
|
if( getPos().offset( facing ).equals( neighbour ) )
|
||||||
|
{
|
||||||
|
WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()];
|
||||||
|
if( peripheral.attach( world, getPos(), facing ) ) updateConnectedPeripherals();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,9 +180,9 @@ public class TileWiredModemFull extends TilePeripheralBase implements IWiredElem
|
|||||||
if( !getWorld().isRemote )
|
if( !getWorld().isRemote )
|
||||||
{
|
{
|
||||||
// On server, we interacted if a peripheral was found
|
// On server, we interacted if a peripheral was found
|
||||||
Set<String> oldPeriphName = getPeripherals().keySet();
|
Set<String> oldPeriphName = getConnectedPeripheralNames();
|
||||||
togglePeripheralAccess();
|
togglePeripheralAccess();
|
||||||
Set<String> periphName = getPeripherals().keySet();
|
Set<String> periphName = getConnectedPeripheralNames();
|
||||||
|
|
||||||
if( !Objects.equal( periphName, oldPeriphName ) )
|
if( !Objects.equal( periphName, oldPeriphName ) )
|
||||||
{
|
{
|
||||||
@@ -221,17 +220,7 @@ public class TileWiredModemFull extends TilePeripheralBase implements IWiredElem
|
|||||||
{
|
{
|
||||||
super.readFromNBT( tag );
|
super.readFromNBT( tag );
|
||||||
m_peripheralAccessAllowed = tag.getBoolean( "peripheralAccess" );
|
m_peripheralAccessAllowed = tag.getBoolean( "peripheralAccess" );
|
||||||
for( int i = 0; i < m_attachedPeripheralIDs.length; i++ )
|
for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].readNBT( tag, "_" + i );
|
||||||
{
|
|
||||||
if( tag.hasKey( "peripheralID_" + i, Constants.NBT.TAG_ANY_NUMERIC ) )
|
|
||||||
{
|
|
||||||
m_attachedPeripheralIDs[i] = tag.getInteger( "peripheralID_" + i );
|
|
||||||
}
|
|
||||||
if( tag.hasKey( "peripheralType_" + i, Constants.NBT.TAG_STRING ) )
|
|
||||||
{
|
|
||||||
m_attachedPeripheralTypes[i] = tag.getString( "peripheralType_" + i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@@ -240,17 +229,7 @@ public class TileWiredModemFull extends TilePeripheralBase implements IWiredElem
|
|||||||
{
|
{
|
||||||
tag = super.writeToNBT( tag );
|
tag = super.writeToNBT( tag );
|
||||||
tag.setBoolean( "peripheralAccess", m_peripheralAccessAllowed );
|
tag.setBoolean( "peripheralAccess", m_peripheralAccessAllowed );
|
||||||
for( int i = 0; i < m_attachedPeripheralIDs.length; i++ )
|
for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].writeNBT( tag, "_" + i );
|
||||||
{
|
|
||||||
if( m_attachedPeripheralIDs[i] >= 0 )
|
|
||||||
{
|
|
||||||
tag.setInteger( "peripheralID_" + i, m_attachedPeripheralIDs[i] );
|
|
||||||
}
|
|
||||||
if( m_attachedPeripheralTypes[i] != null )
|
|
||||||
{
|
|
||||||
tag.setString( "peripheralType_" + i, m_attachedPeripheralTypes[i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,15 +273,24 @@ public class TileWiredModemFull extends TilePeripheralBase implements IWiredElem
|
|||||||
|
|
||||||
if( !m_connectionsFormed )
|
if( !m_connectionsFormed )
|
||||||
{
|
{
|
||||||
networkChanged();
|
|
||||||
m_connectionsFormed = true;
|
m_connectionsFormed = true;
|
||||||
|
|
||||||
|
connectionsChanged();
|
||||||
|
if( m_peripheralAccessAllowed )
|
||||||
|
{
|
||||||
|
for( EnumFacing facing : EnumFacing.VALUES )
|
||||||
|
{
|
||||||
|
m_peripherals[facing.ordinal()].attach( world, getPos(), facing );
|
||||||
|
}
|
||||||
|
updateConnectedPeripherals();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.update();
|
super.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void networkChanged()
|
private void connectionsChanged()
|
||||||
{
|
{
|
||||||
if( getWorld().isRemote ) return;
|
if( getWorld().isRemote ) return;
|
||||||
|
|
||||||
@@ -310,16 +298,15 @@ public class TileWiredModemFull extends TilePeripheralBase implements IWiredElem
|
|||||||
BlockPos current = getPos();
|
BlockPos current = getPos();
|
||||||
for( EnumFacing facing : EnumFacing.VALUES )
|
for( EnumFacing facing : EnumFacing.VALUES )
|
||||||
{
|
{
|
||||||
if( !world.isBlockLoaded( pos ) ) continue;
|
BlockPos offset = current.offset( facing );
|
||||||
|
if( !world.isBlockLoaded( offset ) ) continue;
|
||||||
|
|
||||||
IWiredElement element = ComputerCraft.getWiredElementAt( world, current.offset( facing ), facing.getOpposite() );
|
IWiredElement element = ComputerCraft.getWiredElementAt( world, offset, facing.getOpposite() );
|
||||||
if( element == null ) continue;
|
if( element == null ) continue;
|
||||||
|
|
||||||
// If we can connect to it then do so
|
// If we can connect to it then do so
|
||||||
node.connectTo( element.getNode() );
|
m_node.connectTo( element.getNode() );
|
||||||
}
|
}
|
||||||
|
|
||||||
node.invalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private stuff
|
// private stuff
|
||||||
@@ -327,69 +314,83 @@ public class TileWiredModemFull extends TilePeripheralBase implements IWiredElem
|
|||||||
{
|
{
|
||||||
if( !m_peripheralAccessAllowed )
|
if( !m_peripheralAccessAllowed )
|
||||||
{
|
{
|
||||||
m_peripheralAccessAllowed = true;
|
boolean hasAny = false;
|
||||||
if( getPeripherals().isEmpty() )
|
for( EnumFacing facing : EnumFacing.VALUES )
|
||||||
{
|
{
|
||||||
m_peripheralAccessAllowed = false;
|
WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()];
|
||||||
return;
|
peripheral.attach( world, getPos(), facing );
|
||||||
|
hasAny |= peripheral.hasPeripheral();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !hasAny ) return;
|
||||||
|
|
||||||
|
m_peripheralAccessAllowed = true;
|
||||||
|
m_node.updatePeripherals( getConnectedPeripherals() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_peripheralAccessAllowed = false;
|
m_peripheralAccessAllowed = false;
|
||||||
|
|
||||||
|
for( WiredModemLocalPeripheral peripheral : m_peripherals ) peripheral.detach();
|
||||||
|
m_node.updatePeripherals( Collections.emptyMap() );
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAnim();
|
updateAnim();
|
||||||
node.invalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
private Set<String> getConnectedPeripheralNames()
|
||||||
private Map<String, IPeripheral> getPeripherals()
|
{
|
||||||
|
if( !m_peripheralAccessAllowed ) return Collections.emptySet();
|
||||||
|
|
||||||
|
Set<String> peripherals = new HashSet<>( 6 );
|
||||||
|
for( WiredModemLocalPeripheral m_peripheral : m_peripherals )
|
||||||
|
{
|
||||||
|
String name = m_peripheral.getConnectedName();
|
||||||
|
if( name != null ) peripherals.add( name );
|
||||||
|
}
|
||||||
|
return peripherals;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, IPeripheral> getConnectedPeripherals()
|
||||||
{
|
{
|
||||||
if( !m_peripheralAccessAllowed ) return Collections.emptyMap();
|
if( !m_peripheralAccessAllowed ) return Collections.emptyMap();
|
||||||
|
|
||||||
Map<String, IPeripheral> peripherals = new HashMap<>( 6 );
|
Map<String, IPeripheral> peripherals = new HashMap<>( 6 );
|
||||||
for( EnumFacing facing : EnumFacing.VALUES )
|
for( WiredModemLocalPeripheral m_peripheral : m_peripherals ) m_peripheral.extendMap( peripherals );
|
||||||
{
|
|
||||||
BlockPos neighbour = getPos().offset( facing );
|
|
||||||
IPeripheral peripheral = TileCable.getPeripheral( getWorld(), neighbour, facing.getOpposite() );
|
|
||||||
if( peripheral != null && !(peripheral instanceof WiredModemPeripheral) )
|
|
||||||
{
|
|
||||||
String type = peripheral.getType();
|
|
||||||
int id = m_attachedPeripheralIDs[facing.ordinal()];
|
|
||||||
String oldType = m_attachedPeripheralTypes[facing.ordinal()];
|
|
||||||
if( id < 0 || !type.equals( oldType ) )
|
|
||||||
{
|
|
||||||
m_attachedPeripheralTypes[facing.ordinal()] = type;
|
|
||||||
id = m_attachedPeripheralIDs[facing.ordinal()] = IDAssigner.getNextIDFromFile( new File(
|
|
||||||
ComputerCraft.getWorldDir( getWorld() ),
|
|
||||||
"computer/lastid_" + type + ".txt"
|
|
||||||
) );
|
|
||||||
}
|
|
||||||
|
|
||||||
peripherals.put( type + "_" + id, peripheral );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return peripherals;
|
return peripherals;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCachedPeripheralName( EnumFacing facing )
|
private void updateConnectedPeripherals()
|
||||||
{
|
{
|
||||||
if( !m_peripheralAccessAllowed ) return null;
|
Map<String, IPeripheral> peripherals = getConnectedPeripherals();
|
||||||
|
if( peripherals.isEmpty() )
|
||||||
|
{
|
||||||
|
// If there are no peripherals then disable access and update the display state.
|
||||||
|
m_peripheralAccessAllowed = false;
|
||||||
|
updateAnim();
|
||||||
|
}
|
||||||
|
|
||||||
int id = m_attachedPeripheralIDs[facing.ordinal()];
|
m_node.updatePeripherals( peripherals );
|
||||||
String type = m_attachedPeripheralTypes[facing.ordinal()];
|
|
||||||
return id < 0 || type == null ? null : type + "_" + id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IWiredElementTile
|
// IWiredElementTile
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
@Override
|
||||||
public IWiredElement getWiredElement( @Nonnull EnumFacing side )
|
public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing facing )
|
||||||
{
|
{
|
||||||
return m_element;
|
return capability == CapabilityWiredElement.CAPABILITY || super.hasCapability( capability, facing );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public <T> T getCapability( @Nonnull Capability<T> capability, @Nullable EnumFacing facing )
|
||||||
|
{
|
||||||
|
if( capability == CapabilityWiredElement.CAPABILITY )
|
||||||
|
{
|
||||||
|
return CapabilityWiredElement.CAPABILITY.cast( m_element );
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getCapability( capability, facing );
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPeripheralTile
|
// IPeripheralTile
|
||||||
@@ -400,8 +401,16 @@ public class TileWiredModemFull extends TilePeripheralBase implements IWiredElem
|
|||||||
WiredModemPeripheral peripheral = m_modems[side.ordinal()];
|
WiredModemPeripheral peripheral = m_modems[side.ordinal()];
|
||||||
if( peripheral == null )
|
if( peripheral == null )
|
||||||
{
|
{
|
||||||
|
WiredModemLocalPeripheral localPeripheral = m_peripherals[side.ordinal()];
|
||||||
peripheral = m_modems[side.ordinal()] = new WiredModemPeripheral( m_element )
|
peripheral = m_modems[side.ordinal()] = new WiredModemPeripheral( m_element )
|
||||||
{
|
{
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
protected WiredModemLocalPeripheral getLocalPeripheral()
|
||||||
|
{
|
||||||
|
return localPeripheral;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Vec3d getPosition()
|
public Vec3d getPosition()
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package dan200.computercraft.shared.peripheral.modem;
|
package dan200.computercraft.shared.peripheral.modem;
|
||||||
|
|
||||||
import dan200.computercraft.api.network.wired.IWiredNetworkChange;
|
|
||||||
import dan200.computercraft.api.network.wired.IWiredElement;
|
import dan200.computercraft.api.network.wired.IWiredElement;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredNetworkChange;
|
||||||
import dan200.computercraft.api.network.wired.IWiredNode;
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.shared.wired.WiredNode;
|
import dan200.computercraft.shared.wired.WiredNode;
|
||||||
|
@@ -0,0 +1,139 @@
|
|||||||
|
package dan200.computercraft.shared.peripheral.modem;
|
||||||
|
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
import dan200.computercraft.shared.util.IDAssigner;
|
||||||
|
import dan200.computercraft.shared.util.PeripheralUtil;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.Constants;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a local peripheral exposed on the wired network
|
||||||
|
*
|
||||||
|
* This is responsible for getting the peripheral in world, tracking id and type and determining whether
|
||||||
|
* it has changed.
|
||||||
|
*/
|
||||||
|
public final class WiredModemLocalPeripheral
|
||||||
|
{
|
||||||
|
private int id;
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
private IPeripheral peripheral;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach a new peripheral from the world
|
||||||
|
*
|
||||||
|
* @param world The world to search in
|
||||||
|
* @param origin The position to search from
|
||||||
|
* @param direction The direction so search in
|
||||||
|
* @return Whether the peripheral changed.
|
||||||
|
*/
|
||||||
|
public boolean attach( @Nonnull World world, @Nonnull BlockPos origin, @Nonnull EnumFacing direction )
|
||||||
|
{
|
||||||
|
IPeripheral oldPeripheral = this.peripheral;
|
||||||
|
IPeripheral peripheral = this.peripheral = getPeripheralFrom( world, origin, direction );
|
||||||
|
|
||||||
|
if( peripheral == null )
|
||||||
|
{
|
||||||
|
return oldPeripheral != null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String type = peripheral.getType();
|
||||||
|
int id = this.id;
|
||||||
|
|
||||||
|
if( id > 0 && this.type == null )
|
||||||
|
{
|
||||||
|
// If we had an ID but no type, then just set the type.
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
else if( id < 0 || !type.equals( this.type ) )
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
this.id = IDAssigner.getNextIDFromFile( new File(
|
||||||
|
ComputerCraft.getWorldDir( world ),
|
||||||
|
"computer/lastid_" + type + ".txt"
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldPeripheral == null || !oldPeripheral.equals( peripheral );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach the current peripheral
|
||||||
|
*
|
||||||
|
* @return Whether the peripheral changed
|
||||||
|
*/
|
||||||
|
public boolean detach()
|
||||||
|
{
|
||||||
|
if( peripheral == null ) return false;
|
||||||
|
peripheral = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getConnectedName()
|
||||||
|
{
|
||||||
|
return peripheral != null ? type + "_" + id : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public IPeripheral getPeripheral()
|
||||||
|
{
|
||||||
|
return peripheral;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPeripheral()
|
||||||
|
{
|
||||||
|
return peripheral != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void extendMap( @Nonnull Map<String, IPeripheral> peripherals )
|
||||||
|
{
|
||||||
|
if( peripheral != null ) peripherals.put( type + "_" + id, peripheral );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, IPeripheral> toMap()
|
||||||
|
{
|
||||||
|
return peripheral == null
|
||||||
|
? Collections.emptyMap()
|
||||||
|
: Collections.singletonMap( type + "_" + id, peripheral );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeNBT( @Nonnull NBTTagCompound tag, @Nonnull String suffix )
|
||||||
|
{
|
||||||
|
if( id >= 0 ) tag.setInteger( "peripheralID" + suffix, id );
|
||||||
|
if( type != null ) tag.setString( "peripheralType" + suffix, type );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readNBT( @Nonnull NBTTagCompound tag, @Nonnull String suffix )
|
||||||
|
{
|
||||||
|
id = tag.hasKey( "peripheralID" + suffix, Constants.NBT.TAG_ANY_NUMERIC )
|
||||||
|
? tag.getInteger( "peripheralID" + suffix ) : -1;
|
||||||
|
|
||||||
|
type = tag.hasKey( "peripheralType" + suffix, Constants.NBT.TAG_STRING )
|
||||||
|
? tag.getString( "peripheralType" + suffix ) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IPeripheral getPeripheralFrom( World world, BlockPos pos, EnumFacing direction )
|
||||||
|
{
|
||||||
|
BlockPos offset = pos.offset( direction );
|
||||||
|
|
||||||
|
Block block = world.getBlockState( offset ).getBlock();
|
||||||
|
if( block == ComputerCraft.Blocks.wiredModemFull || block == ComputerCraft.Blocks.cable ) return null;
|
||||||
|
|
||||||
|
IPeripheral peripheral = PeripheralUtil.getPeripheral( world, offset, direction.getOpposite() );
|
||||||
|
return peripheral instanceof WiredModemPeripheral ? null : peripheral;
|
||||||
|
}
|
||||||
|
}
|
@@ -10,7 +10,8 @@ import dan200.computercraft.api.network.wired.IWiredNode;
|
|||||||
import dan200.computercraft.api.network.wired.IWiredSender;
|
import dan200.computercraft.api.network.wired.IWiredSender;
|
||||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import dan200.computercraft.core.computer.Computer;
|
||||||
|
import dan200.computercraft.core.computer.IComputerOwned;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@@ -20,7 +21,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
||||||
|
|
||||||
public class WiredModemPeripheral extends ModemPeripheral implements IWiredSender
|
public abstract class WiredModemPeripheral extends ModemPeripheral implements IWiredSender
|
||||||
{
|
{
|
||||||
private final WiredModemElement modem;
|
private final WiredModemElement modem;
|
||||||
|
|
||||||
@@ -58,11 +59,7 @@ public class WiredModemPeripheral extends ModemPeripheral implements IWiredSende
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
protected abstract WiredModemLocalPeripheral getLocalPeripheral();
|
||||||
public Vec3d getPosition()
|
|
||||||
{
|
|
||||||
return modem.getPosition();
|
|
||||||
}
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
//region IPeripheral
|
//region IPeripheral
|
||||||
@@ -71,13 +68,14 @@ public class WiredModemPeripheral extends ModemPeripheral implements IWiredSende
|
|||||||
public String[] getMethodNames()
|
public String[] getMethodNames()
|
||||||
{
|
{
|
||||||
String[] methods = super.getMethodNames();
|
String[] methods = super.getMethodNames();
|
||||||
String[] newMethods = new String[methods.length + 5];
|
String[] newMethods = new String[methods.length + 6];
|
||||||
System.arraycopy( methods, 0, newMethods, 0, methods.length );
|
System.arraycopy( methods, 0, newMethods, 0, methods.length );
|
||||||
newMethods[methods.length] = "getNamesRemote";
|
newMethods[methods.length] = "getNamesRemote";
|
||||||
newMethods[methods.length + 1] = "isPresentRemote";
|
newMethods[methods.length + 1] = "isPresentRemote";
|
||||||
newMethods[methods.length + 2] = "getTypeRemote";
|
newMethods[methods.length + 2] = "getTypeRemote";
|
||||||
newMethods[methods.length + 3] = "getMethodsRemote";
|
newMethods[methods.length + 3] = "getMethodsRemote";
|
||||||
newMethods[methods.length + 4] = "callRemote";
|
newMethods[methods.length + 4] = "callRemote";
|
||||||
|
newMethods[methods.length + 5] = "getNameLocal";
|
||||||
return newMethods;
|
return newMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +139,12 @@ public class WiredModemPeripheral extends ModemPeripheral implements IWiredSende
|
|||||||
System.arraycopy( arguments, 2, methodArgs, 0, arguments.length - 2 );
|
System.arraycopy( arguments, 2, methodArgs, 0, arguments.length - 2 );
|
||||||
return callMethodRemote( remoteName, context, methodName, methodArgs );
|
return callMethodRemote( remoteName, context, methodName, methodArgs );
|
||||||
}
|
}
|
||||||
|
case 5:
|
||||||
|
{
|
||||||
|
// getNameLocal
|
||||||
|
String local = getLocalPeripheral().getConnectedName();
|
||||||
|
return local == null ? null : new Object[]{ local };
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// The regular modem methods
|
// The regular modem methods
|
||||||
@@ -223,7 +227,7 @@ public class WiredModemPeripheral extends ModemPeripheral implements IWiredSende
|
|||||||
|
|
||||||
private void attachPeripheralImpl( String periphName, IPeripheral peripheral )
|
private void attachPeripheralImpl( String periphName, IPeripheral peripheral )
|
||||||
{
|
{
|
||||||
if( !peripheralWrappers.containsKey( periphName ) )
|
if( !peripheralWrappers.containsKey( periphName ) && !periphName.equals( getLocalPeripheral().getConnectedName() ) )
|
||||||
{
|
{
|
||||||
RemotePeripheralWrapper wrapper = new RemotePeripheralWrapper( modem, peripheral, getComputer(), periphName );
|
RemotePeripheralWrapper wrapper = new RemotePeripheralWrapper( modem, peripheral, getComputer(), periphName );
|
||||||
peripheralWrappers.put( periphName, wrapper );
|
peripheralWrappers.put( periphName, wrapper );
|
||||||
@@ -271,7 +275,7 @@ public class WiredModemPeripheral extends ModemPeripheral implements IWiredSende
|
|||||||
throw new LuaException( "No peripheral: " + remoteName );
|
throw new LuaException( "No peripheral: " + remoteName );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class RemotePeripheralWrapper implements IComputerAccess
|
private static class RemotePeripheralWrapper implements IComputerAccess, IComputerOwned
|
||||||
{
|
{
|
||||||
private final WiredModemElement m_element;
|
private final WiredModemElement m_element;
|
||||||
private final IPeripheral m_peripheral;
|
private final IPeripheral m_peripheral;
|
||||||
@@ -406,5 +410,12 @@ public class WiredModemPeripheral extends ModemPeripheral implements IWiredSende
|
|||||||
return m_element.getRemotePeripherals().get( name );
|
return m_element.getRemotePeripherals().get( name );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Computer getComputer()
|
||||||
|
{
|
||||||
|
return m_computer instanceof IComputerOwned ? ((IComputerOwned) m_computer).getComputer() : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package dan200.computercraft.shared.peripheral.monitor;
|
|||||||
|
|
||||||
import dan200.computercraft.shared.common.ClientTerminal;
|
import dan200.computercraft.shared.common.ClientTerminal;
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@@ -14,6 +15,7 @@ public class ClientMonitor extends ClientTerminal
|
|||||||
private final TileMonitor origin;
|
private final TileMonitor origin;
|
||||||
|
|
||||||
public long lastRenderFrame = -1;
|
public long lastRenderFrame = -1;
|
||||||
|
public BlockPos lastRenderPos = null;
|
||||||
public int[] renderDisplayLists = null;
|
public int[] renderDisplayLists = null;
|
||||||
|
|
||||||
public ClientMonitor( boolean colour, TileMonitor origin )
|
public ClientMonitor( boolean colour, TileMonitor origin )
|
||||||
|
@@ -344,7 +344,7 @@ public class TileMonitor extends TilePeripheralBase
|
|||||||
|
|
||||||
public EnumFacing getFront()
|
public EnumFacing getFront()
|
||||||
{
|
{
|
||||||
return m_dir <= 5 ? EnumFacing.getFront( m_dir ) : (m_dir <= 11 ? EnumFacing.DOWN : EnumFacing.UP);
|
return m_dir <= 5 ? EnumFacing.byIndex( m_dir ) : (m_dir <= 11 ? EnumFacing.DOWN : EnumFacing.UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EnumFacing getRight()
|
public EnumFacing getRight()
|
||||||
|
@@ -8,6 +8,7 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
|
|||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
import net.minecraft.entity.player.InventoryPlayer;
|
import net.minecraft.entity.player.InventoryPlayer;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
@@ -138,7 +139,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
|||||||
{
|
{
|
||||||
if( this.m_upgrade == upgrade ) return;
|
if( this.m_upgrade == upgrade ) return;
|
||||||
|
|
||||||
synchronized (this)
|
synchronized( this )
|
||||||
{
|
{
|
||||||
ComputerCraft.Items.pocketComputer.setUpgrade( m_stack, upgrade );
|
ComputerCraft.Items.pocketComputer.setUpgrade( m_stack, upgrade );
|
||||||
if( m_entity instanceof EntityPlayer ) ((EntityPlayer) m_entity).inventory.markDirty();
|
if( m_entity instanceof EntityPlayer ) ((EntityPlayer) m_entity).inventory.markDirty();
|
||||||
@@ -156,6 +157,9 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
|||||||
setPosition( entity.getPosition() );
|
setPosition( entity.getPosition() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a new entity has picked it up then rebroadcast the terminal to them
|
||||||
|
if( entity != m_entity && entity instanceof EntityPlayerMP ) markTerminalChanged();
|
||||||
|
|
||||||
m_entity = entity;
|
m_entity = entity;
|
||||||
m_stack = stack;
|
m_stack = stack;
|
||||||
|
|
||||||
@@ -165,4 +169,19 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
|||||||
invalidatePeripheral();
|
invalidatePeripheral();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void broadcastState( boolean force )
|
||||||
|
{
|
||||||
|
super.broadcastState( force );
|
||||||
|
|
||||||
|
if( (hasTerminalChanged() || force) && m_entity instanceof EntityPlayerMP )
|
||||||
|
{
|
||||||
|
// Broadcast the state to the current entity if they're not already interacting with it.
|
||||||
|
EntityPlayerMP player = (EntityPlayerMP) m_entity;
|
||||||
|
if( player.connection != null && !isInteracting( player ) )
|
||||||
|
{
|
||||||
|
ComputerCraft.sendToPlayer( player, createTerminalPacket() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -43,7 +43,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
|
|||||||
{
|
{
|
||||||
setMaxStackSize( 1 );
|
setMaxStackSize( 1 );
|
||||||
setHasSubtypes( true );
|
setHasSubtypes( true );
|
||||||
setUnlocalizedName( "computercraft:pocket_computer" );
|
setTranslationKey( "computercraft:pocket_computer" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUnlocalizedName( @Nonnull ItemStack stack )
|
public String getTranslationKey( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
switch( getFamily( stack ) )
|
switch( getFamily( stack ) )
|
||||||
{
|
{
|
||||||
@@ -209,7 +209,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
|
|||||||
@Override
|
@Override
|
||||||
public String getItemStackDisplayName( @Nonnull ItemStack stack )
|
public String getItemStackDisplayName( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
String baseString = getUnlocalizedName( stack );
|
String baseString = getTranslationKey( stack );
|
||||||
IPocketUpgrade upgrade = getUpgrade( stack );
|
IPocketUpgrade upgrade = getUpgrade( stack );
|
||||||
if( upgrade != null )
|
if( upgrade != null )
|
||||||
{
|
{
|
||||||
|
@@ -34,7 +34,7 @@ public class PocketComputerUpgradeRecipe extends IForgeRegistryEntry.Impl<IRecip
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isHidden()
|
public boolean isDynamic()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,6 @@ import dan200.computercraft.shared.turtle.items.ItemTurtleNormal;
|
|||||||
import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
|
import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
|
||||||
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
||||||
import dan200.computercraft.shared.turtle.upgrades.*;
|
import dan200.computercraft.shared.turtle.upgrades.*;
|
||||||
import dan200.computercraft.shared.util.IEntityDropConsumer;
|
|
||||||
import dan200.computercraft.shared.util.ImpostorRecipe;
|
import dan200.computercraft.shared.util.ImpostorRecipe;
|
||||||
import dan200.computercraft.shared.util.InventoryUtil;
|
import dan200.computercraft.shared.util.InventoryUtil;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
@@ -33,33 +32,49 @@ import net.minecraft.item.ItemStack;
|
|||||||
import net.minecraft.item.crafting.IRecipe;
|
import net.minecraft.item.crafting.IRecipe;
|
||||||
import net.minecraft.util.NonNullList;
|
import net.minecraft.util.NonNullList;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.RegistryEvent;
|
import net.minecraftforge.event.RegistryEvent;
|
||||||
|
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
|
||||||
import net.minecraftforge.event.entity.living.LivingDropsEvent;
|
import net.minecraftforge.event.entity.living.LivingDropsEvent;
|
||||||
|
import net.minecraftforge.event.world.BlockEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.EventPriority;
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.registry.EntityRegistry;
|
import net.minecraftforge.fml.common.registry.EntityRegistry;
|
||||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||||
import net.minecraftforge.registries.IForgeRegistry;
|
import net.minecraftforge.registries.IForgeRegistry;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
||||||
{
|
{
|
||||||
private Map<Integer, ITurtleUpgrade> m_legacyTurtleUpgrades;
|
private Map<Integer, ITurtleUpgrade> m_legacyTurtleUpgrades;
|
||||||
private Map<String, ITurtleUpgrade> m_turtleUpgrades;
|
private Map<String, ITurtleUpgrade> m_turtleUpgrades;
|
||||||
private Map<Entity, IEntityDropConsumer> m_dropConsumers;
|
|
||||||
|
private Function<ItemStack, ItemStack> dropConsumer;
|
||||||
|
private List<ItemStack> remainingDrops;
|
||||||
|
private WeakReference<World> dropWorld;
|
||||||
|
private BlockPos dropPos;
|
||||||
|
private AxisAlignedBB dropBounds;
|
||||||
|
private WeakReference<Entity> dropEntity;
|
||||||
|
|
||||||
public CCTurtleProxyCommon()
|
public CCTurtleProxyCommon()
|
||||||
{
|
{
|
||||||
m_legacyTurtleUpgrades = new HashMap<>();
|
m_legacyTurtleUpgrades = new HashMap<>();
|
||||||
m_turtleUpgrades = new HashMap<>();
|
m_turtleUpgrades = new HashMap<>();
|
||||||
m_dropConsumers = new WeakHashMap<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ICCTurtleProxy implementation
|
// ICCTurtleProxy implementation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preInit()
|
public void preInit()
|
||||||
{
|
{
|
||||||
MinecraftForge.EVENT_BUS.register( this );
|
MinecraftForge.EVENT_BUS.register( this );
|
||||||
@@ -75,8 +90,8 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
// RecipeSorter.register( "computercraft:turtle", TurtleRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" );
|
// RecipeSorter.register( "computercraft:turtle", TurtleRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" );
|
||||||
// RecipeSorter.register( "computercraft:turtle_upgrade", TurtleUpgradeRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" );
|
// RecipeSorter.register( "computercraft:turtle_upgrade", TurtleUpgradeRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init()
|
public void init()
|
||||||
{
|
{
|
||||||
registerForgeHandlers();
|
registerForgeHandlers();
|
||||||
@@ -94,7 +109,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
ComputerCraft.log.error( message );
|
ComputerCraft.log.error( message );
|
||||||
throw new RuntimeException( message );
|
throw new RuntimeException( message );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
registerTurtleUpgradeInternal( upgrade );
|
registerTurtleUpgradeInternal( upgrade );
|
||||||
}
|
}
|
||||||
@@ -110,7 +125,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
{
|
{
|
||||||
return m_legacyTurtleUpgrades.get( legacyId );
|
return m_legacyTurtleUpgrades.get( legacyId );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack stack )
|
public ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
@@ -126,7 +141,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
}
|
}
|
||||||
catch( Exception e )
|
catch( Exception e )
|
||||||
{
|
{
|
||||||
ComputerCraft.log.error("Error getting computer upgrade item", e);
|
ComputerCraft.log.error( "Error getting computer upgrade item", e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -148,7 +163,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAllUpgradedTurtles( ComputerFamily family, NonNullList<ItemStack> list )
|
private void addAllUpgradedTurtles( ComputerFamily family, NonNullList<ItemStack> list )
|
||||||
{
|
{
|
||||||
ItemStack basicStack = TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null );
|
ItemStack basicStack = TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null );
|
||||||
@@ -169,7 +184,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
|
|
||||||
private void addUpgradedTurtle( ComputerFamily family, ITurtleUpgrade upgrade, List<ItemStack> list )
|
private void addUpgradedTurtle( ComputerFamily family, ITurtleUpgrade upgrade, List<ItemStack> list )
|
||||||
{
|
{
|
||||||
if ( isUpgradeSuitableForFamily( family, upgrade ) )
|
if( isUpgradeSuitableForFamily( family, upgrade ) )
|
||||||
{
|
{
|
||||||
ItemStack stack = TurtleItemFactory.create( -1, null, -1, family, upgrade, null, 0, null );
|
ItemStack stack = TurtleItemFactory.create( -1, null, -1, family, upgrade, null, 0, null );
|
||||||
if( !stack.isEmpty() )
|
if( !stack.isEmpty() )
|
||||||
@@ -178,54 +193,65 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addAllUpgradedTurtles( NonNullList<ItemStack> list )
|
public void addAllUpgradedTurtles( NonNullList<ItemStack> list )
|
||||||
{
|
{
|
||||||
addAllUpgradedTurtles( ComputerFamily.Normal, list );
|
addAllUpgradedTurtles( ComputerFamily.Normal, list );
|
||||||
addAllUpgradedTurtles( ComputerFamily.Advanced, list );
|
addAllUpgradedTurtles( ComputerFamily.Advanced, list );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer )
|
public void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer )
|
||||||
{
|
{
|
||||||
if( !m_dropConsumers.containsKey( entity ) )
|
dropConsumer = consumer;
|
||||||
{
|
remainingDrops = new ArrayList<>();
|
||||||
boolean captured = entity.captureDrops;
|
dropEntity = new WeakReference<>( entity );
|
||||||
|
dropWorld = new WeakReference<>( entity.world );
|
||||||
if( !captured )
|
dropPos = null;
|
||||||
{
|
dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 );
|
||||||
entity.captureDrops = true;
|
|
||||||
ArrayList<EntityItem> items = entity.capturedDrops;
|
entity.captureDrops = true;
|
||||||
|
}
|
||||||
if( items == null || items.size() == 0 )
|
|
||||||
{
|
|
||||||
m_dropConsumers.put( entity, consumer );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearEntityDropConsumer( Entity entity )
|
public void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer )
|
||||||
{
|
{
|
||||||
if( m_dropConsumers.containsKey( entity ) )
|
dropConsumer = consumer;
|
||||||
|
remainingDrops = new ArrayList<>();
|
||||||
|
dropEntity = null;
|
||||||
|
dropWorld = new WeakReference<>( world );
|
||||||
|
dropPos = pos;
|
||||||
|
dropBounds = new AxisAlignedBB( pos ).grow( 2, 2, 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> clearDropConsumer()
|
||||||
|
{
|
||||||
|
if( dropEntity != null )
|
||||||
{
|
{
|
||||||
boolean captured = entity.captureDrops;
|
Entity entity = dropEntity.get();
|
||||||
|
if( entity != null )
|
||||||
if( captured )
|
|
||||||
{
|
{
|
||||||
entity.captureDrops = false;
|
entity.captureDrops = false;
|
||||||
ArrayList<EntityItem> items = entity.capturedDrops;
|
if( entity.capturedDrops != null )
|
||||||
|
|
||||||
if( items != null )
|
|
||||||
{
|
{
|
||||||
dispatchEntityDrops( entity, items );
|
for( EntityItem entityItem : entity.capturedDrops ) handleDrops( entityItem.getItem() );
|
||||||
items.clear();
|
entity.capturedDrops.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_dropConsumers.remove( entity );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<ItemStack> remainingStacks = remainingDrops;
|
||||||
|
|
||||||
|
dropConsumer = null;
|
||||||
|
remainingDrops = null;
|
||||||
|
dropEntity = null;
|
||||||
|
dropWorld = null;
|
||||||
|
dropPos = null;
|
||||||
|
dropBounds = null;
|
||||||
|
|
||||||
|
return remainingStacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerTurtleUpgradeInternal( ITurtleUpgrade upgrade )
|
private void registerTurtleUpgradeInternal( ITurtleUpgrade upgrade )
|
||||||
@@ -289,7 +315,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
{
|
{
|
||||||
IForgeRegistry<Item> registry = event.getRegistry();
|
IForgeRegistry<Item> registry = event.getRegistry();
|
||||||
|
|
||||||
registry.register( new ItemTurtleLegacy( ComputerCraft.Blocks.turtle).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ) );
|
registry.register( new ItemTurtleLegacy( ComputerCraft.Blocks.turtle ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ) );
|
||||||
registry.register( new ItemTurtleNormal( ComputerCraft.Blocks.turtleExpanded ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_expanded" ) ) );
|
registry.register( new ItemTurtleNormal( ComputerCraft.Blocks.turtleExpanded ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_expanded" ) ) );
|
||||||
registry.register( new ItemTurtleAdvanced( ComputerCraft.Blocks.turtleAdvanced ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ) ) );
|
registry.register( new ItemTurtleAdvanced( ComputerCraft.Blocks.turtleAdvanced ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ) ) );
|
||||||
}
|
}
|
||||||
@@ -362,7 +388,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
private void registerUpgrades()
|
private void registerUpgrades()
|
||||||
{
|
{
|
||||||
// Upgrades
|
// Upgrades
|
||||||
ComputerCraft.Upgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 );
|
ComputerCraft.Upgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 );
|
||||||
registerTurtleUpgradeInternal( ComputerCraft.Upgrades.wirelessModem );
|
registerTurtleUpgradeInternal( ComputerCraft.Upgrades.wirelessModem );
|
||||||
|
|
||||||
ComputerCraft.Upgrades.craftingTable = new TurtleCraftingTable( 2 );
|
ComputerCraft.Upgrades.craftingTable = new TurtleCraftingTable( 2 );
|
||||||
@@ -396,10 +422,10 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
|
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
|
||||||
for( RegistryEvent.MissingMappings.Mapping<Item> mapping : mappings.getAllMappings() )
|
for( RegistryEvent.MissingMappings.Mapping<Item> mapping : mappings.getAllMappings() )
|
||||||
{
|
{
|
||||||
String domain = mapping.key.getResourceDomain();
|
String domain = mapping.key.getNamespace();
|
||||||
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
|
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
|
||||||
|
|
||||||
String key = mapping.key.getResourcePath();
|
String key = mapping.key.getPath();
|
||||||
if( key.equalsIgnoreCase( "CC-Turtle" ) )
|
if( key.equalsIgnoreCase( "CC-Turtle" ) )
|
||||||
{
|
{
|
||||||
mapping.remap( Item.getItemFromBlock( ComputerCraft.Blocks.turtle ) );
|
mapping.remap( Item.getItemFromBlock( ComputerCraft.Blocks.turtle ) );
|
||||||
@@ -421,10 +447,10 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
|
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
|
||||||
for( RegistryEvent.MissingMappings.Mapping<Block> mapping : mappings.getAllMappings() )
|
for( RegistryEvent.MissingMappings.Mapping<Block> mapping : mappings.getAllMappings() )
|
||||||
{
|
{
|
||||||
String domain = mapping.key.getResourceDomain();
|
String domain = mapping.key.getNamespace();
|
||||||
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
|
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
|
||||||
|
|
||||||
String key = mapping.key.getResourcePath();
|
String key = mapping.key.getPath();
|
||||||
if( key.equalsIgnoreCase( "CC-Turtle" ) )
|
if( key.equalsIgnoreCase( "CC-Turtle" ) )
|
||||||
{
|
{
|
||||||
mapping.remap( ComputerCraft.Blocks.turtle );
|
mapping.remap( ComputerCraft.Blocks.turtle );
|
||||||
@@ -447,26 +473,60 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
GameRegistry.registerTileEntity( TileTurtleExpanded.class, ComputerCraft.LOWER_ID + " : " + "turtleex" );
|
GameRegistry.registerTileEntity( TileTurtleExpanded.class, ComputerCraft.LOWER_ID + " : " + "turtleex" );
|
||||||
GameRegistry.registerTileEntity( TileTurtleAdvanced.class, ComputerCraft.LOWER_ID + " : " + "turtleadv" );
|
GameRegistry.registerTileEntity( TileTurtleAdvanced.class, ComputerCraft.LOWER_ID + " : " + "turtleadv" );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerForgeHandlers()
|
private void registerForgeHandlers()
|
||||||
{
|
{
|
||||||
ForgeHandlers handlers = new ForgeHandlers();
|
ForgeHandlers handlers = new ForgeHandlers();
|
||||||
MinecraftForge.EVENT_BUS.register( handlers );
|
MinecraftForge.EVENT_BUS.register( handlers );
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ForgeHandlers
|
|
||||||
{
|
|
||||||
private ForgeHandlers()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forge event responses
|
private void handleDrops(ItemStack stack)
|
||||||
@SubscribeEvent
|
{
|
||||||
|
ItemStack remaining = dropConsumer.apply(stack);
|
||||||
|
if (!remaining.isEmpty()) remainingDrops.add(remaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ForgeHandlers
|
||||||
|
{
|
||||||
|
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||||
public void onEntityLivingDrops( LivingDropsEvent event )
|
public void onEntityLivingDrops( LivingDropsEvent event )
|
||||||
{
|
{
|
||||||
dispatchEntityDrops( event.getEntity(), event.getDrops() );
|
// Capture any mob drops for the current entity
|
||||||
|
if( dropEntity != null && event.getEntity() == dropEntity.get() )
|
||||||
|
{
|
||||||
|
List<EntityItem> drops = event.getDrops();
|
||||||
|
for( EntityItem entityItem : drops ) handleDrops( entityItem.getItem() );
|
||||||
|
drops.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||||
|
public void onHarvestDrops( BlockEvent.HarvestDropsEvent event )
|
||||||
|
{
|
||||||
|
// Capture block drops for the current entity
|
||||||
|
if( dropWorld != null && dropWorld.get() == event.getWorld()
|
||||||
|
&& dropPos != null && dropPos.equals( event.getPos() ) )
|
||||||
|
{
|
||||||
|
for( ItemStack item : event.getDrops() )
|
||||||
|
{
|
||||||
|
if( event.getWorld().rand.nextFloat() < event.getDropChance() ) handleDrops( item );
|
||||||
|
}
|
||||||
|
event.getDrops().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||||
|
public void onEntitySpawn( EntityJoinWorldEvent event )
|
||||||
|
{
|
||||||
|
// Capture any nearby item spawns
|
||||||
|
if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof EntityItem
|
||||||
|
&& dropBounds.contains( event.getEntity().getPositionVector() ) )
|
||||||
|
{
|
||||||
|
handleDrops( ((EntityItem) event.getEntity()).getItem() );
|
||||||
|
event.setCanceled( true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onTurtleAction( TurtleActionEvent event) {
|
public void onTurtleAction( TurtleActionEvent event) {
|
||||||
if( ComputerCraft.turtleDisabledActions.contains( event.getAction() ) )
|
if( ComputerCraft.turtleDisabledActions.contains( event.getAction() ) )
|
||||||
@@ -475,18 +535,5 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dispatchEntityDrops( Entity entity, java.util.List<EntityItem> drops )
|
|
||||||
{
|
|
||||||
IEntityDropConsumer consumer = m_dropConsumers.get( entity );
|
|
||||||
if( consumer != null )
|
|
||||||
{
|
|
||||||
// All checks have passed, lets dispatch the drops
|
|
||||||
for(EntityItem entityItem : drops)
|
|
||||||
{
|
|
||||||
consumer.consumeDrop( entity, entityItem.getItem() );
|
|
||||||
}
|
|
||||||
drops.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -10,6 +10,8 @@ import dan200.computercraft.ComputerCraft;
|
|||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
import dan200.computercraft.core.computer.MainThread;
|
import dan200.computercraft.core.computer.MainThread;
|
||||||
|
import dan200.computercraft.shared.command.CommandComputer;
|
||||||
|
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||||
import dan200.computercraft.shared.command.ContainerViewComputer;
|
import dan200.computercraft.shared.command.ContainerViewComputer;
|
||||||
import dan200.computercraft.shared.common.ColourableRecipe;
|
import dan200.computercraft.shared.common.ColourableRecipe;
|
||||||
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
|
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
|
||||||
@@ -22,6 +24,7 @@ import dan200.computercraft.shared.computer.core.*;
|
|||||||
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
|
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
|
||||||
import dan200.computercraft.shared.computer.items.ItemCommandComputer;
|
import dan200.computercraft.shared.computer.items.ItemCommandComputer;
|
||||||
import dan200.computercraft.shared.computer.items.ItemComputer;
|
import dan200.computercraft.shared.computer.items.ItemComputer;
|
||||||
|
import dan200.computercraft.shared.integration.charset.IntegrationCharset;
|
||||||
import dan200.computercraft.shared.media.common.DefaultMediaProvider;
|
import dan200.computercraft.shared.media.common.DefaultMediaProvider;
|
||||||
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
|
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
|
||||||
import dan200.computercraft.shared.media.items.ItemDiskExpanded;
|
import dan200.computercraft.shared.media.items.ItemDiskExpanded;
|
||||||
@@ -49,8 +52,9 @@ import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe;
|
|||||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||||
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
|
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
|
||||||
import dan200.computercraft.shared.util.*;
|
import dan200.computercraft.shared.util.*;
|
||||||
import dan200.computercraft.shared.wired.DefaultWiredProvider;
|
import dan200.computercraft.shared.wired.CapabilityWiredElement;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.command.CommandHandler;
|
||||||
import net.minecraft.creativetab.CreativeTabs;
|
import net.minecraft.creativetab.CreativeTabs;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.entity.player.EntityPlayerMP;
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
@@ -63,6 +67,7 @@ import net.minecraft.item.ItemStack;
|
|||||||
import net.minecraft.item.crafting.IRecipe;
|
import net.minecraft.item.crafting.IRecipe;
|
||||||
import net.minecraft.item.crafting.Ingredient;
|
import net.minecraft.item.crafting.Ingredient;
|
||||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.*;
|
import net.minecraft.util.*;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
@@ -72,6 +77,7 @@ import net.minecraftforge.event.RegistryEvent;
|
|||||||
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
|
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
|
||||||
import net.minecraftforge.event.world.WorldEvent;
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
|
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
|
||||||
|
import net.minecraftforge.fml.common.Loader;
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||||
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
|
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
|
||||||
@@ -79,6 +85,7 @@ import net.minecraftforge.fml.common.network.IGuiHandler;
|
|||||||
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||||
import net.minecraftforge.registries.IForgeRegistry;
|
import net.minecraftforge.registries.IForgeRegistry;
|
||||||
|
import pl.asie.charset.ModCharset;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -113,6 +120,16 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
|
|||||||
{
|
{
|
||||||
registerTileEntities();
|
registerTileEntities();
|
||||||
registerForgeHandlers();
|
registerForgeHandlers();
|
||||||
|
|
||||||
|
if( Loader.isModLoaded( ModCharset.MODID ) ) IntegrationCharset.register();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initServer( MinecraftServer server )
|
||||||
|
{
|
||||||
|
CommandHandler handler = (CommandHandler) server.getCommandManager();
|
||||||
|
handler.registerCommand( new CommandComputer() );
|
||||||
|
handler.registerCommand( new CommandComputerCraft() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -154,7 +171,8 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
|
|||||||
packet.m_dataInt = new int[] { pos.getX(), pos.getY(), pos.getZ() };
|
packet.m_dataInt = new int[] { pos.getX(), pos.getY(), pos.getZ() };
|
||||||
}
|
}
|
||||||
|
|
||||||
ComputerCraft.sendToAllPlayers( packet );
|
NetworkRegistry.TargetPoint point = new NetworkRegistry.TargetPoint( world.provider.getDimension(), pos.getX(), pos.getY(), pos.getZ(), 64 );
|
||||||
|
ComputerCraft.sendToAllAround( packet, point );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -401,10 +419,10 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
|
|||||||
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
|
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
|
||||||
for( RegistryEvent.MissingMappings.Mapping<Item> mapping : mappings.getAllMappings() )
|
for( RegistryEvent.MissingMappings.Mapping<Item> mapping : mappings.getAllMappings() )
|
||||||
{
|
{
|
||||||
String domain = mapping.key.getResourceDomain();
|
String domain = mapping.key.getNamespace();
|
||||||
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
|
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
|
||||||
|
|
||||||
String key = mapping.key.getResourcePath();
|
String key = mapping.key.getPath();
|
||||||
if( key.equalsIgnoreCase( "CC-Computer" ) )
|
if( key.equalsIgnoreCase( "CC-Computer" ) )
|
||||||
{
|
{
|
||||||
mapping.remap( Item.getItemFromBlock( ComputerCraft.Blocks.computer ) );
|
mapping.remap( Item.getItemFromBlock( ComputerCraft.Blocks.computer ) );
|
||||||
@@ -438,10 +456,10 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
|
|||||||
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
|
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
|
||||||
for( RegistryEvent.MissingMappings.Mapping<Block> mapping : mappings.getAllMappings() )
|
for( RegistryEvent.MissingMappings.Mapping<Block> mapping : mappings.getAllMappings() )
|
||||||
{
|
{
|
||||||
String domain = mapping.key.getResourceDomain();
|
String domain = mapping.key.getNamespace();
|
||||||
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
|
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
|
||||||
|
|
||||||
String key = mapping.key.getResourcePath();
|
String key = mapping.key.getPath();
|
||||||
if( key.equalsIgnoreCase( "CC-Computer" ) )
|
if( key.equalsIgnoreCase( "CC-Computer" ) )
|
||||||
{
|
{
|
||||||
mapping.remap( ComputerCraft.Blocks.computer );
|
mapping.remap( ComputerCraft.Blocks.computer );
|
||||||
@@ -485,7 +503,7 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
|
|||||||
ComputerCraftAPI.registerMediaProvider( new DefaultMediaProvider() );
|
ComputerCraftAPI.registerMediaProvider( new DefaultMediaProvider() );
|
||||||
|
|
||||||
// Register network providers
|
// Register network providers
|
||||||
ComputerCraftAPI.registerWiredProvider( new DefaultWiredProvider() );
|
CapabilityWiredElement.register();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerForgeHandlers()
|
private void registerForgeHandlers()
|
||||||
|
@@ -7,12 +7,16 @@
|
|||||||
package dan200.computercraft.shared.proxy;
|
package dan200.computercraft.shared.proxy;
|
||||||
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.shared.util.IEntityDropConsumer;
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.NonNullList;
|
import net.minecraft.util.NonNullList;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public interface ICCTurtleProxy
|
public interface ICCTurtleProxy
|
||||||
{
|
{
|
||||||
@@ -25,6 +29,7 @@ public interface ICCTurtleProxy
|
|||||||
ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack item );
|
ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack item );
|
||||||
void addAllUpgradedTurtles( NonNullList<ItemStack> list );
|
void addAllUpgradedTurtles( NonNullList<ItemStack> list );
|
||||||
|
|
||||||
void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer );
|
void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer );
|
||||||
void clearEntityDropConsumer( Entity entity );
|
void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer );
|
||||||
|
List<ItemStack> clearDropConsumer();
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@ import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
|||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.entity.player.InventoryPlayer;
|
import net.minecraft.entity.player.InventoryPlayer;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.util.SoundEvent;
|
import net.minecraft.util.SoundEvent;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
@@ -28,6 +29,7 @@ public interface IComputerCraftProxy
|
|||||||
{
|
{
|
||||||
void preInit();
|
void preInit();
|
||||||
void init();
|
void init();
|
||||||
|
void initServer( MinecraftServer server );
|
||||||
boolean isClient();
|
boolean isClient();
|
||||||
|
|
||||||
boolean getGlobalCursorBlink();
|
boolean getGlobalCursorBlink();
|
||||||
|
@@ -15,6 +15,7 @@ import dan200.computercraft.api.turtle.TurtleSide;
|
|||||||
import dan200.computercraft.api.turtle.event.TurtleAction;
|
import dan200.computercraft.api.turtle.event.TurtleAction;
|
||||||
import dan200.computercraft.api.turtle.event.TurtleActionEvent;
|
import dan200.computercraft.api.turtle.event.TurtleActionEvent;
|
||||||
import dan200.computercraft.core.apis.IAPIEnvironment;
|
import dan200.computercraft.core.apis.IAPIEnvironment;
|
||||||
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
import dan200.computercraft.shared.turtle.core.*;
|
import dan200.computercraft.shared.turtle.core.*;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
@@ -161,70 +162,83 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
// forward
|
// forward
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Forward ) );
|
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Forward ) );
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// back
|
// back
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Back ) );
|
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Back ) );
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
// up
|
// up
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Up ) );
|
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Up ) );
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
// down
|
// down
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Down ) );
|
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Down ) );
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
// turnLeft
|
// turnLeft
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleTurnCommand( TurnDirection.Left ) );
|
return tryCommand( context, new TurtleTurnCommand( TurnDirection.Left ) );
|
||||||
}
|
}
|
||||||
case 5:
|
case 5:
|
||||||
{
|
{
|
||||||
// turnRight
|
// turnRight
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleTurnCommand( TurnDirection.Right ) );
|
return tryCommand( context, new TurtleTurnCommand( TurnDirection.Right ) );
|
||||||
}
|
}
|
||||||
case 6:
|
case 6:
|
||||||
{
|
{
|
||||||
// dig
|
// dig
|
||||||
Optional<TurtleSide> side = parseSide( args, 0 );
|
Optional<TurtleSide> side = parseSide( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleDigCommand( InteractDirection.Forward, side ) );
|
return tryCommand( context, new TurtleDigCommand( InteractDirection.Forward, side ) );
|
||||||
}
|
}
|
||||||
case 7:
|
case 7:
|
||||||
{
|
{
|
||||||
// digUp
|
// digUp
|
||||||
Optional<TurtleSide> side = parseSide( args, 0 );
|
Optional<TurtleSide> side = parseSide( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleDigCommand( InteractDirection.Up, side ) );
|
return tryCommand( context, new TurtleDigCommand( InteractDirection.Up, side ) );
|
||||||
}
|
}
|
||||||
case 8:
|
case 8:
|
||||||
{
|
{
|
||||||
// digDown
|
// digDown
|
||||||
Optional<TurtleSide> side = parseSide( args, 0 );
|
Optional<TurtleSide> side = parseSide( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleDigCommand( InteractDirection.Down, side ) );
|
return tryCommand( context, new TurtleDigCommand( InteractDirection.Down, side ) );
|
||||||
}
|
}
|
||||||
case 9:
|
case 9:
|
||||||
{
|
{
|
||||||
// place
|
// place
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Forward, args ) );
|
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Forward, args ) );
|
||||||
}
|
}
|
||||||
case 10:
|
case 10:
|
||||||
{
|
{
|
||||||
// placeUp
|
// placeUp
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Up, args ) );
|
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Up, args ) );
|
||||||
}
|
}
|
||||||
case 11:
|
case 11:
|
||||||
{
|
{
|
||||||
// placeDown
|
// placeDown
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Down, args ) );
|
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Down, args ) );
|
||||||
}
|
}
|
||||||
case 12:
|
case 12:
|
||||||
{
|
{
|
||||||
// drop
|
// drop
|
||||||
int count = parseCount( args, 0 );
|
int count = parseCount( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleDropCommand( InteractDirection.Forward, count ) );
|
return tryCommand( context, new TurtleDropCommand( InteractDirection.Forward, count ) );
|
||||||
}
|
}
|
||||||
case 13:
|
case 13:
|
||||||
@@ -294,48 +308,56 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
// attack
|
// attack
|
||||||
Optional<TurtleSide> side = parseSide( args, 0 );
|
Optional<TurtleSide> side = parseSide( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleAttackCommand( InteractDirection.Forward, side ) );
|
return tryCommand( context, new TurtleAttackCommand( InteractDirection.Forward, side ) );
|
||||||
}
|
}
|
||||||
case 23:
|
case 23:
|
||||||
{
|
{
|
||||||
// attackUp
|
// attackUp
|
||||||
Optional<TurtleSide> side = parseSide( args, 0 );
|
Optional<TurtleSide> side = parseSide( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleAttackCommand( InteractDirection.Up, side ) );
|
return tryCommand( context, new TurtleAttackCommand( InteractDirection.Up, side ) );
|
||||||
}
|
}
|
||||||
case 24:
|
case 24:
|
||||||
{
|
{
|
||||||
// attackDown
|
// attackDown
|
||||||
Optional<TurtleSide> side = parseSide( args, 0 );
|
Optional<TurtleSide> side = parseSide( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleAttackCommand( InteractDirection.Down, side ) );
|
return tryCommand( context, new TurtleAttackCommand( InteractDirection.Down, side ) );
|
||||||
}
|
}
|
||||||
case 25:
|
case 25:
|
||||||
{
|
{
|
||||||
// dropUp
|
// dropUp
|
||||||
int count = parseCount( args, 0 );
|
int count = parseCount( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleDropCommand( InteractDirection.Up, count ) );
|
return tryCommand( context, new TurtleDropCommand( InteractDirection.Up, count ) );
|
||||||
}
|
}
|
||||||
case 26:
|
case 26:
|
||||||
{
|
{
|
||||||
// dropDown
|
// dropDown
|
||||||
int count = parseCount( args, 0 );
|
int count = parseCount( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleDropCommand( InteractDirection.Down, count ) );
|
return tryCommand( context, new TurtleDropCommand( InteractDirection.Down, count ) );
|
||||||
}
|
}
|
||||||
case 27:
|
case 27:
|
||||||
{
|
{
|
||||||
// suck
|
// suck
|
||||||
int count = parseCount( args, 0 );
|
int count = parseCount( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Forward, count ) );
|
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Forward, count ) );
|
||||||
}
|
}
|
||||||
case 28:
|
case 28:
|
||||||
{
|
{
|
||||||
// suckUp
|
// suckUp
|
||||||
int count = parseCount( args, 0 );
|
int count = parseCount( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Up, count ) );
|
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Up, count ) );
|
||||||
}
|
}
|
||||||
case 29:
|
case 29:
|
||||||
{
|
{
|
||||||
// suckDown
|
// suckDown
|
||||||
int count = parseCount( args, 0 );
|
int count = parseCount( args, 0 );
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Down, count ) );
|
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Down, count ) );
|
||||||
}
|
}
|
||||||
case 30:
|
case 30:
|
||||||
@@ -389,11 +411,13 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
case 36:
|
case 36:
|
||||||
{
|
{
|
||||||
// equipLeft
|
// equipLeft
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleEquipCommand( TurtleSide.Left ) );
|
return tryCommand( context, new TurtleEquipCommand( TurtleSide.Left ) );
|
||||||
}
|
}
|
||||||
case 37:
|
case 37:
|
||||||
{
|
{
|
||||||
// equipRight
|
// equipRight
|
||||||
|
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
|
||||||
return tryCommand( context, new TurtleEquipCommand( TurtleSide.Right ) );
|
return tryCommand( context, new TurtleEquipCommand( TurtleSide.Right ) );
|
||||||
}
|
}
|
||||||
case 38:
|
case 38:
|
||||||
|
@@ -48,7 +48,7 @@ public class BlockTurtle extends BlockComputerBase
|
|||||||
{
|
{
|
||||||
super( Material.IRON );
|
super( Material.IRON );
|
||||||
setHardness( 2.5f );
|
setHardness( 2.5f );
|
||||||
setUnlocalizedName( "computercraft:turtle" );
|
setTranslationKey( "computercraft:turtle" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
setDefaultState( this.blockState.getBaseState()
|
setDefaultState( this.blockState.getBaseState()
|
||||||
.withProperty( Properties.FACING, EnumFacing.NORTH )
|
.withProperty( Properties.FACING, EnumFacing.NORTH )
|
||||||
|
@@ -127,6 +127,8 @@ public class TurtleBrain implements ITurtleAccess
|
|||||||
private TurtleAnimation m_animation;
|
private TurtleAnimation m_animation;
|
||||||
private int m_animationProgress;
|
private int m_animationProgress;
|
||||||
private int m_lastAnimationProgress;
|
private int m_lastAnimationProgress;
|
||||||
|
|
||||||
|
TurtlePlayer m_cachedPlayer;
|
||||||
|
|
||||||
public TurtleBrain( TileTurtle turtle )
|
public TurtleBrain( TileTurtle turtle )
|
||||||
{
|
{
|
||||||
@@ -224,7 +226,7 @@ public class TurtleBrain implements ITurtleAccess
|
|||||||
public void readFromNBT( NBTTagCompound nbttagcompound )
|
public void readFromNBT( NBTTagCompound nbttagcompound )
|
||||||
{
|
{
|
||||||
// Read state
|
// Read state
|
||||||
m_direction = EnumFacing.getFront( nbttagcompound.getInteger( "dir" ) );
|
m_direction = EnumFacing.byIndex( nbttagcompound.getInteger( "dir" ) );
|
||||||
m_selectedSlot = nbttagcompound.getInteger( "selectedSlot" );
|
m_selectedSlot = nbttagcompound.getInteger( "selectedSlot" );
|
||||||
if( nbttagcompound.hasKey( "fuelLevel" ) )
|
if( nbttagcompound.hasKey( "fuelLevel" ) )
|
||||||
{
|
{
|
||||||
@@ -368,8 +370,8 @@ public class TurtleBrain implements ITurtleAccess
|
|||||||
// Write overlay
|
// Write overlay
|
||||||
if( m_overlay != null )
|
if( m_overlay != null )
|
||||||
{
|
{
|
||||||
nbttagcompound.setString( "overlay_mod", m_overlay.getResourceDomain() );
|
nbttagcompound.setString( "overlay_mod", m_overlay.getNamespace() );
|
||||||
nbttagcompound.setString( "overlay_path", m_overlay.getResourcePath() );
|
nbttagcompound.setString( "overlay_path", m_overlay.getPath() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write NBT
|
// Write NBT
|
||||||
@@ -427,8 +429,8 @@ public class TurtleBrain implements ITurtleAccess
|
|||||||
// Overlay
|
// Overlay
|
||||||
if( m_overlay != null )
|
if( m_overlay != null )
|
||||||
{
|
{
|
||||||
nbttagcompound.setString( "overlay_mod", m_overlay.getResourceDomain() );
|
nbttagcompound.setString( "overlay_mod", m_overlay.getNamespace() );
|
||||||
nbttagcompound.setString( "overlay_path", m_overlay.getResourcePath() );
|
nbttagcompound.setString( "overlay_path", m_overlay.getPath() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Animation
|
// Animation
|
||||||
@@ -503,7 +505,7 @@ public class TurtleBrain implements ITurtleAccess
|
|||||||
m_lastAnimationProgress = 0;
|
m_lastAnimationProgress = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_direction = EnumFacing.getFront( nbttagcompound.getInteger( "direction" ) );
|
m_direction = EnumFacing.byIndex( nbttagcompound.getInteger( "direction" ) );
|
||||||
m_fuelLevel = nbttagcompound.getInteger( "fuelLevel" );
|
m_fuelLevel = nbttagcompound.getInteger( "fuelLevel" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -996,9 +998,9 @@ public class TurtleBrain implements ITurtleAccess
|
|||||||
|
|
||||||
double distance = -1.0 + getAnimationFraction( f );
|
double distance = -1.0 + getAnimationFraction( f );
|
||||||
return new Vec3d(
|
return new Vec3d(
|
||||||
distance * dir.getFrontOffsetX(),
|
distance * dir.getXOffset(),
|
||||||
distance * dir.getFrontOffsetY(),
|
distance * dir.getYOffset(),
|
||||||
distance * dir.getFrontOffsetZ()
|
distance * dir.getZOffset()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -1182,31 +1184,31 @@ public class TurtleBrain implements ITurtleAccess
|
|||||||
|
|
||||||
float pushFrac = 1.0f - ((float)(m_animationProgress + 1) / (float)ANIM_DURATION);
|
float pushFrac = 1.0f - ((float)(m_animationProgress + 1) / (float)ANIM_DURATION);
|
||||||
float push = Math.max( pushFrac + 0.0125f, 0.0f );
|
float push = Math.max( pushFrac + 0.0125f, 0.0f );
|
||||||
if (moveDir.getFrontOffsetX() < 0)
|
if (moveDir.getXOffset() < 0)
|
||||||
{
|
{
|
||||||
minX += moveDir.getFrontOffsetX() * push;
|
minX += moveDir.getXOffset() * push;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
maxX -= moveDir.getFrontOffsetX() * push;
|
maxX -= moveDir.getXOffset() * push;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moveDir.getFrontOffsetY() < 0)
|
if (moveDir.getYOffset() < 0)
|
||||||
{
|
{
|
||||||
minY += moveDir.getFrontOffsetY() * push;
|
minY += moveDir.getYOffset() * push;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
maxY -= moveDir.getFrontOffsetY() * push;
|
maxY -= moveDir.getYOffset() * push;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moveDir.getFrontOffsetZ() < 0)
|
if (moveDir.getZOffset() < 0)
|
||||||
{
|
{
|
||||||
minZ += moveDir.getFrontOffsetZ() * push;
|
minZ += moveDir.getZOffset() * push;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
maxZ -= moveDir.getFrontOffsetZ() * push;
|
maxZ -= moveDir.getZOffset() * push;
|
||||||
}
|
}
|
||||||
|
|
||||||
AxisAlignedBB aabb = new AxisAlignedBB( minX, minY, minZ, maxX, maxY, maxZ );
|
AxisAlignedBB aabb = new AxisAlignedBB( minX, minY, minZ, maxX, maxY, maxZ );
|
||||||
@@ -1214,9 +1216,9 @@ public class TurtleBrain implements ITurtleAccess
|
|||||||
if( !list.isEmpty() )
|
if( !list.isEmpty() )
|
||||||
{
|
{
|
||||||
double pushStep = 1.0f / ANIM_DURATION;
|
double pushStep = 1.0f / ANIM_DURATION;
|
||||||
double pushStepX = moveDir.getFrontOffsetX() * pushStep;
|
double pushStepX = moveDir.getXOffset() * pushStep;
|
||||||
double pushStepY = moveDir.getFrontOffsetY() * pushStep;
|
double pushStepY = moveDir.getYOffset() * pushStep;
|
||||||
double pushStepZ = moveDir.getFrontOffsetZ() * pushStep;
|
double pushStepZ = moveDir.getZOffset() * pushStep;
|
||||||
for (Entity entity : list)
|
for (Entity entity : list)
|
||||||
{
|
{
|
||||||
entity.move( MoverType.PISTON, pushStepX, pushStepY, pushStepZ );
|
entity.move( MoverType.PISTON, pushStepX, pushStepY, pushStepZ );
|
||||||
|
@@ -126,7 +126,7 @@ public class TurtleCompareCommand implements ITurtleCommand
|
|||||||
{
|
{
|
||||||
return TurtleCommandResult.success();
|
return TurtleCommandResult.success();
|
||||||
}
|
}
|
||||||
else if( selectedStack.getUnlocalizedName().equals( lookAtStack.getUnlocalizedName() ) )
|
else if( selectedStack.getTranslationKey().equals( lookAtStack.getTranslationKey() ) )
|
||||||
{
|
{
|
||||||
return TurtleCommandResult.success();
|
return TurtleCommandResult.success();
|
||||||
}
|
}
|
||||||
|
@@ -87,9 +87,9 @@ public class TurtleMoveCommand implements ITurtleCommand
|
|||||||
if( entityBB != null )
|
if( entityBB != null )
|
||||||
{
|
{
|
||||||
AxisAlignedBB pushedBB = entityBB.offset(
|
AxisAlignedBB pushedBB = entityBB.offset(
|
||||||
direction.getFrontOffsetX(),
|
direction.getXOffset(),
|
||||||
direction.getFrontOffsetY(),
|
direction.getYOffset(),
|
||||||
direction.getFrontOffsetZ()
|
direction.getZOffset()
|
||||||
);
|
);
|
||||||
if( !oldWorld.getCollisionBoxes( null, pushedBB ).isEmpty() )
|
if( !oldWorld.getCollisionBoxes( null, pushedBB ).isEmpty() )
|
||||||
{
|
{
|
||||||
|
@@ -30,7 +30,6 @@ import net.minecraft.util.math.BlockPos;
|
|||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.text.TextComponentString;
|
import net.minecraft.util.text.TextComponentString;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.WorldServer;
|
|
||||||
import net.minecraftforge.common.ForgeHooks;
|
import net.minecraftforge.common.ForgeHooks;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||||
@@ -38,6 +37,7 @@ import net.minecraftforge.fml.common.eventhandler.Event;
|
|||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class TurtlePlaceCommand implements ITurtleCommand
|
public class TurtlePlaceCommand implements ITurtleCommand
|
||||||
{
|
{
|
||||||
@@ -180,12 +180,12 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
|||||||
|
|
||||||
public static TurtlePlayer createPlayer( ITurtleAccess turtle, BlockPos position, EnumFacing direction )
|
public static TurtlePlayer createPlayer( ITurtleAccess turtle, BlockPos position, EnumFacing direction )
|
||||||
{
|
{
|
||||||
TurtlePlayer turtlePlayer = new TurtlePlayer( turtle );
|
TurtlePlayer turtlePlayer = TurtlePlayer.get( turtle );
|
||||||
orientPlayer( turtle, turtlePlayer, position, direction );
|
orientPlayer( turtle, turtlePlayer, position, direction );
|
||||||
return turtlePlayer;
|
return turtlePlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void orientPlayer( ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, EnumFacing direction )
|
private static void orientPlayer( ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, EnumFacing direction )
|
||||||
{
|
{
|
||||||
turtlePlayer.posX = position.getX() + 0.5;
|
turtlePlayer.posX = position.getX() + 0.5;
|
||||||
turtlePlayer.posY = position.getY() + 0.5;
|
turtlePlayer.posY = position.getY() + 0.5;
|
||||||
@@ -194,9 +194,9 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
|||||||
// Stop intersection with the turtle itself
|
// Stop intersection with the turtle itself
|
||||||
if( turtle.getPosition().equals( position ) )
|
if( turtle.getPosition().equals( position ) )
|
||||||
{
|
{
|
||||||
turtlePlayer.posX += 0.48 * direction.getFrontOffsetX();
|
turtlePlayer.posX += 0.48 * direction.getXOffset();
|
||||||
turtlePlayer.posY += 0.48 * direction.getFrontOffsetY();
|
turtlePlayer.posY += 0.48 * direction.getYOffset();
|
||||||
turtlePlayer.posZ += 0.48 * direction.getFrontOffsetZ();
|
turtlePlayer.posZ += 0.48 * direction.getZOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( direction.getAxis() != EnumFacing.Axis.Y )
|
if( direction.getAxis() != EnumFacing.Axis.Y )
|
||||||
@@ -241,14 +241,10 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
|||||||
// Start claiming entity drops
|
// Start claiming entity drops
|
||||||
Entity hitEntity = hit.getKey();
|
Entity hitEntity = hit.getKey();
|
||||||
Vec3d hitPos = hit.getValue();
|
Vec3d hitPos = hit.getValue();
|
||||||
ComputerCraft.setEntityDropConsumer( hitEntity, ( entity, drop ) ->
|
ComputerCraft.setDropConsumer(
|
||||||
{
|
hitEntity,
|
||||||
ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
|
drop -> InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() )
|
||||||
if( !remainder.isEmpty() )
|
);
|
||||||
{
|
|
||||||
WorldUtil.dropItemStack( remainder, world, position, turtle.getDirection().getOpposite() );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Place on the entity
|
// Place on the entity
|
||||||
boolean placed = false;
|
boolean placed = false;
|
||||||
@@ -285,7 +281,11 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop claiming drops
|
// Stop claiming drops
|
||||||
ComputerCraft.clearEntityDropConsumer( hitEntity );
|
List<ItemStack> remainingDrops = ComputerCraft.clearDropConsumer();
|
||||||
|
for( ItemStack remaining : remainingDrops )
|
||||||
|
{
|
||||||
|
WorldUtil.dropItemStack( remaining, world, position, turtle.getDirection().getOpposite() );
|
||||||
|
}
|
||||||
|
|
||||||
// Put everything we collected into the turtles inventory, then return
|
// Put everything we collected into the turtles inventory, then return
|
||||||
ItemStack remainder = turtlePlayer.unloadInventory( turtle );
|
ItemStack remainder = turtlePlayer.unloadInventory( turtle );
|
||||||
@@ -367,9 +367,9 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
|||||||
orientPlayer( turtle, turtlePlayer, playerPosition, playerDir );
|
orientPlayer( turtle, turtlePlayer, playerPosition, playerDir );
|
||||||
|
|
||||||
// Calculate where the turtle would hit the block
|
// Calculate where the turtle would hit the block
|
||||||
float hitX = 0.5f + side.getFrontOffsetX() * 0.5f;
|
float hitX = 0.5f + side.getXOffset() * 0.5f;
|
||||||
float hitY = 0.5f + side.getFrontOffsetY() * 0.5f;
|
float hitY = 0.5f + side.getYOffset() * 0.5f;
|
||||||
float hitZ = 0.5f + side.getFrontOffsetZ() * 0.5f;
|
float hitZ = 0.5f + side.getZOffset() * 0.5f;
|
||||||
if( Math.abs( hitY - 0.5f ) < 0.01f )
|
if( Math.abs( hitY - 0.5f ) < 0.01f )
|
||||||
{
|
{
|
||||||
hitY = 0.45f;
|
hitY = 0.45f;
|
||||||
@@ -382,7 +382,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
|||||||
|
|
||||||
// Do the deploying (put everything in the players inventory)
|
// Do the deploying (put everything in the players inventory)
|
||||||
boolean placed = false;
|
boolean placed = false;
|
||||||
|
TileEntity existingTile = turtle.getWorld().getTileEntity( position );
|
||||||
|
|
||||||
// See PlayerInteractionManager.processRightClickBlock
|
// See PlayerInteractionManager.processRightClickBlock
|
||||||
PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, EnumHand.MAIN_HAND, position, side, new Vec3d( hitX, hitY, hitZ ) );
|
PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, EnumHand.MAIN_HAND, position, side, new Vec3d( hitX, hitY, hitZ ) );
|
||||||
@@ -426,12 +426,11 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
|||||||
{
|
{
|
||||||
World world = turtle.getWorld();
|
World world = turtle.getWorld();
|
||||||
TileEntity tile = world.getTileEntity( position );
|
TileEntity tile = world.getTileEntity( position );
|
||||||
if( tile == null )
|
if( tile == null || tile == existingTile )
|
||||||
{
|
{
|
||||||
BlockPos newPosition = WorldUtil.moveCoords( position, side );
|
tile = world.getTileEntity( WorldUtil.moveCoords( position, side ) );
|
||||||
tile = world.getTileEntity( newPosition );
|
|
||||||
}
|
}
|
||||||
if( tile != null && tile instanceof TileEntitySign )
|
if( tile instanceof TileEntitySign )
|
||||||
{
|
{
|
||||||
TileEntitySign signTile = (TileEntitySign) tile;
|
TileEntitySign signTile = (TileEntitySign) tile;
|
||||||
String s = (String)extraArguments[0];
|
String s = (String)extraArguments[0];
|
||||||
|
@@ -11,10 +11,16 @@ import dan200.computercraft.api.turtle.ITurtleAccess;
|
|||||||
import dan200.computercraft.shared.util.InventoryUtil;
|
import dan200.computercraft.shared.util.InventoryUtil;
|
||||||
import dan200.computercraft.shared.util.WorldUtil;
|
import dan200.computercraft.shared.util.WorldUtil;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.IMerchant;
|
||||||
|
import net.minecraft.entity.passive.AbstractHorse;
|
||||||
|
import net.minecraft.inventory.IInventory;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.tileentity.TileEntitySign;
|
import net.minecraft.tileentity.TileEntitySign;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.IInteractionObject;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.WorldServer;
|
import net.minecraft.world.WorldServer;
|
||||||
import net.minecraftforge.common.util.FakePlayer;
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
@@ -30,16 +36,31 @@ public class TurtlePlayer extends FakePlayer
|
|||||||
"[ComputerCraft]"
|
"[ComputerCraft]"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a TurtlePlayer which exists in the world
|
||||||
|
*
|
||||||
|
* @param world The world the player exists in
|
||||||
|
* @deprecated This is required by {@link Entity}.
|
||||||
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public TurtlePlayer( World world )
|
public TurtlePlayer( World world )
|
||||||
{
|
{
|
||||||
super( (WorldServer) world, DEFAULT_PROFILE );
|
super( (WorldServer) world, DEFAULT_PROFILE );
|
||||||
}
|
}
|
||||||
|
|
||||||
public TurtlePlayer( ITurtleAccess turtle )
|
|
||||||
{
|
|
||||||
super( (WorldServer) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ));
|
|
||||||
|
|
||||||
|
private TurtlePlayer( ITurtleAccess turtle )
|
||||||
|
{
|
||||||
|
super( (WorldServer) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) );
|
||||||
|
setState( turtle );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GameProfile getProfile( @Nullable GameProfile profile )
|
||||||
|
{
|
||||||
|
return profile != null && profile.isComplete() ? profile : DEFAULT_PROFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setState( ITurtleAccess turtle )
|
||||||
|
{
|
||||||
BlockPos position = turtle.getPosition();
|
BlockPos position = turtle.getPosition();
|
||||||
posX = position.getX() + 0.5;
|
posX = position.getX() + 0.5;
|
||||||
posY = position.getY() + 0.5;
|
posY = position.getY() + 0.5;
|
||||||
@@ -47,11 +68,27 @@ public class TurtlePlayer extends FakePlayer
|
|||||||
|
|
||||||
rotationYaw = turtle.getDirection().getHorizontalAngle();
|
rotationYaw = turtle.getDirection().getHorizontalAngle();
|
||||||
rotationPitch = 0.0f;
|
rotationPitch = 0.0f;
|
||||||
|
|
||||||
|
inventory.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GameProfile getProfile( @Nullable GameProfile profile )
|
public static TurtlePlayer get( ITurtleAccess access )
|
||||||
{
|
{
|
||||||
return profile != null && profile.isComplete() ? profile : DEFAULT_PROFILE;
|
if( !(access instanceof TurtleBrain) ) return new TurtlePlayer( access );
|
||||||
|
|
||||||
|
TurtleBrain brain = (TurtleBrain) access;
|
||||||
|
TurtlePlayer player = brain.m_cachedPlayer;
|
||||||
|
if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() )
|
||||||
|
|| player.getEntityWorld() != access.getWorld() )
|
||||||
|
{
|
||||||
|
player = brain.m_cachedPlayer = new TurtlePlayer( brain );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
player.setState( access );
|
||||||
|
}
|
||||||
|
|
||||||
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadInventory( @Nonnull ItemStack currentStack )
|
public void loadInventory( @Nonnull ItemStack currentStack )
|
||||||
@@ -70,7 +107,7 @@ public class TurtlePlayer extends FakePlayer
|
|||||||
// Store (or drop) anything else we found
|
// Store (or drop) anything else we found
|
||||||
BlockPos dropPosition = turtle.getPosition();
|
BlockPos dropPosition = turtle.getPosition();
|
||||||
EnumFacing dropDirection = turtle.getDirection().getOpposite();
|
EnumFacing dropDirection = turtle.getDirection().getOpposite();
|
||||||
for( int i=0; i<inventory.getSizeInventory(); ++i )
|
for( int i = 0; i < inventory.getSizeInventory(); ++i )
|
||||||
{
|
{
|
||||||
ItemStack stack = inventory.getStackInSlot( i );
|
ItemStack stack = inventory.getStackInSlot( i );
|
||||||
if( !stack.isEmpty() )
|
if( !stack.isEmpty() )
|
||||||
@@ -87,6 +124,12 @@ public class TurtlePlayer extends FakePlayer
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vec3d getPositionVector()
|
||||||
|
{
|
||||||
|
return new Vec3d( posX, posY, posZ );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getEyeHeight()
|
public float getEyeHeight()
|
||||||
{
|
{
|
||||||
@@ -99,6 +142,63 @@ public class TurtlePlayer extends FakePlayer
|
|||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendEnterCombat()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendEndCombat()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public SleepResult trySleep( @Nonnull BlockPos bedLocation )
|
||||||
|
{
|
||||||
|
return SleepResult.OTHER_PROBLEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void openEditSign( TileEntitySign signTile )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayGui( IInteractionObject guiOwner )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayGUIChest( IInventory chestInventory )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayVillagerTradeGui( IMerchant villager )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void openGuiHorseInventory( AbstractHorse horse, IInventory inventoryIn )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void openBook( ItemStack stack, @Nonnull EnumHand hand )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateHeldItem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onItemUseFinish()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mountEntityAndWakeUp()
|
public void mountEntityAndWakeUp()
|
||||||
{
|
{
|
||||||
@@ -108,9 +208,4 @@ public class TurtlePlayer extends FakePlayer
|
|||||||
public void dismountEntity( @Nonnull Entity entity )
|
public void dismountEntity( @Nonnull Entity entity )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void openEditSign( TileEntitySign signTile )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,7 @@ public class ItemTurtleAdvanced extends ItemTurtleNormal
|
|||||||
public ItemTurtleAdvanced( Block block )
|
public ItemTurtleAdvanced( Block block )
|
||||||
{
|
{
|
||||||
super( block );
|
super( block );
|
||||||
setUnlocalizedName( "computercraft:advanced_turtle" );
|
setTranslationKey( "computercraft:advanced_turtle" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -114,7 +114,7 @@ public abstract class ItemTurtleBase extends ItemComputerBase implements ITurtle
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUnlocalizedName( @Nonnull ItemStack stack )
|
public String getTranslationKey( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
ComputerFamily family = getFamily( stack );
|
ComputerFamily family = getFamily( stack );
|
||||||
switch( family )
|
switch( family )
|
||||||
@@ -139,7 +139,7 @@ public abstract class ItemTurtleBase extends ItemComputerBase implements ITurtle
|
|||||||
@Override
|
@Override
|
||||||
public String getItemStackDisplayName( @Nonnull ItemStack stack )
|
public String getItemStackDisplayName( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
String baseString = getUnlocalizedName( stack );
|
String baseString = getTranslationKey( stack );
|
||||||
ITurtleUpgrade left = getUpgrade( stack, TurtleSide.Left );
|
ITurtleUpgrade left = getUpgrade( stack, TurtleSide.Left );
|
||||||
ITurtleUpgrade right = getUpgrade( stack, TurtleSide.Right );
|
ITurtleUpgrade right = getUpgrade( stack, TurtleSide.Right );
|
||||||
if( left != null && right != null )
|
if( left != null && right != null )
|
||||||
|
@@ -23,7 +23,7 @@ public class ItemTurtleLegacy extends ItemTurtleBase
|
|||||||
public ItemTurtleLegacy( Block block )
|
public ItemTurtleLegacy( Block block )
|
||||||
{
|
{
|
||||||
super( block );
|
super( block );
|
||||||
setUnlocalizedName( "computercraft:turtle" );
|
setTranslationKey( "computercraft:turtle" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,7 +24,7 @@ public class ItemTurtleNormal extends ItemTurtleBase
|
|||||||
public ItemTurtleNormal( Block block )
|
public ItemTurtleNormal( Block block )
|
||||||
{
|
{
|
||||||
super( block );
|
super( block );
|
||||||
setUnlocalizedName( "computercraft:turtle" );
|
setTranslationKey( "computercraft:turtle" );
|
||||||
setCreativeTab( ComputerCraft.mainCreativeTab );
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,8 +72,8 @@ public class ItemTurtleNormal extends ItemTurtleBase
|
|||||||
}
|
}
|
||||||
if( overlay != null )
|
if( overlay != null )
|
||||||
{
|
{
|
||||||
nbt.setString( "overlay_mod", overlay.getResourceDomain() );
|
nbt.setString( "overlay_mod", overlay.getNamespace() );
|
||||||
nbt.setString( "overlay_path", overlay.getResourcePath() );
|
nbt.setString( "overlay_path", overlay.getPath() );
|
||||||
}
|
}
|
||||||
stack.setTagCompound( nbt );
|
stack.setTagCompound( nbt );
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user