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

Compare commits

...

51 Commits

Author SHA1 Message Date
SquidDev
a4cd1fe77d Stop releasing betas by default
Things just got serious I guess??
2019-02-23 10:35:15 +00:00
Wilma456 (Jakob0815)
4145914024 Make Multishell Scrollable (#123)
You can now Scroll through the program list, if the list bigger than your
screen.
2019-02-21 16:00:13 +00:00
SquidDev
6bd11a5e4a Fix the other instance of the neighbour deprecation warning 2019-02-20 18:37:22 +00:00
SquidDev
46fa798797 Several minor improvements
- Restrict what items can be inserted into printers. They're now closer
   to brewing stands or furnaces: nothing can go in the output slot,
   only ink in the ink slot, and only paper in the paper slot.
 - Fix build.gradle using the wrong version
 - Trim the width of tables to fit when displaying on the client. Closes
   #45. Note, our solution isn't perfect, as it will wordwrap too, but
   it's adaquate for now.
2019-02-20 09:48:16 +00:00
SquidDev
70a226207e Update README and versioning (#121)
- Reword elements of the README, mostly changing the elements about
   vanilla ComputerCraft.
 - Change versioning scheme: we'll now do 1.x.y, with 1.81.0 being the
   next version.
 - Include MC version in the file name
 - Stop bundling javadoc with the jar. We'll look into hosting this on
   squiddev.cc if really needed.
 - Remove the LuaJ license from the root - we no longer bundle the
   sources, so it's not needed here.

I realise this change looks a little dodgey on its own, so see #113 for
the full rationale.
2019-02-19 14:49:13 +00:00
SquidDev
257a35f3ed Merge pull request #120 from SquidDev-CC/feature/palette-improvements
Minor palette improvements
2019-02-19 10:59:35 +00:00
Lignum
af01b9514b Split colours.rgb8 into colours.packRGB and colours.unpackRGB 2019-02-19 09:51:01 +00:00
Lignum
070fd1f2ff Add term.nativePaletteColo(u)r 2019-02-19 09:50:57 +00:00
SquidDev
fb59da2b06 Update GitHub templates, removing CC repo links
See #113
2019-02-18 23:35:50 +00:00
SquidDev
11e4d0de82 Fix turtle peripherals becoming desynced
When a turtle was unloaded but not actually disposed of, the
m_peripheral map hangs around. As a result, when creating a new
ServerComputer, the peripherals aren't considered changed and so they're
never attached.

Fixes #50.

Also fix that blumin' deprecated method which has been around for a wee
while now.
2019-02-18 23:28:51 +00:00
SquidDev
e46ab1e267 Revert some image optimisations 2019-02-18 22:58:39 +00:00
SquidDev
d6e0f368df Handle managing computer inputs/outputs separatly
The Computer class currently has several resposiblities such as storing
id/label, managing redstone/peirpherals, handling management of the
computer (on/off/events) and updating the output.

In order to simplify this a little bit, we move our IAPIEnvironment
implementation into a separate file, and store all "world state"
(redstone + peripherals) in there. While we still need to have some
level of updating them within the main Computer instance, it's
substantially simpler.
2019-02-17 19:48:52 +00:00
SquidDev
9f2884bc0f Several minor improvments to websockets
- Fire close events instead of failure when open websockets error.
 - Handle ping events. I thought I was doing this already, but this
   requires a WebsocketProtocolHandler. Fixes #118
2019-02-17 19:36:18 +00:00
SquidDev
18d468e887 Fix building from a fresh setup
We were attempting to resolve the Forge jars before they had been
generated, which meant the build failed.
2019-02-16 16:01:47 +00:00
SquidDev
63f6735bb8 Attempt to reduce jar size a little
- Run optipng on all our images. This has very little effect on most of
   them (as they're all so small anyway), but has resulted in a 50%
   reduction in some cases.
 - Run Proguard on our shadowed dependencies (Cobalt).
 - Minify our JSON files, stripping all whitespace. This is mostly
   useful for FML's annotation cache, as that's a massive file, but
   still a semi-useful optimisation to make.

This has helped reduce the jar by about 110kb, which isn't much but
still feels somewhat worth it.
2019-02-14 10:53:18 +00:00
SquidDev
ab6f0ccd16 Fix advanced modems not actually being advanced
We were constructing the peripheral before the advanced property had
been set, thus it was always false. Yay for Java.

Closes #111
2019-02-12 18:11:04 +00:00
SquidDev
ae0f093e73 Strip \r from .readLine on binary handles
Note, this is technically inconsistent with the spec. However, we'll use
this method for now in order to remain backwards compatible.

Fixes #109.
2019-02-11 16:58:43 +00:00
SquidDev
e5f988e3fe Fix missing advanced turtle model when rendering
I'm not even sure how I missed this when testing.
2019-02-11 16:38:33 +00:00
SquidDev
12e82afad2 Bump Cobalt version to enable single-threading
The latest version of Cobalt has several major changes, which I'm
looking forward to taking advantage of in the coming months:

 - The Lua interpreter has been split up from the actual LuaClosure
   instance. It now runs multiple functions within one loop, handling
   pushing/popping and resuming method calls correctly.

   This means we have a theoretically infinite call depth, as we're no
   longer bounded by Java's stack size. In reality, this is limited to
   32767 (Short.MAX_VALUE), as that's a mostly equivalent to the limits
   PUC Lua exposes.

 - The stack is no longer unwound in the event of errors. This both
   simplifies error handling (not that CC:T needs to care about that)
   but also means one can call debug.traceback on a now-dead coroutine
   (which is more useful for debugging than using xpcall).

 - Most significantly, coroutines are no longer each run on a dedicated
   thread. Instead, yielding or resuming throws an exception to unwind
   the Java stack and switches to a different coroutine.

   In order to preserve compatability with CC's assumption about LuaJ's
   threading model (namely that yielding blocks the thread), we also
   provide a yieldBlock method (which CC:T consumes). This suspends the
   current thread and switches execution to a new thread (see
   SquidDev/Cobalt@b5ddf164f1 for more
   details). While this does mean we need to use more than 1 thread,
   it's still /substantially/ less than would otherwise be needed.

We've been running these changes on SwitchCraft for a few days now and
haven't seen any issues. One nice thing to observe is that the number of
CC thread has gone down from ~1.9k to ~100 (of those, ~70 are dedicated
to running coroutines). Similarly, the server has gone from generating
~15k threads over its lifetime, to ~3k. While this is still a lot, it's
a substantial improvement.
2019-02-10 22:02:30 +00:00
SquidDev
6c2db93cbd Register item colour handlers on the event instead
Another step on my misguided quest to get rid of proxies
2019-02-10 09:55:06 +00:00
SquidDev
d5edbe700b Load turtle item models using a model loader
This is far more elegant than our weird method of baking things and
manually inserting them into the model map. Also means we no longer need
the whole turtle_dynamic thing.
2019-02-10 09:45:15 +00:00
SquidDev
86ad43c3ab Fix peripheral direction not being set
We moved the direction call within the if block, but never actally
updated the condition! I'm on a roll of stupid bug fixes today, which
really isn't a good sign.
2019-02-07 23:07:49 +00:00
SquidDev
f450c0156b Recomment out a global
It's actually rather worrying this was exposed, you could cause some
serious issues with it.
2019-02-07 20:22:00 +00:00
SquidDev
8abcfcb4ac Track turtle commands as server tasks
They're basically an alternative version of issueMainThreadTask anyway.
2019-01-30 20:43:08 +00:00
SquidDev
f3cace1d03 Allow building without a git repository
Closes #102
2019-01-28 14:05:53 +00:00
SquidDev
e1e5e898ab Make monitors use a concurrent map instead of a synchronized
We didn't lock when iterating on the main-thread, so it wasn't actually
thread-safe anyway!
2019-01-25 22:59:01 +00:00
SquidDev
3aa3852ff6 Some further improvements to BlockGeneric
- Only have computers implement custom block drop logic: everything
   else only drops in creative mode.
 - Fix redstone inputs not being received correctly. Introduced in
   8b86a954ee, yes I'm a silly billy.
 - Only update the neighbour which changed.
2019-01-25 22:03:44 +00:00
SquidDev
709a6329c7 Fix all wireless modem blocks being advanced 2019-01-25 00:12:49 +00:00
SquidDev
c9f05a2939 Make require a little more consistent with Lua 5.1
- Error messages are indented correctly
 - The module's name is passed as the first argument to modules
 - Make error messages match Lua's
2019-01-23 18:50:17 +00:00
Devilholk
e41377f862 Handle connection errors on websockets 2019-01-22 11:11:25 +00:00
SquidDev
d173787a94 Another backwards compat change
Plethora only implements getPos on older versions, so we need to stub
out both.
2019-01-21 17:36:25 +00:00
SquidDev
d5aea26f3a Bump version
It's pretty soon after the previous release (10 days!) but there's a
couple of important bug fixes and some nice improvements.
2019-01-21 11:02:29 +00:00
SquidDev
2681e578c4 Merge pull request #101 from SquidDev-CC/feature/no-ticking
Make several tile entities non-ticking, hopefully reducing
server load.
2019-01-21 08:29:42 +00:00
SquidDev
1f498dcc73 Backwards compat patch for Plethora
Ughghgghghr.
2019-01-20 16:16:02 +00:00
SquidDev
83b01d35eb Make monitors non-ticking
- Convert terminals from a polling-based system to a more event-driven
   one: they now accept an onChanged callback, which marks the parent as
   dirty.
 - Schedule ticks when monitors are marked as dirty.
 - Add several missing @Overrides. This has nothing to do with the rest
   of the changes, but I'm bad at good git practice.
2019-01-20 15:39:11 +00:00
SquidDev
8a7e651c99 Several miscellaneous changes
- Merge BlockPeripheralBase and BlockPeripheral, as no other classes
   extended the former.
 - Make BlockPeripheral use ITilePeripheral instead of
   TilePeripheralBase. This allows us to use other, non-ticking tiles
   instead.
 - Convert advanced and normal modems to extend from a generic
   TileWirelessModemBase class, and thus neither now tick.
2019-01-20 14:06:41 +00:00
SquidDev
80a5759bae Make advanced modems non-ticking
- Move getPeripheralType and getLabel from IPeripheralTile to
   TilePeripheralBase. These were mostly constant on all other tiles, so
   were rather redundant.
 - Make TileAdvancedModem extend TileGeneric, and be non-ticking (using
   similar logic to all other blocks).
2019-01-20 09:34:15 +00:00
SquidDev
e8a4fbb4e3 Make TileCable non-ticking
- Move updateTick onto BlockGeneric/TileGeneric instead of the full
   wired modem, as it is used by several tiles now.
 - Make *Cable extend from *Generic, and schedule ticks instead of
   running every tick.
2019-01-19 22:25:38 +00:00
SquidDev
0ce67afcc1 Be less strict in comparing upgrade crafting items
We currently generate the crafting item once when the upgrade is first
created, and cache it for the duration of the game. As the item never
changes throughout the game, and constructing a stack is a little
expensive (we need to fire an event, etc...), the caching is worth
having.

However, some mods may register capabilities after we've constructed our
ItemStack. This means the capability will be present on other items but
not ours, meaning they are not considered equivalent, and thus the item
cannot be equipped.

In order to avoid this, we use compare items using their share-tag, like
Forge's IngredientNBT. This means the items must still be "mostly" the
same (same enchantements, etc...), but allow differing capabilities.

See NillerMedDild/Enigmatica2Expert#655 for the original bug report -
in this case, Astral Sourcery was registering the capability in init,
but we construct upgrades just before then.
2019-01-19 21:57:21 +00:00
SquidDev
a8dad23fa3 Begin investigations into reducing ticking of TEs
- Move IDirectionalTile constraint from IPeripheralTile to
   TilePeripheralBase.
 - Make *WiredModemFull no longer inherit from *PeripheralBase. While
   there is still some shared logic (namely in the syncing of "anim"),
   it's largely fine as we don't store label or direction in NBT.
 - Add a TickScheduler. This is a thread-safe version of
   World.scheduleUpdate. We simply build a set of all TEs, and schedule
   them to be updated the next tick.
 - Make ModemState receive an "onChanged" listener, which is fired
   whenever the modem changes.
 - Make WiredModemFull no longer tick, instead scheduling updates when
   it is first loaded and whenever the modem changes.
2019-01-19 10:16:41 +00:00
SquidDev
443e0f8f76 Remove FileSystemMount and rewrite JarMount
FileSystemMount was originally added to allow using ReadableByteChannels
instead of InputStreams. However, as zip files do not allow seeking,
there is no benefit of using them over the original JarMount (which we
need to preserve for backwards compatibility).

Instead of maintaining two near-identical mounts, we remove the
FileSystemMount and rewrite the JarMount implementation with several
improvements:

 - Rewrite the jar scanning algorithm to be closer to 1.13+'s data pack
   mount. This means we no longer require the jar file to have
   directories before the file (though this was not a problem in
   practice).
 - Add all JarMounts to a ReferenceQueue, closing up the ZipFile when
   they have been garbage collected (fixes #100).
 - Cache the contents of all files for 60 seconds (with some constraints
   on size). This allows us to seek on ROM files too (assuming they are
   small), by reading the whole thing into memory.
   The cache is shared across all mounts, and has a 64MiB limit, and
   thus should not have an adverse impact on memory.
2019-01-16 17:25:46 +00:00
SquidDev
a838595e1e Derive upgrade adjectives from its ID
This is done in 1.13+ for items and blocks, so we might as well do it
for upgrades now. Note we can't do it for ender pocket modems, as the
upgrade ID is spelled incorrectly there.
2019-01-14 10:42:13 +00:00
SquidDev
61daab910e Simplify placement logic of various blocks
- For those where placement is stored in the metadata (computers),
   don't also set it in onBlockPlacedBy.
 - Remove .getDefaultState(int, EnumFacing) override, as this means we
   have more control over what is passed to us (namely, placer's
   direction too).
2019-01-14 10:27:19 +00:00
SquidDev
7fd19c43e9 Try to hide CommandCopy from most completions.
"/computercraf" auto-completes to "/computercraft_copy" instead of
"/computercraft", which is rather annoying, as the former is not meant
to be used normally.
2019-01-14 10:10:52 +00:00
SquidDev
ce0685c31f Move our message model to be closer to Forge's
It's rather embarassing that it's been restructured _again_, but I think
this is a nice middle-ground. The previous implementation was written
mostly for Fabric, which doesn't always map perfectly to Forge.

 - Move the message identifier into the registration phrase. It's not
   really a property of the message itself, rather a property of the
   registry, so better suited there.

 - Move message handling into the message itself. Honestly, it was just
   ending up being rather messy mixing the logic in two places.

   This also means we can drop some proxy methods, as it's easier to
   have conditionally loaded methods.

 - Move network registry into a dedicated class, as that's what we're
   doing for everything else.
2019-01-14 10:09:22 +00:00
SquidDev
e33f852baa Store references to the registered items
This means we can avoid several rather ugly instances of getItemBlock
and a cast. We also derive the ItemBlock's registered name from the
block's name, which makes the register a little less ugly.
2019-01-12 19:01:32 +00:00
SquidDev
227d5e9e69 Fix cables not rendering the breaking steps
The fact that it's taken this long for anyone to notice this didn't work
is rather embarassing.
2019-01-12 18:35:43 +00:00
SquidDev
1c648850ab Even more proxy pruning
- Move the "world directory" getter out of the proxy - we can just use
   Forge's code here.
 - Remove the server proxies, as both were empty. We don't tend to
   register any dedicated-server specific code, so I think we can leave
   them out.
2019-01-12 18:23:22 +00:00
SquidDev
63691707fc Move registration methods into a separate class
- All "named" entries (blocks, items, recipes, TEs and pocket/turtle
   upgrades) are registeredin one place.
 - Most client side models/textures are registered in ClientRegistry -
   we can't do item colours or TEs for now, as these aren't event based.
 - A little cleanup to how we handle ItemPocketComputer models.
2019-01-12 17:51:26 +00:00
SquidDev
5d97b9c8f3 Utilise @Mod.EventBusSubscriber a little more
This offers several advantages

 - Less registration code: the subscribers are reigstered automatically,
   and we don't need to worry about sided-proxies.
 - We no longer have so many .instance() calls.
2019-01-12 16:27:40 +00:00
SquidDev
77666d7399 Some more minor cleanups
- Move SpeakerPeripheral's TileSpeaker functionality to a sub-class.
 - Use Vec3d instead of BlockPos for speaker's positions.
 - Use WorldUtil.dropItemStack to spawn in items.
 - Remove redundant lock on ModemPeripheral.
2019-01-12 15:43:18 +00:00
185 changed files with 3604 additions and 4079 deletions

View File

@@ -6,11 +6,10 @@ 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.
- Search for the bug on the issue tracker. Make sure to look at closed issues too!
-->
## 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.
- Detailed reproduction steps: sometimes I can spot a bug pretty easily, but often it's much more obscure. The more information I have to help reproduce it, the quicker it'll get fixed.

View File

@@ -6,10 +6,9 @@ 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.
- Search for the suggestion here. It's possible someone's suggested it before!
-->
## 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
- Explanation of how the feature/change should work.
- Some rationale/use case for a feature. I'd like to keep CC:T as minimal as possible, so I like have a solid justification for each feature.

View File

@@ -1,9 +0,0 @@
<!--
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.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2007 LuaJ. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,35 +1,35 @@
# ![CC: Tweaked](logo.png)
[![Build Status](https://travis-ci.org/SquidDev-CC/CC-Tweaked.svg?branch=master)](https://travis-ci.org/SquidDev-CC/CC-Tweaked)
CC: Tweaked is a fork of ComputerCraft which aims to provide earlier access to the more experimental and in-development
features of the mod. For a more stable experience, I recommend checking out the
[original mod](https://github.com/dan200/ComputerCraft).
CC: Tweaked is a fork of [ComputerCraft](https://github.com/dan200/ComputerCraft), adding programmable computers,
turtles and more to Minecraft.
## What?
CC: Tweaked (or CC:T for short) does not aim to create a competing fork of ComputerCraft, nor am I planning to take it
in in a vastly different direction to the original mod. In fact, CC:T aims to be a nurturing ground for various
features, with a pull request against the original mod being the end goal.
ComputerCraft has always held a fond place in my heart: it's the mod which really got me into Minecraft, and it's the
mod which has kept me playing it for many years. However, development of the original mod has slowed, as the original
developers have had less time to work on the mod, and moved onto other projects and commitments.
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.
CC:Tweaked (or CC:T for short) is an attempt to continue ComputerCraft's legacy. It's not intended to be a competitor
to CC, nor do I want to take it in a vastly different direction to the original mod. Instead, CC:T focuses on making the
ComputerCraft experience as _solid_ as possible, ironing out any wrinkles that may have developed over time.
## Features
CC: Tweaked contains all the 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:
CC: Tweaked contains all the features of the latest version of ComputerCraft, as well as numerous fixes, performance
improvements and several nifty additions. I'd recommend checking out [the releases page](https://github.com/SquidDev-CC/CC-Tweaked/releases)
to see the full set of changes, but here's a couple of the more interesting additions:
- 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
- Improvements to the `http` library, including websockets, support for other HTTP methods (`PUT`, `DELETE`, etc...)
and configurable limits on HTTP usage.
- Full-block wired modems, allowing one to wrap non-solid peripherals (such as turtles, or chests if Plethora is
installed).
- Pocket computers can be held like maps, allowing you to view the screen without entering a GUI.
- Printed pages and books can be placed in item frames and held like maps.
- Several profiling and administration tools for server owners, via the `/computercraft` command. 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).
- Extended binary file handles. They support file seeking, and reading new lines, allowing full (and accurate)
emulation of the standard Lua `io` library.
- Closer emulation of standard Lua, adding the `debug` and `io` libraries. This also enables seeking within binary
files, meaning you don't need to read large files into memory.
- Allow running multiple computers on multiple threads, reducing latency on worlds with many computers.
## Relation to CCTweaks?
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. That being said,
@@ -37,10 +37,8 @@ several features have been included, such as full block modems, the Cobalt runti
computers.
## Contributing
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 first.
That being said, in order to start helping develop CC:T, you'll need to follow these steps:
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. 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`
- **Setup Forge:** `./gradlew setupDecompWorkspace`

View File

@@ -9,8 +9,10 @@ buildscript {
}
}
dependencies {
classpath 'com.google.code.gson:gson:2.8.1'
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
classpath 'org.ajoberstar:gradle-git:1.6.0'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta1'
classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
}
}
@@ -23,12 +25,14 @@ apply plugin: 'org.ajoberstar.grgit'
apply plugin: 'maven-publish'
apply plugin: 'maven'
version = "1.80pr1.13"
def mc_version = "1.12.2"
version = "1.81.0"
group = "org.squiddev"
archivesBaseName = "cc-tweaked"
archivesBaseName = "cc-tweaked-${mc_version}"
minecraft {
version = "1.12.2-14.23.4.2749"
version = "${mc_version}-14.23.4.2749"
runDir = "run"
replace '${version}', project.version
@@ -48,7 +52,7 @@ repositories {
}
maven {
name = "squiddev"
url = "https://dl.bintray.com/squiddev/maven"
url = "https://squiddev.cc/maven"
}
ivy { artifactPattern "https://asie.pl/files/mods/Charset/LibOnly/[module]-[revision](-[classifier]).[ext]" }
@@ -66,7 +70,7 @@ dependencies {
runtime "mezz.jei:jei_1.12.2:4.8.5.159"
shade 'org.squiddev:Cobalt:0.4.0'
shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT'
testCompile 'junit:junit:4.11'
@@ -84,39 +88,91 @@ jar {
attributes('FMLAT': 'computercraft_at.cfg')
}
into("docs", { from (javadoc.destinationDir) })
into("api", { from (sourceSets.main.allSource) {
from (sourceSets.main.allSource) {
include "dan200/computercraft/api/**/*.java"
}})
}
from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
}
import java.nio.charset.StandardCharsets
import java.nio.file.*
import java.util.zip.*
import com.google.gson.GsonBuilder
import com.google.gson.JsonElement
import org.ajoberstar.grgit.Grgit
import proguard.gradle.ProGuardTask
task proguard(type: ProGuardTask, dependsOn: jar) {
description "Removes unused shadowed classes from the jar"
group "compact"
injars jar.archivePath
outjars "${jar.archivePath.absolutePath.replace(".jar", "")}-min.jar"
// Add the main runtime jar and all non-shadowed dependencies
libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
doFirst {
sourceSets.main.compileClasspath
.filter { !it.name.contains("Cobalt") }
.each { libraryjars it }
}
// We want to avoid as much obfuscation as possible. We're only doing this to shrink code size.
dontobfuscate; dontoptimize; keepattributes; keepparameternames
// Proguard will remove directories by default, but that breaks JarMount.
keepdirectories 'assets/computercraft/lua**'
// Preserve ComputerCraft classes - we only want to strip shadowed files.
keep 'class dan200.computercraft.** { *; }'
// Preserve the constructors in Cobalt library class, as we init them via reflection
keepclassmembers 'class org.squiddev.cobalt.lib.** { <init>(...); }'
}
task proguardMove(dependsOn: proguard) {
description "Replace the original jar with the minified version"
group "compact"
doLast {
Files.move(
file("${jar.archivePath.absolutePath.replace(".jar", "")}-min.jar").toPath(),
file(jar.archivePath).toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
reobfJar.dependsOn proguardMove
processResources {
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
inputs.property "mcversion", mc_version
def grgit = Grgit.open(dir: '.')
inputs.property "commithash", grgit.head().id
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
def hash = 'none'
Set<String> contributors = []
try {
def grgit = Grgit.open(dir: '.')
hash = grgit.head().id
grgit.log().each {
if (!blacklist.contains(it.author.name)) contributors.add(it.author.name)
if (!blacklist.contains(it.committer.name)) contributors.add(it.committer.name)
}
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
grgit.log().each {
if (!blacklist.contains(it.author.name)) contributors.add(it.author.name)
if (!blacklist.contains(it.committer.name)) contributors.add(it.committer.name)
}
} catch(Exception ignored) { }
inputs.property "commithash", hash
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
include 'assets/computercraft/lua/rom/help/credits.txt'
expand 'version':project.version,
'mcversion':project.minecraft.version,
'gitcontributors':contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n')
expand 'version': project.version,
'mcversion': mc_version,
'gitcontributors': contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n')
}
from(sourceSets.main.resources.srcDirs) {
@@ -125,12 +181,53 @@ processResources {
}
}
task compressJson(dependsOn: extractAnnotationsJar) {
group "compact"
description "Minifies all JSON files, stripping whitespace"
def jarPath = file(jar.archivePath)
def tempPath = File.createTempFile("input", ".jar", temporaryDir)
tempPath.deleteOnExit()
def gson = new GsonBuilder().create()
doLast {
// Copy over all files in the current jar to the new one, running json files from GSON. As pretty printing
// is turned off, they should be minified.
new ZipFile(jarPath).withCloseable { inJar ->
new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tempPath))).withCloseable { outJar ->
inJar.entries().each { entry ->
if(entry.directory) {
outJar.putNextEntry(entry)
} else if(!entry.name.endsWith(".json")) {
outJar.putNextEntry(entry)
inJar.getInputStream(entry).withCloseable { outJar << it }
} else {
ZipEntry newEntry = new ZipEntry(entry.name)
newEntry.setTime(entry.time)
outJar.putNextEntry(newEntry)
def element = inJar.getInputStream(entry).withCloseable { gson.fromJson(it.newReader("UTF8"), JsonElement.class) }
outJar.write(gson.toJson(element).getBytes(StandardCharsets.UTF_8))
}
}
}
}
// And replace the original jar again
Files.move(tempPath.toPath(), jarPath.toPath(), StandardCopyOption.REPLACE_EXISTING)
}
}
assemble.dependsOn compressJson
curseforge {
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
project {
id = '282001'
releaseType = 'beta'
releaseType = 'release'
changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${project.version})."
}
}

View File

@@ -26,7 +26,7 @@ import dan200.computercraft.core.apis.ApiFactories;
import dan200.computercraft.core.apis.http.websocket.Websocket;
import dan200.computercraft.core.filesystem.ComboMount;
import dan200.computercraft.core.filesystem.FileMount;
import dan200.computercraft.core.filesystem.FileSystemMount;
import dan200.computercraft.core.filesystem.JarMount;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.shared.*;
@@ -37,15 +37,21 @@ import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.core.ServerComputerRegistry;
import dan200.computercraft.shared.computer.items.ItemCommandComputer;
import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.media.items.ItemDiskExpanded;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.network.NetworkHandler;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.ItemPeripheral;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
import dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull;
import dan200.computercraft.shared.peripheral.modem.wired.ItemCable;
import dan200.computercraft.shared.peripheral.modem.wireless.BlockAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.ItemAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
@@ -55,6 +61,9 @@ import dan200.computercraft.shared.proxy.ICCTurtleProxy;
import dan200.computercraft.shared.proxy.IComputerCraftProxy;
import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.items.ItemTurtleAdvanced;
import dan200.computercraft.shared.turtle.items.ItemTurtleLegacy;
import dan200.computercraft.shared.turtle.items.ItemTurtleNormal;
import dan200.computercraft.shared.turtle.upgrades.*;
import dan200.computercraft.shared.util.CreativeTabMain;
import dan200.computercraft.shared.util.IDAssigner;
@@ -62,7 +71,7 @@ import dan200.computercraft.shared.util.IoUtil;
import dan200.computercraft.shared.wired.CapabilityWiredElement;
import dan200.computercraft.shared.wired.WiredNode;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
@@ -71,13 +80,11 @@ import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.*;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.relauncher.Side;
import org.apache.logging.log4j.Logger;
@@ -85,13 +92,9 @@ import java.io.*;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.ServiceConfigurationError;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -172,51 +175,74 @@ public class ComputerCraft
public static class Blocks
{
public static BlockComputer computer;
public static BlockPeripheral peripheral;
public static BlockCable cable;
public static BlockCommandComputer commandComputer;
public static BlockTurtle turtle;
public static BlockTurtle turtleExpanded;
public static BlockTurtle turtleAdvanced;
public static BlockCommandComputer commandComputer;
public static BlockPeripheral peripheral;
public static BlockCable cable;
public static BlockAdvancedModem advancedModem;
public static BlockWiredModemFull wiredModemFull;
}
public static class Items
{
public static ItemComputer computer;
public static ItemCommandComputer commandComputer;
public static ItemTurtleLegacy turtle;
public static ItemTurtleNormal turtleExpanded;
public static ItemTurtleAdvanced turtleAdvanced;
public static ItemPocketComputer pocketComputer;
public static ItemDiskLegacy disk;
public static ItemDiskExpanded diskExpanded;
public static ItemPrintout printout;
public static ItemTreasureDisk treasureDisk;
public static ItemPocketComputer pocketComputer;
public static ItemPrintout printout;
public static ItemPeripheral peripheral;
public static ItemAdvancedModem advancedModem;
public static ItemCable cable;
public static ItemBlock wiredModemFull;
}
public static class Upgrades
public static class TurtleUpgrades
{
public static TurtleModem wirelessModem;
public static TurtleModem advancedModem;
public static TurtleSpeaker speaker;
public static TurtleCraftingTable craftingTable;
public static TurtleSword diamondSword;
public static TurtleShovel diamondShovel;
public static TurtleTool diamondPickaxe;
public static TurtleAxe diamondAxe;
public static TurtleHoe diamondHoe;
public static TurtleModem advancedModem;
public static TurtleSpeaker turtleSpeaker;
}
public static class PocketUpgrades
{
public static PocketModem wirelessModem;
public static PocketModem advancedModem;
public static PocketSpeaker speaker;
@Deprecated
public static PocketSpeaker pocketSpeaker;
}
// Registries
public static ClientComputerRegistry clientComputerRegistry = new ClientComputerRegistry();
public static ServerComputerRegistry serverComputerRegistry = new ServerComputerRegistry();
@Deprecated
public static class Upgrades
{
public static TurtleModem advancedModem;
}
// Networking
public static SimpleNetworkWrapper networkWrapper;
// Registries
public static final ClientComputerRegistry clientComputerRegistry = new ClientComputerRegistry();
public static final ServerComputerRegistry serverComputerRegistry = new ServerComputerRegistry();
// Creative
public static CreativeTabMain mainCreativeTab;
@@ -231,11 +257,17 @@ public class ComputerCraft
@Mod.Instance( value = ComputerCraft.MOD_ID )
public static ComputerCraft instance;
@SidedProxy( clientSide = "dan200.computercraft.client.proxy.ComputerCraftProxyClient", serverSide = "dan200.computercraft.server.proxy.ComputerCraftProxyServer" )
public static IComputerCraftProxy proxy;
@SidedProxy(
clientSide = "dan200.computercraft.client.proxy.ComputerCraftProxyClient",
serverSide = "dan200.computercraft.shared.proxy.ComputerCraftProxyCommon"
)
private static IComputerCraftProxy proxy;
@SidedProxy( clientSide = "dan200.computercraft.client.proxy.CCTurtleProxyClient", serverSide = "dan200.computercraft.server.proxy.CCTurtleProxyServer" )
public static ICCTurtleProxy turtleProxy;
@SidedProxy(
clientSide = "dan200.computercraft.client.proxy.CCTurtleProxyClient",
serverSide = "dan200.computercraft.shared.proxy.CCTurtleProxyCommon"
)
private static ICCTurtleProxy turtleProxy;
@Mod.EventHandler
public void preInit( FMLPreInitializationEvent event )
@@ -246,7 +278,7 @@ public class ComputerCraft
Config.load( event.getSuggestedConfigurationFile() );
// Setup network
networkWrapper = NetworkRegistry.INSTANCE.newSimpleChannel( ComputerCraft.MOD_ID );
NetworkHandler.setup();
proxy.preInit();
turtleProxy.preInit();
@@ -354,31 +386,6 @@ public class ComputerCraft
return new File( getBaseDir(), "resourcepacks" );
}
public static File getWorldDir( World world )
{
return proxy.getWorldDir( world );
}
public static void sendToPlayer( EntityPlayer player, IMessage packet )
{
networkWrapper.sendTo( packet, (EntityPlayerMP) player );
}
public static void sendToAllPlayers( IMessage packet )
{
networkWrapper.sendToAll( packet );
}
public static void sendToServer( IMessage packet )
{
networkWrapper.sendToServer( packet );
}
public static void sendToAllAround( IMessage packet, NetworkRegistry.TargetPoint point )
{
networkWrapper.sendToAllAround( packet, point );
}
public static boolean canPlayerUseCommands( EntityPlayer player )
{
MinecraftServer server = player.getServer();
@@ -455,7 +462,7 @@ public class ComputerCraft
@Deprecated
public static int createUniqueNumberedSaveDir( World world, String parentSubPath )
{
return IDAssigner.getNextIDFromDirectory( new File( getWorldDir( world ), parentSubPath ) );
return IDAssigner.getNextIDFromDirectory( parentSubPath );
}
@Deprecated
@@ -463,7 +470,7 @@ public class ComputerCraft
{
try
{
return new FileMount( new File( getWorldDir( world ), subPath ), capacity );
return new FileMount( new File( getWorldDir(), subPath ), capacity );
}
catch( Exception e )
{
@@ -496,13 +503,11 @@ public class ComputerCraft
{
try
{
FileSystem fs = FileSystems.newFileSystem( modJar.toPath(), ComputerCraft.class.getClassLoader() );
mounts.add( new FileSystemMount( fs, subPath ) );
mounts.add( new JarMount( modJar, subPath ) );
}
catch( IOException | RuntimeException | ServiceConfigurationError e )
catch( IOException | RuntimeException e )
{
ComputerCraft.log.error( "Could not load mount from mod jar", e );
// Ignore
}
}
@@ -519,21 +524,16 @@ public class ComputerCraft
if( !resourcePack.isDirectory() )
{
// Mount a resource pack from a jar
FileSystem fs = FileSystems.newFileSystem( resourcePack.toPath(), ComputerCraft.class.getClassLoader() );
if( Files.exists( fs.getPath( subPath ) ) ) mounts.add( new FileSystemMount( fs, subPath ) );
mounts.add( new JarMount( resourcePack, subPath ) );
}
else
{
// Mount a resource pack from a folder
File subResource = new File( resourcePack, subPath );
if( subResource.exists() )
{
IMount resourcePackMount = new FileMount( subResource, 0 );
mounts.add( resourcePackMount );
}
if( subResource.exists() ) mounts.add( new FileMount( subResource, 0 ) );
}
}
catch( IOException | RuntimeException | ServiceConfigurationError e )
catch( IOException | RuntimeException e )
{
ComputerCraft.log.error( "Could not load resource pack '" + resourcePackName + "'", e );
}
@@ -680,10 +680,21 @@ public class ComputerCraft
@Deprecated
public static void registerTurtleUpgrade( ITurtleUpgrade upgrade )
{
TurtleUpgrades.register( upgrade );
dan200.computercraft.shared.TurtleUpgrades.register( upgrade );
}
public static File getWorldDir()
{
return DimensionManager.getCurrentSaveRootDirectory();
}
//region Compatibility
@Deprecated
public static File getWorldDir( World world )
{
return DimensionManager.getCurrentSaveRootDirectory();
}
@Deprecated
public static IMedia getMedia( ItemStack stack )
{
@@ -699,7 +710,7 @@ public class ComputerCraft
@Deprecated
public static ITurtleUpgrade getTurtleUpgrade( ItemStack stack )
{
return TurtleUpgrades.get( stack );
return dan200.computercraft.shared.TurtleUpgrades.get( stack );
}
@Deprecated
@@ -711,7 +722,7 @@ public class ComputerCraft
@Deprecated
public static ITurtleUpgrade getTurtleUpgrade( String id )
{
return TurtleUpgrades.get( id );
return dan200.computercraft.shared.TurtleUpgrades.get( id );
}
@Deprecated

View File

@@ -0,0 +1,193 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.TurtleModelLoader;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.turtle.items.ItemTurtleBase;
import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemMeshDefinition;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ModelBakery;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ColorHandlerEvent;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import javax.annotation.Nonnull;
/**
* Registers textures and models for items.
*/
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
public class ClientRegistry
{
private static final String[] EXTRA_MODELS = {
"turtle_modem_off_left",
"turtle_modem_on_left",
"turtle_modem_off_right",
"turtle_modem_on_right",
"turtle_crafting_table_left",
"turtle_crafting_table_right",
"advanced_turtle_modem_off_left",
"advanced_turtle_modem_on_left",
"advanced_turtle_modem_off_right",
"advanced_turtle_modem_on_right",
"turtle_speaker_upgrade_left",
"turtle_speaker_upgrade_right",
"turtle_white",
"turtle_elf_overlay",
};
@SubscribeEvent
public static void registerModels( ModelRegistryEvent event )
{
ModelLoaderRegistry.registerLoader( TurtleModelLoader.INSTANCE );
// Register item models
registerUniversalItemModel( ComputerCraft.Items.computer, "computer" );
registerItemModel( ComputerCraft.Items.commandComputer, 0, "command_computer" );
registerItemModel( ComputerCraft.Items.pocketComputer, 0, "pocket_computer" );
registerItemModel( ComputerCraft.Items.pocketComputer, 1, "advanced_pocket_computer" );
registerItemModel( ComputerCraft.Items.peripheral, 0, "peripheral" );
registerItemModel( ComputerCraft.Items.peripheral, 1, "wireless_modem" );
registerItemModel( ComputerCraft.Items.peripheral, 2, "monitor" );
registerItemModel( ComputerCraft.Items.peripheral, 3, "printer" );
registerItemModel( ComputerCraft.Items.peripheral, 4, "advanced_monitor" );
registerItemModel( ComputerCraft.Items.cable, 0, "cable" );
registerItemModel( ComputerCraft.Items.cable, 1, "wired_modem" );
registerItemModel( ComputerCraft.Items.advancedModem, 0, "advanced_modem" );
registerItemModel( ComputerCraft.Items.peripheral, 5, "speaker" );
registerItemModel( ComputerCraft.Items.wiredModemFull, 0, "wired_modem_full" );
registerUniversalItemModel( ComputerCraft.Items.disk, "disk" );
registerItemModel( ComputerCraft.Items.diskExpanded, 0, "disk_expanded" );
registerItemModel( ComputerCraft.Items.treasureDisk, 0, "treasure_disk" );
registerItemModel( ComputerCraft.Items.printout, 0, "printout" );
registerItemModel( ComputerCraft.Items.printout, 1, "pages" );
registerItemModel( ComputerCraft.Items.printout, 2, "book" );
registerUniversalItemModel( ComputerCraft.Items.turtle, "turtle" );
registerUniversalItemModel( ComputerCraft.Items.turtleExpanded, "turtle" );
registerUniversalItemModel( ComputerCraft.Items.turtleAdvanced, "turtle_advanced" );
}
@SubscribeEvent
public static void onTextureStitchEvent( TextureStitchEvent.Pre event )
{
// Load all textures for the extra models
TextureMap map = event.getMap();
for( String upgrade : EXTRA_MODELS )
{
IModel model = ModelLoaderRegistry.getModelOrMissing( new ResourceLocation( "computercraft", "block/" + upgrade ) );
for( ResourceLocation texture : model.getTextures() ) map.registerSprite( texture );
}
}
@SubscribeEvent
public static void onModelBakeEvent( ModelBakeEvent event )
{
// Load all extra models
for( String model : EXTRA_MODELS ) loadBlockModel( event, model );
}
@SubscribeEvent
public static void onItemColours( ColorHandlerEvent.Item event )
{
event.getItemColors().registerItemColorHandler(
( stack, layer ) -> layer == 0 ? 0xFFFFFF : ((ItemDiskLegacy) stack.getItem()).getColour( stack ),
ComputerCraft.Items.disk, ComputerCraft.Items.diskExpanded
);
event.getItemColors().registerItemColorHandler( ( stack, layer ) -> {
switch( layer )
{
case 0:
default:
return 0xFFFFFF;
case 1:
{
// Frame colour
int colour = ComputerCraft.Items.pocketComputer.getColour( stack );
return colour == -1 ? 0xFFFFFF : colour;
}
case 2:
{
// Light colour
int colour = ComputerCraft.Items.pocketComputer.getLightState( stack );
return colour == -1 ? Colour.Black.getHex() : colour;
}
}
}, ComputerCraft.Items.pocketComputer );
// Setup turtle colours
event.getItemColors().registerItemColorHandler( ( stack, tintIndex ) -> {
if( tintIndex == 0 )
{
ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem();
int colour = turtle.getColour( stack );
if( colour != -1 ) return colour;
}
return 0xFFFFFF;
}, ComputerCraft.Blocks.turtle, ComputerCraft.Blocks.turtleExpanded, ComputerCraft.Blocks.turtleAdvanced );
}
private static void registerItemModel( Item item, int damage, String name )
{
ResourceLocation location = new ResourceLocation( ComputerCraft.MOD_ID, name );
final ModelResourceLocation res = new ModelResourceLocation( location, "inventory" );
ModelBakery.registerItemVariants( item, location );
ModelLoader.setCustomModelResourceLocation( item, damage, res );
}
private static void registerUniversalItemModel( Item item, String mainModel )
{
ResourceLocation mainLocation = new ResourceLocation( ComputerCraft.MOD_ID, mainModel );
ModelBakery.registerItemVariants( item, mainLocation );
final ModelResourceLocation mainModelLocation = new ModelResourceLocation( mainLocation, "inventory" );
ModelLoader.setCustomMeshDefinition( item, new ItemMeshDefinition()
{
@Nonnull
@Override
public ModelResourceLocation getModelLocation( @Nonnull ItemStack stack )
{
return mainModelLocation;
}
} );
}
private static void loadBlockModel( ModelBakeEvent event, String name )
{
IModel model = ModelLoaderRegistry.getModelOrMissing( new ResourceLocation( ComputerCraft.MOD_ID, "block/" + name ) );
IBakedModel bakedModel = model.bake(
model.getDefaultState(), DefaultVertexFormats.ITEM,
location -> Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( location.toString() )
);
event.getModelRegistry().putObject( new ModelResourceLocation( ComputerCraft.MOD_ID + ":" + name, "inventory" ), bakedModel );
}
}

View File

@@ -13,12 +13,14 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.client.gui.GuiUtilRenderComponents;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextFormatting;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
import java.util.List;
public class ClientTableFormatter implements TableFormatter
{
@@ -62,7 +64,13 @@ public class ClientTableFormatter implements TableFormatter
@Override
public void writeLine( int id, ITextComponent component )
{
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion( component, id );
Minecraft mc = Minecraft.getMinecraft();
GuiNewChat chat = mc.ingameGUI.getChatGUI();
// Trim the text if it goes over the allowed length
int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getChatScale() );
List<ITextComponent> list = GuiUtilRenderComponents.splitText( component, maxWidth, mc.fontRenderer, false, false );
if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id );
}
@Override

View File

@@ -6,43 +6,40 @@
package dan200.computercraft.client;
import dan200.computercraft.ComputerCraft;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side;
public class FrameInfo
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
public final class FrameInfo
{
private static final FrameInfo instance = new FrameInfo();
public static FrameInfo instance()
{
return instance;
}
private int tick;
private long renderFrame;
private static int tick;
private static long renderFrame;
private FrameInfo()
{
}
public boolean getGlobalCursorBlink()
public static boolean getGlobalCursorBlink()
{
return (tick / 8) % 2 == 0;
}
public long getRenderFrame()
public static long getRenderFrame()
{
return renderFrame;
}
@SubscribeEvent
public void onTick( TickEvent.ClientTickEvent event )
public static void onTick( TickEvent.ClientTickEvent event )
{
if( event.phase == TickEvent.Phase.START ) tick++;
}
@SubscribeEvent
public void onRenderTick( TickEvent.RenderTickEvent event )
public static void onRenderTick( TickEvent.RenderTickEvent event )
{
if( event.phase == TickEvent.Phase.START ) renderFrame++;
}

View File

@@ -388,7 +388,7 @@ public class WidgetTerminal extends Widget
// Get the data from the terminal first
// Unfortunately we have to keep the lock for the whole of drawing, so the text doesn't change under us.
FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance();
boolean tblink = m_focus && terminal.getCursorBlink() && FrameInfo.instance().getGlobalCursorBlink();
boolean tblink = m_focus && terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink();
int tw = terminal.getWidth();
int th = terminal.getHeight();
int tx = terminal.getCursorX();

View File

@@ -6,209 +6,19 @@
package dan200.computercraft.client.proxy;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.client.render.TurtleSmartItemModel;
import dan200.computercraft.shared.proxy.CCTurtleProxyCommon;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.items.ItemTurtleBase;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemMeshDefinition;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ModelBakery;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.color.IItemColor;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.SimpleReloadableResourceManager;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import javax.annotation.Nonnull;
public class CCTurtleProxyClient extends CCTurtleProxyCommon
{
// IComputerCraftProxy implementation
@Override
public void preInit()
{
super.preInit();
// Setup client forge handlers
registerForgeHandlers();
}
@SubscribeEvent
public void registerModels( ModelRegistryEvent event )
{
// Register item models
ItemMeshDefinition turtleMeshDefinition = new ItemMeshDefinition()
{
private ModelResourceLocation turtle_dynamic = new ModelResourceLocation( "computercraft:turtle_dynamic", "inventory" );
@Nonnull
@Override
public ModelResourceLocation getModelLocation( @Nonnull ItemStack stack )
{
return turtle_dynamic;
}
};
String[] turtleModelNames = new String[] {
"turtle_dynamic",
"turtle", "turtle_advanced",
"turtle_white",
"turtle_elf_overlay"
};
registerItemModel( ComputerCraft.Blocks.turtle, turtleMeshDefinition, turtleModelNames );
registerItemModel( ComputerCraft.Blocks.turtleExpanded, turtleMeshDefinition, turtleModelNames );
registerItemModel( ComputerCraft.Blocks.turtleAdvanced, turtleMeshDefinition, turtleModelNames );
}
@Override
public void init()
{
super.init();
// Setup turtle colours
Minecraft.getMinecraft().getItemColors().registerItemColorHandler(
new TurtleItemColour(),
ComputerCraft.Blocks.turtle, ComputerCraft.Blocks.turtleExpanded, ComputerCraft.Blocks.turtleAdvanced
);
// Setup renderers
ClientRegistry.bindTileEntitySpecialRenderer( TileTurtle.class, new TileEntityTurtleRenderer() );
}
private void registerItemModel( Block block, ItemMeshDefinition definition, String[] names )
{
registerItemModel( Item.getItemFromBlock( block ), definition, names );
}
private void registerItemModel( Item item, ItemMeshDefinition definition, String[] names )
{
ResourceLocation[] resources = new ResourceLocation[names.length];
for( int i = 0; i < names.length; i++ )
{
resources[i] = new ResourceLocation( "computercraft:" + names[i] );
}
ModelBakery.registerItemVariants( item, resources );
ModelLoader.setCustomMeshDefinition( item, definition );
}
private void registerForgeHandlers()
{
ForgeHandlers handlers = new ForgeHandlers();
MinecraftForge.EVENT_BUS.register( handlers );
}
public static class ForgeHandlers
{
private static final String[] TURTLE_UPGRADES = {
"turtle_modem_off_left",
"turtle_modem_on_left",
"turtle_modem_off_right",
"turtle_modem_on_right",
"turtle_crafting_table_left",
"turtle_crafting_table_right",
"advanced_turtle_modem_off_left",
"advanced_turtle_modem_on_left",
"advanced_turtle_modem_off_right",
"advanced_turtle_modem_on_right",
"turtle_speaker_upgrade_left",
"turtle_speaker_upgrade_right",
};
private TurtleSmartItemModel m_turtleSmartItemModel;
public ForgeHandlers()
{
m_turtleSmartItemModel = new TurtleSmartItemModel();
IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager();
if( resourceManager instanceof SimpleReloadableResourceManager )
{
SimpleReloadableResourceManager reloadableResourceManager = (SimpleReloadableResourceManager) resourceManager;
reloadableResourceManager.registerReloadListener( m_turtleSmartItemModel );
}
}
@SubscribeEvent
public void onTextureStitchEvent( TextureStitchEvent.Pre event )
{
// Load all textures for upgrades
TextureMap map = event.getMap();
for( String upgrade : TURTLE_UPGRADES )
{
IModel model = ModelLoaderRegistry.getModelOrMissing( new ResourceLocation( "computercraft", "block/" + upgrade ) );
for( ResourceLocation texture : model.getTextures() )
{
map.registerSprite( texture );
}
}
}
@SubscribeEvent
public void onModelBakeEvent( ModelBakeEvent event )
{
// Load all upgrade models
for( String upgrade : TURTLE_UPGRADES )
{
loadModel( event, upgrade );
}
loadSmartModel( event, "turtle_dynamic", m_turtleSmartItemModel );
}
private void loadModel( ModelBakeEvent event, String name )
{
IModel model = ModelLoaderRegistry.getModelOrMissing(
new ResourceLocation( "computercraft", "block/" + name )
);
IBakedModel bakedModel = model.bake(
model.getDefaultState(),
DefaultVertexFormats.ITEM,
location -> Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( location.toString() )
);
event.getModelRegistry().putObject(
new ModelResourceLocation( "computercraft:" + name, "inventory" ),
bakedModel
);
}
private void loadSmartModel( ModelBakeEvent event, String name, IBakedModel smartModel )
{
event.getModelRegistry().putObject(
new ModelResourceLocation( "computercraft:" + name, "inventory" ),
smartModel
);
}
}
private static class TurtleItemColour implements IItemColor
{
@Override
public int colorMultiplier( @Nonnull ItemStack stack, int tintIndex )
{
if( tintIndex == 0 )
{
ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem();
int colour = turtle.getColour( stack );
if( colour != -1 ) return colour;
}
return 0xFFFFFF;
}
}
}

View File

@@ -7,41 +7,19 @@
package dan200.computercraft.client.proxy;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.ClientTableFormatter;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.render.*;
import dan200.computercraft.client.render.TileEntityCableRenderer;
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.shared.command.CommandCopy;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import dan200.computercraft.shared.util.Colour;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemMeshDefinition;
import net.minecraft.client.renderer.block.model.ModelBakery;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.color.IItemColor;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.client.ClientCommandHandler;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
import java.io.File;
public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{
@@ -50,143 +28,25 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{
super.preInit();
// Setup client forge handlers
registerForgeHandlers();
// Register any client-specific commands
ClientCommandHandler.instance.registerCommand( CommandCopy.INSTANCE );
}
@SubscribeEvent
public void registerModels( ModelRegistryEvent event )
{
// Register item models
registerItemModel( ComputerCraft.Blocks.computer, "computer" );
registerItemModel( ComputerCraft.Blocks.peripheral, 0, "peripheral" );
registerItemModel( ComputerCraft.Blocks.peripheral, 1, "wireless_modem" );
registerItemModel( ComputerCraft.Blocks.peripheral, 2, "monitor" );
registerItemModel( ComputerCraft.Blocks.peripheral, 3, "printer" );
registerItemModel( ComputerCraft.Blocks.peripheral, 4, "advanced_monitor" );
registerItemModel( ComputerCraft.Blocks.cable, 0, "cable" );
registerItemModel( ComputerCraft.Blocks.cable, 1, "wired_modem" );
registerItemModel( ComputerCraft.Blocks.commandComputer, "command_computer" );
registerItemModel( ComputerCraft.Blocks.advancedModem, "advanced_modem" );
registerItemModel( ComputerCraft.Blocks.peripheral, 5, "speaker" );
registerItemModel( ComputerCraft.Blocks.wiredModemFull, "wired_modem_full" );
registerItemModel( ComputerCraft.Items.disk, "disk" );
registerItemModel( ComputerCraft.Items.diskExpanded, "disk_expanded" );
registerItemModel( ComputerCraft.Items.treasureDisk, "treasure_disk" );
registerItemModel( ComputerCraft.Items.printout, 0, "printout" );
registerItemModel( ComputerCraft.Items.printout, 1, "pages" );
registerItemModel( ComputerCraft.Items.printout, 2, "book" );
registerItemModel( ComputerCraft.Items.pocketComputer, "pocket_computer" );
}
@Override
public void init()
{
super.init();
// Load textures
Minecraft mc = Minecraft.getMinecraft();
// Setup
mc.getItemColors().registerItemColorHandler( new DiskColorHandler( ComputerCraft.Items.disk ), ComputerCraft.Items.disk );
mc.getItemColors().registerItemColorHandler( new DiskColorHandler( ComputerCraft.Items.diskExpanded ), ComputerCraft.Items.diskExpanded );
mc.getItemColors().registerItemColorHandler( ( stack, layer ) ->
{
switch( layer )
{
case 0:
default:
return 0xFFFFFF;
case 1:
{
// Frame colour
int colour = ComputerCraft.Items.pocketComputer.getColour( stack );
return colour == -1 ? 0xFFFFFF : colour;
}
case 2:
{
// Light colour
int colour = ComputerCraft.Items.pocketComputer.getLightState( stack );
return colour == -1 ? Colour.Black.getHex() : colour;
}
}
}, ComputerCraft.Items.pocketComputer );
// Setup renderers
ClientRegistry.bindTileEntitySpecialRenderer( TileMonitor.class, new TileEntityMonitorRenderer() );
ClientRegistry.bindTileEntitySpecialRenderer( TileCable.class, new TileEntityCableRenderer() );
}
private void registerItemModel( Block block, int damage, String name )
{
registerItemModel( Item.getItemFromBlock( block ), damage, name );
}
private void registerItemModel( Item item, int damage, String name )
{
ModelResourceLocation res = new ModelResourceLocation( "computercraft:" + name, "inventory" );
ModelBakery.registerItemVariants( item, new ResourceLocation( "computercraft", name ) );
ModelLoader.setCustomModelResourceLocation( item, damage, res );
}
private void registerItemModel( Block block, String name )
{
registerItemModel( Item.getItemFromBlock( block ), name );
}
private void registerItemModel( Item item, String name )
{
final ModelResourceLocation res = new ModelResourceLocation( "computercraft:" + name, "inventory" );
ModelBakery.registerItemVariants( item, new ResourceLocation( "computercraft", name ) );
ModelLoader.setCustomMeshDefinition( item, new ItemMeshDefinition()
{
@Nonnull
@Override
public ModelResourceLocation getModelLocation( @Nonnull ItemStack stack )
{
return res;
}
} );
}
@Override
public File getWorldDir( World world )
{
return world.getSaveHandler().getWorldDirectory();
}
private void registerForgeHandlers()
{
MinecraftForge.EVENT_BUS.register( new ForgeHandlers() );
MinecraftForge.EVENT_BUS.register( new RenderOverlayCable() );
MinecraftForge.EVENT_BUS.register( new ItemPocketRenderer() );
MinecraftForge.EVENT_BUS.register( new ItemPrintoutRenderer() );
MinecraftForge.EVENT_BUS.register( FrameInfo.instance() );
}
@Override
public void playRecordClient( BlockPos pos, SoundEvent record, String info )
{
Minecraft mc = Minecraft.getMinecraft();
mc.world.playRecord( pos, record );
if( info != null ) mc.ingameGUI.setRecordPlayingMessage( info );
}
@Override
public void showTableClient( TableBuilder table )
{
ClientTableFormatter.INSTANCE.display( table );
}
public class ForgeHandlers
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
public static class ForgeHandlers
{
@SubscribeEvent
public void onWorldUnload( WorldEvent.Unload event )
public static void onWorldUnload( WorldEvent.Unload event )
{
if( event.getWorld().isRemote )
{
@@ -195,20 +55,5 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
}
}
@SideOnly( Side.CLIENT )
private static class DiskColorHandler implements IItemColor
{
private final ItemDiskLegacy disk;
private DiskColorHandler( ItemDiskLegacy disk )
{
this.disk = disk;
}
@Override
public int colorMultiplier( @Nonnull ItemStack stack, int layer )
{
return layer == 0 ? 0xFFFFFF : disk.getColour( stack );
}
}
}

View File

@@ -24,9 +24,9 @@ import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.item.ItemStack;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.opengl.GL11;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
@@ -35,17 +35,23 @@ import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
/**
* Emulates map rendering for pocket computers
*/
@SideOnly( Side.CLIENT )
public class ItemPocketRenderer extends ItemMapLikeRenderer
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
public final class ItemPocketRenderer extends ItemMapLikeRenderer
{
private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
private ItemPocketRenderer()
{
}
@SubscribeEvent
public void renderItem( RenderSpecificHandEvent event )
public static void renderItem( RenderSpecificHandEvent event )
{
ItemStack stack = event.getItemStack();
if( !(stack.getItem() instanceof ItemPocketComputer) ) return;
event.setCanceled( true );
renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() );
INSTANCE.renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() );
}
@Override
@@ -145,7 +151,7 @@ public class ItemPocketRenderer extends ItemMapLikeRenderer
// And render the cursor;
int tx = terminal.getCursorX(), ty = terminal.getCursorY();
if( terminal.getCursorBlink() && FrameInfo.instance().getGlobalCursorBlink() &&
if( terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink() &&
tx >= 0 && ty >= 0 && tx < tw && ty < th )
{
TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 );

View File

@@ -12,7 +12,9 @@ import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.item.ItemStack;
import net.minecraftforge.client.event.RenderItemInFrameEvent;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
@@ -20,17 +22,27 @@ 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 extends ItemMapLikeRenderer
/**
* Emulates map and item-frame rendering for prinouts
*/
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
{
private static final ItemPrintoutRenderer INSTANCE = new ItemPrintoutRenderer();
private ItemPrintoutRenderer()
{
}
@SubscribeEvent
public void onRenderInHand( RenderSpecificHandEvent event )
public static void onRenderInHand( RenderSpecificHandEvent event )
{
ItemStack stack = event.getItemStack();
if( stack.getItem() != ComputerCraft.Items.printout ) return;
event.setCanceled( true );
renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() );
INSTANCE.renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() );
}
@Override
@@ -51,7 +63,7 @@ public class ItemPrintoutRenderer extends ItemMapLikeRenderer
}
@SubscribeEvent
public void onRenderInFrame( RenderItemInFrameEvent event )
public static void onRenderInFrame( RenderItemInFrameEvent event )
{
ItemStack stack = event.getItem();
if( stack.getItem() != ComputerCraft.Items.printout ) return;
@@ -69,6 +81,7 @@ public class ItemPrintoutRenderer extends ItemMapLikeRenderer
drawPrintout( stack );
GlStateManager.enableLighting();
GlStateManager.disableBlend();
}
private static void drawPrintout( ItemStack stack )

View File

@@ -23,17 +23,24 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import org.lwjgl.opengl.GL11;
public class RenderOverlayCable
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
public final class RenderOverlayCable
{
private static final float EXPAND = 0.002f;
private static final double MIN = CableBounds.MIN - EXPAND;
private static final double MAX = CableBounds.MAX + EXPAND;
private RenderOverlayCable()
{
}
@SubscribeEvent
public void drawHighlight( DrawBlockHighlightEvent event )
public static void drawHighlight( DrawBlockHighlightEvent event )
{
if( event.getTarget().typeOfHit != RayTraceResult.Type.BLOCK ) return;

View File

@@ -49,7 +49,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
// 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 = FrameInfo.instance().getRenderFrame();
long renderFrame = FrameInfo.getRenderFrame();
if( originTerminal.lastRenderFrame == renderFrame && !monitorPos.equals( originTerminal.lastRenderPos ) )
{
return;
@@ -230,7 +230,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
GlStateManager.glEndList();
}
}
if( FrameInfo.instance().getGlobalCursorBlink() )
if( FrameInfo.getGlobalCursorBlink() )
{
GlStateManager.callList( originTerminal.renderDisplayLists[2] );
GlStateManager.resetColor();

View File

@@ -14,23 +14,20 @@ import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ModelManager;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.model.pipeline.LightUtil;
@@ -65,7 +62,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
}
}
public static ModelResourceLocation getTurtleOverlayModel( ComputerFamily family, ResourceLocation overlay, boolean christmas )
public static ModelResourceLocation getTurtleOverlayModel( ResourceLocation overlay, boolean christmas )
{
if( overlay != null )
{
@@ -83,6 +80,19 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
private void renderTurtleAt( TileTurtle turtle, double posX, double posY, double posZ, float f, int i )
{
// Render the label
String label = turtle.createProxy().getLabel();
if( label != null && rendererDispatcher.cameraHitResult != null && turtle.getPos().equals( rendererDispatcher.cameraHitResult.getBlockPos() ) )
{
setLightmapDisabled( true );
EntityRenderer.drawNameplate(
getFontRenderer(), label,
(float) posX + 0.5F, (float) posY + 1.2F, (float) posZ + 0.5F, 0,
rendererDispatcher.entityYaw, rendererDispatcher.entityPitch, false, false
);
setLightmapDisabled( false );
}
IBlockState state = turtle.getWorld().getBlockState( turtle.getPos() );
GlStateManager.pushMatrix();
try
@@ -94,13 +104,6 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
yaw = turtle.getRenderYaw( f );
GlStateManager.translate( posX + offset.x, posY + offset.y, posZ + offset.z );
// Render the label
String label = turtle.createProxy().getLabel();
if( label != null )
{
renderLabel( turtle.getAccess().getPosition(), label );
}
// Render the turtle
GlStateManager.translate( 0.5f, 0.5f, 0.5f );
GlStateManager.rotate( 180.0f - yaw, 0.0f, 1.0f, 0.0f );
@@ -123,7 +126,6 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
// Render the overlay
ModelResourceLocation overlayModel = getTurtleOverlayModel(
family,
overlay,
HolidayUtil.getCurrentHoliday() == Holiday.Christmas
);
@@ -232,72 +234,4 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
}
tessellator.draw();
}
private void renderLabel( BlockPos position, String label )
{
Minecraft mc = Minecraft.getMinecraft();
RayTraceResult mop = mc.objectMouseOver;
if( mop != null && mop.typeOfHit == RayTraceResult.Type.BLOCK && mop.getBlockPos().equals( position ) )
{
RenderManager renderManager = mc.getRenderManager();
FontRenderer fontrenderer = renderManager.getFontRenderer();
float scale = 0.016666668F * 1.6f;
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.blendFunc( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA );
try
{
GlStateManager.translate( 0.5f, 1.25f, 0.5f );
GlStateManager.rotate( -renderManager.playerViewY, 0.0F, 1.0F, 0.0F );
GlStateManager.rotate( renderManager.playerViewX, 1.0F, 0.0F, 0.0F );
GlStateManager.scale( -scale, -scale, scale );
int yOffset = 0;
int xOffset = fontrenderer.getStringWidth( label ) / 2;
// Draw background
GlStateManager.depthMask( false );
GlStateManager.disableDepth();
try
{
// Quad
GlStateManager.disableTexture2D();
try
{
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder renderer = tessellator.getBuffer();
renderer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR );
renderer.pos( -xOffset - 1, -1 + yOffset, 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex();
renderer.pos( -xOffset - 1, 8 + yOffset, 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex();
renderer.pos( xOffset + 1, 8 + yOffset, 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex();
renderer.pos( xOffset + 1, -1 + yOffset, 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex();
tessellator.draw();
}
finally
{
GlStateManager.enableTexture2D();
}
// Text
fontrenderer.drawString( label, -fontrenderer.getStringWidth( label ) / 2, yOffset, 0x20ffffff );
}
finally
{
GlStateManager.enableDepth();
GlStateManager.depthMask( true );
}
// Draw foreground text
fontrenderer.drawString( label, -fontrenderer.getStringWidth( label ) / 2, yOffset, -1 );
}
finally
{
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
}
}
}

View File

@@ -0,0 +1,121 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.render;
import com.google.common.collect.ImmutableMap;
import dan200.computercraft.ComputerCraft;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ICustomModelLoader;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.common.model.IModelState;
import javax.annotation.Nonnull;
import java.util.function.Function;
public class TurtleModelLoader implements ICustomModelLoader
{
private static final ResourceLocation NORMAL_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle" );
private static final ResourceLocation ADVANCED_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/advanced_turtle" );
private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_white" );
public static final TurtleModelLoader INSTANCE = new TurtleModelLoader();
private TurtleModelLoader()
{
}
@Override
public void onResourceManagerReload( @Nonnull IResourceManager manager )
{
}
@Override
public boolean accepts( @Nonnull ResourceLocation name )
{
return name.getNamespace().equals( ComputerCraft.MOD_ID )
&& (name.getPath().equals( "turtle" ) || name.getPath().equals( "turtle_advanced" ));
}
@Nonnull
@Override
public IModel loadModel( @Nonnull ResourceLocation name ) throws Exception
{
if( name.getNamespace().equals( ComputerCraft.MOD_ID ) )
{
IModel colourModel = ModelLoaderRegistry.getModel( COLOUR_TURTLE_MODEL );
switch( name.getPath() )
{
case "turtle":
return new TurtleModel( ModelLoaderRegistry.getModel( NORMAL_TURTLE_MODEL ), colourModel );
case "turtle_advanced":
return new TurtleModel( ModelLoaderRegistry.getModel( ADVANCED_TURTLE_MODEL ), colourModel );
}
}
throw new IllegalStateException( "Loader does not accept " + name );
}
private static class TurtleModel implements IModel
{
private final IModel family;
private final IModel colour;
private TurtleModel( IModel family, IModel colour )
{
this.family = family;
this.colour = colour;
}
@Nonnull
@Override
public IBakedModel bake( @Nonnull IModelState state, @Nonnull VertexFormat format, @Nonnull Function<ResourceLocation, TextureAtlasSprite> function )
{
return new TurtleSmartItemModel(
family.bake( state, format, function ),
colour.bake( state, format, function )
);
}
private TurtleModel copy( IModel family, IModel colour )
{
return this.family == family && this.colour == colour ? this : new TurtleModel( family, colour );
}
@Nonnull
@Override
public IModel smoothLighting( boolean value )
{
return copy( family.smoothLighting( value ), colour.smoothLighting( value ) );
}
@Nonnull
@Override
public IModel gui3d( boolean value )
{
return copy( family.gui3d( value ), colour.gui3d( value ) );
}
@Nonnull
@Override
public IModel uvlock( boolean value )
{
return copy( family.uvlock( value ), colour.uvlock( value ) );
}
@Nonnull
@Override
public IModel retexture( ImmutableMap<String, String> textures )
{
return copy( family.retexture( textures ), colour.retexture( textures ) );
}
}
}

View File

@@ -9,7 +9,6 @@ package dan200.computercraft.client.render;
import com.google.common.base.Objects;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.turtle.items.ItemTurtleBase;
import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil;
@@ -17,15 +16,11 @@ import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.*;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.client.resource.IResourceType;
import net.minecraftforge.client.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.client.resource.VanillaResourceType;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
@@ -34,9 +29,8 @@ import javax.vecmath.Matrix4f;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Predicate;
public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceReloadListener
public class TurtleSmartItemModel implements IBakedModel
{
private static final Matrix4f s_identity, s_flip;
@@ -53,17 +47,15 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
private static class TurtleModelCombination
{
public final ComputerFamily m_family;
public final boolean m_colour;
public final ITurtleUpgrade m_leftUpgrade;
public final ITurtleUpgrade m_rightUpgrade;
public final ResourceLocation m_overlay;
public final boolean m_christmas;
public final boolean m_flip;
final boolean m_colour;
final ITurtleUpgrade m_leftUpgrade;
final ITurtleUpgrade m_rightUpgrade;
final ResourceLocation m_overlay;
final boolean m_christmas;
final boolean m_flip;
public TurtleModelCombination( ComputerFamily family, boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas, boolean flip )
TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas, boolean flip )
{
m_family = family;
m_colour = colour;
m_leftUpgrade = leftUpgrade;
m_rightUpgrade = rightUpgrade;
@@ -79,8 +71,7 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
if( !(other instanceof TurtleModelCombination) ) return false;
TurtleModelCombination otherCombo = (TurtleModelCombination) other;
return otherCombo.m_family == m_family &&
otherCombo.m_colour == m_colour &&
return otherCombo.m_colour == m_colour &&
otherCombo.m_leftUpgrade == m_leftUpgrade &&
otherCombo.m_rightUpgrade == m_rightUpgrade &&
Objects.equal( otherCombo.m_overlay, m_overlay ) &&
@@ -92,8 +83,7 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + m_family.hashCode();
int result = 0;
result = prime * result + (m_colour ? 1 : 0);
result = prime * result + (m_leftUpgrade != null ? m_leftUpgrade.hashCode() : 0);
result = prime * result + (m_rightUpgrade != null ? m_rightUpgrade.hashCode() : 0);
@@ -104,14 +94,18 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
}
}
private final IBakedModel familyModel;
private final IBakedModel colourModel;
private HashMap<TurtleModelCombination, IBakedModel> m_cachedModels;
private ItemOverrideList m_overrides;
private final TurtleModelCombination m_defaultCombination;
public TurtleSmartItemModel()
public TurtleSmartItemModel( IBakedModel familyModel, IBakedModel colourModel )
{
this.familyModel = familyModel;
this.colourModel = colourModel;
m_cachedModels = new HashMap<>();
m_defaultCombination = new TurtleModelCombination( ComputerFamily.Normal, false, null, null, null, false, false );
m_overrides = new ItemOverrideList( new ArrayList<>() )
{
@Nonnull
@@ -119,7 +113,6 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
public IBakedModel handleItemState( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity )
{
ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem();
ComputerFamily family = turtle.getFamily( stack );
int colour = turtle.getColour( stack );
ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.Left );
ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.Right );
@@ -127,17 +120,11 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.Christmas;
String label = turtle.getLabel( stack );
boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" ));
TurtleModelCombination combo = new TurtleModelCombination( family, colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
if( m_cachedModels.containsKey( combo ) )
{
return m_cachedModels.get( combo );
}
else
{
IBakedModel model = buildModel( combo );
m_cachedModels.put( combo, model );
return model;
}
TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
IBakedModel model = m_cachedModels.get( combo );
if( model == null ) m_cachedModels.put( combo, model = buildModel( combo ) );
return model;
}
};
}
@@ -149,19 +136,13 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
return m_overrides;
}
@Override
public void onResourceManagerReload( @Nonnull IResourceManager resourceManager, @Nonnull Predicate<IResourceType> resourcePredicate )
{
if( resourcePredicate.test( VanillaResourceType.MODELS ) ) m_cachedModels.clear();
}
private IBakedModel buildModel( TurtleModelCombination combo )
{
Minecraft mc = Minecraft.getMinecraft();
ModelManager modelManager = mc.getRenderItem().getItemModelMesher().getModelManager();
ModelResourceLocation baseModelLocation = TileEntityTurtleRenderer.getTurtleModel( combo.m_family, combo.m_colour );
ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.m_family, combo.m_overlay, combo.m_christmas );
IBakedModel baseModel = modelManager.getModel( baseModelLocation );
ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.m_overlay, combo.m_christmas );
IBakedModel baseModel = combo.m_colour ? colourModel : familyModel;
IBakedModel overlayModel = (overlayModelLocation != null) ? modelManager.getModel( overlayModelLocation ) : null;
Matrix4f transform = combo.m_flip ? s_flip : s_identity;
Pair<IBakedModel, Matrix4f> leftModel = (combo.m_leftUpgrade != null) ? combo.m_leftUpgrade.getModel( null, TurtleSide.Left ) : null;
@@ -184,38 +165,36 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
}
}
// These should not be called:
@Nonnull
@Override
public List<BakedQuad> getQuads( IBlockState state, EnumFacing facing, long rand )
{
return getDefaultModel().getQuads( state, facing, rand );
return familyModel.getQuads( state, facing, rand );
}
@Override
public boolean isAmbientOcclusion()
{
return getDefaultModel().isAmbientOcclusion();
return familyModel.isAmbientOcclusion();
}
@Override
public boolean isGui3d()
{
return getDefaultModel().isGui3d();
return familyModel.isGui3d();
}
@Override
public boolean isBuiltInRenderer()
{
return getDefaultModel().isBuiltInRenderer();
return familyModel.isBuiltInRenderer();
}
@Nonnull
@Override
public TextureAtlasSprite getParticleTexture()
{
return getDefaultModel().getParticleTexture();
return familyModel.getParticleTexture();
}
@Nonnull
@@ -223,18 +202,7 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
@Deprecated
public ItemCameraTransforms getItemCameraTransforms()
{
return getDefaultModel().getItemCameraTransforms();
return familyModel.getItemCameraTransforms();
}
private IBakedModel getDefaultModel()
{
IBakedModel model = m_cachedModels.get( m_defaultCombination );
if( model == null )
{
model = buildModel( m_defaultCombination );
m_cachedModels.put( m_defaultCombination, model );
}
return model;
}
}

View File

@@ -14,20 +14,32 @@ import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.tracking.TrackingField;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface IAPIEnvironment extends IComputerOwned
{
String[] SIDE_NAMES = new String[] {
"bottom", "top", "back", "front", "right", "left",
};
int SIDE_COUNT = 6;
interface IPeripheralChangeListener
{
void onPeripheralChanged( int side, IPeripheral newPeripheral );
void onPeripheralChanged( int side, @Nullable IPeripheral newPeripheral );
}
@Nonnull
@Override
Computer getComputer();
int getComputerID();
@Nonnull
IComputerEnvironment getComputerEnvironment();
@Nonnull
Terminal getTerminal();
FileSystem getFileSystem();
@@ -50,17 +62,18 @@ public interface IAPIEnvironment extends IComputerOwned
int getBundledInput( int side );
void setPeripheralChangeListener( IPeripheralChangeListener listener );
void setPeripheralChangeListener( @Nullable IPeripheralChangeListener listener );
@Nullable
IPeripheral getPeripheral( int side );
String getLabel();
void setLabel( String label );
void setLabel( @Nullable String label );
void addTrackingChange( TrackingField field, long change );
void addTrackingChange( @Nonnull TrackingField field, long change );
default void addTrackingChange( TrackingField field )
default void addTrackingChange( @Nonnull TrackingField field )
{
addTrackingChange( field, 1 );
}

View File

@@ -16,6 +16,7 @@ public interface ILuaAPI extends dan200.computercraft.api.lua.ILuaAPI
{
void advance( double v );
@Override
default void update()
{
advance( 0.05 );

View File

@@ -278,13 +278,13 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
}, null );
// Queue a detachment event
m_environment.queueEvent( "peripheral_detach", new Object[] { Computer.s_sideNames[side] } );
m_environment.queueEvent( "peripheral_detach", new Object[] { IAPIEnvironment.SIDE_NAMES[side] } );
}
// Assign the new peripheral
if( newPeripheral != null )
{
m_peripherals[side] = new PeripheralWrapper( newPeripheral, Computer.s_sideNames[side] );
m_peripherals[side] = new PeripheralWrapper( newPeripheral, IAPIEnvironment.SIDE_NAMES[side] );
}
else
{
@@ -317,7 +317,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
}, null );
// Queue an attachment event
m_environment.queueEvent( "peripheral", new Object[] { Computer.s_sideNames[side] } );
m_environment.queueEvent( "peripheral", new Object[] { IAPIEnvironment.SIDE_NAMES[side] } );
}
}
}
@@ -483,9 +483,9 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
private int parseSide( Object[] args ) throws LuaException
{
String side = getString( args, 0 );
for( int n = 0; n < Computer.s_sideNames.length; n++ )
for( int n = 0; n < IAPIEnvironment.SIDE_NAMES.length; n++ )
{
if( side.equals( Computer.s_sideNames[n] ) )
if( side.equals( IAPIEnvironment.SIDE_NAMES[n] ) )
{
return n;
}

View File

@@ -9,7 +9,6 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.computer.Computer;
import javax.annotation.Nonnull;
import java.util.HashMap;
@@ -65,9 +64,9 @@ public class RedstoneAPI implements ILuaAPI
{
// getSides
Map<Object, Object> table = new HashMap<>();
for( int i = 0; i < Computer.s_sideNames.length; i++ )
for( int i = 0; i < IAPIEnvironment.SIDE_NAMES.length; i++ )
{
table.put( i + 1, Computer.s_sideNames[i] );
table.put( i + 1, IAPIEnvironment.SIDE_NAMES[i] );
}
return new Object[] { table };
}
@@ -156,9 +155,9 @@ public class RedstoneAPI implements ILuaAPI
private int parseSide( Object[] args ) throws LuaException
{
String side = getString( args, 0 );
for( int n = 0; n < Computer.s_sideNames.length; n++ )
for( int n = 0; n < IAPIEnvironment.SIDE_NAMES.length; n++ )
{
if( side.equals( Computer.s_sideNames[n] ) )
if( side.equals( IAPIEnvironment.SIDE_NAMES[n] ) )
{
return n;
}

View File

@@ -11,6 +11,7 @@ import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette;
import org.apache.commons.lang3.ArrayUtils;
@@ -65,6 +66,8 @@ public class TermAPI implements ILuaAPI
"setPaletteColor",
"getPaletteColour",
"getPaletteColor",
"nativePaletteColour",
"nativePaletteColor",
"getCursorBlink",
};
}
@@ -289,6 +292,19 @@ public class TermAPI implements ILuaAPI
return null;
}
case 23:
case 24:
{
// nativePaletteColour/nativePaletteColor
int colour = 15 - parseColour( args );
Colour c = Colour.fromInt( colour );
float[] rgb = c.getRGB();
Object[] rgbObj = new Object[rgb.length];
for( int i = 0; i < rgbObj.length; ++i ) rgbObj[i] = rgb[i];
return rgbObj;
}
case 25:
// getCursorBlink
return new Object[] { m_terminal.getCursorBlink() };
default:

View File

@@ -169,27 +169,42 @@ public class BinaryReadableHandle extends HandleGeneric
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
boolean readAnything = false;
boolean readAnything = false, readRc = false;
while( true )
{
single.clear();
int r = m_reader.read( single );
if( r == -1 ) break;
int read = m_reader.read( single );
if( read <= 0 )
{
// Nothing else to read, and we saw no \n. Return the array. If we saw a \r, then add it
// back.
if( readRc ) stream.write( '\r' );
return readAnything ? new Object[] { stream.toByteArray() } : null;
}
readAnything = true;
byte b = single.get( 0 );
if( b == '\n' )
byte chr = single.get( 0 );
if( chr == '\n' )
{
if( withTrailing ) stream.write( b );
break;
if( withTrailing )
{
if( readRc ) stream.write( '\r' );
stream.write( chr );
}
return new Object[] { stream.toByteArray() };
}
else
{
stream.write( b );
// We want to skip \r\n, but obviously need to include cases where \r is not followed by \n.
// Note, this behaviour is non-standard compliant (strictly speaking we should have no
// special logic for \r), but we preserve compatibility with EncodedReadableHandle and
// previous behaviour of the io library.
if( readRc ) stream.write( '\r' );
readRc = chr == '\r';
if( !readRc ) stream.write( chr );
}
}
return readAnything ? new Object[] { stream.toByteArray() } : null;
}
catch( IOException e )
{

View File

@@ -26,12 +26,14 @@ public class ResourceQueue<T extends Resource<T>> extends ResourceGroup<T>
{
}
@Override
public synchronized void shutdown()
{
super.shutdown();
pending.clear();
}
@Override
public synchronized boolean queue( Supplier<T> resource )
{
if( !active ) return false;
@@ -40,6 +42,7 @@ public class ResourceQueue<T extends Resource<T>> extends ResourceGroup<T>
return true;
}
@Override
public synchronized void release( T resource )
{
super.release( resource );

View File

@@ -239,6 +239,7 @@ public class HttpRequest extends Resource<HttpRequest>
if( tryClose() ) environment.queueEvent( SUCCESS_EVENT, new Object[] { address, object } );
}
@Override
protected void dispose()
{
super.dispose();

View File

@@ -161,7 +161,10 @@ public class Websocket extends Resource<Websocket>
}
} )
.remoteAddress( socketAddress )
.connect();
.connect()
.addListener( c -> {
if( !c.isSuccess() ) failure( c.cause().getMessage() );
} );
// Do an additional check for cancellation
checkClosed();

View File

@@ -83,6 +83,11 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object>
CloseWebSocketFrame closeFrame = (CloseWebSocketFrame) frame;
websocket.close( closeFrame.statusCode(), closeFrame.reasonText() );
}
else if( frame instanceof PingWebSocketFrame )
{
frame.content().retain();
ctx.channel().writeAndFlush( new PongWebSocketFrame( frame.content() ) );
}
}
@Override
@@ -108,6 +113,13 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object>
message = "Could not connect";
}
websocket.failure( message );
if( handshaker.isHandshakeComplete() )
{
websocket.close( -1, message );
}
else
{
websocket.failure( message );
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.computer;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A wrapper for {@link ILuaAPI}s which cleans up after a {@link ComputerSystem} when the computer is shutdown.
*/
public class ApiWrapper implements ILuaAPI
{
private final ILuaAPI delegate;
private final ComputerSystem system;
ApiWrapper( ILuaAPI delegate, ComputerSystem system )
{
this.delegate = delegate;
this.system = system;
}
@Override
public String[] getNames()
{
return delegate.getNames();
}
@Override
public void startup()
{
delegate.startup();
}
@Override
public void update()
{
delegate.update();
}
@Override
public void shutdown()
{
delegate.shutdown();
system.unmountAll();
}
@Nonnull
@Override
public String[] getMethodNames()
{
return delegate.getMethodNames();
}
@Nullable
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return delegate.callMethod( context, method, arguments );
}
}

View File

@@ -8,11 +8,10 @@ package dan200.computercraft.core.computer;
import com.google.common.base.Objects;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.filesystem.IFileSystem;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.*;
import dan200.computercraft.core.filesystem.FileSystem;
@@ -20,11 +19,7 @@ import dan200.computercraft.core.filesystem.FileSystemException;
import dan200.computercraft.core.lua.CobaltLuaMachine;
import dan200.computercraft.core.lua.ILuaMachine;
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.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -32,10 +27,6 @@ import java.util.List;
public class Computer
{
public static final String[] s_sideNames = new String[] {
"bottom", "top", "back", "front", "right", "left",
};
private enum State
{
Off,
@@ -44,319 +35,81 @@ public class Computer
Stopping,
}
private static class APIEnvironment implements IAPIEnvironment
{
private Computer m_computer;
private IAPIEnvironment.IPeripheralChangeListener m_peripheralListener;
public APIEnvironment( Computer computer )
{
m_computer = computer;
m_peripheralListener = null;
}
@Override
public Computer getComputer()
{
return m_computer;
}
@Override
public int getComputerID()
{
return m_computer.assignID();
}
@Override
public IComputerEnvironment getComputerEnvironment()
{
return m_computer.m_environment;
}
@Override
public Terminal getTerminal()
{
return m_computer.m_terminal;
}
@Override
public FileSystem getFileSystem()
{
return m_computer.m_fileSystem;
}
@Override
public void shutdown()
{
m_computer.shutdown();
}
@Override
public void reboot()
{
m_computer.reboot();
}
@Override
public void queueEvent( String event, Object[] args )
{
m_computer.queueEvent( event, args );
}
@Override
public void setOutput( int side, int output )
{
m_computer.setRedstoneOutput( side, output );
}
@Override
public int getOutput( int side )
{
return m_computer.getInternalRedstoneOutput( side );
}
@Override
public int getInput( int side )
{
return m_computer.getRedstoneInput( side );
}
@Override
public void setBundledOutput( int side, int output )
{
m_computer.setBundledRedstoneOutput( side, output );
}
@Override
public int getBundledOutput( int side )
{
return m_computer.getInternalBundledRedstoneOutput( side );
}
@Override
public int getBundledInput( int side )
{
return m_computer.getBundledRedstoneInput( side );
}
@Override
public IPeripheral getPeripheral( int side )
{
synchronized( m_computer.m_peripherals )
{
return m_computer.m_peripherals[side];
}
}
@Override
public void setPeripheralChangeListener( IPeripheralChangeListener listener )
{
synchronized( m_computer.m_peripherals )
{
m_peripheralListener = listener;
}
}
@Override
public String getLabel()
{
return m_computer.getLabel();
}
@Override
public void setLabel( String 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 )
{
synchronized( m_computer.m_peripherals )
{
if( m_peripheralListener != null )
{
m_peripheralListener.onPeripheralChanged( side, peripheral );
}
}
}
}
private static class ComputerSystem extends ComputerAccess implements IComputerSystem
{
private final IAPIEnvironment m_environment;
private ComputerSystem( IAPIEnvironment m_environment )
{
super( m_environment );
this.m_environment = m_environment;
}
@Nonnull
@Override
public String getAttachmentName()
{
return "computer";
}
@Nullable
@Override
public IFileSystem getFileSystem()
{
FileSystem fs = m_environment.getFileSystem();
return fs == null ? null : fs.getMountWrapper();
}
@Nullable
@Override
public String getLabel()
{
return m_environment.getLabel();
}
}
private static class APIWrapper implements ILuaAPI
{
private final ILuaAPI delegate;
private final ComputerSystem system;
private APIWrapper( ILuaAPI delegate, ComputerSystem system )
{
this.delegate = delegate;
this.system = system;
}
@Override
public String[] getNames()
{
return delegate.getNames();
}
@Override
public void startup()
{
delegate.startup();
}
@Override
public void update()
{
delegate.update();
}
@Override
public void shutdown()
{
delegate.shutdown();
system.unmountAll();
}
@Nonnull
@Override
public String[] getMethodNames()
{
return delegate.getMethodNames();
}
@Nullable
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return delegate.callMethod( context, method, arguments );
}
}
private static IMount s_romMount = null;
private int m_id;
private String m_label;
private String m_label = null;
private final IComputerEnvironment m_environment;
private int m_ticksSinceStart;
private boolean m_startRequested;
private State m_state;
private boolean m_blinking;
private int m_ticksSinceStart = -1;
private boolean m_startRequested = false;
private State m_state = State.Off;
private boolean m_blinking = false;
private ILuaMachine m_machine;
private final List<ILuaAPI> m_apis;
private final APIEnvironment m_apiEnvironment;
private ILuaMachine m_machine = null;
private final List<ILuaAPI> m_apis = new ArrayList<>();
private final Environment m_internalEnvironment = new Environment( this );
private final Terminal m_terminal;
private FileSystem m_fileSystem;
private IWritableMount m_rootMount;
private FileSystem m_fileSystem = null;
private IWritableMount m_rootMount = null;
private final int[] m_internalOutput;
private final int[] m_internalBundledOutput;
private boolean m_internalOutputChanged;
private final int[] m_externalOutput;
private final int[] m_externalBundledOutput;
private boolean m_externalOutputChanged;
private final int[] m_input;
private final int[] m_bundledInput;
private boolean m_inputChanged;
private final IPeripheral[] m_peripherals;
public Computer( IComputerEnvironment environment, Terminal terminal, int id )
{
m_id = id;
m_environment = environment;
m_terminal = terminal;
// Ensure the computer thread is running as required.
ComputerThread.start();
m_id = id;
m_label = null;
m_environment = environment;
// Add all default APIs to the loaded list.
m_apis.add( new TermAPI( m_internalEnvironment ) );
m_apis.add( new RedstoneAPI( m_internalEnvironment ) );
m_apis.add( new FSAPI( m_internalEnvironment ) );
m_apis.add( new PeripheralAPI( m_internalEnvironment ) );
m_apis.add( new OSAPI( m_internalEnvironment ) );
if( ComputerCraft.http_enable ) m_apis.add( new HTTPAPI( m_internalEnvironment ) );
m_ticksSinceStart = -1;
m_startRequested = false;
m_state = State.Off;
m_blinking = false;
m_terminal = terminal;
m_fileSystem = null;
m_machine = null;
m_apis = new ArrayList<>();
m_apiEnvironment = new APIEnvironment( this );
m_internalOutput = new int[6];
m_internalBundledOutput = new int[6];
m_internalOutputChanged = true;
m_externalOutput = new int[6];
m_externalBundledOutput = new int[6];
m_externalOutputChanged = true;
m_input = new int[6];
m_bundledInput = new int[6];
m_inputChanged = false;
m_peripherals = new IPeripheral[6];
for( int i = 0; i < 6; i++ )
// Load in the API registered APIs.
for( ILuaAPIFactory factory : ApiFactories.getAll() )
{
m_peripherals[i] = null;
ComputerSystem system = new ComputerSystem( m_internalEnvironment );
ILuaAPI api = factory.create( system );
if( api != null ) m_apis.add( new ApiWrapper( api, system ) );
}
}
m_rootMount = null;
createAPIs();
IComputerEnvironment getComputerEnvironment()
{
return m_environment;
}
FileSystem getFileSystem()
{
return m_fileSystem;
}
Terminal getTerminal()
{
return m_terminal;
}
public Environment getEnvironment()
{
return m_internalEnvironment;
}
public IAPIEnvironment getAPIEnvironment()
{
return m_apiEnvironment;
return m_internalEnvironment;
}
public void turnOn()
{
if( m_state == State.Off )
{
m_startRequested = true;
}
if( m_state == State.Off ) m_startRequested = true;
}
public void shutdown()
@@ -397,10 +150,7 @@ public class Computer
public void unload()
{
synchronized( this )
{
stopComputer( false );
}
stopComputer( false );
}
public int getID()
@@ -436,7 +186,7 @@ public class Computer
}
}
public void advance( double _dt )
public void advance()
{
synchronized( this )
{
@@ -453,67 +203,27 @@ public class Computer
if( m_state == State.Running )
{
// Fire the redstone event if our redstone input has changed
synchronized( m_input )
{
if( m_inputChanged )
{
queueEvent( "redstone", null );
m_inputChanged = false;
}
}
// Update the environment's internal state.
m_internalEnvironment.update();
// Advance our APIs
synchronized( m_apis )
{
for( ILuaAPI api : m_apis )
{
api.update();
}
}
for( ILuaAPI api : m_apis ) api.update();
}
}
// Set outputchanged if the internal redstone has changed
synchronized( m_internalOutput )
{
if( m_internalOutputChanged )
{
boolean changed = false;
for( int i = 0; i < 6; i++ )
{
if( m_externalOutput[i] != m_internalOutput[i] )
{
m_externalOutput[i] = m_internalOutput[i];
changed = true;
}
if( m_externalBundledOutput[i] != m_internalBundledOutput[i] )
{
m_externalBundledOutput[i] = m_internalBundledOutput[i];
changed = true;
}
}
m_internalOutputChanged = false;
if( changed )
{
m_externalOutputChanged = true;
}
}
}
// Prepare to propagate the environment's output to the world.
if( m_internalEnvironment.updateOutput() ) m_externalOutputChanged = true;
// Set outputchanged if the terminal has changed from blinking to not
synchronized( m_terminal )
{
boolean blinking =
m_terminal.getCursorBlink() &&
m_terminal.getCursorX() >= 0 && m_terminal.getCursorX() < m_terminal.getWidth() &&
m_terminal.getCursorY() >= 0 && m_terminal.getCursorY() < m_terminal.getHeight();
// Set output changed if the terminal has changed from blinking to not
boolean blinking =
m_terminal.getCursorBlink() &&
m_terminal.getCursorX() >= 0 && m_terminal.getCursorX() < m_terminal.getWidth() &&
m_terminal.getCursorY() >= 0 && m_terminal.getCursorY() < m_terminal.getHeight();
if( blinking != m_blinking )
{
m_blinking = blinking;
m_externalOutputChanged = true;
}
if( blinking != m_blinking )
{
m_blinking = blinking;
m_externalOutputChanged = true;
}
}
@@ -529,10 +239,7 @@ public class Computer
public boolean isBlinking()
{
synchronized( m_terminal )
{
return isOn() && m_blinking;
}
return isOn() && m_blinking;
}
public IWritableMount getRootMount()
@@ -553,10 +260,7 @@ public class Computer
try
{
m_fileSystem = new FileSystem( "hdd", getRootMount() );
if( s_romMount == null )
{
s_romMount = m_environment.createResourceMount( "computercraft", "lua/rom" );
}
if( s_romMount == null ) s_romMount = m_environment.createResourceMount( "computercraft", "lua/rom" );
if( s_romMount != null )
{
m_fileSystem.mount( "rom", "rom", s_romMount );
@@ -571,104 +275,6 @@ public class Computer
}
}
// Redstone
public int getRedstoneOutput( int side )
{
synchronized( m_internalOutput )
{
return isOn() ? m_externalOutput[side] : 0;
}
}
private int getInternalRedstoneOutput( int side )
{
synchronized( m_internalOutput )
{
return isOn() ? m_internalOutput[side] : 0;
}
}
private void setRedstoneOutput( int side, int level )
{
synchronized( m_internalOutput )
{
if( m_internalOutput[side] != level )
{
m_internalOutput[side] = level;
m_internalOutputChanged = true;
}
}
}
public void setRedstoneInput( int side, int level )
{
synchronized( m_input )
{
if( m_input[side] != level )
{
m_input[side] = level;
m_inputChanged = true;
}
}
}
private int getRedstoneInput( int side )
{
synchronized( m_input )
{
return m_input[side];
}
}
public int getBundledRedstoneOutput( int side )
{
synchronized( m_internalOutput )
{
return isOn() ? m_externalBundledOutput[side] : 0;
}
}
private int getInternalBundledRedstoneOutput( int side )
{
synchronized( m_internalOutput )
{
return isOn() ? m_internalBundledOutput[side] : 0;
}
}
private void setBundledRedstoneOutput( int side, int combination )
{
synchronized( m_internalOutput )
{
if( m_internalBundledOutput[side] != combination )
{
m_internalBundledOutput[side] = combination;
m_internalOutputChanged = true;
}
}
}
public void setBundledRedstoneInput( int side, int combination )
{
synchronized( m_input )
{
if( m_bundledInput[side] != combination )
{
m_bundledInput[side] = combination;
m_inputChanged = true;
}
}
}
private int getBundledRedstoneInput( int side )
{
synchronized( m_input )
{
return m_bundledInput[side];
}
}
// Peripherals
public void addAPI( ILuaAPI api )
@@ -676,57 +282,8 @@ public class Computer
m_apis.add( api );
}
@SuppressWarnings( "deprecation" )
public void addAPI( dan200.computercraft.core.apis.ILuaAPI api )
{
addAPI( (ILuaAPI) api );
}
public void setPeripheral( int side, IPeripheral peripheral )
{
synchronized( m_peripherals )
{
IPeripheral existing = m_peripherals[side];
if( (existing == null && peripheral != null) ||
(existing != null && peripheral == null) ||
(existing != null && !existing.equals( peripheral )) )
{
m_peripherals[side] = peripheral;
m_apiEnvironment.onPeripheralChanged( side, peripheral );
}
}
}
public IPeripheral getPeripheral( int side )
{
synchronized( m_peripherals )
{
return m_peripherals[side];
}
}
// Lua
private void createAPIs()
{
m_apis.add( new TermAPI( m_apiEnvironment ) );
m_apis.add( new RedstoneAPI( m_apiEnvironment ) );
m_apis.add( new FSAPI( m_apiEnvironment ) );
m_apis.add( new PeripheralAPI( m_apiEnvironment ) );
m_apis.add( new OSAPI( m_apiEnvironment ) );
if( ComputerCraft.http_enable )
{
m_apis.add( new HTTPAPI( m_apiEnvironment ) );
}
for( ILuaAPIFactory factory : ApiFactories.getAll() )
{
ComputerSystem system = new ComputerSystem( m_apiEnvironment );
ILuaAPI api = factory.create( system );
if( api != null ) m_apis.add( api );
}
}
private void initLua()
{
// Create the lua machine
@@ -824,10 +381,7 @@ public class Computer
}
// Init terminal
synchronized( m_terminal )
{
m_terminal.reset();
}
m_terminal.reset();
// Init filesystem
if( !initFileSystem() )
@@ -920,10 +474,7 @@ public class Computer
if( m_machine != null )
{
synchronized( m_terminal )
{
m_terminal.reset();
}
m_terminal.reset();
synchronized( m_machine )
{
@@ -933,15 +484,7 @@ public class Computer
}
// Reset redstone output
synchronized( m_internalOutput )
{
for( int i = 0; i < 6; i++ )
{
m_internalOutput[i] = 0;
m_internalBundledOutput[i] = 0;
}
m_internalOutputChanged = true;
}
m_internalEnvironment.resetOutput();
m_state = State.Off;
m_externalOutputChanged = true;
@@ -1002,4 +545,23 @@ public class Computer
ComputerThread.queueTask( task, computer );
}
@Deprecated
public void setPeripheral( int side, IPeripheral peripheral )
{
m_internalEnvironment.setPeripheral( side, peripheral );
}
@Deprecated
public void addAPI( dan200.computercraft.core.apis.ILuaAPI api )
{
addAPI( (ILuaAPI) api );
}
@Deprecated
@SuppressWarnings( "unused" )
public void advance( double dt )
{
advance();
}
}

View File

@@ -0,0 +1,58 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.computer;
import dan200.computercraft.api.filesystem.IFileSystem;
import dan200.computercraft.api.lua.IComputerSystem;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.core.apis.ComputerAccess;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.filesystem.FileSystem;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Implementation of {@link IComputerAccess}/{@link IComputerSystem} for external APIs.
*
* @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
* @see ILuaAPIFactory
* @see ApiWrapper
*/
public class ComputerSystem extends ComputerAccess implements IComputerSystem
{
private final IAPIEnvironment m_environment;
ComputerSystem( IAPIEnvironment m_environment )
{
super( m_environment );
this.m_environment = m_environment;
}
@Nonnull
@Override
public String getAttachmentName()
{
return "computer";
}
@Nullable
@Override
public IFileSystem getFileSystem()
{
FileSystem fs = m_environment.getFileSystem();
return fs == null ? null : fs.getMountWrapper();
}
@Nullable
@Override
public String getLabel()
{
return m_environment.getLabel();
}
}

View File

@@ -16,6 +16,7 @@ import java.util.WeakHashMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.locks.LockSupport;
public class ComputerThread
{
@@ -216,22 +217,37 @@ public class ComputerThread
// Interrupt the thread
if( !done )
{
StringBuilder builder = new StringBuilder( "Terminating " );
if( computer != null )
if( ComputerCraft.logPeripheralErrors )
{
builder.append( "computer " ).append( computer.getID() );
}
else
{
builder.append( "unknown computer" );
}
long time = System.nanoTime() - start;
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 );
{
builder.append( " due to timeout (running for " )
.append( time / 1e9 )
.append( " seconds). This is NOT a bug, but may mean a computer is misbehaving. " )
.append( thread.getName() )
.append( " is currently " )
.append( thread.getState() );
Object blocking = LockSupport.getBlocker( thread );
if( blocking != null ) builder.append( "\n on " ).append( blocking );
for( StackTraceElement element : thread.getStackTrace() )
{
builder.append( "\n at " ).append( element );
}
}
ComputerCraft.log.warn( builder.toString() );
}
ComputerCraft.log.error( builder.toString() );
thread.interrupt();
thread = null;

View File

@@ -0,0 +1,306 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.computer;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.core.tracking.TrackingField;
import javax.annotation.Nonnull;
import java.util.Arrays;
/**
* Represents the "environment" that a {@link Computer} exists in.
*
* This handles storing and updating of peripherals and redstone.
*
* <h2>Redstone</h2>
* We holds three kinds of arrays for redstone, in normal and bundled versions:
* <ul>
* <li>{@link #internalOutput} is the redstone output which the computer has currently set. This is read on both
* threads, and written on the computer thread.</li>
* <li>{@link #externalOutput} is the redstone output currently propagated to the world. This is only read and written
* on the main thread.</li>
* <li>{@link #input} is the redstone input from external sources. This is read on both threads, and written on the main
* thread.</li>
* </ul>
*
* <h2>Peripheral</h2>
* We also keep track of peripherals. These are read on both threads, and only written on the main thread.
*/
public final class Environment implements IAPIEnvironment
{
private final Computer computer;
private boolean internalOutputChanged = false;
private final int[] internalOutput = new int[SIDE_COUNT];
private final int[] internalBundledOutput = new int[SIDE_COUNT];
private final int[] externalOutput = new int[SIDE_COUNT];
private final int[] externalBundledOutput = new int[SIDE_COUNT];
private boolean inputChanged = false;
private final int[] input = new int[SIDE_COUNT];
private final int[] bundledInput = new int[SIDE_COUNT];
private final IPeripheral[] peripherals = new IPeripheral[SIDE_COUNT];
private IPeripheralChangeListener peripheralListener = null;
Environment( Computer computer )
{
this.computer = computer;
}
@Nonnull
@Override
public Computer getComputer()
{
return computer;
}
@Override
public int getComputerID()
{
return computer.assignID();
}
@Nonnull
@Override
public IComputerEnvironment getComputerEnvironment()
{
return computer.getComputerEnvironment();
}
@Nonnull
@Override
public Terminal getTerminal()
{
return computer.getTerminal();
}
@Override
public FileSystem getFileSystem()
{
return computer.getFileSystem();
}
@Override
public void shutdown()
{
computer.shutdown();
}
@Override
public void reboot()
{
computer.reboot();
}
@Override
public void queueEvent( String event, Object[] args )
{
computer.queueEvent( event, args );
}
@Override
public int getInput( int side )
{
return input[side];
}
@Override
public int getBundledInput( int side )
{
return bundledInput[side];
}
@Override
public void setOutput( int side, int output )
{
synchronized( internalOutput )
{
if( internalOutput[side] != output )
{
internalOutput[side] = output;
internalOutputChanged = true;
}
}
}
@Override
public int getOutput( int side )
{
synchronized( internalOutput )
{
return computer.isOn() ? internalOutput[side] : 0;
}
}
@Override
public void setBundledOutput( int side, int output )
{
synchronized( internalOutput )
{
if( internalBundledOutput[side] != output )
{
internalBundledOutput[side] = output;
internalOutputChanged = true;
}
}
}
@Override
public int getBundledOutput( int side )
{
synchronized( internalOutput )
{
return computer.isOn() ? internalBundledOutput[side] : 0;
}
}
public int getExternalRedstoneOutput( int side )
{
return computer.isOn() ? externalOutput[side] : 0;
}
public int getExternalBundledRedstoneOutput( int side )
{
return computer.isOn() ? externalBundledOutput[side] : 0;
}
public void setRedstoneInput( int side, int level )
{
if( input[side] != level )
{
input[side] = level;
inputChanged = true;
}
}
public void setBundledRedstoneInput( int side, int combination )
{
if( bundledInput[side] != combination )
{
bundledInput[side] = combination;
inputChanged = true;
}
}
/**
* Called on the main thread to update the internal state of the computer.
*
* This just queues a {@code redstone} event if the input has changed.
*/
void update()
{
if( inputChanged )
{
inputChanged = false;
queueEvent( "redstone", null );
}
}
/**
* Called on the main thread to propagate the internal outputs to the external ones.
*
* @return If the outputs have changed.
*/
boolean updateOutput()
{
// Set outputchanged if the internal redstone has changed
synchronized( internalOutput )
{
if( !internalOutputChanged ) return false;
boolean changed = false;
for( int i = 0; i < SIDE_COUNT; i++ )
{
if( externalOutput[i] != internalOutput[i] )
{
externalOutput[i] = internalOutput[i];
changed = true;
}
if( externalBundledOutput[i] != internalBundledOutput[i] )
{
externalBundledOutput[i] = internalBundledOutput[i];
changed = true;
}
}
internalOutputChanged = false;
return changed;
}
}
void resetOutput()
{
// Reset redstone output
synchronized( internalOutput )
{
Arrays.fill( internalOutput, 0 );
Arrays.fill( internalBundledOutput, 0 );
internalOutputChanged = true;
}
}
@Override
public IPeripheral getPeripheral( int side )
{
synchronized( peripherals )
{
return peripherals[side];
}
}
public void setPeripheral( int side, IPeripheral peripheral )
{
synchronized( peripherals )
{
IPeripheral existing = peripherals[side];
if( (existing == null && peripheral != null) ||
(existing != null && peripheral == null) ||
(existing != null && !existing.equals( peripheral )) )
{
peripherals[side] = peripheral;
if( peripheralListener != null ) peripheralListener.onPeripheralChanged( side, peripheral );
}
}
}
@Override
public void setPeripheralChangeListener( IPeripheralChangeListener listener )
{
synchronized( peripherals )
{
peripheralListener = listener;
}
}
@Override
public String getLabel()
{
return computer.getLabel();
}
@Override
public void setLabel( String label )
{
computer.setLabel( label );
}
@Override
public void addTrackingChange( @Nonnull TrackingField field, long change )
{
Tracking.addValue( computer, field, change );
}
}

View File

@@ -1,144 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.filesystem;
import dan200.computercraft.api.filesystem.IMount;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.FileSystem;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.stream.Stream;
public class FileSystemMount implements IMount
{
private final Entry rootEntry;
public FileSystemMount( FileSystem fileSystem, String root ) throws IOException
{
Path rootPath = fileSystem.getPath( root );
rootEntry = new Entry( "", rootPath );
populate( rootEntry );
}
private void populate( Entry root ) throws IOException
{
if( !root.directory ) return;
Queue<Entry> entries = new ArrayDeque<>();
entries.add( root );
while( !entries.isEmpty() )
{
Entry entry = entries.remove();
try( Stream<Path> childStream = Files.list( entry.path ) )
{
Iterator<Path> children = childStream.iterator();
while( children.hasNext() )
{
Path childPath = children.next();
Entry child = new Entry( childPath.getFileName().toString(), childPath );
entry.children.put( child.name, child );
if( child.directory ) entries.add( child );
}
}
}
}
@Override
public boolean exists( @Nonnull String path )
{
return getFile( path ) != null;
}
@Override
public boolean isDirectory( @Nonnull String path )
{
Entry entry = getFile( path );
return entry != null && entry.directory;
}
@Override
public void list( @Nonnull String path, @Nonnull List<String> contents ) throws IOException
{
Entry entry = getFile( path );
if( entry == null || !entry.directory ) throw new IOException( "/" + path + ": Not a directory" );
contents.addAll( entry.children.keySet() );
}
@Override
public long getSize( @Nonnull String path ) throws IOException
{
Entry file = getFile( path );
if( file == null ) throw new IOException( "/" + path + ": No such file" );
return file.size;
}
@Nonnull
@Override
@Deprecated
public InputStream openForRead( @Nonnull String path ) throws IOException
{
Entry file = getFile( path );
if( file == null || file.directory ) throw new IOException( "/" + path + ": No such file" );
return Files.newInputStream( file.path, StandardOpenOption.READ );
}
@Nonnull
@Override
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{
Entry file = getFile( path );
if( file == null || file.directory ) throw new IOException( "/" + path + ": No such file" );
return Files.newByteChannel( file.path, StandardOpenOption.READ );
}
private Entry getFile( String path )
{
if( path.equals( "" ) ) return rootEntry;
if( !path.contains( "/" ) ) return rootEntry.children.get( path );
String[] components = path.split( "/" );
Entry entry = rootEntry;
for( String component : components )
{
if( entry == null || entry.children == null ) return null;
entry = entry.children.get( component );
}
return entry;
}
private static class Entry
{
final String name;
final Path path;
final boolean directory;
final long size;
final Map<String, Entry> children;
private Entry( String name, Path path ) throws IOException
{
if( name.endsWith( "/" ) || name.endsWith( "\\" ) ) name = name.substring( 0, name.length() - 1 );
this.name = name;
this.path = path;
BasicFileAttributes attributes = Files.readAttributes( path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS );
this.directory = attributes.isDirectory();
this.size = directory ? 0 : attributes.size();
this.children = directory ? new HashMap<>() : null;
}
}
}

View File

@@ -6,242 +6,266 @@
package dan200.computercraft.core.filesystem;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.io.ByteStreams;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.core.apis.handles.ArrayByteChannel;
import dan200.computercraft.shared.util.IoUtil;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@Deprecated
public class JarMount implements IMount
{
private static class FileInZip
{
private String m_path;
private boolean m_directory;
private long m_size;
private Map<String, FileInZip> m_children;
/**
* Only cache files smaller than 1MiB.
*/
private static final int MAX_CACHED_SIZE = 1 << 20;
public FileInZip( String path, boolean directory, long size )
{
m_path = path;
m_directory = directory;
m_size = m_directory ? 0 : size;
m_children = new LinkedHashMap<>();
}
/**
* Limit the entire cache to 64MiB.
*/
private static final int MAX_CACHE_SIZE = 64 << 20;
public String getPath()
{
return m_path;
}
/**
* We maintain a cache of the contents of all files in the mount. This allows us to allow
* seeking within ROM files, and reduces the amount we need to access disk for computer startup.
*/
private static final Cache<FileEntry, byte[]> CONTENTS_CACHE = CacheBuilder.newBuilder()
.concurrencyLevel( 4 )
.expireAfterAccess( 60, TimeUnit.SECONDS )
.maximumWeight( MAX_CACHE_SIZE )
.weakKeys()
.<FileEntry, byte[]>weigher( ( k, v ) -> v.length )
.build();
public boolean isDirectory()
{
return m_directory;
}
/**
* We have a {@link ReferenceQueue} of all mounts, a long with their corresponding {@link ZipFile}. If
* the mount has been destroyed, we clean up after it.
*/
private static final ReferenceQueue<JarMount> MOUNT_QUEUE = new ReferenceQueue<>();
public long getSize()
{
return m_size;
}
private final ZipFile zip;
private final FileEntry root;
public void list( List<String> contents )
{
contents.addAll( m_children.keySet() );
}
public void insertChild( FileInZip child )
{
String localPath = FileSystem.toLocal( child.getPath(), m_path );
m_children.put( localPath, child );
}
public FileInZip getFile( String path )
{
// If we've reached the target, return this
if( path.equals( m_path ) )
{
return this;
}
// Otherwise, get the next component of the path
String localPath = FileSystem.toLocal( path, m_path );
int slash = localPath.indexOf( "/" );
if( slash >= 0 )
{
localPath = localPath.substring( 0, slash );
}
// And recurse down using it
FileInZip subFile = m_children.get( localPath );
if( subFile != null )
{
return subFile.getFile( path );
}
return null;
}
public FileInZip getParent( String path )
{
if( path.length() == 0 )
{
return null;
}
FileInZip file = getFile( FileSystem.getDirectory( path ) );
if( file.isDirectory() )
{
return file;
}
return null;
}
}
private ZipFile m_zipFile;
private FileInZip m_root;
private String m_rootPath;
@Deprecated
public JarMount( File jarFile, String subPath ) throws IOException
{
if( !jarFile.exists() || jarFile.isDirectory() )
{
throw new FileNotFoundException();
}
// Cleanup any old mounts. It's unlikely that there will be any, but it's best to be safe.
cleanup();
if( !jarFile.exists() || jarFile.isDirectory() ) throw new FileNotFoundException();
// Open the zip file
try
{
m_zipFile = new ZipFile( jarFile );
zip = new ZipFile( jarFile );
}
catch( Exception e )
{
throw new IOException( "Error loading zip file" );
}
if( m_zipFile.getEntry( subPath ) == null )
// Ensure the root entry exists.
if( zip.getEntry( subPath ) == null )
{
m_zipFile.close();
zip.close();
throw new IOException( "Zip does not contain path" );
}
// We now create a weak reference to this mount. This is automatically added to the appropriate queue.
new MountReference( this );
// Read in all the entries
Enumeration<? extends ZipEntry> zipEntries = m_zipFile.entries();
root = new FileEntry( "" );
Enumeration<? extends ZipEntry> zipEntries = zip.entries();
while( zipEntries.hasMoreElements() )
{
ZipEntry entry = zipEntries.nextElement();
String entryName = entry.getName();
if( entryName.startsWith( subPath ) )
{
entryName = FileSystem.toLocal( entryName, subPath );
if( m_root == null )
{
if( entryName.equals( "" ) )
{
m_root = new FileInZip( entryName, entry.isDirectory(), entry.getSize() );
m_rootPath = subPath;
if( !m_root.isDirectory() ) break;
}
else
{
// TODO: handle this case. The code currently assumes we find the root before anything else
}
}
else
{
FileInZip parent = m_root.getParent( entryName );
if( parent != null )
{
parent.insertChild( new FileInZip( entryName, entry.isDirectory(), entry.getSize() ) );
}
else
{
// TODO: handle this case. The code currently assumes we find folders before their contents
}
}
}
String entryPath = entry.getName();
if( !entryPath.startsWith( subPath ) ) continue;
String localPath = FileSystem.toLocal( entryPath, subPath );
create( entry, localPath );
}
}
// IMount implementation
private FileEntry get( String path )
{
FileEntry lastEntry = root;
int lastIndex = 0;
while( lastEntry != null && lastIndex < path.length() )
{
int nextIndex = path.indexOf( '/', lastIndex );
if( nextIndex < 0 ) nextIndex = path.length();
lastEntry = lastEntry.children == null ? null : lastEntry.children.get( path.substring( lastIndex, nextIndex ) );
lastIndex = nextIndex + 1;
}
return lastEntry;
}
private void create( ZipEntry entry, String localPath )
{
FileEntry lastEntry = root;
int lastIndex = 0;
while( lastIndex < localPath.length() )
{
int nextIndex = localPath.indexOf( '/', lastIndex );
if( nextIndex < 0 ) nextIndex = localPath.length();
String part = localPath.substring( lastIndex, nextIndex );
if( lastEntry.children == null ) lastEntry.children = new HashMap<>( 0 );
FileEntry nextEntry = lastEntry.children.get( part );
if( nextEntry == null || !nextEntry.isDirectory() )
{
lastEntry.children.put( part, nextEntry = new FileEntry( part ) );
}
lastEntry = nextEntry;
lastIndex = nextIndex + 1;
}
lastEntry.setup( entry );
}
@Override
public boolean exists( @Nonnull String path )
{
FileInZip file = m_root.getFile( path );
return file != null;
return get( path ) != null;
}
@Override
public boolean isDirectory( @Nonnull String path )
{
FileInZip file = m_root.getFile( path );
if( file != null )
{
return file.isDirectory();
}
return false;
FileEntry file = get( path );
return file != null && file.isDirectory();
}
@Override
public void list( @Nonnull String path, @Nonnull List<String> contents ) throws IOException
{
FileInZip file = m_root.getFile( path );
if( file != null && file.isDirectory() )
{
file.list( contents );
}
else
{
throw new IOException( "/" + path + ": Not a directory" );
}
FileEntry file = get( path );
if( file == null || !file.isDirectory() ) throw new IOException( "/" + path + ": Not a directory" );
file.list( contents );
}
@Override
public long getSize( @Nonnull String path ) throws IOException
{
FileInZip file = m_root.getFile( path );
if( file != null )
{
return file.getSize();
}
FileEntry file = get( path );
if( file != null ) return file.size;
throw new IOException( "/" + path + ": No such file" );
}
@Nonnull
@Override
@Deprecated
public InputStream openForRead( @Nonnull String path ) throws IOException
{
FileInZip file = m_root.getFile( path );
return Channels.newInputStream( openChannelForRead( path ) );
}
@Nonnull
@Override
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{
FileEntry file = get( path );
if( file != null && !file.isDirectory() )
{
byte[] contents = CONTENTS_CACHE.getIfPresent( file );
if( contents != null ) return new ArrayByteChannel( contents );
try
{
String fullPath = m_rootPath;
if( path.length() > 0 )
{
fullPath = fullPath + "/" + path;
}
ZipEntry entry = m_zipFile.getEntry( fullPath );
ZipEntry entry = zip.getEntry( file.path );
if( entry != null )
{
return m_zipFile.getInputStream( entry );
try( InputStream stream = zip.getInputStream( entry ) )
{
if( stream.available() > MAX_CACHED_SIZE ) return Channels.newChannel( stream );
contents = ByteStreams.toByteArray( stream );
CONTENTS_CACHE.put( file, contents );
return new ArrayByteChannel( contents );
}
}
}
catch( Exception e )
{
// treat errors as non-existance of file
// Treat errors as non-existence of file
}
}
throw new IOException( "/" + path + ": No such file" );
}
private static class FileEntry
{
final String name;
String path;
long size;
Map<String, FileEntry> children;
FileEntry( String name )
{
this.name = name;
}
void setup( ZipEntry entry )
{
path = entry.getName();
size = entry.getSize();
if( children == null && entry.isDirectory() ) children = new HashMap<>( 0 );
}
boolean isDirectory()
{
return children != null;
}
void list( List<String> contents )
{
if( children != null ) contents.addAll( children.keySet() );
}
}
private static class MountReference extends WeakReference<JarMount>
{
final ZipFile file;
MountReference( JarMount file )
{
super( file, MOUNT_QUEUE );
this.file = file.zip;
}
}
private static void cleanup()
{
Reference<? extends JarMount> next;
while( (next = MOUNT_QUEUE.poll()) != null ) IoUtil.closeQuietly( ((MountReference) next).file );
}
}

View File

@@ -46,7 +46,7 @@ public class CobaltLuaMachine implements ILuaMachine
{
private static final ThreadPoolExecutor coroutines = new ThreadPoolExecutor(
0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
5L, TimeUnit.MINUTES,
new SynchronousQueue<>(),
ThreadUtils.factory( "Coroutine" )
);
@@ -74,12 +74,12 @@ public class CobaltLuaMachine implements ILuaMachine
private boolean hasSoftAbort;
@Override
public void onInstruction( DebugState ds, DebugFrame di, int pc, Varargs extras, int top ) throws LuaError
public void onInstruction( DebugState ds, DebugFrame di, int pc ) throws LuaError, UnwindThrowable
{
int count = ++this.count;
if( count > 100000 )
{
if( m_hardAbortMessage != null ) LuaThread.yield( m_state, NONE );
if( m_hardAbortMessage != null ) throw HardAbortError.INSTANCE;
this.count = 0;
}
else
@@ -87,13 +87,13 @@ public class CobaltLuaMachine implements ILuaMachine
handleSoftAbort();
}
super.onInstruction( ds, di, pc, extras, top );
super.onInstruction( ds, di, pc );
}
@Override
public void poll() throws LuaError
{
if( m_hardAbortMessage != null ) LuaThread.yield( m_state, NONE );
if( m_hardAbortMessage != null ) throw HardAbortError.INSTANCE;
handleSoftAbort();
}
@@ -117,7 +117,7 @@ public class CobaltLuaMachine implements ILuaMachine
throw new LuaError( message );
}
} )
.coroutineFactory( command -> {
.yieldThreader( command -> {
Tracking.addValue( m_computer, TrackingField.COROUTINES_CREATED, 1 );
coroutines.execute( () -> {
try
@@ -145,10 +145,10 @@ public class CobaltLuaMachine implements ILuaMachine
if( ComputerCraft.debug_enable ) m_globals.load( state, new DebugLib() );
// Register custom load/loadstring provider which automatically adds prefixes.
LibFunction.bind( state, m_globals, PrefixLoader.class, new String[] { "load", "loadstring" } );
LibFunction.bind( m_globals, PrefixLoader.class, new String[] { "load", "loadstring" } );
// Remove globals we don't want to expose
// m_globals.rawset( "collectgarbage", Constants.NIL );
m_globals.rawset( "collectgarbage", Constants.NIL );
m_globals.rawset( "dofile", Constants.NIL );
m_globals.rawset( "loadfile", Constants.NIL );
m_globals.rawset( "print", Constants.NIL );
@@ -222,26 +222,18 @@ public class CobaltLuaMachine implements ILuaMachine
resumeArgs = varargsOf( valueOf( eventName ), toValues( arguments ) );
}
Varargs results = m_mainRoutine.resume( resumeArgs );
if( m_hardAbortMessage != null )
{
throw new LuaError( m_hardAbortMessage );
}
else if( !results.first().checkBoolean() )
{
throw new LuaError( results.arg( 2 ).checkString() );
}
else
{
LuaValue filter = results.arg( 2 );
m_eventFilter = filter.isString() ? filter.toString() : null;
}
Varargs results = LuaThread.run( m_mainRoutine, resumeArgs );
if( m_hardAbortMessage != null ) throw new LuaError( m_hardAbortMessage );
LuaValue filter = results.first();
m_eventFilter = filter.isString() ? filter.toString() : null;
if( m_mainRoutine.getStatus().equals( "dead" ) ) unload();
}
catch( LuaError e )
catch( LuaError | HardAbortError e )
{
unload();
ComputerCraft.log.warn( "Top level coroutine errored", e );
}
finally
{
@@ -339,16 +331,12 @@ public class CobaltLuaMachine implements ILuaMachine
{
try
{
Varargs results = LuaThread.yield( state, toValues( yieldArgs ) );
Varargs results = LuaThread.yieldBlocking( state, toValues( yieldArgs ) );
return toObjects( results, 1 );
}
catch( OrphanedThread e )
catch( LuaError e )
{
throw new InterruptedException();
}
catch( Throwable e )
{
throw new RuntimeException( e );
throw new IllegalStateException( e );
}
}
@@ -699,7 +687,7 @@ public class CobaltLuaMachine implements ILuaMachine
LuaValue s;
try
{
s = OperationHelper.call( state, func );
s = OperationHelper.noYield( state, () -> OperationHelper.call( state, func ) );
}
catch( LuaError e )
{
@@ -731,4 +719,16 @@ public class CobaltLuaMachine implements ILuaMachine
return bytes[offset++];
}
}
private static class HardAbortError extends Error
{
private static final long serialVersionUID = 7954092008586367501L;
public static final HardAbortError INSTANCE = new HardAbortError();
private HardAbortError()
{
super( "Hard Abort", null, true, false );
}
}
}

View File

@@ -29,11 +29,18 @@ public class Terminal
private final Palette m_palette;
private boolean m_changed;
private final Runnable onChanged;
public Terminal( int width, int height )
{
this( width, height, null );
}
public Terminal( int width, int height, Runnable changedCallback )
{
m_width = width;
m_height = height;
this.onChanged = changedCallback;
m_cursorColour = 0;
m_cursorBackgroundColour = 15;
@@ -65,7 +72,7 @@ public class Terminal
m_cursorY = 0;
m_cursorBlink = false;
clear();
m_changed = true;
setChanged();
m_palette.resetColours();
}
@@ -122,7 +129,7 @@ public class Terminal
m_backgroundColour[i].write( oldBackgroundColour[i] );
}
}
m_changed = true;
setChanged();
}
public void setCursorPos( int x, int y )
@@ -131,7 +138,7 @@ public class Terminal
{
m_cursorX = x;
m_cursorY = y;
m_changed = true;
setChanged();
}
}
@@ -140,7 +147,7 @@ public class Terminal
if( m_cursorBlink != blink )
{
m_cursorBlink = blink;
m_changed = true;
setChanged();
}
}
@@ -149,7 +156,7 @@ public class Terminal
if( m_cursorColour != colour )
{
m_cursorColour = colour;
m_changed = true;
setChanged();
}
}
@@ -158,7 +165,7 @@ public class Terminal
if( m_cursorBackgroundColour != colour )
{
m_cursorBackgroundColour = colour;
m_changed = true;
setChanged();
}
}
@@ -201,7 +208,7 @@ public class Terminal
m_text[y].write( text, x );
m_textColour[y].write( textColour, x );
m_backgroundColour[y].write( backgroundColour, x );
m_changed = true;
setChanged();
}
}
@@ -214,7 +221,7 @@ public class Terminal
m_text[y].write( text, x );
m_textColour[y].fill( base16.charAt( m_cursorColour ), x, x + text.length() );
m_backgroundColour[y].fill( base16.charAt( m_cursorBackgroundColour ), x, x + text.length() );
m_changed = true;
setChanged();
}
}
@@ -244,7 +251,7 @@ public class Terminal
m_text = newText;
m_textColour = newTextColour;
m_backgroundColour = newBackgroundColour;
m_changed = true;
setChanged();
}
}
@@ -256,7 +263,7 @@ public class Terminal
m_textColour[y].fill( base16.charAt( m_cursorColour ) );
m_backgroundColour[y].fill( base16.charAt( m_cursorBackgroundColour ) );
}
m_changed = true;
setChanged();
}
public synchronized void clearLine()
@@ -267,7 +274,7 @@ public class Terminal
m_text[y].fill( ' ' );
m_textColour[y].fill( base16.charAt( m_cursorColour ) );
m_backgroundColour[y].fill( base16.charAt( m_cursorBackgroundColour ) );
m_changed = true;
setChanged();
}
}
@@ -285,7 +292,7 @@ public class Terminal
m_text[y].write( text );
m_textColour[y].write( textColour );
m_backgroundColour[y].write( backgroundColour );
m_changed = true;
setChanged();
}
public synchronized TextBuffer getTextColourLine( int y )
@@ -306,17 +313,23 @@ public class Terminal
return null;
}
public boolean getChanged()
/**
* @deprecated All {@code *Changed()} methods are deprecated: one should pass in a callback
* instead.
*/
@Deprecated
public final boolean getChanged()
{
return m_changed;
}
public void setChanged()
public final void setChanged()
{
m_changed = true;
if( onChanged != null ) onChanged.run();
}
public void clearChanged()
public final void clearChanged()
{
m_changed = false;
}
@@ -371,6 +384,6 @@ public class Terminal
{
m_palette.readFromNBT( nbt );
}
m_changed = true;
setChanged();
}
}

View File

@@ -1,13 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.server.proxy;
import dan200.computercraft.shared.proxy.CCTurtleProxyCommon;
public class CCTurtleProxyServer extends CCTurtleProxyCommon
{
}

View File

@@ -1,22 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.server.proxy;
import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import java.io.File;
public class ComputerCraftProxyServer extends ComputerCraftProxyCommon
{
@Override
public File getWorldDir( World world )
{
return DimensionManager.getWorld( 0 ).getSaveHandler().getWorldDirectory();
}
}

View File

@@ -49,7 +49,7 @@ public final class PocketUpgrades
for( IPocketUpgrade upgrade : upgrades.values() )
{
ItemStack craftingStack = upgrade.getCraftingItem();
if( !craftingStack.isEmpty() && InventoryUtil.areItemsStackable( stack, craftingStack ) )
if( !craftingStack.isEmpty() && InventoryUtil.areItemsSimilar( stack, craftingStack ) )
{
return upgrade;
}
@@ -63,7 +63,7 @@ public final class PocketUpgrades
List<IPocketUpgrade> vanilla = new ArrayList<>();
vanilla.add( ComputerCraft.PocketUpgrades.wirelessModem );
vanilla.add( ComputerCraft.PocketUpgrades.advancedModem );
vanilla.add( ComputerCraft.PocketUpgrades.pocketSpeaker );
vanilla.add( ComputerCraft.PocketUpgrades.speaker );
return vanilla;
}
}

View File

@@ -0,0 +1,432 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.shared.computer.blocks.BlockCommandComputer;
import dan200.computercraft.shared.computer.blocks.BlockComputer;
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.items.ItemCommandComputer;
import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.media.items.ItemDiskExpanded;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.ItemPeripheral;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.modem.wired.*;
import dan200.computercraft.shared.peripheral.modem.wireless.BlockAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.ItemAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.TileAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
import dan200.computercraft.shared.peripheral.speaker.TileSpeaker;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory;
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.blocks.TileTurtleAdvanced;
import dan200.computercraft.shared.turtle.blocks.TileTurtleExpanded;
import dan200.computercraft.shared.turtle.items.ItemTurtleAdvanced;
import dan200.computercraft.shared.turtle.items.ItemTurtleLegacy;
import dan200.computercraft.shared.turtle.items.ItemTurtleNormal;
import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
import dan200.computercraft.shared.turtle.upgrades.*;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.ImpostorRecipe;
import dan200.computercraft.shared.util.ImpostorShapelessRecipe;
import net.minecraft.block.Block;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.registries.IForgeRegistry;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID )
public final class Registry
{
private Registry()
{
}
@SubscribeEvent
public static void registerBlocks( RegistryEvent.Register<Block> event )
{
IForgeRegistry<Block> registry = event.getRegistry();
// Computers
ComputerCraft.Blocks.computer = new BlockComputer();
ComputerCraft.Blocks.commandComputer = new BlockCommandComputer();
registry.registerAll(
ComputerCraft.Blocks.computer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ),
ComputerCraft.Blocks.commandComputer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ) )
);
// Turtle
ComputerCraft.Blocks.turtle = new BlockTurtle();
ComputerCraft.Blocks.turtleExpanded = new BlockTurtle();
ComputerCraft.Blocks.turtleAdvanced = new BlockTurtle();
registry.registerAll(
ComputerCraft.Blocks.turtle.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ),
ComputerCraft.Blocks.turtleExpanded.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_expanded" ) ),
ComputerCraft.Blocks.turtleAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ) )
);
// Peripheral
ComputerCraft.Blocks.peripheral = new BlockPeripheral();
registry.register( ComputerCraft.Blocks.peripheral.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "peripheral" ) ) );
// Cable
ComputerCraft.Blocks.cable = new BlockCable();
registry.register( ComputerCraft.Blocks.cable.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ) ) );
// Advanced modem
ComputerCraft.Blocks.advancedModem = new BlockAdvancedModem();
registry.register( ComputerCraft.Blocks.advancedModem.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "advanced_modem" ) ) );
// Full block modem
ComputerCraft.Blocks.wiredModemFull = new BlockWiredModemFull();
registry.register( ComputerCraft.Blocks.wiredModemFull.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ) ) );
registerTileEntities();
}
private static void registerTileEntities()
{
GameRegistry.registerTileEntity( TileComputer.class, new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) );
GameRegistry.registerTileEntity( TileCommandComputer.class, new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ) );
GameRegistry.registerTileEntity( TileTurtle.class, new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) );
GameRegistry.registerTileEntity( TileTurtleExpanded.class, new ResourceLocation( ComputerCraft.MOD_ID, "turtleex" ) );
GameRegistry.registerTileEntity( TileTurtleAdvanced.class, new ResourceLocation( ComputerCraft.MOD_ID, "turtleadv" ) );
GameRegistry.registerTileEntity( TileDiskDrive.class, new ResourceLocation( ComputerCraft.MOD_ID, "diskdrive" ) );
GameRegistry.registerTileEntity( TileWirelessModem.class, new ResourceLocation( ComputerCraft.MOD_ID, "wirelessmodem" ) );
GameRegistry.registerTileEntity( TileMonitor.class, new ResourceLocation( ComputerCraft.MOD_ID, "monitor" ) );
GameRegistry.registerTileEntity( TilePrinter.class, new ResourceLocation( ComputerCraft.MOD_ID, "ccprinter" ) );
GameRegistry.registerTileEntity( TileCable.class, new ResourceLocation( ComputerCraft.MOD_ID, "wiredmodem" ) );
GameRegistry.registerTileEntity( TileAdvancedModem.class, new ResourceLocation( ComputerCraft.MOD_ID, "advanced_modem" ) );
GameRegistry.registerTileEntity( TileSpeaker.class, new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ) );
GameRegistry.registerTileEntity( TileWiredModemFull.class, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ) );
}
private static <T extends ItemBlock> T setupItemBlock( T item )
{
item.setRegistryName( item.getBlock().getRegistryName() );
return item;
}
@SubscribeEvent
public static void registerItems( RegistryEvent.Register<Item> event )
{
IForgeRegistry<Item> registry = event.getRegistry();
// Computers
ComputerCraft.Items.computer = new ItemComputer( ComputerCraft.Blocks.computer );
ComputerCraft.Items.commandComputer = new ItemCommandComputer( ComputerCraft.Blocks.commandComputer );
registry.registerAll(
setupItemBlock( ComputerCraft.Items.computer ),
setupItemBlock( ComputerCraft.Items.commandComputer )
);
// Pocket computer
ComputerCraft.Items.pocketComputer = new ItemPocketComputer();
registry.register(
ComputerCraft.Items.pocketComputer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer" ) )
);
// Turtle
ComputerCraft.Items.turtle = new ItemTurtleLegacy( ComputerCraft.Blocks.turtle );
ComputerCraft.Items.turtleExpanded = new ItemTurtleNormal( ComputerCraft.Blocks.turtleExpanded );
ComputerCraft.Items.turtleAdvanced = new ItemTurtleAdvanced( ComputerCraft.Blocks.turtleAdvanced );
registry.registerAll(
setupItemBlock( ComputerCraft.Items.turtle ),
setupItemBlock( ComputerCraft.Items.turtleExpanded ),
setupItemBlock( ComputerCraft.Items.turtleAdvanced )
);
// Printouts
ComputerCraft.Items.printout = new ItemPrintout();
registry.register( ComputerCraft.Items.printout.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printout" ) ) );
// Disks
ComputerCraft.Items.disk = new ItemDiskLegacy();
ComputerCraft.Items.diskExpanded = new ItemDiskExpanded();
ComputerCraft.Items.treasureDisk = new ItemTreasureDisk();
registry.registerAll(
ComputerCraft.Items.disk.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk" ) ),
ComputerCraft.Items.diskExpanded.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk_expanded" ) ),
ComputerCraft.Items.treasureDisk.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "treasure_disk" ) )
);
// Peripherals
ComputerCraft.Items.peripheral = new ItemPeripheral( ComputerCraft.Blocks.peripheral );
ComputerCraft.Items.advancedModem = new ItemAdvancedModem( ComputerCraft.Blocks.advancedModem );
ComputerCraft.Items.cable = new ItemCable( ComputerCraft.Blocks.cable );
ComputerCraft.Items.wiredModemFull = new ItemWiredModemFull( ComputerCraft.Blocks.wiredModemFull );
registry.registerAll(
setupItemBlock( ComputerCraft.Items.peripheral ),
setupItemBlock( ComputerCraft.Items.advancedModem ),
setupItemBlock( ComputerCraft.Items.cable ),
setupItemBlock( ComputerCraft.Items.wiredModemFull )
);
registerTurtleUpgrades();
registerPocketUpgrades();
registerLegacyUpgrades();
}
@SubscribeEvent
public static void registerRecipes( RegistryEvent.Register<IRecipe> event )
{
IForgeRegistry<IRecipe> registry = event.getRegistry();
// Register fake recipes for the recipe book and JEI. We have several dynamic recipes,
// and we'd like people to be able to see them.
// Turtle upgrades
// TODO: Figure out a way to do this in a "nice" way.
for( ITurtleUpgrade upgrade : TurtleUpgrades.getVanillaUpgrades() )
{
ItemStack craftingItem = upgrade.getCraftingItem();
// A turtle just containing this upgrade
for( ComputerFamily family : ComputerFamily.values() )
{
if( !TurtleUpgrades.suitableForFamily( family, upgrade ) ) continue;
ItemStack baseTurtle = TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null );
if( !baseTurtle.isEmpty() )
{
ItemStack craftedTurtle = TurtleItemFactory.create( -1, null, -1, family, upgrade, null, 0, null );
ItemStack craftedTurtleFlipped = TurtleItemFactory.create( -1, null, -1, family, null, upgrade, 0, null );
registry.register(
new ImpostorRecipe( "computercraft:" + family.toString() + "_turtle_upgrade", 2, 1, new ItemStack[] { baseTurtle, craftingItem }, craftedTurtle )
.setRegistryName( new ResourceLocation( "computercraft:" + family + "_turtle_upgrade_" + upgrade.getUpgradeID().toString().replace( ':', '_' ) + "_1" ) )
);
registry.register(
new ImpostorRecipe( "computercraft:" + family.toString() + "_turtle_upgrade", 2, 1, new ItemStack[] { craftingItem, baseTurtle }, craftedTurtleFlipped )
.setRegistryName( new ResourceLocation( "computercraft:" + family + "_turtle_upgrade_" + upgrade.getUpgradeID().toString().replace( ':', '_' ) + "_2" ) )
);
}
}
}
// Coloured disks
ItemStack paper = new ItemStack( Items.PAPER, 1 );
ItemStack redstone = new ItemStack( Items.REDSTONE, 1 );
for( int colour = 0; colour < 16; colour++ )
{
ItemStack disk = ItemDiskLegacy.createFromIDAndColour( -1, null, Colour.values()[colour].getHex() );
ItemStack dye = new ItemStack( Items.DYE, 1, colour );
int diskIdx = 0;
ItemStack[] disks = new ItemStack[15];
for( int otherColour = 0; otherColour < 16; otherColour++ )
{
if( colour != otherColour )
{
disks[diskIdx++] = ItemDiskLegacy.createFromIDAndColour( -1, null, Colour.values()[otherColour].getHex() );
}
}
// Normal recipe
registry.register(
new ImpostorShapelessRecipe( "computercraft:disk", disk, new ItemStack[] { redstone, paper, dye } )
.setRegistryName( new ResourceLocation( "computercraft:disk_imposter_" + colour ) )
);
// Conversion recipe
registry.register(
new ImpostorShapelessRecipe( "computercraft:disk", disk, NonNullList.from( Ingredient.EMPTY, Ingredient.fromStacks( disks ), Ingredient.fromStacks( dye ) ) )
.setRegistryName( new ResourceLocation( "computercraft:disk_imposter_convert_" + colour ) )
);
}
// Pocket computer upgrades
ItemStack pocketComputer = PocketComputerItemFactory.create( -1, null, -1, ComputerFamily.Normal, null );
ItemStack advancedPocketComputer = PocketComputerItemFactory.create( -1, null, -1, ComputerFamily.Advanced, null );
for( IPocketUpgrade upgrade : PocketUpgrades.getVanillaUpgrades() )
{
registry.register( new ImpostorRecipe(
"computercraft:normal_pocket_upgrade",
1, 2,
new ItemStack[] { upgrade.getCraftingItem(), pocketComputer },
PocketComputerItemFactory.create( -1, null, -1, ComputerFamily.Normal, upgrade )
).setRegistryName( new ResourceLocation( "computercraft:normal_pocket_upgrade_" + upgrade.getUpgradeID().toString().replace( ':', '_' ) ) )
);
registry.register(
new ImpostorRecipe( "computercraft:advanced_pocket_upgrade",
1, 2,
new ItemStack[] { upgrade.getCraftingItem(), advancedPocketComputer },
PocketComputerItemFactory.create( -1, null, -1, ComputerFamily.Advanced, upgrade )
).setRegistryName( new ResourceLocation( "computercraft:advanced_pocket_upgrade_" + upgrade.getUpgradeID().toString().replace( ':', '_' ) ) )
);
}
}
public static void registerTurtleUpgrades()
{
// Upgrades
ComputerCraft.TurtleUpgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.wirelessModem );
ComputerCraft.TurtleUpgrades.advancedModem = new TurtleModem( true, new ResourceLocation( "computercraft", "advanced_modem" ), -1 );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.advancedModem );
ComputerCraft.TurtleUpgrades.speaker = new TurtleSpeaker( new ResourceLocation( "computercraft", "speaker" ), 8 );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.speaker );
ComputerCraft.TurtleUpgrades.craftingTable = new TurtleCraftingTable( new ResourceLocation( "minecraft", "crafting_table" ), 2 );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.craftingTable );
ComputerCraft.TurtleUpgrades.diamondSword = new TurtleSword( new ResourceLocation( "minecraft", "diamond_sword" ), 3, Items.DIAMOND_SWORD );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondSword );
ComputerCraft.TurtleUpgrades.diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), 4, Items.DIAMOND_SHOVEL );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondShovel );
ComputerCraft.TurtleUpgrades.diamondPickaxe = new TurtleTool( new ResourceLocation( "minecraft", "diamond_pickaxe" ), 5, Items.DIAMOND_PICKAXE );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondPickaxe );
ComputerCraft.TurtleUpgrades.diamondAxe = new TurtleAxe( new ResourceLocation( "minecraft", "diamond_axe" ), 6, Items.DIAMOND_AXE );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondAxe );
ComputerCraft.TurtleUpgrades.diamondHoe = new TurtleHoe( new ResourceLocation( "minecraft", "diamond_hoe" ), 7, Items.DIAMOND_HOE );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondHoe );
}
public static void registerPocketUpgrades()
{
// Register pocket upgrades
ComputerCraft.PocketUpgrades.wirelessModem = new PocketModem( false );
ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.wirelessModem );
ComputerCraft.PocketUpgrades.advancedModem = new PocketModem( true );
ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.advancedModem );
ComputerCraft.PocketUpgrades.speaker = new PocketSpeaker();
ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.speaker );
}
@SuppressWarnings( "deprecation" )
private static void registerLegacyUpgrades()
{
ComputerCraft.PocketUpgrades.pocketSpeaker = ComputerCraft.PocketUpgrades.speaker;
ComputerCraft.Upgrades.advancedModem = ComputerCraft.TurtleUpgrades.advancedModem;
}
@SubscribeEvent
public static void remapItems( RegistryEvent.MissingMappings<Item> mappings )
{
// 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() )
{
String domain = mapping.key.getNamespace();
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
String key = mapping.key.getPath();
if( key.equalsIgnoreCase( "CC-Computer" ) )
{
mapping.remap( ComputerCraft.Items.computer );
}
else if( key.equalsIgnoreCase( "CC-Peripheral" ) )
{
mapping.remap( ComputerCraft.Items.peripheral );
}
else if( key.equalsIgnoreCase( "CC-Cable" ) )
{
mapping.remap( ComputerCraft.Items.cable );
}
else if( key.equalsIgnoreCase( "diskExpanded" ) )
{
mapping.remap( ComputerCraft.Items.diskExpanded );
}
else if( key.equalsIgnoreCase( "treasureDisk" ) )
{
mapping.remap( ComputerCraft.Items.treasureDisk );
}
else if( key.equalsIgnoreCase( "pocketComputer" ) )
{
mapping.remap( ComputerCraft.Items.pocketComputer );
}
else if( key.equalsIgnoreCase( "CC-Turtle" ) )
{
mapping.remap( ComputerCraft.Items.turtle );
}
else if( key.equalsIgnoreCase( "CC-TurtleExpanded" ) )
{
mapping.remap( ComputerCraft.Items.turtleExpanded );
}
else if( key.equalsIgnoreCase( "CC-TurtleAdvanced" ) )
{
mapping.remap( ComputerCraft.Items.turtleAdvanced );
}
}
}
@SubscribeEvent
public static void remapBlocks( RegistryEvent.MissingMappings<Block> mappings )
{
// 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() )
{
String domain = mapping.key.getNamespace();
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
String key = mapping.key.getPath();
if( key.equalsIgnoreCase( "CC-Computer" ) )
{
mapping.remap( ComputerCraft.Blocks.computer );
}
else if( key.equalsIgnoreCase( "CC-Peripheral" ) )
{
mapping.remap( ComputerCraft.Blocks.peripheral );
}
else if( key.equalsIgnoreCase( "CC-Cable" ) )
{
mapping.remap( ComputerCraft.Blocks.cable );
}
else if( key.equalsIgnoreCase( "CC-Turtle" ) )
{
mapping.remap( ComputerCraft.Blocks.turtle );
}
else if( key.equalsIgnoreCase( "CC-TurtleExpanded" ) )
{
mapping.remap( ComputerCraft.Blocks.turtleExpanded );
}
else if( key.equalsIgnoreCase( "CC-TurtleAdvanced" ) )
{
mapping.remap( ComputerCraft.Blocks.turtleAdvanced );
}
}
}
}

View File

@@ -7,20 +7,29 @@
package dan200.computercraft.shared;
import com.google.common.base.Preconditions;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
import dan200.computercraft.api.turtle.event.TurtleActionEvent;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.LinkedHashSet;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID )
public final class TurtlePermissions
{
private static final Collection<ITurtlePermissionProvider> providers = new LinkedHashSet<>();
private TurtlePermissions()
{
}
public static void register( @Nonnull ITurtlePermissionProvider upgrade )
{
Preconditions.checkNotNull( upgrade, "upgrade cannot be null" );
@@ -57,4 +66,13 @@ public final class TurtlePermissions
}
return true;
}
@SubscribeEvent
public static void onTurtleAction( TurtleActionEvent event )
{
if( ComputerCraft.turtleDisabledActions.contains( event.getAction() ) )
{
event.setCanceled( true, "Action has been disabled" );
}
}
}

View File

@@ -101,7 +101,7 @@ public final class TurtleUpgrades
for( ITurtleUpgrade upgrade : upgrades.values() )
{
ItemStack craftingStack = upgrade.getCraftingItem();
if( !craftingStack.isEmpty() && InventoryUtil.areItemsStackable( stack, craftingStack ) )
if( !craftingStack.isEmpty() && InventoryUtil.areItemsSimilar( stack, craftingStack ) )
{
return upgrade;
}
@@ -113,15 +113,15 @@ public final class TurtleUpgrades
public static Iterable<ITurtleUpgrade> getVanillaUpgrades()
{
List<ITurtleUpgrade> vanilla = new ArrayList<>();
vanilla.add( ComputerCraft.Upgrades.diamondPickaxe );
vanilla.add( ComputerCraft.Upgrades.diamondAxe );
vanilla.add( ComputerCraft.Upgrades.diamondSword );
vanilla.add( ComputerCraft.Upgrades.diamondShovel );
vanilla.add( ComputerCraft.Upgrades.diamondHoe );
vanilla.add( ComputerCraft.Upgrades.craftingTable );
vanilla.add( ComputerCraft.Upgrades.wirelessModem );
vanilla.add( ComputerCraft.Upgrades.advancedModem );
vanilla.add( ComputerCraft.Upgrades.turtleSpeaker );
vanilla.add( ComputerCraft.TurtleUpgrades.diamondPickaxe );
vanilla.add( ComputerCraft.TurtleUpgrades.diamondAxe );
vanilla.add( ComputerCraft.TurtleUpgrades.diamondSword );
vanilla.add( ComputerCraft.TurtleUpgrades.diamondShovel );
vanilla.add( ComputerCraft.TurtleUpgrades.diamondHoe );
vanilla.add( ComputerCraft.TurtleUpgrades.craftingTable );
vanilla.add( ComputerCraft.TurtleUpgrades.wirelessModem );
vanilla.add( ComputerCraft.TurtleUpgrades.advancedModem );
vanilla.add( ComputerCraft.TurtleUpgrades.speaker );
return vanilla;
}

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.shared.command;
import com.google.common.collect.Sets;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.tracking.ComputerTracker;
import dan200.computercraft.core.tracking.Tracking;
@@ -126,7 +127,7 @@ public final class CommandComputerCraft extends CommandDelegate
IPeripheral peripheral = computer.getPeripheral( i );
if( peripheral != null )
{
table.row( header( "Peripheral " + Computer.s_sideNames[i] ), text( peripheral.getType() ) );
table.row( header( "Peripheral " + IAPIEnvironment.SIDE_NAMES[i] ), text( peripheral.getType() ) );
}
}

View File

@@ -24,7 +24,11 @@ import javax.annotation.Nonnull;
public class CommandCopy extends CommandBase implements IClientCommand
{
public static final CommandCopy INSTANCE = new CommandCopy();
private static final String NAME = "computercraft_copy";
/**
* We start with a "~" so we're less likely to show up on completions.
*/
private static final String NAME = "~computercraft_copy";
private CommandCopy()
{
@@ -47,7 +51,7 @@ public class CommandCopy extends CommandBase implements IClientCommand
@Override
public String getUsage( @Nonnull ICommandSender sender )
{
return "computercraft_copy <text>";
return "/" + NAME + " <text>";
}
@Override

View File

@@ -6,8 +6,8 @@
package dan200.computercraft.shared.command.text;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.command.CommandUtils;
import dan200.computercraft.shared.network.NetworkHandler;
import dan200.computercraft.shared.network.client.ChatTableClientMessage;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
@@ -101,6 +101,11 @@ public class TableBuilder
return additional;
}
public void setAdditional( int additional )
{
this.additional = additional;
}
/**
* Trim this table to a given height
*
@@ -110,8 +115,8 @@ public class TableBuilder
{
if( rows.size() > height )
{
additional += rows.size() - height;
rows.subList( height, rows.size() ).clear();
additional += rows.size() - height - 1;
rows.subList( height - 1, rows.size() ).clear();
}
}
@@ -120,7 +125,7 @@ public class TableBuilder
if( CommandUtils.isPlayer( source ) )
{
trim( 18 );
ComputerCraft.sendToPlayer( (EntityPlayerMP) source, new ChatTableClientMessage( this ) );
NetworkHandler.sendToPlayer( (EntityPlayerMP) source, new ChatTableClientMessage( this ) );
}
else
{

View File

@@ -74,8 +74,6 @@ public interface TableFormatter
int totalWidth = (columns - 1) * getWidth( SEPARATOR );
for( int x : maxWidths ) totalWidth += x;
// TODO: Limit the widths of some entries if totalWidth > maxWidth
if( headers != null )
{
TextComponentString line = new TextComponentString( "" );

View File

@@ -10,18 +10,16 @@ import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.Random;
public abstract class BlockGeneric extends Block implements ITileEntityProvider
{
@@ -31,122 +29,47 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
this.hasTileEntity = true;
}
protected abstract IBlockState getDefaultBlockState( int damage, EnumFacing placedSide );
protected abstract TileGeneric createTile( IBlockState state );
protected abstract TileGeneric createTile( int damage );
@Override
public final void dropBlockAsItemWithChance( World world, @Nonnull BlockPos pos, @Nonnull IBlockState state, float chance, int fortune )
{
}
@Override
public final void getDrops( @Nonnull NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.getDroppedItems( drops, false );
}
}
@Nonnull
@Override
@Deprecated
public final IBlockState getStateForPlacement( World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ, int damage, EntityLivingBase placer )
{
return getDefaultBlockState( damage, side );
}
@Override
public boolean removedByPlayer( @Nonnull IBlockState state, World world, @Nonnull BlockPos pos, @Nonnull EntityPlayer player, boolean willHarvest )
{
if( !world.isRemote )
{
// Drop items
boolean creative = player.capabilities.isCreativeMode;
dropAllItems( world, pos, creative );
}
// Remove block
return super.removedByPlayer( state, world, pos, player, willHarvest );
}
public final void dropAllItems( World world, BlockPos pos, boolean creative )
{
// Get items to drop
NonNullList<ItemStack> drops = NonNullList.create();
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.getDroppedItems( drops, creative );
}
// Drop items
if( drops.size() > 0 )
{
for( ItemStack item : drops )
{
dropItem( world, pos, item );
}
}
}
public final void dropItem( World world, BlockPos pos, @Nonnull ItemStack stack )
{
Block.spawnAsEntity( world, pos, stack );
}
@Override
public final void breakBlock( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState newState )
{
TileEntity tile = world.getTileEntity( pos );
super.breakBlock( world, pos, newState );
world.removeTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.destroy();
}
if( tile instanceof TileGeneric ) ((TileGeneric) tile).destroy();
}
@Override
public final boolean onBlockActivated( World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
return generic.onActivate( player, hand, side, hitX, hitY, hitZ );
}
return false;
return tile instanceof TileGeneric && ((TileGeneric) tile).onActivate( player, hand, side, hitX, hitY, hitZ );
}
@Override
@Deprecated
public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block block, BlockPos neighorPos )
@SuppressWarnings( "deprecation" )
public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block block, BlockPos neighbour )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.onNeighbourChange();
}
if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourChange( neighbour );
}
@Override
public final void onNeighborChange( IBlockAccess world, BlockPos pos, BlockPos neighbour )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.onNeighbourTileEntityChange( neighbour );
}
if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourTileEntityChange( neighbour );
}
@Override
public void updateTick( World world, BlockPos pos, IBlockState state, Random rand )
{
TileEntity te = world.getTileEntity( pos );
if( te instanceof TileGeneric ) ((TileGeneric) te).updateTick();
}
@Override
@@ -160,12 +83,7 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
public final boolean canConnectRedstone( IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing side )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
return generic.getRedstoneConnectivity( side );
}
return false;
return tile instanceof TileGeneric && ((TileGeneric) tile).getRedstoneConnectivity( side );
}
@Override
@@ -175,8 +93,7 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric && tile.hasWorld() )
{
TileGeneric generic = (TileGeneric) tile;
return generic.getRedstoneOutput( oppositeSide.getOpposite() );
return ((TileGeneric) tile).getRedstoneOutput( oppositeSide.getOpposite() );
}
return 0;
}
@@ -193,8 +110,7 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
return generic.getBundledRedstoneConnectivity( side );
return ((TileGeneric) tile).getBundledRedstoneConnectivity( side );
}
return false;
}
@@ -204,8 +120,7 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric && tile.hasWorld() )
{
TileGeneric generic = (TileGeneric) tile;
return generic.getBundledRedstoneOutput( side );
return ((TileGeneric) tile).getBundledRedstoneOutput( side );
}
return 0;
}

View File

@@ -22,19 +22,14 @@ public class ClientTerminal implements ITerminal
m_terminalChanged = false;
}
public void update()
{
if( m_terminal != null )
{
m_terminalChanged |= m_terminal.getChanged();
m_terminal.clearChanged();
}
}
public boolean pollTerminalChanged()
{
boolean changed = m_terminalChanged;
m_terminalChanged = false;
Terminal terminal = m_terminal;
if( terminal != null ) terminal.clearChanged();
return changed;
}
@@ -71,7 +66,7 @@ public class ClientTerminal implements ITerminal
{
if( m_terminal == null )
{
m_terminal = new Terminal( width, height );
m_terminal = new Terminal( width, height, () -> m_terminalChanged = true );
m_terminalChanged = true;
}
else

View File

@@ -9,35 +9,33 @@ package dan200.computercraft.shared.common;
import dan200.computercraft.core.terminal.Terminal;
import net.minecraft.nbt.NBTTagCompound;
import java.util.concurrent.atomic.AtomicBoolean;
public class ServerTerminal implements ITerminal
{
private final boolean m_colour;
private Terminal m_terminal;
private boolean m_terminalChanged;
private boolean m_terminalChangedLastFrame;
private final AtomicBoolean m_terminalChanged = new AtomicBoolean( false );
private boolean m_terminalChangedLastFrame = false;
public ServerTerminal( boolean colour )
{
m_colour = colour;
m_terminal = null;
m_terminalChanged = false;
m_terminalChangedLastFrame = false;
}
public ServerTerminal( boolean colour, int terminalWidth, int terminalHeight )
{
m_colour = colour;
m_terminal = new Terminal( terminalWidth, terminalHeight );
m_terminalChanged = false;
m_terminalChangedLastFrame = false;
m_terminal = new Terminal( terminalWidth, terminalHeight, this::markTerminalChanged );
}
public void resize( int width, int height )
protected void resize( int width, int height )
{
if( m_terminal == null )
{
m_terminal = new Terminal( width, height );
m_terminalChanged = true;
m_terminal = new Terminal( width, height, this::markTerminalChanged );
markTerminalChanged();
}
else
{
@@ -50,23 +48,21 @@ public class ServerTerminal implements ITerminal
if( m_terminal != null )
{
m_terminal = null;
m_terminalChanged = true;
markTerminalChanged();
}
}
protected void markTerminalChanged()
{
m_terminalChanged = true;
m_terminalChanged.set( true );
}
public void update()
{
m_terminalChangedLastFrame = m_terminalChanged || (m_terminal != null && m_terminal.getChanged());
if( m_terminal != null )
{
m_terminal.clearChanged();
}
m_terminalChanged = false;
Terminal terminal = m_terminal;
if( terminal != null ) terminal.clearChanged();
m_terminalChangedLastFrame = m_terminalChanged.getAndSet( false );
}
public boolean hasTerminalChanged()

View File

@@ -9,14 +9,12 @@ package dan200.computercraft.shared.common;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@@ -55,23 +53,30 @@ public abstract class TileGeneric extends TileEntity
getWorld().setBlockState( getPos(), newState, 3 );
}
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
}
public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ )
{
return false;
}
@Deprecated
public void onNeighbourChange()
{
}
@SuppressWarnings( "deprecation" )
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
onNeighbourChange();
}
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
{
}
protected void updateTick()
{
}
public boolean getRedstoneConnectivity( EnumFacing side )
{
return false;

View File

@@ -8,19 +8,17 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.computer.items.ComputerItemFactory;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
@@ -87,14 +85,7 @@ public class BlockCommandComputer extends BlockComputerBase
@Override
protected IBlockState getDefaultBlockState( ComputerFamily family, EnumFacing placedSide )
{
if( placedSide.getAxis() != EnumFacing.Axis.Y )
{
return getDefaultState().withProperty( Properties.FACING, placedSide );
}
else
{
return getDefaultState();
}
return getDefaultState().withProperty( Properties.FACING, placedSide );
}
@Override
@@ -115,19 +106,10 @@ public class BlockCommandComputer extends BlockComputerBase
return new TileCommandComputer();
}
@Nonnull
@Override
public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase player, @Nonnull ItemStack itemstack )
protected ItemStack getItem( TileComputerBase tile )
{
// Not sure why this is necessary
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileCommandComputer )
{
tile.setWorld( world ); // Not sure why this is necessary
tile.setPos( pos ); // Not sure why this is necessary
}
// Set direction
EnumFacing dir = DirectionUtil.fromEntityRot( player );
setDirection( world, pos, dir );
return tile instanceof TileCommandComputer ? ComputerItemFactory.create( (TileComputer) tile ) : ItemStack.EMPTY;
}
}

View File

@@ -9,24 +9,17 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.items.ComputerItemFactory;
import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
@@ -99,24 +92,9 @@ public class BlockComputer extends BlockComputerBase
@Override
protected IBlockState getDefaultBlockState( ComputerFamily family, EnumFacing placedSide )
{
IBlockState state = getDefaultState();
if( placedSide.getAxis() != EnumFacing.Axis.Y )
{
state = state.withProperty( Properties.FACING, placedSide );
}
switch( family )
{
case Normal:
default:
{
return state.withProperty( Properties.ADVANCED, false );
}
case Advanced:
{
return state.withProperty( Properties.ADVANCED, true );
}
}
return getDefaultState()
.withProperty( Properties.FACING, placedSide )
.withProperty( Properties.ADVANCED, family == ComputerFamily.Advanced );
}
@Nonnull
@@ -131,7 +109,7 @@ public class BlockComputer extends BlockComputerBase
@Override
public ComputerFamily getFamily( int damage )
{
return ((ItemComputer) Item.getItemFromBlock( this )).getFamily( damage );
return ComputerCraft.Items.computer.getFamily( damage );
}
@Override
@@ -153,27 +131,10 @@ public class BlockComputer extends BlockComputerBase
return new TileComputer();
}
@Override
public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase player, @Nonnull ItemStack stack )
{
// Not sure why this is necessary
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileComputer )
{
tile.setWorld( world ); // Not sure why this is necessary
tile.setPos( pos ); // Not sure why this is necessary
}
// Set direction
EnumFacing dir = DirectionUtil.fromEntityRot( player );
setDirection( world, pos, dir );
}
@Nonnull
@Override
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
protected ItemStack getItem( TileComputerBase tile )
{
TileEntity tile = world.getTileEntity( pos );
return tile instanceof TileComputer ? ComputerItemFactory.create( (TileComputer) tile ) : super.getPickBlock( state, target, world, pos, player );
return tile instanceof TileComputer ? ComputerItemFactory.create( (TileComputer) tile ) : ItemStack.EMPTY;
}
}

View File

@@ -8,16 +8,22 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.shared.common.BlockDirectional;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.items.ItemComputerBase;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public abstract class BlockComputerBase extends BlockDirectional
{
public BlockComputerBase( Material material )
@@ -47,11 +53,15 @@ public abstract class BlockComputerBase extends BlockDirectional
protected abstract TileComputerBase createTile( ComputerFamily family );
@Nonnull
protected abstract ItemStack getItem( TileComputerBase tile );
@Nonnull
@Override
protected final IBlockState getDefaultBlockState( int damage, EnumFacing placedSide )
@Deprecated
public final IBlockState getStateForPlacement( World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ, int damage, EntityLivingBase placer )
{
ItemComputerBase item = (ItemComputerBase) Item.getItemFromBlock( this );
return getDefaultBlockState( item.getFamily( damage ), placedSide );
return getDefaultBlockState( getFamily( damage ), DirectionUtil.fromEntityRot( placer ) );
}
@Override
@@ -80,4 +90,55 @@ public abstract class BlockComputerBase extends BlockDirectional
computer.updateInput();
}
}
@Override
@Nonnull
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileComputerBase )
{
ItemStack result = getItem( (TileComputerBase) tile );
if( !result.isEmpty() ) return result;
}
return super.getPickBlock( state, target, world, pos, player );
}
@Override
public final void dropBlockAsItemWithChance( World world, @Nonnull BlockPos pos, @Nonnull IBlockState state, float chance, int fortune )
{
}
@Override
public final void getDrops( @Nonnull NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileComputerBase )
{
ItemStack stack = getItem( (TileComputerBase) tile );
if( !stack.isEmpty() ) drops.add( stack );
}
}
@Override
public boolean removedByPlayer( @Nonnull IBlockState state, World world, @Nonnull BlockPos pos, @Nonnull EntityPlayer player, boolean willHarvest )
{
if( !world.isRemote )
{
// We drop the item here instead of doing it in the harvest method, as we
// need to drop it for creative players too.
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileComputerBase )
{
TileComputerBase computer = (TileComputerBase) tile;
if( !player.capabilities.isCreativeMode || computer.getLabel() != null )
{
spawnAsEntity( world, pos, getItem( computer ) );
}
}
}
return super.removedByPlayer( state, world, pos, player, willHarvest );
}
}

View File

@@ -9,13 +9,10 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.items.ComputerItemFactory;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import javax.annotation.Nonnull;
@@ -60,12 +57,6 @@ public class TileComputer extends TileComputerBase
return m_proxy;
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
if( !creative || getLabel() != null ) drops.add( ComputerItemFactory.create( this ) );
}
@Override
public void openGUI( EntityPlayer player )
{

View File

@@ -173,9 +173,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
}
@Override
public void onNeighbourChange()
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
updateInput();
updateInput( neighbour );
}
@Override
@@ -296,7 +296,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
int localDir = remapLocalSide( DirectionUtil.toLocal( this, dir ) );
if( !isRedstoneBlockedOnSide( localDir ) )
{
computer.setRedstoneInput( localDir, getWorld().getRedstonePower( offset, offsetSide ) );
computer.setRedstoneInput( localDir, getWorld().getRedstonePower( offset, dir ) );
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) );
}
if( !isPeripheralBlockedOnSide( localDir ) )

View File

@@ -7,9 +7,9 @@
package dan200.computercraft.shared.computer.core;
import com.google.common.base.Objects;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.common.ClientTerminal;
import dan200.computercraft.shared.computer.blocks.ComputerState;
import dan200.computercraft.shared.network.NetworkHandler;
import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
import dan200.computercraft.shared.network.server.QueueEventServerMessage;
import dan200.computercraft.shared.network.server.RequestComputerMessage;
@@ -32,10 +32,8 @@ public class ClientComputer extends ClientTerminal implements IComputer
m_instanceID = instanceID;
}
@Override
public void update()
{
super.update();
m_changedLastFrame = m_changed;
m_changed = false;
}
@@ -53,7 +51,7 @@ public class ClientComputer extends ClientTerminal implements IComputer
public void requestState()
{
// Request state from server
ComputerCraft.sendToServer( new RequestComputerMessage( getInstanceID() ) );
NetworkHandler.sendToServer( new RequestComputerMessage( getInstanceID() ) );
}
// IComputer
@@ -94,28 +92,28 @@ public class ClientComputer extends ClientTerminal implements IComputer
public void turnOn()
{
// Send turnOn to server
ComputerCraft.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.TURN_ON ) );
NetworkHandler.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.TURN_ON ) );
}
@Override
public void shutdown()
{
// Send shutdown to server
ComputerCraft.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.SHUTDOWN ) );
NetworkHandler.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.SHUTDOWN ) );
}
@Override
public void reboot()
{
// Send reboot to server
ComputerCraft.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.REBOOT ) );
NetworkHandler.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.REBOOT ) );
}
@Override
public void queueEvent( String event, Object[] arguments )
{
// Send event to server
ComputerCraft.sendToServer( new QueueEventServerMessage( m_instanceID, event, arguments ) );
NetworkHandler.sendToServer( new QueueEventServerMessage( m_instanceID, event, arguments ) );
}
public void setState( ComputerState state, NBTTagCompound userData )

View File

@@ -16,6 +16,7 @@ import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.shared.common.ServerTerminal;
import dan200.computercraft.shared.network.NetworkHandler;
import dan200.computercraft.shared.network.client.ComputerDataClientMessage;
import dan200.computercraft.shared.network.client.ComputerDeletedClientMessage;
import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage;
@@ -104,7 +105,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
public void update()
{
super.update();
m_computer.advance( 0.05 );
m_computer.advance();
m_changedLastFrame = m_computer.pollAndResetChanged() || m_changed;
m_changed = false;
@@ -163,7 +164,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
if( hasOutputChanged() || force )
{
// Send computer state to all clients
ComputerCraft.sendToAllPlayers( createComputerPacket() );
NetworkHandler.sendToAllPlayers( createComputerPacket() );
}
if( hasTerminalChanged() || force )
@@ -178,7 +179,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
{
if( isInteracting( player ) )
{
ComputerCraft.sendToPlayer( player, packet );
NetworkHandler.sendToPlayer( player, packet );
}
}
}
@@ -188,19 +189,19 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
public void sendComputerState( EntityPlayer player )
{
// Send state to client
ComputerCraft.sendToPlayer( player, createComputerPacket() );
NetworkHandler.sendToPlayer( player, createComputerPacket() );
}
public void sendTerminalState( EntityPlayer player )
{
// Send terminal state to client
ComputerCraft.sendToPlayer( player, createTerminalPacket() );
NetworkHandler.sendToPlayer( player, createTerminalPacket() );
}
public void broadcastDelete()
{
// Send deletion to client
ComputerCraft.sendToAllPlayers( new ComputerDeletedClientMessage( getInstanceID() ) );
NetworkHandler.sendToAllPlayers( new ComputerDeletedClientMessage( getInstanceID() ) );
}
public IWritableMount getRootMount()
@@ -282,22 +283,22 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
public int getRedstoneOutput( int side )
{
return m_computer.getRedstoneOutput( side );
return m_computer.getEnvironment().getExternalRedstoneOutput( side );
}
public void setRedstoneInput( int side, int level )
{
m_computer.setRedstoneInput( side, level );
m_computer.getEnvironment().setRedstoneInput( side, level );
}
public int getBundledRedstoneOutput( int side )
{
return m_computer.getBundledRedstoneOutput( side );
return m_computer.getEnvironment().getExternalBundledRedstoneOutput( side );
}
public void setBundledRedstoneInput( int side, int combination )
{
m_computer.setBundledRedstoneInput( side, combination );
m_computer.getEnvironment().setBundledRedstoneInput( side, combination );
}
public void addAPI( ILuaAPI api )
@@ -305,7 +306,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
m_computer.addAPI( api );
}
@SuppressWarnings( "deprecation" )
@Deprecated
public void addAPI( dan200.computercraft.core.apis.ILuaAPI api )
{
m_computer.addAPI( api );
@@ -313,12 +314,12 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
public void setPeripheral( int side, IPeripheral peripheral )
{
m_computer.setPeripheral( side, peripheral );
m_computer.getEnvironment().setPeripheral( side, peripheral );
}
public IPeripheral getPeripheral( int side )
{
return m_computer.getPeripheral( side );
return m_computer.getEnvironment().getPeripheral( side );
}
public void setLabel( String label )

View File

@@ -9,7 +9,6 @@ package dan200.computercraft.shared.computer.items;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
@@ -31,15 +30,9 @@ public class ComputerItemFactory
{
case Normal:
case Advanced:
{
ItemComputer computer = ((ItemComputer) Item.getItemFromBlock( ComputerCraft.Blocks.computer ));
return computer.create( id, label, family );
}
return ComputerCraft.Items.computer.create( id, label, family );
case Command:
{
ItemCommandComputer commandComputer = ((ItemCommandComputer) Item.getItemFromBlock( ComputerCraft.Blocks.commandComputer ));
return commandComputer.create( id, label, family );
}
return ComputerCraft.Items.commandComputer.create( id, label, family );
default:
return ItemStack.EMPTY;
}

View File

@@ -22,9 +22,9 @@ public class JEIComputerCraft implements IModPlugin
@Override
public void registerItemSubtypes( ISubtypeRegistry subtypeRegistry )
{
subtypeRegistry.registerSubtypeInterpreter( Item.getItemFromBlock( ComputerCraft.Blocks.turtle ), turtleSubtype );
subtypeRegistry.registerSubtypeInterpreter( Item.getItemFromBlock( ComputerCraft.Blocks.turtleExpanded ), turtleSubtype );
subtypeRegistry.registerSubtypeInterpreter( Item.getItemFromBlock( ComputerCraft.Blocks.turtleAdvanced ), turtleSubtype );
subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.turtle, turtleSubtype );
subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.turtleExpanded, turtleSubtype );
subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.turtleAdvanced, turtleSubtype );
subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.pocketComputer, pocketSubtype );

View File

@@ -43,7 +43,10 @@ final class BundledCapabilityProvider implements ICapabilityProvider
if( capability == CAPABILITY_RECEIVER )
{
IBundledReceiver receiver = this.receiver;
if( receiver == null ) receiver = this.receiver = tile::onNeighbourChange;
if( receiver == null )
{
receiver = this.receiver = () -> tile.onNeighbourChange( tile.getPos().offset( side ) );
}
return CAPABILITY_RECEIVER.cast( receiver );
}

View File

@@ -0,0 +1,106 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.network.client.*;
import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
import dan200.computercraft.shared.network.server.QueueEventServerMessage;
import dan200.computercraft.shared.network.server.RequestComputerMessage;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.IThreadListener;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.relauncher.Side;
import java.util.function.Supplier;
public final class NetworkHandler
{
public static SimpleNetworkWrapper network;
private NetworkHandler()
{
}
private static final int COMPUTER_ACTION_SERVER_MESSAGE = 0;
private static final int QUEUE_EVENT_SERVER_MESSAGE = 1;
private static final int REQUEST_COMPUTER_SERVER_MESSAGE = 2;
private static final int CHAT_TABLE_CLIENT_MESSAGE = 10;
private static final int COMPUTER_DATA_CLIENT_MESSAGE = 11;
private static final int COMPUTER_DELETED_CLIENT_MESSAGE = 12;
private static final int COMPUTER_TERMINAL_CLIENT_MESSAGE = 13;
private static final int PLAY_RECORD_CLIENT_MESSAGE = 14;
public static void setup()
{
network = NetworkRegistry.INSTANCE.newSimpleChannel( ComputerCraft.MOD_ID );
// Server messages
registerMainThread( NetworkHandler.COMPUTER_ACTION_SERVER_MESSAGE, Side.SERVER, ComputerActionServerMessage::new );
registerMainThread( NetworkHandler.QUEUE_EVENT_SERVER_MESSAGE, Side.SERVER, QueueEventServerMessage::new );
registerMainThread( NetworkHandler.REQUEST_COMPUTER_SERVER_MESSAGE, Side.SERVER, RequestComputerMessage::new );
// Client messages
registerMainThread( NetworkHandler.PLAY_RECORD_CLIENT_MESSAGE, Side.CLIENT, PlayRecordClientMessage::new );
registerMainThread( NetworkHandler.COMPUTER_DATA_CLIENT_MESSAGE, Side.CLIENT, ComputerDataClientMessage::new );
registerMainThread( NetworkHandler.COMPUTER_TERMINAL_CLIENT_MESSAGE, Side.CLIENT, ComputerTerminalClientMessage::new );
registerMainThread( NetworkHandler.COMPUTER_DELETED_CLIENT_MESSAGE, Side.CLIENT, ComputerDeletedClientMessage::new );
registerMainThread( NetworkHandler.CHAT_TABLE_CLIENT_MESSAGE, Side.CLIENT, ChatTableClientMessage::new );
}
public static void sendToPlayer( EntityPlayer player, IMessage packet )
{
network.sendTo( packet, (EntityPlayerMP) player );
}
public static void sendToAllPlayers( IMessage packet )
{
network.sendToAll( packet );
}
public static void sendToServer( IMessage packet )
{
network.sendToServer( packet );
}
public static void sendToAllAround( IMessage packet, NetworkRegistry.TargetPoint point )
{
network.sendToAllAround( packet, point );
}
/**
* /**
* Register packet, and a thread-unsafe handler for it.
*
* @param id The identifier for this packet type
* @param side The side to register this packet handler under
* @param factory The factory for this type of packet.
*/
private static <T extends NetworkMessage> void registerMainThread( int id, Side side, Supplier<T> factory )
{
network.registerMessage( MAIN_THREAD_HANDLER, factory.get().getClass(), id, side );
}
private static final IMessageHandler<NetworkMessage, IMessage> MAIN_THREAD_HANDLER = ( packet, context ) -> {
IThreadListener listener = context.side == Side.CLIENT ? Minecraft.getMinecraft() : context.getServerHandler().player.server;
if( listener.isCallingFromMinecraftThread() )
{
packet.handle( context );
}
else
{
listener.addScheduledTask( () -> packet.handle( context ) );
}
return null;
};
}

View File

@@ -6,18 +6,12 @@
package dan200.computercraft.shared.network;
import dan200.computercraft.ComputerCraft;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.IThreadListener;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import javax.annotation.Nonnull;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
* The base interface for any message which will be sent to the client or server.
@@ -27,13 +21,6 @@ import java.util.function.Supplier;
*/
public interface NetworkMessage extends IMessage
{
/**
* The unique identifier for this packet type
*
* @return This packet type's identifier
*/
int getId();
/**
* Write this packet to a buffer.
*
@@ -52,6 +39,13 @@ public interface NetworkMessage extends IMessage
*/
void fromBytes( @Nonnull PacketBuffer buf );
/**
* Handle this {@link NetworkMessage}.
*
* @param context The context with which to handle this message
*/
void handle( MessageContext context );
@Override
default void fromBytes( ByteBuf buf )
{
@@ -63,56 +57,4 @@ public interface NetworkMessage extends IMessage
{
toBytes( new PacketBuffer( buf ) );
}
/**
* Register a packet, and a thread-safe handler for it.
*
* @param side The side to register this packet handler under
* @param factory The factory for this type of packet.
* @param handler The handler for this type of packet. Note, this may be called on any thread,
* and so should be thread-safe.
*/
@SuppressWarnings( "unchecked" )
static <T extends NetworkMessage> void register(
Side side,
Supplier<T> factory,
BiConsumer<MessageContext, T> handler
)
{
T instance = factory.get();
ComputerCraft.networkWrapper.registerMessage( ( packet, ctx ) -> {
handler.accept( ctx, (T) packet );
return null;
}, instance.getClass(), instance.getId(), side );
}
/**
* Register packet, and a thread-unsafe handler for it.
*
* @param side The side to register this packet handler under
* @param factory The factory for this type of packet.
* @param handler The handler for this type of packet. This will be called on the "main"
* thread (either client or server).
*/
@SuppressWarnings( "unchecked" )
static <T extends NetworkMessage> void registerMainThread(
Side side,
Supplier<T> factory,
BiConsumer<MessageContext, T> handler
)
{
T instance = factory.get();
ComputerCraft.networkWrapper.registerMessage( ( packet, ctx ) -> {
IThreadListener listener = side == Side.CLIENT ? Minecraft.getMinecraft() : ctx.getServerHandler().player.server;
if( listener.isCallingFromMinecraftThread() )
{
handler.accept( ctx, (T) packet );
}
else
{
listener.addScheduledTask( () -> handler.accept( ctx, (T) packet ) );
}
return null;
}, instance.getClass(), instance.getId(), side );
}
}

View File

@@ -1,24 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network;
public final class NetworkMessages
{
private NetworkMessages()
{
}
public static final int COMPUTER_ACTION_SERVER_MESSAGE = 0;
public static final int QUEUE_EVENT_SERVER_MESSAGE = 1;
public static final int REQUEST_COMPUTER_SERVER_MESSAGE = 2;
public static final int CHAT_TABLE_CLIENT_MESSAGE = 10;
public static final int COMPUTER_DATA_CLIENT_MESSAGE = 11;
public static final int COMPUTER_DELETED_CLIENT_MESSAGE = 12;
public static final int COMPUTER_TERMINAL_CLIENT_MESSAGE = 13;
public static final int PLAY_RECORD_CLIENT_MESSAGE = 14;
}

View File

@@ -6,12 +6,15 @@
package dan200.computercraft.shared.network.client;
import dan200.computercraft.client.ClientTableFormatter;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.network.NetworkMessage;
import dan200.computercraft.shared.network.NetworkMessages;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
@@ -29,17 +32,6 @@ public class ChatTableClientMessage implements NetworkMessage
{
}
@Override
public int getId()
{
return NetworkMessages.CHAT_TABLE_CLIENT_MESSAGE;
}
public TableBuilder getTable()
{
return table;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
@@ -56,6 +48,8 @@ public class ChatTableClientMessage implements NetworkMessage
{
for( ITextComponent column : row ) buf.writeTextComponent( column );
}
buf.writeVarInt( table.getAdditional() );
}
@Override
@@ -82,6 +76,15 @@ public class ChatTableClientMessage implements NetworkMessage
for( int j = 0; j < columns; j++ ) row[j] = NBTUtil.readTextComponent( buf );
table.row( row );
}
table.setAdditional( buf.readVarInt() );
this.table = table;
}
@Override
@SideOnly( Side.CLIENT )
public void handle( MessageContext context )
{
ClientTableFormatter.INSTANCE.display( table );
}
}

View File

@@ -10,11 +10,8 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.network.NetworkMessage;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.relauncher.Side;
import javax.annotation.Nonnull;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
* A packet, which performs an action on a {@link ClientComputer}.
@@ -58,12 +55,4 @@ public abstract class ComputerClientMessage implements NetworkMessage
}
return computer;
}
public static <T extends ComputerClientMessage> void register( Supplier<T> factory, BiConsumer<ClientComputer, T> handler )
{
NetworkMessage.registerMainThread( Side.CLIENT, factory, ( context, packet ) -> {
ClientComputer computer = packet.getComputer();
if( computer != null ) handler.accept( computer, packet );
} );
}
}

View File

@@ -8,10 +8,10 @@ package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.computer.blocks.ComputerState;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.network.NetworkMessages;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import javax.annotation.Nonnull;
@@ -34,22 +34,6 @@ public class ComputerDataClientMessage extends ComputerClientMessage
{
}
@Override
public int getId()
{
return NetworkMessages.COMPUTER_DATA_CLIENT_MESSAGE;
}
public ComputerState getState()
{
return state;
}
public NBTTagCompound getUserData()
{
return userData;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
@@ -65,4 +49,10 @@ public class ComputerDataClientMessage extends ComputerClientMessage
state = buf.readEnumValue( ComputerState.class );
userData = NBTUtil.readCompoundTag( buf );
}
@Override
public void handle( MessageContext context )
{
getComputer().setState( state, userData );
}
}

View File

@@ -6,7 +6,8 @@
package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.network.NetworkMessages;
import dan200.computercraft.ComputerCraft;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
public class ComputerDeletedClientMessage extends ComputerClientMessage
{
@@ -20,8 +21,8 @@ public class ComputerDeletedClientMessage extends ComputerClientMessage
}
@Override
public int getId()
public void handle( MessageContext context )
{
return NetworkMessages.COMPUTER_DELETED_CLIENT_MESSAGE;
ComputerCraft.clientComputerRegistry.remove( getInstanceId() );
}
}

View File

@@ -6,10 +6,10 @@
package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.network.NetworkMessages;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import javax.annotation.Nonnull;
@@ -27,17 +27,6 @@ public class ComputerTerminalClientMessage extends ComputerClientMessage
{
}
@Override
public int getId()
{
return NetworkMessages.COMPUTER_TERMINAL_CLIENT_MESSAGE;
}
public NBTTagCompound getTag()
{
return tag;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
@@ -51,4 +40,10 @@ public class ComputerTerminalClientMessage extends ComputerClientMessage
super.fromBytes( buf );
tag = NBTUtil.readCompoundTag( buf );
}
@Override
public void handle( MessageContext context )
{
getComputer().readDescription( tag );
}
}

View File

@@ -7,10 +7,13 @@
package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.network.NetworkMessage;
import dan200.computercraft.shared.network.NetworkMessages;
import net.minecraft.client.Minecraft;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
@@ -43,27 +46,6 @@ public class PlayRecordClientMessage implements NetworkMessage
{
}
@Override
public int getId()
{
return NetworkMessages.PLAY_RECORD_CLIENT_MESSAGE;
}
public BlockPos getPos()
{
return pos;
}
public String getName()
{
return name;
}
public SoundEvent getSoundEvent()
{
return soundEvent;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
@@ -90,4 +72,13 @@ public class PlayRecordClientMessage implements NetworkMessage
soundEvent = SoundEvent.REGISTRY.getObjectById( buf.readInt() );
}
}
@Override
@SideOnly( Side.CLIENT )
public void handle( MessageContext context )
{
Minecraft mc = Minecraft.getMinecraft();
mc.world.playRecord( pos, soundEvent );
if( name != null ) mc.ingameGUI.setRecordPlayingMessage( name );
}
}

View File

@@ -6,7 +6,7 @@
package dan200.computercraft.shared.network.server;
import dan200.computercraft.shared.network.NetworkMessages;
import dan200.computercraft.shared.computer.core.ServerComputer;
import net.minecraft.network.PacketBuffer;
import javax.annotation.Nonnull;
@@ -25,12 +25,6 @@ public class ComputerActionServerMessage extends ComputerServerMessage
{
}
@Override
public int getId()
{
return NetworkMessages.COMPUTER_ACTION_SERVER_MESSAGE;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
@@ -45,9 +39,21 @@ public class ComputerActionServerMessage extends ComputerServerMessage
action = buf.readEnumValue( Action.class );
}
public Action getAction()
@Override
protected void handle( ServerComputer computer )
{
return action;
switch( action )
{
case TURN_ON:
computer.turnOn();
break;
case REBOOT:
computer.reboot();
break;
case SHUTDOWN:
computer.shutdown();
break;
}
}
public enum Action

View File

@@ -12,11 +12,8 @@ import dan200.computercraft.shared.network.NetworkMessage;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import javax.annotation.Nonnull;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
* A packet, which performs an action on a {@link ServerComputer}.
@@ -61,11 +58,12 @@ public abstract class ComputerServerMessage implements NetworkMessage
return computer;
}
public static <T extends ComputerServerMessage> void register( Supplier<T> factory, BiConsumer<ServerComputer, T> handler )
@Override
public void handle( MessageContext context )
{
NetworkMessage.registerMainThread( Side.SERVER, factory, ( context, packet ) -> {
ServerComputer computer = packet.getComputer( context );
if( computer != null ) handler.accept( computer, packet );
} );
ServerComputer computer = getComputer( context );
if( computer != null ) handle( computer );
}
protected abstract void handle( ServerComputer computer );
}

View File

@@ -6,7 +6,7 @@
package dan200.computercraft.shared.network.server;
import dan200.computercraft.shared.network.NetworkMessages;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
@@ -36,24 +36,6 @@ public class QueueEventServerMessage extends ComputerServerMessage
{
}
@Override
public int getId()
{
return NetworkMessages.QUEUE_EVENT_SERVER_MESSAGE;
}
@Nonnull
public String getEvent()
{
return event;
}
@Nullable
public Object[] getArgs()
{
return args;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
@@ -71,4 +53,10 @@ public class QueueEventServerMessage extends ComputerServerMessage
NBTTagCompound args = NBTUtil.readCompoundTag( buf );
this.args = args == null ? null : NBTUtil.decodeObjects( args );
}
@Override
protected void handle( ServerComputer computer )
{
computer.queueEvent( event, args );
}
}

View File

@@ -6,9 +6,11 @@
package dan200.computercraft.shared.network.server;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.network.NetworkMessage;
import dan200.computercraft.shared.network.NetworkMessages;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import javax.annotation.Nonnull;
@@ -25,17 +27,6 @@ public class RequestComputerMessage implements NetworkMessage
{
}
@Override
public int getId()
{
return NetworkMessages.REQUEST_COMPUTER_SERVER_MESSAGE;
}
public int getInstance()
{
return instance;
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
@@ -47,4 +38,11 @@ public class RequestComputerMessage implements NetworkMessage
{
instance = buf.readVarInt();
}
@Override
public void handle( MessageContext context )
{
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance );
if( computer != null ) computer.sendComputerState( context.getServerHandler().player );
}
}

View File

@@ -7,6 +7,8 @@
package dan200.computercraft.shared.peripheral.common;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.modem.ModemBounds;
@@ -15,19 +17,22 @@ import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
import dan200.computercraft.shared.peripheral.speaker.TileSpeaker;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.Item;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
@@ -35,7 +40,7 @@ import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
public class BlockPeripheral extends BlockPeripheralBase
public class BlockPeripheral extends BlockGeneric
{
public static class Properties
{
@@ -45,6 +50,7 @@ public class BlockPeripheral extends BlockPeripheralBase
public BlockPeripheral()
{
super( Material.ROCK );
setHardness( 2.0f );
setTranslationKey( "computercraft:peripheral" );
setCreativeTab( ComputerCraft.mainCreativeTab );
@@ -188,202 +194,107 @@ public class BlockPeripheral extends BlockPeripheralBase
@Deprecated
public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos )
{
int anim;
EnumFacing dir;
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TilePeripheralBase )
{
TilePeripheralBase peripheral = (TilePeripheralBase) tile;
anim = peripheral.getAnim();
dir = peripheral.getDirection();
}
else
{
anim = 0;
dir = state.getValue( Properties.FACING );
switch( state.getValue( Properties.VARIANT ) )
{
case WirelessModemDownOff:
case WirelessModemDownOn:
{
dir = EnumFacing.DOWN;
break;
}
case WirelessModemUpOff:
case WirelessModemUpOn:
{
dir = EnumFacing.UP;
break;
}
}
}
PeripheralType type = getPeripheralType( state );
switch( type )
{
case DiskDrive:
{
state = state.withProperty( Properties.FACING, dir );
switch( anim )
if( !(tile instanceof TileDiskDrive) ) return state;
TileDiskDrive drive = (TileDiskDrive) tile;
state = state.withProperty( Properties.FACING, drive.getDirection() );
switch( drive.getAnim() )
{
case 0:
default:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveEmpty );
break;
}
case 0:
return state.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveEmpty );
case 1:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveInvalid );
break;
}
return state.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveInvalid );
case 2:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveFull );
break;
}
return state.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveFull );
}
break;
}
case Printer:
{
state = state.withProperty( Properties.FACING, dir );
switch( anim )
if( !(tile instanceof TilePrinter) ) return state;
TilePrinter printer = (TilePrinter) tile;
state = state.withProperty( Properties.FACING, printer.getDirection() );
switch( printer.getAnim() )
{
case 0:
default:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.PrinterEmpty );
break;
}
case 0:
return state.withProperty( Properties.VARIANT, BlockPeripheralVariant.PrinterEmpty );
case 1:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.PrinterTopFull );
break;
}
return state.withProperty( Properties.VARIANT, BlockPeripheralVariant.PrinterTopFull );
case 2:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.PrinterBottomFull );
break;
}
return state.withProperty( Properties.VARIANT, BlockPeripheralVariant.PrinterBottomFull );
case 3:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.PrinterBothFull );
break;
}
return state.withProperty( Properties.VARIANT, BlockPeripheralVariant.PrinterBothFull );
}
break;
}
case WirelessModem:
{
switch( dir )
if( !(tile instanceof TileWirelessModem) ) return state;
TileWirelessModem modem = (TileWirelessModem) tile;
EnumFacing direction = modem.getDirection();
switch( direction )
{
case UP:
{
state = state.withProperty( Properties.FACING, EnumFacing.NORTH );
switch( anim )
{
case 0:
default:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.WirelessModemUpOff );
break;
}
case 1:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.WirelessModemUpOn );
break;
}
}
break;
}
return state
.withProperty( Properties.FACING, EnumFacing.NORTH )
.withProperty( Properties.VARIANT,
modem.isOn() ? BlockPeripheralVariant.WirelessModemUpOn : BlockPeripheralVariant.WirelessModemUpOff );
case DOWN:
{
state = state.withProperty( Properties.FACING, EnumFacing.NORTH );
switch( anim )
{
case 0:
default:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.WirelessModemDownOff );
break;
}
case 1:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.WirelessModemDownOn );
break;
}
}
break;
}
return state
.withProperty( Properties.FACING, EnumFacing.NORTH )
.withProperty( Properties.VARIANT,
modem.isOn() ? BlockPeripheralVariant.WirelessModemDownOn : BlockPeripheralVariant.WirelessModemDownOff );
default:
{
state = state.withProperty( Properties.FACING, dir );
switch( anim )
{
case 0:
default:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.WirelessModemOff );
break;
}
case 1:
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.WirelessModemOn );
break;
}
}
break;
return state
.withProperty( Properties.FACING, direction )
.withProperty( Properties.VARIANT,
modem.isOn() ? BlockPeripheralVariant.WirelessModemOn : BlockPeripheralVariant.WirelessModemOff );
}
}
break;
}
case Speaker:
{
state = state.withProperty( Properties.FACING, dir );
break;
if( !(tile instanceof TileSpeaker) ) return state;
return state.withProperty( Properties.FACING, ((TileSpeaker) tile).getDirection() );
}
case Monitor:
case AdvancedMonitor:
{
EnumFacing front;
int xIndex, yIndex, width, height;
if( tile instanceof TileMonitor )
{
TileMonitor monitor = (TileMonitor) tile;
dir = monitor.getDirection();
front = monitor.getFront();
xIndex = monitor.getXIndex();
yIndex = monitor.getYIndex();
width = monitor.getWidth();
height = monitor.getHeight();
}
else
{
dir = EnumFacing.NORTH;
front = EnumFacing.NORTH;
xIndex = 0;
yIndex = 0;
width = 1;
height = 1;
}
if( !(tile instanceof TileMonitor) ) return state;
TileMonitor monitor = (TileMonitor) tile;
EnumFacing dir = monitor.getDirection();
EnumFacing front = monitor.getFront();
int xIndex = monitor.getXIndex();
int yIndex = monitor.getYIndex();
int width = monitor.getWidth();
int height = monitor.getHeight();
BlockPeripheralVariant baseVariant;
if( front == EnumFacing.UP )
{
baseVariant = (type == PeripheralType.AdvancedMonitor) ?
baseVariant = type == PeripheralType.AdvancedMonitor ?
BlockPeripheralVariant.AdvancedMonitorUp :
BlockPeripheralVariant.MonitorUp;
}
else if( front == EnumFacing.DOWN )
{
baseVariant = (type == PeripheralType.AdvancedMonitor) ?
baseVariant = type == PeripheralType.AdvancedMonitor ?
BlockPeripheralVariant.AdvancedMonitorDown :
BlockPeripheralVariant.MonitorDown;
}
else
{
baseVariant = (type == PeripheralType.AdvancedMonitor) ?
baseVariant = type == PeripheralType.AdvancedMonitor ?
BlockPeripheralVariant.AdvancedMonitor :
BlockPeripheralVariant.Monitor;
}
@@ -447,34 +358,27 @@ public class BlockPeripheral extends BlockPeripheralBase
}
}
state = state.withProperty( Properties.FACING, dir );
state = state.withProperty( Properties.VARIANT,
BlockPeripheralVariant.values()[baseVariant.ordinal() + subType]
);
break;
return state
.withProperty( Properties.FACING, dir )
.withProperty( Properties.VARIANT, BlockPeripheralVariant.values()[baseVariant.ordinal() + subType] );
}
default:
return state;
}
return state;
}
@Nonnull
@Override
public IBlockState getDefaultBlockState( PeripheralType type, EnumFacing placedSide )
@Deprecated
public final IBlockState getStateForPlacement( World world, BlockPos pos, EnumFacing placedSide, float hitX, float hitY, float hitZ, int damage, EntityLivingBase placer )
{
switch( type )
switch( getPeripheralType( damage ) )
{
case DiskDrive:
default:
{
IBlockState state = getDefaultState().withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveEmpty );
if( placedSide.getAxis() != EnumFacing.Axis.Y )
{
return state.withProperty( Properties.FACING, placedSide );
}
else
{
return state.withProperty( Properties.FACING, EnumFacing.NORTH );
}
}
return getDefaultState()
.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveEmpty )
.withProperty( Properties.FACING, placedSide.getAxis() == EnumFacing.Axis.Y ? EnumFacing.NORTH : placedSide );
case WirelessModem:
{
EnumFacing dir = placedSide.getOpposite();
@@ -498,95 +402,63 @@ public class BlockPeripheral extends BlockPeripheralBase
}
}
case Monitor:
{
return getDefaultState().withProperty( Properties.VARIANT, BlockPeripheralVariant.Monitor );
}
case Printer:
{
return getDefaultState().withProperty( Properties.VARIANT, BlockPeripheralVariant.PrinterEmpty );
}
case AdvancedMonitor:
{
return getDefaultState().withProperty( Properties.VARIANT, BlockPeripheralVariant.AdvancedMonitor );
}
case Speaker:
{
return getDefaultState().withProperty( Properties.VARIANT, BlockPeripheralVariant.Speaker );
}
}
}
@Override
public PeripheralType getPeripheralType( int damage )
{
return ((ItemPeripheral) Item.getItemFromBlock( this )).getPeripheralType( damage );
return ComputerCraft.Items.peripheral.getPeripheralType( damage );
}
@Override
public PeripheralType getPeripheralType( IBlockState state )
{
return state.getValue( Properties.VARIANT ).getPeripheralType();
}
@Override
public TilePeripheralBase createTile( PeripheralType type )
private TileGeneric createTile( PeripheralType type )
{
switch( type )
{
case DiskDrive:
default:
{
return new TileDiskDrive();
}
case WirelessModem:
{
return new TileWirelessModem();
}
case Monitor:
case AdvancedMonitor:
{
return new TileMonitor();
}
case Printer:
{
return new TilePrinter();
}
case Speaker:
{
return new TileSpeaker();
}
}
}
@Override
public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase player, @Nonnull ItemStack stack )
{
// Not sure why this is necessary
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TilePeripheralBase )
{
tile.setWorld( world ); // Not sure why this is necessary
tile.setPos( pos ); // Not sure why this is necessary
}
switch( getPeripheralType( state ) )
{
case Speaker:
case DiskDrive:
case Printer:
{
EnumFacing dir = DirectionUtil.fromEntityRot( player );
setDirection( world, pos, dir );
if( stack.hasDisplayName() && tile instanceof TilePeripheralBase )
if( tile instanceof TilePeripheralBase )
{
TilePeripheralBase peripheral = (TilePeripheralBase) tile;
peripheral.setLabel( stack.getDisplayName() );
peripheral.setDirection( DirectionUtil.fromEntityRot( player ) );
if( stack.hasDisplayName() ) peripheral.setLabel( stack.getDisplayName() );
}
break;
}
case Monitor:
case AdvancedMonitor:
{
if( tile instanceof TileMonitor )
{
int direction = DirectionUtil.fromEntityRot( player ).getIndex();
@@ -613,7 +485,6 @@ public class BlockPeripheral extends BlockPeripheralBase
}
}
break;
}
}
}
@@ -667,13 +538,52 @@ public class BlockPeripheral extends BlockPeripheralBase
@Override
@Deprecated
public AxisAlignedBB getBoundingBox( IBlockState state, IBlockAccess source, BlockPos pos )
@Nonnull
public AxisAlignedBB getBoundingBox( IBlockState state, IBlockAccess world, BlockPos pos )
{
if( getPeripheralType( state ) == PeripheralType.WirelessModem )
{
return ModemBounds.getBounds( getDirection( source, pos ) );
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileWirelessModem )
{
return ModemBounds.getBounds( ((TileWirelessModem) tile).getDirection() );
}
}
return super.getBoundingBox( state, source, pos );
return super.getBoundingBox( state, world, pos );
}
@Override
public final boolean canPlaceBlockOnSide( @Nonnull World world, @Nonnull BlockPos pos, EnumFacing side )
{
return true; // ItemPeripheralBase handles this
}
@Override
public final TileGeneric createTile( IBlockState state )
{
return createTile( getPeripheralType( state ) );
}
@Override
public final TileGeneric createTile( int damage )
{
return createTile( getPeripheralType( damage ) );
}
@Nonnull
@Override
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
{
TileEntity tile = world.getTileEntity( pos );
return tile instanceof ITilePeripheral
? PeripheralItemFactory.create( (ITilePeripheral) tile )
: super.getPickBlock( state, target, world, pos, player );
}
@Override
public void getDrops( @Nonnull NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune )
{
drops.add( PeripheralItemFactory.create( getPeripheralType( state ), null, 1 ) );
}
}

View File

@@ -1,78 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.common;
import dan200.computercraft.shared.common.BlockDirectional;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public abstract class BlockPeripheralBase extends BlockDirectional
{
public BlockPeripheralBase()
{
super( Material.ROCK );
}
protected abstract IBlockState getDefaultBlockState( PeripheralType type, EnumFacing placedSide );
protected abstract PeripheralType getPeripheralType( int damage );
protected abstract PeripheralType getPeripheralType( IBlockState state );
protected abstract TilePeripheralBase createTile( PeripheralType type );
@Override
public final boolean canPlaceBlockOnSide( @Nonnull World world, @Nonnull BlockPos pos, EnumFacing side )
{
return true; // ItemPeripheralBase handles this
}
@Override
protected final IBlockState getDefaultBlockState( int damage, EnumFacing placedSide )
{
ItemPeripheralBase item = (ItemPeripheralBase) Item.getItemFromBlock( this );
return getDefaultBlockState( item.getPeripheralType( damage ), placedSide );
}
@Override
public final TileGeneric createTile( IBlockState state )
{
return createTile( getPeripheralType( state ) );
}
@Override
public final TileGeneric createTile( int damage )
{
return createTile( getPeripheralType( damage ) );
}
public final PeripheralType getPeripheralType( IBlockAccess world, BlockPos pos )
{
return getPeripheralType( world.getBlockState( pos ) );
}
@Nonnull
@Override
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
{
TileEntity tile = world.getTileEntity( pos );
return tile instanceof IPeripheralTile ? PeripheralItemFactory.create( (IPeripheralTile) tile ) : super.getPickBlock( state, target, world, pos, player );
}
}

View File

@@ -7,15 +7,9 @@
package dan200.computercraft.shared.peripheral.common;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.common.IDirectionalTile;
import dan200.computercraft.shared.peripheral.PeripheralType;
import net.minecraft.util.EnumFacing;
public interface IPeripheralTile extends IDirectionalTile
public interface IPeripheralTile
{
PeripheralType getPeripheralType();
IPeripheral getPeripheral( EnumFacing side );
String getLabel();
}

View File

@@ -0,0 +1,26 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.common;
import dan200.computercraft.shared.peripheral.PeripheralType;
/**
* The tile for {@link BlockPeripheral}.
*/
public interface ITilePeripheral
{
PeripheralType getPeripheralType();
default String getLabel()
{
return null;
}
default void setLabel( String label )
{
}
}

View File

@@ -8,9 +8,6 @@ package dan200.computercraft.shared.peripheral.common;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.modem.wired.ItemCable;
import dan200.computercraft.shared.peripheral.modem.wireless.ItemAdvancedModem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
@@ -18,7 +15,7 @@ import javax.annotation.Nonnull;
public class PeripheralItemFactory
{
@Nonnull
public static ItemStack create( IPeripheralTile tile )
public static ItemStack create( ITilePeripheral tile )
{
return create( tile.getPeripheralType(), tile.getLabel(), 1 );
}
@@ -26,9 +23,6 @@ public class PeripheralItemFactory
@Nonnull
public static ItemStack create( PeripheralType type, String label, int quantity )
{
ItemPeripheral peripheral = ((ItemPeripheral) Item.getItemFromBlock( ComputerCraft.Blocks.peripheral ));
ItemCable cable = ((ItemCable) Item.getItemFromBlock( ComputerCraft.Blocks.cable ));
ItemAdvancedModem advancedModem = ((ItemAdvancedModem) Item.getItemFromBlock( ComputerCraft.Blocks.advancedModem ));
switch( type )
{
case Speaker:
@@ -37,18 +31,12 @@ public class PeripheralItemFactory
case Monitor:
case AdvancedMonitor:
case WirelessModem:
{
return peripheral.create( type, label, quantity );
}
return ComputerCraft.Items.peripheral.create( type, label, quantity );
case WiredModem:
case Cable:
{
return cable.create( type, label, quantity );
}
return ComputerCraft.Items.cable.create( type, quantity );
case AdvancedModem:
{
return advancedModem.create( type, label, quantity );
}
return new ItemStack( ComputerCraft.Blocks.advancedModem, quantity );
case WiredModemFull:
return new ItemStack( ComputerCraft.Blocks.wiredModemFull, quantity );
}

View File

@@ -7,22 +7,18 @@
package dan200.computercraft.shared.peripheral.common;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.common.IDirectionalTile;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.NonNullList;
import javax.annotation.Nonnull;
public abstract class TilePeripheralBase extends TileGeneric
implements IPeripheralTile, ITickable
public abstract class TilePeripheralBase extends TileGeneric implements IPeripheralTile, ITickable, IDirectionalTile, ITilePeripheral
{
// Statics
protected EnumFacing m_dir;
private EnumFacing m_dir;
private int m_anim;
private boolean m_changed;
@@ -39,22 +35,11 @@ public abstract class TilePeripheralBase extends TileGeneric
@Override
public BlockPeripheralBase getBlock()
public BlockPeripheral getBlock()
{
return (BlockPeripheralBase) super.getBlock();
return (BlockPeripheral) super.getBlock();
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
if( !creative )
{
drops.add( PeripheralItemFactory.create( this ) );
}
}
// IPeripheralTile implementation
@Override
public final PeripheralType getPeripheralType()
{
@@ -77,6 +62,7 @@ public abstract class TilePeripheralBase extends TileGeneric
return null;
}
@Override
public void setLabel( String label )
{
m_label = label;
@@ -90,11 +76,6 @@ public abstract class TilePeripheralBase extends TileGeneric
return m_dir;
}
public EnumFacing getCachedDirection()
{
return m_dir;
}
@Override
public void setDirection( EnumFacing dir )
{
@@ -110,7 +91,7 @@ public abstract class TilePeripheralBase extends TileGeneric
return m_anim;
}
public void setAnim( int anim )
protected void setAnim( int anim )
{
if( anim != m_anim )
{

View File

@@ -181,21 +181,19 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa
int channel = parseChannel( arguments, 0 );
int replyChannel = parseChannel( arguments, 1 );
Object payload = arguments.length > 2 ? arguments[2] : null;
synchronized( this )
World world = getWorld();
Vec3d position = getPosition();
IPacketNetwork network = m_network;
if( world != null && position != null && network != null )
{
World world = getWorld();
Vec3d position = getPosition();
if( world != null && position != null && m_network != null )
Packet packet = new Packet( channel, replyChannel, payload, this );
if( isInterdimensional() )
{
Packet packet = new Packet( channel, replyChannel, payload, this );
if( isInterdimensional() )
{
m_network.transmitInterdimensional( packet );
}
else
{
m_network.transmitSameDimension( packet, getRange() );
}
network.transmitInterdimensional( packet );
}
else
{
network.transmitSameDimension( packet, getRange() );
}
}
return null;

View File

@@ -14,16 +14,27 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class ModemState
{
private boolean open = false;
private AtomicBoolean changed = new AtomicBoolean( true );
private final Runnable onChanged;
private final AtomicBoolean changed = new AtomicBoolean( true );
private boolean open = false;
private final IntSet channels = new IntOpenHashSet();
public ModemState()
{
this.onChanged = null;
}
public ModemState( Runnable onChanged )
{
this.onChanged = onChanged;
}
private void setOpen( boolean open )
{
if( this.open == open ) return;
this.open = open;
this.changed.set( true );
if( !changed.getAndSet( true ) && onChanged != null ) onChanged.run();
}
public boolean pollChanged()

View File

@@ -1,80 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.modem;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import javax.annotation.Nonnull;
public abstract class TileModemBase extends TilePeripheralBase
{
protected ModemPeripheral m_modem;
protected TileModemBase()
{
m_modem = createPeripheral();
}
protected abstract ModemPeripheral createPeripheral();
@Override
public void destroy()
{
if( m_modem != null )
{
m_modem.destroy();
m_modem = null;
}
}
@Override
public void onNeighbourChange()
{
EnumFacing dir = getDirection();
if( !getWorld().isSideSolid( getPos().offset( dir ), dir.getOpposite() ) )
{
// Drop everything and remove block
((BlockGeneric) getBlockType()).dropAllItems( getWorld(), getPos(), false );
getWorld().setBlockToAir( getPos() );
}
}
@Override
public void update()
{
super.update();
if( !getWorld().isRemote && m_modem.getModemState().pollChanged() )
{
updateAnim();
}
}
protected void updateAnim()
{
setAnim( m_modem.getModemState().isOpen() ? 1 : 0 );
}
@Override
public final void readDescription( @Nonnull NBTTagCompound nbt )
{
super.readDescription( nbt );
updateBlock();
}
// IPeripheralTile implementation
@Override
public IPeripheral getPeripheral( EnumFacing side )
{
return side == getDirection() ? m_modem : null;
}
}

View File

@@ -9,11 +9,13 @@ package dan200.computercraft.shared.peripheral.modem.wired;
import com.google.common.collect.ImmutableMap;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.BlockPeripheralBase;
import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockFaceShape;
@@ -22,10 +24,10 @@ import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
@@ -39,7 +41,7 @@ import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
public class BlockCable extends BlockPeripheralBase
public class BlockCable extends BlockGeneric
{
// Statics
@@ -66,6 +68,7 @@ public class BlockCable extends BlockPeripheralBase
public BlockCable()
{
super( Material.ROCK );
setHardness( 1.5f );
setTranslationKey( "computercraft:cable" );
setCreativeTab( ComputerCraft.mainCreativeTab );
@@ -142,10 +145,12 @@ public class BlockCable extends BlockPeripheralBase
return meta;
}
@Override
public IBlockState getDefaultBlockState( PeripheralType type, EnumFacing placedSide )
@Deprecated
public final IBlockState getStateForPlacement( World world, BlockPos pos, EnumFacing placedSide, float hitX, float hitY, float hitZ, int damage, EntityLivingBase placer )
{
switch( type )
switch( ComputerCraft.Items.cable.getPeripheralType( damage ) )
{
case Cable:
return getDefaultState()
@@ -190,7 +195,7 @@ public class BlockCable extends BlockPeripheralBase
.withProperty( Properties.DOWN, doesConnectVisually( state, world, pos, EnumFacing.DOWN ) );
TileEntity tile = world.getTileEntity( pos );
int anim = tile instanceof TilePeripheralBase ? ((TilePeripheralBase) tile).getAnim() : 0;
int anim = tile instanceof TileCable ? ((TileCable) tile).getState() : 0;
BlockCableModemVariant modem = state.getValue( Properties.MODEM );
if( modem != BlockCableModemVariant.None )
@@ -209,13 +214,6 @@ public class BlockCable extends BlockPeripheralBase
return true;
}
@Override
public PeripheralType getPeripheralType( int damage )
{
return ((ItemCable) Item.getItemFromBlock( this )).getPeripheralType( damage );
}
@Override
public PeripheralType getPeripheralType( IBlockState state )
{
boolean cable = state.getValue( Properties.CABLE );
@@ -235,7 +233,13 @@ public class BlockCable extends BlockPeripheralBase
}
@Override
public TilePeripheralBase createTile( PeripheralType type )
protected TileGeneric createTile( IBlockState state )
{
return new TileCable();
}
@Override
protected TileGeneric createTile( int damage )
{
return new TileCable();
}
@@ -320,7 +324,10 @@ public class BlockCable extends BlockPeripheralBase
cable.modemChanged();
cable.connectionsChanged();
if( !world.isRemote && !player.capabilities.isCreativeMode ) dropItem( world, pos, item );
if( !world.isRemote && !player.capabilities.isCreativeMode )
{
Block.spawnAsEntity( world, pos, item );
}
return false;
}
@@ -330,6 +337,23 @@ public class BlockCable extends BlockPeripheralBase
return super.removedByPlayer( state, world, pos, player, willHarvest );
}
@Override
public void getDrops( @Nonnull NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune )
{
PeripheralType type = getPeripheralType( state );
switch( type )
{
case Cable:
case WiredModem:
drops.add( PeripheralItemFactory.create( type, null, 1 ) );
break;
case WiredModemWithCable:
drops.add( PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 ) );
drops.add( PeripheralItemFactory.create( PeripheralType.Cable, null, 1 ) );
break;
}
}
@Nonnull
@Override
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult hit, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
@@ -381,4 +405,11 @@ public class BlockCable extends BlockPeripheralBase
{
return BlockFaceShape.UNDEFINED;
}
@Override
@Deprecated
public boolean hasCustomBreakingProgress( IBlockState state )
{
return true;
}
}

View File

@@ -7,20 +7,19 @@
package dan200.computercraft.shared.peripheral.modem.wired;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.BlockPeripheralBase;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.common.TileGeneric;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import javax.annotation.Nonnull;
public class BlockWiredModemFull extends BlockPeripheralBase
public class BlockWiredModemFull extends BlockGeneric
{
// Statics
@@ -34,6 +33,7 @@ public class BlockWiredModemFull extends BlockPeripheralBase
public BlockWiredModemFull()
{
super( Material.ROCK );
setHardness( 1.5f );
setTranslationKey( "computercraft:wired_modem_full" );
setCreativeTab( ComputerCraft.mainCreativeTab );
@@ -43,12 +43,6 @@ public class BlockWiredModemFull extends BlockPeripheralBase
);
}
@Override
protected IBlockState getDefaultBlockState( PeripheralType type, EnumFacing placedSide )
{
return getDefaultState();
}
@Nonnull
@Override
protected BlockStateContainer createBlockState()
@@ -74,7 +68,7 @@ public class BlockWiredModemFull extends BlockPeripheralBase
if( te instanceof TileWiredModemFull )
{
TileWiredModemFull modem = (TileWiredModemFull) te;
int anim = modem.getAnim();
int anim = modem.getState();
state = state
.withProperty( Properties.MODEM_ON, (anim & 1) != 0 )
.withProperty( Properties.PERIPHERAL_ON, (anim & 2) != 0 );
@@ -84,19 +78,13 @@ public class BlockWiredModemFull extends BlockPeripheralBase
}
@Override
public PeripheralType getPeripheralType( int damage )
protected TileGeneric createTile( IBlockState state )
{
return PeripheralType.WiredModemFull;
return new TileWiredModemFull();
}
@Override
public PeripheralType getPeripheralType( IBlockState state )
{
return PeripheralType.WiredModemFull;
}
@Override
public TilePeripheralBase createTile( PeripheralType type )
protected TileGeneric createTile( int damage )
{
return new TileWiredModemFull();
}

View File

@@ -34,7 +34,7 @@ public class ItemCable extends ItemPeripheralBase
}
@Nonnull
public ItemStack create( PeripheralType type, String label, int quantity )
public ItemStack create( PeripheralType type, int quantity )
{
ItemStack stack;
switch( type )
@@ -54,10 +54,7 @@ public class ItemCable extends ItemPeripheralBase
return ItemStack.EMPTY;
}
}
if( label != null )
{
stack.setStackDisplayName( label );
}
return stack;
}
@@ -81,11 +78,11 @@ public class ItemCable extends ItemPeripheralBase
// Try to add a cable to a modem
PeripheralType type = getPeripheralType( stack );
Block existing = world.getBlockState( pos ).getBlock();
IBlockState existingState = world.getBlockState( pos );
Block existing = existingState.getBlock();
if( existing == ComputerCraft.Blocks.cable )
{
PeripheralType existingType = ComputerCraft.Blocks.cable.getPeripheralType( world, pos );
PeripheralType existingType = ComputerCraft.Blocks.cable.getPeripheralType( existingState );
if( existingType == PeripheralType.WiredModem && type == PeripheralType.Cable )
{
if( !stack.isEmpty() )
@@ -112,12 +109,12 @@ public class ItemCable extends ItemPeripheralBase
if( !existing.isAir( existingState, world, pos ) && (type == PeripheralType.Cable || existingState.isSideSolid( world, pos, side )) )
{
BlockPos offset = pos.offset( side );
Block offsetExisting = world.getBlockState( offset ).getBlock();
IBlockState offsetExistingState = world.getBlockState( offset );
Block offsetExisting = offsetExistingState.getBlock();
if( offsetExisting == ComputerCraft.Blocks.cable )
{
// Try to add a modem to a cable
PeripheralType offsetExistingType = ComputerCraft.Blocks.cable.getPeripheralType( world, offset );
PeripheralType offsetExistingType = ComputerCraft.Blocks.cable.getPeripheralType( offsetExistingState );
if( offsetExistingType == PeripheralType.Cable && type == PeripheralType.WiredModem )
{
if( !stack.isEmpty() )

View File

@@ -7,25 +7,25 @@
package dan200.computercraft.shared.peripheral.modem.wired;
import com.google.common.base.Objects;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.command.CommandCopy;
import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.IPeripheralTile;
import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory;
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.peripheral.modem.TileModemBase;
import dan200.computercraft.shared.util.TickScheduler;
import dan200.computercraft.shared.wired.CapabilityWiredElement;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentTranslation;
@@ -37,42 +37,35 @@ import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Map;
public class TileCable extends TileModemBase
public class TileCable extends TileGeneric implements IPeripheralTile
{
private static class CableElement extends WiredModemElement
private class CableElement extends WiredModemElement
{
private final TileCable m_entity;
private CableElement( TileCable m_entity )
{
this.m_entity = m_entity;
}
@Nonnull
@Override
public World getWorld()
{
return m_entity.getWorld();
return TileCable.this.getWorld();
}
@Nonnull
@Override
public Vec3d getPosition()
{
BlockPos pos = m_entity.getPos();
BlockPos pos = TileCable.this.getPos();
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
}
@Override
protected void attachPeripheral( String name, IPeripheral peripheral )
{
((WiredModemPeripheral) m_entity.m_modem).attachPeripheral( name, peripheral );
m_modem.attachPeripheral( name, peripheral );
}
@Override
protected void detachPeripheral( String name )
{
((WiredModemPeripheral) m_entity.m_modem).detachPeripheral( name );
m_modem.detachPeripheral( name );
}
}
@@ -83,35 +76,35 @@ public class TileCable extends TileModemBase
private boolean m_destroyed = false;
private boolean m_hasDirection = false;
private EnumFacing modemDirection;
private boolean hasModemDirection = false;
private boolean m_connectionsFormed = false;
private WiredModemElement m_cable;
private IWiredNode m_node;
@Override
protected ModemPeripheral createPeripheral()
private final WiredModemElement m_cable = new CableElement();
private final IWiredNode m_node = m_cable.getNode();
private final WiredModemPeripheral m_modem = new WiredModemPeripheral(
new ModemState( () -> TickScheduler.schedule( this ) ),
m_cable
)
{
m_cable = new CableElement( this );
m_node = m_cable.getNode();
return new WiredModemPeripheral( new ModemState(), m_cable )
@Nonnull
@Override
protected WiredModemLocalPeripheral getLocalPeripheral()
{
@Nonnull
@Override
protected WiredModemLocalPeripheral getLocalPeripheral()
{
return m_peripheral;
}
return m_peripheral;
}
@Nonnull
@Override
public Vec3d getPosition()
{
BlockPos pos = getPos().offset( getCachedDirection() );
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
}
};
}
@Nonnull
@Override
public Vec3d getPosition()
{
BlockPos pos = getPos().offset( modemDirection );
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
}
};
private int m_state = 0;
private void remove()
{
@@ -128,9 +121,9 @@ public class TileCable extends TileModemBase
if( !m_destroyed )
{
m_destroyed = true;
m_modem.destroy();
remove();
}
super.destroy();
}
@Override
@@ -151,26 +144,31 @@ public class TileCable extends TileModemBase
public void onLoad()
{
super.onLoad();
updateDirection();
if( !world.isRemote )
{
updateDirection();
world.scheduleUpdate( pos, getBlockType(), 0 );
}
}
@Override
public void updateContainingBlockInfo()
{
m_hasDirection = false;
super.updateContainingBlockInfo();
hasModemDirection = false;
if( !world.isRemote ) world.scheduleUpdate( pos, getBlockType(), 0 );
}
private void updateDirection()
{
if( !m_hasDirection )
if( !hasModemDirection )
{
m_hasDirection = true;
m_dir = getDirection();
hasModemDirection = true;
modemDirection = getDirection();
}
}
@Override
public EnumFacing getDirection()
private EnumFacing getDirection()
{
IBlockState state = getBlockState();
EnumFacing facing = state.getValue( BlockCable.Properties.MODEM ).getFacing();
@@ -178,55 +176,17 @@ public class TileCable extends TileModemBase
}
@Override
public void setDirection( EnumFacing dir )
{
IBlockState state = getBlockState();
BlockCableModemVariant modem = state.getValue( BlockCable.Properties.MODEM );
if( modem != BlockCableModemVariant.None )
{
setBlockState( state.withProperty( BlockCable.Properties.MODEM, BlockCableModemVariant.fromFacing( dir ) ) );
}
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
if( !creative )
{
PeripheralType type = getPeripheralType();
switch( type )
{
case Cable:
case WiredModem:
{
drops.add( PeripheralItemFactory.create( type, getLabel(), 1 ) );
break;
}
case WiredModemWithCable:
{
drops.add( PeripheralItemFactory.create( PeripheralType.WiredModem, getLabel(), 1 ) );
drops.add( PeripheralItemFactory.create( PeripheralType.Cable, null, 1 ) );
break;
}
}
}
}
@Override
public void onNeighbourChange()
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
EnumFacing dir = getDirection();
if( !getWorld().isSideSolid(
getPos().offset( dir ),
dir.getOpposite()
) )
if( neighbour.equals( getPos().offset( dir ) ) && !getWorld().isSideSolid( neighbour, dir.getOpposite() ) )
{
switch( getPeripheralType() )
{
case WiredModem:
{
// Drop everything and remove block
((BlockGeneric) getBlockType()).dropAllItems( getWorld(), getPos(), false );
getBlock().dropBlockAsItem( getWorld(), getPos(), getBlockState(), 0 );
getWorld().setBlockToAir( getPos() );
// This'll call #destroy(), so we don't need to reset the network here.
@@ -235,8 +195,7 @@ public class TileCable extends TileModemBase
case WiredModemWithCable:
{
// Drop the modem and convert to cable
((BlockGeneric) getBlockType()).dropItem( getWorld(), getPos(), PeripheralItemFactory.create( PeripheralType.WiredModem, getLabel(), 1 ) );
setLabel( null );
Block.spawnAsEntity( getWorld(), getPos(), PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 ) );
setBlockState( getBlockState().withProperty( BlockCable.Properties.MODEM, BlockCableModemVariant.None ) );
modemChanged();
connectionsChanged();
@@ -328,21 +287,46 @@ public class TileCable extends TileModemBase
}
@Override
protected void updateAnim()
protected void writeDescription( @Nonnull NBTTagCompound nbt )
{
int anim = 0;
if( m_modem.getModemState().isOpen() ) anim |= 1;
if( m_peripheralAccessAllowed ) anim |= 2;
setAnim( anim );
super.writeDescription( nbt );
nbt.setInteger( "state", m_state );
}
@Override
public void update()
public final void readDescription( @Nonnull NBTTagCompound nbt )
{
super.readDescription( nbt );
m_state = nbt.getInteger( "state" );
updateBlock();
}
public int getState()
{
return m_state;
}
private void updateState()
{
int state = 0;
if( m_modem.getModemState().isOpen() ) state |= 1;
if( m_peripheralAccessAllowed ) state |= 2;
if( state != m_state )
{
m_state = state;
updateBlock();
}
}
@Override
protected void updateTick()
{
super.update();
updateDirection();
if( !getWorld().isRemote )
{
updateDirection();
if( m_modem.getModemState().pollChanged() ) updateState();
if( !m_connectionsFormed )
{
m_connectionsFormed = true;
@@ -350,7 +334,7 @@ public class TileCable extends TileModemBase
connectionsChanged();
if( m_peripheralAccessAllowed )
{
m_peripheral.attach( world, pos, m_dir );
m_peripheral.attach( world, pos, modemDirection );
updateConnectedPeripherals();
}
}
@@ -396,7 +380,7 @@ public class TileCable extends TileModemBase
m_peripheral.detach();
m_node.updatePeripherals( Collections.emptyMap() );
markDirty();
updateAnim();
updateState();
}
}
@@ -419,7 +403,7 @@ public class TileCable extends TileModemBase
m_node.updatePeripherals( Collections.emptyMap() );
}
updateAnim();
updateState();
}
private void updateConnectedPeripherals()
@@ -429,7 +413,7 @@ public class TileCable extends TileModemBase
{
// If there are no peripherals then disable access and update the display state.
m_peripheralAccessAllowed = false;
updateAnim();
updateState();
}
m_node.updatePeripherals( peripherals );
@@ -441,12 +425,14 @@ public class TileCable extends TileModemBase
return true;
}
// IWiredElement capability
@Override
public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing facing )
{
if( capability == CapabilityWiredElement.CAPABILITY ) return BlockCable.canConnectIn( getBlockState(), facing );
if( capability == CapabilityWiredElement.CAPABILITY )
{
return !m_destroyed && BlockCable.canConnectIn( getBlockState(), facing );
}
return super.hasCapability( capability, facing );
}
@@ -456,21 +442,23 @@ public class TileCable extends TileModemBase
{
if( capability == CapabilityWiredElement.CAPABILITY )
{
return BlockCable.canConnectIn( getBlockState(), facing ) ? CapabilityWiredElement.CAPABILITY.cast( m_cable ) : null;
return !m_destroyed && BlockCable.canConnectIn( getBlockState(), facing )
? CapabilityWiredElement.CAPABILITY.cast( m_cable )
: null;
}
return super.getCapability( capability, facing );
}
// IPeripheralTile
@Override
public IPeripheral getPeripheral( EnumFacing side )
{
if( getPeripheralType() != PeripheralType.Cable )
{
return super.getPeripheral( side );
}
return null;
return !m_destroyed && getPeripheralType() != PeripheralType.Cable && side == getDirection() ? m_modem : null;
}
public PeripheralType getPeripheralType()
{
IBlockState state = getBlockState();
return ComputerCraft.Blocks.cable.getPeripheralType( state );
}
}

View File

@@ -12,8 +12,10 @@ import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.command.CommandCopy;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.common.IPeripheralTile;
import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.util.TickScheduler;
import dan200.computercraft.shared.wired.CapabilityWiredElement;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
@@ -30,7 +32,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class TileWiredModemFull extends TilePeripheralBase
public class TileWiredModemFull extends TileGeneric implements IPeripheralTile
{
private static class FullElement extends WiredModemElement
{
@@ -85,10 +87,12 @@ public class TileWiredModemFull extends TilePeripheralBase
private boolean m_destroyed = false;
private boolean m_connectionsFormed = false;
private final ModemState m_modemState = new ModemState();
private final ModemState m_modemState = new ModemState( () -> TickScheduler.schedule( this ) );
private final WiredModemElement m_element = new FullElement( this );
private final IWiredNode m_node = m_element.getNode();
private int m_state = 0;
public TileWiredModemFull()
{
for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i] = new WiredModemLocalPeripheral();
@@ -129,29 +133,9 @@ public class TileWiredModemFull extends TilePeripheralBase
}
@Override
public EnumFacing getDirection()
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
return EnumFacing.NORTH;
}
@Override
public void setDirection( EnumFacing dir )
{
}
@Override
public void onNeighbourChange()
{
if( !world.isRemote && m_peripheralAccessAllowed )
{
boolean hasChanged = false;
for( EnumFacing facing : EnumFacing.VALUES )
{
hasChanged |= m_peripherals[facing.ordinal()].attach( world, getPos(), facing );
}
if( hasChanged ) updateConnectedPeripherals();
}
onNeighbourTileEntityChange( neighbour );
}
@Override
@@ -231,27 +215,51 @@ public class TileWiredModemFull extends TilePeripheralBase
return nbt;
}
protected void updateAnim()
public int getState()
{
int anim = 0;
if( m_modemState.isOpen() ) anim |= 1;
if( m_peripheralAccessAllowed ) anim |= 2;
setAnim( anim );
return m_state;
}
private void updateState()
{
int state = 0;
if( m_modemState.isOpen() ) state |= 1;
if( m_peripheralAccessAllowed ) state |= 2;
if( state != m_state )
{
m_state = state;
updateBlock();
}
}
@Override
protected void writeDescription( @Nonnull NBTTagCompound nbt )
{
super.writeDescription( nbt );
nbt.setInteger( "state", m_state );
}
@Override
public final void readDescription( @Nonnull NBTTagCompound nbt )
{
super.readDescription( nbt );
m_state = nbt.getInteger( "state" );
updateBlock();
}
@Override
public void update()
public void onLoad()
{
super.onLoad();
if( !world.isRemote ) world.scheduleUpdate( pos, getBlockType(), 0 );
}
@Override
protected void updateTick()
{
if( !getWorld().isRemote )
{
if( m_modemState.pollChanged() ) updateAnim();
if( m_modemState.pollChanged() ) updateState();
if( !m_connectionsFormed )
{
@@ -268,8 +276,6 @@ public class TileWiredModemFull extends TilePeripheralBase
}
}
}
super.update();
}
private void connectionsChanged()
@@ -291,7 +297,6 @@ public class TileWiredModemFull extends TilePeripheralBase
}
}
// private stuff
private void togglePeripheralAccess()
{
if( !m_peripheralAccessAllowed )
@@ -317,7 +322,7 @@ public class TileWiredModemFull extends TilePeripheralBase
m_node.updatePeripherals( Collections.emptyMap() );
}
updateAnim();
updateState();
}
private Set<String> getConnectedPeripheralNames()
@@ -349,7 +354,7 @@ public class TileWiredModemFull extends TilePeripheralBase
{
// If there are no peripherals then disable access and update the display state.
m_peripheralAccessAllowed = false;
updateAnim();
updateState();
}
m_node.updatePeripherals( peripherals );
@@ -360,7 +365,8 @@ public class TileWiredModemFull extends TilePeripheralBase
@Override
public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing facing )
{
return capability == CapabilityWiredElement.CAPABILITY || super.hasCapability( capability, facing );
if( capability == CapabilityWiredElement.CAPABILITY ) return !m_destroyed;
return super.hasCapability( capability, facing );
}
@Nullable
@@ -369,17 +375,18 @@ public class TileWiredModemFull extends TilePeripheralBase
{
if( capability == CapabilityWiredElement.CAPABILITY )
{
if( m_destroyed ) return null;
return CapabilityWiredElement.CAPABILITY.cast( m_element );
}
return super.getCapability( capability, facing );
}
// IPeripheralTile
@Override
public IPeripheral getPeripheral( EnumFacing side )
{
if( m_destroyed ) return null;
WiredModemPeripheral peripheral = m_modems[side.ordinal()];
if( peripheral == null )
{

View File

@@ -19,7 +19,6 @@ 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;
@@ -66,10 +65,7 @@ public final class WiredModemLocalPeripheral
else if( id < 0 || !type.equals( this.type ) )
{
this.type = type;
this.id = IDAssigner.getNextIDFromFile( new File(
ComputerCraft.getWorldDir( world ),
"computer/lastid_" + type + ".txt"
) );
this.id = IDAssigner.getNextIDFromFile( "computer/lastid_" + type + ".txt" );
}
return oldPeripheral == null || !oldPeripheral.equals( peripheral );

View File

@@ -7,33 +7,37 @@
package dan200.computercraft.shared.peripheral.modem.wireless;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.BlockPeripheralBase;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.modem.ModemBounds;
import net.minecraft.block.BlockDirectional;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public class BlockAdvancedModem extends BlockPeripheralBase
public class BlockAdvancedModem extends BlockGeneric
{
public static class Properties
{
public static final PropertyDirection FACING = PropertyDirection.create( "facing" );
public static final PropertyDirection FACING = BlockDirectional.FACING;
public static final PropertyBool ON = PropertyBool.create( "on" );
}
public BlockAdvancedModem()
{
super( Material.ROCK );
setHardness( 2.0f );
setTranslationKey( "computercraft:advanced_modem" );
setCreativeTab( ComputerCraft.mainCreativeTab );
@@ -55,17 +59,13 @@ public class BlockAdvancedModem extends BlockPeripheralBase
@Deprecated
public IBlockState getStateFromMeta( int meta )
{
IBlockState state = getDefaultState();
state = state.withProperty( Properties.FACING, EnumFacing.byIndex( meta ) );
state = state.withProperty( Properties.ON, false );
return state;
return getDefaultState().withProperty( Properties.FACING, EnumFacing.byIndex( meta ) );
}
@Override
public int getMetaFromState( IBlockState state )
{
EnumFacing dir = state.getValue( Properties.FACING );
return dir.getIndex();
return state.getValue( Properties.FACING ).getIndex();
}
@Nonnull
@@ -73,47 +73,26 @@ public class BlockAdvancedModem extends BlockPeripheralBase
@Deprecated
public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos )
{
int anim;
EnumFacing dir;
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TilePeripheralBase )
{
TilePeripheralBase peripheral = (TilePeripheralBase) tile;
anim = peripheral.getAnim();
dir = peripheral.getDirection();
}
else
{
anim = 0;
dir = state.getValue( Properties.FACING );
}
state = state.withProperty( Properties.FACING, dir );
state = state.withProperty( Properties.ON, anim > 0 );
return state;
return state.withProperty( Properties.ON, tile instanceof TileAdvancedModem && ((TileAdvancedModem) tile).isOn() );
}
@Nonnull
@Override
public IBlockState getDefaultBlockState( PeripheralType type, EnumFacing placedSide )
@Deprecated
public IBlockState getStateForPlacement( World worldIn, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer )
{
EnumFacing dir = placedSide.getOpposite();
return getDefaultState().withProperty( Properties.FACING, dir );
return getDefaultState().withProperty( Properties.FACING, facing.getOpposite() );
}
@Override
public PeripheralType getPeripheralType( int damage )
protected TileGeneric createTile( IBlockState state )
{
return PeripheralType.AdvancedModem;
return new TileAdvancedModem();
}
@Override
public PeripheralType getPeripheralType( IBlockState state )
{
return PeripheralType.AdvancedModem;
}
@Override
public TilePeripheralBase createTile( PeripheralType type )
protected TileGeneric createTile( int damage )
{
return new TileAdvancedModem();
}
@@ -140,6 +119,7 @@ public class BlockAdvancedModem extends BlockPeripheralBase
return BlockFaceShape.UNDEFINED;
}
@Nonnull
@Override
@Deprecated
public AxisAlignedBB getBoundingBox( IBlockState state, IBlockAccess source, BlockPos pos )

View File

@@ -27,30 +27,6 @@ public class ItemAdvancedModem extends ItemPeripheralBase
setCreativeTab( ComputerCraft.mainCreativeTab );
}
@Nonnull
public ItemStack create( PeripheralType type, String label, int quantity )
{
ItemStack stack;
switch( type )
{
case AdvancedModem:
{
stack = new ItemStack( this, quantity, 0 );
break;
}
default:
{
// Ignore types we can't handle
return ItemStack.EMPTY;
}
}
if( label != null )
{
stack.setStackDisplayName( label );
}
return stack;
}
@Override
public void getSubItems( @Nullable CreativeTabs tabs, @Nonnull NonNullList<ItemStack> list )
{

View File

@@ -6,116 +6,18 @@
package dan200.computercraft.shared.peripheral.modem.wireless;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.peripheral.modem.TileModemBase;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public class TileAdvancedModem extends TileModemBase
public class TileAdvancedModem extends TileWirelessModemBase
{
// Statics
private static class Peripheral extends WirelessModemPeripheral
{
private TileModemBase m_entity;
public Peripheral( TileModemBase entity )
{
super( new ModemState(), true );
m_entity = entity;
}
@Nonnull
@Override
public World getWorld()
{
return m_entity.getWorld();
}
@Nonnull
@Override
public Vec3d getPosition()
{
BlockPos pos = m_entity.getPos().offset( m_entity.getCachedDirection() );
return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
}
@Override
public boolean equals( IPeripheral other )
{
if( other instanceof Peripheral )
{
Peripheral otherModem = (Peripheral) other;
return otherModem.m_entity == m_entity;
}
return false;
}
}
// Members
private boolean m_hasDirection = false;
public TileAdvancedModem()
{
m_dir = EnumFacing.DOWN;
super( true );
}
@Override
public void onLoad()
protected EnumFacing getDirection()
{
super.onLoad();
updateDirection();
}
@Override
public void updateContainingBlockInfo()
{
m_hasDirection = false;
}
@Override
public void update()
{
super.update();
updateDirection();
}
private void updateDirection()
{
if( !m_hasDirection )
{
m_hasDirection = true;
m_dir = getDirection();
}
}
@Override
public EnumFacing getDirection()
{
// Wireless Modem
IBlockState state = getBlockState();
return state.getValue( BlockAdvancedModem.Properties.FACING );
}
@Override
public void setDirection( EnumFacing dir )
{
// Wireless Modem
setBlockState( getBlockState()
.withProperty( BlockAdvancedModem.Properties.FACING, dir )
);
}
@Override
protected ModemPeripheral createPeripheral()
{
return new Peripheral( this );
return getBlockState().getValue( BlockAdvancedModem.Properties.FACING );
}
}

View File

@@ -7,98 +7,23 @@
package dan200.computercraft.shared.peripheral.modem.wireless;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.common.IDirectionalTile;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.BlockPeripheralVariant;
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.peripheral.modem.TileModemBase;
import dan200.computercraft.shared.peripheral.common.ITilePeripheral;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public class TileWirelessModem extends TileModemBase
public class TileWirelessModem extends TileWirelessModemBase implements IDirectionalTile, ITilePeripheral
{
// Statics
private static class Peripheral extends WirelessModemPeripheral
{
private TileModemBase m_entity;
public Peripheral( TileModemBase entity )
{
super( new ModemState(), false );
m_entity = entity;
}
@Nonnull
@Override
public World getWorld()
{
return m_entity.getWorld();
}
@Nonnull
@Override
public Vec3d getPosition()
{
BlockPos pos = m_entity.getPos().offset( m_entity.getCachedDirection() );
return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
}
@Override
public boolean equals( IPeripheral other )
{
if( other instanceof Peripheral )
{
Peripheral otherModem = (Peripheral) other;
return otherModem.m_entity == m_entity;
}
return false;
}
}
// Members
private boolean m_hasDirection = false;
public TileWirelessModem()
{
m_dir = EnumFacing.DOWN;
}
@Override
public void onLoad()
{
super.onLoad();
updateDirection();
}
@Override
public void updateContainingBlockInfo()
{
m_hasDirection = false;
}
@Override
public void update()
{
super.update();
updateDirection();
}
private void updateDirection()
{
if( !m_hasDirection )
{
m_hasDirection = true;
m_dir = getDirection();
}
super( false );
}
@Override
@@ -110,18 +35,12 @@ public class TileWirelessModem extends TileModemBase
{
case WirelessModemDownOff:
case WirelessModemDownOn:
{
return EnumFacing.DOWN;
}
case WirelessModemUpOff:
case WirelessModemUpOn:
{
return EnumFacing.UP;
}
default:
{
return state.getValue( BlockPeripheral.Properties.FACING );
}
}
}
@@ -152,15 +71,15 @@ public class TileWirelessModem extends TileModemBase
}
}
@Override
protected ModemPeripheral createPeripheral()
{
return new Peripheral( this );
}
@Override
public boolean shouldRefresh( World world, BlockPos pos, @Nonnull IBlockState oldState, @Nonnull IBlockState newState )
{
return super.shouldRefresh( world, pos, oldState, newState ) || ComputerCraft.Blocks.peripheral.getPeripheralType( newState ) != PeripheralType.WirelessModem;
}
@Override
public PeripheralType getPeripheralType()
{
return PeripheralType.WirelessModem;
}
}

View File

@@ -0,0 +1,161 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.modem.wireless;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.common.IPeripheralTile;
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.util.TickScheduler;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public abstract class TileWirelessModemBase extends TileGeneric implements IPeripheralTile
{
protected TileWirelessModemBase( boolean advanced )
{
this.advanced = advanced;
this.modem = new Peripheral( this ); // Needs to be initialised after advanced
}
private static class Peripheral extends WirelessModemPeripheral
{
private final TileWirelessModemBase entity;
Peripheral( TileWirelessModemBase entity )
{
super( new ModemState( () -> TickScheduler.schedule( entity ) ), entity.advanced );
this.entity = entity;
}
@Nonnull
@Override
public World getWorld()
{
return entity.getWorld();
}
@Nonnull
@Override
public Vec3d getPosition()
{
BlockPos pos = entity.getPos().offset( entity.modemDirection );
return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
}
@Override
public boolean equals( IPeripheral other )
{
return this == other;
}
}
private final boolean advanced;
private boolean hasModemDirection = false;
private EnumFacing modemDirection = EnumFacing.DOWN;
private final ModemPeripheral modem;
private boolean destroyed = false;
private boolean on = false;
@Override
public void onLoad()
{
super.onLoad();
updateDirection();
world.scheduleUpdate( getPos(), getBlockType(), 0 );
}
@Override
public void destroy()
{
if( !destroyed )
{
modem.destroy();
destroyed = true;
}
}
@Override
public void updateContainingBlockInfo()
{
hasModemDirection = false;
super.updateContainingBlockInfo();
world.scheduleUpdate( getPos(), getBlockType(), 0 );
}
@Override
public void updateTick()
{
updateDirection();
if( modem.getModemState().pollChanged() )
{
boolean newOn = modem.getModemState().isOpen();
if( newOn != on )
{
on = newOn;
updateBlock();
}
}
}
private void updateDirection()
{
if( !hasModemDirection )
{
hasModemDirection = true;
modemDirection = getDirection();
}
}
protected abstract EnumFacing getDirection();
@Override
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
EnumFacing dir = getDirection();
if( neighbour.equals( getPos().offset( dir ) ) && !getWorld().isSideSolid( neighbour, dir.getOpposite() ) )
{
// Drop everything and remove block
getBlock().dropBlockAsItem( getWorld(), getPos(), getBlockState(), 0 );
getWorld().setBlockToAir( getPos() );
}
}
@Override
protected void writeDescription( @Nonnull NBTTagCompound nbt )
{
super.writeDescription( nbt );
nbt.setBoolean( "on", on );
}
@Override
public final void readDescription( @Nonnull NBTTagCompound nbt )
{
super.readDescription( nbt );
on = nbt.getBoolean( "on" );
updateBlock();
}
public boolean isOn()
{
return on;
}
@Override
public IPeripheral getPeripheral( EnumFacing side )
{
return !destroyed && side == getDirection() ? modem : null;
}
}

View File

@@ -28,8 +28,6 @@ public class MonitorPeripheral implements IPeripheral
m_monitor = monitor;
}
// IPeripheral implementation
@Nonnull
@Override
public String getType()

View File

@@ -8,12 +8,16 @@ package dan200.computercraft.shared.peripheral.monitor;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.common.ServerTerminal;
import dan200.computercraft.shared.util.TickScheduler;
import java.util.concurrent.atomic.AtomicBoolean;
public class ServerMonitor extends ServerTerminal
{
private final TileMonitor origin;
private int textScale = 2;
private boolean resized;
private final AtomicBoolean resized = new AtomicBoolean( false );
private final AtomicBoolean changed = new AtomicBoolean( false );
public ServerMonitor( boolean colour, TileMonitor origin )
{
@@ -41,10 +45,28 @@ public class ServerMonitor extends ServerTerminal
if( oldWidth != termWidth || oldHeight != termHeight )
{
getTerminal().clear();
resized = true;
resized.set( true );
markChanged();
}
}
@Override
protected void markTerminalChanged()
{
super.markTerminalChanged();
markChanged();
}
private void markChanged()
{
if( !changed.getAndSet( true ) ) TickScheduler.schedule( origin );
}
protected void clearChanged()
{
changed.set( false );
}
public int getTextScale()
{
return textScale;
@@ -57,14 +79,14 @@ public class ServerMonitor extends ServerTerminal
rebuild();
}
public synchronized boolean pollResized()
public boolean pollResized()
{
if( resized )
{
resized = false;
return true;
}
return resized.getAndSet( false );
}
return false;
public boolean pollTerminalChanged()
{
update();
return hasTerminalChanged();
}
}

View File

@@ -11,9 +11,11 @@ import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.common.ServerTerminal;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import dan200.computercraft.shared.peripheral.common.IPeripheralTile;
import dan200.computercraft.shared.peripheral.common.ITilePeripheral;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
@@ -25,13 +27,12 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class TileMonitor extends TilePeripheralBase
public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeripheralTile
{
// Statics
public static final double RENDER_BORDER = (2.0 / 16.0);
public static final double RENDER_MARGIN = (0.5 / 16.0);
public static final double RENDER_PIXEL_SCALE = (1.0 / 64.0);
@@ -39,45 +40,30 @@ public class TileMonitor extends TilePeripheralBase
private static final int MAX_WIDTH = 8;
private static final int MAX_HEIGHT = 6;
// Members
private ServerMonitor m_serverMonitor;
private ClientMonitor m_clientMonitor;
private MonitorPeripheral m_peripheral;
private final Set<IComputerAccess> m_computers;
private final Set<IComputerAccess> m_computers = Collections.newSetFromMap( new ConcurrentHashMap<>() );
private boolean m_destroyed;
private boolean m_ignoreMe;
private boolean m_destroyed = false;
private boolean m_ignoreMe = false;
private int m_width;
private int m_height;
private int m_xIndex;
private int m_yIndex;
private int m_width = 1;
private int m_height = 1;
private int m_xIndex = 0;
private int m_yIndex = 0;
private int m_dir;
private int m_dir = 2;
private boolean m_advanced;
public TileMonitor()
{
m_computers = new HashSet<>();
m_destroyed = false;
m_ignoreMe = false;
m_width = 1;
m_height = 1;
m_xIndex = 0;
m_yIndex = 0;
m_dir = 2;
}
@Override
public void onLoad()
{
super.onLoad();
m_advanced = getBlockState().getValue( BlockPeripheral.Properties.VARIANT )
.getPeripheralType() == PeripheralType.AdvancedMonitor;
world.scheduleUpdate( getPos(), getBlockType(), 0 );
}
@Override
@@ -146,44 +132,32 @@ public class TileMonitor extends TilePeripheralBase
}
@Override
public void update()
public void updateTick()
{
super.update();
if( m_xIndex != 0 || m_yIndex != 0 || m_serverMonitor == null ) return;
if( !getWorld().isRemote )
m_serverMonitor.clearChanged();
if( m_serverMonitor.pollResized() )
{
if( m_xIndex == 0 && m_yIndex == 0 && m_serverMonitor != null )
for( int x = 0; x < m_width; x++ )
{
if( m_serverMonitor.pollResized() )
for( int y = 0; y < m_height; y++ )
{
for( int x = 0; x < m_width; x++ )
{
for( int y = 0; y < m_height; y++ )
{
TileMonitor monitor = getNeighbour( x, y );
if( monitor == null ) continue;
TileMonitor monitor = getNeighbour( x, y );
if( monitor == null ) continue;
for( IComputerAccess computer : monitor.m_computers )
{
computer.queueEvent( "monitor_resize", new Object[] {
computer.getAttachmentName()
} );
}
}
for( IComputerAccess computer : monitor.m_computers )
{
computer.queueEvent( "monitor_resize", new Object[] {
computer.getAttachmentName()
} );
}
}
}
}
m_serverMonitor.update();
if( m_serverMonitor.hasTerminalChanged() ) updateBlock();
}
}
else
{
if( m_xIndex == 0 && m_yIndex == 0 && m_clientMonitor != null )
{
m_clientMonitor.update();
}
}
if( m_serverMonitor.pollTerminalChanged() ) updateBlock();
}
// IPeripheralTile implementation
@@ -197,6 +171,12 @@ public class TileMonitor extends TilePeripheralBase
return m_peripheral;
}
@Override
public PeripheralType getPeripheralType()
{
return m_advanced ? PeripheralType.AdvancedMonitor : PeripheralType.Monitor;
}
public ServerMonitor getCachedServerMonitor()
{
return m_serverMonitor;
@@ -319,7 +299,6 @@ public class TileMonitor extends TilePeripheralBase
}
// Sizing and placement stuff
@Override
public EnumFacing getDirection()
{
int dir = getDir() % 6;
@@ -444,7 +423,7 @@ public class TileMonitor extends TilePeripheralBase
return getSimilarMonitorAt( pos.offset( right, xOffset ).offset( down, yOffset ) );
}
public TileMonitor getOrigin()
private TileMonitor getOrigin()
{
return getNeighbour( 0, 0 );
}
@@ -698,20 +677,14 @@ public class TileMonitor extends TilePeripheralBase
}
}
public void addComputer( IComputerAccess computer )
void addComputer( IComputerAccess computer )
{
synchronized( this )
{
m_computers.add( computer );
}
m_computers.add( computer );
}
public void removeComputer( IComputerAccess computer )
void removeComputer( IComputerAccess computer )
{
synchronized( this )
{
m_computers.remove( computer );
}
m_computers.remove( computer );
}
@Nonnull
@@ -752,15 +725,10 @@ public class TileMonitor extends TilePeripheralBase
{
case Monitor:
case AdvancedMonitor:
{
return false;
}
default:
{
return true;
}
}
}
}
}

View File

@@ -13,9 +13,8 @@ import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import dan200.computercraft.shared.util.DefaultSidedInventory;
import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
@@ -262,6 +261,23 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
}
}
@Override
public boolean isItemValidForSlot( int slot, @Nonnull ItemStack stack )
{
if( slot == 0 )
{
return isInk( stack );
}
else if( slot >= topSlots[0] && slot <= topSlots[topSlots.length - 1] )
{
return isPaper( stack );
}
else
{
return false;
}
}
@Override
public boolean hasCustomName()
{
@@ -393,15 +409,15 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
}
}
private boolean isInk( @Nonnull ItemStack stack )
private static boolean isInk( @Nonnull ItemStack stack )
{
return (stack.getItem() == Items.DYE);
return stack.getItem() == Items.DYE;
}
private boolean isPaper( @Nonnull ItemStack stack )
private static boolean isPaper( @Nonnull ItemStack stack )
{
Item item = stack.getItem();
return (item == Items.PAPER || (item instanceof ItemPrintout && ItemPrintout.getType( stack ) == ItemPrintout.Type.Single));
return item == Items.PAPER || (item instanceof ItemPrintout && ItemPrintout.getType( stack ) == ItemPrintout.Type.Single);
}
private boolean canInputPage()
@@ -493,11 +509,14 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours );
synchronized( m_inventory )
{
ItemStack remainder = InventoryUtil.storeItems( stack, m_itemHandlerAll, 7, 6, 7 );
if( remainder.isEmpty() )
for( int slot : bottomSlots )
{
m_printing = false;
return true;
if( m_inventory.get( slot ).isEmpty() )
{
m_inventory.set( slot, stack );
m_printing = false;
return true;
}
}
}
return false;
@@ -521,11 +540,7 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
double x = pos.getX() + 0.5;
double y = pos.getY() + 0.75;
double z = pos.getZ() + 0.5;
EntityItem entityitem = new EntityItem( getWorld(), x, y, z, stack );
entityitem.motionX = getWorld().rand.nextFloat() * 0.2 - 0.1;
entityitem.motionY = getWorld().rand.nextFloat() * 0.2 - 0.1;
entityitem.motionZ = getWorld().rand.nextFloat() * 0.2 - 0.1;
getWorld().spawnEntity( entityitem );
WorldUtil.dropItemStack( stack, getWorld(), x, y, z );
}
}
}

Some files were not shown because too many files have changed in this diff Show More