1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-19 16:07:38 +00:00

Compare commits

..

448 Commits

Author SHA1 Message Date
Daniel Ratcliffe
fa498e74fb 1.80pr1 2017-09-12 00:11:19 +01:00
Daniel Ratcliffe
bd90d7d3b0 Ignore .DS_Store files 2017-09-12 00:05:26 +01:00
Daniel Ratcliffe
1fdfcdb5f2 Merge pull request #378 from MineRobber9000/patch-3
Add ability to load raw data from a string [paintutils]
2017-09-11 13:28:27 +01:00
Daniel Ratcliffe
6c32d8a57e Merge pull request #394 from Wojbie/bugfix/Filesystem-dots-#35
Modify logic behind ... and more in file path.
2017-09-11 13:27:13 +01:00
Daniel Ratcliffe
61ff91f237 Merge pull request #316 from SquidDev-CC/feature/minecraft-1.12.2
Update to 1.12. Bam!
2017-09-10 20:52:26 +01:00
SquidDev
3b2de38227 Build against Oracle JDK 8 instead 2017-09-10 20:45:24 +01:00
Daniel Ratcliffe
bde9ac9747 Merge pull request #400 from SquidDev-CC/hotfix/redstone-propagation
Fix redstone not being propagated through solid blocks
2017-09-10 18:05:51 +01:00
Wojbie
6aa4a385a3 Requested changes to logic behind ... in file path. 2017-09-10 17:51:29 +02:00
SquidDev
a2da6d9601 Pass the original block in redstone propagation
notifyBlockOfStateChange and notifyNeighborsOfStateExcept expect the
block which caused the redstone update, rather than the neighbor block.

Fixes #393
2017-09-10 09:32:02 +01:00
Daniel Ratcliffe
88b1124204 Merge pull request #399 from SquidDev-CC/hotfix/http-encoding
Fix setting an invalid content-encoding header
2017-09-10 00:28:39 +01:00
Daniel Ratcliffe
51644e32ed Merge pull request #415 from Wilma456/palletecheck
Add valid check to term.setPaletteColor/getPaletteColor
2017-09-10 00:12:46 +01:00
Daniel Ratcliffe
cf5216aefb Merge pull request #401 from SquidDev-CC/hotfix/peripheral-errors
Fix logPeripheralErrors not being set
2017-09-10 00:06:15 +01:00
Daniel Ratcliffe
c7e5386e80 Merge pull request #414 from Wilma456/listfix
Fix Bug in list.lua
2017-09-10 00:04:08 +01:00
Daniel Ratcliffe
707f0899da Merge pull request #429 from Wilma456/iofix
Fix io API
2017-09-09 23:59:57 +01:00
Daniel Ratcliffe
3095a6bbad Merge pull request #241 from SquidDev-CC/feature/minecraft-1.11.2
Update to 1.11.2
2017-09-09 23:54:42 +01:00
Wilma456 (Jakob0815)
a5bbed528d Make mode from io.open() accept nil 2017-09-06 18:53:44 +02:00
Wilma456 (Jakob0815)
369be7c32c Fix io API
While adding checks to the io API in #424, I had forgot that the io API has his own type() function who overwrite the default one. This PR fix this. Sorry for that.
2017-08-27 17:08:40 +02:00
Daniel Ratcliffe
fd8837c631 Merge pull request #377 from Wilma456/fserror
Better Errors for fs API
2017-08-27 13:51:36 +01:00
Daniel Ratcliffe
2f829a1413 Fixed load() not accepting function arguments 2017-08-27 13:34:33 +01:00
Daniel Ratcliffe
0de3a42808 Merge pull request #424 from Wilma456/newcheck
Add more Checks
2017-08-27 12:26:58 +01:00
Daniel Ratcliffe
2fb6a9dc62 Merge pull request #389 from Wilma456/ioerr
Make io.open() return Error
2017-08-27 12:22:54 +01:00
Daniel Ratcliffe
87b771b7c8 Merge pull request #421 from Wilma456/sleephelp
Remove sleep.txt
2017-08-27 12:17:53 +01:00
Wilma456
79697e37b0 Add Check to load() 2017-08-24 20:18:21 +02:00
Wilma456
4f9de6b02c Update Checks 2017-08-24 20:17:31 +02:00
Wilma456
e9cea7d0f5 Add more Checks 2017-08-21 15:20:32 +02:00
Wilma456 (Jakob0815)
90626748e4 Remove sleep.txt
sleep was removed from CC, so It's time to remove the help file
2017-08-18 15:45:57 +02:00
Wilma456 (Jakob0815)
30b55d966b Add valid check to term.setPaletteColor/getPaletteColor 2017-08-11 15:38:02 +02:00
Wilma456 (Jakob0815)
3371345fad Fix Bug in list.lua
list.lua check now, if sDir is a Directory
2017-08-11 13:42:20 +02:00
SquidDev
8f6feff4fd Fix logPeripheralErrors not being set 2017-08-01 21:25:23 +01:00
SquidDev
26bca2e109 Fix setting an invalid content-encoding header 2017-07-31 07:50:23 +01:00
Wojbie
0d5397db34 Modify logic behind ... and more in file path.
Changes all equal or longer then 3 multidots setups to be treated as .
This removes other potentialy dangerus situations and brings it closer to windows in how it treats said dots.
2017-07-30 14:11:25 +02:00
Wilma456
226ae3648f Forget string 2017-07-28 15:21:15 +02:00
Wilma456 (Jakob0815)
83f34b430d Make io.open() return Error
If fs.open() failed, it will return nil and a a error message like "No such file"  or "Out of space". This PR make, that io.open() returned this error too.
2017-07-28 15:18:14 +02:00
Wilma456
0a5155c0ff New style 2017-07-27 16:40:00 +02:00
Daniel Ratcliffe
579f7443a8 Merge pull request #360 from Wojbie/Mixed-lua-side-improvements.-Part-2
Mixed-Lua-side-improvements.-Part-2
2017-07-25 23:15:10 +01:00
Daniel Ratcliffe
df1c8e22b8 Merge pull request #376 from CrazedProgrammer/fix-argument-checks
Fix argument checks made in PR #304 and #338
2017-07-25 23:13:34 +01:00
CrazedProgrammer
96288164c5 Fix textutils.serializeJSON argument check 2017-07-25 22:36:54 +02:00
SquidDev
263bade338 Add some basic recipe advancements
This doesn't provide the ability to unlock the upgrade impostor recipes,
but I'm not sure that is currently feasible.
2017-07-25 21:10:49 +01:00
SquidDev
d29ffed383 Java 8. Java 8. Does whatever Java 8 can.
Default methods, everywhere.
Arrow types, switch on strings.
Lambdas!
Here comes Java 8.
2017-07-25 21:10:48 +01:00
SquidDev
08099f08f2 Initial update to 1.12
- Convert most recipes to JSON
 - Add JSON factories for impostor and turtle recipes.
 - Several mappings changes
 - Migrate to Forge's new registry system
2017-07-25 21:10:47 +01:00
SquidDev
bee41e7f97 Avoid deprecated warnings on ItemCable 2017-07-25 21:08:52 +01:00
SquidDev
35425f0f61 Update to 1.11.2 2017-07-25 21:08:51 +01:00
Daniel Ratcliffe
f480965e67 Merge pull request #372 from Wilma456/apispro
Update alias.lua
2017-07-25 20:32:30 +01:00
Daniel Ratcliffe
6701403370 Merge pull request #364 from KingofGamesYami/feature/computer-get-label
Add .getLabel
2017-07-25 20:06:22 +01:00
Daniel Ratcliffe
ff2c26c4a1 Merge pull request #367 from SquidDev-CC/feature/texture-spacing
Fix texture artifacts when rendering monitors
2017-07-25 20:05:31 +01:00
Wojbie
4c89364964 Requested changes 2017-07-25 21:01:04 +02:00
Daniel Ratcliffe
94613d28a6 Merge pull request #381 from Wilma456/colerror
Better Error for "Invalid color"
2017-07-25 19:56:59 +01:00
Daniel Ratcliffe
f6ea561270 Merge pull request #374 from Wilma456/packapis
Add package to apis.lua
2017-07-25 19:05:11 +01:00
Daniel Ratcliffe
b4fb7bb20f Merge pull request #354 from Wilma456/multifix
Fix multishell.launch
2017-07-25 19:04:39 +01:00
Daniel Ratcliffe
35d29e1d88 Merge pull request #348 from Wilma456/termcheck
Update term.redirect check to new style
2017-07-25 19:03:55 +01:00
Daniel Ratcliffe
f14a14f4c3 Merge pull request #355 from MineRobber9000/patch-2
Make pastebin.lua use HTTPS
2017-07-25 19:03:15 +01:00
Daniel Ratcliffe
77cadf52fe Merge pull request #351 from Wojbie/Fix-to-349-Monitors-causing-miscolouration-of-tile-entities
Fix to #349 - Monitors causing miscolouration of tile entities.
2017-07-25 19:02:43 +01:00
Daniel Ratcliffe
e97a32cd69 Merge pull request #375 from SquidDev-CC/feature/resourcepack-bios
Adds the ability to load custom bios.lua files from resource packs
2017-07-25 19:02:05 +01:00
Daniel Ratcliffe
44a5284dd6 Merge pull request #379 from SquidDev-CC/hotfix/nil-errors
Fix incorrect null check in HTTP API
2017-07-25 19:00:25 +01:00
Wilma456 (Jakob0815)
43a5fc9fe7 Better Error for "Invalid color"
the "Invalid color" error now contain the wrong color.
2017-07-18 16:12:19 +02:00
SquidDev
505ccf97cf Fix incorrect null check
This was causing NPEs when no headers were specified and one was
attempting to POST data.
2017-07-17 22:46:48 +01:00
MineRobber___T
2c91c7962f Remove unused tImage table and slightly clean code 2017-07-17 01:49:14 -04:00
MineRobber___T
f785b0a488 Update paintutils.lua 2017-07-17 01:16:36 -04:00
MineRobber___T
af847818d2 Remove some context from comment
I agree with SquidDev, I went a bit too far with the whole context thing.
2017-07-16 02:10:42 -04:00
MineRobber___T
ee20d7bed2 Fix line split
Also fixes a typo.
2017-07-16 02:08:54 -04:00
MineRobber___T
11060596b1 Remove legacy bHandleRawData check and fix file loading
While the check (most likely) wouldn't break anything, it's better to fix it and not worry then to not fix it and find out it breaks image loading. Also fixes how files are loaded.
2017-07-15 18:31:42 -04:00
MineRobber___T
71d024a76c Move raw data parsing to paintutils.drawImage 2017-07-15 18:27:52 -04:00
MineRobber___T
260bb2e4e1 Add ability to load raw data from a string 2017-07-15 17:50:05 -04:00
Wilma456
f28a1ba517 Fix Bugs 2017-07-15 16:41:40 +02:00
Wilma456
239a2f0d25 Better Errors for fs API 2017-07-15 16:09:29 +02:00
CrazedProgrammer
1850dcdf38 Fix indentation of previous commits (tabs -> spaces) 2017-07-15 13:01:08 +02:00
CrazedProgrammer
af0549946b Fix window API argument check made in PR #304
- Fix window.reposition so the new width and height arguments are
optional
2017-07-15 00:17:34 +02:00
CrazedProgrammer
7e5a9b3a5a Fix some textutils API argument checks made in PR #338
- textutils.serializeJSON now takes a table/string/number/boolean instead of just a string as the t argument, and checks for nil in the tNBTStyle argument, so the parameter becomes optional again, as described in the wiki.
- textutils.slowWrite and textutils.slowPrint now checks if the rate
parameter is a number, if not nil.
2017-07-15 00:00:01 +02:00
SquidDev
c0294e1534 Adds the ability to load custom bios.lua files from resource packs
Computer now delegates to IComputerEnvironment which, by default, looks
in the following locations:

 - Resouce pack files
 - The "debug" folder
 - The original ComputerCraft jar
2017-07-14 21:58:58 +01:00
Wilma456 (Jakob0815)
bb6d423710 Add package to apis.lua 2017-07-14 12:50:59 +02:00
Wilma456 (Jakob0815)
0ab79fd466 Update alias.lua
The apis program show now, waht programs are behind the aliases
2017-07-13 16:04:55 +02:00
Bomb Bloke
756d297c85 Update worm.lua
Fix #368
2017-07-11 10:24:36 +10:00
SquidDev
1cf3d78eac Fix texture artifacts when rendering monitors
- Adds a 1px margin around every glyph. This is generally empty,
   with the exception of teletext characters where it continues their
   pattern.
 - Uses GL_CLAMP with the font texture.

Closes #300
2017-07-10 22:20:07 +01:00
Steven Dirth
f1bb56557d Update changelog and whatsnew 2017-07-09 12:45:08 -05:00
Steven Dirth
4b36ed6719 Add .getLabel to computer peripheral
Closes #359
2017-07-09 12:43:50 -05:00
KingofGamesYami
592c0c9341 Merge pull request #1 from dan200/master
update 7/8
2017-07-08 16:17:24 -05:00
SquidDev
e664eb26a9 Fix several global definitions
There were a couple of programs which were defining global variables, or
referencing undefined ones. This fixes all problems in the main rom files.
2017-07-08 11:31:30 +00:00
SquidDev
1ab5094b7f Only delete indent when at the beginning of a line
edit currently deletes the previous 4 spaces when pressing backspace,
wherever you are on the line. This can be frustrating when you are
trying to align text in comments or strings.

This changes edit to only delete 4 spaces if all preceding characters
are whitespace, otherwise it only deletes a single character.
2017-07-08 12:07:30 +01:00
Daniel Ratcliffe
94d701b1f7 Merge pull request #350 from Wilma456/argnil
Replaced "no value" with "nil" in ArgumentHelper
2017-07-07 20:58:09 +01:00
Daniel Ratcliffe
db2364dae6 Merge pull request #357 from SquidDev-CC/hotfix/credits-include
Various improvements to credits generation
2017-07-07 20:57:36 +01:00
Wojbie
87406bc00d Tweak to Colon syntax lua autocompletition.
Changes autocompletition to only complete function names (Or table names treated as functions via __call metamethod) after the colon symbol.
2017-07-07 02:30:57 +02:00
Wojbie
224e752a8f Tweak to Go and Turn autocompletition.
Adds spaces to simplyfy making chains of commands.  Also fix up turn not autocompleting after first argument.
2017-07-07 02:18:24 +02:00
SquidDev
48754659f8 Various improvements to credits generation
- Include author and comitter (so includes rebased commits)
 - Ignore case when sorting names

Fixes #356
2017-07-06 17:27:20 +01:00
MineRobber___T
f0559867d0 Fix pastebin.lua not using HTTPS
Attempting to use pastebin with plain HTTP results in a 301 redirect to the HTTPS version. This PR (and associated commit) makes the pastebin command work again.
2017-07-06 03:58:41 -04:00
Wilma456
02eb52da71 Fix multishell.launch 2017-07-05 10:17:44 +02:00
Wojbie
ef05eb7fe9 @SquidDev fix to #349.
This fixes problem reported in #349.
I was one of pepole that were having this bug so i was able to test it and confirm this fix.

Closes #349
2017-07-04 22:54:20 +02:00
Wilma456
6fdf38f55f Replaced "no value" with "nil" in ArgumentHelper 2017-07-04 12:44:20 +02:00
Wilma456
c46391555f Update term.redirect check to new style 2017-07-03 18:08:51 +02:00
Daniel Ratcliffe
1d63598d43 Merge pull request #338 from Wilma456/textcheck
Add Checks to Textutils API
2017-06-29 19:04:37 +01:00
Wilma456
5e244273c2 Allow Number and Table 2017-06-29 17:58:53 +02:00
Daniel Ratcliffe
b0a2dd5eb1 Merge pull request #344 from Wilma456/othercheck
Add Checks to disk,gps,help and keys
2017-06-29 16:09:46 +01:00
Wilma456
13f886be5a Add Checks to disk,gps,help and keys 2017-06-29 16:41:48 +02:00
Wilma456
845e1b633d Merge branch 'master' into textcheck 2017-06-29 16:24:30 +02:00
Wilma456
6a8c544914 Feedback from dan200 2017-06-29 16:18:13 +02:00
Daniel Ratcliffe
123a0158af Merge pull request #313 from SquidDev-CC/feature/http-blacklist
HTTP blacklist and IP address support
2017-06-28 22:36:14 +01:00
SquidDev
b37b33f4f4 Migrate default whitelist/blacklist values to fields
This means we're not duplicating them between the initial field and
property creation.
2017-06-28 22:33:20 +01:00
Daniel Ratcliffe
00a1342883 Merge pull request #297 from SquidDev-CC/feature/fire-events
Fire Forge events where appropriate
2017-06-28 22:32:22 +01:00
Daniel Ratcliffe
14e4d037ad Merge pull request #317 from Wojbie/Mixed-lua-side-improvements
Multiple fixes and feature fixes for lua side of CC.
2017-06-28 22:25:18 +01:00
Daniel Ratcliffe
28a89a26ad Merge pull request #342 from SquidDev-CC/hotfix/turtle-suck
Replace direct equality with InventoryUtil.areItemsEqual
2017-06-28 22:12:30 +01:00
SquidDev
c9a3bcb68b Replace direct equality with InventoryUtil.areItemsEqual
Some IItemHandler.insertItem implementations clone the item, so we must
check whether the object is equal instead.

Fixes #340
2017-06-28 22:11:25 +01:00
Daniel Ratcliffe
025af6a0a0 Merge pull request #329 from Wilma456/pocketequip
Add equip and unequip for Pocket Computers
2017-06-28 22:06:35 +01:00
Wojbie
f247879d98 Re-add Colon syntax support to edit. 2017-06-28 23:06:06 +02:00
Wojbie
bf533dd00a Reverting requested changes. Take 1
Reverting rewrites to painutils, paint and edit - keept the paste logic change in edit.
Changed and removed misc parts as requested in PR.
2017-06-28 22:58:57 +02:00
Logan Davis
0fb8177721 Fixed possible Typo. (#337) 2017-06-28 21:39:54 +01:00
Daniel Ratcliffe
22066a96dd Merge pull request #335 from Wilma456/shellcheck
Add Checks to Shell and Multishell
2017-06-28 21:20:04 +01:00
Daniel Ratcliffe
836de416bc Merge pull request #334 from Wilma456/colorcheck
Add Checks to Colors API
2017-06-28 21:16:54 +01:00
Wilma456
6bbd1f3718 Add Checks to Textutils API 2017-06-26 15:21:52 +02:00
Wojbie
6255314ba8 Fir error in http.request _post error cheacking code and add package.config to shell require code to support standard better. 2017-06-24 14:33:29 +02:00
Wojbie
fc93ee474f Merge branch 'master' into Mixed-lua-side-improvements 2017-06-24 14:29:19 +02:00
Wilma456
13ed933c6b Add Checks to Shell and Multishell 2017-06-23 18:33:11 +02:00
Wilma456
fb5ba01e5a Add Checks to Colors API 2017-06-23 17:38:40 +02:00
Wojbie
7090f6b6a7 Make settings API getNames() function sort names.
Makes it easier for eye and keeps settings from same program next to eachother.
2017-06-23 01:07:18 +02:00
Wilma456
01c024d8b0 Add equip and unequip for Pocket Computers 2017-06-22 14:05:42 +02:00
Wojbie
52a2c6f7f9 Merge pull request #3 from BombBloke/patch-1
Update paintutils.lua
2017-06-21 16:51:09 +02:00
Bomb Bloke
d9190f95ec Update paintutils.lua
Couple of fixes, plus let's not use maxn when blitting images after all. Load method ensures it isn't needed.
2017-06-21 23:41:40 +10:00
Wojbie
6df22235ae Add forgotten settings.set in bios. 2017-06-20 02:09:28 +02:00
Daniel Ratcliffe
174b63d59a Merge pull request #309 from Wilma456/execcom
Add autocompletion to exec
2017-06-19 20:44:21 +01:00
Daniel Ratcliffe
f0257028ba Merge pull request #321 from Wilma456/bioscheck
Add Checks to Bios
2017-06-19 19:18:14 +01:00
Daniel Ratcliffe
4a9f1e013c Merge pull request #324 from BombBloke/patch-1
Fix Bug with peripheral.find()
2017-06-19 19:17:02 +01:00
Bomb Bloke
a7db108762 Update paintutils.lua 2017-06-19 13:46:13 +10:00
Bomb Bloke
be861a1c0d Fix Bug with peripheral.find()
Since #315 peripheral.find() doesn't work. This PR fix this.
2017-06-19 13:09:06 +10:00
Wojbie
1489da1f5f Adds support for colon operator in complete() function.
Includes changes to lua and edit programs to correctly support that too.
2017-06-19 01:15:26 +02:00
Wilma456
c70acbb05a Add Checks to Bios 2017-06-18 17:48:07 +02:00
Wojbie
7e08662b95 Assorted fixes to rednet, textutils, gps, chat.
As reported by @SquidDev.
2017-06-18 17:12:08 +02:00
Daniel Ratcliffe
93d1facbab Merge pull request #320 from Wilma456/perifix
Fix Bug with peripheral.find()
2017-06-18 15:07:18 +01:00
Wilma456
4580f10567 Fix Bug with peripheral.find() 2017-06-18 15:58:06 +02:00
Wojbie
06b2f3511f Update paintutils.lua
Make error messages consistent with new system.
Fix some type errors and fix problem noticed by @BombBloke.
2017-06-18 12:03:14 +02:00
Wojbie
3acbdb2f90 Merge branch 'master' into Mixed-lua-side-improvements 2017-06-17 22:21:25 +02:00
Wojbie
01a0ce3dd0 Implements suggested changes. 2017-06-17 22:14:04 +02:00
Daniel Ratcliffe
bfb682bef9 Merge pull request #315 from SquidDev-CC/feature/argument-validation
Rewrite argument validation
2017-06-17 19:25:20 +01:00
Daniel Ratcliffe
9b5aa43d95 Merge pull request #319 from Wilma456/defread
Add Default to read()
2017-06-17 19:18:27 +01:00
Wojbie
efb351e1b0 Modification of edit.lua to use blit in writeHighlighted
Reduces amount of string operations and write calls inside writeHighlighted function by switching it to blit and using the 3rd argument in string.match.
2017-06-16 23:13:53 +02:00
Wilma456
2445a5b5d5 Add Default to read() 2017-06-15 14:50:47 +02:00
Wojbie
c611b20db8 Merge pull request #2 from BombBloke/patch-1
Paint tweaks
2017-06-14 16:32:48 +02:00
Bomb Bloke
221143e767 Update paintutils.lua
Resolve a few potential bugs.
2017-06-15 00:23:40 +10:00
Bomb Bloke
34ac28066e Create paint.lua
General re-write for speed; much less likely to fail yield protection when attempting to draw the canvas.
2017-06-15 00:16:16 +10:00
Wojbie
9472d30dfc Update startup.lua
Removed code better implemented by @Wilma456
2017-06-14 03:11:47 +02:00
SquidDev
eb628e9b62 Make error messages more consistent 2017-06-13 19:33:42 +01:00
Wojbie
157bc01be5 Merge pull request #1 from BombBloke/patch-1
Better update paintutils.lua
2017-06-13 15:55:07 +02:00
Bomb Bloke
8e958d7a13 Update paintutils.lua
Remove drawPixelInternal / drawLineHorizontal. At runtime they're both just excess calls.
Localise high-use term functions.
Arg-related function errors reflect that "colour" parameter is optional.
Add saveImage(tImage, sPath).
Use term.blit for images.
2017-06-13 23:44:07 +10:00
Wojbie
76a3562d58 Multiple fixes and feature fixes for lua side of CC
In no particular order:
bios.lua - added missing test for ensure turtle folder exists.
paintutils.lua - added drawLineHorizontal() to reduce most (not all) cases of running multiple writes on same horizontal line that can be solved with one write.
textutils.lua - Added exception to complete function - will not complete if provided with LuaKeyword - solves do->dofile problem and removes other LuaKeyword related ones in advance.
edit.lua - Changed logic in handling the paste event - if paste event is received when menu is open it automatically closed said menu and lets it paste - resolves ctrl+ctrl+v annoyance. Added Jump to Menu functions - allows for fast jump to needed line - must for bigger files and a nice feature to have.
set.lua - Switched set to use pagedPrint - this will ensure that even if there are more settings than lines on screen the set command will show you all of them.
startup.lua - Added autocompletition for turtle programs go, turn, equip, unequip and command program exec.
lua.lua - Changed return function to print returned stuff correctly -
will print all returned variables even if there are any nils in there.
2017-06-13 11:00:07 +02:00
SquidDev
585c769c2a Restructure the HTTP API
- Adds support for blacklisting domains
 - Adds support for blacklisting & whitelisting IP addresses and
   IP ranges.
 - Reuse threads for HTTP requests

AddressPredicate will parse a series of patterns and convert them into
regexes or CIDR ranges. When checking whether an address is accessible,
we first ensure the domain is whitelisted and isn't blacklisted.

If everything is OK, then we start create a new thread for the HTTP
request and resolve the IP, ensuring that is whitelisted & not
blacklisted. Then the normal HTTP request is continued.

However, http.checkURL also needs to resolve the IP address. In order to
avoid blocking the Lua thread, this method will return instantly and
create a new thread which will queue an event.

As both http.request and http.checkURL are now creating threads and
queuing events, some logic is abstracted into a separate HTTPTask class
- this allows us to share the thread creation, finishing and cancelling
logic.
2017-06-12 19:22:02 +01:00
SquidDev
fac625173a Use Lua style error messages in the rom files
This makes it mostly consistent with the Java APIs, and makes debugging
significantly easier.
2017-06-12 10:54:44 +01:00
SquidDev
bffc3c18cc Rewrite argument validation
This uses a new utility class ArgumentHelper, which provides convenience
methods for parsing arguments from an array of Objects.

The format of error messages has also changed. It now follows a format
similar to Lua's native error messages - including the invalid argument
index, the expected type and the type actually received.
2017-06-12 10:28:31 +01:00
Wilma456
9e9df37c40 Add autocompletion to exec 2017-06-07 16:51:23 +02:00
Daniel Ratcliffe
0f982e6199 Merge pull request #303 from Wojbie/Window-api-fix
Fix to setPaletteColour in rgb8 mode.
2017-06-04 13:58:40 +01:00
Daniel Ratcliffe
4f3be7963e Merge pull request #304 from Wilma456/windowcheck
Add checks to window API
2017-06-04 13:57:51 +01:00
Daniel Ratcliffe
2cd4daa9ad Merge pull request #305 from Wojbie/Redirection-fix
Fix to redirection game.
2017-06-04 13:57:06 +01:00
Wojbie
60e9ce1b68 Fix to redirection game.
Was not testing for correct file type. Game ended after first lvl cause it was looking from wrong name of file.
2017-06-04 14:51:49 +02:00
Wilma456
c9bf463419 Add checks to window API 2017-06-04 12:34:40 +02:00
Wojbie
a90e2a8bfd Fix to setPaletteColour in rgb8 mode.
Was not saving color if called using rgb8 mode.
2017-06-04 11:59:30 +02:00
Daniel Ratcliffe
3828750ade Merge pull request #302 from Wojbie/Wget-binary-mode
Switch wget to use binary mode.
2017-06-03 21:32:45 +01:00
Daniel Ratcliffe
5e3eb2c6a7 Merge pull request #299 from Wilma456/termbug
Fix Bug with term.setCursorPos
2017-06-03 21:31:56 +01:00
Wilma456
fd842be37f Remove second fix 2017-06-03 16:30:35 +02:00
Wojbie
0cc65adff9 Switch wget to use binary mode.
Allows wget to download all types of files not only text ones.
2017-06-03 13:19:57 +02:00
Wilma456
d6e4323f17 Fix Bug with term.setCursorPos
I fixed 2 Bugs:
1. If you call this function, without 2 numbers, you get a error in the window API and not in your Program
2. If you call, this function with 2 numbers lower then 1 (e.g. term.setCursorPos(0,0) ), CraftOS will hang forever and need to press Ctrl+R or rejoin the world.
2017-06-02 17:35:18 +02:00
SquidDev
255dc925fb Fire Forge events where appropriate
- BlockEvent.BreakEvent and BlockEvent.HarvestDropsEvent are fired when
   digging.
 - AttackEntityEvent is fired when attacking.
 - Various PlayerInteractEvent.* events are fired when placing.

Closes #103, closes #100
2017-05-31 12:41:31 +01:00
Daniel Ratcliffe
114c49e3f6 Merge pull request #291 from Wilma456/apis
Add multishell to apis program
2017-05-29 16:57:42 +01:00
Daniel Ratcliffe
26077cbced Merge pull request #293 from Lignum/fix-warning
Fix generic-related compiler warning
2017-05-29 16:56:30 +01:00
Lignum
44c67796b8 Fix generic-related compiler warning 2017-05-29 17:35:41 +02:00
Wilma456
9770f103ed Add multishell to apis program 2017-05-29 15:55:45 +02:00
Wilma456
07ae332c24 Add fileextension for Paint (#260)
* Add fileextension for Paint

* Change extension to .nfp

* Add setting
2017-05-29 14:05:19 +01:00
Wilma456
99b5534099 Add setting for .lua extension (#278)
* Add setting for .lua extension

* Feedback  from SquidDev

* Feedback from dan200

* All requested changes are done

* Better description

* Cleaner check
2017-05-29 13:21:27 +01:00
Daniel Ratcliffe
54d202cf6b Merge pull request #288 from Wojbie/getPaletteColour-fix
Fix to getPalletteColour
2017-05-28 13:40:56 +01:00
Wojbie
47f470910e Fix to getPalletteColour
Done as @dan200 specified in #287. Closes #287.
2017-05-28 14:08:15 +02:00
Daniel Ratcliffe
235131c3fb codesize.sh now only counts lua files 2017-05-28 12:18:12 +01:00
Daniel Ratcliffe
9f35d2a2b7 Merge pull request #282 from apemanzilla/contributors_task
Dynamically generate contributors list
2017-05-28 12:06:12 +01:00
Daniel Ratcliffe
934fd08506 Merge pull request #285 from MineRobber9000/patch-1
Add github repo url to credits.txt
2017-05-28 12:03:37 +01:00
Daniel Ratcliffe
7b182e32b8 Update credits.txt 2017-05-28 12:03:23 +01:00
MineRobber___T
3d9d54beef Update credits.txt
Add url of github repo to credits.
2017-05-25 10:15:01 -04:00
apemanzilla
51b9f3ca3b Use template instead of separate task 2017-05-24 13:20:46 -04:00
apemanzilla
3b6ed552e3 Fix incorrect forEach usage 2017-05-24 12:42:49 -04:00
apemanzilla
5ff3ae6434 Add Gradle task to generate contributor list 2017-05-24 12:35:41 -04:00
Daniel Ratcliffe
e66f0d7033 Merge pull request #268 from Wilma456/credits
Add Contributors to credits.txt
2017-05-24 13:21:52 +01:00
Daniel Ratcliffe
b34adde6f3 Merge pull request #279 from lupus590/feature/lua_extention_for_tresure_disks
.lua extentions for treasure disks
2017-05-24 13:17:54 +01:00
Nephi (AKA Lupus590)
5f2446009d mass file rename, left some files...
... as they are levels for nitrogenfingers goldrunner
2017-05-22 21:34:49 +01:00
Wilma456
19fc491532 Remove Ingamename and sort alphabetical 2017-05-22 17:18:11 +02:00
Daniel Ratcliffe
853e626756 Merge pull request #263 from Lignum/fix-speakers
Speaker-related cleanup
2017-05-20 12:27:12 +01:00
Lignum
0a2cb7442d Merge branch 'master' into fix-speakers 2017-05-20 13:23:12 +02:00
Daniel Ratcliffe
d86aa50bec Merge pull request #267 from SquidDev-CC/feature/tutle-tool-changes
Shovel upgrade converts grass to path blocks
2017-05-20 12:16:47 +01:00
Wilma456
df2fe7c445 Add Contributors to credits.txt 2017-05-20 13:13:08 +02:00
Daniel Ratcliffe
6c85ca071f Merge pull request #266 from Wilma456/leveldat
Add .dat extension to all redirection levels
2017-05-20 11:57:26 +01:00
Daniel Ratcliffe
aaa82dceab Merge pull request #265 from Wilma456/newhelp
Add .txt extension to all help files (update)
2017-05-20 11:56:04 +01:00
Wilma456
b31518cfb5 Add .dat extension to all redirection levels 2017-05-20 12:51:01 +02:00
Wilma456
e8ecf5dcd5 Add .txt extension to all help files 2017-05-20 12:20:27 +02:00
Lignum
163c1db6be Fix some if statements 2017-05-19 23:37:02 +02:00
Lignum
c8697d9158 nTicks -> nPitch in speaker help file
Not sure why this was called nTicks, but it had nothing to do with ticks.
2017-05-19 20:27:08 +02:00
Lignum
c2af482615 Format TileSpeaker and TurtleSpeaker 2017-05-19 20:25:08 +02:00
Lignum
a402fc9093 Format SpeakerPeripheral correctly 2017-05-19 20:20:51 +02:00
Daniel Ratcliffe
d822147704 Merge pull request #262 from Lignum/fix-spelling
Fix some minor spelling mistakes
2017-05-19 18:49:48 +01:00
Lignum
387fc13322 Pocket Computer upgrde -> Pocket Computer upgrade 2017-05-19 19:19:29 +02:00
Lignum
b30191638f Ensure the existence, not existance 2017-05-19 19:17:23 +02:00
Lignum
95991694e0 Load modules, not modiles 2017-05-19 19:16:50 +02:00
Daniel Ratcliffe
9b6d335c5d small fix 2017-05-19 14:13:08 +01:00
Daniel Ratcliffe
ffa075cd3d Merge pull request #259 from SquidDev-CC/hotfix/check-palette
Add some sanity checks to Palette.readFromNBT
2017-05-19 13:06:35 +01:00
SquidDev
971c719a9f Add some sanity checks to Palette.readFromNBT
Printers use a Terminal to store the page currently being printed.
Printers saved in an older version of ComputerCraft would be missing the
term_palette field, resulting in an NPE when loading the tile.
2017-05-19 11:47:27 +01:00
Daniel Ratcliffe
f3c291cb4d Merge pull request #205 from SquidDev-CC/feature/packet-network-api
Expose wireless network in the public API
2017-05-18 23:57:44 +01:00
SquidDev
d76ce22db7 Split transmit into two separate methods
This removes the interdimensional and range options from the packet
and ensures they are provides them from the transmit* methods instead.
2017-05-18 23:50:14 +01:00
Daniel Ratcliffe
6d590cee3b Merge pull request #258 from Wojbie/Speaker-volume-fix
Speaker max hearable range limit
2017-05-18 22:32:38 +01:00
Wojbie
af07a78f76 Speaker rage limit
Limit max volume of speaker to volume of normal noteblock.
2017-05-18 23:12:55 +02:00
Daniel Ratcliffe
757b1efd7e Merge pull request #255 from SquidDev-CC/feature/add-package-loaded
Include standard Lua libraries in package.loaded
2017-05-18 00:20:46 +01:00
SquidDev
d19bc53cb4 Include standard Lua libraries in package.loaded
PUC Lua includes all builtin libraries in the package.loaded table.
2017-05-18 00:15:21 +01:00
Daniel Ratcliffe
61b2ed36a9 Reworked how shell creates environments. Implemented require
"shell" now runs each program in a new lua environment, instead of
sharing that lua environment between all programs launched under a one
shell. Said environment now includes an implemenation of "require" and
the "package" API, so that programs can require modules into that
environment.

This means that programs can require in libraries without polluting the
global namespace, and without breaking the virtual computer model, as
each program has it's own set of requires, which are discarded when the
program ends.
2017-05-17 23:43:44 +01:00
Daniel Ratcliffe
4fb93853ce Running "edit foo" will now create "foo.lua" if "foo" does not exist 2017-05-17 22:47:39 +01:00
Daniel Ratcliffe
6e6b8e7eef Made os.loadAPI handle .lua files. Renamed all builtin APIs to .lua 2017-05-17 22:47:13 +01:00
Daniel Ratcliffe
50a4a961e5 Pressing tab in "edit" now inserts 4 spaces instead of 2, backspace now deletes them 2017-05-17 19:48:27 +01:00
Daniel Ratcliffe
f5edb32be9 Replaced tabs with spaces in all lua files 2017-05-17 19:48:27 +01:00
Daniel Ratcliffe
b86708aaf8 Merge pull request #253 from SquidDev-CC/hotfix/empty-files
Fix files not writing data when closed
2017-05-17 19:35:26 +01:00
SquidDev
5cf581e6c9 Fix files not writing data when closed
As the raw stream was being provided to the parent class, buffered data
was not written, resulting in empty files. This ensures the buffered
reader/writer is the one which is closed.
2017-05-17 19:25:13 +01:00
Daniel Ratcliffe
05e838ca5a Strip ".lua" from program names in multishell title bar 2017-05-17 19:05:45 +01:00
Daniel Ratcliffe
25a18ee33a Merge pull request #250 from Wilma456/luaex
Add .lua extension to all programs and startup (updated)
2017-05-17 18:13:56 +01:00
Wilma456
1d905963e9 Add .lua extension to all programs and startup 2017-05-17 16:28:43 +02:00
Daniel Ratcliffe
ebf8492198 Merge pull request #249 from SquidDev-CC/hotfix/speaker-server
Fixes speakers playing incorrect sounds on the server
2017-05-17 11:11:34 +01:00
SquidDev
12e61efd76 Fixes speakers playing incorrect sounds on the server
As a new SoundEvent was being created each time, the actual sound was
not in the registry, resulting in the sound -> id mapping yielding
incorrect values.
2017-05-17 08:00:14 +01:00
Daniel Ratcliffe
0a350077e9 Updated turtle speaker texture to match the style of the other turtle peripherals 2017-05-16 23:59:35 +01:00
Daniel Ratcliffe
19c8613dea Better shell.programs() fix
Prevents duplicate entries
2017-05-16 23:34:53 +01:00
Daniel Ratcliffe
fb00698557 Merge pull request #239 from Wilma456/shellprog
Make shell.programs filter .lua extension
2017-05-16 23:00:14 +01:00
Daniel Ratcliffe
3d1eb830c7 Saner extension check 2017-05-16 22:59:39 +01:00
Daniel Ratcliffe
2bc72a883f Merge pull request #228 from Lignum/startup-dir
Startup directories
2017-05-16 22:56:00 +01:00
Daniel Ratcliffe
c15fcd00ec Merge pull request #248 from Cruor/master
Added help file for speakers
2017-05-16 22:55:43 +01:00
Cruor
cd2a51f816 Updated text... again... 2017-05-16 23:39:48 +02:00
Cruor
8b7c769ff9 Update speakers 2017-05-16 23:33:09 +02:00
Cruor
4101cb2dfb Added help file for speakers
Added help file for speakers
2017-05-16 23:30:53 +02:00
Lignum
03794970ba Merge master into startup-dir 2017-05-16 23:25:54 +02:00
Lignum
9d0afe9e18 Mention startup directories in whatsnew and changelog
Also makes the line endings in these files consistent to be LF only.
2017-05-16 23:22:34 +02:00
Daniel Ratcliffe
f833450a68 Changed permissions on deploy.sh 2017-05-16 21:57:57 +01:00
Daniel Ratcliffe
d6bf2c5dbc Merge pull request #246 from SquidDev-CC/hotfix/at-stacked-block
Remove AT for Block.createStackedBlock
2017-05-16 21:38:49 +01:00
SquidDev
b5e75a86c8 Remove AT for Block.createStackedBlock
Access transformers do not propagate to sub classes, and so the access
transformer did not work here. Reverting to reflection fixes this issue.
2017-05-16 21:19:36 +01:00
Lignum
00943163c8 Replace type check with nil check 2017-05-16 21:53:50 +02:00
Lignum
eb9b7f3b8c Ignore dirs inside startup directories 2017-05-16 21:50:35 +02:00
Daniel Ratcliffe
ba4b1e21fe Merge pull request #238 from SquidDev-CC/feature/binary-handles
Refactor the filesystem and HTTP code
2017-05-16 20:02:34 +01:00
Daniel Ratcliffe
cd85a03429 Merge pull request #237 from Restioson/feature/speaker
[Peripheral] Speaker
2017-05-16 19:52:10 +01:00
Restioson
0113e7229f Added speaker to whatsnew 2017-05-16 20:44:34 +02:00
Restioson
7e556acebc Added Speaker to Changelog 2017-05-16 20:42:16 +02:00
Daniel Ratcliffe
aa8455e0b1 Merge pull request #245 from Wilma456/settings
Update Settings Help
2017-05-16 19:39:34 +01:00
Daniel Ratcliffe
2e22ca4ccf Merge pull request #217 from SquidDev-CC/feature/logging
Add a basic logging system
2017-05-16 19:38:03 +01:00
Wilma456
68f4611abc Add Default Settings 2017-05-16 20:35:46 +02:00
SquidDev
0e1135ed97 Disable peripheral logging by default 2017-05-16 19:35:07 +01:00
Daniel Ratcliffe
ebbdd29bd6 Merge pull request #243 from SquidDev-CC/feature/access-transformer
Replace reflection with access transformers
2017-05-16 19:25:10 +01:00
Daniel Ratcliffe
8c4331d15a Added checks to window.setTextColor and window.setBackgroundColor 2017-05-16 19:23:08 +01:00
Restioson
4df4b91d09 Converted (!x == y) to x != y 2017-05-16 20:02:59 +02:00
Restioson
b28c565665 (Hopefully) addressed @dan200's concerns
Push your fix to thread safety if this doesn't cut it
2017-05-16 19:48:38 +02:00
SquidDev
efb0065ebd Add config option to disable certain error messages 2017-05-16 15:59:09 +01:00
SquidDev
a0b6cbb671 Remove ILogger facade
Just use global Log4j logger on the ComputerCraft class.
2017-05-16 15:49:55 +01:00
SquidDev
44ba4069c1 Print stack traces/add logging messages in several places
This will hopefully make it easier to track down various issues which
might otherwise go unnoticed or provide little information.

The main areas modified are those that external APIs may provide values
for or interact with: various providers and ILuaObject/IPeripheral
implementations. However, we do also log in a couple of other places
which indicate a problem with this, or another, mod.
2017-05-16 15:49:55 +01:00
SquidDev
bdc438fc62 Add a basic logging system
This adds a common ILogger interface and two built-in loggers - one
which prints to stdout, the other using a Log4J logger. These are split
up as not to cause dependency issues for emulators.

The stdout logger is enabled by default, but the ComputerCraft mod class
will swap over to using FML's mod specific logger, which provides a more
consistent look with the rest of Minecraft.
2017-05-16 15:49:55 +01:00
Restioson
b3c49db761 Made Speaker threadsafe & fix warnings 2017-05-15 17:42:29 +02:00
Restioson
7ff4631a9f @gegy1000 strikes again 2017-05-15 17:42:29 +02:00
Restioson
aad81bead7 Fix style
@gegy1000 don't say *I* get distracted
2017-05-15 17:42:29 +02:00
Restioson
88b55934c7 Fix castException 2017-05-15 17:42:29 +02:00
Restioson
42962dcd48 Fix Noisy turtles not in creative - Thanks @SquidDev 2017-05-15 17:42:29 +02:00
Restioson
093d2ea89f Added PocketSpeaker & corrected blockmodel for turtle speaker 2017-05-15 17:42:29 +02:00
Restioson
97a6679510 Dammit, I hope my git history works now! 2017-05-15 17:38:50 +02:00
Restioson
a3b0e4e993 Added speaker as turtle peripheral 2017-05-15 17:38:50 +02:00
Restioson
3bf15a3798 Added speaker model - potentially glitched 2017-05-15 17:38:50 +02:00
Restioson
dc96f2121a Fix Speaker not playing sounds on break and replace for entire Lua session 2017-05-15 17:38:50 +02:00
Restioson
2899246dbc Fix speaker peripheral API 2017-05-15 17:38:50 +02:00
gegy1000
2444245b80 Speaker rendering and name 2017-05-15 17:38:50 +02:00
Restioson
a748d0167b Fixed Speaker being recognized as Disk Drive. Massive thanks to @SquidDev 2017-05-15 17:38:50 +02:00
Restioson
6cf1801f7e Changed method names to camelCaser 2017-05-15 17:38:50 +02:00
Restioson
61c08afc7f Implemented speaker. It's broken though - thinks it's a Disk Drive
~~Damn Tile Entities these days, always with their identity crises~~
2017-05-15 17:38:50 +02:00
Restioson
61dc61d356 Attempt to fix git history #2 2017-05-15 17:36:29 +02:00
Daniel Ratcliffe
7f365c5102 Merge pull request #232 from SquidDev-CC/feature/remove-duplicate-history
Do not insert empty or duplicate entries into shell history
2017-05-15 14:00:15 +01:00
Daniel Ratcliffe
42874073e9 Merge pull request #230 from SquidDev-CC/feature/dye-improvements
Dye improvements
2017-05-14 21:45:33 +01:00
SquidDev
63cdc7a72e Replace reflection with access transformers
This makes the code slightly neater and allows us to catch places where
the variable/function has been renamed between versions.
2017-05-14 17:01:14 +01:00
SquidDev
cf7308dbc8 Fix holes appearing in coloured turtles
There was a very small gap between the turtle frame and the top of the
turtle body. This increases the height of the body by one pixel, adding
a little bit of overlap and ensuring the frame renders on top fixes
this issue.
2017-05-14 16:02:15 +01:00
SquidDev
b37dbbd0af Allow dying pocket computers too
This splits up the pocket computer textures and models into the frame
(off, on, blinking), colour layer (normal, advanced, custom) and modem
light.
2017-05-14 15:02:56 +01:00
SquidDev
a6b870dfbb Expand IPocketAccess.getLight/setLight to use RGB colours
This allows us to restore the modem light to its original colour.
2017-05-14 14:22:20 +01:00
SquidDev
6426255bd4 Remove getColour and setColour methods from ITurtleAccess
This allows us to remove the m_Colour field from TurtleBrain
2017-05-14 14:17:55 +01:00
SquidDev
8c36eccfef Allow dying turtles arbitrary colours
- Makes ITurtleItem implement IColourableItem
 - Only cache one turtle item model for all colours, rather than one for
   each colour.
 - Allow ITurtleAccess to set an arbitrary colour.
2017-05-14 14:17:55 +01:00
SquidDev
88de097c1c Add more general item colouring system
This allows for other items, such as turtles, to be dyed in the future.
This also adds support for the ore dictionary, meaning you can use other
mod's dyes to colour items.
2017-05-14 14:17:54 +01:00
SquidDev
6ccffe9742 Refactor the filesystem and HTTP code
- Move the encoding/decoding from the Filesystem implementation to the
   individual handles.
 - Move each handle into an core.apis.handles package from the main fs
   API.
 - Move the HTTP response to inherit from these handles.
 - Allow binary handles' read function to accept a number, specifying
   how many characters to read - these will be returned as a Lua string.
 - Add readAll to binary handles
 - Allow binary handles' write function to accept a string which is
   decoded into the individual bytes.
 - Add "binary" argument to http.request and friends in order to return
   a binary handle.
 - Ensure file handles are open when reading from/writing to them.
 - Return the error message when opening a file fails.
2017-05-13 22:47:28 +01:00
Daniel Ratcliffe
2fd01b2adf Merge pull request #233 from SquidDev-CC/feature/file-handle-errors
Provide various error messages for file handles
2017-05-13 21:55:37 +01:00
Daniel Ratcliffe
ea0d688345 Merge pull request #234 from SquidDev-CC/feature/remap-ids
Remap all blocks and items to underscore_case
2017-05-13 21:44:10 +01:00
Daniel Ratcliffe
891666c8bf Merge pull request #220 from SquidDev-CC/feature/item-handler
Replace most inventory handling code with IItemHandlers
2017-05-13 21:31:58 +01:00
SquidDev
a328308f67 Switch from using INetwork to IPacketNetwork 2017-05-13 20:43:12 +01:00
SquidDev
e6ef1cfadd Add packet network API
This provides a publically accessible way of interacting with wireless
networks, hopefully extending to wired networks in the future.

Unlike the original INetwork/IReceiver system, networked devices listen
on all channels, filtering when they recieve the packet. This allows
other peripheral mods to be more flexible in their packet handling.
2017-05-13 20:43:10 +01:00
ObloxCC
7f754f33bb Updated (C) from 2016 to 2017 (#229)
* Updated (C)

* Fixed Whitespace

bugs, bugs, and more bugs

* Fixed Whitespaces 1/2

* Fixed Whitespaces 2/2

* Fixed Whitespaces 3/2
2017-05-13 19:20:39 +01:00
Wilma456
516bd8cf03 Make shell.programs filter .lua extension 2017-05-13 13:37:18 +02:00
SquidDev
add046cbda Remap all blocks and items to underscore_case
This makes block/model names a little mode consistent and should help
with porting to 1.11.2.

 - Prefix all tile entities with "computercraft:".
 - Change all "pascalCase" and "CC-*" items to use underscore_case
 - Listen to the missing mappings event and gracefully convert
   blocks/items.
2017-05-12 13:29:56 +01:00
SquidDev
9908f8c289 Do not insert empty or duplicate entries into shell history
If a string is empty or the same as the previous command then it will
not be inserted into history.
2017-05-11 21:01:23 +01:00
Lignum
259fe4b6b4 Remove unnecessary shell.resolveProgram call 2017-05-11 18:12:58 +02:00
SquidDev
b07f28c30c Replace most inventory handling code with IItemHandlers
- Make InventoryUtil deal with item handlers instead. This
   significantly simplifies the implementation, the interface now
   does most of the hard work.
 - Add InvWrapper item handlers to printers, disk drives and turtles
 - Add IItemHandlerModifiable accessor to ITurtleAccess
 - Migrate all other inventory code (mostly turtle commands) to use
   item handlers instead.
2017-05-11 00:00:10 +01:00
Lignum
8acf43256c Don't sort startup files
fs.list is already sorted, making this unnecessary.
2017-05-10 23:27:07 +02:00
Lignum
962e419098 Allow having a startup directory and a startup.lua file simultaneously 2017-05-10 23:21:04 +02:00
Lignum
2e7c9b163d Enable the use of startup directories 2017-05-10 23:02:08 +02:00
SquidDev
2c63a5f9a3 Provide various error messages for file handles
- fs.open will return an error message if the handle cannot be read
 - fs and http handles will error when reading from a closed file
2017-05-10 10:52:35 +01:00
Daniel Ratcliffe
25128dfb66 Merge pull request #224 from SquidDev-CC/feature/lowercase-models
Lower case most resource names
2017-05-09 20:31:24 +01:00
Daniel Ratcliffe
c049de6939 Merge pull request #221 from SquidDev-CC/feature/nullable-annotations
Fix several crashes caused by incorrect NonNull annotations.
2017-05-09 20:00:02 +01:00
SquidDev
82dbaece41 Lower case all resource names
- Lower case all model and texture names
 - Move model registration code into preInit - this ensures we don't
   get texture/model errors in the preInit stage.
2017-05-09 16:37:32 +01:00
Daniel Ratcliffe
8e3badf4f7 Merge pull request #222 from SquidDev-CC/feature/register-player
Register TurtlePlayer in the entity registry
2017-05-09 14:00:39 +01:00
SquidDev
93aea371a7 Shovel upgrade converts grass to path blocks
Using turtle.dig() with a shovel upgrade on a grass block will create a
path block.

Closes #127
2017-05-09 13:03:12 +01:00
SquidDev
dd63fac8af Register TurtlePlayer in the entity registry
Fixes #143
2017-05-09 12:16:32 +01:00
SquidDev
8b411387f1 Fix several craches caused by incorrect NonNull annotations.
Awfully sorry about this. It appears that Minecraft's annotations are
occasionally wrong. IntelliJ will automatically add "not-null" checks on
these annotations, resulting in crashes when they are actually null.
2017-05-09 00:54:15 +01:00
ObloxCC
922818dfa5 Add setPaletteColor and rgb8 to help files (#214)
* Added rgb8 help

* Update colours

* Added rgb8 help

* Added setPaletteColor help

* Added setPaletteColor help

* Added setColorPalette and rgb8 to change log

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Added changes to change log

* Added changes to whatsnew

* Fixed changelog

* Fixed whatsnew

* Added setPalatteColor

* Fixed Palette spelling

* Added space after 'b'

* Added getPaletteColor

* Ddded getPaletteColor

* Added getPaletteColor()

* Added getPaletteColor

* Update changelog

* Added getPaletteColor
2017-05-07 22:24:32 +01:00
Daniel Ratcliffe
0308ec555a Merge pull request #207 from SquidDev-CC/feature/cleanup
Fix a couple of warnings
2017-05-07 18:26:07 +01:00
Daniel Ratcliffe
008663c0e1 Lua fix 2017-05-07 17:42:39 +01:00
Daniel Ratcliffe
38e09920fa Lua fix 2017-05-07 17:40:23 +01:00
Daniel Ratcliffe
6fba381a4e Merge pull request #211 from Lignum/shell-run-lua
Make shell.resolveProgram pick up on *.lua files
2017-05-07 17:33:44 +01:00
Daniel Ratcliffe
e063f5a6b8 Merge pull request #197 from Lignum/colour-palettes
Modifiable terminal colour palette
2017-05-07 17:31:14 +01:00
Daniel Ratcliffe
0b8b39ced0 colours.rgb8(r,g,b) and colours.rgb8(c) are now the inverse of each other 2017-05-07 17:29:59 +01:00
Daniel Ratcliffe
5f22d8bac6 Enabled setTextColour/setBackgroundColour with all colours on greyscale monitors
It's fine, now that we have greyscale rendering
2017-05-07 17:24:45 +01:00
Daniel Ratcliffe
a5e1dad5fc Enabled term.setText/BackgroundColour with non grey colours on greyscale monitors
As rendering is greyscale now, this is fine.
2017-05-07 17:22:49 +01:00
Daniel Ratcliffe
ebb7d7a8d9 Enabled window.setText/BackgroundColour with no grey colours. Some small optimisations 2017-05-07 17:19:21 +01:00
Lignum
c6abf0b890 Make shell.resolveProgram pick up on *.lua files 2017-05-07 16:21:15 +02:00
Lignum
c10e1ba78c Get rid of setPaletteColour table overload 2017-05-07 15:04:09 +02:00
SquidDev
2e901a063d Remove accessibility modifiers from all enums and interfaces 2017-05-07 13:35:18 +01:00
SquidDev
5a60818c99 Make many fields final 2017-05-07 13:35:18 +01:00
SquidDev
a3400ecf26 Fix all the deprecated warnings 2017-05-07 13:35:05 +01:00
SquidDev
a2fd0b1f7f Use block comment instead of Javadoc for license 2017-05-07 13:30:10 +01:00
SquidDev
db9cd15fb3 Remove most raw types
This means we can remove even more casts and what not.
2017-05-07 13:30:05 +01:00
SquidDev
9af15d1e30 Remove some unnecessary constructs
- Replace for and while loops with for iterators
 - Remove unused casts
2017-05-07 13:29:52 +01:00
SquidDev
dc5517303f Add @Nullable and @NonNull annotations 2017-05-07 13:29:49 +01:00
Lignum
941d47908f Oh bother 2017-05-07 13:09:51 +02:00
Lignum
0164032a4a Allow greyscale palettes on basic computers 2017-05-07 13:04:54 +02:00
Lignum
70c2f50aa8 Un-break the non-table setPaletteColour overload 2017-05-07 12:55:16 +02:00
Lignum
54273fc6e5 Add Palette.DEFAULT 2017-05-07 12:51:06 +02:00
Lignum
4e55e03c8b Don't sync the whole palette in window.setPaletteColour 2017-05-07 12:46:23 +02:00
Lignum
156e74b69c setColour -> setPaletteColour 2017-05-07 12:40:31 +02:00
Daniel Ratcliffe
9d1872c948 Merge pull request #172 from SquidDev-CC/feature/pocket-upgrades
Pocket computer upgrades
2017-05-07 10:32:22 +01:00
SquidDev
8ba5edb6e4 Minor cleanup of pocket computer upgrades
- General improvements of the docs.
 - Move all ItemStack code to the ItemPocketComputer class
 - Make PocketAPI execute on the server thread, rather than the computer
   thread
2017-05-07 08:09:36 +01:00
SquidDev
5a4375f6ac Allow changing the colour of the modem light
This now uses an integer between 0 and 15 to represent a colour, rather
than a simple on/off flag.
2017-05-07 08:09:36 +01:00
SquidDev
6020cd55b1 Added documentation and updated changelog/whatsnew 2017-05-07 08:09:36 +01:00
SquidDev
7f8100ae0f Check the offhand inventory too when searching for upgrades 2017-05-07 08:08:09 +01:00
SquidDev
22631cfc63 Add .equip and .unequip methods to pocket API. 2017-05-07 08:08:09 +01:00
SquidDev
5faceac7ba Add registry for pocket computer upgrades 2017-05-07 08:08:09 +01:00
Daniel Ratcliffe
ff16868dd8 Merge pull request #206 from Lignum/update-craftos-version
Set CraftOS version to 1.8
2017-05-07 00:41:58 +01:00
Lignum
287c6f172c Allow passing RGB8 hex values to term.setColour 2017-05-07 01:16:48 +02:00
Daniel Ratcliffe
cad10fa2c7 Fixed incorrectness in os.day(). Added os.epoch() 2017-05-06 23:56:28 +01:00
Daniel Ratcliffe
58713caa73 Merge pull request #203 from SquidDev-CC/feature/turtle-models
Convert turtle rendering to use tinting
2017-05-06 23:56:13 +01:00
Daniel Ratcliffe
a6e3d4fd26 Merge pull request #195 from SquidDev-CC/hotfix/selection-boxes
Fix selection boxes not being shown
2017-05-06 23:55:45 +01:00
SquidDev
f34a319b79 Make cable collision boxes more accurate for cables
Each cable segment is added to the list, meaning you can get close and
snugly with the cables.
2017-05-06 23:45:15 +01:00
Lignum
1cc403191f Add colours.rgb8(r, g, b)/colours.rgb8(hex) 2017-05-07 00:13:36 +02:00
Lignum
2c7ee1d7e7 Bump CraftOS version to 1.8 2017-05-06 23:26:45 +02:00
Daniel Ratcliffe
3e3c1239b0 Merge pull request #183 from timia2109/master
Add real world time support
2017-05-06 22:26:14 +01:00
Daniel Ratcliffe
4b4e041f6f Merge branch 'master' into master 2017-05-06 22:25:46 +01:00
Daniel Ratcliffe
423d5af87f Merge pull request #191 from SquidDev-CC/feature/text-illumination
Make monitor text glow in the dark
2017-05-06 22:11:28 +01:00
Daniel Ratcliffe
5b6bbc3cbf Merge pull request #200 from Lignum/fs-weak-set
Replace WeakHashMap for open files with a weak set
2017-05-06 21:44:28 +01:00
Daniel Ratcliffe
f4dab801e4 Merge pull request #204 from SquidDev-CC/feature/some-deprecation
Use IBlockState instead of Block methods
2017-05-06 21:41:54 +01:00
Lignum
a9e7acbec5 Fix monitors fetching palette when there is no terminal 2017-05-06 20:23:44 +02:00
Lignum
ac2382a861 Add setColour overload with table parameter 2017-05-06 20:22:16 +02:00
SquidDev
2f93354981 Remove dye block state property
It doesn't make sense to have it now as the coloured models do not exist
any more, and so would just produce errors should we try to load them.
2017-05-06 17:41:49 +01:00
SquidDev
c7f5d039b2 Use IBlockState instead of Block methods
There was a crash in RedstoneUtil when redstone state was changing next
to a full block due to the incorrect state being passed. By using
IBlockState methods we ensure that this cannot happen again.

The old IBlockState methods were also deprecated, so this reduces the
warning count a little. I've also moved string translation into
StringUtils, to reduce the number of deprecation warnings from there.
2017-05-06 15:31:06 +01:00
SquidDev
d652bdb0b0 Convert turtle rendering to use tinting
This uses Minecraft's colour tinting system in order to change the
colour of turtle models. This removes the need to have 16 models and
textures for each colour, reducing texture atlas space and hopefully
memory consumption.

See #145
2017-05-06 15:06:02 +01:00
Tim Ittermann
f1c4634dfa os.time( ... ) now returns float 2017-05-06 14:52:02 +02:00
Tim Ittermann
f89bbeee54 Remove import 2017-05-06 14:30:19 +02:00
Tim Ittermann
e0e81a9b18 Put time functions into the OS API 2017-05-06 14:24:48 +02:00
Lignum
bfa5f6ec9c Make palettes work properly with the window API 2017-05-05 20:23:57 +02:00
Lignum
988e9f10db Fix compiler error 2017-05-05 19:13:52 +02:00
Lignum
b0ac48b9a3 Use some sweet tricks to have a weak set to store open files 2017-05-05 19:11:59 +02:00
Lignum
3de674dfb1 Simplify the palette payload to an int array 2017-05-05 18:47:43 +02:00
Lignum
39a56c8e55 Get rid of the PaletteColour class
It just took up a bunch of space. We're storing an array of float[3] now.
2017-05-05 18:22:48 +02:00
Daniel Ratcliffe
06b63980eb Merge pull request #196 from SquidDev-CC/feature/docs
Fix several documentation warnings
2017-05-05 17:19:26 +01:00
Daniel Ratcliffe
3eae944923 Merge pull request #198 from SquidDev-CC/hotfix/no-reset-redstone
Do not reset redstone inputs when adding peripherals
2017-05-05 17:17:15 +01:00
Lignum
6997471280 Add palette functions to monitor peripheral 2017-05-05 18:12:33 +02:00
SquidDev
4b95ed5d53 Do not reset redstone inputs when adding peripherals
As of 8abff95441, peripherals no longer
block redstone input. As this is no longer the case, redstone levels
should not be reset.
2017-05-05 17:00:44 +01:00
Lignum
088dab799e Network the colour palette
Which means it actually has a visible effect! 🎉
2017-05-05 17:21:53 +02:00
SquidDev
0cdd0ea21a Change license headers to block comments
This means they do not get picked up by Javadoc and friends
2017-05-05 16:16:09 +01:00
Daniel Ratcliffe
c413b9af04 Merge pull request #194 from SquidDev-CC/feature/docs
General improvements to the documentation
2017-05-05 16:08:45 +01:00
SquidDev
76e926c090 Document several undocumented arguments and exceptions 2017-05-05 16:07:18 +01:00
SquidDev
d87b0e9435 Fix selection boxes not being shown
getSelectedBoundingBox expects a bounding box relative to (0, 0, 0) but
we were returning one relative to the current block. Instead we allow
the default behaviour to continue, which will call getBoundingBox and
offset it.
2017-05-05 15:25:07 +01:00
Lignum
b0f0d8fd71 Add getColour/setColour to the window api 2017-05-05 16:14:13 +02:00
SquidDev
7b07921a73 General improvements to the documentation
- Add documentation for all undocumented methods and enums.
 - Use @code, @link and @see where appropriate.
 - Fix spelling in a couple of cases.
2017-05-05 14:59:11 +01:00
Lignum
56c9dec687 Add term.setColour/term.getColour 2017-05-05 15:52:21 +02:00
Lignum
936a531cd5 Add a palette class and use it for rendering 2017-05-05 15:24:29 +02:00
Daniel Ratcliffe
09215daa03 FileSystem uses a WeakHashMap to store it's open file handles
This means if lua code forgets to free a handle, the java GC will still
be able to collect the stream (andclose the file in the finaliser in the
process)
2017-05-05 00:54:24 +01:00
Daniel Ratcliffe
42f2235d45 Made the black colour on monitors, terminals, block and item graphics darker
0x111111 is now used throughout, previously there was quite a bit of
variance
2017-05-05 00:54:24 +01:00
Daniel Ratcliffe
2436d813e6 Treat a maximumFilesOpen values of 0 as unlimited 2017-05-05 00:54:23 +01:00
Daniel Ratcliffe
6271555c45 Merge pull request #192 from Lignum/render-improvements
Small terminal & monitor rendering improvements
2017-05-04 23:09:48 +01:00
Lignum
4b8493baab Terminal cursor bounds checking 2017-05-05 00:08:10 +02:00
Lignum
4e3def39e0 Render terminal cursor in a less awkward way
The previous way seemed weird enough to seem to have had a purpose, but I can't tell. Revert this if it turns out that there was.
2017-05-04 23:53:43 +02:00
Lignum
7e71045c7b Remove texture coordinates from text background part 2017-05-04 23:49:08 +02:00
Lignum
2d5d5e3a9e Use GL_TRIANGLES in FixedWidthFontRenderer 2017-05-04 23:43:05 +02:00
Lignum
c0b5b6af07 Add ".idea" to .gitignore 2017-05-04 23:39:12 +02:00
Lignum
c104eabcdd Use GlStateManager where necessary, replace GL_QUADS with GL_TRIANGLE_STRIP 2017-05-04 23:38:24 +02:00
SquidDev
933bdcc6b7 Make monitor text glow in the dark 2017-05-04 22:24:39 +01:00
Tim Ittermann
45803e4a49 Replace get...() functions with properties. NOT ALL TESTED YET! 2017-05-04 23:18:03 +02:00
Daniel Ratcliffe
8abff95441 Peripherals no longer break turtle<->redstone connectivity
I can't think of a good reason for this feature tbh
2017-05-04 22:13:14 +01:00
Daniel Ratcliffe
f99caed4f2 Merge pull request #169 from Lignum/fd-limit
Configurable file descriptor limit
2017-05-04 22:12:50 +01:00
Daniel Ratcliffe
4b0a976bd6 Merge pull request #182 from SquidDev-CC/feature/turtle-upgrade-both
Allow turtle upgrades to act as tools and peripherals
2017-05-04 22:02:09 +01:00
Lignum
30d191df0b Avoid casts with generic type args 2017-05-04 23:00:02 +02:00
Daniel Ratcliffe
17a3e120e8 Merge pull request #180 from boq/master
Handle tile entity changes
2017-05-04 21:42:34 +01:00
Daniel Ratcliffe
55b160e1bb Merge pull request #164 from SquidDev-CC/hotfix/turtle-connectivity
Fix redstone connectivity on turtles
2017-05-04 21:28:08 +01:00
Daniel Ratcliffe
a57eb14113 Added windows setup script 2017-05-04 21:14:28 +01:00
Daniel Ratcliffe
fa99305914 Merge pull request #168 from SquidDev-CC/hotfix/modem-model-rotation
Various model improvements
2017-05-04 21:08:51 +01:00
Daniel Ratcliffe
27ef182294 Merge pull request #158 from SquidDev-CC/feature/require-container
Require the player to be interacting with the computer when typing
2017-05-04 21:08:34 +01:00
Daniel Ratcliffe
82e76d9872 Merge pull request #184 from SquidDev-CC/hotfix/sort-list
Sort the result of FileSystem.list
2017-05-04 21:06:26 +01:00
Daniel Ratcliffe
2a0556fa4c Merge pull request #185 from SquidDev-CC/hotfix/unpack-length
Manually specify the number of values to unpack
2017-05-04 21:05:14 +01:00
Daniel Ratcliffe
22e36fc35d Merge pull request #178 from boq/patch-1
Fix compilation error
2017-05-04 21:04:14 +01:00
Daniel Ratcliffe
655a328b86 Merge pull request #174 from SquidDev-CC/hotfix/shutdown-abort
Send termination signals unless the computer is off
2017-05-04 21:03:40 +01:00
Daniel Ratcliffe
df1ef7133d Merge pull request #181 from SquidDev-CC/hotfix/gps-locate
Ensure GPS coordinates are numbers
2017-05-04 21:02:36 +01:00
SquidDev
bd14223ea8 Manually specify the number of values to unpack
table.unpack will often stop at the first nil value, meaning some event
arguments may be discarded. By storing the number of arguments through
table.pack, and then using that count when unpacking, we can ensure all
values are returned/resumed with.
2017-05-04 10:49:41 +01:00
SquidDev
72dfb0e7cc Sort the result of FileSystem.list
This ensures fs.list and fs.find always return the same result.

For some reason, the ComputerCraft jar was being packaged differently on
some platforms, causing files to appear in a different order. As
computers depend on the colors API being loaded before colours, we need
to ensure that they are loaded in a consistent order.
2017-05-03 22:29:57 +01:00
Tim Ittermann
b2cc6ec82a Add TimeAPI to Computers APIs 2017-05-03 23:12:48 +02:00
Tim Ittermann
c1d5ae2a09 Rename src/main/java/dan200.computercraft/core/apis/TimeAPI.java to src/main/java/dan200/computercraft/core/apis/TimeAPI.java 2017-05-03 23:11:52 +02:00
Tim Ittermann
627524dcb7 Create TimeAPI.java 2017-05-03 23:10:58 +02:00
SquidDev
6b6829e22b Use tonumber when validating message format 2017-05-03 18:39:32 +01:00
SquidDev
67eecd4b1c Use tonumber instead of checking type 2017-05-03 18:21:14 +01:00
SquidDev
a021a072b5 Allow turtle upgrades to act as tools and peripherals
This may be useful when you want your tool to also provide additional
methods. For instance, a pickaxe could provide methods to check whether
it can break the block in front.
2017-05-03 17:28:54 +01:00
SquidDev
7e5970673f Ensure GPS coordinates are numbers
Fixes #138
2017-05-03 16:35:45 +01:00
Bartek Bok
4eb4bb933f Different fix for shadow turtles 2017-05-03 16:03:47 +02:00
Bartek Bok
5284b145f8 Handle tile entity changes 2017-05-03 11:36:55 +02:00
Bartek Bok
bd8769f300 Fix compilation error 2017-05-02 23:40:31 +02:00
Lignum
994dcd9f58 Localise the maximumFilesOpen setting 2017-05-02 18:29:50 +02:00
Lignum
2bfb53227a Merge master into fd-limit 2017-05-02 18:26:45 +02:00
SquidDev
ba761a15b6 Send termination signals unless the computer is off
If a shutdown has been queued, then the abort message was not set. This
allowed for programs to run for a significantly longer period of time.
2017-05-02 14:04:48 +01:00
Daniel Ratcliffe
58e6e9ea46 Fixed a typo 2017-05-02 13:56:24 +01:00
Daniel Ratcliffe
4825aefccf Merge pull request #167 from SquidDev-CC/hotfix/limit-label
Impose additional limitations on disk and computer labels
2017-05-02 13:54:43 +01:00
Daniel Ratcliffe
3a360a50b0 Merge pull request #166 from SquidDev-CC/feature/config-gui
Add config GUI
2017-05-02 13:46:01 +01:00
SquidDev
65ef8a0937 Add config GUI description to changelog/whatsnew 2017-05-02 13:35:05 +01:00
SquidDev
14d3a182d9 Fix NPE when clearing disk label 2017-05-02 13:32:53 +01:00
Daniel Ratcliffe
800e448264 Improved the wording of some of the labels in the Config UI 2017-05-02 13:28:54 +01:00
SquidDev
2fef772f3d Use '?' for unprintable characters 2017-05-02 13:24:42 +01:00
Daniel Ratcliffe
463d6fdcbe Fixed some typos 2017-05-02 13:18:20 +01:00
Daniel Ratcliffe
b2c786c06c Merge pull request #171 from JLLeitschuh/fix/daemon_thread
Make threads daemon threads
2017-05-02 08:53:05 +01:00
SquidDev
c537c4fa78 Swap from builtin/generated to item/generated
This model has more sane defaults, meaning items are scaled to the
appropriate size.
2017-05-02 02:12:51 +01:00
Jonathan Leitschuh
2a01883177 Make threads daemon threads
Threads that aren't daemon threads can keep the JVM from shutting down.
I'm certain that this doesn't happen very often but if one of these
threads hangs it can cause the rest of the JVM to not shut down
when the main thread exits.
By making all threads daemon threads if the main thread terminates
the rest of these threads will shut down.
2017-05-01 20:34:28 -04:00
SquidDev
c190ec5147 Do not limit labels to the ASCII range.
This should accept all printable characters that ComputerCraft can
handle.
2017-05-02 00:20:46 +01:00
Lignum
6ff9db89cc Fix file handle leak 2017-05-02 00:44:33 +02:00
Lignum
2a1e110a65 Make the file descriptor limit configurable 2017-05-02 00:17:16 +02:00
SquidDev
d08b47db93 Preserve default values in configuration
Before we were setting the default as the previous value each time. Here
we store each property in a separate field, allowing us to access them
without setting a default.
2017-05-01 23:14:06 +01:00
Lignum
2d0690e625 Add file descriptor limit 2017-05-02 00:05:42 +02:00
SquidDev
876df68294 Rotate modem models 180 degrees
Or pi radians. Or tau/2 radians.

This ensures the main modem texture is facing towards the screen.
2017-05-01 22:39:18 +01:00
SquidDev
b1efbdad95 Impose additional limitations on disk and computer labels
Closes #147
2017-05-01 22:23:54 +01:00
SquidDev
230b578a98 Add config GUI
This allows you to modify various settings in-game.
2017-05-01 22:14:45 +01:00
SquidDev
02ce111d9e Invert side when checking connectivity
The side marks the direction relative to the wire, rather than the side
of the block it is attempting to connect to. Therefore needs to be
flipped.

Closes #149
2017-05-01 21:44:48 +01:00
Daniel Ratcliffe
1b562ae837 Merge pull request #159 from SquidDev-CC/feature/http-extensions
Various extensions to the HTTP API
2017-05-01 18:11:21 +01:00
SquidDev
ae04070915 Update documentation to include HTTP API changes 2017-05-01 18:05:04 +01:00
SquidDev
f2596a8547 Return string->string headers instead, joining fields with a comma. 2017-05-01 18:00:53 +01:00
Daniel Ratcliffe
6cd734a305 Merge pull request #160 from JLLeitschuh/patch-1
Add travis-ci build status badge to README
2017-05-01 17:54:27 +01:00
Jonathan Leitschuh
d4cb5f6f3f Add travis-ci build status badge to README 2017-05-01 12:50:15 -04:00
Daniel Ratcliffe
5775c77aa3 Merge pull request #157 from JLLeitschuh/feat/add-travis
Add travis.yml file to project
2017-05-01 17:38:47 +01:00
SquidDev
29952d5b4f Various extensions to the HTTP API
- A response is returned on the event of a HTTP error (such as 404).
 - Responses include the response headers.
2017-05-01 17:35:06 +01:00
SquidDev
b2542289f0 Require the player to be interacting with the computer when typing
Packets will be discarded if the sending player is not currently
interacting with the appropriate computer. This ensures players cannot
control other people's computers.

This is enforced by checking if the current container is a "computer
container", and this container holds the correct computer.
2017-05-01 17:07:32 +01:00
Jonathan Leitschuh
910ac37716 Add travis.yml file to project 2017-05-01 12:00:47 -04:00
Daniel Ratcliffe
ec7a251c09 Merge pull request #156 from SquidDev-CC/feature/fs-find-performance
Performance improvements to fs.find
2017-05-01 16:47:44 +01:00
Daniel Ratcliffe
92b319a05b Merge pull request #155 from JLLeitschuh/bug/make_gradlew_executable
Make gradlew executable by default
2017-05-01 16:46:37 +01:00
SquidDev
b3760f58e6 Performance improvements to fs.find
If the path includes no wildcards then it just checks it exists.
If it does, instead of scanning the entire tree, it works out the last
directory before the wildcard and starts scanning from there.

Closes #89
2017-05-01 16:45:41 +01:00
Jonathan Leitschuh
a74388c954 Make gradlew executable by default 2017-05-01 11:43:41 -04:00
Daniel Ratcliffe
5c6369b910 Merge pull request #154 from SquidDev-CC/hotfix/unborked-patches
Various fixes for 1.9.4
2017-05-01 16:31:14 +01:00
SquidDev
bbbbccf63d Fire all entity interaction events in TurtlePlaceCommand
This allows turtles to interact with entities correctly.
2017-05-01 16:14:05 +01:00
SquidDev
d050ca9849 Fix advanced computer's item model 2017-05-01 16:10:45 +01:00
SquidDev
77d225d1fe Listen to correct block update
We now listen to neighborChanged instead of onNeighborChange. This means
computers correctly detect redstone updates.

However, this leads to issues when moving turtles, so we defer the block
update until the turtle has finished moving.
2017-05-01 16:08:27 +01:00
SquidDev
9b5f4a877c Fix null bounding box being returned
Its usage is not always checked for null, so it is safer to return a
full block.
2017-05-01 16:04:42 +01:00
SquidDev
34cb75dfc3 Fix various tile entities not syncing correctly
This ensures the tile state is sent and received when it changes. This
fixes turtles facing the wrong direction and computers not turning on.
2017-05-01 16:04:36 +01:00
SquidDev
43d68db349 Add missing classes 2017-05-01 16:02:47 +01:00
Daniel Ratcliffe
b202b7b8a5 Converted tabs to spaces throughout 2017-05-01 15:48:44 +01:00
Daniel Ratcliffe
df01405583 codesize.sh now counts JSON too 2017-05-01 15:24:08 +01:00
826 changed files with 26767 additions and 20830 deletions

2
.gitignore vendored
View File

@@ -5,6 +5,8 @@ deploy
*.ipr *.ipr
*.iws *.iws
*.iml *.iml
.idea
.gradle .gradle
luaj-2.0.3/lib luaj-2.0.3/lib
luaj-2.0.3/*.jar luaj-2.0.3/*.jar
*.DS_Store

14
.travis.yml Normal file
View File

@@ -0,0 +1,14 @@
language: java
script: ./gradlew build --no-daemon
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/s
jdk:
- oraclejdk8

View File

@@ -36,7 +36,7 @@ This mod is provided 'as is' with no warranties, implied or otherwise. The owner
of this mod takes no responsibility for any damages incurred from the use of of this mod takes no responsibility for any damages incurred from the use of
this mod. This mod alters fundamental parts of the Minecraft game, parts of this mod. This mod alters fundamental parts of the Minecraft game, parts of
Minecraft may not work with this mod installed. All damages caused from the use Minecraft may not work with this mod installed. All damages caused from the use
or misuse of this mad fall on the user. or misuse of this mod fall on the user.
3. Play rights 3. Play rights
-------------- --------------

View File

@@ -1,5 +1,6 @@
ComputerCraft ComputerCraft
============= =============
[![Build Status](https://travis-ci.org/dan200/ComputerCraft.svg?branch=master)](https://travis-ci.org/dan200/ComputerCraft)
ComputerCraft is a Minecraft modification which adds programmable Robots and Computers to the world of Minecraft. ComputerCraft is a Minecraft modification which adds programmable Robots and Computers to the world of Minecraft.
If you're not familiar with ComputerCraft, visit the [Website](http://www.computercraft.info/download) or the [Wiki](http://www.computercraft.info/wiki) to find out more. If you're not familiar with ComputerCraft, visit the [Website](http://www.computercraft.info/download) or the [Wiki](http://www.computercraft.info/wiki) to find out more.
@@ -14,7 +15,7 @@ The code in this repository will always represent the "bleeding edge" of the Com
Contributing Contributing
============ ============
While ComputerCraft will no longer be actively developed by Daniel Ratcliffe, you may still contribute pull requests which will be reviewed and incorporated into releases periodically. A pull requests is more likely to be accepted if it meets the following criteria: While ComputerCraft will no longer be actively developed by Daniel Ratcliffe, you may still contribute pull requests which will be reviewed and incorporated into releases periodically. A pull request is more likely to be accepted if it meets the following criteria:
* It does not add any new dependencies for compiling, running or using the mod. * It does not add any new dependencies for compiling, running or using the mod.
* It does not break compatibility with world saves or programs created with previous versions of the mod. * It does not break compatibility with world saves or programs created with previous versions of the mod.

View File

@@ -9,10 +9,12 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT' classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
classpath 'org.ajoberstar:gradle-git:1.6.0'
} }
} }
apply plugin: 'net.minecraftforge.gradle.forge' apply plugin: 'net.minecraftforge.gradle.forge'
apply plugin: 'org.ajoberstar.grgit'
/* /*
// for people who want stable - not yet functional for MC 1.8.8 - we require the forgegradle 2.1 snapshot // for people who want stable - not yet functional for MC 1.8.8 - we require the forgegradle 2.1 snapshot
@@ -21,21 +23,21 @@ plugins {
} }
*/ */
version = "1.80pr0" version = "1.80pr1"
group = "dan200.computercraft" group = "dan200.computercraft"
archivesBaseName = "ComputerCraft" archivesBaseName = "ComputerCraft"
minecraft { minecraft {
version = "1.9.4-12.17.0.1959" version = "1.12-14.21.1.2387"
runDir = "run" runDir = "run"
replace '${version}', project.version replace '${version}', project.version
// the mappings can be changed at any time, and must be in the following format. // the mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD snapshot are built nightly. // snapshot_YYYYMMDD snapshot are built nightly.
// stable_# stables are built at the discretion of the MCP team. // stable_# stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not allways work. // Use non-default mappings at your own risk. they may not allways work.
// simply re-run your setup task after changing the mappings to update your workspace. // simply re-run your setup task after changing the mappings to update your workspace.
mappings = "snapshot_20160518" mappings = "snapshot_20170629"
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
} }
@@ -44,7 +46,7 @@ dependencies {
// or you may define them like so.. // or you may define them like so..
//compile "some.group:artifact:version:classifier" //compile "some.group:artifact:version:classifier"
//compile "some.group:artifact:version" //compile "some.group:artifact:version"
// real examples // real examples
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env //compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
@@ -63,23 +65,47 @@ dependencies {
} }
processResources jar {
{ manifest {
// this will ensure that this task is redone when the versions change. attributes('FMLAT': 'computercraft_at.cfg')
inputs.property "version", project.version }
inputs.property "mcversion", project.minecraft.version }
// replace stuff in mcmod.info, nothing else import org.ajoberstar.grgit.Grgit
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info' processResources {
inputs.property "version", project.version
// replace version and mcversion inputs.property "mcversion", project.minecraft.version
expand 'version':project.version, 'mcversion':project.minecraft.version
} def grgit = Grgit.open(dir: '.')
inputs.property "commithash", grgit.head().id
// copy everything else, thats not the mcmod.info
from(sourceSets.main.resources.srcDirs) { def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
exclude 'mcmod.info' Set<String> contributors = []
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)
}
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')
}
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
exclude 'assets/computercraft/lua/rom/help/credits.txt'
}
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint"
} }
} }

View File

@@ -3,4 +3,8 @@ echo "Java code:"
cat `find src | grep \\.java$` | wc cat `find src | grep \\.java$` | wc
echo "Lua code:" echo "Lua code:"
cat `find src/main/resources/assets/computercraft/lua` | wc cat `find src/main/resources/assets/computercraft/lua | grep \\.lua$` | wc
echo "JSON:"
cat `find src/main/resources/assets/computercraft | grep \\.json$` | wc

0
deploy.sh Normal file → Executable file
View File

0
gradlew vendored Normal file → Executable file
View File

90
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-d64 -Xmx2048m"
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

7
setup.bat Normal file
View File

@@ -0,0 +1,7 @@
echo "Setting up IntelliJ development environment with gradle..."
rmdir /s /q .\build
call gradlew.bat --stacktrace setupDecompWorkspace --refresh-dependencies
call gradlew.bat --stacktrace cleanIdea idea
echo "Done."
pause

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
@@ -8,15 +8,22 @@ package dan200.computercraft.api;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.media.IMediaProvider; import dan200.computercraft.api.media.IMediaProvider;
import dan200.computercraft.api.network.IPacketNetwork;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.api.permissions.ITurtlePermissionProvider; import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
/** /**
@@ -32,6 +39,7 @@ public final class ComputerCraftAPI
return computerCraft != null; return computerCraft != null;
} }
@Nonnull
public static String getInstalledVersion() public static String getInstalledVersion()
{ {
findCC(); findCC();
@@ -46,116 +54,134 @@ public final class ComputerCraftAPI
return ""; return "";
} }
@Nonnull
public static String getAPIVersion() public static String getAPIVersion()
{ {
return "${version}"; return "${version}";
} }
/** /**
* Creates a numbered directory in a subfolder of the save directory for a given world, and returns that number.<br> * Creates a numbered directory in a subfolder of the save directory for a given world, and returns that number.
* Use in conjuction with createSaveDirMount() to create a unique place for your peripherals or media items to store files.<br> *
* @param world The world for which the save dir should be created. This should be the serverside world object. * Use in conjunction with createSaveDirMount() to create a unique place for your peripherals or media items to store files.
* @param parentSubPath The folder path within the save directory where the new directory should be created. eg: "computercraft/disk" *
* @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some reason.<br> * @param world The world for which the save dir should be created. This should be the server side world object.
* eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now available for writing. * @param parentSubPath The folder path within the save directory where the new directory should be created. eg: "computercraft/disk"
* @see #createSaveDirMount(World, String, long) * @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some reason.
*/ *
public static int createUniqueNumberedSaveDir( World world, String parentSubPath ) * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now
{ * available for writing.
findCC(); * @see #createSaveDirMount(World, String, long)
if( computerCraft_createUniqueNumberedSaveDir != null ) */
{ public static int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath )
try { {
return (Integer)computerCraft_createUniqueNumberedSaveDir.invoke( null, world, parentSubPath ); findCC();
} catch (Exception e) { if( computerCraft_createUniqueNumberedSaveDir != null )
// It failed {
} try {
} return (Integer)computerCraft_createUniqueNumberedSaveDir.invoke( null, world, parentSubPath );
return -1; } catch (Exception e) {
} // It failed
}
/** }
* Creates a file system mount that maps to a subfolder of the save directory for a given world, and returns it.<br> return -1;
* Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the }
* users save directory onto a computers file system.<br>
* @param world The world for which the save dir can be found. This should be the serverside world object. /**
* @param subPath The folder path within the save directory that the mount should map to. eg: "computer/disk/42".<br> * Creates a file system mount that maps to a subfolder of the save directory for a given world, and returns it.
* Use createUniqueNumberedSaveDir() to create a new numbered folder to use. *
* @param capacity The ammount of data that can be stored in the directory before it fills up, in bytes. * Use in conjunction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the
* @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() * users save directory onto a computers file system.
* to mount this on a Computers' file system. *
* @see #createUniqueNumberedSaveDir(World, String) * @param world The world for which the save dir can be found. This should be the server side world object.
* @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, dan200.computercraft.api.filesystem.IMount) * @param subPath The folder path within the save directory that the mount should map to. eg: "computer/disk/42".
* @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, dan200.computercraft.api.filesystem.IWritableMount) * Use createUniqueNumberedSaveDir() to create a new numbered folder to use.
* @see dan200.computercraft.api.filesystem.IMount * @param capacity The amount of data that can be stored in the directory before it fills up, in bytes.
* @see IWritableMount * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable()
*/ * to mount this on a Computers' file system.
public static IWritableMount createSaveDirMount( World world, String subPath, long capacity ) * @see #createUniqueNumberedSaveDir(World, String)
{ * @see IComputerAccess#mount(String, IMount)
findCC(); * @see IComputerAccess#mountWritable(String, IWritableMount)
if( computerCraft_createSaveDirMount != null ) * @see IMount
{ * @see IWritableMount
try { */
return (IWritableMount)computerCraft_createSaveDirMount.invoke( null, world, subPath, capacity ); @Nullable
} catch (Exception e){ public static IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity )
// It failed {
} findCC();
} if( computerCraft_createSaveDirMount != null )
return null; {
} try {
return (IWritableMount)computerCraft_createSaveDirMount.invoke( null, world, subPath, capacity );
/** } catch (Exception e){
* Creates a file system mount to a resource folder, and returns it.<br> // It failed
* Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a resource folder onto a computers file system.<br> }
* The files in this mount will be a combination of files in the specified mod jar, and resource packs that contain resources with the same domain and path.<br> }
* @param modClass A class in whose jar to look first for the resources to mount. Using your main mod class is recommended. eg: MyMod.class return null;
* @param domain The domain under which to look for resources. eg: "mymod" }
* @param subPath The domain under which to look for resources. eg: "mymod/lua/myfiles"
* @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() /**
* to mount this on a Computers' file system. * Creates a file system mount to a resource folder, and returns it.
* @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, dan200.computercraft.api.filesystem.IMount) *
* @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, IWritableMount) * Use in conjunction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a resource folder
* @see dan200.computercraft.api.filesystem.IMount * onto a computer's file system.
*/ *
public static IMount createResourceMount( Class modClass, String domain, String subPath ) * The files in this mount will be a combination of files in the specified mod jar, and resource packs that contain
{ * resources with the same domain and path.
findCC(); *
if( computerCraft_createResourceMount != null ) * @param modClass A class in whose jar to look first for the resources to mount. Using your main mod class is recommended. eg: MyMod.class
{ * @param domain The domain under which to look for resources. eg: "mymod".
try { * @param subPath The domain under which to look for resources. eg: "mymod/lua/myfiles".
return (IMount)computerCraft_createResourceMount.invoke( null, modClass, domain, subPath ); * @return The mount, or {@code null} if it could be created for some reason. Use IComputerAccess.mount() or
} catch (Exception e){ * IComputerAccess.mountWritable() to mount this on a Computers' file system.
// It failed * @see IComputerAccess#mount(String, IMount)
} * @see IComputerAccess#mountWritable(String, IWritableMount)
} * @see IMount
return null; */
} @Nullable
public static IMount createResourceMount( @Nonnull Class<?> modClass, @Nonnull String domain, @Nonnull String subPath )
/** {
* Registers a peripheral handler to convert blocks into IPeripheral implementations. findCC();
* @see dan200.computercraft.api.peripheral.IPeripheral if( computerCraft_createResourceMount != null )
* @see dan200.computercraft.api.peripheral.IPeripheralProvider {
*/ try {
public static void registerPeripheralProvider( IPeripheralProvider handler ) return (IMount)computerCraft_createResourceMount.invoke( null, modClass, domain, subPath );
{ } catch (Exception e){
findCC(); // It failed
if ( computerCraft_registerPeripheralProvider != null) }
{ }
try { return null;
computerCraft_registerPeripheralProvider.invoke( null, handler ); }
} catch (Exception e){
// It failed /**
} * Registers a peripheral handler to convert blocks into {@link IPeripheral} implementations.
} *
} * @param handler The peripheral provider to register.
* @see dan200.computercraft.api.peripheral.IPeripheral
* @see dan200.computercraft.api.peripheral.IPeripheralProvider
*/
public static void registerPeripheralProvider( @Nonnull IPeripheralProvider handler )
{
findCC();
if ( computerCraft_registerPeripheralProvider != null)
{
try {
computerCraft_registerPeripheralProvider.invoke( null, handler );
} catch (Exception e){
// It failed
}
}
}
/** /**
* Registers a new turtle turtle for use in ComputerCraft. After calling this, * Registers a new turtle turtle for use in ComputerCraft. After calling this,
* users should be able to craft Turtles with your new turtle. It is recommended to call * users should be able to craft Turtles with your new turtle. It is recommended to call
* this during the load() method of your mod. * this during the load() method of your mod.
*
* @param upgrade The turtle upgrade to register.
* @see dan200.computercraft.api.turtle.ITurtleUpgrade * @see dan200.computercraft.api.turtle.ITurtleUpgrade
*/ */
public static void registerTurtleUpgrade( ITurtleUpgrade upgrade ) public static void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade )
{ {
if( upgrade != null ) if( upgrade != null )
{ {
@@ -172,10 +198,12 @@ public final class ComputerCraftAPI
} }
/** /**
* Registers a bundled redstone handler to provide bundled redstone output for blocks * Registers a bundled redstone handler to provide bundled redstone output for blocks.
*
* @param handler The bundled redstone provider to register.
* @see dan200.computercraft.api.redstone.IBundledRedstoneProvider * @see dan200.computercraft.api.redstone.IBundledRedstoneProvider
*/ */
public static void registerBundledRedstoneProvider( IBundledRedstoneProvider handler ) public static void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider handler )
{ {
findCC(); findCC();
if( computerCraft_registerBundledRedstoneProvider != null ) if( computerCraft_registerBundledRedstoneProvider != null )
@@ -190,11 +218,15 @@ public final class ComputerCraftAPI
/** /**
* If there is a Computer or Turtle at a certain position in the world, get it's bundled redstone output. * If there is a Computer or Turtle at a certain position in the world, get it's bundled redstone output.
* @see dan200.computercraft.api.redstone.IBundledRedstoneProvider *
* @param world The world this block is in.
* @param pos The position this block is at.
* @param side The side to extract the bundled redstone output from.
* @return If there is a block capable of emitting bundled redstone at the location, it's signal (0-65535) will be returned. * @return If there is a block capable of emitting bundled redstone at the location, it's signal (0-65535) will be returned.
* If there is no block capable of emitting bundled redstone at the location, -1 will be returned. * If there is no block capable of emitting bundled redstone at the location, -1 will be returned.
* @see dan200.computercraft.api.redstone.IBundledRedstoneProvider
*/ */
public static int getBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ) public static int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
{ {
findCC(); findCC();
if( computerCraft_getDefaultBundledRedstoneOutput != null ) if( computerCraft_getDefaultBundledRedstoneOutput != null )
@@ -209,10 +241,12 @@ public final class ComputerCraftAPI
} }
/** /**
* Registers a media handler to provide IMedia implementations for Items * Registers a media handler to provide {@link IMedia} implementations for Items
*
* @param handler The media provider to register.
* @see dan200.computercraft.api.media.IMediaProvider * @see dan200.computercraft.api.media.IMediaProvider
*/ */
public static void registerMediaProvider( IMediaProvider handler ) public static void registerMediaProvider( @Nonnull IMediaProvider handler )
{ {
findCC(); findCC();
if( computerCraft_registerMediaProvider != null ) if( computerCraft_registerMediaProvider != null )
@@ -226,10 +260,12 @@ public final class ComputerCraftAPI
} }
/** /**
* Registers a permission handler to restrict where turtles can move or build * Registers a permission handler to restrict where turtles can move or build.
*
* @param handler The turtle permission provider to register.
* @see dan200.computercraft.api.permissions.ITurtlePermissionProvider * @see dan200.computercraft.api.permissions.ITurtlePermissionProvider
*/ */
public static void registerPermissionProvider( ITurtlePermissionProvider handler ) public static void registerPermissionProvider( @Nonnull ITurtlePermissionProvider handler )
{ {
findCC(); findCC();
if( computerCraft_registerPermissionProvider != null ) if( computerCraft_registerPermissionProvider != null )
@@ -242,76 +278,116 @@ public final class ComputerCraftAPI
} }
} }
public static void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade )
{
findCC();
if(computerCraft_registerPocketUpgrade != null) {
try {
computerCraft_registerPocketUpgrade.invoke( null, upgrade );
} catch (Exception e) {
// It failed
}
}
}
/**
* Attempt to get the game-wide wireless network.
*
* @return The global wireless network, or {@code null} if it could not be fetched.
*/
public static IPacketNetwork getWirelessNetwork()
{
findCC();
if( computerCraft_getWirelessNetwork != null )
{
try
{
return (IPacketNetwork) computerCraft_getWirelessNetwork.invoke( null );
} catch (Exception e) {
// It failed;
}
}
return null;
}
// The functions below here are private, and are used to interface with the non-API ComputerCraft classes. // The functions below here are private, and are used to interface with the non-API ComputerCraft classes.
// Reflection is used here so you can develop your mod without decompiling ComputerCraft and including // Reflection is used here so you can develop your mod without decompiling ComputerCraft and including
// it in your solution, and so your mod won't crash if ComputerCraft is installed. // it in your solution, and so your mod won't crash if ComputerCraft is installed.
private static void findCC() private static void findCC()
{ {
if( !ccSearched ) { if( !ccSearched ) {
try { try {
computerCraft = Class.forName( "dan200.computercraft.ComputerCraft" ); computerCraft = Class.forName( "dan200.computercraft.ComputerCraft" );
computerCraft_getVersion = findCCMethod( "getVersion", new Class[]{ computerCraft_getVersion = findCCMethod( "getVersion", new Class<?>[]{
} ); } );
computerCraft_createUniqueNumberedSaveDir = findCCMethod( "createUniqueNumberedSaveDir", new Class[]{ computerCraft_createUniqueNumberedSaveDir = findCCMethod( "createUniqueNumberedSaveDir", new Class<?>[]{
World.class, String.class World.class, String.class
} ); } );
computerCraft_createSaveDirMount = findCCMethod( "createSaveDirMount", new Class[] { computerCraft_createSaveDirMount = findCCMethod( "createSaveDirMount", new Class<?>[] {
World.class, String.class, Long.TYPE World.class, String.class, Long.TYPE
} ); } );
computerCraft_createResourceMount = findCCMethod( "createResourceMount", new Class[] { computerCraft_createResourceMount = findCCMethod( "createResourceMount", new Class<?>[] {
Class.class, String.class, String.class Class.class, String.class, String.class
} ); } );
computerCraft_registerPeripheralProvider = findCCMethod( "registerPeripheralProvider", new Class[] { computerCraft_registerPeripheralProvider = findCCMethod( "registerPeripheralProvider", new Class<?>[] {
IPeripheralProvider.class IPeripheralProvider.class
} ); } );
computerCraft_registerTurtleUpgrade = findCCMethod( "registerTurtleUpgrade", new Class[] { computerCraft_registerTurtleUpgrade = findCCMethod( "registerTurtleUpgrade", new Class<?>[] {
ITurtleUpgrade.class ITurtleUpgrade.class
} ); } );
computerCraft_registerBundledRedstoneProvider = findCCMethod( "registerBundledRedstoneProvider", new Class[] { computerCraft_registerBundledRedstoneProvider = findCCMethod( "registerBundledRedstoneProvider", new Class<?>[] {
IBundledRedstoneProvider.class IBundledRedstoneProvider.class
} ); } );
computerCraft_getDefaultBundledRedstoneOutput = findCCMethod( "getDefaultBundledRedstoneOutput", new Class[] { computerCraft_getDefaultBundledRedstoneOutput = findCCMethod( "getDefaultBundledRedstoneOutput", new Class<?>[] {
World.class, BlockPos.class, EnumFacing.class World.class, BlockPos.class, EnumFacing.class
} ); } );
computerCraft_registerMediaProvider = findCCMethod( "registerMediaProvider", new Class[] { computerCraft_registerMediaProvider = findCCMethod( "registerMediaProvider", new Class<?>[] {
IMediaProvider.class IMediaProvider.class
} ); } );
computerCraft_registerPermissionProvider = findCCMethod( "registerPermissionProvider", new Class[] { computerCraft_registerPermissionProvider = findCCMethod( "registerPermissionProvider", new Class<?>[] {
ITurtlePermissionProvider.class ITurtlePermissionProvider.class
} ); } );
} catch( Exception e ) { computerCraft_registerPocketUpgrade = findCCMethod( "registerPocketUpgrade", new Class<?>[] {
System.out.println( "ComputerCraftAPI: ComputerCraft not found." ); IPocketUpgrade.class
} finally { } );
ccSearched = true; computerCraft_getWirelessNetwork = findCCMethod( "getWirelessNetwork", new Class<?>[] {
} } );
} } catch( Exception e ) {
} System.out.println( "ComputerCraftAPI: ComputerCraft not found." );
} finally {
ccSearched = true;
}
}
}
private static Method findCCMethod( String name, Class[] args ) private static Method findCCMethod( String name, Class<?>[] args )
{ {
try { try {
if( computerCraft != null ) if( computerCraft != null )
{ {
return computerCraft.getMethod( name, args ); return computerCraft.getMethod( name, args );
} }
return null; return null;
} catch( NoSuchMethodException e ) { } catch( NoSuchMethodException e ) {
System.out.println( "ComputerCraftAPI: ComputerCraft method " + name + " not found." ); System.out.println( "ComputerCraftAPI: ComputerCraft method " + name + " not found." );
return null; return null;
} }
} }
private static boolean ccSearched = false; private static boolean ccSearched = false;
private static Class computerCraft = null; private static Class<?> computerCraft = null;
private static Method computerCraft_getVersion = null; private static Method computerCraft_getVersion = null;
private static Method computerCraft_createUniqueNumberedSaveDir = null; private static Method computerCraft_createUniqueNumberedSaveDir = null;
private static Method computerCraft_createSaveDirMount = null; private static Method computerCraft_createSaveDirMount = null;
private static Method computerCraft_createResourceMount = null; private static Method computerCraft_createResourceMount = null;
private static Method computerCraft_registerPeripheralProvider = null; private static Method computerCraft_registerPeripheralProvider = null;
private static Method computerCraft_registerTurtleUpgrade = null; private static Method computerCraft_registerTurtleUpgrade = null;
private static Method computerCraft_registerBundledRedstoneProvider = null; private static Method computerCraft_registerBundledRedstoneProvider = null;
private static Method computerCraft_getDefaultBundledRedstoneOutput = null; private static Method computerCraft_getDefaultBundledRedstoneOutput = null;
private static Method computerCraft_registerMediaProvider = null; private static Method computerCraft_registerMediaProvider = null;
private static Method computerCraft_registerPermissionProvider = null; private static Method computerCraft_registerPermissionProvider = null;
private static Method computerCraft_registerPocketUpgrade = null;
private static Method computerCraft_getWirelessNetwork = null;
} }

View File

@@ -1,57 +1,78 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.filesystem; package dan200.computercraft.api.filesystem;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IComputerAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
/** /**
* Represents a read only part of a virtual filesystem that can be mounted onto a computercraft using IComputerAccess.mount(). * Represents a read only part of a virtual filesystem that can be mounted onto a computer using
* Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount() or ComputerCraftAPI.createResourceMount(), or you're free to implement it yourselves! * {@link IComputerAccess#mount(String, IMount)}
* @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) *
* @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) * Ready made implementations of this interface can be created using
* @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, IMount) * {@link ComputerCraftAPI#createSaveDirMount(World, String, long)} or
* {@link ComputerCraftAPI#createResourceMount(Class, String, String)}, or you're free to implement it yourselves!
*
* @see ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see ComputerCraftAPI#createResourceMount(Class, String, String)
* @see IComputerAccess#mount(String, IMount)
* @see IWritableMount * @see IWritableMount
*/ */
public interface IMount public interface IMount
{ {
/** /**
* Returns whether a file with a given path exists or not. * Returns whether a file with a given path exists or not.
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" *
* @return true if the file exists, false otherwise * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram"
*/ * @return If the file exists.
public boolean exists( String path ) throws IOException; * @throws IOException If an error occurs when checking the existence of the file.
*/
boolean exists( @Nonnull String path ) throws IOException;
/** /**
* Returns whether a file with a given path is a directory or not. * Returns whether a file with a given path is a directory or not.
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms" *
* @return true if the file exists and is a directory, false otherwise * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms".
*/ * @return If the file exists and is a directory
public boolean isDirectory( String path ) throws IOException; * @throws IOException If an error occurs when checking whether the file is a directory.
*/
boolean isDirectory( @Nonnull String path ) throws IOException;
/** /**
* Returns the file names of all the files in a directory. * Returns the file names of all the files in a directory.
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms" *
* @param contents A list of strings. Add all the file names to this list * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms".
*/ * @param contents A list of strings. Add all the file names to this list.
public void list( String path, List<String> contents ) throws IOException; * @throws IOException If the file was not a directory, or could not be listed.
*/
void list( @Nonnull String path, @Nonnull List<String> contents ) throws IOException;
/** /**
* Returns the size of a file with a given path, in bytes * Returns the size of a file with a given path, in bytes
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" *
* @return the size of the file, in bytes * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram".
*/ * @return The size of the file, in bytes.
public long getSize( String path ) throws IOException; * @throws IOException If the file does not exist, or its size could not be determined.
*/
/** long getSize( @Nonnull String path ) throws IOException;
* Opens a file with a given path, and returns an inputstream representing it's contents.
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" /**
* @return a stream representing the contents of the file * Opens a file with a given path, and returns an {@link InputStream} representing its contents.
*/ *
public InputStream openForRead( String path ) throws IOException; * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram".
* @return A stream representing the contents of the file.
* @throws IOException If the file does not exist, or could not be opened.
*/
@Nonnull
InputStream openForRead( @Nonnull String path ) throws IOException;
} }

View File

@@ -1,52 +1,75 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.filesystem; package dan200.computercraft.api.filesystem;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IComputerAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
* Represents a part of a virtual filesystem that can be mounted onto a computercraft using IComputerAccess.mount() or IComputerAccess.mountWritable(), that can also be written to. * Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)}
* Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount(), or you're free to implement it yourselves! * or {@link IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to.
* @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) *
* @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, dan200.computercraft.api.filesystem.IMount) * Ready made implementations of this interface can be created using
* @see dan200.computercraft.api.filesystem.IMount * {@link ComputerCraftAPI#createSaveDirMount(World, String, long)}, or you're free to implement it yourselves!
*
* @see ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see IComputerAccess#mount(String, IMount)
* @see IComputerAccess#mountWritable(String, IWritableMount)
* @see IMount
*/ */
public interface IWritableMount extends IMount public interface IWritableMount extends IMount
{ {
/** /**
* Creates a directory at a given path inside the virtual file system. * Creates a directory at a given path inside the virtual file system.
* @param path A file path in normalised format, relative to the mount location. ie: "programs/mynewprograms" *
*/ * @param path A file path in normalised format, relative to the mount location. ie: "programs/mynewprograms".
public void makeDirectory( String path ) throws IOException; * @throws IOException If the directory already exists or could not be created.
*/
void makeDirectory( @Nonnull String path ) throws IOException;
/** /**
* Deletes a directory at a given path inside the virtual file system. * Deletes a directory at a given path inside the virtual file system.
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myoldprograms" *
*/ * @param path A file path in normalised format, relative to the mount location. ie: "programs/myoldprograms".
public void delete( String path ) throws IOException; * @throws IOException If the file does not exist or could not be deleted.
*/
void delete( @Nonnull String path ) throws IOException;
/** /**
* Opens a file with a given path, and returns an outputstream for writing to it. * Opens a file with a given path, and returns an {@link OutputStream} for writing to it.
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" *
* @return a stream for writing to * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram".
*/ * @return A stream for writing to
public OutputStream openForWrite( String path ) throws IOException; * @throws IOException If the file could not be opened for writing.
*/
@Nonnull
OutputStream openForWrite( @Nonnull String path ) throws IOException;
/** /**
* Opens a file with a given path, and returns an outputstream for appending to it. * Opens a file with a given path, and returns an {@link OutputStream} for appending to it.
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" *
* @return a stream for writing to * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram".
*/ * @return A stream for writing to.
public OutputStream openForAppend( String path ) throws IOException; * @throws IOException If the file could not be opened for writing.
*/
@Nonnull
OutputStream openForAppend( @Nonnull String path ) throws IOException;
/** /**
* Get the ammount of free space on the mount, in bytes. You should decrease this value as the user writes to the mount, and write operations should fail once it reaches zero. * Get the amount of free space on the mount, in bytes. You should decrease this value as the user writes to the
* @return The ammount of free space, in bytes. * mount, and write operations should fail once it reaches zero.
*/ *
public long getRemainingSpace() throws IOException; * @return The amount of free space, in bytes.
* @throws IOException If the remaining space could not be computed.
*/
long getRemainingSpace() throws IOException;
} }

View File

@@ -1,10 +1,10 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
@API( owner="ComputerCraft", provides="ComputerCraft|API|FileSystem", apiVersion="${version}" ) @API( owner="ComputerCraft", provides="ComputerCraft|API|FileSystem", apiVersion="${version}" )
package dan200.computercraft.api.filesystem; package dan200.computercraft.api.filesystem;
import net.minecraftforge.fml.common.API; import net.minecraftforge.fml.common.API;

View File

@@ -1,58 +1,97 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* An interface passed to peripherals and ILuaObjects' by computers or turtles, providing methods * An interface passed to peripherals and {@link ILuaObject}s by computers or turtles, providing methods
* that allow the peripheral call to wait for events before returning, just like in lua. * that allow the peripheral call to wait for events before returning, just like in lua. This is very useful if you need
* This is very useful if you need to signal work to be performed on the main thread, and don't want to return * to signal work to be performed on the main thread, and don't want to return until the work has been completed.
* until the work has been completed.
*/ */
public interface ILuaContext public interface ILuaContext
{ {
/** /**
* Wait for an event to occur on the computercraft, suspending the thread until it arises. This method is exactly equivalent to os.pullEvent() in lua. * Wait for an event to occur on the computer, suspending the thread until it arises. This method is exactly
* @param filter A specific event to wait for, or null to wait for any event * equivalent to {@code os.pullEvent()} in lua.
* @return An object array containing the name of the event that occurred, and any event parameters *
* @throws Exception If the user presses CTRL+T to terminate the current program while pullEvent() is waiting for an event, a "Terminated" exception will be thrown here. * @param filter A specific event to wait for, or null to wait for any event.
* Do not attempt to common this exception, unless you wish to prevent termination, which is not recommended. * @return An object array containing the name of the event that occurred, and any event parameters.
* @throws InterruptedException If the user shuts down or reboots the computercraft while pullEvent() is waiting for an event, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state. * @throws LuaException If the user presses CTRL+T to terminate the current program while pullEvent() is
*/ * waiting for an event, a "Terminated" exception will be thrown here.
public Object[] pullEvent( String filter ) throws LuaException, InterruptedException; *
* Do not attempt to catch this exception. You should use {@link #pullEventRaw(String)}
/** * should you wish to disable termination.
* The same as pullEvent(), except "terminated" events are ignored. Only use this if you want to prevent program termination, which is not recommended. This method is exactly equivalent to os.pullEventRaw() in lua. * @throws InterruptedException If the user shuts down or reboots the computer while pullEvent() is waiting for an
* @param filter A specific event to wait for, or null to wait for any event * event, InterruptedException will be thrown. This exception must not be caught or
* @return An object array containing the name of the event that occurred, and any event parameters * intercepted, or the computer will leak memory and end up in a broken state.
* @throws InterruptedException If the user shuts down or reboots the computercraft while pullEventRaw() is waiting for an event, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state. */
* @see #pullEvent(String) @Nonnull
*/ Object[] pullEvent( @Nullable String filter ) throws LuaException, InterruptedException;
public Object[] pullEventRaw( String filter ) throws InterruptedException;
/**
* Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to coroutine.yield() in lua. Use pullEvent() if you wish to wait for events.
* @param arguments An object array containing the arguments to pass to coroutine.yield()
* @return An object array containing the return values from coroutine.yield()
* @throws InterruptedException If the user shuts down or reboots the computercraft the coroutine is suspended, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state.
* @see #pullEvent(String)
*/
public Object[] yield( Object[] arguments ) throws InterruptedException;
/** /**
* TODO: Document me * The same as {@link #pullEvent(String)}, except "terminated" events are ignored. Only use this if you want to
* @param task * prevent program termination, which is not recommended. This method is exactly equivalent to
* @return * {@code os.pullEventRaw()} in lua.
*
* @param filter A specific event to wait for, or null to wait for any event.
* @return An object array containing the name of the event that occurred, and any event parameters.
* @throws InterruptedException If the user shuts down or reboots the computer while pullEventRaw() is waiting for
* an event, InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.
* @see #pullEvent(String)
*/ */
public Object[] executeMainThreadTask( ILuaTask task ) throws LuaException, InterruptedException; @Nonnull
Object[] pullEventRaw( @Nullable String filter ) throws InterruptedException;
/** /**
* TODO: Document me * Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to
* @param task * {@code coroutine.yield()} in lua. Use {@code pullEvent()} if you wish to wait for events.
* @return *
* @param arguments An object array containing the arguments to pass to coroutine.yield()
* @return An object array containing the return values from coroutine.yield()
* @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended,
* InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.
* @see #pullEvent(String)
*/ */
public long issueMainThreadTask( ILuaTask task ) throws LuaException; @Nonnull
Object[] yield( @Nullable Object[] arguments ) throws InterruptedException;
/**
* Queue a task to be executed on the main server thread at the beginning of next tick, waiting for it to complete.
* This should be used when you need to interact with the world in a thread-safe manner.
*
* Note that the return values of your task are handled as events, meaning more complex objects such as maps or
* {@link ILuaObject} will not preserve their identities.
*
* @param task The task to execute on the main thread.
* @return The objects returned by {@code task}.
* @throws LuaException If the task could not be queued, or if the task threw an exception.
* @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended,
* InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.
*/
@Nullable
Object[] executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException, InterruptedException;
/**
* Queue a task to be executed on the main server thread at the beginning of next tick, but do not wait for it to
* complete. This should be used when you need to interact with the world in a thread-safe manner but do not care
* about the result or you wish to run asynchronously.
*
* When the task has finished, it will enqueue a {@code task_completed} event, which takes the task id, a success
* value and the return values, or an error message if it failed. If you need to wait on this event, it may be
* better to use {@link #executeMainThreadTask(ILuaTask)}.
*
* @param task The task to execute on the main thread.
* @return The "id" of the task. This will be the first argument to the {@code task_completed} event.
* @throws LuaException If the task could not be queued.
*/
long issueMainThreadTask( @Nonnull ILuaTask task ) throws LuaException;
} }

View File

@@ -1,26 +1,56 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* An interface for representing custom objects returned by IPeripheral.callMethod() calls. * An interface for representing custom objects returned by {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}
* calls.
*
* Return objects implementing this interface to expose objects with methods to lua. * Return objects implementing this interface to expose objects with methods to lua.
*/ */
public interface ILuaObject public interface ILuaObject
{ {
/** /**
* Get the names of the methods that this object implements. This works the same as IPeripheral.getMethodNames(). See that method for detailed documentation. * Get the names of the methods that this object implements. This works the same as {@link IPeripheral#getMethodNames()}.
* @see dan200.computercraft.api.peripheral.IPeripheral#getMethodNames() * See that method for detailed documentation.
*/ *
public String[] getMethodNames(); * @return The method names this object provides.
* @see IPeripheral#getMethodNames()
*/
@Nonnull
String[] getMethodNames();
/** /**
* Called when a user calls one of the methods that this object implements. This works the same as IPeripheral.callMethod(). See that method for detailed documentation. * Called when a user calls one of the methods that this object implements. This works the same as
* @see dan200.computercraft.api.peripheral.IPeripheral#callMethod(dan200.computercraft.api.peripheral.IComputerAccess, ILuaContext, int, Object[]) * {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}}. See that method for detailed
*/ * documentation.
public Object[] callMethod( ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException; *
* @param context The context of the currently running lua thread. This can be used to wait for events
* or otherwise yield.
* @param method An integer identifying which of the methods from getMethodNames() the computercraft
* wishes to call. The integer indicates the index into the getMethodNames() table
* that corresponds to the string passed into peripheral.call()
* @param arguments The arguments for this method. See {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}
* the possible values and conversion rules.
* @return An array of objects, representing the values you wish to return to the Lua program.
* See {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])} for the valid values and
* conversion rules.
* @throws LuaException If the task could not be queued, or if the task threw an exception.
* @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended,
* InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.w
* @see IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])
*/
@Nullable
Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException;
} }

View File

@@ -1,12 +1,33 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import javax.annotation.Nullable;
/**
* A task which can be executed via {@link ILuaContext#executeMainThreadTask(ILuaTask)} or
* {@link ILuaContext#issueMainThreadTask(ILuaTask)}. This will be run on the main thread, at the beginning of the
* next tick.
*
* @see ILuaContext#executeMainThreadTask(ILuaTask)
* @see ILuaContext#issueMainThreadTask(ILuaTask)
*/
@FunctionalInterface
public interface ILuaTask public interface ILuaTask
{ {
public Object[] execute() throws LuaException; /**
* Execute this task.
*
* @return The arguments to add to the {@code task_completed} event. These will be returned by
* {@link ILuaContext#executeMainThreadTask(ILuaTask)}.
* @throws LuaException If you throw any exception from this function, a lua error will be raised with the
* same message as your exception. Use this to throw appropriate errors if the wrong
* arguments are supplied to your method.
*/
@Nullable
Object[] execute() throws LuaException;
} }

View File

@@ -1,16 +1,19 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import javax.annotation.Nullable;
/** /**
* An exception representing an error in Lua, like that raised by the error() function * An exception representing an error in Lua, like that raised by the {@code error()} function.
*/ */
public class LuaException extends Exception public class LuaException extends Exception
{ {
private static final long serialVersionUID = -6136063076818512651L;
private final int m_level; private final int m_level;
public LuaException() public LuaException()
@@ -18,17 +21,23 @@ public class LuaException extends Exception
this( "error", 1 ); this( "error", 1 );
} }
public LuaException( String message ) public LuaException( @Nullable String message )
{ {
this( message, 1 ); this( message, 1 );
} }
public LuaException( String message, int level ) public LuaException( @Nullable String message, int level )
{ {
super( message ); super( message );
m_level = level; m_level = level;
} }
/**
* The level this error is raised at. Level 1 is the function's caller, level 2 is that function's caller, and so
* on.
*
* @return The level to raise the error at.
*/
public int getLevel() public int getLevel()
{ {
return m_level; return m_level;

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
@@ -11,50 +11,65 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.SoundEvent; import net.minecraft.util.SoundEvent;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* Represents an item that can be placed in a disk drive and used by a Computer. * Represents an item that can be placed in a disk drive and used by a Computer.
* Implement this interface on your Item class to allow it to be used in the drive. * Implement this interface on your Item class to allow it to be used in the drive.
*/ */
public interface IMedia public interface IMedia
{ {
/** /**
* Get a string representing the label of this item. Will be called vi disk.getLabel() in lua. * Get a string representing the label of this item. Will be called via {@code disk.getLabel()} in lua.
* @param stack The itemstack to inspect *
* @return The label. ie: "Dan's Programs" * @param stack The itemstack to inspect.
*/ * @return The label. ie: "Dan's Programs".
public String getLabel( ItemStack stack ); */
@Nullable
String getLabel( @Nonnull ItemStack stack );
/** /**
* Set a string representing the label of this item. Will be called vi disk.setLabel() in lua. * Set a string representing the label of this item. Will be called vi {@code disk.setLabel()} in lua.
* @param stack The itemstack to modify. *
* @param label The string to set the label to. * @param stack The itemstack to modify.
* @return true if the label was updated, false if the label may not be modified. * @param label The string to set the label to.
*/ * @return true if the label was updated, false if the label may not be modified.
public boolean setLabel( ItemStack stack, String label ); */
boolean setLabel( @Nonnull ItemStack stack, @Nullable String label );
/**
* If this disk represents an item with audio (like a record), get the readable name of the audio track. ie: "Jonathon Coulton - Still Alive"
* @param stack The itemstack to inspect.
* @return The name, or null if this item does not represent an item with audio.
*/
public String getAudioTitle( ItemStack stack );
/** /**
* If this disk represents an item with audio (like a record), get the resource name of the audio track to play. * If this disk represents an item with audio (like a record), get the readable name of the audio track. ie:
* @param stack The itemstack to inspect. * "Jonathon Coulton - Still Alive"
* @return The name, or null if this item does not represent an item with audio. *
*/ * @param stack The itemstack to inspect.
public SoundEvent getAudio( ItemStack stack ); * @return The name, or null if this item does not represent an item with audio.
*/
/** @Nullable
* If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will be mounted onto the filesystem of the computercraft while the media is in the disk drive. String getAudioTitle( @Nonnull ItemStack stack );
* @param stack The itemstack to inspect.
* @param world The world in which the item and disk drive reside. /**
* @return The mount, or null if this item does not represent an item with data. If the IMount returned also implements IWritableMount, it will mounted using mountWritable() * If this disk represents an item with audio (like a record), get the resource name of the audio track to play.
* @see dan200.computercraft.api.filesystem.IMount *
* @see dan200.computercraft.api.filesystem.IWritableMount * @param stack The itemstack to inspect.
* @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String, long) * @return The name, or null if this item does not represent an item with audio.
* @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) */
*/ @Nullable
public IMount createDataMount( ItemStack stack, World world ); SoundEvent getAudio( @Nonnull ItemStack stack );
/**
* If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will
* be mounted onto the filesystem of the computer while the media is in the disk drive.
*
* @param stack The itemstack to inspect.
* @param world The world in which the item and disk drive reside.
* @return The mount, or null if this item does not represent an item with data. If the mount returned also
* implements {@link dan200.computercraft.api.filesystem.IWritableMount}, it will mounted using mountWritable()
* @see dan200.computercraft.api.filesystem.IMount
* @see dan200.computercraft.api.filesystem.IWritableMount
* @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String)
*/
@Nullable
IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world );
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
@@ -8,16 +8,24 @@ package dan200.computercraft.api.media;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* This interface is used to provide IMedia implementations for ItemStack * This interface is used to provide {@link IMedia} implementations for {@link ItemStack}.
*
* @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider) * @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider)
*/ */
@FunctionalInterface
public interface IMediaProvider public interface IMediaProvider
{ {
/** /**
* Produce an IMedia implementation from an ItemStack. * Produce an IMedia implementation from an ItemStack.
*
* @param stack The stack from which to extract the media information.
* @return An IMedia implementation, or null if the item is not something you wish to handle
* @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider) * @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider)
* @return an IMedia implementation, or null if the item is not something you wish to handle
*/ */
public IMedia getMedia( ItemStack stack ); @Nullable
IMedia getMedia( @Nonnull ItemStack stack );
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */

View File

@@ -0,0 +1,58 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.api.network;
import javax.annotation.Nonnull;
/**
* A packet network represents a collection of devices which can send and receive packets.
*
* @see Packet
* @see IPacketReceiver
*/
public interface IPacketNetwork
{
/**
* Add a receiver to the network.
*
* @param receiver The receiver to register to the network.
*/
void addReceiver( @Nonnull IPacketReceiver receiver );
/**
* Remove a receiver from the network.
*
* @param receiver The device to remove from the network.
*/
void removeReceiver( @Nonnull IPacketReceiver receiver );
/**
* Determine whether this network is wireless.
*
* @return Whether this network is wireless.
*/
boolean isWireless();
/**
* Submit a packet for transmitting across the network. This will route the packet through the network, sending it
* to all receivers within range (or any interdimensional ones).
*
* @param packet The packet to send.
* @see #transmitInterdimensional(Packet)
* @see IPacketReceiver#receiveSameDimension(Packet, double)
*/
void transmitSameDimension( @Nonnull Packet packet, double range );
/**
* Submit a packet for transmitting across the network. This will route the packet through the network, sending it
* to all receivers across all dimensions.
*
* @param packet The packet to send.
* @see #transmitSameDimension(Packet, double)
* @see IPacketReceiver#receiveDifferentDimension(Packet)
*/
void transmitInterdimensional( @Nonnull Packet packet );
}

View File

@@ -0,0 +1,84 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.api.network;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
/**
* An object on an {@link IPacketNetwork}, capable of receiving packets.
*/
public interface IPacketReceiver
{
/**
* Get the world in which this packet receiver exists.
*
* @return The receivers's world.
*/
@Nonnull
World getWorld();
/**
* Get the position in the world at which this receiver exists.
*
* @return The receiver's position.
*/
@Nonnull
Vec3d getPosition();
/**
* Get the maximum distance this receiver can send and receive messages.
*
* When determining whether a receiver can receive a message, the largest distance of the packet and receiver is
* used - ensuring it is within range. If the packet or receiver is inter-dimensional, then the packet will always
* be received.
*
* @return The maximum distance this device can send and receive messages.
* @see #isInterdimensional()
* @see #receiveSameDimension(Packet packet, double)
* @see IPacketNetwork#transmitInterdimensional(Packet)
*/
double getRange();
/**
* Determine whether this receiver can receive packets from other dimensions.
*
* A device will receive an inter-dimensional packet if either it or the sending device is inter-dimensional.
*
* @return Whether this receiver receives packets from other dimensions.
* @see #getRange()
* @see #receiveDifferentDimension(Packet)
* @see IPacketNetwork#transmitInterdimensional(Packet)
*/
boolean isInterdimensional();
/**
* Receive a network packet from the same dimension.
*
* @param packet The packet to receive. Generally you should check that you are listening on the given channel and,
* if so, queue the appropriate modem event.
* @param distance The distance this packet has travelled from the source.
* @see Packet
* @see #getRange()
* @see IPacketNetwork#transmitSameDimension(Packet, double)
* @see IPacketNetwork#transmitInterdimensional(Packet)
*/
void receiveSameDimension( @Nonnull Packet packet, double distance );
/**
* Receive a network packet from a different dimension.
*
* @param packet The packet to receive. Generally you should check that you are listening on the given channel and,
* if so, queue the appropriate modem event.
* @see Packet
* @see IPacketNetwork#transmitInterdimensional(Packet)
* @see IPacketNetwork#transmitSameDimension(Packet, double)
* @see #isInterdimensional()
*/
void receiveDifferentDimension( @Nonnull Packet packet );
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.api.network;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
/**
* An object on a {@link IPacketNetwork}, capable of sending packets.
*/
public interface IPacketSender
{
/**
* Get the world in which this packet sender exists.
*
* @return The sender's world.
*/
@Nonnull
World getWorld();
/**
* Get the position in the world at which this sender exists.
*
* @return The sender's position.
*/
@Nonnull
Vec3d getPosition();
/**
* Get some sort of identification string for this sender. This does not strictly need to be unique, but you
* should be able to extract some identifiable information from it.
*
* @return This device's id.
*/
@Nonnull
String getSenderID();
}

View File

@@ -0,0 +1,118 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.api.network;
import com.google.common.base.Preconditions;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Represents a packet which may be sent across a {@link IPacketNetwork}.
*
* @see IPacketSender
* @see IPacketNetwork#transmitSameDimension(Packet, double)
* @see IPacketNetwork#transmitInterdimensional(Packet)
* @see IPacketReceiver#receiveDifferentDimension(Packet)
* @see IPacketReceiver#receiveSameDimension(Packet, double)
*/
public class Packet
{
private final int m_channel;
private final int m_replyChannel;
private final Object m_payload;
private final IPacketSender m_sender;
/**
* Create a new packet, ready for transmitting across the network.
*
* @param channel The channel to send the packet along. Receiving devices should only process packets from on
* channels they are listening to.
* @param replyChannel The channel to reply on.
* @param payload The contents of this packet. This should be a "valid" Lua object, safe for queuing as an
* event or returning from a peripheral call.
* @param sender The object which sent this packet.
*/
public Packet( int channel, int replyChannel, @Nullable Object payload, @Nonnull IPacketSender sender )
{
Preconditions.checkNotNull( sender, "sender cannot be null" );
m_channel = channel;
m_replyChannel = replyChannel;
m_payload = payload;
m_sender = sender;
}
/**
* Get the channel this packet is sent along. Receivers should generally only process packets from on channels they
* are listening to.
*
* @return This packet's channel.
*/
public int getChannel()
{
return m_channel;
}
/**
* The channel to reply on. Objects which will reply should send it along this channel.
*
* @return This channel to reply on.
*/
public int getReplyChannel()
{
return m_replyChannel;
}
/**
* The actual data of this packet. This should be a "valid" Lua object, safe for queuing as an
* event or returning from a peripheral call.
*
* @return The packet's payload
*/
@Nullable
public Object getPayload()
{
return m_payload;
}
/**
* The object which sent this message.
*
* @return The sending object.
*/
@Nonnull
public IPacketSender getSender()
{
return m_sender;
}
@Override
public boolean equals( Object o )
{
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
Packet packet = (Packet) o;
if( m_channel != packet.m_channel ) return false;
if( m_replyChannel != packet.m_replyChannel ) return false;
if( m_payload != null ? !m_payload.equals( packet.m_payload ) : packet.m_payload != null ) return false;
return m_sender.equals( packet.m_sender );
}
@Override
public int hashCode()
{
int result;
result = m_channel;
result = 31 * result + m_replyChannel;
result = 31 * result + (m_payload != null ? m_payload.hashCode() : 0);
result = 31 * result + m_sender.hashCode();
return result;
}
}

View File

@@ -0,0 +1,10 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
@API( owner="ComputerCraft", provides="ComputerCraft|API|Network", apiVersion="${version}" )
package dan200.computercraft.api.network;
import net.minecraftforge.fml.common.API;

View File

@@ -1,10 +1,10 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
@API( owner="ComputerCraft", provides="ComputerCraft|API", apiVersion="${version}" ) @API( owner="ComputerCraft", provides="ComputerCraft|API", apiVersion="${version}" )
package dan200.computercraft.api; package dan200.computercraft.api;
import net.minecraftforge.fml.common.API; import net.minecraftforge.fml.common.API;

View File

@@ -1,13 +1,18 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.filesystem.IWritableMount;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* The interface passed to peripherals by computers or turtles, providing methods * The interface passed to peripherals by computers or turtles, providing methods
@@ -16,87 +21,137 @@ import dan200.computercraft.api.filesystem.IWritableMount;
*/ */
public interface IComputerAccess public interface IComputerAccess
{ {
/** /**
* Mount a mount onto the computers' file system in a read only mode.<br> * Mount a mount onto the computer's file system in a read only mode.
* @param desiredLocation The location on the computercraft's file system where you would like the mount to be mounted. *
* @param mount The mount object to mount on the computercraft. These can be obtained by calling ComputerCraftAPI.createSaveDirMount(), ComputerCraftAPI.createResourceMount() or by creating your own objects that implement the IMount interface. * @param desiredLocation The location on the computer's file system where you would like the mount to be mounted.
* @return The location on the computercraft's file system where you the mount mounted, or null if there was already a file in the desired location. Store this value if you wish to unmount the mount later. * @param mount The mount object to mount on the computer.
* @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a
* @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) * file in the desired location. Store this value if you wish to unmount the mount later.
* @see #mountWritable(String, dan200.computercraft.api.filesystem.IWritableMount) * @throws RuntimeException If the peripheral has been detached.
* @see #unmount(String) * @see ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see dan200.computercraft.api.filesystem.IMount * @see ComputerCraftAPI#createResourceMount(Class, String, String)
*/ * @see #mount(String, IMount, String)
public String mount( String desiredLocation, IMount mount ); * @see #mountWritable(String, IWritableMount)
* @see #unmount(String)
* @see IMount
*/
@Nullable
String mount( @Nonnull String desiredLocation, @Nonnull IMount mount );
/** /**
* TODO: Document me * Mount a mount onto the computer's file system in a read only mode.
*
* @param desiredLocation The location on the computer's file system where you would like the mount to be mounted.
* @param mount The mount object to mount on the computer.
* @param driveName A custom name to give for this mount location, as returned by {@code fs.getDrive()}.
* @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a
* file in the desired location. Store this value if you wish to unmount the mount later.
* @throws RuntimeException If the peripheral has been detached.
* @see ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see ComputerCraftAPI#createResourceMount(Class, String, String)
* @see #mount(String, IMount)
* @see #mountWritable(String, IWritableMount)
* @see #unmount(String)
* @see IMount
*/ */
public String mount( String desiredLocation, IMount mount, String driveName ); @Nullable
String mount( @Nonnull String desiredLocation, @Nonnull IMount mount, @Nonnull String driveName );
/**
* Mount a mount onto the computers' file system in a writable mode.<br>
* @param desiredLocation The location on the computercraft's file system where you would like the mount to be mounted.
* @param mount The mount object to mount on the computercraft. These can be obtained by calling ComputerCraftAPI.createSaveDirMount() or by creating your own objects that implement the IWritableMount interface.
* @return The location on the computercraft's file system where you the mount mounted, or null if there was already a file in the desired location. Store this value if you wish to unmount the mount later.
* @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String)
* @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String)
* @see #mount(String, IMount)
* @see #unmount(String)
* @see IMount
*/
public String mountWritable( String desiredLocation, IWritableMount mount );
/** /**
* TODO: Document me * Mount a mount onto the computer's file system in a writable mode.
*
* @param desiredLocation The location on the computer's file system where you would like the mount to be mounted.
* @param mount The mount object to mount on the computer.
* @return The location on the computer's file system where you the mount mounted, or null if there was already a
* file in the desired location. Store this value if you wish to unmount the mount later.
* @throws RuntimeException If the peripheral has been detached.
* @see ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see ComputerCraftAPI#createResourceMount(Class, String, String)
* @see #mount(String, IMount)
* @see #unmount(String)
* @see IMount
*/ */
public String mountWritable( String desiredLocation, IWritableMount mount, String driveName ); @Nullable
String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount );
/** /**
* Unmounts a directory previously mounted onto the computers file system by mount() or mountWritable().<br> * Mount a mount onto the computer's file system in a writable mode.
* When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be able to *
* access it. All directories mounted by a mount or mountWritable are automatically unmounted when the peripheral * @param desiredLocation The location on the computer's file system where you would like the mount to be mounted.
* is attached if they have not been explicitly unmounted. * @param mount The mount object to mount on the computer.
* @param location The desired location in the computers file system of the directory to unmount. * @param driveName A custom name to give for this mount location, as returned by {@code fs.getDrive()}.
* This must be the location of a directory previously mounted by mount() or mountWritable(), as * @return The location on the computer's file system where you the mount mounted, or null if there was already a
* indicated by their return value. * file in the desired location. Store this value if you wish to unmount the mount later.
* @see #mount(String, IMount) * @throws RuntimeException If the peripheral has been detached.
* @see #mountWritable(String, IWritableMount) * @see ComputerCraftAPI#createSaveDirMount(World, String, long)
*/ * @see ComputerCraftAPI#createResourceMount(Class, String, String)
public void unmount( String location ); * @see #mount(String, IMount)
* @see #unmount(String)
/** * @see IMount
* Returns the numerical ID of this computercraft.<br> */
* This is the same number obtained by calling os.getComputerID() or running the "id" program from lua, String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount, @Nonnull String driveName );
* and is guarunteed unique. This number will be positive.
* @return The identifier.
*/
public int getID();
/** /**
* Causes an event to be raised on this computercraft, which the computercraft can respond to by calling * Unmounts a directory previously mounted onto the computers file system by {@link #mount(String, IMount)}
* os.pullEvent(). This can be used to notify the computercraft when things happen in the world or to * or {@link #mountWritable(String, IWritableMount)}.
* this peripheral. *
* @param event A string identifying the type of event that has occurred, this will be * When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be
* returned as the first value from os.pullEvent(). It is recommended that you * able to access it. All directories mounted by a mount or mountWritable are automatically unmounted when the
* you choose a name that is unique, and recognisable as originating from your * peripheral is attached if they have not been explicitly unmounted.
* peripheral. eg: If your peripheral type is "button", a suitable event would be *
* "button_pressed". * Note that you cannot unmount another peripheral's mounts.
* @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will *
* be supplied as extra return values to os.pullEvent(). Objects in the array will be converted * @param location The desired location in the computers file system of the directory to unmount.
* to lua data types in the same fashion as the return values of IPeripheral.callMethod().<br> * This must be the location of a directory previously mounted by {@link #mount(String, IMount)} or
* You may supply null to indicate that no arguments are to be supplied. * {@link #mountWritable(String, IWritableMount)}, as indicated by their return value.
* @see dan200.computercraft.api.peripheral.IPeripheral#callMethod * @throws RuntimeException If the peripheral has been detached.
*/ * @throws RuntimeException If the mount does not exist, or was mounted by another peripheral.
public void queueEvent( String event, Object[] arguments ); * @see #mount(String, IMount)
* @see #mountWritable(String, IWritableMount)
*/
void unmount( @Nullable String location );
/** /**
* Get a string, unique to the computercraft, by which the computercraft refers to this peripheral. * Returns the numerical ID of this computer.
* For directly attached peripherals this will be "left","right","front","back",etc, but *
* for peripherals attached remotely it will be different. It is good practice to supply * This is the same number obtained by calling {@code os.getComputerID()} or running the "id" program from lua,
* this string when raising events to the computercraft, so that the computercraft knows from * and is guaranteed unique. This number will be positive.
* which peripheral the event came. *
* @return A string unique to the computercraft, but not globally. * @return The identifier.
*/ */
public String getAttachmentName(); int getID();
/**
* Causes an event to be raised on this computer, which the computer can respond to by calling
* {@code os.pullEvent()}. This can be used to notify the computer when things happen in the world or to
* this peripheral.
*
* @param event A string identifying the type of event that has occurred, this will be
* returned as the first value from {@code os.pullEvent()}. It is recommended that you
* you choose a name that is unique, and recognisable as originating from your
* peripheral. eg: If your peripheral type is "button", a suitable event would be
* "button_pressed".
* @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will
* be supplied as extra return values to os.pullEvent(). Objects in the array will be converted
* to lua data types in the same fashion as the return values of IPeripheral.callMethod().
*
* You may supply {@code null} to indicate that no arguments are to be supplied.
* @throws RuntimeException If the peripheral has been detached.
* @see dan200.computercraft.api.peripheral.IPeripheral#callMethod
*/
void queueEvent( @Nonnull String event, @Nullable Object[] arguments );
/**
* Get a string, unique to the computer, by which the computer refers to this peripheral.
* For directly attached peripherals this will be "left","right","front","back",etc, but
* for peripherals attached remotely it will be different. It is good practice to supply
* this string when raising events to the computer, so that the computer knows from
* which peripheral the event came.
*
* @return A string unique to the computer, but not globally.
* @throws RuntimeException If the peripheral has been detached.
*/
@Nonnull
String getAttachmentName();
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
@@ -9,90 +9,119 @@ package dan200.computercraft.api.peripheral;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* The interface that defines a peripheral. See IPeripheralProvider for how to associate blocks with peripherals. * The interface that defines a peripheral. See {@link IPeripheralProvider} for how to associate blocks with peripherals.
*/ */
public interface IPeripheral public interface IPeripheral
{ {
/** /**
* Should return a string that uniquely identifies this type of peripheral. * Should return a string that uniquely identifies this type of peripheral.
* This can be queried from lua by calling peripheral.getType() * This can be queried from lua by calling {@code peripheral.getType()}
* @return A string identifying the type of peripheral. *
*/ * @return A string identifying the type of peripheral.
public String getType(); */
@Nonnull
/** String getType();
* Should return an array of strings that identify the methods that this
* peripheral exposes to Lua. This will be called once before each attachment,
* and should not change when called multiple times.
* @return An array of strings representing method names.
* @see #callMethod
*/
public String[] getMethodNames();
/**
* This is called when a lua program on an attached computercraft calls peripheral.call() with
* one of the methods exposed by getMethodNames().<br>
* <br>
* Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe
* when interacting with minecraft objects.
* @param computer The interface to the computercraft that is making the call. Remember that multiple
* computers can be attached to a peripheral at once.
* @param context The context of the currently running lua thread. This can be used to wait for events
* or otherwise yield.
* @param method An integer identifying which of the methods from getMethodNames() the computercraft
* wishes to call. The integer indicates the index into the getMethodNames() table
* that corresponds to the string passed into peripheral.call()
* @param arguments An array of objects, representing the arguments passed into peripheral.call().<br>
* Lua values of type "string" will be represented by Object type String.<br>
* Lua values of type "number" will be represented by Object type Double.<br>
* Lua values of type "boolean" will be represented by Object type Boolean.<br>
* Lua values of any other type will be represented by a null object.<br>
* This array will be empty if no arguments are passed.
* @return An array of objects, representing values you wish to return to the lua program.<br>
* Integers, Doubles, Floats, Strings, Booleans and null be converted to their corresponding lua type.<br>
* All other types will be converted to nil.<br>
* You may return null to indicate no values should be returned.
* @throws Exception If you throw any exception from this function, a lua error will be raised with the
* same message as your exception. Use this to throw appropriate errors if the wrong
* arguments are supplied to your method.
* @see #getMethodNames
*/
public Object[] callMethod( IComputerAccess computer, ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException;
/**
* Is called when canAttachToSide has returned true, and a computercraft is attaching to the peripheral.
* This will occur when a peripheral is placed next to an active computercraft, when a computercraft is turned on next to a peripheral,
* or when a turtle travels into a square next to a peripheral.
* Between calls to attach() and detach(), the attached computercraft can make method calls on the peripheral using peripheral.call().
* This method can be used to keep track of which computers are attached to the peripheral, or to take action when attachment
* occurs.<br>
* <br>
* Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe
* when interacting with minecraft objects.
* @param computer The interface to the computercraft that is being attached. Remember that multiple
* computers can be attached to a peripheral at once.
* @see #detach
*/
public void attach( IComputerAccess computer );
/**
* Is called when a computercraft is detaching from the peripheral.
* This will occur when a computercraft shuts down, when the peripheral is removed while attached to computers,
* or when a turtle moves away from a square attached to a peripheral.
* This method can be used to keep track of which computers are attached to the peripheral, or to take action when detachment
* occurs.<br>
* <br>
* Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe
* when interacting with minecraft objects.
* @param computer The interface to the computercraft that is being detached. Remember that multiple
* computers can be attached to a peripheral at once.
* @see #detach
*/
public void detach( IComputerAccess computer );
/** /**
* TODO: Document me * Should return an array of strings that identify the methods that this
* peripheral exposes to Lua. This will be called once before each attachment,
* and should not change when called multiple times.
*
* @return An array of strings representing method names.
* @see #callMethod
*/ */
public boolean equals( IPeripheral other ); @Nonnull
String[] getMethodNames();
/**
* This is called when a lua program on an attached computer calls {@code peripheral.call()} with
* one of the methods exposed by {@link #getMethodNames()}.
*
* Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe
* when interacting with Minecraft objects.
*
* @param computer The interface to the computer that is making the call. Remember that multiple
* computers can be attached to a peripheral at once.
* @param context The context of the currently running lua thread. This can be used to wait for events
* or otherwise yield.
* @param method An integer identifying which of the methods from getMethodNames() the computercraft
* wishes to call. The integer indicates the index into the getMethodNames() table
* that corresponds to the string passed into peripheral.call()
* @param arguments An array of objects, representing the arguments passed into {@code peripheral.call()}.<br>
* Lua values of type "string" will be represented by Object type String.<br>
* Lua values of type "number" will be represented by Object type Double.<br>
* Lua values of type "boolean" will be represented by Object type Boolean.<br>
* Lua values of type "table" will be represented by Object type Map.<br>
* Lua values of any other type will be represented by a null object.<br>
* This array will be empty if no arguments are passed.
* @return An array of objects, representing values you wish to return to the lua program. Integers, Doubles, Floats,
* Strings, Booleans, Maps and ILuaObject and null be converted to their corresponding lua type. All other types
* will be converted to nil.
*
* You may return null to indicate no values should be returned.
* @throws LuaException If you throw any exception from this function, a lua error will be raised with the
* same message as your exception. Use this to throw appropriate errors if the wrong
* arguments are supplied to your method.
* @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended,
* InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.
* @see #getMethodNames
*/
@Nullable
Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException;
/**
* Is called when canAttachToSide has returned true, and a computer is attaching to the peripheral.
*
* This will occur when a peripheral is placed next to an active computer, when a computer is turned on next to a
* peripheral, or when a turtle travels into a square next to a peripheral.
*
* Between calls to attach() and detach(), the attached computer can make method calls on the peripheral using
* {@code peripheral.call()}. This method can be used to keep track of which computers are attached to the
* peripheral, or to take action when attachment occurs.
*
* Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe
* when interacting with Minecraft objects.
*
* @param computer The interface to the computer that is being attached. Remember that multiple
* computers can be attached to a peripheral at once.
* @see #detach
*/
default void attach( @Nonnull IComputerAccess computer )
{
}
/**
* Is called when a computer is detaching from the peripheral.
*
* This will occur when a computer shuts down, when the peripheral is removed while attached to computers,
* or when a turtle moves away from a square attached to a peripheral. This method can be used to keep track of
* which computers are attached to the peripheral, or to take action when detachment
* occurs.
*
* Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe
* when interacting with Minecraft objects.
*
* @param computer The interface to the computer that is being detached. Remember that multiple
* computers can be attached to a peripheral at once.
* @see #detach
*/
default void detach( @Nonnull IComputerAccess computer )
{
}
/**
* Determine whether this peripheral is equivalent to another one.
*
* The minimal example should at least check whether they are the same object. However, you may wish to check if
* they point to the same block or tile entity.
*
* @param other The peripheral to compare against. This may be {@code null}.
* @return Whether these peripherals are equivalent.
*/
boolean equals( @Nullable IPeripheral other );
} }

View File

@@ -1,25 +1,35 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* This interface is used to create peripheral implementations for blocks * This interface is used to create peripheral implementations for blocks.
*
* @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider)
*/ */
@FunctionalInterface
public interface IPeripheralProvider public interface IPeripheralProvider
{ {
/** /**
* Produce an peripheral implementation from a block location. * Produce an peripheral implementation from a block location.
*
* @param world The world the block is in.
* @param pos The position the block is at.
* @param side The side to get the peripheral from.
* @return A peripheral, or {@code null} if there is not a peripheral here you'd like to handle.
* @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider)
* @return a peripheral, or null if there is not a peripheral here you'd like to handle.
*/ */
public IPeripheral getPeripheral( World world, BlockPos pos, EnumFacing side ); @Nullable
IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side );
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
@@ -9,12 +9,34 @@ package dan200.computercraft.api.permissions;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
/** /**
* This interface is used to restrict where turtles can move or build * This interface is used to restrict where turtles can move or build.
*
* Turtles will call these methods before attempting to perform an action, allowing them to be cancelled.
*
* @see dan200.computercraft.api.ComputerCraftAPI#registerPermissionProvider(ITurtlePermissionProvider) * @see dan200.computercraft.api.ComputerCraftAPI#registerPermissionProvider(ITurtlePermissionProvider)
*/ */
public interface ITurtlePermissionProvider public interface ITurtlePermissionProvider
{ {
public boolean isBlockEnterable( World world, BlockPos pos ); /**
public boolean isBlockEditable( World world, BlockPos pos ); * Determine whether a block can be entered by a turtle.
*
* @param world The world the block exists in
* @param pos The location of the block.
* @return Whether the turtle can move into this block.
*/
boolean isBlockEnterable( @Nonnull World world, @Nonnull BlockPos pos );
/**
* Determine whether a block can be modified by a turtle.
*
* This includes breaking and placing blocks.
*
* @param world The world the block exists in
* @param pos The location of the block.
* @return Whether the turtle can modify this block.
*/
boolean isBlockEditable( @Nonnull World world, @Nonnull BlockPos pos );
} }

View File

@@ -1,10 +1,10 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
@API( owner="ComputerCraft", provides="ComputerCraft|API|Permissions", apiVersion="${version}" ) @API( owner="ComputerCraft", provides="ComputerCraft|API|Permissions", apiVersion="${version}" )
package dan200.computercraft.api.permissions; package dan200.computercraft.api.permissions;
import net.minecraftforge.fml.common.API; import net.minecraftforge.fml.common.API;

View File

@@ -0,0 +1,91 @@
package dan200.computercraft.api.pocket;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
/**
* Wrapper class for pocket computers
*/
public interface IPocketAccess
{
/**
* Gets the entity holding this item.
*
* @return The holding entity. This may be {@code null}.
*/
@Nullable
Entity getEntity();
/**
* Get the colour of this pocket computer as a RGB number.
*
* @return The colour this pocket computer is. This will be a RGB colour between {@code 0x000000} and
* {@code 0xFFFFFF} or -1 if it has no colour.
* @see #setColour(int)
*/
int getColour();
/**
* Set the colour of the pocket computer to a RGB number.
*
* @param colour The colour this pocket computer should be changed to. This should be a RGB colour between
* {@code 0x000000} and {@code 0xFFFFFF} or -1 to reset to the default colour.
* @see #getColour()
*/
void setColour( int colour );
/**
* Get the colour of this pocket computer's light as a RGB number.
*
* @return The colour this light is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or
* -1 if it has no colour.
* @see #setLight(int)
*/
int getLight();
/**
* Set the colour of the pocket computer's light to a RGB number.
*
* @param colour The colour this modem's light will be changed to. This should be a RGB colour between
* {@code 0x000000} and {@code 0xFFFFFF} or -1 to reset to the default colour.
* @see #getLight()
*/
void setLight( int colour );
/**
* Get the upgrade-specific NBT.
*
* This is persisted between computer reboots and chunk loads.
*
* @return The upgrade's NBT.
* @see #updateUpgradeNBTData()
*/
@Nonnull
NBTTagCompound getUpgradeNBTData();
/**
* Mark the upgrade-specific NBT as dirty.
*
* @see #getUpgradeNBTData()
*/
void updateUpgradeNBTData();
/**
* Remove the current peripheral and create a new one. You may wish to do this if the methods available change.
*/
void invalidatePeripheral();
/**
* Get a list of all upgrades for the pocket computer.
*
* @return A collection of all upgrade names.
*/
@Nonnull
Map<ResourceLocation, IPeripheral> getUpgrades();
}

View File

@@ -0,0 +1,96 @@
package dan200.computercraft.api.pocket;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Additional peripherals for pocket computers.
*
* This is similar to {@link dan200.computercraft.api.turtle.ITurtleUpgrade}.
*/
public interface IPocketUpgrade
{
/**
* Gets a unique identifier representing this type of turtle upgrade. eg: "computercraft:wireless_modem" or
* "my_mod:my_upgrade".
*
* You should use a unique resource domain to ensure this upgrade is uniquely identified. The upgrade will fail
* registration if an already used ID is specified.
*
* @return The upgrade's id.
* @see IPocketUpgrade#getUpgradeID()
* @see ComputerCraftAPI#registerPocketUpgrade(IPocketUpgrade)
*/
@Nonnull
ResourceLocation getUpgradeID();
/**
* Return an unlocalised string to describe the type of pocket computer this upgrade provides.
*
* An example of a built-in adjectives is "Wireless" - this is converted to "Wireless Pocket Computer".
*
* @return The unlocalised adjective.
* @see ITurtleUpgrade#getUnlocalisedAdjective()
*/
@Nonnull
String getUnlocalisedAdjective();
/**
* Return an item stack representing the type of item that a pocket computer must be crafted with to create a
* pocket computer which holds this upgrade. This item stack is also used to determine the upgrade given by
* {@code pocket.equip()}/{@code pocket.unequip()}.
*
* @return The item stack used for crafting. This can be {@link ItemStack#EMPTY} if crafting is disabled.
*/
@Nonnull
ItemStack getCraftingItem();
/**
* Creates a peripheral for the pocket computer.
*
* The peripheral created will be stored for the lifetime of the upgrade, will be passed an argument to
* {@link #update(IPocketAccess, IPeripheral)} and will be attached, detached and have methods called in the same
* manner as an ordinary peripheral.
*
* @param access The access object for the pocket item stack.
* @return The newly created peripheral.
* @see #update(IPocketAccess, IPeripheral)
*/
@Nullable
IPeripheral createPeripheral( @Nonnull IPocketAccess access );
/**
* Called when the pocket computer item stack updates.
*
* @param access The access object for the pocket item stack.
* @param peripheral The peripheral for this upgrade.
* @see #createPeripheral(IPocketAccess)
*/
default void update( @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral )
{
}
/**
* Called when the pocket computer is right clicked.
*
* @param world The world the computer is in.
* @param access The access object for the pocket item stack.
* @param peripheral The peripheral for this upgrade.
* @return {@code true} to stop the GUI from opening, otherwise false. You should always provide some code path
* which returns {@code false}, such as requiring the player to be sneaking - otherwise they will be unable to
* access the GUI.
* @see #createPeripheral(IPocketAccess)
*/
default boolean onRightClick( @Nonnull World world, @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral )
{
return false;
}
}

View File

@@ -1,25 +1,34 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.redstone; package dan200.computercraft.api.redstone;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
/** /**
* This interface is used to provide bundled redstone output for blocks * This interface is used to provide bundled redstone output for blocks.
*
* @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider)
*/ */
@FunctionalInterface
public interface IBundledRedstoneProvider public interface IBundledRedstoneProvider
{ {
/** /**
* Produce an bundled redstone output from a block location. * Produce an bundled redstone output from a block location.
*
* @param world The world this block is in.
* @param pos The position this block is at.
* @param side The side to extract the bundled redstone output from.
* @return A number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to
* handle this block.
* @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider)
* @return a number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to handle this block
*/ */
public int getBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ); int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side );
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
@@ -11,116 +11,204 @@ import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.inventory.IInventory; import net.minecraft.inventory.IInventory;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandlerModifiable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* The interface passed to turtle by turtles, providing methods that they can call. * The interface passed to turtle by turtles, providing methods that they can call.
* This should not be implemented by your classes. Do not interact with turtles except via this interface and ITurtleUpgrade. *
* This should not be implemented by your classes. Do not interact with turtles except via this interface and
* {@link ITurtleUpgrade}.
*/ */
public interface ITurtleAccess public interface ITurtleAccess
{ {
/**
* Returns the world in which the turtle resides.
* @return the world in which the turtle resides.
*/
public World getWorld();
/**
* Returns a vector containing the integer co-ordinates at which the turtle resides.
* @return a vector containing the integer co-ordinates at which the turtle resides.
*/
public BlockPos getPosition();
/** /**
* TODO: Document me * Returns the world in which the turtle resides.
*
* @return the world in which the turtle resides.
*/ */
public boolean teleportTo( World world, BlockPos pos ); @Nonnull
World getWorld();
/**
* Returns a vector containing the floating point co-ordinates at which the turtle is rendered.
* This will shift when the turtle is moving.
* @param f The subframe fraction
* @return a vector containing the floating point co-ordinates at which the turtle resides.
*/
public Vec3d getVisualPosition( float f );
/** /**
* TODO: Document me * Returns a vector containing the integer co-ordinates at which the turtle resides.
*
* @return a vector containing the integer co-ordinates at which the turtle resides.
*/ */
public float getVisualYaw( float f ); @Nonnull
BlockPos getPosition();
/**
* Returns the world direction the turtle is currently facing.
* @return the world direction the turtle is currently facing.
*/
public EnumFacing getDirection();
/** /**
* TODO: Document me * Attempt to move this turtle to a new position.
*
* This will preserve the turtle's internal state, such as it's inventory, computer and upgrades. It should
* be used before playing a movement animation using {@link #playAnimation(TurtleAnimation)}.
*
* @param world The new world to move it to
* @param pos The new position to move it to.
* @return Whether the movement was successful. It may fail if the block was not loaded or the block placement
* was cancelled. Note this will not check
* {@link dan200.computercraft.api.permissions.ITurtlePermissionProvider#isBlockEnterable(World, BlockPos)}.
* @throws UnsupportedOperationException When attempting to teleport on the client side.
*/ */
public void setDirection( EnumFacing dir ); boolean teleportTo( @Nonnull World world, @Nonnull BlockPos pos );
/** /**
* TODO: Document me * Returns a vector containing the floating point co-ordinates at which the turtle is rendered.
* This will shift when the turtle is moving.
*
* @param f The subframe fraction.
* @return A vector containing the floating point co-ordinates at which the turtle resides.
* @see #getVisualYaw(float)
*/ */
public int getSelectedSlot(); @Nonnull
Vec3d getVisualPosition( float f );
/** /**
* TODO: Document me * Returns the yaw the turtle is facing when it is rendered.
*
* @param f The subframe fraction.
* @return The yaw the turtle is facing.
* @see #getVisualPosition(float)
*/ */
public void setSelectedSlot( int slot ); float getVisualYaw( float f );
/** /**
* Sets the colour of the turtle, as if the player had dyed it with a dye item. * Returns the world direction the turtle is currently facing.
* @param dyeColour 0-15 to dye the turtle one of the 16 standard minecraft colours, or -1 to remove the dye from the turtle. *
* @return The world direction the turtle is currently facing.
* @see #setDirection(EnumFacing)
*/ */
public void setDyeColour( int dyeColour ); @Nonnull
EnumFacing getDirection();
/** /**
* Gets the colour the turtle has been dyed. * Set the direction the turtle is facing. Note that this will not play a rotation animation, you will also need to
* @return 0-15 if the turtle has been dyed one of the 16 standard minecraft colours, -1 if the turtle is clean. * call {@link #playAnimation(TurtleAnimation)} to do so.
*
* @param dir The new direction to set. This should be on either the x or z axis (so north, south, east or west).
* @see #getDirection()
*/ */
public int getDyeColour(); void setDirection( @Nonnull EnumFacing dir );
/** /**
* TODO: Document me * Get the currently selected slot in the turtle's inventory.
*
* @return An integer representing the current slot.
* @see #getInventory()
* @see #setSelectedSlot(int)
*/ */
public IInventory getInventory(); int getSelectedSlot();
/** /**
* TODO: Document me * Set the currently selected slot in the turtle's inventory.
*
* @param slot The slot to set. This must be greater or equal to 0 and less than the inventory size. Otherwise no
* action will be taken.
* @throws UnsupportedOperationException When attempting to change the slot on the client side.
* @see #getInventory()
* @see #getSelectedSlot()
*/ */
public boolean isFuelNeeded(); void setSelectedSlot( int slot );
/**
* TODO: Document me
*/
public int getFuelLevel();
/** /**
* TODO: Document me * Set the colour of the turtle to a RGB number.
*
* @param colour The colour this turtle should be changed to. This should be a RGB colour between {@code 0x000000}
* and {@code 0xFFFFFF} or -1 to reset to the default colour.
* @see #getColour()
*/ */
public void setFuelLevel( int fuel ); void setColour( int colour );
/** /**
* TODO: Document me * Get the colour of this turtle as a RGB number.
*
* @return The colour this turtle is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or
* -1 if it has no colour.
* @see #setColour(int)
*/ */
public int getFuelLimit(); int getColour();
/** /**
* Removes some fuel from the turtles fuel supply. Negative numbers can be passed in to INCREASE the fuel level of the turtle. * Get the inventory of this turtle
* @return Whether the turtle was able to consume the ammount of fuel specified. Will return false if you supply a number *
* greater than the current fuel level of the turtle. * @return This turtle's inventory
*/ * @see #getItemHandler()
public boolean consumeFuel( int fuel );
/**
* TODO: Document me
*/ */
public void addFuel( int fuel ); @Nonnull
IInventory getInventory();
/**
* Get the inventory of this turtle as an {@link IItemHandlerModifiable}.
*
* @return This turtle's inventory
* @see #getInventory()
* @see IItemHandlerModifiable
* @see net.minecraftforge.items.CapabilityItemHandler#ITEM_HANDLER_CAPABILITY
*/
@Nonnull
IItemHandlerModifiable getItemHandler();
/**
* Determine whether this turtle will require fuel when performing actions.
*
* @return Whether this turtle needs fuel.
* @see #getFuelLevel()
* @see #setFuelLevel(int)
*/
boolean isFuelNeeded();
/**
* Get the current fuel level of this turtle.
*
* @return The turtle's current fuel level.
* @see #isFuelNeeded()
* @see #setFuelLevel(int)
*/
int getFuelLevel();
/**
* Set the fuel level to a new value. It is generally preferred to use {@link #consumeFuel(int)}} or {@link #addFuel(int)}
* instead.
*
* @param fuel The new amount of fuel. This must be between 0 and the fuel limit.
* @see #getFuelLevel()
* @see #getFuelLimit()
* @see #addFuel(int)
* @see #consumeFuel(int)
*/
void setFuelLevel( int fuel );
/**
* Get the maximum amount of fuel a turtle can hold.
*
* @return The turtle's fuel limit.
*/
int getFuelLimit();
/**
* Removes some fuel from the turtles fuel supply. Negative numbers can be passed in to INCREASE the fuel level of the turtle.
*
* @param fuel The amount of fuel to consume.
* @return Whether the turtle was able to consume the amount of fuel specified. Will return false if you supply a number
* greater than the current fuel level of the turtle. No fuel will be consumed if {@code false} is returned.
* @throws UnsupportedOperationException When attempting to consume fuel on the client side.
*/
boolean consumeFuel( int fuel );
/**
* Increase the turtle's fuel level by the given amount.
*
* @param fuel The amount to refuel with.
* @throws UnsupportedOperationException When attempting to refuel on the client side.
*/
void addFuel( int fuel );
/** /**
* Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be executed * Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be executed
@@ -128,42 +216,80 @@ public interface ITurtleAccess
* with the turtles standard movement and tool commands. An issued command will return an unique integer, which will * with the turtles standard movement and tool commands. An issued command will return an unique integer, which will
* be supplied as a parameter to a "turtle_response" event issued to the turtle after the command has completed. Look at the * be supplied as a parameter to a "turtle_response" event issued to the turtle after the command has completed. Look at the
* lua source code for "rom/apis/turtle" for how to build a lua wrapper around this functionality. * lua source code for "rom/apis/turtle" for how to build a lua wrapper around this functionality.
* @param command an object which will execute the custom command when its point in the queue is reached *
* @return the objects the command returned when executed. you should probably return these to the player * @param context The Lua context to pull events from.
* @param command An object which will execute the custom command when its point in the queue is reached
* @return The objects the command returned when executed. you should probably return these to the player
* unchanged if called from a peripheral method. * unchanged if called from a peripheral method.
* @throws UnsupportedOperationException When attempting to execute a command on the client side.
* @throws LuaException If the user presses CTRL+T to terminate the current program while {@code executeCommand()} is
* waiting for an event, a "Terminated" exception will be thrown here.
* @throws InterruptedException If the user shuts down or reboots the computer while pullEvent() is waiting for an
* event, InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.
* @see ITurtleCommand * @see ITurtleCommand
* @see ILuaContext#pullEvent(String)
*/ */
public Object[] executeCommand( ILuaContext context, ITurtleCommand command ) throws LuaException, InterruptedException; @Nonnull
Object[] executeCommand( @Nonnull ILuaContext context, @Nonnull ITurtleCommand command ) throws LuaException, InterruptedException;
/** /**
* TODO: Document me * Start playing a specific animation. This will prevent other turtle commands from executing until
* it is finished.
*
* @param animation The animation to play.
* @throws UnsupportedOperationException When attempting to execute play an animation on the client side.
* @see TurtleAnimation
*/ */
public void playAnimation( TurtleAnimation animation ); void playAnimation( @Nonnull TurtleAnimation animation );
/**
* Returns the turtle on the specified side of the turtle, if there is one.
* @return the turtle on the specified side of the turtle, if there is one.
*/
public ITurtleUpgrade getUpgrade( TurtleSide side );
/** /**
* TODO: Document me * Returns the turtle on the specified side of the turtle, if there is one.
*
* @param side The side to get the upgrade from.
* @return The upgrade on the specified side of the turtle, if there is one.
* @see #setUpgrade(TurtleSide, ITurtleUpgrade)
*/ */
public void setUpgrade( TurtleSide side, ITurtleUpgrade upgrade ); @Nullable
ITurtleUpgrade getUpgrade( @Nonnull TurtleSide side );
/**
* Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one.
* @return the peripheral created by the upgrade on the specified side of the turtle, if there is one.
*/
public IPeripheral getPeripheral( TurtleSide side );
/** /**
* TODO: Document me * Set the upgrade for a given side, resetting peripherals and clearing upgrade specific data.
*
* @param side The side to set the upgrade on.
* @param upgrade The upgrade to set, may be {@code null} to clear.
* @see #getUpgrade(TurtleSide)
*/ */
public NBTTagCompound getUpgradeNBTData( TurtleSide side ); void setUpgrade( @Nonnull TurtleSide side, @Nullable ITurtleUpgrade upgrade );
/** /**
* TODO: Document me * Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one.
*
* @param side The side to get the peripheral from.
* @return The peripheral created by the upgrade on the specified side of the turtle, {@code null} if none exists.
*/ */
public void updateUpgradeNBTData( TurtleSide side ); @Nullable
IPeripheral getPeripheral( @Nonnull TurtleSide side );
/**
* Get an upgrade-specific NBT compound, which can be used to store arbitrary data.
*
* This will be persisted across turtle restarts and chunk loads, as well as being synced to the client. You must
* call {@link #updateUpgradeNBTData(TurtleSide)} after modifying it.
*
* @param side The side to get the upgrade data for.
* @return The upgrade-specific data.
* @see #updateUpgradeNBTData(TurtleSide)
*/
@Nonnull
NBTTagCompound getUpgradeNBTData( @Nullable TurtleSide side );
/**
* Mark the upgrade-specific data as dirty on a specific side. This is required for the data to be synced to the
* client and persisted.
*
* @param side The side to mark dirty.
* @see #updateUpgradeNBTData(TurtleSide)
*/
void updateUpgradeNBTData( @Nonnull TurtleSide side );
} }

View File

@@ -1,25 +1,36 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import dan200.computercraft.api.lua.ILuaContext;
import javax.annotation.Nonnull;
/** /**
* An interface for objects executing custom turtle commands, used with ITurtleAccess.issueCommand * An interface for objects executing custom turtle commands, used with {@link ITurtleAccess#executeCommand(ILuaContext, ITurtleCommand)}.
* @see ITurtleAccess#executeCommand(dan200.computercraft.api.lua.ILuaContext,ITurtleCommand) *
* @see ITurtleAccess#executeCommand(ILuaContext, ITurtleCommand)
*/ */
@FunctionalInterface
public interface ITurtleCommand public interface ITurtleCommand
{ {
/** /**
* Will be called by the turtle on the main thread when it is time to execute the custom command. * Will be called by the turtle on the main thread when it is time to execute the custom command.
* The handler should either perform the work of the command, and return success, or return *
* failure with an error message to indicate the command cannot be executed at this time. * The handler should either perform the work of the command, and return success, or return
* @param turtle access to the turtle for whom the command was issued * failure with an error message to indicate the command cannot be executed at this time.
* @return TurtleCommandResult.success() or TurtleCommandResult.failure( errorMessage ) *
* @see ITurtleAccess#executeCommand(dan200.computercraft.api.lua.ILuaContext,ITurtleCommand) * @param turtle Access to the turtle for whom the command was issued.
* @see dan200.computercraft.api.turtle.TurtleCommandResult * @return A result, indicating whether this action succeeded or not.
*/ * @see ITurtleAccess#executeCommand(ILuaContext, ITurtleCommand)
public TurtleCommandResult execute( ITurtleAccess turtle ); * @see TurtleCommandResult#success()
* @see TurtleCommandResult#failure(String)
* @see TurtleCommandResult
*/
@Nonnull
TurtleCommandResult execute( @Nonnull ITurtleAccess turtle );
} }

View File

@@ -1,13 +1,15 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.client.renderer.block.model.IBakedModel; import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
@@ -15,94 +17,126 @@ import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.vecmath.Matrix4f; import javax.vecmath.Matrix4f;
/** /**
* The primary interface for defining an update for Turtles. A turtle update * The primary interface for defining an update for Turtles. A turtle update
* can either be a new tool, or a new peripheral. * can either be a new tool, or a new peripheral.
* @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( dan200.computercraft.api.turtle.ITurtleUpgrade ) *
* @see ComputerCraftAPI#registerTurtleUpgrade(ITurtleUpgrade)
*/ */
public interface ITurtleUpgrade public interface ITurtleUpgrade
{ {
/** /**
* Gets a unique identifier representing this type of turtle upgrade. eg: "computercraft:wireless_modem" or "my_mod:my_upgrade". * Gets a unique identifier representing this type of turtle upgrade. eg: "computercraft:wireless_modem" or "my_mod:my_upgrade".
* You should use a unique resource domain to ensure this upgrade is uniquely identified. * You should use a unique resource domain to ensure this upgrade is uniquely identified.
* The turtle will fail registration if an already used ID is specified. * The turtle will fail registration if an already used ID is specified.
* @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( dan200.computercraft.api.turtle.ITurtleUpgrade ) *
*/ * @return The unique ID for this upgrade.
public ResourceLocation getUpgradeID(); * @see ComputerCraftAPI#registerTurtleUpgrade(ITurtleUpgrade)
*/
@Nonnull
ResourceLocation getUpgradeID();
/** /**
* Gets a numerical identifier representing this type of turtle upgrade, * Gets a numerical identifier representing this type of turtle upgrade,
* for backwards compatibility with pre-1.76 worlds. If your upgrade was * for backwards compatibility with pre-1.76 worlds. If your upgrade was
* not released for older ComputerCraft versions, you can return -1 here. * not released for older ComputerCraft versions, you can return -1 here.
* The turtle will fail registration if an already used positive ID is specified. * The turtle will fail registration if an already used positive ID is specified.
* @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( dan200.computercraft.api.turtle.ITurtleUpgrade ) *
* @return The legacy ID, or -1 if is needed.
* @see ComputerCraftAPI#registerTurtleUpgrade(ITurtleUpgrade)
*/ */
public int getLegacyUpgradeID(); int getLegacyUpgradeID();
/** /**
* Return a String to describe this type of turtle in turtle item names. * Return an unlocalised string to describe this type of turtle in turtle item names.
* Examples of built-in adjectives are "Wireless", "Mining" and "Crafty". *
*/ * Examples of built-in adjectives are "Wireless", "Mining" and "Crafty".
public String getUnlocalisedAdjective(); *
* @return The localisation key for this upgrade's adjective.
/** */
* Return whether this turtle adds a tool or a peripheral to the turtle. @Nonnull
* @see TurtleUpgradeType for the differences between the two. String getUnlocalisedAdjective();
*/
public TurtleUpgradeType getType();
/**
* Return an item stack representing the type of item that a turtle must be crafted
* with to create a turtle which holds this upgrade. This item stack is also used
* to determine the upgrade given by turtle.equip()
*/
public ItemStack getCraftingItem();
/** /**
* Will only be called for peripheral upgrades. Creates a peripheral for a turtle * Return whether this turtle adds a tool or a peripheral to the turtle.
* being placed using this upgrade. The peripheral created will be stored *
* for the lifetime of the upgrade, will have update() called once-per-tick, and will be * @return The type of upgrade this is.
* attached, detached and have methods called in the same manner as a Computer peripheral. * @see TurtleUpgradeType for the differences between them.
* */
@Nonnull
TurtleUpgradeType getType();
/**
* Return an item stack representing the type of item that a turtle must be crafted
* with to create a turtle which holds this upgrade. This item stack is also used
* to determine the upgrade given by {@code turtle.equip()}
*
* @return The item stack to craft with, or {@link ItemStack#EMPTY} if it cannot be crafted.
*/
@Nonnull
ItemStack getCraftingItem();
/**
* Will only be called for peripheral upgrades. Creates a peripheral for a turtle being placed using this upgrade.
*
* The peripheral created will be stored for the lifetime of the upgrade and will be passed as an argument to
* {@link #update(ITurtleAccess, TurtleSide)}. It will be attached, detached and have methods called in the same
* manner as a Computer peripheral.
*
* @param turtle Access to the turtle that the peripheral is being created for. * @param turtle Access to the turtle that the peripheral is being created for.
* @param side Which side of the turtle (left or right) that the upgrade resides on. * @param side Which side of the turtle (left or right) that the upgrade resides on.
* @return The newly created peripheral. You may return null if this upgrade is a Tool * @return The newly created peripheral. You may return {@code null} if this upgrade is a Tool
* and this method is not expected to be called. * and this method is not expected to be called.
*/ */
public IPeripheral createPeripheral( ITurtleAccess turtle, TurtleSide side ); @Nullable
IPeripheral createPeripheral( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side );
/** /**
* Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called * Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called
* by the turtle, and the tool is required to do some work. * by the turtle, and the tool is required to do some work.
* @param turtle Access to the turtle that the tool resides on. *
* @param side Which side of the turtle (left or right) the tool resides on. * @param turtle Access to the turtle that the tool resides on.
* @param verb Which action (dig or attack) the turtle is being called on to perform. * @param side Which side of the turtle (left or right) the tool resides on.
* @param direction Which world direction the action should be performed in, relative to the turtles * @param verb Which action (dig or attack) the turtle is being called on to perform.
* position. This will either be up, down, or the direction the turtle is facing, depending on * @param direction Which world direction the action should be performed in, relative to the turtles
* whether dig, digUp or digDown was called. * position. This will either be up, down, or the direction the turtle is facing, depending on
* @return Whether the turtle was able to perform the action, and hence whether the turtle.dig() * whether dig, digUp or digDown was called.
* or turtle.attack() lua method should return true. If true is returned, the tool will perform * @return Whether the turtle was able to perform the action, and hence whether the {@code turtle.dig()}
* a swinging animation. You may return null if this turtle is a Peripheral * or {@code turtle.attack()} lua method should return true. If true is returned, the tool will perform
* and this method is not expected to be called. * a swinging animation. You may return {@code null} if this turtle is a Peripheral and this method is not expected
*/ * to be called.
public TurtleCommandResult useTool( ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, EnumFacing direction ); */
@Nonnull
TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull EnumFacing direction );
/** /**
* Called to obtain the model to be used when rendering a turtle peripheral. * Called to obtain the model to be used when rendering a turtle peripheral.
*
* This can be obtained from {@link net.minecraft.client.renderer.ItemModelMesher#getItemModel(ItemStack)},
* {@link net.minecraft.client.renderer.block.model.ModelManager#getModel(ModelResourceLocation)} or any other
* source.
*
* @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models! * @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models!
* @param side Which side of the turtle (left or right) the upgrade resides on. * @param side Which side of the turtle (left or right) the upgrade resides on.
* @return The model that you wish to be used to render your upgrade, and a transformation to apply to it. Returning a transformation of null has the same effect as the identify matrix. * @return The model that you wish to be used to render your upgrade, and a transformation to apply to it. Returning
* a transformation of {@code null} has the same effect as the identify matrix.
*/ */
@SideOnly( Side.CLIENT ) @SideOnly(Side.CLIENT)
public Pair<IBakedModel, Matrix4f> getModel( ITurtleAccess turtle, TurtleSide side ); @Nonnull
Pair<IBakedModel, Matrix4f> getModel( @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side );
/** /**
* Called once per tick for each turtle which has the upgrade equipped. * Called once per tick for each turtle which has the upgrade equipped.
*
* @param turtle Access to the turtle that the upgrade resides on. * @param turtle Access to the turtle that the upgrade resides on.
* @param side Which side of the turtle (left or right) the upgrade resides on. * @param side Which side of the turtle (left or right) the upgrade resides on.
*/ */
public void update( ITurtleAccess turtle, TurtleSide side ); default void update( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side )
{
}
} }

View File

@@ -1,22 +1,87 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
/**
* An animation a turtle will play between executing commands.
*
* Each animation takes 8 ticks to complete unless otherwise specified.
*
* @see ITurtleAccess#playAnimation(TurtleAnimation)
*/
public enum TurtleAnimation public enum TurtleAnimation
{ {
/**
* An animation which does nothing. This takes no time to complete.
*
* @see #Wait
* @see #ShortWait
*/
None, None,
/**
* Make the turtle move forward. Note that the animation starts from the block <em>behind</em> it, and
* moves into this one.
*/
MoveForward, MoveForward,
/**
* Make the turtle move backwards. Note that the animation starts from the block <em>in front</em> it, and
* moves into this one.
*/
MoveBack, MoveBack,
/**
* Make the turtle move backwards. Note that the animation starts from the block <em>above</em> it, and
* moves into this one.
*/
MoveUp, MoveUp,
/**
* Make the turtle move backwards. Note that the animation starts from the block <em>below</em> it, and
* moves into this one.
*/
MoveDown, MoveDown,
/**
* Turn the turtle to the left. Note that the animation starts with the turtle facing <em>right</em>, and
* the turtle turns to face in the current direction.
*/
TurnLeft, TurnLeft,
/**
* Turn the turtle to the left. Note that the animation starts with the turtle facing <em>right</em>, and
* the turtle turns to face in the current direction.
*/
TurnRight, TurnRight,
/**
* Swing the tool on the left.
*/
SwingLeftTool, SwingLeftTool,
/**
* Swing the tool on the right.
*/
SwingRightTool, SwingRightTool,
/**
* Wait until the animation has finished, performing no movement.
*
* @see #ShortWait
* @see #None
*/
Wait, Wait,
/**
* Wait until the animation has finished, performing no movement. This takes 4 ticks to complete.
*
* @see #Wait
* @see #None
*/
ShortWait, ShortWait,
} }

View File

@@ -1,22 +1,46 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import net.minecraft.util.EnumFacing;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Used to indicate the result of executing a turtle command.
*
* @see ITurtleCommand#execute(ITurtleAccess)
* @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)
*/
public final class TurtleCommandResult public final class TurtleCommandResult
{ {
private static final TurtleCommandResult s_success = new TurtleCommandResult( true, null, null ); private static final TurtleCommandResult s_success = new TurtleCommandResult( true, null, null );
private static final TurtleCommandResult s_emptyFailure = new TurtleCommandResult( false, null, null ); private static final TurtleCommandResult s_emptyFailure = new TurtleCommandResult( false, null, null );
/**
* Create a successful command result with no result.
*
* @return A successful command result with no values.
*/
@Nonnull
public static TurtleCommandResult success() public static TurtleCommandResult success()
{ {
return success( null ); return success( null );
} }
public static TurtleCommandResult success( Object[] results ) /**
* Create a successful command result with the given result values.
*
* @param results The results of executing this command.
* @return A successful command result with the given values.
*/
@Nonnull
public static TurtleCommandResult success( @Nullable Object[] results )
{ {
if( results == null || results.length == 0 ) if( results == null || results.length == 0 )
{ {
@@ -28,12 +52,25 @@ public final class TurtleCommandResult
} }
} }
/**
* Create a failed command result with no error message.
*
* @return A failed command result with no message.
*/
@Nonnull
public static TurtleCommandResult failure() public static TurtleCommandResult failure()
{ {
return failure( null ); return failure( null );
} }
public static TurtleCommandResult failure( String errorMessage ) /**
* Create a failed command result with an error message.
*
* @param errorMessage The error message to provide.
* @return A failed command result with a message.
*/
@Nonnull
public static TurtleCommandResult failure( @Nullable String errorMessage )
{ {
if( errorMessage == null ) if( errorMessage == null )
{ {
@@ -56,16 +93,33 @@ public final class TurtleCommandResult
m_results = results; m_results = results;
} }
/**
* Determine whether the command executed successfully.
*
* @return If the command was successful.
*/
public boolean isSuccess() public boolean isSuccess()
{ {
return m_success; return m_success;
} }
/**
* Get the error message of this command result.
*
* @return The command's error message, or {@code null} if it was a success.
*/
@Nullable
public String getErrorMessage() public String getErrorMessage()
{ {
return m_errorMessage; return m_errorMessage;
} }
/**
* Get the resulting values of this command result.
*
* @return The command's result, or {@code null} if it was a failure.
*/
@Nullable
public Object[] getResults() public Object[] getResults()
{ {
return m_results; return m_results;

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
@@ -11,13 +11,13 @@ package dan200.computercraft.api.turtle;
*/ */
public enum TurtleSide public enum TurtleSide
{ {
/** /**
* The turtles left side (where the pickaxe usually is on a Wireless Mining Turtle) * The turtle's left side (where the pickaxe usually is on a Wireless Mining Turtle)
*/ */
Left, Left,
/** /**
* The turtles right side (where the modem usually is on a Wireless Mining Turtle) * The turtle's right side (where the modem usually is on a Wireless Mining Turtle)
*/ */
Right, Right,
} }

View File

@@ -1,27 +1,44 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
/** /**
* An enum representing the two different types of turtle that an ITurtleUpgrade * An enum representing the different types of turtle that an {@link ITurtleUpgrade} implementation can add to a turtle.
* implementation can add to a turtle. *
* @see ITurtleUpgrade * @see ITurtleUpgrade#getType()
*/ */
public enum TurtleUpgradeType public enum TurtleUpgradeType
{ {
/** /**
* A tool is rendered as an item on the side of the turtle, and responds to the turtle.dig() * A tool is rendered as an item on the side of the turtle, and responds to the {@code turtle.dig()}
* and turtle.attack() methods (Such as pickaxe or sword on Mining and Melee turtles). * and {@code turtle.attack()} methods (Such as pickaxe or sword on Mining and Melee turtles).
*/ */
Tool, Tool,
/** /**
* A peripheral adds a special peripheral which is attached to the side of the turtle, * A peripheral adds a special peripheral which is attached to the side of the turtle,
* and can be interacted with the peripheral API (Such as the modem on Wireless Turtles). * and can be interacted with the {@code peripheral} API (Such as the modem on Wireless Turtles).
*/ */
Peripheral, Peripheral,
/**
* An upgrade which provides both a tool and a peripheral. This can be used when you wish
* your upgrade to also provide methods. For example, a pickaxe could provide methods
* determining whether it can break the given block or not.
*/
Both,;
public boolean isTool()
{
return this == Tool || this == Both;
}
public boolean isPeripheral()
{
return this == Peripheral || this == Both;
}
} }

View File

@@ -1,26 +1,29 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import net.minecraft.util.EnumFacing;
/** /**
* An enum representing the two different actions that an ITurtleUpgrade of type * An enum representing the different actions that an {@link ITurtleUpgrade} of type Tool may be called on to perform by
* Tool may be called on to perform by a turtle. * a turtle.
* @see ITurtleUpgrade *
* @see ITurtleUpgrade#useTool * @see ITurtleUpgrade#getType()
* @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)
*/ */
public enum TurtleVerb public enum TurtleVerb
{ {
/** /**
* The turtle called turtle.dig(), turtle.digUp() or turtle.digDown() * The turtle called {@code turtle.dig()}, {@code turtle.digUp()} or {@code turtle.digDown()}
*/ */
Dig, Dig,
/** /**
* The turtle called turtle.attack(), turtle.attackUp() or turtle.attackDown() * The turtle called {@code turtle.attack()}, {@code turtle.attackUp()} or {@code turtle.attackDown()}
*/ */
Attack, Attack,
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of the public ComputerCraft API - http://www.computercraft.info * This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */

View File

@@ -1,24 +1,27 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import java.util.Arrays;
public class FixedWidthFontRenderer public class FixedWidthFontRenderer
{ {
public static ResourceLocation font = new ResourceLocation( "computercraft", "textures/gui/termFont.png" ); private static ResourceLocation font = new ResourceLocation( "computercraft", "textures/gui/term_font.png" );
public static ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/termBackground.png" ); public static ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/term_background.png" );
public static int FONT_HEIGHT = 9; public static int FONT_HEIGHT = 9;
public static int FONT_WIDTH = 6; public static int FONT_WIDTH = 6;
@@ -30,24 +33,53 @@ public class FixedWidthFontRenderer
m_textureManager = textureManager; m_textureManager = textureManager;
} }
private void drawChar( VertexBuffer renderer, double x, double y, int index, int color ) private static void greyscaleify( double[] rgb )
{
Arrays.fill( rgb, ( rgb[0] + rgb[1] + rgb[2] ) / 3.0f );
}
private void drawChar( BufferBuilder renderer, double x, double y, int index, int color, Palette p, boolean greyscale )
{ {
int column = index % 16; int column = index % 16;
int row = index / 16; int row = index / 16;
Colour colour = Colour.values()[ 15 - color ];
renderer.pos( x, y + FONT_HEIGHT, 0.0 ).tex( (double) (column * FONT_WIDTH) / 256.0, (double) ((row + 1) * FONT_HEIGHT) / 256.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); double[] colour = p.getColour( 15 - color );
renderer.pos( x + FONT_WIDTH, y + FONT_HEIGHT, 0.0 ).tex( (double) ((column + 1) * FONT_WIDTH) / 256.0, (double) ((row + 1) * FONT_HEIGHT) / 256.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); if(greyscale)
renderer.pos( x + FONT_WIDTH, y, 0.0 ).tex( (double) ((column + 1) * FONT_WIDTH) / 256.0, (double) (row * FONT_HEIGHT) / 256.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); {
renderer.pos( x, y, 0.0 ).tex( (double) (column * FONT_WIDTH) / 256.0, (double) (row * FONT_HEIGHT ) / 256.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); greyscaleify( colour );
}
float r = (float)colour[0];
float g = (float)colour[1];
float b = (float)colour[2];
int xStart = 1 + column * (FONT_WIDTH + 2);
int yStart = 1 + row * (FONT_HEIGHT + 2);
renderer.pos( x, y, 0.0 ).tex( xStart / 256.0, yStart / 256.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( x, y + FONT_HEIGHT, 0.0 ).tex( xStart / 256.0, (yStart + FONT_HEIGHT) / 256.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( x + FONT_WIDTH, y, 0.0 ).tex( (xStart + FONT_WIDTH) / 256.0, yStart / 256.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( x + FONT_WIDTH, y, 0.0 ).tex( (xStart + FONT_WIDTH) / 256.0, yStart / 256.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( x, y + FONT_HEIGHT, 0.0 ).tex( xStart / 256.0, (yStart + FONT_HEIGHT) / 256.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( x + FONT_WIDTH, y + FONT_HEIGHT, 0.0 ).tex( (xStart + FONT_WIDTH) / 256.0, (yStart + FONT_HEIGHT) / 256.0 ).color( r, g, b, 1.0f ).endVertex();
} }
private void drawQuad( VertexBuffer renderer, double x, double y, int color, double width ) private void drawQuad( BufferBuilder renderer, double x, double y, int color, double width, Palette p, boolean greyscale )
{ {
Colour colour = Colour.values()[ 15 - color ]; double[] colour = p.getColour( 15 - color );
renderer.pos( x, y + FONT_HEIGHT, 0.0 ).tex( 0.0, 1.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); if(greyscale)
renderer.pos( x + width, y + FONT_HEIGHT, 0.0 ).tex( 1.0, 1.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); {
renderer.pos( x + width, y, 0.0 ).tex( 1.0, 0.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); greyscaleify( colour );
renderer.pos( x, y, 0.0 ).tex( 0.0, 0.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); }
float r = (float)colour[0];
float g = (float)colour[1];
float b = (float)colour[2];
renderer.pos( x, y, 0.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( x, y + FONT_HEIGHT, 0.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( x + width, y, 0.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( x + width, y, 0.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( x, y + FONT_HEIGHT, 0.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( x + width, y + FONT_HEIGHT, 0.0 ).color( r, g, b, 1.0f ).endVertex();
} }
private boolean isGreyScale( int colour ) private boolean isGreyScale( int colour )
@@ -55,12 +87,12 @@ public class FixedWidthFontRenderer
return (colour == 0 || colour == 15 || colour == 7 || colour == 8); return (colour == 0 || colour == 15 || colour == 7 || colour == 8);
} }
public void drawStringBackgroundPart( int x, int y, TextBuffer backgroundColour, double leftMarginSize, double rightMarginSize, boolean greyScale ) public void drawStringBackgroundPart( int x, int y, TextBuffer backgroundColour, double leftMarginSize, double rightMarginSize, boolean greyScale, Palette p )
{ {
// Draw the quads // Draw the quads
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
VertexBuffer renderer = tessellator.getBuffer(); BufferBuilder renderer = tessellator.getBuffer();
renderer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR ); renderer.begin( GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_COLOR );
if( leftMarginSize > 0.0 ) if( leftMarginSize > 0.0 )
{ {
int colour1 = "0123456789abcdef".indexOf( backgroundColour.charAt( 0 ) ); int colour1 = "0123456789abcdef".indexOf( backgroundColour.charAt( 0 ) );
@@ -68,7 +100,7 @@ public class FixedWidthFontRenderer
{ {
colour1 = 15; colour1 = 15;
} }
drawQuad( renderer, x - leftMarginSize, y, colour1, leftMarginSize ); drawQuad( renderer, x - leftMarginSize, y, colour1, leftMarginSize, p, greyScale );
} }
if( rightMarginSize > 0.0 ) if( rightMarginSize > 0.0 )
{ {
@@ -77,7 +109,7 @@ public class FixedWidthFontRenderer
{ {
colour2 = 15; colour2 = 15;
} }
drawQuad( renderer, x + backgroundColour.length() * FONT_WIDTH, y, colour2, rightMarginSize ); drawQuad( renderer, x + backgroundColour.length() * FONT_WIDTH, y, colour2, rightMarginSize, p, greyScale );
} }
for( int i = 0; i < backgroundColour.length(); i++ ) for( int i = 0; i < backgroundColour.length(); i++ )
{ {
@@ -86,17 +118,19 @@ public class FixedWidthFontRenderer
{ {
colour = 15; colour = 15;
} }
drawQuad( renderer, x + i * FONT_WIDTH, y, colour, FONT_WIDTH ); drawQuad( renderer, x + i * FONT_WIDTH, y, colour, FONT_WIDTH, p, greyScale );
} }
GlStateManager.disableTexture2D();
tessellator.draw(); tessellator.draw();
GlStateManager.enableTexture2D();
} }
public void drawStringTextPart( int x, int y, TextBuffer s, TextBuffer textColour, boolean greyScale ) public void drawStringTextPart( int x, int y, TextBuffer s, TextBuffer textColour, boolean greyScale, Palette p )
{ {
// Draw the quads // Draw the quads
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
VertexBuffer renderer = tessellator.getBuffer(); BufferBuilder renderer = tessellator.getBuffer();
renderer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR ); renderer.begin( GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_TEX_COLOR );
for( int i = 0; i < s.length(); i++ ) for( int i = 0; i < s.length(); i++ )
{ {
// Switch colour // Switch colour
@@ -112,32 +146,32 @@ public class FixedWidthFontRenderer
{ {
index = (int)'?'; index = (int)'?';
} }
drawChar( renderer, x + i * FONT_WIDTH, y, index, colour ); drawChar( renderer, x + i * FONT_WIDTH, y, index, colour, p, greyScale );
} }
tessellator.draw(); tessellator.draw();
} }
public void drawString( TextBuffer s, int x, int y, TextBuffer textColour, TextBuffer backgroundColour, double leftMarginSize, double rightMarginSize, boolean greyScale ) public void drawString( TextBuffer s, int x, int y, TextBuffer textColour, TextBuffer backgroundColour, double leftMarginSize, double rightMarginSize, boolean greyScale, Palette p )
{ {
// Draw background // Draw background
if( backgroundColour != null ) if( backgroundColour != null )
{ {
// Bind the background texture // Bind the background texture
m_textureManager.bindTexture( background ); m_textureManager.bindTexture( background );
// Draw the quads // Draw the quads
drawStringBackgroundPart( x, y, backgroundColour, leftMarginSize, rightMarginSize, greyScale ); drawStringBackgroundPart( x, y, backgroundColour, leftMarginSize, rightMarginSize, greyScale, p );
} }
// Draw text // Draw text
if( s != null && textColour != null ) if( s != null && textColour != null )
{ {
// Bind the font texture // Bind the font texture
m_textureManager.bindTexture( font ); bindFont();
// Draw the quads // Draw the quads
drawStringTextPart( x, y, s, textColour, greyScale ); drawStringTextPart( x, y, s, textColour, greyScale, p );
} }
} }
public int getStringWidth(String s) public int getStringWidth(String s)
@@ -148,4 +182,10 @@ public class FixedWidthFontRenderer
} }
return s.length() * FONT_WIDTH; return s.length() * FONT_WIDTH;
} }
public void bindFont()
{
m_textureManager.bindTexture( font );
GlStateManager.glTexParameteri( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP );
}
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -11,7 +11,6 @@ import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.computer.core.IComputerContainer;
import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
@@ -25,14 +24,14 @@ import java.io.IOException;
public class GuiComputer extends GuiContainer public class GuiComputer extends GuiContainer
{ {
private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/corners.png" ); private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/corners.png" );
private static final ResourceLocation backgroundAdvanced = new ResourceLocation( "computercraft", "textures/gui/corners2.png" ); private static final ResourceLocation backgroundAdvanced = new ResourceLocation( "computercraft", "textures/gui/corners_advanced.png" );
private static final ResourceLocation backgroundCommand = new ResourceLocation( "computercraft", "textures/gui/cornersCommand.png" ); private static final ResourceLocation backgroundCommand = new ResourceLocation( "computercraft", "textures/gui/corners_command.png" );
private final ComputerFamily m_family; private final ComputerFamily m_family;
private final IComputer m_computer; private final IComputer m_computer;
private final int m_termWidth; private final int m_termWidth;
private final int m_termHeight; private final int m_termHeight;
private WidgetTerminal m_terminal; private WidgetTerminal m_terminal;
protected GuiComputer( Container container, ComputerFamily family, IComputer computer, int termWidth, int termHeight ) protected GuiComputer( Container container, ComputerFamily family, IComputer computer, int termWidth, int termHeight )
{ {
@@ -46,85 +45,78 @@ public class GuiComputer extends GuiContainer
public GuiComputer( TileComputer computer ) public GuiComputer( TileComputer computer )
{ {
this( this(
new ContainerComputer( computer ), new ContainerComputer( computer ),
computer.getFamily(), computer.getFamily(),
computer.createComputer(), computer.createComputer(),
ComputerCraft.terminalWidth_computer, ComputerCraft.terminalWidth_computer,
ComputerCraft.terminalHeight_computer ComputerCraft.terminalHeight_computer
); );
} }
@Override @Override
public void initGui() public void initGui()
{ {
super.initGui(); super.initGui();
Keyboard.enableRepeatEvents( true ); Keyboard.enableRepeatEvents( true );
m_terminal = new WidgetTerminal( 0, 0, m_termWidth, m_termHeight, new IComputerContainer() m_terminal = new WidgetTerminal( 0, 0, m_termWidth, m_termHeight, () -> m_computer, 2, 2, 2, 2 );
{
@Override
public IComputer getComputer()
{
return m_computer;
}
}, 2, 2, 2, 2 );
m_terminal.setAllowFocusLoss( false ); m_terminal.setAllowFocusLoss( false );
xSize = m_terminal.getWidth() + 24; xSize = m_terminal.getWidth() + 24;
ySize = m_terminal.getHeight() + 24; ySize = m_terminal.getHeight() + 24;
} }
@Override @Override
public void onGuiClosed() public void onGuiClosed()
{ {
super.onGuiClosed(); super.onGuiClosed();
Keyboard.enableRepeatEvents( false ); Keyboard.enableRepeatEvents( false );
} }
@Override @Override
public boolean doesGuiPauseGame() public boolean doesGuiPauseGame()
{ {
return false; return false;
} }
@Override @Override
public void updateScreen() public void updateScreen()
{ {
super.updateScreen(); super.updateScreen();
m_terminal.update(); m_terminal.update();
} }
@Override @Override
protected void keyTyped(char c, int k) throws IOException protected void keyTyped(char c, int k) throws IOException
{ {
if( k == 1 ) if( k == 1 )
{ {
super.keyTyped( c, k ); super.keyTyped( c, k );
} }
else else
{ {
m_terminal.keyTyped( c, k ); m_terminal.keyTyped( c, k );
} }
} }
@Override @Override
protected void mouseClicked( int x, int y, int button ) protected void mouseClicked( int x, int y, int button )
{ {
int startX = (width - m_terminal.getWidth()) / 2; int startX = (width - m_terminal.getWidth()) / 2;
int startY = (height - m_terminal.getHeight()) / 2; int startY = (height - m_terminal.getHeight()) / 2;
m_terminal.mouseClicked( x - startX, y - startY, button ); m_terminal.mouseClicked( x - startX, y - startY, button );
} }
@Override @Override
public void handleMouseInput() throws IOException public void handleMouseInput() throws IOException
{ {
super.handleMouseInput(); super.handleMouseInput();
int x = Mouse.getEventX() * width / mc.displayWidth; int x = Mouse.getEventX() * width / mc.displayWidth;
int y = height - Mouse.getEventY() * height / mc.displayHeight - 1; int y = height - Mouse.getEventY() * height / mc.displayHeight - 1;
int startX = (width - m_terminal.getWidth()) / 2; int startX = (width - m_terminal.getWidth()) / 2;
int startY = (height - m_terminal.getHeight()) / 2; int startY = (height - m_terminal.getHeight()) / 2;
m_terminal.handleMouseInput( x - startX, y - startY ); m_terminal.handleMouseInput( x - startX, y - startY );
} }
@Override @Override
@@ -134,17 +126,17 @@ public class GuiComputer extends GuiContainer
m_terminal.handleKeyboardInput(); m_terminal.handleKeyboardInput();
} }
@Override @Override
protected void drawGuiContainerForegroundLayer(int par1, int par2) protected void drawGuiContainerForegroundLayer(int par1, int par2)
{ {
} }
@Override @Override
protected void drawGuiContainerBackgroundLayer( float var1, int var2, int var3 ) protected void drawGuiContainerBackgroundLayer( float var1, int var2, int var3 )
{ {
} }
@Override @Override
public void drawScreen( int mouseX, int mouseY, float f ) public void drawScreen( int mouseX, int mouseY, float f )
{ {
// Work out where to draw // Work out where to draw
@@ -153,14 +145,14 @@ public class GuiComputer extends GuiContainer
int endX = startX + m_terminal.getWidth(); int endX = startX + m_terminal.getWidth();
int endY = startY + m_terminal.getHeight(); int endY = startY + m_terminal.getHeight();
// Draw background // Draw background
drawDefaultBackground(); drawDefaultBackground();
// Draw terminal // Draw terminal
m_terminal.draw( this.mc, startX, startY, mouseX, mouseY ); m_terminal.draw( this.mc, startX, startY, mouseX, mouseY );
// Draw a border around the terminal // Draw a border around the terminal
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
switch( m_family ) switch( m_family )
{ {
case Normal: case Normal:
@@ -181,15 +173,15 @@ public class GuiComputer extends GuiContainer
} }
} }
drawTexturedModalRect(startX - 12, startY - 12, 12, 28, 12, 12); drawTexturedModalRect(startX - 12, startY - 12, 12, 28, 12, 12);
drawTexturedModalRect(startX - 12, endY, 12, 40, 12, 16); drawTexturedModalRect(startX - 12, endY, 12, 40, 12, 16);
drawTexturedModalRect(endX, startY - 12, 24, 28, 12, 12); drawTexturedModalRect(endX, startY - 12, 24, 28, 12, 12);
drawTexturedModalRect(endX, endY, 24, 40, 12, 16); drawTexturedModalRect(endX, endY, 24, 40, 12, 16);
drawTexturedModalRect(startX, startY-12, 0, 0, endX - startX, 12); drawTexturedModalRect(startX, startY-12, 0, 0, endX - startX, 12);
drawTexturedModalRect(startX, endY, 0, 12, endX - startX, 16); drawTexturedModalRect(startX, endY, 0, 12, endX - startX, 16);
drawTexturedModalRect(startX-12, startY, 0, 28, 12, endY - startY); drawTexturedModalRect(startX-12, startY, 0, 28, 12, endY - startY);
drawTexturedModalRect(endX, startY, 36, 28, 12, endY - startY); drawTexturedModalRect(endX, startY, 36, 28, 12, endY - startY);
} }
} }

View File

@@ -0,0 +1,61 @@
package dan200.computercraft.client.gui;
import dan200.computercraft.ComputerCraft;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.common.config.ConfigElement;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.fml.client.IModGuiFactory;
import net.minecraftforge.fml.client.config.GuiConfig;
import net.minecraftforge.fml.client.config.IConfigElement;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class GuiConfigCC extends GuiConfig
{
public GuiConfigCC( GuiScreen parentScreen )
{
super( parentScreen, getConfigElements(), ComputerCraft.MOD_ID, false, false, "ComputerCraft" );
}
private static List<IConfigElement> getConfigElements()
{
ArrayList<IConfigElement> elements = new ArrayList<>();
for (Property property : ComputerCraft.Config.config.getCategory( Configuration.CATEGORY_GENERAL ).getOrderedValues())
{
elements.add( new ConfigElement( property ) );
}
return elements;
}
public static class Factory
implements IModGuiFactory
{
@Override
public void initialize( Minecraft minecraft )
{
}
@Override
public boolean hasConfigGui()
{
return true;
}
@Override
public GuiScreen createConfigGui( GuiScreen parentScreen )
{
return new GuiConfigCC( parentScreen );
}
@Override
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories()
{
return null;
}
}
}

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -30,8 +30,8 @@ public class GuiDiskDrive extends GuiContainer
protected void drawGuiContainerForegroundLayer(int par1, int par2) protected void drawGuiContainerForegroundLayer(int par1, int par2)
{ {
String title = m_diskDrive.getDisplayName().getUnformattedText(); String title = m_diskDrive.getDisplayName().getUnformattedText();
fontRendererObj.drawString( title, (xSize - fontRendererObj.getStringWidth(title)) / 2, 6, 0x404040 ); fontRenderer.drawString( title, (xSize - fontRenderer.getStringWidth(title)) / 2, 6, 0x404040 );
fontRendererObj.drawString( I18n.format("container.inventory"), 8, (ySize - 96) + 2, 0x404040 ); fontRenderer.drawString( I18n.format("container.inventory"), 8, (ySize - 96) + 2, 0x404040 );
} }
@Override @Override

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -32,8 +32,8 @@ public class GuiPrinter extends GuiContainer
protected void drawGuiContainerForegroundLayer(int par1, int par2) protected void drawGuiContainerForegroundLayer(int par1, int par2)
{ {
String title = m_printer.getDisplayName().getUnformattedText(); String title = m_printer.getDisplayName().getUnformattedText();
fontRendererObj.drawString( title, (xSize - fontRendererObj.getStringWidth(title)) / 2, 6, 0x404040 ); fontRenderer.drawString( title, (xSize - fontRenderer.getStringWidth(title)) / 2, 6, 0x404040 );
fontRendererObj.drawString( I18n.format("container.inventory"), 8, (ySize - 96) + 2, 0x404040 ); fontRenderer.drawString( I18n.format("container.inventory"), 8, (ySize - 96) + 2, 0x404040 );
} }
@Override @Override
@@ -48,7 +48,7 @@ public class GuiPrinter extends GuiContainer
boolean printing = m_container.isPrinting(); boolean printing = m_container.isPrinting();
if( printing ) if( printing )
{ {
drawTexturedModalRect(startX + 34, startY + 21, 176, 0, 25, 45); drawTexturedModalRect(startX + 34, startY + 21, 176, 0, 25, 45);
} }
} }
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -10,11 +10,11 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.media.inventory.ContainerHeldItem; import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Mouse; import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import java.io.IOException; import java.io.IOException;
@@ -22,106 +22,106 @@ public class GuiPrintout extends GuiContainer
{ {
private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/printout.png" ); private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/printout.png" );
private static final int xSize = 172; private static final int xSize = 172;
private static final int ySize = 209; private static final int ySize = 209;
private final boolean m_book; private final boolean m_book;
private final int m_pages; private final int m_pages;
private final TextBuffer[] m_text; private final TextBuffer[] m_text;
private final TextBuffer[] m_colours; private final TextBuffer[] m_colours;
private int m_page; private int m_page;
public GuiPrintout( ContainerHeldItem container ) public GuiPrintout( ContainerHeldItem container )
{ {
super( container ); super( container );
m_book = (ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book); m_book = (ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book);
String[] text = ItemPrintout.getText( container.getStack() ); String[] text = ItemPrintout.getText( container.getStack() );
m_text = new TextBuffer[ text.length ]; m_text = new TextBuffer[ text.length ];
for( int i=0; i<m_text.length; ++i ) for( int i=0; i<m_text.length; ++i )
{ {
m_text[i] = new TextBuffer( text[i] ); m_text[i] = new TextBuffer( text[i] );
} }
String[] colours = ItemPrintout.getColours( container.getStack() ); String[] colours = ItemPrintout.getColours( container.getStack() );
m_colours = new TextBuffer[ colours.length ]; m_colours = new TextBuffer[ colours.length ];
for( int i=0; i<m_colours.length; ++i ) for( int i=0; i<m_colours.length; ++i )
{ {
m_colours[i] = new TextBuffer( colours[i] ); m_colours[i] = new TextBuffer( colours[i] );
} }
m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 ); m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 );
m_page = 0; m_page = 0;
} }
@Override @Override
public void initGui() public void initGui()
{ {
super.initGui(); super.initGui();
} }
@Override @Override
public void onGuiClosed() public void onGuiClosed()
{ {
super.onGuiClosed(); super.onGuiClosed();
} }
@Override @Override
public boolean doesGuiPauseGame() public boolean doesGuiPauseGame()
{ {
return false; return false;
} }
@Override @Override
public void updateScreen() public void updateScreen()
{ {
super.updateScreen(); super.updateScreen();
} }
@Override @Override
protected void keyTyped(char c, int k) throws IOException protected void keyTyped(char c, int k) throws IOException
{ {
super.keyTyped( c, k ); super.keyTyped( c, k );
if( k == 205 ) if( k == 205 )
{ {
// Right // Right
if( m_page < m_pages - 1 ) if( m_page < m_pages - 1 )
{ {
m_page = m_page + 1; m_page = m_page + 1;
} }
} }
else if( k == 203 ) else if( k == 203 )
{ {
// Left // Left
if( m_page > 0 ) if( m_page > 0 )
{ {
m_page = m_page - 1; m_page = m_page - 1;
} }
} }
} }
@Override @Override
public void handleMouseInput() throws IOException public void handleMouseInput() throws IOException
{ {
super.handleMouseInput(); super.handleMouseInput();
int mouseWheelChange = Mouse.getEventDWheel(); int mouseWheelChange = Mouse.getEventDWheel();
if (mouseWheelChange < 0) if (mouseWheelChange < 0)
{ {
// Up // Up
if( m_page < m_pages - 1 ) if( m_page < m_pages - 1 )
{ {
m_page = m_page + 1; m_page = m_page + 1;
} }
} }
else if (mouseWheelChange > 0) else if (mouseWheelChange > 0)
{ {
// Down // Down
if( m_page > 0 ) if( m_page > 0 )
{ {
m_page = m_page - 1; m_page = m_page - 1;
} }
} }
} }
@Override @Override
@@ -137,76 +137,76 @@ public class GuiPrintout extends GuiContainer
@Override @Override
public void drawScreen(int mouseX, int mouseY, float f) public void drawScreen(int mouseX, int mouseY, float f)
{ {
// Draw background // Draw background
drawDefaultBackground(); drawDefaultBackground();
// Draw the printout // Draw the printout
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
this.mc.getTextureManager().bindTexture( background ); this.mc.getTextureManager().bindTexture( background );
int startY = (height - ySize) / 2; int startY = (height - ySize) / 2;
//int startX = (width - xSize) / 2 - (m_page * 8); //int startX = (width - xSize) / 2 - (m_page * 8);
int startX = (width - (xSize + (m_pages - 1)*8)) / 2; int startX = (width - (xSize + (m_pages - 1)*8)) / 2;
if( m_book ) if( m_book )
{ {
// Border // Border
drawTexturedModalRect( startX - 8, startY - 8, xSize + 48, 0, 12, ySize + 24); drawTexturedModalRect( startX - 8, startY - 8, xSize + 48, 0, 12, ySize + 24);
drawTexturedModalRect( startX + xSize + (m_pages - 1)*8 - 4, startY - 8, xSize + 48 + 12, 0, 12, ySize + 24); drawTexturedModalRect( startX + xSize + (m_pages - 1)*8 - 4, startY - 8, xSize + 48 + 12, 0, 12, ySize + 24);
drawTexturedModalRect( startX, startY - 8, 0, ySize, xSize, 12); drawTexturedModalRect( startX, startY - 8, 0, ySize, xSize, 12);
drawTexturedModalRect( startX, startY + ySize - 4, 0, ySize + 12, xSize, 12); drawTexturedModalRect( startX, startY + ySize - 4, 0, ySize + 12, xSize, 12);
for( int n=1; n<m_pages; ++n ) for( int n=1; n<m_pages; ++n )
{ {
drawTexturedModalRect( startX + xSize + (n-1)*8, startY - 8, 0, ySize, 8, 12); drawTexturedModalRect( startX + xSize + (n-1)*8, startY - 8, 0, ySize, 8, 12);
drawTexturedModalRect( startX + xSize + (n-1)*8, startY + ySize - 4, 0, ySize + 12, 8, 12); drawTexturedModalRect( startX + xSize + (n-1)*8, startY + ySize - 4, 0, ySize + 12, 8, 12);
} }
} }
// Left half // Left half
if( m_page == 0 ) if( m_page == 0 )
{ {
drawTexturedModalRect( startX, startY, 24, 0, xSize / 2, ySize); drawTexturedModalRect( startX, startY, 24, 0, xSize / 2, ySize);
drawTexturedModalRect( startX, startY, 0, 0, 12, ySize); drawTexturedModalRect( startX, startY, 0, 0, 12, ySize);
} }
else else
{ {
drawTexturedModalRect( startX, startY, 0, 0, 12, ySize); drawTexturedModalRect( startX, startY, 0, 0, 12, ySize);
for( int n=1; n<m_page; ++n ) for( int n=1; n<m_page; ++n )
{ {
drawTexturedModalRect( startX + n*8, startY, 12, 0, 12, ySize); drawTexturedModalRect( startX + n*8, startY, 12, 0, 12, ySize);
} }
drawTexturedModalRect( startX + m_page*8, startY, 24, 0, xSize / 2, ySize); drawTexturedModalRect( startX + m_page*8, startY, 24, 0, xSize / 2, ySize);
} }
// Right half // Right half
if( m_page == (m_pages - 1) ) if( m_page == (m_pages - 1) )
{ {
drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize); drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize);
drawTexturedModalRect( startX + m_page*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize); drawTexturedModalRect( startX + m_page*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize);
} }
else else
{ {
drawTexturedModalRect( startX + (m_pages - 1)*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize); drawTexturedModalRect( startX + (m_pages - 1)*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize);
for( int n=m_pages-2; n>=m_page; --n ) for( int n=m_pages-2; n>=m_page; --n )
{ {
drawTexturedModalRect( startX + n*8 + (xSize - 12), startY, 24 + xSize, 0, 12, ySize); drawTexturedModalRect( startX + n*8 + (xSize - 12), startY, 24 + xSize, 0, 12, ySize);
} }
drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize); drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize);
} }
// Draw the text // Draw the text
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer)ComputerCraft.getFixedWidthFontRenderer(); FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer)ComputerCraft.getFixedWidthFontRenderer();
int x = startX + m_page * 8 + 13; int x = startX + m_page * 8 + 13;
int y = startY + 11; int y = startY + 11;
for( int line=0; line<ItemPrintout.LINES_PER_PAGE; ++line ) for( int line=0; line<ItemPrintout.LINES_PER_PAGE; ++line )
{ {
int lineIdx = ItemPrintout.LINES_PER_PAGE * m_page + line; int lineIdx = ItemPrintout.LINES_PER_PAGE * m_page + line;
if( lineIdx >= 0 && lineIdx < m_text.length ) if( lineIdx >= 0 && lineIdx < m_text.length )
{ {
fontRenderer.drawString( m_text[lineIdx], x, y, m_colours[lineIdx], null, 0, 0, false ); fontRenderer.drawString( m_text[lineIdx], x, y, m_colours[lineIdx], null, 0, 0, false, Palette.DEFAULT );
} }
y = y + FixedWidthFontRenderer.FONT_HEIGHT; y = y + FixedWidthFontRenderer.FONT_HEIGHT;
} }
} }
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -11,7 +11,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.computer.core.IComputerContainer;
import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@@ -28,10 +27,10 @@ import java.io.IOException;
public class GuiTurtle extends GuiContainer public class GuiTurtle extends GuiContainer
{ {
private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/turtle.png" ); private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/turtle.png" );
private static final ResourceLocation backgroundAdvanced = new ResourceLocation( "computercraft", "textures/gui/turtle2.png" ); private static final ResourceLocation backgroundAdvanced = new ResourceLocation( "computercraft", "textures/gui/turtle_advanced.png" );
protected World m_world; protected World m_world;
protected ContainerTurtle m_container; protected ContainerTurtle m_container;
protected final ComputerFamily m_family; protected final ComputerFamily m_family;
protected final ITurtleAccess m_turtle; protected final ITurtleAccess m_turtle;
@@ -40,15 +39,15 @@ public class GuiTurtle extends GuiContainer
public GuiTurtle( World world, InventoryPlayer inventoryplayer, TileTurtle turtle ) public GuiTurtle( World world, InventoryPlayer inventoryplayer, TileTurtle turtle )
{ {
this( world, turtle, new ContainerTurtle( inventoryplayer, turtle.getAccess() ) ); this( world, turtle, new ContainerTurtle( inventoryplayer, turtle.getAccess() ) );
} }
protected GuiTurtle( World world, TileTurtle turtle, ContainerTurtle container ) protected GuiTurtle( World world, TileTurtle turtle, ContainerTurtle container )
{ {
super( container ); super( container );
m_world = world; m_world = world;
m_container = container; m_container = container;
m_family = turtle.getFamily(); m_family = turtle.getFamily();
m_turtle = turtle.getAccess(); m_turtle = turtle.getAccess();
m_computer = turtle.createComputer(); m_computer = turtle.createComputer();
@@ -60,67 +59,60 @@ public class GuiTurtle extends GuiContainer
@Override @Override
public void initGui() public void initGui()
{ {
super.initGui(); super.initGui();
Keyboard.enableRepeatEvents(true); Keyboard.enableRepeatEvents(true);
m_terminalGui = new WidgetTerminal( m_terminalGui = new WidgetTerminal(
( width - xSize ) / 2 + 8, ( width - xSize ) / 2 + 8,
( height - ySize ) / 2 + 8, ( height - ySize ) / 2 + 8,
ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalWidth_turtle,
ComputerCraft.terminalHeight_turtle, ComputerCraft.terminalHeight_turtle,
new IComputerContainer() () -> m_computer,
{
@Override
public IComputer getComputer()
{
return m_computer;
}
},
2, 2, 2, 2 2, 2, 2, 2
); );
m_terminalGui.setAllowFocusLoss( false ); m_terminalGui.setAllowFocusLoss( false );
} }
@Override @Override
public void onGuiClosed() public void onGuiClosed()
{ {
super.onGuiClosed(); super.onGuiClosed();
Keyboard.enableRepeatEvents(false); Keyboard.enableRepeatEvents(false);
} }
@Override @Override
public void updateScreen() public void updateScreen()
{ {
super.updateScreen(); super.updateScreen();
m_terminalGui.update(); m_terminalGui.update();
} }
@Override @Override
protected void keyTyped(char c, int k) throws IOException protected void keyTyped(char c, int k) throws IOException
{ {
if( k == 1 ) if( k == 1 )
{ {
super.keyTyped( c, k ); super.keyTyped( c, k );
} }
else else
{ {
m_terminalGui.keyTyped( c, k ); m_terminalGui.keyTyped( c, k );
} }
} }
@Override @Override
protected void mouseClicked(int x, int y, int button) throws IOException protected void mouseClicked(int x, int y, int button) throws IOException
{ {
super.mouseClicked( x, y, button ); super.mouseClicked( x, y, button );
m_terminalGui.mouseClicked( x, y, button ); m_terminalGui.mouseClicked( x, y, button );
} }
@Override @Override
public void handleMouseInput() throws IOException public void handleMouseInput() throws IOException
{ {
super.handleMouseInput(); super.handleMouseInput();
int x = Mouse.getEventX() * this.width / mc.displayWidth; int x = Mouse.getEventX() * this.width / mc.displayWidth;
int y = this.height - Mouse.getEventY() * this.height / mc.displayHeight - 1; int y = this.height - Mouse.getEventY() * this.height / mc.displayHeight - 1;
m_terminalGui.handleMouseInput( x, y ); m_terminalGui.handleMouseInput( x, y );
} }
@Override @Override
@@ -135,28 +127,28 @@ public class GuiTurtle extends GuiContainer
int x = (width - xSize) / 2; int x = (width - xSize) / 2;
int y = (height - ySize) / 2; int y = (height - ySize) / 2;
// Draw selection slot // Draw selection slot
int slot = m_container.getSelectedSlot(); int slot = m_container.getSelectedSlot();
if( slot >= 0 ) if( slot >= 0 )
{ {
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F ); GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
int slotX = (slot%4); int slotX = (slot%4);
int slotY = (slot/4); int slotY = (slot/4);
this.mc.getTextureManager().bindTexture( advanced ? backgroundAdvanced : background ); this.mc.getTextureManager().bindTexture( advanced ? backgroundAdvanced : background );
drawTexturedModalRect(x + m_container.m_turtleInvStartX - 2 + slotX * 18, y + m_container.m_playerInvStartY - 2 + slotY * 18, 0, 217, 24, 24); drawTexturedModalRect(x + m_container.m_turtleInvStartX - 2 + slotX * 18, y + m_container.m_playerInvStartY - 2 + slotY * 18, 0, 217, 24, 24);
} }
} }
@Override @Override
protected void drawGuiContainerBackgroundLayer( float f, int mouseX, int mouseY ) protected void drawGuiContainerBackgroundLayer( float f, int mouseX, int mouseY )
{ {
// Draw term // Draw term
boolean advanced = (m_family == ComputerFamily.Advanced); boolean advanced = (m_family == ComputerFamily.Advanced);
m_terminalGui.draw( Minecraft.getMinecraft(), 0, 0, mouseX, mouseY ); m_terminalGui.draw( Minecraft.getMinecraft(), 0, 0, mouseX, mouseY );
// Draw border/inventory // Draw border/inventory
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F ); GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
this.mc.getTextureManager().bindTexture( advanced ? backgroundAdvanced : background ); this.mc.getTextureManager().bindTexture( advanced ? backgroundAdvanced : background );
int x = (width - xSize) / 2; int x = (width - xSize) / 2;
int y = (height - ySize) / 2; int y = (height - ySize) / 2;
drawTexturedModalRect(x, y, 0, 0, xSize, ySize); drawTexturedModalRect(x, y, 0, 0, xSize, ySize);

View File

@@ -0,0 +1,19 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui.widgets;
public class MousePos
{
public int x;
public int y;
public MousePos( int x, int y )
{
this.x = x;
this.y = y;
}
}

View File

@@ -1,25 +1,22 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.gui.widgets; package dan200.computercraft.client.gui.widgets;
import dan200.computercraftedu.client.gui.widgets.MousePos;
import dan200.computercraftedu.client.gui.widgets.WidgetContainer;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.Gui;
import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.RenderItem;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.init.SoundEvents; import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import javax.annotation.Nonnull;
public abstract class Widget extends Gui public abstract class Widget extends Gui
{ {
@@ -268,12 +265,11 @@ public abstract class Widget extends Gui
protected void drawTooltip( String[] lines, int x, int y ) protected void drawTooltip( String[] lines, int x, int y )
{ {
Minecraft mc = Minecraft.getMinecraft(); Minecraft mc = Minecraft.getMinecraft();
FontRenderer fontRenderer = mc.fontRendererObj; FontRenderer fontRenderer = mc.fontRenderer;
int width = 0; int width = 0;
for( int i=0; i<lines.length; ++i ) for( String line : lines )
{ {
String line = lines[i];
width = Math.max( fontRenderer.getStringWidth( line ), width ); width = Math.max( fontRenderer.getStringWidth( line ), width );
} }
int startX = x + 12; int startX = x + 12;
@@ -328,9 +324,9 @@ public abstract class Widget extends Gui
} }
} }
protected void drawItemStack( int x, int y, ItemStack stack ) protected void drawItemStack( int x, int y, @Nonnull ItemStack stack )
{ {
if( stack != null ) if( !stack.isEmpty() )
{ {
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.enableLighting(); GlStateManager.enableLighting();
@@ -344,7 +340,7 @@ public abstract class Widget extends Gui
if( renderItem != null ) if( renderItem != null )
{ {
renderItem.renderItemAndEffectIntoGUI( stack, x, y ); renderItem.renderItemAndEffectIntoGUI( stack, x, y );
renderItem.renderItemOverlayIntoGUI( mc.fontRendererObj, stack, x, y, null ); renderItem.renderItemOverlayIntoGUI( mc.fontRenderer, stack, x, y, null );
} }
} }
finally finally
@@ -364,7 +360,7 @@ public abstract class Widget extends Gui
Minecraft mc = Minecraft.getMinecraft(); Minecraft mc = Minecraft.getMinecraft();
try try
{ {
mc.fontRendererObj.drawString( s, x, y, color ); mc.fontRenderer.drawString( s, x, y, color );
} }
finally finally
{ {
@@ -375,7 +371,7 @@ public abstract class Widget extends Gui
protected int getStringWidth( String s ) protected int getStringWidth( String s )
{ {
Minecraft mc = Minecraft.getMinecraft(); Minecraft mc = Minecraft.getMinecraft();
return mc.fontRendererObj.getStringWidth( s ); return mc.fontRenderer.getStringWidth( s );
} }
protected void playClickSound() protected void playClickSound()

View File

@@ -0,0 +1,336 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui.widgets;
import dan200.computercraft.client.gui.widgets.Widget;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import java.util.ArrayList;
public class WidgetContainer extends Widget
{
private ArrayList<Widget> m_widgets;
private Widget m_modalWidget;
public WidgetContainer( int x, int y, int w, int h )
{
super( x, y, w, h );
m_widgets = new ArrayList<>();
m_modalWidget = null;
}
public void addWidget( Widget widget )
{
m_widgets.add( widget );
widget.setParent( this );
}
public void setModalWidget( Widget widget )
{
m_modalWidget = widget;
if( widget != null )
{
widget.setParent( this );
}
}
public Widget getModalWidget()
{
return m_modalWidget;
}
@Override
public void update()
{
for( Widget m_widget : m_widgets )
{
m_widget.update();
}
if( m_modalWidget != null )
{
m_modalWidget.update();
}
}
@Override
public void draw( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY )
{
for( Widget widget : m_widgets )
{
if( widget.isVisible() )
{
widget.draw(
mc,
xOrigin + getXPosition(),
yOrigin + getYPosition(),
(m_modalWidget == null) ? (mouseX - getXPosition()) : -99,
(m_modalWidget == null) ? (mouseY - getYPosition()) : -99
);
}
}
if( m_modalWidget != null )
{
if( m_modalWidget.isVisible() )
{
GlStateManager.pushMatrix();
try
{
GlStateManager.translate( 0.0f, 0.0f, 200.0f );
m_modalWidget.draw(
mc,
xOrigin + getXPosition(),
yOrigin + getYPosition(),
mouseX - getXPosition(),
mouseY - getYPosition()
);
}
finally
{
GlStateManager.popMatrix();
}
}
}
}
@Override
public void drawForeground( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY )
{
for( Widget widget : m_widgets )
{
if( widget.isVisible() )
{
widget.drawForeground(
mc,
xOrigin + getXPosition(),
yOrigin + getYPosition(),
(m_modalWidget == null) ? (mouseX - getXPosition()) : -99,
(m_modalWidget == null) ? (mouseY - getYPosition()) : -99
);
}
}
if( m_modalWidget != null )
{
if( m_modalWidget.isVisible() )
{
GlStateManager.pushMatrix();
try
{
GlStateManager.translate( 0.0f, 0.0f, 200.0f );
m_modalWidget.drawForeground(
mc,
xOrigin + getXPosition(),
yOrigin + getYPosition(),
mouseX - getXPosition(),
mouseY - getYPosition()
);
}
finally
{
GlStateManager.popMatrix();
}
}
}
}
@Override
public void modifyMousePosition( MousePos pos )
{
pos.x -= getXPosition();
pos.y -= getYPosition();
if( m_modalWidget == null )
{
for( Widget widget : m_widgets )
{
if( widget.isVisible() )
{
widget.modifyMousePosition( pos );
}
}
}
else
{
if( m_modalWidget.isVisible() )
{
m_modalWidget.modifyMousePosition( pos );
}
}
pos.x += getXPosition();
pos.y += getYPosition();
}
@Override
public boolean suppressItemTooltips( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY )
{
if( m_modalWidget == null )
{
for( Widget widget : m_widgets )
{
if( widget.isVisible() )
{
if( widget.suppressItemTooltips(
mc,
xOrigin + getXPosition(),
yOrigin + getYPosition(),
mouseX - getXPosition(),
mouseY - getYPosition()
) )
{
return true;
}
}
}
}
else
{
if( m_modalWidget.isVisible() && m_modalWidget.suppressItemTooltips(
mc,
xOrigin + getXPosition(),
yOrigin + getYPosition(),
mouseX - getXPosition(),
mouseY - getYPosition()
) )
{
return true;
}
}
return false;
}
@Override
public boolean suppressKeyPress( char c, int k )
{
if( m_modalWidget == null )
{
for( Widget widget : m_widgets )
{
if( widget.isVisible() )
{
if( widget.suppressKeyPress( c, k ) )
{
return true;
}
}
}
}
else
{
if( m_modalWidget.isVisible() )
{
if( m_modalWidget.suppressKeyPress( c, k ) )
{
return true;
}
}
}
return false;
}
@Override
public void handleMouseInput( int mouseX, int mouseY )
{
if( m_modalWidget == null )
{
for( Widget widget : m_widgets )
{
if( widget.isVisible() )
{
widget.handleMouseInput(
mouseX - getXPosition(),
mouseY - getYPosition()
);
}
}
}
else
{
if( m_modalWidget.isVisible() )
{
m_modalWidget.handleMouseInput(
mouseX - getXPosition(),
mouseY - getYPosition()
);
}
}
}
@Override
public void handleKeyboardInput()
{
if( m_modalWidget == null )
{
for( Widget widget : m_widgets )
{
if( widget.isVisible() )
{
widget.handleKeyboardInput();
}
}
}
else
{
if( m_modalWidget.isVisible() )
{
m_modalWidget.handleKeyboardInput();
}
}
}
@Override
public void mouseClicked( int mouseX, int mouseY, int mouseButton )
{
if( m_modalWidget == null )
{
for( Widget widget : m_widgets )
{
if( widget.isVisible() )
{
widget.mouseClicked(
mouseX - getXPosition(),
mouseY - getYPosition(),
mouseButton
);
}
}
}
else
{
if( m_modalWidget.isVisible() )
{
m_modalWidget.mouseClicked(
mouseX - getXPosition(),
mouseY - getYPosition(),
mouseButton
);
}
}
}
@Override
public void keyTyped( char c, int k )
{
if( m_modalWidget == null )
{
for( Widget widget : m_widgets )
{
if( widget.isVisible() )
{
widget.keyTyped( c, k );
}
}
}
else
{
if( m_modalWidget.isVisible() )
{
m_modalWidget.keyTyped( c, k );
}
}
}
}

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -13,6 +13,7 @@ import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.computer.core.IComputerContainer; import dan200.computercraft.shared.computer.core.IComputerContainer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
@@ -25,18 +26,18 @@ import java.util.ArrayList;
public class WidgetTerminal extends Widget public class WidgetTerminal extends Widget
{ {
private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/termBackground.png" ); private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/term_background.png" );
private static float TERMINATE_TIME = 0.5f; private static float TERMINATE_TIME = 0.5f;
private IComputerContainer m_computer; private final IComputerContainer m_computer;
private float m_terminateTimer; private float m_terminateTimer;
private float m_rebootTimer; private float m_rebootTimer;
private float m_shutdownTimer; private float m_shutdownTimer;
private int m_lastClickButton; private int m_lastClickButton;
private int m_lastClickX; private int m_lastClickX;
private int m_lastClickY; private int m_lastClickY;
private boolean m_focus; private boolean m_focus;
private boolean m_allowFocusLoss; private boolean m_allowFocusLoss;
@@ -75,7 +76,7 @@ public class WidgetTerminal extends Widget
m_topMargin = topMargin; m_topMargin = topMargin;
m_bottomMargin = bottomMargin; m_bottomMargin = bottomMargin;
m_keysDown = new ArrayList<Integer>(); m_keysDown = new ArrayList<>();
} }
public void setAllowFocusLoss( boolean allowFocusLoss ) public void setAllowFocusLoss( boolean allowFocusLoss )
@@ -167,9 +168,9 @@ public class WidgetTerminal extends Widget
@Override @Override
public void mouseClicked( int mouseX, int mouseY, int button ) public void mouseClicked( int mouseX, int mouseY, int button )
{ {
if( mouseX >= getXPosition() && mouseX < getXPosition() + getWidth() && if( mouseX >= getXPosition() && mouseX < getXPosition() + getWidth() &&
mouseY >= getYPosition() && mouseY < getYPosition() + getHeight() ) mouseY >= getYPosition() && mouseY < getYPosition() + getHeight() )
{ {
if( !m_focus && button == 0) if( !m_focus && button == 0)
{ {
m_focus = true; m_focus = true;
@@ -198,7 +199,7 @@ public class WidgetTerminal extends Widget
} }
} }
} }
} }
else else
{ {
if( m_focus && button == 0 && m_allowFocusLoss ) if( m_focus && button == 0 && m_allowFocusLoss )
@@ -229,8 +230,8 @@ public class WidgetTerminal extends Widget
} }
@Override @Override
public void handleMouseInput( int mouseX, int mouseY ) public void handleMouseInput( int mouseX, int mouseY )
{ {
IComputer computer = m_computer.getComputer(); IComputer computer = m_computer.getComputer();
if( mouseX >= getXPosition() && mouseX < getXPosition() + getWidth() && if( mouseX >= getXPosition() && mouseX < getXPosition() + getWidth() &&
mouseY >= getYPosition() && mouseY < getYPosition() + getHeight() && mouseY >= getYPosition() && mouseY < getYPosition() + getHeight() &&
@@ -287,159 +288,160 @@ public class WidgetTerminal extends Widget
} }
} }
} }
} }
@Override @Override
public void update() public void update()
{ {
// Handle special keys // Handle special keys
if( m_focus && !m_locked && (Keyboard.isKeyDown( 29 ) || Keyboard.isKeyDown( 157 )) ) if( m_focus && !m_locked && (Keyboard.isKeyDown( 29 ) || Keyboard.isKeyDown( 157 )) )
{ {
// Ctrl+T for terminate // Ctrl+T for terminate
if( Keyboard.isKeyDown( 20 ) ) if( Keyboard.isKeyDown( 20 ) )
{ {
if( m_terminateTimer < TERMINATE_TIME ) if( m_terminateTimer < TERMINATE_TIME )
{ {
m_terminateTimer = m_terminateTimer + 0.05f; m_terminateTimer = m_terminateTimer + 0.05f;
if( m_terminateTimer >= TERMINATE_TIME ) if( m_terminateTimer >= TERMINATE_TIME )
{ {
queueEvent( "terminate" ); queueEvent( "terminate" );
} }
} }
} }
else else
{ {
m_terminateTimer = 0.0f; m_terminateTimer = 0.0f;
} }
// Ctrl+R for reboot // Ctrl+R for reboot
if( Keyboard.isKeyDown(19) ) if( Keyboard.isKeyDown(19) )
{ {
if( m_rebootTimer < TERMINATE_TIME ) if( m_rebootTimer < TERMINATE_TIME )
{ {
m_rebootTimer = m_rebootTimer + 0.05f; m_rebootTimer = m_rebootTimer + 0.05f;
if( m_rebootTimer >= TERMINATE_TIME ) if( m_rebootTimer >= TERMINATE_TIME )
{ {
IComputer computer = m_computer.getComputer(); IComputer computer = m_computer.getComputer();
if( computer != null ) if( computer != null )
{ {
computer.reboot(); computer.reboot();
} }
} }
} }
} }
else else
{ {
m_rebootTimer = 0.0f; m_rebootTimer = 0.0f;
} }
// Ctrl+S for shutdown // Ctrl+S for shutdown
if( Keyboard.isKeyDown(31) ) if( Keyboard.isKeyDown(31) )
{ {
if( m_shutdownTimer < TERMINATE_TIME ) if( m_shutdownTimer < TERMINATE_TIME )
{ {
m_shutdownTimer = m_shutdownTimer + 0.05f; m_shutdownTimer = m_shutdownTimer + 0.05f;
if( m_shutdownTimer >= TERMINATE_TIME ) if( m_shutdownTimer >= TERMINATE_TIME )
{ {
IComputer computer = m_computer.getComputer(); IComputer computer = m_computer.getComputer();
if( computer != null ) if( computer != null )
{ {
computer.shutdown(); computer.shutdown();
} }
} }
} }
} }
else else
{ {
m_shutdownTimer = 0.0f; m_shutdownTimer = 0.0f;
} }
} }
else else
{ {
m_terminateTimer = 0.0f; m_terminateTimer = 0.0f;
m_rebootTimer = 0.0f; m_rebootTimer = 0.0f;
m_shutdownTimer = 0.0f; m_shutdownTimer = 0.0f;
} }
} }
@Override @Override
public void draw( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY ) public void draw( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY )
{ {
int startX = xOrigin + getXPosition(); int startX = xOrigin + getXPosition();
int startY = yOrigin + getYPosition(); int startY = yOrigin + getYPosition();
// Draw the screen contents synchronized( m_computer )
IComputer computer = m_computer.getComputer(); {
Terminal terminal = (computer != null) ? computer.getTerminal() : null; // Draw the screen contents
if( terminal != null ) IComputer computer = m_computer.getComputer();
{ Terminal terminal = ( computer != null ) ? computer.getTerminal() : null;
// Draw the terminal if( terminal != null )
boolean greyscale = !computer.isColour(); {
synchronized( terminal ) // Draw the terminal
{ boolean greyscale = !computer.isColour();
// 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. Palette palette = terminal.getPalette();
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer)ComputerCraft.getFixedWidthFontRenderer();
boolean tblink = m_focus && terminal.getCursorBlink() && ComputerCraft.getGlobalCursorBlink(); // Get the data from the terminal first
int tw = terminal.getWidth(); // Unfortunately we have to keep the lock for the whole of drawing, so the text doesn't change under us.
int th = terminal.getHeight(); FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer();
int tx = terminal.getCursorX(); boolean tblink = m_focus && terminal.getCursorBlink() && ComputerCraft.getGlobalCursorBlink();
int ty = terminal.getCursorY(); int tw = terminal.getWidth();
int th = terminal.getHeight();
int x = startX + m_leftMargin; int tx = terminal.getCursorX();
int y = startY + m_topMargin; int ty = terminal.getCursorY();
int x = startX + m_leftMargin;
int y = startY + m_topMargin;
// Draw margins // Draw margins
TextBuffer emptyLine = new TextBuffer( ' ', tw ); TextBuffer emptyLine = new TextBuffer( ' ', tw );
if( m_topMargin > 0 ) if( m_topMargin > 0 )
{ {
fontRenderer.drawString( emptyLine, x, startY, terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), m_leftMargin, m_rightMargin, greyscale ); fontRenderer.drawString( emptyLine, x, startY, terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), m_leftMargin, m_rightMargin, greyscale, palette );
} }
if( m_bottomMargin > 0 ) if( m_bottomMargin > 0 )
{ {
fontRenderer.drawString( emptyLine, x, startY + 2 * m_bottomMargin + ( th - 1 ) * FixedWidthFontRenderer.FONT_HEIGHT, terminal.getTextColourLine( th - 1 ), terminal.getBackgroundColourLine( th - 1 ), m_leftMargin, m_rightMargin, greyscale ); fontRenderer.drawString( emptyLine, x, startY + 2 * m_bottomMargin + ( th - 1 ) * FixedWidthFontRenderer.FONT_HEIGHT, terminal.getTextColourLine( th - 1 ), terminal.getBackgroundColourLine( th - 1 ), m_leftMargin, m_rightMargin, greyscale, palette );
} }
// Draw lines // Draw lines
for( int line=0; line<th; ++line ) for( int line = 0; line < th; ++line )
{ {
TextBuffer text = terminal.getLine(line); TextBuffer text = terminal.getLine( line );
TextBuffer colour = terminal.getTextColourLine( line ); TextBuffer colour = terminal.getTextColourLine( line );
TextBuffer backgroundColour = terminal.getBackgroundColourLine( line ); TextBuffer backgroundColour = terminal.getBackgroundColourLine( line );
fontRenderer.drawString( text, x, y, colour, backgroundColour, m_leftMargin, m_rightMargin, greyscale ); fontRenderer.drawString( text, x, y, colour, backgroundColour, m_leftMargin, m_rightMargin, greyscale, palette );
if( tblink && ty == line ) y += FixedWidthFontRenderer.FONT_HEIGHT;
{ }
if( tx >= 0 && tx < tw )
{ if( tblink && tx >= 0 && ty >= 0 && tx < tw && ty < th )
TextBuffer cursor = new TextBuffer( '_', 1 ); {
TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 ); TextBuffer cursor = new TextBuffer( '_', 1 );
fontRenderer.drawString( TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 );
cursor,
x + FixedWidthFontRenderer.FONT_WIDTH * tx, fontRenderer.drawString(
y, cursor,
cursorColour, null, x + FixedWidthFontRenderer.FONT_WIDTH * tx,
0, 0, startY + m_topMargin + FixedWidthFontRenderer.FONT_HEIGHT * ty,
greyscale cursorColour, null,
); 0, 0,
} greyscale,
} palette
y = y + FixedWidthFontRenderer.FONT_HEIGHT; );
} }
} } else
}
else
{
// Draw a black background
mc.getTextureManager().bindTexture( background );
Colour black = Colour.Black;
GlStateManager.color( black.getR(), black.getG(), black.getB(), 1.0f );
try
{ {
drawTexturedModalRect( startX, startY, 0, 0, getWidth(), getHeight() ); // Draw a black background
} mc.getTextureManager().bindTexture( background );
finally Colour black = Colour.Black;
{ GlStateManager.color( black.getR(), black.getG(), black.getB(), 1.0f );
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); try
{
drawTexturedModalRect( startX, startY, 0, 0, getWidth(), getHeight() );
} finally
{
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
}
} }
} }
} }

View File

@@ -1,86 +1,97 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.proxy; package dan200.computercraft.client.proxy;
import com.google.common.base.Function;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.client.render.TurtleSmartItemModel; import dan200.computercraft.client.render.TurtleSmartItemModel;
import dan200.computercraft.shared.proxy.CCTurtleProxyCommon; import dan200.computercraft.shared.proxy.CCTurtleProxyCommon;
import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.core.TurtleBrain;
import dan200.computercraft.shared.turtle.items.ItemTurtleBase;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemMeshDefinition; 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.ModelBakery;
import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.color.IItemColor;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.SimpleReloadableResourceManager; import net.minecraft.client.resources.SimpleReloadableResourceManager;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.IModel; import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry; import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.gameevent.TickEvent;
import java.io.IOException; import javax.annotation.Nonnull;
public class CCTurtleProxyClient extends CCTurtleProxyCommon public class CCTurtleProxyClient extends CCTurtleProxyCommon
{ {
public CCTurtleProxyClient() // IComputerCraftProxy implementation
{
} @Override
public void preInit()
// IComputerCraftProxy implementation {
super.preInit();
@Override
public void init()
{
super.init();
// Setup client forge handlers
registerForgeHandlers();
}
@SubscribeEvent
public void registerModels( ModelRegistryEvent event )
{
// Register item models // Register item models
ItemMeshDefinition turtleMeshDefinition = new ItemMeshDefinition() ItemMeshDefinition turtleMeshDefinition = new ItemMeshDefinition()
{ {
private ModelResourceLocation turtle_dynamic = new ModelResourceLocation( "computercraft:turtle_dynamic", "inventory" ); private ModelResourceLocation turtle_dynamic = new ModelResourceLocation( "computercraft:turtle_dynamic", "inventory" );
@Nonnull
@Override @Override
public ModelResourceLocation getModelLocation( ItemStack stack ) public ModelResourceLocation getModelLocation( @Nonnull ItemStack stack )
{ {
return turtle_dynamic; return turtle_dynamic;
} }
}; };
String[] turtleModelNames = new String[] { String[] turtleModelNames = new String[] {
"turtle_dynamic", "turtle_dynamic",
"CC-Turtle", "CC-TurtleAdvanced", "turtle", "turtle_advanced",
"turtle_black", "turtle_red", "turtle_green", "turtle_brown", "turtle_white",
"turtle_blue", "turtle_purple", "turtle_cyan", "turtle_lightGrey",
"turtle_grey", "turtle_pink", "turtle_lime", "turtle_yellow",
"turtle_lightBlue", "turtle_magenta", "turtle_orange", "turtle_white",
"turtle_elf_overlay" "turtle_elf_overlay"
}; };
registerItemModel( ComputerCraft.Blocks.turtle, turtleMeshDefinition, turtleModelNames ); registerItemModel( ComputerCraft.Blocks.turtle, turtleMeshDefinition, turtleModelNames );
registerItemModel( ComputerCraft.Blocks.turtleExpanded, turtleMeshDefinition, turtleModelNames ); registerItemModel( ComputerCraft.Blocks.turtleExpanded, turtleMeshDefinition, turtleModelNames );
registerItemModel( ComputerCraft.Blocks.turtleAdvanced, 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 // Setup renderers
ClientRegistry.bindTileEntitySpecialRenderer( TileTurtle.class, new TileEntityTurtleRenderer() ); ClientRegistry.bindTileEntitySpecialRenderer( TileTurtle.class, new TileEntityTurtleRenderer() );
}
// Setup client forge handlers
registerForgeHandlers();
}
private void registerItemModel( Block block, ItemMeshDefinition definition, String[] names ) private void registerItemModel( Block block, ItemMeshDefinition definition, String[] names )
{ {
@@ -95,14 +106,14 @@ public class CCTurtleProxyClient extends CCTurtleProxyCommon
resources[i] = new ResourceLocation( "computercraft:" + names[i] ); resources[i] = new ResourceLocation( "computercraft:" + names[i] );
} }
ModelBakery.registerItemVariants( item, resources ); ModelBakery.registerItemVariants( item, resources );
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register( item, definition ); ModelLoader.setCustomMeshDefinition( item, definition );
} }
private void registerForgeHandlers() private void registerForgeHandlers()
{ {
ForgeHandlers handlers = new ForgeHandlers(); ForgeHandlers handlers = new ForgeHandlers();
MinecraftForge.EVENT_BUS.register( handlers ); MinecraftForge.EVENT_BUS.register( handlers );
} }
public class ForgeHandlers public class ForgeHandlers
{ {
@@ -131,7 +142,7 @@ public class CCTurtleProxyClient extends CCTurtleProxyCommon
@SubscribeEvent @SubscribeEvent
public void onTextureStitchEvent( TextureStitchEvent.Pre event ) public void onTextureStitchEvent( TextureStitchEvent.Pre event )
{ {
event.getMap().registerSprite( new ResourceLocation( "computercraft", "blocks/craftyUpgrade" ) ); event.getMap().registerSprite( new ResourceLocation( "computercraft", "blocks/crafty_upgrade" ) );
} }
@SubscribeEvent @SubscribeEvent
@@ -147,6 +158,8 @@ public class CCTurtleProxyClient extends CCTurtleProxyCommon
loadModel( event, "advanced_turtle_modem_on_left" ); loadModel( event, "advanced_turtle_modem_on_left" );
loadModel( event, "advanced_turtle_modem_off_right" ); loadModel( event, "advanced_turtle_modem_off_right" );
loadModel( event, "advanced_turtle_modem_on_right" ); loadModel( event, "advanced_turtle_modem_on_right" );
loadModel( event, "turtle_speaker_upgrade_left" );
loadModel( event, "turtle_speaker_upgrade_right" );
loadSmartModel( event, "turtle_dynamic", m_turtleSmartItemModel ); loadSmartModel( event, "turtle_dynamic", m_turtleSmartItemModel );
} }
@@ -158,14 +171,7 @@ public class CCTurtleProxyClient extends CCTurtleProxyCommon
IBakedModel bakedModel = model.bake( IBakedModel bakedModel = model.bake(
model.getDefaultState(), model.getDefaultState(),
DefaultVertexFormats.ITEM, DefaultVertexFormats.ITEM,
new Function<ResourceLocation, TextureAtlasSprite>() location -> Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( location.toString() )
{
@Override
public TextureAtlasSprite apply( ResourceLocation location )
{
return Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( location.toString() );
}
}
); );
event.getModelRegistry().putObject( event.getModelRegistry().putObject(
new ModelResourceLocation( "computercraft:" + name, "inventory" ), new ModelResourceLocation( "computercraft:" + name, "inventory" ),
@@ -181,4 +187,20 @@ public class CCTurtleProxyClient extends CCTurtleProxyCommon
); );
} }
} }
private static class TurtleItemColour implements IItemColor
{
@Override
public int getColorFromItemstack( @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

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -9,175 +9,220 @@ package dan200.computercraft.client.proxy;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.*; import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.shared.computer.blocks.ComputerState;
import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.items.ItemComputer; import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.media.inventory.ContainerHeldItem; import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.network.ComputerCraftPacket; import dan200.computercraft.shared.network.ComputerCraftPacket;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.peripheral.printer.TilePrinter; import dan200.computercraft.shared.peripheral.printer.TilePrinter;
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera; import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera;
import dan200.computercraft.shared.util.Colour;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.ItemMeshDefinition; import net.minecraft.client.renderer.ItemMeshDefinition;
import net.minecraft.client.renderer.block.model.ModelBakery; import net.minecraft.client.renderer.block.model.ModelBakery;
import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.color.IItemColor;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.server.MinecraftServer; import net.minecraft.util.EnumHand;
import net.minecraft.util.IThreadListener;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent; import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.IThreadListener;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderHandEvent; import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.client.event.RenderPlayerEvent; import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.lwjgl.opengl.GL11; import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class ComputerCraftProxyClient extends ComputerCraftProxyCommon public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{ {
private long m_tick; private long m_tick;
private long m_renderFrame; private long m_renderFrame;
private FixedWidthFontRenderer m_fixedWidthFontRenderer; private FixedWidthFontRenderer m_fixedWidthFontRenderer;
public ComputerCraftProxyClient() // IComputerCraftProxy implementation
{
} @Override
public void preInit()
// IComputerCraftProxy implementation {
super.preInit();
@Override m_tick = 0;
public void init()
{
super.init();
m_tick = 0;
m_renderFrame = 0; m_renderFrame = 0;
// Load textures // Setup client forge handlers
Minecraft mc = Minecraft.getMinecraft(); registerForgeHandlers();
m_fixedWidthFontRenderer = new FixedWidthFontRenderer( mc.getTextureManager() ); }
@SubscribeEvent
public void registerModels( ModelRegistryEvent event )
{
// Register item models // Register item models
registerItemModel( ComputerCraft.Blocks.computer, new ItemMeshDefinition() registerItemModel( ComputerCraft.Blocks.computer, new ItemMeshDefinition()
{ {
private ModelResourceLocation computer = new ModelResourceLocation( "computercraft:CC-Computer", "inventory" ); private ModelResourceLocation computer = new ModelResourceLocation( "computercraft:computer", "inventory" );
private ModelResourceLocation advanced_computer = new ModelResourceLocation( "computercraft:advanced_computer", "inventory" ); private ModelResourceLocation advanced_computer = new ModelResourceLocation( "computercraft:advanced_computer", "inventory" );
@Nonnull
@Override @Override
public ModelResourceLocation getModelLocation( ItemStack stack ) public ModelResourceLocation getModelLocation( @Nonnull ItemStack stack )
{ {
ItemComputer itemComputer = (ItemComputer) stack.getItem(); ItemComputer itemComputer = (ItemComputer) stack.getItem();
ComputerFamily family = itemComputer.getFamily( stack.getItemDamage() ); ComputerFamily family = itemComputer.getFamily( stack.getItemDamage() );
return ( family == ComputerFamily.Advanced ) ? advanced_computer : computer; return ( family == ComputerFamily.Advanced ) ? advanced_computer : computer;
} }
}, new String[]{ "CC-Computer", "advanced_computer" } ); }, new String[]{ "computer", "advanced_computer" } );
registerItemModel( ComputerCraft.Blocks.peripheral, 0, "CC-Peripheral" ); registerItemModel( ComputerCraft.Blocks.peripheral, 0, "peripheral" );
registerItemModel( ComputerCraft.Blocks.peripheral, 1, "wireless_modem" ); registerItemModel( ComputerCraft.Blocks.peripheral, 1, "wireless_modem" );
registerItemModel( ComputerCraft.Blocks.peripheral, 2, "monitor" ); registerItemModel( ComputerCraft.Blocks.peripheral, 2, "monitor" );
registerItemModel( ComputerCraft.Blocks.peripheral, 3, "printer" ); registerItemModel( ComputerCraft.Blocks.peripheral, 3, "printer" );
registerItemModel( ComputerCraft.Blocks.peripheral, 4, "advanced_monitor" ); registerItemModel( ComputerCraft.Blocks.peripheral, 4, "advanced_monitor" );
registerItemModel( ComputerCraft.Blocks.cable, 0, "CC-Cable" ); registerItemModel( ComputerCraft.Blocks.cable, 0, "cable" );
registerItemModel( ComputerCraft.Blocks.cable, 1, "wired_modem" ); registerItemModel( ComputerCraft.Blocks.cable, 1, "wired_modem" );
registerItemModel( ComputerCraft.Blocks.commandComputer, "command_computer" ); registerItemModel( ComputerCraft.Blocks.commandComputer, "command_computer" );
registerItemModel( ComputerCraft.Blocks.advancedModem, "advanced_modem" ); registerItemModel( ComputerCraft.Blocks.advancedModem, "advanced_modem" );
registerItemModel( ComputerCraft.Blocks.peripheral, 5, "speaker" );
registerItemModel( ComputerCraft.Items.disk, "disk" ); registerItemModel( ComputerCraft.Items.disk, "disk" );
registerItemModel( ComputerCraft.Items.diskExpanded, "diskExpanded" ); registerItemModel( ComputerCraft.Items.diskExpanded, "disk_expanded" );
registerItemModel( ComputerCraft.Items.treasureDisk, "treasureDisk" ); registerItemModel( ComputerCraft.Items.treasureDisk, "treasure_disk" );
registerItemModel( ComputerCraft.Items.printout, 0, "printout" ); registerItemModel( ComputerCraft.Items.printout, 0, "printout" );
registerItemModel( ComputerCraft.Items.printout, 1, "pages" ); registerItemModel( ComputerCraft.Items.printout, 1, "pages" );
registerItemModel( ComputerCraft.Items.printout, 2, "book" ); registerItemModel( ComputerCraft.Items.printout, 2, "book" );
registerItemModel( ComputerCraft.Items.pocketComputer, new ItemMeshDefinition() registerItemModel( ComputerCraft.Items.pocketComputer, new ItemMeshDefinition()
{ {
private ModelResourceLocation pocket_computer_off = new ModelResourceLocation( "computercraft:pocketComputer", "inventory" ); private ModelResourceLocation pocket_computer_off = new ModelResourceLocation( "computercraft:pocket_computer", "inventory" );
private ModelResourceLocation pocket_computer_on = new ModelResourceLocation( "computercraft:pocket_computer_on", "inventory" ); private ModelResourceLocation pocket_computer_on = new ModelResourceLocation( "computercraft:pocket_computer_on", "inventory" );
private ModelResourceLocation pocket_computer_blinking = new ModelResourceLocation( "computercraft:pocket_computer_blinking", "inventory" ); private ModelResourceLocation pocket_computer_blinking = new ModelResourceLocation( "computercraft:pocket_computer_blinking", "inventory" );
private ModelResourceLocation pocket_computer_on_modem_on = new ModelResourceLocation( "computercraft:pocket_computer_on_modem_on", "inventory" ); private ModelResourceLocation advanced_pocket_computer_off = new ModelResourceLocation( "computercraft:advanced_pocket_computer", "inventory" );
private ModelResourceLocation pocket_computer_blinking_modem_on = new ModelResourceLocation( "computercraft:pocket_computer_blinking_modem_on", "inventory" );
private ModelResourceLocation advanced_pocket_computer_off = new ModelResourceLocation( "computercraft:advanced_pocket_computer_off", "inventory" );
private ModelResourceLocation advanced_pocket_computer_on = new ModelResourceLocation( "computercraft:advanced_pocket_computer_on", "inventory" ); private ModelResourceLocation advanced_pocket_computer_on = new ModelResourceLocation( "computercraft:advanced_pocket_computer_on", "inventory" );
private ModelResourceLocation advanced_pocket_computer_blinking = new ModelResourceLocation( "computercraft:advanced_pocket_computer_blinking", "inventory" ); private ModelResourceLocation advanced_pocket_computer_blinking = new ModelResourceLocation( "computercraft:advanced_pocket_computer_blinking", "inventory" );
private ModelResourceLocation advanced_pocket_computer_on_modem_on = new ModelResourceLocation( "computercraft:advanced_pocket_computer_on_modem_on", "inventory" ); private ModelResourceLocation colour_pocket_computer_off = new ModelResourceLocation( "computercraft:pocket_computer_colour", "inventory" );
private ModelResourceLocation advanced_pocket_computer_blinking_modem_on = new ModelResourceLocation( "computercraft:advanced_pocket_computer_blinking_modem_on", "inventory" ); private ModelResourceLocation colour_pocket_computer_on = new ModelResourceLocation( "computercraft:pocket_computer_colour_on", "inventory" );
private ModelResourceLocation colour_pocket_computer_blinking = new ModelResourceLocation( "computercraft:pocket_computer_colour_blinking", "inventory" );
@Nonnull
@Override @Override
public ModelResourceLocation getModelLocation( ItemStack stack ) public ModelResourceLocation getModelLocation( @Nonnull ItemStack stack )
{ {
ItemPocketComputer itemPocketComputer = (ItemPocketComputer)stack.getItem(); ItemPocketComputer itemPocketComputer = (ItemPocketComputer) stack.getItem();
boolean modemOn = itemPocketComputer.getModemState( stack ); ComputerState state = itemPocketComputer.getState( stack );
switch( itemPocketComputer.getFamily( stack ) ) if( itemPocketComputer.getColour( stack ) == -1 )
{ {
case Advanced: switch( itemPocketComputer.getFamily( stack ) )
{ {
switch( itemPocketComputer.getState( stack ) ) case Advanced:
{ switch( state )
case Off:
default:
{ {
return advanced_pocket_computer_off; case Off:
default:
return advanced_pocket_computer_off;
case On:
return advanced_pocket_computer_on;
case Blinking:
return advanced_pocket_computer_blinking;
} }
case On: case Normal:
default:
switch( state )
{ {
return modemOn ? advanced_pocket_computer_on_modem_on : advanced_pocket_computer_on; case Off:
default:
return pocket_computer_off;
case On:
return pocket_computer_on;
case Blinking:
return pocket_computer_blinking;
} }
case Blinking:
{
return modemOn ? advanced_pocket_computer_blinking_modem_on : advanced_pocket_computer_blinking;
}
}
} }
case Normal: }
default: else
{
switch( state )
{ {
switch( itemPocketComputer.getState( stack ) ) case Off:
{ default:
case Off: return colour_pocket_computer_off;
default: case On:
{ return colour_pocket_computer_on;
return pocket_computer_off; case Blinking:
} return colour_pocket_computer_blinking;
case On:
{
return modemOn ? pocket_computer_on_modem_on : pocket_computer_on;
}
case Blinking:
{
return modemOn ? pocket_computer_blinking_modem_on : pocket_computer_blinking;
}
}
} }
} }
} }
}, new String[] { }, new String[] {
"pocketComputer", "pocket_computer_on", "pocket_computer_blinking", "pocket_computer_on_modem_on", "pocket_computer_blinking_modem_on", "pocket_computer", "pocket_computer_on", "pocket_computer_blinking",
"advanced_pocket_computer_off", "advanced_pocket_computer_on", "advanced_pocket_computer_blinking", "advanced_pocket_computer_on_modem_on", "advanced_pocket_computer_blinking_modem_on", "advanced_pocket_computer", "advanced_pocket_computer_on", "advanced_pocket_computer_blinking",
"pocket_computer_colour", "pocket_computer_colour_on", "pocket_computer_colour_blinking",
} ); } );
}
@Override
public void init()
{
super.init();
// Load textures
Minecraft mc = Minecraft.getMinecraft();
m_fixedWidthFontRenderer = new FixedWidthFontRenderer( mc.getTextureManager() );
// 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 // Setup renderers
ClientRegistry.bindTileEntitySpecialRenderer( TileMonitor.class, new TileEntityMonitorRenderer() ); ClientRegistry.bindTileEntitySpecialRenderer( TileMonitor.class, new TileEntityMonitorRenderer() );
}
// Setup client forge handlers
registerForgeHandlers();
}
private void registerItemModel( Block block, int damage, String name ) private void registerItemModel( Block block, int damage, String name )
{ {
@@ -188,7 +233,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{ {
ModelResourceLocation res = new ModelResourceLocation( "computercraft:" + name, "inventory" ); ModelResourceLocation res = new ModelResourceLocation( "computercraft:" + name, "inventory" );
ModelBakery.registerItemVariants( item, new ResourceLocation( "computercraft", name ) ); ModelBakery.registerItemVariants( item, new ResourceLocation( "computercraft", name ) );
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register( item, damage, res ); ModelLoader.setCustomModelResourceLocation( item, damage, res );
} }
private void registerItemModel( Block block, String name ) private void registerItemModel( Block block, String name )
@@ -200,10 +245,11 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{ {
final ModelResourceLocation res = new ModelResourceLocation( "computercraft:" + name, "inventory" ); final ModelResourceLocation res = new ModelResourceLocation( "computercraft:" + name, "inventory" );
ModelBakery.registerItemVariants( item, new ResourceLocation( "computercraft", name ) ); ModelBakery.registerItemVariants( item, new ResourceLocation( "computercraft", name ) );
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register( item, new ItemMeshDefinition() ModelLoader.setCustomMeshDefinition( item, new ItemMeshDefinition()
{ {
@Nonnull
@Override @Override
public ModelResourceLocation getModelLocation( ItemStack stack ) public ModelResourceLocation getModelLocation( @Nonnull ItemStack stack )
{ {
return res; return res;
} }
@@ -223,20 +269,20 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
resources[i] = new ResourceLocation( "computercraft", names[i] ); resources[i] = new ResourceLocation( "computercraft", names[i] );
} }
ModelBakery.registerItemVariants( item, resources ); ModelBakery.registerItemVariants( item, resources );
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register( item, definition ); ModelLoader.setCustomMeshDefinition( item, definition );
} }
@Override
public boolean isClient()
{
return true;
}
@Override @Override
public boolean getGlobalCursorBlink() public boolean isClient()
{ {
return ( m_tick / 8) % 2 == 0; return true;
} }
@Override
public boolean getGlobalCursorBlink()
{
return ( m_tick / 8) % 2 == 0;
}
@Override @Override
public long getRenderFrame() public long getRenderFrame()
@@ -247,55 +293,55 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
@Override @Override
public void deleteDisplayLists( int list, int range ) public void deleteDisplayLists( int list, int range )
{ {
GL11.glDeleteLists( list, range ); GlStateManager.glDeleteLists( list, range );
} }
@Override @Override
public Object getFixedWidthFontRenderer() public Object getFixedWidthFontRenderer()
{ {
return m_fixedWidthFontRenderer; return m_fixedWidthFontRenderer;
} }
@Override @Override
public String getRecordInfo( ItemStack recordStack ) public String getRecordInfo( @Nonnull ItemStack recordStack )
{ {
List info = new ArrayList(1); List<String> info = new ArrayList<>( 1 );
recordStack.getItem().addInformation( recordStack, null, info, false ); recordStack.getItem().addInformation( recordStack, null, info, ITooltipFlag.TooltipFlags.NORMAL );
if( info.size() > 0 ) { if( info.size() > 0 ) {
return info.get(0).toString(); return info.get( 0 );
} else { } else {
return super.getRecordInfo( recordStack ); return super.getRecordInfo( recordStack );
} }
} }
@Override @Override
public void playRecord( SoundEvent record, String recordInfo, World world, BlockPos pos ) public void playRecord( SoundEvent record, String recordInfo, World world, BlockPos pos )
{ {
Minecraft mc = FMLClientHandler.instance().getClient(); Minecraft mc = FMLClientHandler.instance().getClient();
world.playRecord( pos, record ); world.playRecord( pos, record );
if( record != null ) if( record != null )
{ {
mc.ingameGUI.setRecordPlayingMessage( recordInfo ); mc.ingameGUI.setRecordPlayingMessage( recordInfo );
} }
} }
@Override @Override
public Object getDiskDriveGUI( InventoryPlayer inventory, TileDiskDrive drive ) public Object getDiskDriveGUI( InventoryPlayer inventory, TileDiskDrive drive )
{ {
return new GuiDiskDrive( inventory, drive ); return new GuiDiskDrive( inventory, drive );
} }
@Override @Override
public Object getComputerGUI( TileComputer computer ) public Object getComputerGUI( TileComputer computer )
{ {
return new GuiComputer( computer ); return new GuiComputer( computer );
} }
@Override @Override
public Object getPrinterGUI( InventoryPlayer inventory, TilePrinter printer ) public Object getPrinterGUI( InventoryPlayer inventory, TilePrinter printer )
{ {
return new GuiPrinter( inventory, printer ); return new GuiPrinter( inventory, printer );
} }
@Override @Override
public Object getTurtleGUI( InventoryPlayer inventory, TileTurtle turtle ) public Object getTurtleGUI( InventoryPlayer inventory, TileTurtle turtle )
@@ -304,32 +350,32 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
} }
@Override @Override
public Object getPrintoutGUI( InventoryPlayer inventory ) public Object getPrintoutGUI( EntityPlayer player, EnumHand hand )
{ {
ContainerHeldItem container = new ContainerHeldItem( inventory ); ContainerHeldItem container = new ContainerHeldItem( player, hand );
if( container.getStack() != null && container.getStack().getItem() instanceof ItemPrintout ) if( container.getStack().getItem() instanceof ItemPrintout )
{ {
return new GuiPrintout( container ); return new GuiPrintout( container );
} }
return null; return null;
} }
@Override @Override
public Object getPocketComputerGUI( InventoryPlayer inventory ) public Object getPocketComputerGUI( EntityPlayer player, EnumHand hand )
{ {
ContainerHeldItem container = new ContainerHeldItem( inventory ); ContainerPocketComputer container = new ContainerPocketComputer( player, hand );
if( container.getStack() != null && container.getStack().getItem() instanceof ItemPocketComputer ) if( container.getStack().getItem() instanceof ItemPocketComputer )
{ {
return new GuiPocketComputer( container ); return new GuiPocketComputer( container );
} }
return null; return null;
} }
@Override @Override
public File getWorldDir( World world ) public File getWorldDir( World world )
{ {
return world.getSaveHandler().getWorldDirectory(); return world.getSaveHandler().getWorldDirectory();
} }
@Override @Override
public void handlePacket( final ComputerCraftPacket packet, final EntityPlayer player ) public void handlePacket( final ComputerCraftPacket packet, final EntityPlayer player )
@@ -349,14 +395,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
} }
else else
{ {
listener.addScheduledTask( new Runnable() listener.addScheduledTask( () -> processPacket( packet, player ) );
{
@Override
public void run()
{
processPacket( packet, player );
}
} );
} }
} }
break; break;
@@ -384,7 +423,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{ {
ComputerCraft.clientComputerRegistry.add( instanceID, new ClientComputer( instanceID ) ); ComputerCraft.clientComputerRegistry.add( instanceID, new ClientComputer( instanceID ) );
} }
ComputerCraft.clientComputerRegistry.get( instanceID ).handlePacket( packet, (EntityPlayer) player ); ComputerCraft.clientComputerRegistry.get( instanceID ).handlePacket( packet, player );
break; break;
} }
case ComputerCraftPacket.ComputerDeleted: case ComputerCraftPacket.ComputerDeleted:
@@ -399,18 +438,17 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
} }
} }
private void registerForgeHandlers() private void registerForgeHandlers()
{ {
ForgeHandlers handlers = new ForgeHandlers(); ForgeHandlers handlers = new ForgeHandlers();
FMLCommonHandler.instance().bus().register( handlers );
MinecraftForge.EVENT_BUS.register( handlers ); MinecraftForge.EVENT_BUS.register( handlers );
} }
public class ForgeHandlers public class ForgeHandlers
{ {
public ForgeHandlers() public ForgeHandlers()
{ {
} }
@SubscribeEvent @SubscribeEvent
public void onRenderHand( RenderHandEvent event ) public void onRenderHand( RenderHandEvent event )
@@ -490,5 +528,22 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
m_renderFrame++; m_renderFrame++;
} }
} }
} }
@SideOnly(Side.CLIENT)
private static class DiskColorHandler implements IItemColor
{
private final ItemDiskLegacy disk;
private DiskColorHandler( ItemDiskLegacy disk )
{
this.disk = disk;
}
@Override
public int getColorFromItemstack( @Nonnull ItemStack stack, int layer )
{
return layer == 0 ? 0xFFFFFF : disk.getColour( stack );
}
}
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -11,21 +11,18 @@ import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.common.ClientTerminal; import dan200.computercraft.shared.common.ClientTerminal;
import dan200.computercraft.shared.common.ITerminal;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos;
import net.minecraftforge.client.MinecraftForgeClient;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMonitor> public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMonitor>
@@ -35,7 +32,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
} }
@Override @Override
public void renderTileEntityAt( TileMonitor tileEntity, double posX, double posY, double posZ, float f, int i ) public void render( TileMonitor tileEntity, double posX, double posY, double posZ, float f, int i, float f2 )
{ {
if( tileEntity != null ) if( tileEntity != null )
{ {
@@ -94,7 +91,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
// Get renderers // Get renderers
Minecraft mc = Minecraft.getMinecraft(); Minecraft mc = Minecraft.getMinecraft();
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
VertexBuffer renderer = tessellator.getBuffer(); BufferBuilder renderer = tessellator.getBuffer();
// Get terminal // Get terminal
ClientTerminal clientTerminal = (ClientTerminal)origin.getTerminal(); ClientTerminal clientTerminal = (ClientTerminal)origin.getTerminal();
@@ -104,14 +101,17 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
// Draw the contents // Draw the contents
GlStateManager.depthMask( false ); GlStateManager.depthMask( false );
GlStateManager.disableLighting(); GlStateManager.disableLighting();
mc.entityRenderer.disableLightmap();
try try
{ {
if( terminal != null ) if( terminal != null )
{ {
Palette palette = terminal.getPalette();
// Allocate display lists // Allocate display lists
if( origin.m_renderDisplayList < 0 ) if( origin.m_renderDisplayList < 0 )
{ {
origin.m_renderDisplayList = GL11.glGenLists( 3 ); origin.m_renderDisplayList = GlStateManager.glGenLists( 3 );
redraw = true; redraw = true;
} }
@@ -135,7 +135,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
if( redraw ) if( redraw )
{ {
// Build background display list // Build background display list
GL11.glNewList( origin.m_renderDisplayList, GL11.GL_COMPILE ); GlStateManager.glNewList( origin.m_renderDisplayList, GL11.GL_COMPILE );
try try
{ {
double marginXSize = TileMonitor.RENDER_MARGIN / xScale; double marginXSize = TileMonitor.RENDER_MARGIN / xScale;
@@ -143,18 +143,18 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
double marginSquash = marginYSize / (double) FixedWidthFontRenderer.FONT_HEIGHT; double marginSquash = marginYSize / (double) FixedWidthFontRenderer.FONT_HEIGHT;
// Top and bottom margins // Top and bottom margins
GL11.glPushMatrix(); GlStateManager.pushMatrix();
try try
{ {
GL11.glScaled( 1.0, marginSquash, 1.0 ); GlStateManager.scale( 1.0, marginSquash, 1.0 );
GL11.glTranslated( 0.0, -marginYSize / marginSquash, 0.0 ); GlStateManager.translate( 0.0, -marginYSize / marginSquash, 0.0 );
fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( 0 ), marginXSize, marginXSize, greyscale ); fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( 0 ), marginXSize, marginXSize, greyscale, palette );
GL11.glTranslated( 0.0, ( marginYSize + height * FixedWidthFontRenderer.FONT_HEIGHT ) / marginSquash, 0.0 ); GlStateManager.translate( 0.0, ( marginYSize + height * FixedWidthFontRenderer.FONT_HEIGHT ) / marginSquash, 0.0 );
fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( height - 1 ), marginXSize, marginXSize, greyscale ); fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( height - 1 ), marginXSize, marginXSize, greyscale, palette );
} }
finally finally
{ {
GL11.glPopMatrix(); GlStateManager.popMatrix();
} }
// Backgrounds // Backgrounds
@@ -164,23 +164,25 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
0, FixedWidthFontRenderer.FONT_HEIGHT * y, 0, FixedWidthFontRenderer.FONT_HEIGHT * y,
terminal.getBackgroundColourLine( y ), terminal.getBackgroundColourLine( y ),
marginXSize, marginXSize, marginXSize, marginXSize,
greyscale greyscale,
palette
); );
} }
} }
finally finally
{ {
GL11.glEndList(); GlStateManager.glEndList();
} }
} }
GlStateManager.callList( origin.m_renderDisplayList ); GlStateManager.callList( origin.m_renderDisplayList );
GlStateManager.resetColor();
// Draw text // Draw text
mc.getTextureManager().bindTexture( FixedWidthFontRenderer.font ); fontRenderer.bindFont();
if( redraw ) if( redraw )
{ {
// Build text display list // Build text display list
GL11.glNewList( origin.m_renderDisplayList + 1, GL11.GL_COMPILE ); GlStateManager.glNewList( origin.m_renderDisplayList + 1, GL11.GL_COMPILE );
try try
{ {
// Lines // Lines
@@ -190,23 +192,25 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
0, FixedWidthFontRenderer.FONT_HEIGHT * y, 0, FixedWidthFontRenderer.FONT_HEIGHT * y,
terminal.getLine( y ), terminal.getLine( y ),
terminal.getTextColourLine( y ), terminal.getTextColourLine( y ),
greyscale greyscale,
palette
); );
} }
} }
finally finally
{ {
GL11.glEndList(); GlStateManager.glEndList();
} }
} }
GlStateManager.callList( origin.m_renderDisplayList + 1 ); GlStateManager.callList( origin.m_renderDisplayList + 1 );
GlStateManager.resetColor();
// Draw cursor // Draw cursor
mc.getTextureManager().bindTexture( FixedWidthFontRenderer.font ); fontRenderer.bindFont();
if( redraw ) if( redraw )
{ {
// Build cursor display list // Build cursor display list
GL11.glNewList( origin.m_renderDisplayList + 2, GL11.GL_COMPILE ); GlStateManager.glNewList( origin.m_renderDisplayList + 2, GL11.GL_COMPILE );
try try
{ {
// Cursor // Cursor
@@ -220,18 +224,20 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
FixedWidthFontRenderer.FONT_HEIGHT * cursorY, FixedWidthFontRenderer.FONT_HEIGHT * cursorY,
cursorColour, null, cursorColour, null,
0, 0, 0, 0,
greyscale greyscale,
palette
); );
} }
} }
finally finally
{ {
GL11.glEndList(); GlStateManager.glEndList();
} }
} }
if( ComputerCraft.getGlobalCursorBlink() ) if( ComputerCraft.getGlobalCursorBlink() )
{ {
GlStateManager.callList( origin.m_renderDisplayList + 2 ); GlStateManager.callList( origin.m_renderDisplayList + 2 );
GlStateManager.resetColor();
} }
} }
finally finally
@@ -243,19 +249,24 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
{ {
// Draw a big black quad // Draw a big black quad
mc.getTextureManager().bindTexture( FixedWidthFontRenderer.background ); mc.getTextureManager().bindTexture( FixedWidthFontRenderer.background );
renderer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR ); final Colour colour = Colour.Black;
Colour colour = Colour.Black;
renderer.pos( -TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 0.0, 1.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); final float r = colour.getR();
renderer.pos( xSize + TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 1.0, 1.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); final float g = colour.getG();
renderer.pos( xSize + TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0D ).tex( 1.0, 0.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); final float b = colour.getB();
renderer.pos( -TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0D ).tex( 0.0, 0.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex();
renderer.pos( -TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 0.0, 1.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); renderer.begin( GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR );
renderer.pos( -TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0D ).tex( 0.0, 0.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( -TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 0.0, 1.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( xSize + TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0D ).tex( 1.0, 0.0 ).color( r, g, b, 1.0f ).endVertex();
renderer.pos( xSize + TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 1.0, 1.0 ).color( r, g, b, 1.0f ).endVertex();
tessellator.draw(); tessellator.draw();
} }
} }
finally finally
{ {
GlStateManager.depthMask( true ); GlStateManager.depthMask( true );
mc.entityRenderer.enableLightmap();
GlStateManager.enableLighting(); GlStateManager.enableLighting();
} }
@@ -264,13 +275,11 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
try try
{ {
mc.getTextureManager().bindTexture( FixedWidthFontRenderer.background ); mc.getTextureManager().bindTexture( FixedWidthFontRenderer.background );
renderer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR ); renderer.begin( GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION );
Colour colour = Colour.Black; renderer.pos( -TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0 ).endVertex();
renderer.pos( -TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 0.0, 1.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); renderer.pos( -TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).endVertex();
renderer.pos( xSize + TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 1.0, 1.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); renderer.pos( xSize + TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0 ).endVertex();
renderer.pos( xSize + TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0D ).tex( 1.0, 0.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex(); renderer.pos( xSize + TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).endVertex();
renderer.pos( -TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0D ).tex( 0.0, 0.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex();
renderer.pos( -TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 0.0, 1.0 ).color( colour.getR(), colour.getG(), colour.getB(), 1.0f ).endVertex();
tessellator.draw(); tessellator.draw();
} }
finally finally

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -12,76 +12,44 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera; import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil; import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.block.model.BakedQuad; 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.ModelManager;
import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.*; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.*; 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.ForgeHooksClient;
import net.minecraftforge.client.model.pipeline.LightUtil;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import javax.vecmath.Matrix4f; import javax.vecmath.Matrix4f;
import java.util.Iterator;
import java.util.List; import java.util.List;
public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurtle> public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurtle>
{ {
private static ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation( "computercraft:CC-Turtle", "inventory" ); private static ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle", "inventory" );
private static ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation( "computercraft:CC-TurtleAdvanced", "inventory" ); private static ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_advanced", "inventory" );
private static ModelResourceLocation[] COLOUR_TURTLE_MODELS = new ModelResourceLocation[] { private static ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_white", "inventory" );
new ModelResourceLocation( "computercraft:turtle_black", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_red", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_green", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_brown", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_blue", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_purple", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_cyan", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_lightGrey", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_grey", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_pink", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_lime", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_yellow", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_lightBlue", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_magenta", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_orange", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_white", "inventory" ),
};
private static ModelResourceLocation BEGINNER_TURTLE_MODEL = new ModelResourceLocation( "computercraftedu:CC-TurtleJunior", "inventory" ); private static ModelResourceLocation BEGINNER_TURTLE_MODEL = new ModelResourceLocation( "computercraftedu:CC-TurtleJunior", "inventory" );
private static ModelResourceLocation[] BEGINNER_TURTLE_COLOUR_MODELS = new ModelResourceLocation[] { private static ModelResourceLocation BEGINNER_TURTLE_COLOUR_MODEL = new ModelResourceLocation( "computercraftedu:turtleJunior_white", "inventory" );
new ModelResourceLocation( "computercraftedu:turtleJunior_black", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_red", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_green", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_brown", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_blue", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_purple", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_cyan", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_lightGrey", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_grey", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_pink", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_lime", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_yellow", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_lightBlue", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_magenta", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_orange", "inventory" ),
new ModelResourceLocation( "computercraftedu:turtleJunior_white", "inventory" ),
};
private static ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" ); private static ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" );
public TileEntityTurtleRenderer() public TileEntityTurtleRenderer()
@@ -89,7 +57,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
} }
@Override @Override
public void renderTileEntityAt( TileTurtle tileEntity, double posX, double posY, double posZ, float f, int i ) public void render( TileTurtle tileEntity, double posX, double posY, double posZ, float f, int i, float f2 )
{ {
if( tileEntity != null ) if( tileEntity != null )
{ {
@@ -97,7 +65,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
Entity viewEntity = Minecraft.getMinecraft().getRenderViewEntity(); Entity viewEntity = Minecraft.getMinecraft().getRenderViewEntity();
if( viewEntity != null && viewEntity instanceof TurtleVisionCamera ) if( viewEntity != null && viewEntity instanceof TurtleVisionCamera )
{ {
TurtleVisionCamera camera = (TurtleVisionCamera)viewEntity; TurtleVisionCamera camera = (TurtleVisionCamera) viewEntity;
if( camera.getTurtle() == tileEntity.getAccess() ) if( camera.getTurtle() == tileEntity.getAccess() )
{ {
return; return;
@@ -109,44 +77,17 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
} }
} }
public static ModelResourceLocation getTurtleModel( ComputerFamily family, Colour colour ) public static ModelResourceLocation getTurtleModel( ComputerFamily family, boolean coloured )
{ {
switch( family ) switch( family )
{ {
case Normal: case Normal:
default: default:
{ return coloured ? COLOUR_TURTLE_MODEL : NORMAL_TURTLE_MODEL;
if( colour != null )
{
return COLOUR_TURTLE_MODELS[ colour.ordinal() ];
}
else
{
return NORMAL_TURTLE_MODEL;
}
}
case Advanced: case Advanced:
{ return coloured ? COLOUR_TURTLE_MODEL : ADVANCED_TURTLE_MODEL;
if( colour != null )
{
return COLOUR_TURTLE_MODELS[ colour.ordinal() ];
}
else
{
return ADVANCED_TURTLE_MODEL;
}
}
case Beginners: case Beginners:
{ return coloured ? BEGINNER_TURTLE_COLOUR_MODEL : BEGINNER_TURTLE_MODEL;
if( colour != null )
{
return BEGINNER_TURTLE_COLOUR_MODELS[ colour.ordinal() ];
}
else
{
return BEGINNER_TURTLE_MODEL;
}
}
} }
} }
@@ -185,7 +126,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
offset = new Vec3d( 0.0, 0.0, 0.0 ); offset = new Vec3d( 0.0, 0.0, 0.0 );
yaw = 0.0f; yaw = 0.0f;
} }
GlStateManager.translate( posX + offset.xCoord, posY + offset.yCoord, posZ + offset.zCoord ); GlStateManager.translate( posX + offset.x, posY + offset.y, posZ + offset.z );
// Render the label // Render the label
IComputer computer = (turtle != null) ? turtle.getComputer() : null; IComputer computer = (turtle != null) ? turtle.getComputer() : null;
@@ -201,7 +142,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
GlStateManager.translate( -0.5f, 0.0f, -0.5f ); GlStateManager.translate( -0.5f, 0.0f, -0.5f );
// Render the turtle // Render the turtle
Colour colour; int colour;
ComputerFamily family; ComputerFamily family;
ResourceLocation overlay; ResourceLocation overlay;
if( turtle != null ) if( turtle != null )
@@ -212,11 +153,12 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
} }
else else
{ {
colour = null; colour = -1;
family = ComputerFamily.Normal; family = ComputerFamily.Normal;
overlay = null; overlay = null;
} }
renderModel( state, getTurtleModel( family, colour ) );
renderModel( state, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } );
// Render the overlay // Render the overlay
ModelResourceLocation overlayModel = getTurtleOverlayModel( ModelResourceLocation overlayModel = getTurtleOverlayModel(
@@ -231,7 +173,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
GlStateManager.blendFunc( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA ); GlStateManager.blendFunc( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA );
try try
{ {
renderModel( state, overlayModel ); renderModel( state, overlayModel, null );
} }
finally finally
{ {
@@ -275,7 +217,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
} }
if( pair.getLeft() != null ) if( pair.getLeft() != null )
{ {
renderModel( state, pair.getLeft() ); renderModel( state, pair.getLeft(), null );
} }
} }
} }
@@ -286,35 +228,32 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
} }
} }
private void renderModel( IBlockState state, ModelResourceLocation modelLocation ) private void renderModel( IBlockState state, ModelResourceLocation modelLocation, int[] tints )
{ {
Minecraft mc = Minecraft.getMinecraft(); Minecraft mc = Minecraft.getMinecraft();
ModelManager modelManager = mc.getRenderItem().getItemModelMesher().getModelManager(); ModelManager modelManager = mc.getRenderItem().getItemModelMesher().getModelManager();
renderModel( state, modelManager.getModel( modelLocation ) ); renderModel( state, modelManager.getModel( modelLocation ), tints );
} }
private void renderModel( IBlockState state, IBakedModel model ) private void renderModel( IBlockState state, IBakedModel model, int[] tints )
{ {
Minecraft mc = Minecraft.getMinecraft(); Minecraft mc = Minecraft.getMinecraft();
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
mc.getTextureManager().bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ); mc.getTextureManager().bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
renderQuads( tessellator, model.getQuads( state, null, 0 ) ); renderQuads( tessellator, model.getQuads( state, null, 0 ), tints );
for( EnumFacing facing : EnumFacing.VALUES ) for( EnumFacing facing : EnumFacing.VALUES )
{ {
renderQuads( tessellator, model.getQuads( state, facing, 0 ) ); renderQuads( tessellator, model.getQuads( state, facing, 0 ), tints );
} }
} }
private void renderQuads( Tessellator tessellator, List quads ) private void renderQuads( Tessellator tessellator, List<BakedQuad> quads, int[] tints )
{ {
int color = 0xFFFFFFFF; BufferBuilder buffer = tessellator.getBuffer();
Iterator it = quads.iterator();
VertexBuffer buffer = tessellator.getBuffer();
VertexFormat format = DefaultVertexFormats.ITEM; VertexFormat format = DefaultVertexFormats.ITEM;
buffer.begin( GL11.GL_QUADS, format ); buffer.begin( GL11.GL_QUADS, format );
while( it.hasNext() ) for (BakedQuad quad : quads)
{ {
BakedQuad quad = (BakedQuad)it.next();
VertexFormat quadFormat = quad.getFormat(); VertexFormat quadFormat = quad.getFormat();
if( quadFormat != format ) if( quadFormat != format )
{ {
@@ -322,7 +261,15 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
format = quadFormat; format = quadFormat;
buffer.begin( GL11.GL_QUADS, format ); buffer.begin( GL11.GL_QUADS, format );
} }
net.minecraftforge.client.model.pipeline.LightUtil.renderQuadColor( buffer, quad, color );
int colour = 0xFFFFFFFF;
if( quad.hasTintIndex() && tints != null )
{
int index = quad.getTintIndex();
if( index >= 0 && index < tints.length ) colour = tints[ index ] | 0xFF000000;
}
LightUtil.renderQuadColor( buffer, quad, colour );
} }
tessellator.draw(); tessellator.draw();
} }
@@ -361,7 +308,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
try try
{ {
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
VertexBuffer renderer = tessellator.getBuffer(); BufferBuilder renderer = tessellator.getBuffer();
renderer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR ); renderer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR );
renderer.pos( (double) ( -xOffset - 1 ), (double) ( -1 + yOffset ), 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex(); renderer.pos( (double) ( -xOffset - 1 ), (double) ( -1 + yOffset ), 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex();
renderer.pos( (double) ( -xOffset - 1 ), (double) ( 8 + yOffset ), 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex(); renderer.pos( (double) ( -xOffset - 1 ), (double) ( 8 + yOffset ), 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex();

View File

@@ -1,22 +1,22 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.*; import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.block.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement; import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.vecmath.Matrix4f; import javax.vecmath.Matrix4f;
import javax.vecmath.Point3f; import javax.vecmath.Point3f;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Dictionary; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
public class TurtleMultiModel implements IBakedModel public class TurtleMultiModel implements IBakedModel
{ {
@@ -27,7 +27,7 @@ public class TurtleMultiModel implements IBakedModel
private IBakedModel m_rightUpgradeModel; private IBakedModel m_rightUpgradeModel;
private Matrix4f m_rightUpgradeTransform; private Matrix4f m_rightUpgradeTransform;
private List<BakedQuad> m_generalQuads; private List<BakedQuad> m_generalQuads;
private List<BakedQuad> m_faceQuads[]; private Map<EnumFacing, List<BakedQuad>> m_faceQuads;
public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, IBakedModel leftUpgradeModel, Matrix4f leftUpgradeTransform, IBakedModel rightUpgradeModel, Matrix4f rightUpgradeTransform ) public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, IBakedModel leftUpgradeModel, Matrix4f leftUpgradeTransform, IBakedModel rightUpgradeModel, Matrix4f rightUpgradeTransform )
{ {
@@ -39,17 +39,18 @@ public class TurtleMultiModel implements IBakedModel
m_rightUpgradeModel = rightUpgradeModel; m_rightUpgradeModel = rightUpgradeModel;
m_rightUpgradeTransform = rightUpgradeTransform; m_rightUpgradeTransform = rightUpgradeTransform;
m_generalQuads = null; m_generalQuads = null;
m_faceQuads = new List[6]; m_faceQuads = new HashMap<>();
} }
@Nonnull
@Override @Override
public List<BakedQuad> getQuads( IBlockState state, EnumFacing side, long rand ) public List<BakedQuad> getQuads( IBlockState state, EnumFacing side, long rand )
{ {
if( side != null ) if( side != null )
{ {
if( m_faceQuads[ side.ordinal() ] == null ) if( !m_faceQuads.containsKey( side ) )
{ {
List<BakedQuad> quads = new ArrayList<BakedQuad>(); ArrayList<BakedQuad> quads = new ArrayList<>();
if( m_overlayModel != null ) if( m_overlayModel != null )
{ {
quads.addAll( m_overlayModel.getQuads( state, side, rand ) ); quads.addAll( m_overlayModel.getQuads( state, side, rand ) );
@@ -62,28 +63,31 @@ public class TurtleMultiModel implements IBakedModel
{ {
quads.addAll( transformQuads( m_rightUpgradeModel.getQuads( state, side, rand ), m_rightUpgradeTransform ) ); quads.addAll( transformQuads( m_rightUpgradeModel.getQuads( state, side, rand ), m_rightUpgradeTransform ) );
} }
m_faceQuads[ side.ordinal() ] = quads; quads.trimToSize();
m_faceQuads.put( side, quads );
} }
return m_faceQuads[ side.ordinal() ]; return m_faceQuads.get( side );
} }
else else
{ {
if( m_generalQuads == null ) if( m_generalQuads == null )
{ {
m_generalQuads = new ArrayList<BakedQuad>(); ArrayList<BakedQuad> quads = new ArrayList<>();
m_generalQuads.addAll( m_baseModel.getQuads( state, side, rand ) ); quads.addAll( m_baseModel.getQuads( state, side, rand ) );
if( m_overlayModel != null ) if( m_overlayModel != null )
{ {
m_generalQuads.addAll( m_overlayModel.getQuads( state, side, rand ) ); quads.addAll( m_overlayModel.getQuads( state, side, rand ) );
} }
if( m_leftUpgradeModel != null ) if( m_leftUpgradeModel != null )
{ {
m_generalQuads.addAll( transformQuads( m_leftUpgradeModel.getQuads( state, side, rand ), m_leftUpgradeTransform ) ); quads.addAll( transformQuads( m_leftUpgradeModel.getQuads( state, side, rand ), m_leftUpgradeTransform ) );
} }
if( m_rightUpgradeModel != null ) if( m_rightUpgradeModel != null )
{ {
m_generalQuads.addAll( transformQuads( m_rightUpgradeModel.getQuads( state, side, rand ), m_rightUpgradeTransform ) ); quads.addAll( transformQuads( m_rightUpgradeModel.getQuads( state, side, rand ), m_rightUpgradeTransform ) );
} }
quads.trimToSize();
m_generalQuads = quads;
} }
return m_generalQuads; return m_generalQuads;
} }
@@ -107,18 +111,22 @@ public class TurtleMultiModel implements IBakedModel
return m_baseModel.isBuiltInRenderer(); return m_baseModel.isBuiltInRenderer();
} }
@Nonnull
@Override @Override
public TextureAtlasSprite getParticleTexture() public TextureAtlasSprite getParticleTexture()
{ {
return m_baseModel.getParticleTexture(); return m_baseModel.getParticleTexture();
} }
@Nonnull
@Override @Override
@Deprecated
public ItemCameraTransforms getItemCameraTransforms() public ItemCameraTransforms getItemCameraTransforms()
{ {
return m_baseModel.getItemCameraTransforms(); return m_baseModel.getItemCameraTransforms();
} }
@Nonnull
@Override @Override
public ItemOverrideList getOverrides() public ItemOverrideList getOverrides()
{ {
@@ -133,10 +141,9 @@ public class TurtleMultiModel implements IBakedModel
} }
else else
{ {
List<BakedQuad> output = new ArrayList<BakedQuad>( input.size() ); List<BakedQuad> output = new ArrayList<>( input.size() );
for( int i=0; i<input.size(); ++i ) for( BakedQuad quad : input )
{ {
BakedQuad quad = input.get( i );
output.add( transformQuad( quad, transform ) ); output.add( transformQuad( quad, transform ) );
} }
return output; return output;
@@ -147,7 +154,7 @@ public class TurtleMultiModel implements IBakedModel
{ {
int[] vertexData = quad.getVertexData().clone(); int[] vertexData = quad.getVertexData().clone();
int offset = 0; int offset = 0;
BakedQuad copy = new BakedQuad( vertexData, quad.getTintIndex(), quad.getFace(), quad.getSprite(), quad.shouldApplyDiffuseLighting(), quad.getFormat() ); BakedQuad copy = new BakedQuad( vertexData, -1, quad.getFace(), quad.getSprite(), quad.shouldApplyDiffuseLighting(), quad.getFormat() );
VertexFormat format = copy.getFormat(); VertexFormat format = copy.getFormat();
for( int i=0; i<format.getElementCount(); ++i ) // For each vertex element for( int i=0; i<format.getElementCount(); ++i ) // For each vertex element
{ {

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -11,8 +11,6 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.turtle.items.ItemTurtleBase; import dan200.computercraft.shared.turtle.items.ItemTurtleBase;
import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil; import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
@@ -26,10 +24,10 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ISmartVariant;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.vecmath.Matrix4f; import javax.vecmath.Matrix4f;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -40,13 +38,13 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
private static class TurtleModelCombination private static class TurtleModelCombination
{ {
public final ComputerFamily m_family; public final ComputerFamily m_family;
public final Colour m_colour; public final boolean m_colour;
public final ITurtleUpgrade m_leftUpgrade; public final ITurtleUpgrade m_leftUpgrade;
public final ITurtleUpgrade m_rightUpgrade; public final ITurtleUpgrade m_rightUpgrade;
public final ResourceLocation m_overlay; public final ResourceLocation m_overlay;
public final boolean m_christmas; public final boolean m_christmas;
public TurtleModelCombination( ComputerFamily family, Colour colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas ) public TurtleModelCombination( ComputerFamily family, boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas )
{ {
m_family = family; m_family = family;
m_colour = colour; m_colour = colour;
@@ -83,7 +81,7 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + m_family.hashCode(); result = prime * result + m_family.hashCode();
result = prime * result + (m_colour != null ? m_colour.hashCode() : 0); result = prime * result + (m_colour ? 1 : 0);
result = prime * result + (m_leftUpgrade != null ? m_leftUpgrade.hashCode() : 0); result = prime * result + (m_leftUpgrade != null ? m_leftUpgrade.hashCode() : 0);
result = prime * result + (m_rightUpgrade != null ? m_rightUpgrade.hashCode() : 0); result = prime * result + (m_rightUpgrade != null ? m_rightUpgrade.hashCode() : 0);
result = prime * result + (m_overlay != null ? m_overlay.hashCode() : 0); result = prime * result + (m_overlay != null ? m_overlay.hashCode() : 0);
@@ -91,28 +89,29 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
return result; return result;
} }
} }
private ItemStack m_defaultItem;
private HashMap<TurtleModelCombination, IBakedModel> m_cachedModels; private HashMap<TurtleModelCombination, IBakedModel> m_cachedModels;
private ItemOverrideList m_overrides; private ItemOverrideList m_overrides;
private final TurtleModelCombination m_defaultCombination;
public TurtleSmartItemModel() public TurtleSmartItemModel()
{ {
m_defaultItem = TurtleItemFactory.create( -1, null, null, ComputerFamily.Normal, null, null, 0, null ); m_cachedModels = new HashMap<>();
m_cachedModels = new HashMap<TurtleModelCombination, IBakedModel>(); m_defaultCombination = new TurtleModelCombination( ComputerFamily.Normal, false, null, null, null, false );
m_overrides = new ItemOverrideList( new ArrayList<ItemOverride>() ) m_overrides = new ItemOverrideList( new ArrayList<>() )
{ {
@Nonnull
@Override @Override
public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world, EntityLivingBase entity) public IBakedModel handleItemState( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity)
{ {
ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem(); ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem();
ComputerFamily family = turtle.getFamily( stack ); ComputerFamily family = turtle.getFamily( stack );
Colour colour = turtle.getColour( stack ); int colour = turtle.getColour( stack );
ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.Left ); ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.Left );
ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.Right ); ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.Right );
ResourceLocation overlay = turtle.getOverlay( stack ); ResourceLocation overlay = turtle.getOverlay( stack );
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.Christmas; boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.Christmas;
TurtleModelCombination combo = new TurtleModelCombination( family, colour, leftUpgrade, rightUpgrade, overlay, christmas ); TurtleModelCombination combo = new TurtleModelCombination( family, colour != -1, leftUpgrade, rightUpgrade, overlay, christmas );
if( m_cachedModels.containsKey( combo ) ) if( m_cachedModels.containsKey( combo ) )
{ {
return m_cachedModels.get( combo ); return m_cachedModels.get( combo );
@@ -127,6 +126,7 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
}; };
} }
@Nonnull
@Override @Override
public ItemOverrideList getOverrides() public ItemOverrideList getOverrides()
{ {
@@ -134,7 +134,7 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
} }
@Override @Override
public void onResourceManagerReload( IResourceManager resourceManager ) public void onResourceManagerReload( @Nonnull IResourceManager resourceManager )
{ {
m_cachedModels.clear(); m_cachedModels.clear();
} }
@@ -173,6 +173,7 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
// These should not be called: // These should not be called:
@Nonnull
@Override @Override
public List<BakedQuad> getQuads( IBlockState state, EnumFacing facing, long rand ) public List<BakedQuad> getQuads( IBlockState state, EnumFacing facing, long rand )
{ {
@@ -197,13 +198,16 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
return getDefaultModel().isBuiltInRenderer(); return getDefaultModel().isBuiltInRenderer();
} }
@Nonnull
@Override @Override
public TextureAtlasSprite getParticleTexture() public TextureAtlasSprite getParticleTexture()
{ {
return getDefaultModel().getParticleTexture(); return getDefaultModel().getParticleTexture();
} }
@Nonnull
@Override @Override
@Deprecated
public ItemCameraTransforms getItemCameraTransforms() public ItemCameraTransforms getItemCameraTransforms()
{ {
return getDefaultModel().getItemCameraTransforms(); return getDefaultModel().getItemCameraTransforms();
@@ -211,6 +215,13 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
private IBakedModel getDefaultModel() private IBakedModel getDefaultModel()
{ {
return m_overrides.handleItemState( this, m_defaultItem, null, null ); IBakedModel model = m_cachedModels.get( m_defaultCombination );
if( model == null )
{
model = buildModel( m_defaultCombination );
m_cachedModels.put( m_defaultCombination, model );
}
return model;
} }
} }

View File

@@ -0,0 +1,168 @@
package dan200.computercraft.core.apis;
import com.google.common.net.InetAddresses;
import dan200.computercraft.ComputerCraft;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* Used to determine whether a domain or IP address matches a series of patterns.
*/
public class AddressPredicate
{
private static class HostRange
{
private final byte[] min;
private final byte[] max;
private HostRange( byte[] min, byte[] max )
{
this.min = min;
this.max = max;
}
public boolean contains( InetAddress address )
{
byte[] entry = address.getAddress();
if( entry.length != min.length ) return false;
for( int i = 0; i < entry.length; i++ )
{
int value = 0xFF & entry[ i ];
if( value < (0xFF & min[ i ]) || value > (0xFF & max[ i ]) ) return false;
}
return true;
}
}
private final List<Pattern> wildcards;
private final List<HostRange> ranges;
public AddressPredicate( String... filters )
{
List<Pattern> wildcards = this.wildcards = new ArrayList<Pattern>();
List<HostRange> ranges = this.ranges = new ArrayList<HostRange>();
for( String filter : filters )
{
int cidr = filter.indexOf( '/' );
if( cidr >= 0 )
{
String addressStr = filter.substring( 0, cidr );
String prefixSizeStr = filter.substring( cidr + 1 );
int prefixSize;
try
{
prefixSize = Integer.parseInt( prefixSizeStr );
}
catch( NumberFormatException e )
{
ComputerCraft.log.warn( "Cannot parse CIDR size from {} ({})", filter, prefixSizeStr );
continue;
}
InetAddress address;
try
{
address = InetAddresses.forString( addressStr );
}
catch( IllegalArgumentException e )
{
ComputerCraft.log.warn( "Cannot parse IP address from {} ({})", filter, addressStr );
continue;
}
// Mask the bytes of the IP address.
byte[] minBytes = address.getAddress(), maxBytes = address.getAddress();
int size = prefixSize;
for( int i = 0; i < minBytes.length; i++ )
{
if( size <= 0 )
{
minBytes[ i ] &= 0;
maxBytes[ i ] |= 0xFF;
}
else if( size < 8 )
{
minBytes[ i ] &= 0xFF << (8 - size);
maxBytes[ i ] |= ~(0xFF << (8 - size));
}
size -= 8;
}
ranges.add( new HostRange( minBytes, maxBytes ) );
}
else
{
wildcards.add( Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" ) );
}
}
}
/**
* Determine whether a host name matches a series of patterns.
*
* This is intended to allow early exiting, before one has to look up the IP address. You should use
* {@link #matches(InetAddress)} instead of/in addition to this one.
*
* @param domain The domain to match.
* @return Whether the patterns were matched.
*/
public boolean matches( String domain )
{
for( Pattern domainPattern : wildcards )
{
if( domainPattern.matcher( domain ).matches() ) return true;
}
return false;
}
private boolean matchesAddress( InetAddress address )
{
String addressString = address.getHostAddress();
for( Pattern domainPattern : wildcards )
{
if( domainPattern.matcher( addressString ).matches() ) return true;
}
for( HostRange range : ranges )
{
if( range.contains( address ) ) return true;
}
return false;
}
/**
* Determine whether the given address matches a series of patterns
*
* @param address The address to check.
* @return Whether it matches any of these patterns.
*/
public boolean matches( InetAddress address )
{
// Match the host name
String host = address.getHostName();
if( host != null && matches( host ) ) return true;
// Match the normal address
if( matchesAddress( address ) ) return true;
// If we're an IPv4 address in disguise then let's check that.
if( address instanceof Inet6Address && InetAddresses.is6to4Address( (Inet6Address) address )
&& matchesAddress( InetAddresses.get6to4IPv4Address( (Inet6Address) address ) ) )
{
return true;
}
return false;
}
}

View File

@@ -0,0 +1,246 @@
package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
/**
* Various helpers for arguments
*/
public final class ArgumentHelper
{
private ArgumentHelper()
{
throw new IllegalStateException( "Cannot instantiate singleton " + getClass().getName() );
}
@Nonnull
public static String getType( @Nullable Object type )
{
if( type == null ) return "nil";
if( type instanceof String ) return "string";
if( type instanceof Boolean ) return "boolean";
if( type instanceof Number ) return "number";
if( type instanceof Map ) return "table";
Class<?> klass = type.getClass();
if( klass.isArray() )
{
StringBuilder name = new StringBuilder();
while( klass.isArray() )
{
name.append( "[]" );
klass = klass.getComponentType();
}
name.insert( 0, klass.getName() );
return name.toString();
}
else
{
return klass.getName();
}
}
@Nonnull
public static LuaException badArgument( int index, @Nonnull String expected, @Nullable Object actual )
{
return badArgument( index, expected, getType( actual ) );
}
@Nonnull
public static LuaException badArgument( int index, @Nonnull String expected, @Nonnull String actual )
{
return new LuaException( "bad argument #" + (index + 1) + " (" + expected + " expected, got " + actual + ")" );
}
public static double getNumber( @Nonnull Object[] args, int index ) throws LuaException
{
if( index >= args.length ) throw badArgument( index, "number", "nil" );
Object value = args[ index ];
if( value instanceof Number )
{
return ((Number) value).doubleValue();
}
else
{
throw badArgument( index, "number", value );
}
}
public static int getInt( @Nonnull Object[] args, int index ) throws LuaException
{
if( index >= args.length ) throw badArgument( index, "number", "nil" );
Object value = args[ index ];
if( value instanceof Number )
{
return (int) ((Number) value).longValue();
}
else
{
throw badArgument( index, "number", value );
}
}
public static double getReal( @Nonnull Object[] args, int index ) throws LuaException
{
return checkReal( index, getNumber( args, index ) );
}
public static boolean getBoolean( @Nonnull Object[] args, int index ) throws LuaException
{
if( index >= args.length ) throw badArgument( index, "boolean", "nil" );
Object value = args[ index ];
if( value instanceof Boolean )
{
return (Boolean) value;
}
else
{
throw badArgument( index, "boolean", value );
}
}
@Nonnull
public static String getString( @Nonnull Object[] args, int index ) throws LuaException
{
if( index >= args.length ) throw badArgument( index, "string", "nil" );
Object value = args[ index ];
if( value instanceof String )
{
return (String) value;
}
else
{
throw badArgument( index, "string", value );
}
}
@SuppressWarnings("unchecked")
@Nonnull
public static Map<Object, Object> getTable( @Nonnull Object[] args, int index ) throws LuaException
{
if( index >= args.length ) throw badArgument( index, "table", "nil" );
Object value = args[ index ];
if( value instanceof Map )
{
return (Map<Object, Object>) value;
}
else
{
throw badArgument( index, "table", value );
}
}
public static double optNumber( @Nonnull Object[] args, int index, double def ) throws LuaException
{
Object value = index < args.length ? args[ index ] : null;
if( value == null )
{
return def;
}
else if( value instanceof Number )
{
return ((Number) value).doubleValue();
}
else
{
throw badArgument( index, "number", value );
}
}
public static int optInt( @Nonnull Object[] args, int index, int def ) throws LuaException
{
Object value = index < args.length ? args[ index ] : null;
if( value == null )
{
return def;
}
else if( value instanceof Number )
{
return (int) ((Number) value).longValue();
}
else
{
throw badArgument( index, "number", value );
}
}
public static double optReal( @Nonnull Object[] args, int index, double def ) throws LuaException
{
return checkReal( index, optNumber( args, index, def ) );
}
public static boolean optBoolean( @Nonnull Object[] args, int index, boolean def ) throws LuaException
{
Object value = index < args.length ? args[ index ] : null;
if( value == null )
{
return def;
}
else if( value instanceof Boolean )
{
return (Boolean) value;
}
else
{
throw badArgument( index, "boolean", value );
}
}
public static String optString( @Nonnull Object[] args, int index, String def ) throws LuaException
{
Object value = index < args.length ? args[ index ] : null;
if( value == null )
{
return def;
}
else if( value instanceof String )
{
return (String) value;
}
else
{
throw badArgument( index, "string", value );
}
}
@SuppressWarnings("unchecked")
public static Map<Object, Object> optTable( @Nonnull Object[] args, int index, Map<Object, Object> def ) throws LuaException
{
Object value = index < args.length ? args[ index ] : null;
if( value == null )
{
return def;
}
else if( value instanceof Map )
{
return (Map<Object, Object>) value;
}
else
{
throw badArgument( index, "table", value );
}
}
private static double checkReal( int index, double value ) throws LuaException
{
if( Double.isNaN( value ) )
{
throw badArgument( index, "number", "nan" );
}
else if( value == Double.POSITIVE_INFINITY )
{
throw badArgument( index, "number", "inf" );
}
else if( value == Double.NEGATIVE_INFINITY )
{
throw badArgument( index, "number", "-inf" );
}
else
{
return value;
}
}
}

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -9,6 +9,10 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nonnull;
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
// Contributed by Nia // Contributed by Nia
// Based on LuaBit (http://luaforge.net/projects/bit) // Based on LuaBit (http://luaforge.net/projects/bit)
@@ -18,57 +22,39 @@ public class BitAPI implements ILuaAPI
private static final int BAND = 1; private static final int BAND = 1;
private static final int BOR = 2; private static final int BOR = 2;
private static final int BXOR = 3; private static final int BXOR = 3;
private static final int BRSHIFT = 4; private static final int BRSHIFT = 4;
private static final int BLSHIFT = 5; private static final int BLSHIFT = 5;
private static final int BLOGIC_RSHIFT = 6; private static final int BLOGIC_RSHIFT = 6;
private static int checkInt( Object o, int count ) throws LuaException
{
if( o instanceof Number )
{
return (int)(((Number)o).longValue());
}
else
{
if( count == 2 )
{
throw new LuaException( "Expected number, number" );
}
else
{
throw new LuaException( "Expected number" );
}
}
}
public BitAPI( IAPIEnvironment _environment ) public BitAPI( IAPIEnvironment _environment )
{ {
} }
@Override @Override
public String[] getNames() public String[] getNames()
{ {
return new String[] { return new String[] {
"bit" "bit"
}; };
} }
@Override @Override
public void startup( ) public void startup( )
{ {
} }
@Override @Override
public void advance( double _dt ) public void advance( double _dt )
{ {
} }
@Override @Override
public void shutdown( ) public void shutdown( )
{ {
} }
@Override @Nonnull
@Override
public String[] getMethodNames() { public String[] getMethodNames() {
return new String[] { return new String[] {
"bnot", "band", "bor", "bxor", "bnot", "band", "bor", "bxor",
@@ -77,33 +63,30 @@ public class BitAPI implements ILuaAPI
} }
@Override @Override
public Object[] callMethod( ILuaContext context, int method, Object[] args ) throws LuaException public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{ {
Object a = args.length>0?args[0]:null;
Object b = args.length>1?args[1]:null;
int ret = 0; int ret = 0;
switch(method) { switch(method) {
case BNOT: case BNOT:
ret = ~checkInt(a, 1); ret = ~getInt( args, 0 );
break; break;
case BAND: case BAND:
ret = checkInt(a, 2) & checkInt(b, 2); ret = getInt( args, 0 ) & getInt( args, 1 );
break; break;
case BOR: case BOR:
ret = checkInt(a, 2) | checkInt(b, 2); ret = getInt( args, 0 ) | getInt( args, 1 );
break; break;
case BXOR: case BXOR:
ret = checkInt(a, 2) ^ checkInt(b, 2); ret = getInt( args, 0 ) ^ getInt( args, 1 );
break; break;
case BRSHIFT: case BRSHIFT:
ret = checkInt(a, 2) >> checkInt(b, 2); ret = getInt( args, 0 ) >> getInt( args, 1 );
break; break;
case BLSHIFT: case BLSHIFT:
ret = checkInt(a, 2) << checkInt(b, 2); ret = getInt( args, 0 ) << getInt( args, 1 );
break; break;
case BLOGIC_RSHIFT: case BLOGIC_RSHIFT:
ret = checkInt(a, 2) >>> checkInt(b, 2); ret = getInt( args, 0 ) >>> getInt( args, 1 );
break; break;
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -11,6 +11,11 @@ import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import javax.annotation.Nonnull;
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
import static dan200.computercraft.core.apis.ArgumentHelper.optInt;
public class BufferAPI implements ILuaAPI public class BufferAPI implements ILuaAPI
{ {
private static class BufferLuaObject implements ILuaObject private static class BufferLuaObject implements ILuaObject
@@ -22,6 +27,7 @@ public class BufferAPI implements ILuaAPI
m_buffer = buffer; m_buffer = buffer;
} }
@Nonnull
@Override @Override
public String[] getMethodNames() public String[] getMethodNames()
{ {
@@ -35,7 +41,7 @@ public class BufferAPI implements ILuaAPI
} }
@Override @Override
public Object[] callMethod( ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{ {
switch( method ) switch( method )
{ {
@@ -52,81 +58,25 @@ public class BufferAPI implements ILuaAPI
case 2: case 2:
{ {
// read // read
int start = 0; int start = optInt( arguments, 0, 0 );
if( arguments.length >= 1 && (arguments[0] != null) ) int end = optInt( arguments, 1, m_buffer.length() );
{
if( !(arguments[0] instanceof Number) )
{
throw new LuaException( "Expected number" );
}
start = ((Number)arguments[1]).intValue() - 1;
}
int end = m_buffer.length();
if( arguments.length >= 2 && (arguments[1] != null) )
{
if( !(arguments[1] instanceof Number) )
{
throw new LuaException( "Expected number, number" );
}
end = ((Number)arguments[1]).intValue();
}
return new Object[] { m_buffer.read( start, end ) }; return new Object[] { m_buffer.read( start, end ) };
} }
case 3: case 3:
{ {
// write // write
if( arguments.length < 1 || !(arguments[0] instanceof String) ) String text = getString( arguments, 0 );
{ int start = optInt( arguments, 1, 0 );
throw new LuaException( "Expected string" ); int end = optInt( arguments, 2, start + text.length() );
}
String text = (String)(arguments[0]);
int start = 0;
if( arguments.length >= 2 && (arguments[1] != null) )
{
if( !(arguments[1] instanceof Number) )
{
throw new LuaException( "Expected string, number" );
}
start = ((Number)arguments[1]).intValue() - 1;
}
int end = start + text.length();
if( arguments.length >= 3 && (arguments[2] != null) )
{
if( !(arguments[2] instanceof Number) )
{
throw new LuaException( "Expected string, number, number" );
}
end = ((Number)arguments[2]).intValue();
}
m_buffer.write( text, start, end ); m_buffer.write( text, start, end );
return null; return null;
} }
case 4: case 4:
{ {
// fill // fill
if( arguments.length < 1 || !(arguments[0] instanceof String) ) String text = getString( arguments, 0 );
{ int start = optInt( arguments, 1, 0 );
throw new LuaException( "Expected string" ); int end = optInt( arguments, 2, m_buffer.length() );
}
String text = (String)(arguments[0]);
int start = 0;
if( arguments.length >= 2 && (arguments[1] != null) )
{
if( !(arguments[1] instanceof Number) )
{
throw new LuaException( "Expected string, number" );
}
start = ((Number)arguments[1]).intValue() - 1;
}
int end = m_buffer.length();
if( arguments.length >= 3 && (arguments[2] != null) )
{
if( !(arguments[2] instanceof Number) )
{
throw new LuaException( "Expected string, number, number" );
}
end = ((Number)arguments[2]).intValue();
}
m_buffer.fill( text, start, end ); m_buffer.fill( text, start, end );
return null; return null;
} }
@@ -165,6 +115,7 @@ public class BufferAPI implements ILuaAPI
{ {
} }
@Nonnull
@Override @Override
public String[] getMethodNames() public String[] getMethodNames()
{ {
@@ -174,29 +125,17 @@ public class BufferAPI implements ILuaAPI
} }
@Override @Override
public Object[] callMethod( ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{ {
switch( method ) switch( method )
{ {
case 0: case 0:
{ {
if( arguments.length < 1 || !(arguments[0] instanceof String) ) String text = getString( arguments, 0 );
int repetitions = optInt( arguments, 1, 1 );
if( repetitions < 0 )
{ {
throw new LuaException( "Expected string" ); throw ArgumentHelper.badArgument( 1, "positive number", Integer.toString( repetitions ) );
}
String text = (String)(arguments[0]);
int repetitions = 1;
if( arguments.length >= 2 && arguments[1] != null )
{
if( !(arguments[1] instanceof Number) )
{
throw new LuaException( "Expected string, number" );
}
repetitions = ((Number)arguments[1]).intValue();
if( repetitions < 0 )
{
throw new LuaException( "Expected positive number" );
}
} }
TextBuffer buffer = new TextBuffer( text, repetitions ); TextBuffer buffer = new TextBuffer( text, repetitions );
return new Object[] { new BufferLuaObject( buffer ) }; return new Object[] { new BufferLuaObject( buffer ) };

View File

@@ -1,346 +1,299 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.apis.handles.BinaryInputHandle;
import dan200.computercraft.core.apis.handles.BinaryOutputHandle;
import dan200.computercraft.core.apis.handles.EncodedInputHandle;
import dan200.computercraft.core.apis.handles.EncodedOutputHandle;
import dan200.computercraft.core.filesystem.FileSystem; import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.filesystem.FileSystemException; import dan200.computercraft.core.filesystem.FileSystemException;
import dan200.computercraft.core.filesystem.IMountedFileBinary;
import dan200.computercraft.core.filesystem.IMountedFileNormal;
import java.io.IOException; import javax.annotation.Nonnull;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
public class FSAPI implements ILuaAPI public class FSAPI implements ILuaAPI
{ {
private IAPIEnvironment m_env; private IAPIEnvironment m_env;
private FileSystem m_fileSystem; private FileSystem m_fileSystem;
public FSAPI( IAPIEnvironment _env ) public FSAPI( IAPIEnvironment _env )
{ {
m_env = _env; m_env = _env;
m_fileSystem = null; m_fileSystem = null;
} }
@Override @Override
public String[] getNames() public String[] getNames()
{ {
return new String[] { return new String[] {
"fs" "fs"
}; };
} }
@Override @Override
public void startup( ) public void startup( )
{ {
m_fileSystem = m_env.getFileSystem(); m_fileSystem = m_env.getFileSystem();
} }
@Override @Override
public void advance( double _dt ) public void advance( double _dt )
{ {
} }
@Override @Override
public void shutdown( ) public void shutdown( )
{ {
m_fileSystem = null; m_fileSystem = null;
} }
@Override @Nonnull
@Override
public String[] getMethodNames() public String[] getMethodNames()
{ {
return new String[] { return new String[] {
"list", "list",
"combine", "combine",
"getName", "getName",
"getSize", "getSize",
"exists", "exists",
"isDir", "isDir",
"isReadOnly", "isReadOnly",
"makeDir", "makeDir",
"move", "move",
"copy", "copy",
"delete", "delete",
"open", "open",
"getDrive", "getDrive",
"getFreeSpace", "getFreeSpace",
"find", "find",
"getDir", "getDir",
}; };
} }
@Override @Override
public Object[] callMethod( ILuaContext context, int method, Object[] args ) throws LuaException public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{ {
switch( method ) switch( method )
{ {
case 0: case 0:
{ {
// list // list
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) ) String path = getString( args, 0 );
{ try {
throw new LuaException( "Expected string" ); String[] results = m_fileSystem.list( path );
} Map<Object,Object> table = new HashMap<>();
String path = (String)args[0]; for(int i=0; i<results.length; ++i ) {
try { table.put( i+1, results[i] );
String[] results = m_fileSystem.list( path ); }
Map<Object,Object> table = new HashMap<Object,Object>(); return new Object[] { table };
for(int i=0; i<results.length; ++i ) { }
table.put( i+1, results[i] );
}
return new Object[] { table };
}
catch( FileSystemException e ) catch( FileSystemException e )
{ {
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
case 1: case 1:
{ {
// combine // combine
if( args.length != 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof String) ) String pathA = getString( args, 0 );
{ String pathB = getString( args, 1 );
throw new LuaException( "Expected string, string" ); return new Object[] { m_fileSystem.combine( pathA, pathB ) };
} }
String pathA = (String)args[0]; case 2:
String pathB = (String)args[1]; {
return new Object[] { m_fileSystem.combine( pathA, pathB ) }; // getName
} String path = getString( args, 0 );
case 2: return new Object[]{ FileSystem.getName( path ) };
{ }
// getName case 3:
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) ) {
{ // getSize
throw new LuaException( "Expected string" ); String path = getString( args, 0 );
} try
String path = (String)args[0];
return new Object[]{ m_fileSystem.getName( path ) };
}
case 3:
{
// getSize
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
{
throw new LuaException( "Expected string" );
}
String path = (String)args[0];
try
{ {
return new Object[]{ m_fileSystem.getSize( path ) }; return new Object[]{ m_fileSystem.getSize( path ) };
} }
catch( FileSystemException e ) catch( FileSystemException e )
{ {
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
case 4: case 4:
{ {
// exists // exists
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) ) String path = getString( args, 0 );
{ try {
throw new LuaException( "Expected string" ); return new Object[]{ m_fileSystem.exists( path ) };
} } catch( FileSystemException e ) {
String path = (String)args[0]; return new Object[]{ false };
try { }
return new Object[]{ m_fileSystem.exists( path ) }; }
} catch( FileSystemException e ) { case 5:
return new Object[]{ false }; {
} // isDir
} String path = getString( args, 0 );
case 5: try {
{ return new Object[]{ m_fileSystem.isDir( path ) };
// isDir } catch( FileSystemException e ) {
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) ) return new Object[]{ false };
{ }
throw new LuaException( "Expected string" ); }
} case 6:
String path = (String)args[0]; {
try { // isReadOnly
return new Object[]{ m_fileSystem.isDir( path ) }; String path = getString( args, 0 );
} catch( FileSystemException e ) { try {
return new Object[]{ false }; return new Object[]{ m_fileSystem.isReadOnly( path ) };
} } catch( FileSystemException e ) {
} return new Object[]{ false };
case 6: }
{ }
// isReadOnly case 7:
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) ) {
{ // makeDir
throw new LuaException( "Expected string" ); String path = getString( args, 0 );
} try {
String path = (String)args[0]; m_fileSystem.makeDir( path );
try { return null;
return new Object[]{ m_fileSystem.isReadOnly( path ) }; } catch( FileSystemException e ) {
} catch( FileSystemException e ) { throw new LuaException( e.getMessage() );
return new Object[]{ false }; }
} }
} case 8:
case 7: {
{ // move
// makeDir String path = getString( args, 0 );
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) ) String dest = getString( args, 1 );
{ try {
throw new LuaException( "Expected string" ); m_fileSystem.move( path, dest );
} return null;
String path = (String)args[0]; } catch( FileSystemException e ) {
try { throw new LuaException( e.getMessage() );
m_fileSystem.makeDir( path ); }
return null; }
} catch( FileSystemException e ) { case 9:
throw new LuaException( e.getMessage() ); {
} // copy
} String path = getString( args, 0 );
case 8: String dest = getString( args, 1 );
{ try {
// move m_fileSystem.copy( path, dest );
if( args.length != 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof String) ) return null;
{ } catch( FileSystemException e ) {
throw new LuaException( "Expected string, string" ); throw new LuaException( e.getMessage() );
} }
String path = (String)args[0]; }
String dest = (String)args[1]; case 10:
try { {
m_fileSystem.move( path, dest ); // delete
return null; String path = getString( args, 0 );
} catch( FileSystemException e ) { try {
throw new LuaException( e.getMessage() ); m_fileSystem.delete( path );
} return null;
} } catch( FileSystemException e ) {
case 9: throw new LuaException( e.getMessage() );
{ }
// copy }
if( args.length != 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof String) ) case 11:
{ {
throw new LuaException( "Expected string, string" ); // open
} String path = getString( args, 0 );
String path = (String)args[0]; String mode = getString( args, 1 );
String dest = (String)args[1]; try {
try { switch( mode )
m_fileSystem.copy( path, dest ); {
return null; case "r":
} catch( FileSystemException e ) { {
throw new LuaException( e.getMessage() ); // Open the file for reading, then create a wrapper around the reader
} InputStream reader = m_fileSystem.openForRead( path );
} return new Object[] { new EncodedInputHandle( reader ) };
case 10: }
{ case "w":
// delete {
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) ) // Open the file for writing, then create a wrapper around the writer
{ OutputStream writer = m_fileSystem.openForWrite( path, false );
throw new LuaException( "Expected string" ); return new Object[] { new EncodedOutputHandle( writer ) };
} }
String path = (String)args[0]; case "a":
try { {
m_fileSystem.delete( path ); // Open the file for appending, then create a wrapper around the writer
return null; OutputStream writer = m_fileSystem.openForWrite( path, true );
} catch( FileSystemException e ) { return new Object[] { new EncodedOutputHandle( writer ) };
throw new LuaException( e.getMessage() ); }
} case "rb":
} {
case 11: // Open the file for binary reading, then create a wrapper around the reader
{ InputStream reader = m_fileSystem.openForRead( path );
// open return new Object[] { new BinaryInputHandle( reader ) };
if( args.length < 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof String) ) }
{ case "wb":
throw new LuaException( "Expected string, string" ); {
} // Open the file for binary writing, then create a wrapper around the writer
String path = (String)args[0]; OutputStream writer = m_fileSystem.openForWrite( path, false );
String mode = (String)args[1]; return new Object[] { new BinaryOutputHandle( writer ) };
try { }
if( mode.equals( "r" ) ) { case "ab":
// Open the file for reading, then create a wrapper around the reader {
IMountedFileNormal reader = m_fileSystem.openForRead( path ); // Open the file for binary appending, then create a wrapper around the reader
return wrapBufferedReader( reader ); OutputStream writer = m_fileSystem.openForWrite( path, true );
return new Object[] { new BinaryOutputHandle( writer ) };
} else if( mode.equals( "w" ) ) { }
// Open the file for writing, then create a wrapper around the writer default:
IMountedFileNormal writer = m_fileSystem.openForWrite( path, false ); throw new LuaException( "Unsupported mode" );
return wrapBufferedWriter( writer ); }
} catch( FileSystemException e ) {
} else if( mode.equals( "a" ) ) { return new Object[] { null, e.getMessage() };
// Open the file for appending, then create a wrapper around the writer }
IMountedFileNormal writer = m_fileSystem.openForWrite( path, true ); }
return wrapBufferedWriter( writer ); case 12:
{
} else if( mode.equals( "rb" ) ) { // getDrive
// Open the file for binary reading, then create a wrapper around the reader String path = getString( args, 0 );
IMountedFileBinary reader = m_fileSystem.openForBinaryRead( path ); try {
return wrapInputStream( reader );
} else if( mode.equals( "wb" ) ) {
// Open the file for binary writing, then create a wrapper around the writer
IMountedFileBinary writer = m_fileSystem.openForBinaryWrite( path, false );
return wrapOutputStream( writer );
} else if( mode.equals( "ab" ) ) {
// Open the file for binary appending, then create a wrapper around the reader
IMountedFileBinary writer = m_fileSystem.openForBinaryWrite( path, true );
return wrapOutputStream( writer );
} else {
throw new LuaException( "Unsupported mode" );
}
} catch( FileSystemException e ) {
return null;
}
}
case 12:
{
// getDrive
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
{
throw new LuaException( "Expected string" );
}
String path = (String)args[0];
try {
if( !m_fileSystem.exists( path ) ) if( !m_fileSystem.exists( path ) )
{ {
return null; return null;
} }
return new Object[]{ m_fileSystem.getMountLabel( path ) }; return new Object[]{ m_fileSystem.getMountLabel( path ) };
} catch( FileSystemException e ) { } catch( FileSystemException e ) {
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
case 13: case 13:
{ {
// getFreeSpace // getFreeSpace
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) ) String path = getString( args, 0 );
{ try {
throw new LuaException( "Expected string" );
}
String path = (String)args[0];
try {
long freeSpace = m_fileSystem.getFreeSpace( path ); long freeSpace = m_fileSystem.getFreeSpace( path );
if( freeSpace >= 0 ) if( freeSpace >= 0 )
{ {
return new Object[]{ freeSpace }; return new Object[]{ freeSpace };
} }
return new Object[]{ "unlimited" }; return new Object[]{ "unlimited" };
} catch( FileSystemException e ) { } catch( FileSystemException e ) {
throw new LuaException( e.getMessage() ); throw new LuaException( e.getMessage() );
} }
} }
case 14: case 14:
{ {
// find // find
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) ) String path = getString( args, 0 );
{
throw new LuaException( "Expected string" );
}
String path = (String)args[0];
try { try {
String[] results = m_fileSystem.find( path ); String[] results = m_fileSystem.find( path );
Map<Object,Object> table = new HashMap<Object,Object>(); Map<Object,Object> table = new HashMap<>();
for(int i=0; i<results.length; ++i ) { for(int i=0; i<results.length; ++i ) {
table.put( i+1, results[i] ); table.put( i+1, results[i] );
} }
@@ -352,279 +305,14 @@ public class FSAPI implements ILuaAPI
case 15: case 15:
{ {
// getDir // getDir
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) ) String path = getString( args, 0 );
{ return new Object[]{ FileSystem.getDirectory( path ) };
throw new LuaException( "Expected string" );
}
String path = (String)args[0];
return new Object[]{ m_fileSystem.getDirectory( path ) };
} }
default: default:
{ {
assert( false ); assert( false );
return null; return null;
} }
} }
} }
private static Object[] wrapBufferedReader( final IMountedFileNormal reader )
{
return new Object[] { new ILuaObject() {
@Override
public String[] getMethodNames()
{
return new String[] {
"readLine",
"readAll",
"close"
};
}
@Override
public Object[] callMethod( ILuaContext context, int method, Object[] args ) throws LuaException
{
switch( method )
{
case 0:
{
// readLine
try {
String line = reader.readLine();
if( line != null ) {
return new Object[] { line };
} else {
return null;
}
} catch( IOException e ) {
return null;
}
}
case 1:
{
// readAll
try {
StringBuilder result = new StringBuilder( "" );
String line = reader.readLine();
while( line != null ) {
result.append( line );
line = reader.readLine();
if( line != null ) {
result.append( "\n" );
}
}
return new Object[] { result.toString() };
} catch( IOException e ) {
return null;
}
}
case 2:
{
// close
try {
reader.close();
return null;
} catch( IOException e ) {
return null;
}
}
default:
{
return null;
}
}
}
} };
}
private static Object[] wrapBufferedWriter( final IMountedFileNormal writer )
{
return new Object[] { new ILuaObject() {
@Override
public String[] getMethodNames()
{
return new String[] {
"write",
"writeLine",
"close",
"flush"
};
}
@Override
public Object[] callMethod( ILuaContext context, int method, Object[] args ) throws LuaException
{
switch( method )
{
case 0:
{
// write
String text;
if( args.length > 0 && args[0] != null ) {
text = args[0].toString();
} else {
text = "";
}
try {
writer.write( text, 0, text.length(), false );
return null;
} catch( IOException e ) {
throw new LuaException( e.getMessage() );
}
}
case 1:
{
// writeLine
String text;
if( args.length > 0 && args[0] != null ) {
text = args[0].toString();
} else {
text = "";
}
try {
writer.write( text, 0, text.length(), true );
return null;
} catch( IOException e ) {
throw new LuaException( e.getMessage() );
}
}
case 2:
{
// close
try {
writer.close();
return null;
} catch( IOException e ) {
return null;
}
}
case 3:
{
try {
writer.flush();
return null;
} catch ( IOException e ) {
return null;
}
}
default:
{
assert( false );
return null;
}
}
}
} };
}
private static Object[] wrapInputStream( final IMountedFileBinary reader )
{
return new Object[] { new ILuaObject() {
@Override
public String[] getMethodNames() {
return new String[] {
"read",
"close"
};
}
@Override
public Object[] callMethod( ILuaContext context, int method, Object[] args) throws LuaException {
switch( method )
{
case 0:
{
// read
try {
int b = reader.read();
if( b != -1 ) {
return new Object[] { b };
} else {
return null;
}
} catch( IOException e ) {
return null;
}
}
case 1:
{
//close
try {
reader.close();
return null;
} catch( IOException e ) {
return null;
}
}
default:
{
assert( false );
return null;
}
}
}
}};
}
private static Object[] wrapOutputStream( final IMountedFileBinary writer )
{
return new Object[] { new ILuaObject() {
@Override
public String[] getMethodNames() {
return new String[] {
"write",
"close",
"flush"
};
}
@Override
public Object[] callMethod( ILuaContext context, int method, Object[] args) throws LuaException {
switch( method )
{
case 0:
{
// write
try {
if( args.length > 0 && args[0] instanceof Number )
{
int number = ((Number)args[0]).intValue();
writer.write( number );
}
return null;
} catch( IOException e ) {
throw new LuaException(e.getMessage());
}
}
case 1:
{
//close
try {
writer.close();
return null;
} catch( IOException e ) {
return null;
}
}
case 2:
{
try {
writer.flush();
return null;
} catch ( IOException e ) {
return null;
}
}
default:
{
assert( false );
return null;
}
}
}
}};
}
} }

View File

@@ -1,170 +1,91 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.apis.http.HTTPCheck;
import dan200.computercraft.core.apis.http.HTTPRequest;
import dan200.computercraft.core.apis.http.HTTPTask;
import java.io.BufferedReader; import javax.annotation.Nonnull;
import java.io.IOException; import java.net.URL;
import java.util.*; import java.util.*;
import static dan200.computercraft.core.apis.ArgumentHelper.*;
public class HTTPAPI implements ILuaAPI public class HTTPAPI implements ILuaAPI
{ {
private IAPIEnvironment m_apiEnvironment; private final IAPIEnvironment m_apiEnvironment;
private List<HTTPRequest> m_httpRequests; private final List<HTTPTask> m_httpTasks;
public HTTPAPI( IAPIEnvironment environment ) public HTTPAPI( IAPIEnvironment environment )
{ {
m_apiEnvironment = environment; m_apiEnvironment = environment;
m_httpRequests = new ArrayList<HTTPRequest>(); m_httpTasks = new ArrayList<>();
} }
@Override @Override
public String[] getNames() public String[] getNames()
{ {
return new String[] { return new String[] {
"http" "http"
}; };
} }
@Override @Override
public void startup( ) public void startup( )
{ {
} }
@Override @Override
public void advance( double _dt ) public void advance( double _dt )
{ {
// Wait for all of our http requests // Wait for all of our http requests
synchronized( m_httpRequests ) synchronized( m_httpTasks )
{ {
Iterator<HTTPRequest> it = m_httpRequests.iterator(); Iterator<HTTPTask> it = m_httpTasks.iterator();
while( it.hasNext() ) { while( it.hasNext() )
final HTTPRequest h = it.next(); {
if( h.isComplete() ) { final HTTPTask h = it.next();
final String url = h.getURL(); if( h.isFinished() )
if( h.wasSuccessful() ) { {
// Queue the "http_success" event h.whenFinished( m_apiEnvironment );
final BufferedReader contents = h.getContents(); it.remove();
final int responseCode = h.getResponseCode(); }
final Object result = wrapBufferedReader( contents, responseCode ); }
m_apiEnvironment.queueEvent( "http_success", new Object[] { url, result } ); }
} else { }
// Queue the "http_failure" event
m_apiEnvironment.queueEvent( "http_failure", new Object[] { url, "Could not connect" } ); @Override
} public void shutdown( )
it.remove(); {
} synchronized( m_httpTasks )
} {
} for( HTTPTask r : m_httpTasks )
} {
r.cancel();
private static ILuaObject wrapBufferedReader( final BufferedReader reader, final int responseCode ) }
{ m_httpTasks.clear();
return new ILuaObject() { }
@Override }
public String[] getMethodNames()
{
return new String[] {
"readLine",
"readAll",
"close",
"getResponseCode"
};
}
@Override
public Object[] callMethod( ILuaContext context, int method, Object[] args ) throws LuaException
{
switch( method )
{
case 0:
{
// readLine
try {
String line = reader.readLine();
if( line != null ) {
return new Object[] { line };
} else {
return null;
}
} catch( IOException e ) {
return null;
}
}
case 1:
{
// readAll
try {
StringBuilder result = new StringBuilder( "" );
String line = reader.readLine();
while( line != null ) {
result.append( line );
line = reader.readLine();
if( line != null ) {
result.append( "\n" );
}
}
return new Object[] { result.toString() };
} catch( IOException e ) {
return null;
}
}
case 2:
{
// close
try {
reader.close();
return null;
} catch( IOException e ) {
return null;
}
}
case 3:
{
// getResponseCode
return new Object[] { responseCode };
}
default:
{
return null;
}
}
}
};
}
@Override
public void shutdown( )
{
synchronized( m_httpRequests )
{
Iterator<HTTPRequest> it = m_httpRequests.iterator();
while( it.hasNext() ) {
HTTPRequest r = it.next();
r.cancel();
}
m_httpRequests.clear();
}
}
@Override @Nonnull
@Override
public String[] getMethodNames() public String[] getMethodNames()
{ {
return new String[] { return new String[] {
"request", "request",
"checkURL" "checkURL"
}; };
} }
@Override @Override
public Object[] callMethod( ILuaContext context, int method, Object[] args ) throws LuaException public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{ {
switch( method ) switch( method )
{ {
@@ -172,25 +93,17 @@ public class HTTPAPI implements ILuaAPI
{ {
// request // request
// Get URL // Get URL
if( args.length < 1 || !(args[0] instanceof String) ) String urlString = getString( args, 0 );
{
throw new LuaException( "Expected string" );
}
String urlString = args[0].toString();
// Get POST // Get POST
String postString = null; String postString = optString( args, 1, null );
if( args.length >= 2 && args[1] instanceof String )
{
postString = args[1].toString();
}
// Get Headers // Get Headers
Map<String, String> headers = null; Map<String, String> headers = null;
if( args.length >= 3 && args[2] instanceof Map ) Map<Object, Object> table = optTable( args, 2, null );
if( table != null )
{ {
Map table = (Map)args[2]; headers = new HashMap<>( table.size() );
headers = new HashMap<String, String>( table.size() );
for( Object key : table.keySet() ) for( Object key : table.keySet() )
{ {
Object value = table.get( key ); Object value = table.get( key );
@@ -200,14 +113,22 @@ public class HTTPAPI implements ILuaAPI
} }
} }
} }
// Get binary
boolean binary = false;
if( args.length >= 4 )
{
binary = args[ 3 ] != null && !args[ 3 ].equals( Boolean.FALSE );
}
// Make the request // Make the request
try try
{ {
HTTPRequest request = new HTTPRequest( urlString, postString, headers ); URL url = HTTPRequest.checkURL( urlString );
synchronized( m_httpRequests ) HTTPRequest request = new HTTPRequest( urlString, url, postString, headers, binary );
synchronized( m_httpTasks )
{ {
m_httpRequests.add( request ); m_httpTasks.add( HTTPTask.submit( request ) );
} }
return new Object[] { true }; return new Object[] { true };
} }
@@ -220,16 +141,16 @@ public class HTTPAPI implements ILuaAPI
{ {
// checkURL // checkURL
// Get URL // Get URL
if( args.length < 1 || !(args[0] instanceof String) ) String urlString = getString( args, 0 );
{
throw new LuaException( "Expected string" );
}
String urlString = args[0].toString();
// Check URL // Check URL
try try
{ {
HTTPRequest.checkURL( urlString ); URL url = HTTPRequest.checkURL( urlString );
HTTPCheck check = new HTTPCheck( urlString, url );
synchronized( m_httpTasks ) {
m_httpTasks.add( HTTPTask.submit( check ) );
}
return new Object[] { true }; return new Object[] { true };
} }
catch( HTTPRequestException e ) catch( HTTPRequestException e )
@@ -242,5 +163,5 @@ public class HTTPAPI implements ILuaAPI
return null; return null;
} }
} }
} }
} }

View File

@@ -1,25 +1,22 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import com.google.common.base.Joiner;
import com.google.common.io.ByteStreams;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import java.io.*; import java.io.*;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern;
class HTTPRequestException extends Exception {
public HTTPRequestException( String s ) {
super( s );
}
}
public class HTTPRequest public class HTTPRequest
{ {
@@ -43,20 +40,7 @@ public class HTTPRequest
} }
// Compare the URL to the whitelist // Compare the URL to the whitelist
boolean allowed = false; if( !ComputerCraft.http_whitelist.matches( url.getHost() ) || ComputerCraft.http_blacklist.matches( url.getHost() ) )
String whitelistString = ComputerCraft.http_whitelist;
String[] allowedURLs = whitelistString.split( ";" );
for( int i=0; i<allowedURLs.length; ++i )
{
String allowedURL = allowedURLs[i];
Pattern allowedURLPattern = Pattern.compile( "^\\Q" + allowedURL.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" );
if( allowedURLPattern.matcher( url.getHost() ).matches() )
{
allowed = true;
break;
}
}
if( !allowed )
{ {
throw new HTTPRequestException( "Domain not permitted" ); throw new HTTPRequestException( "Domain not permitted" );
} }
@@ -64,176 +48,146 @@ public class HTTPRequest
return url; return url;
} }
public HTTPRequest( String url, final String postText, final Map<String, String> headers ) throws HTTPRequestException public HTTPRequest( String url, final String postText, final Map<String, String> headers, boolean binary ) throws HTTPRequestException
{ {
// Parse the URL // Parse the URL
m_urlString = url; m_urlString = url;
m_url = checkURL( m_urlString ); m_url = checkURL( m_urlString );
m_binary = binary;
// Start the thread // Start the thread
m_cancelled = false; m_cancelled = false;
m_complete = false; m_complete = false;
m_success = false; m_success = false;
m_result = null; m_result = null;
m_responseCode = -1; m_responseCode = -1;
Thread thread = new Thread( new Runnable() { Thread thread = new Thread( () ->
@Override {
public void run() try
{ {
try // Connect to the URL
HttpURLConnection connection = (HttpURLConnection)m_url.openConnection();
if( postText != null )
{ {
// Connect to the URL connection.setRequestMethod( "POST" );
HttpURLConnection connection = (HttpURLConnection)m_url.openConnection(); connection.setDoOutput( true );
}
else
{
connection.setRequestMethod( "GET" );
}
if( postText != null ) // Set headers
connection.setRequestProperty( "accept-charset", "UTF-8" );
if( postText != null )
{
connection.setRequestProperty( "content-type", "application/x-www-form-urlencoded; charset=utf-8" );
connection.setRequestProperty( "content-encoding", "UTF-8" );
}
if( headers != null )
{
for( Map.Entry<String, String> header : headers.entrySet() )
{ {
connection.setRequestMethod( "POST" ); connection.setRequestProperty( header.getKey(), header.getValue() );
connection.setDoOutput( true );
}
else
{
connection.setRequestMethod( "GET" );
} }
}
// Set headers // Send POST text
connection.setRequestProperty( "accept-charset", "UTF-8" ); if( postText != null )
if( postText != null ) {
{ OutputStream os = connection.getOutputStream();
connection.setRequestProperty( "content-type", "application/x-www-form-urlencoded; charset=utf-8" ); OutputStreamWriter osw;
connection.setRequestProperty( "content-encoding", "UTF-8" );
}
if( headers != null )
{
for( Map.Entry<String, String> header : headers.entrySet() )
{
connection.setRequestProperty( header.getKey(), header.getValue() );
}
}
// Send POST text
if( postText != null )
{
OutputStream os = connection.getOutputStream();
OutputStreamWriter osw;
try
{
osw = new OutputStreamWriter( os, "UTF-8" );
}
catch( UnsupportedEncodingException e )
{
osw = new OutputStreamWriter( os );
}
BufferedWriter writer = new BufferedWriter( osw );
writer.write( postText, 0, postText.length() );
writer.close();
}
// Read response
InputStream is = connection.getInputStream();
InputStreamReader isr;
try try
{ {
String contentEncoding = connection.getContentEncoding(); osw = new OutputStreamWriter( os, "UTF-8" );
if( contentEncoding != null )
{
try
{
isr = new InputStreamReader( is, contentEncoding );
}
catch( UnsupportedEncodingException e )
{
isr = new InputStreamReader( is, "UTF-8" );
}
}
else
{
isr = new InputStreamReader( is, "UTF-8" );
}
} }
catch( UnsupportedEncodingException e ) catch( UnsupportedEncodingException e )
{ {
isr = new InputStreamReader( is ); osw = new OutputStreamWriter( os );
} }
BufferedWriter writer = new BufferedWriter( osw );
// Download the contents writer.write( postText, 0, postText.length() );
BufferedReader reader = new BufferedReader( isr ); writer.close();
StringBuilder result = new StringBuilder();
while( true )
{
synchronized( m_lock )
{
if( m_cancelled )
{
break;
}
}
String line = reader.readLine();
if( line == null )
{
break;
}
result.append( line );
result.append( '\n' );
}
reader.close();
synchronized( m_lock )
{
if( m_cancelled )
{
// We cancelled
m_complete = true;
m_success = false;
m_result = null;
}
else
{
// We completed
m_complete = true;
m_success = true;
m_result = result.toString();
m_responseCode = connection.getResponseCode();
}
}
connection.disconnect(); // disconnect
} }
catch( IOException e )
// Read response
InputStream is;
int code = connection.getResponseCode();
boolean responseSuccess;
if (code >= 200 && code < 400) {
is = connection.getInputStream();
responseSuccess = true;
} else {
is = connection.getErrorStream();
responseSuccess = false;
}
byte[] result = ByteStreams.toByteArray( is );
is.close();
synchronized( m_lock )
{ {
synchronized( m_lock ) if( m_cancelled )
{ {
// There was an error // We cancelled
m_complete = true; m_complete = true;
m_success = false; m_success = false;
m_result = null; m_result = null;
} }
else
{
// We completed
m_complete = true;
m_success = responseSuccess;
m_result = result;
m_responseCode = connection.getResponseCode();
m_encoding = connection.getContentEncoding();
Joiner joiner = Joiner.on( ',' );
Map<String, String> headers1 = m_responseHeaders = new HashMap<>();
for (Map.Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
headers1.put(header.getKey(), joiner.join( header.getValue() ));
}
}
}
connection.disconnect(); // disconnect
}
catch( IOException e )
{
synchronized( m_lock )
{
// There was an error
m_complete = true;
m_success = false;
m_result = null;
} }
} }
} ); } );
thread.setDaemon(true);
thread.start(); thread.start();
} }
public String getURL() { public String getURL() {
return m_urlString; return m_urlString;
} }
public void cancel() public void cancel()
{ {
synchronized(m_lock) { synchronized(m_lock) {
m_cancelled = true; m_cancelled = true;
} }
} }
public boolean isComplete() public boolean isComplete()
{ {
synchronized(m_lock) { synchronized(m_lock) {
return m_complete; return m_complete;
} }
} }
public int getResponseCode() { public int getResponseCode() {
synchronized(m_lock) { synchronized(m_lock) {
@@ -241,33 +195,51 @@ public class HTTPRequest
} }
} }
public Map<String, String> getResponseHeaders() {
synchronized (m_lock) {
return m_responseHeaders;
}
}
public boolean wasSuccessful() public boolean wasSuccessful()
{ {
synchronized(m_lock) { synchronized(m_lock) {
return m_success; return m_success;
} }
} }
public BufferedReader getContents() public boolean isBinary()
{ {
String result = null; return m_binary;
synchronized(m_lock) { }
result = m_result;
} public InputStream getContents()
{
if( result != null ) { byte[] result;
return new BufferedReader( new StringReader( result ) ); synchronized(m_lock) {
} result = m_result;
return null; }
}
if( result != null ) {
private Object m_lock = new Object(); return new ByteArrayInputStream( result );
private URL m_url; }
return null;
}
public String getEncoding() {
return m_encoding;
}
private final Object m_lock = new Object();
private final URL m_url;
private final String m_urlString; private final String m_urlString;
private boolean m_complete; private boolean m_complete;
private boolean m_cancelled; private boolean m_cancelled;
private boolean m_success; private boolean m_success;
private String m_result; private String m_encoding;
private int m_responseCode; private byte[] m_result;
private boolean m_binary;
private int m_responseCode;
private Map<String, String> m_responseHeaders;
} }

View File

@@ -0,0 +1,11 @@
package dan200.computercraft.core.apis;
public class HTTPRequestException extends Exception
{
private static final long serialVersionUID = 7591208619422744652L;
public HTTPRequestException( String s )
{
super( s );
}
}

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -14,32 +14,32 @@ import dan200.computercraft.core.terminal.Terminal;
public interface IAPIEnvironment public interface IAPIEnvironment
{ {
public static interface IPeripheralChangeListener interface IPeripheralChangeListener
{ {
public void onPeripheralChanged( int side, IPeripheral newPeripheral ); void onPeripheralChanged( int side, IPeripheral newPeripheral );
} }
public Computer getComputer(); Computer getComputer();
public int getComputerID(); int getComputerID();
public IComputerEnvironment getComputerEnvironment(); IComputerEnvironment getComputerEnvironment();
public Terminal getTerminal(); Terminal getTerminal();
public FileSystem getFileSystem(); FileSystem getFileSystem();
public void shutdown(); void shutdown();
public void reboot(); void reboot();
public void queueEvent( String event, Object[] args ); void queueEvent( String event, Object[] args );
public void setOutput( int side, int output ); void setOutput( int side, int output );
public int getOutput( int side ); int getOutput( int side );
public int getInput( int side ); int getInput( int side );
public void setBundledOutput( int side, int output ); void setBundledOutput( int side, int output );
public int getBundledOutput( int side ); int getBundledOutput( int side );
public int getBundledInput( int side ); int getBundledInput( int side );
public void setPeripheralChangeListener( IPeripheralChangeListener listener ); void setPeripheralChangeListener( IPeripheralChangeListener listener );
public IPeripheral getPeripheral( int side ); IPeripheral getPeripheral( int side );
public String getLabel(); String getLabel();
public void setLabel( String label ); void setLabel( String label );
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -9,9 +9,9 @@ import dan200.computercraft.api.lua.ILuaObject;
public interface ILuaAPI extends ILuaObject public interface ILuaAPI extends ILuaObject
{ {
public String[] getNames(); String[] getNames();
public void startup(); // LT void startup(); // LT
public void advance( double _dt ); // MT void advance( double _dt ); // MT
public void shutdown(); // LT void shutdown(); // LT
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -8,78 +8,79 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.shared.util.StringUtil;
import java.util.Arrays; import javax.annotation.Nonnull;
import java.util.HashMap; import java.util.*;
import java.util.Iterator;
import java.util.Map; import static dan200.computercraft.core.apis.ArgumentHelper.*;
public class OSAPI implements ILuaAPI public class OSAPI implements ILuaAPI
{ {
private IAPIEnvironment m_apiEnvironment; private IAPIEnvironment m_apiEnvironment;
private final Map<Integer, Timer> m_timers; private final Map<Integer, Timer> m_timers;
private final Map<Integer, Alarm> m_alarms; private final Map<Integer, Alarm> m_alarms;
private int m_clock; private int m_clock;
private double m_time; private double m_time;
private int m_day; private int m_day;
private int m_nextTimerToken; private int m_nextTimerToken;
private int m_nextAlarmToken; private int m_nextAlarmToken;
private static class Timer private static class Timer
{ {
public int m_ticksLeft; public int m_ticksLeft;
public Timer( int ticksLeft ) public Timer( int ticksLeft )
{ {
m_ticksLeft = ticksLeft; m_ticksLeft = ticksLeft;
} }
} }
private class Alarm implements Comparable<Alarm> private class Alarm implements Comparable<Alarm>
{ {
public final double m_time; public final double m_time;
public final int m_day; public final int m_day;
public Alarm( double time, int day ) public Alarm( double time, int day )
{ {
m_time = time; m_time = time;
m_day = day; m_day = day;
} }
@Override @Override
public int compareTo( Alarm o ) public int compareTo( @Nonnull Alarm o )
{ {
double t = (double)m_day * 24.0 + m_time; double t = (double)m_day * 24.0 + m_time;
double ot = (double)m_day * 24.0 + m_time; double ot = (double)m_day * 24.0 + m_time;
if( t < ot ) { if( t < ot ) {
return -1; return -1;
} else if( t > ot ) { } else if( t > ot ) {
return 1; return 1;
} else { } else {
return 0; return 0;
} }
} }
} }
public OSAPI( IAPIEnvironment environment ) public OSAPI( IAPIEnvironment environment )
{ {
m_apiEnvironment = environment; m_apiEnvironment = environment;
m_nextTimerToken = 0; m_nextTimerToken = 0;
m_nextAlarmToken = 0; m_nextAlarmToken = 0;
m_timers = new HashMap<Integer, Timer>(); m_timers = new HashMap<>();
m_alarms = new HashMap<Integer, Alarm>(); m_alarms = new HashMap<>();
} }
// ILuaAPI implementation // ILuaAPI implementation
@Override @Override
public String[] getNames() public String[] getNames()
{ {
return new String[] { return new String[] {
"os" "os"
}; };
} }
@Override @Override
@@ -87,7 +88,7 @@ public class OSAPI implements ILuaAPI
{ {
m_time = m_apiEnvironment.getComputerEnvironment().getTimeOfDay(); m_time = m_apiEnvironment.getComputerEnvironment().getTimeOfDay();
m_day = m_apiEnvironment.getComputerEnvironment().getDay(); m_day = m_apiEnvironment.getComputerEnvironment().getDay();
m_clock = 0; m_clock = 0;
synchronized( m_timers ) synchronized( m_timers )
{ {
@@ -99,40 +100,40 @@ public class OSAPI implements ILuaAPI
m_alarms.clear(); m_alarms.clear();
} }
} }
@Override @Override
public void advance( double dt ) public void advance( double dt )
{ {
synchronized( m_timers ) synchronized( m_timers )
{ {
// Update the clock // Update the clock
m_clock++; m_clock++;
// Countdown all of our active timers // Countdown all of our active timers
Iterator<Map.Entry<Integer, Timer>> it = m_timers.entrySet().iterator(); Iterator<Map.Entry<Integer, Timer>> it = m_timers.entrySet().iterator();
while( it.hasNext() ) while( it.hasNext() )
{ {
Map.Entry<Integer, Timer> entry = it.next(); Map.Entry<Integer, Timer> entry = it.next();
Timer timer = entry.getValue(); Timer timer = entry.getValue();
timer.m_ticksLeft = timer.m_ticksLeft - 1; timer.m_ticksLeft = timer.m_ticksLeft - 1;
if( timer.m_ticksLeft <= 0 ) if( timer.m_ticksLeft <= 0 )
{ {
// Queue the "timer" event // Queue the "timer" event
queueLuaEvent( "timer", new Object[] { entry.getKey() } ); queueLuaEvent( "timer", new Object[] { entry.getKey() } );
it.remove(); it.remove();
} }
} }
} }
// Wait for all of our alarms // Wait for all of our alarms
synchronized( m_alarms ) synchronized( m_alarms )
{ {
double previousTime = m_time; double previousTime = m_time;
int previousDay = m_day; int previousDay = m_day;
double time = m_apiEnvironment.getComputerEnvironment().getTimeOfDay(); double time = m_apiEnvironment.getComputerEnvironment().getTimeOfDay();
int day = m_apiEnvironment.getComputerEnvironment().getDay(); int day = m_apiEnvironment.getComputerEnvironment().getDay();
if( time > previousTime || day > previousDay ) if( time > previousTime || day > previousDay )
{ {
double now = (double)m_day * 24.0 + m_time; double now = (double)m_day * 24.0 + m_time;
Iterator<Map.Entry<Integer, Alarm>> it = m_alarms.entrySet().iterator(); Iterator<Map.Entry<Integer, Alarm>> it = m_alarms.entrySet().iterator();
@@ -149,175 +150,215 @@ public class OSAPI implements ILuaAPI
} }
} }
m_time = time; m_time = time;
m_day = day; m_day = day;
} }
} }
@Override @Override
public void shutdown( ) public void shutdown( )
{
synchronized( m_timers )
{
m_timers.clear();
}
synchronized( m_alarms )
{
m_alarms.clear();
}
}
@Override
public String[] getMethodNames()
{ {
return new String[] { synchronized( m_timers )
"queueEvent", {
"startTimer", m_timers.clear();
"setAlarm", }
"shutdown",
"reboot", synchronized( m_alarms )
"computerID", {
"getComputerID", m_alarms.clear();
"setComputerLabel", }
"computerLabel",
"getComputerLabel",
"clock",
"time",
"day",
"cancelTimer",
"cancelAlarm",
};
} }
@Override @Nonnull
public Object[] callMethod( ILuaContext context, int method, Object[] args ) throws LuaException @Override
public String[] getMethodNames()
{ {
switch( method ) return new String[] {
{ "queueEvent",
case 0: "startTimer",
{ "setAlarm",
// queueEvent "shutdown",
if( args.length == 0 || args[0] == null || !(args[0] instanceof String) ) "reboot",
{ "computerID",
throw new LuaException( "Expected string" ); "getComputerID",
} "setComputerLabel",
queueLuaEvent( (String)args[0], trimArray( args, 1 ) ); "computerLabel",
return null; "getComputerLabel",
} "clock",
case 1: "time",
{ "day",
// startTimer "cancelTimer",
if( args.length < 1 || args[0] == null || !(args[0] instanceof Number) ) "cancelAlarm",
{ "epoch"
throw new LuaException( "Expected number" ); };
} }
double timer = ((Number)args[0]).doubleValue();
synchronized( m_timers ) private float getTimeForCalendar(Calendar c)
{ {
m_timers.put( m_nextTimerToken, new Timer( (int)Math.round( timer / 0.05 ) ) ); float time = c.get(Calendar.HOUR_OF_DAY);
time += (float)c.get(Calendar.MINUTE) / 60.0f;
time += (float)c.get(Calendar.SECOND) / (60.0f * 60.0f);
return time;
}
private int getDayForCalendar(Calendar c)
{
GregorianCalendar g = (c instanceof GregorianCalendar) ? (GregorianCalendar)c : new GregorianCalendar();
int year = c.get(Calendar.YEAR);
int day = 0;
for( int y=1970; y<year; ++y )
{
day += g.isLeapYear(y) ? 366 : 365;
}
day += c.get(Calendar.DAY_OF_YEAR);
return day;
}
private long getEpochForCalendar(Calendar c)
{
return c.getTime().getTime();
}
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
case 0:
{
// queueEvent
queueLuaEvent( getString( args, 0 ), trimArray( args, 1 ) );
return null;
}
case 1:
{
// startTimer
double timer = getReal( args, 0 );
synchronized( m_timers )
{
m_timers.put( m_nextTimerToken, new Timer( (int)Math.round( timer / 0.05 ) ) );
return new Object[] { m_nextTimerToken++ }; return new Object[] { m_nextTimerToken++ };
} }
} }
case 2: case 2:
{ {
// setAlarm // setAlarm
if( args.length < 1 || args[0] == null || !(args[0] instanceof Number) ) double time = getReal( args, 0 );
{ if( time < 0.0 || time >= 24.0 )
throw new LuaException( "Expected number" ); {
} throw new LuaException( "Number out of range" );
double time = ((Number)args[0]).doubleValue(); }
if( time < 0.0 || time >= 24.0 ) synchronized( m_alarms )
{ {
throw new LuaException( "Number out of range" );
}
synchronized( m_alarms )
{
int day = (time > m_time) ? m_day : (m_day + 1); int day = (time > m_time) ? m_day : (m_day + 1);
m_alarms.put( m_nextAlarmToken, new Alarm( time, day ) ); m_alarms.put( m_nextAlarmToken, new Alarm( time, day ) );
return new Object[] { m_nextAlarmToken++ }; return new Object[] { m_nextAlarmToken++ };
} }
} }
case 3: case 3:
{ {
// shutdown // shutdown
m_apiEnvironment.shutdown(); m_apiEnvironment.shutdown();
return null; return null;
} }
case 4: case 4:
{ {
// reboot // reboot
m_apiEnvironment.reboot(); m_apiEnvironment.reboot();
return null; return null;
} }
case 5: case 5:
case 6: case 6:
{ {
// computerID/getComputerID // computerID/getComputerID
return new Object[] { getComputerID() }; return new Object[] { getComputerID() };
} }
case 7: case 7:
{ {
// setComputerLabel // setComputerLabel
String label = null; String label = optString( args, 0, null );
if( args.length > 0 && args[0] != null ) m_apiEnvironment.setLabel( StringUtil.normaliseLabel( label ) );
{ return null;
if(!(args[0] instanceof String)) }
{ case 8:
throw new LuaException( "Expected string or nil" ); case 9:
} {
label = (String)args[0]; // computerLabel/getComputerLabel
if( label.length() > 32 ) String label = m_apiEnvironment.getLabel();
if( label != null )
{
return new Object[] { label };
}
return null;
}
case 10:
{
// clock
synchronized( m_timers )
{
return new Object[] { (double)m_clock * 0.05 };
}
}
case 11:
{
// time
String param = optString( args, 0, "ingame" );
switch( param )
{
case "utc":
{ {
label = label.substring( 0, 32 ); // Get Hour of day (UTC)
Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
return new Object[] { getTimeForCalendar( c ) };
} }
} case "local":
m_apiEnvironment.setLabel( label ); {
return null; // Get Hour of day (local time)
} Calendar c = Calendar.getInstance();
case 8: return new Object[] { getTimeForCalendar( c ) };
case 9: }
{ case "ingame":
// computerLabel/getComputerLabel // Get ingame hour
String label = m_apiEnvironment.getLabel(); synchronized( m_alarms )
if( label != null ) {
{ return new Object[] { m_time };
return new Object[] { label }; }
} default:
return null; throw new LuaException( "Unsupported operation" );
} }
case 10: }
{ case 12:
// clock {
synchronized( m_timers ) // day
{ String param = optString( args, 0, "ingame" );
return new Object[] { (double)m_clock * 0.05 }; switch( param )
} {
} case "utc":
case 11: {
{ // Get numbers of days since 1970-01-01 (utc)
// m_time Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
synchronized( m_alarms ) return new Object[] { getDayForCalendar( c ) };
{ }
return new Object[] { m_time }; case "local":
} {
} // Get numbers of days since 1970-01-01 (local time)
case 12: Calendar c = Calendar.getInstance();
{ return new Object[] { getDayForCalendar( c ) };
// day }
synchronized( m_alarms ) case "ingame":
{ // Get game day
return new Object[] { m_day }; synchronized( m_alarms )
} {
} return new Object[] { m_day };
}
default:
throw new LuaException( "Unsupported operation" );
}
}
case 13: case 13:
{ {
// cancelTimer // cancelTimer
if( args.length < 1 || args[0] == null || !(args[0] instanceof Number) ) int token = getInt( args, 0 );
{
throw new LuaException( "Expected number" );
}
int token = ((Number)args[0]).intValue();
synchronized( m_timers ) synchronized( m_timers )
{ {
if( m_timers.containsKey( token ) ) if( m_timers.containsKey( token ) )
@@ -330,11 +371,7 @@ public class OSAPI implements ILuaAPI
case 14: case 14:
{ {
// cancelAlarm // cancelAlarm
if( args.length < 1 || args[0] == null || !(args[0] instanceof Number) ) int token = getInt( args, 0 );
{
throw new LuaException( "Expected number" );
}
int token = ((Number)args[0]).intValue();
synchronized( m_alarms ) synchronized( m_alarms )
{ {
if( m_alarms.containsKey( token ) ) if( m_alarms.containsKey( token ) )
@@ -344,27 +381,57 @@ public class OSAPI implements ILuaAPI
} }
return null; return null;
} }
default: case 15:
{ {
return null; // epoch
} String param = optString( args, 0, "ingame" );
} switch( param )
} {
case "utc":
{
// Get utc epoch
Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
return new Object[] { getEpochForCalendar( c ) };
}
case "local":
{
// Get local epoch
Calendar c = Calendar.getInstance();
return new Object[] { getEpochForCalendar( c ) };
}
case "ingame":
// Get in-game epoch
synchronized( m_alarms )
{
return new Object[] {
m_day * 86400000 + (int) (m_time * 3600000.0f)
};
}
default:
throw new LuaException( "Unsupported operation" );
}
}
default:
{
return null;
}
}
}
// Private methods // Private methods
private void queueLuaEvent( String event, Object[] args ) private void queueLuaEvent( String event, Object[] args )
{ {
m_apiEnvironment.queueEvent( event, args ); m_apiEnvironment.queueEvent( event, args );
} }
private Object[] trimArray( Object[] array, int skip ) private Object[] trimArray( Object[] array, int skip )
{ {
return Arrays.copyOfRange( array, skip, array.length ); return Arrays.copyOfRange( array, skip, array.length );
} }
private int getComputerID() private int getComputerID()
{ {
return m_apiEnvironment.getComputerID(); return m_apiEnvironment.getComputerID();
} }
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -18,252 +18,256 @@ import dan200.computercraft.core.computer.ITask;
import dan200.computercraft.core.filesystem.FileSystem; import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.filesystem.FileSystemException; import dan200.computercraft.core.filesystem.FileSystemException;
import javax.annotation.Nonnull;
import java.util.*; import java.util.*;
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener
{ {
private class PeripheralWrapper implements IComputerAccess private class PeripheralWrapper implements IComputerAccess
{ {
private final String m_side; private final String m_side;
private final IPeripheral m_peripheral; private final IPeripheral m_peripheral;
private String m_type; private String m_type;
private String[] m_methods; private String[] m_methods;
private Map<String, Integer> m_methodMap; private Map<String, Integer> m_methodMap;
private boolean m_attached; private boolean m_attached;
private Set<String> m_mounts; private Set<String> m_mounts;
public PeripheralWrapper( IPeripheral peripheral, String side ) public PeripheralWrapper( IPeripheral peripheral, String side )
{ {
m_side = side; m_side = side;
m_peripheral = peripheral; m_peripheral = peripheral;
m_attached = false; m_attached = false;
m_type = peripheral.getType(); m_type = peripheral.getType();
m_methods = peripheral.getMethodNames(); m_methods = peripheral.getMethodNames();
assert( m_type != null ); assert( m_type != null );
assert( m_methods != null ); assert( m_methods != null );
m_methodMap = new HashMap<String, Integer>(); m_methodMap = new HashMap<>();
for(int i=0; i<m_methods.length; ++i ) { for(int i=0; i<m_methods.length; ++i ) {
if( m_methods[i] != null ) { if( m_methods[i] != null ) {
m_methodMap.put( m_methods[i], i ); m_methodMap.put( m_methods[i], i );
} }
} }
m_mounts = new HashSet<String>(); m_mounts = new HashSet<>();
} }
public IPeripheral getPeripheral() public IPeripheral getPeripheral()
{ {
return m_peripheral; return m_peripheral;
} }
public String getType() public String getType()
{ {
return m_type; return m_type;
} }
public String[] getMethods() public String[] getMethods()
{ {
return m_methods; return m_methods;
} }
public synchronized boolean isAttached() public synchronized boolean isAttached()
{ {
return m_attached; return m_attached;
} }
public synchronized void attach() public synchronized void attach()
{ {
m_attached = true; m_attached = true;
m_peripheral.attach( this ); m_peripheral.attach( this );
} }
public synchronized void detach() public synchronized void detach()
{ {
// Call detach // Call detach
m_peripheral.detach( this ); m_peripheral.detach( this );
m_attached = false; m_attached = false;
// Unmount everything the detach function forgot to do // Unmount everything the detach function forgot to do
Iterator<String> it = m_mounts.iterator(); for( String m_mount : m_mounts )
while( it.hasNext() ) { {
m_fileSystem.unmount( it.next() ); m_fileSystem.unmount( m_mount );
} }
m_mounts.clear(); m_mounts.clear();
} }
public Object[] call( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException public Object[] call( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException
{ {
int method = -1; int method = -1;
synchronized( this ) synchronized( this )
{ {
if( m_methodMap.containsKey( methodName ) ) if( m_methodMap.containsKey( methodName ) )
{ {
method = m_methodMap.get( methodName ); method = m_methodMap.get( methodName );
} }
} }
if( method >= 0 ) if( method >= 0 )
{ {
return m_peripheral.callMethod( this, context, method, arguments ); return m_peripheral.callMethod( this, context, method, arguments );
} }
else else
{ {
throw new LuaException( "No such method " + methodName ); throw new LuaException( "No such method " + methodName );
} }
} }
// IComputerAccess implementation // IComputerAccess implementation
@Override @Override
public String mount( String desiredLoc, IMount mount ) public String mount( @Nonnull String desiredLoc, @Nonnull IMount mount )
{ {
return mount( desiredLoc, mount, m_side ); return mount( desiredLoc, mount, m_side );
} }
@Override @Override
public synchronized String mount( String desiredLoc, IMount mount, String driveName ) public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName )
{ {
if( !m_attached ) if( !m_attached )
{ {
throw new RuntimeException( "You are not attached to this Computer" ); throw new RuntimeException( "You are not attached to this Computer" );
} }
// Mount the location // Mount the location
String location = null; String location;
synchronized( m_fileSystem ) synchronized( m_fileSystem )
{ {
location = findFreeLocation( desiredLoc ); location = findFreeLocation( desiredLoc );
if( location != null ) if( location != null )
{ {
try { try {
m_fileSystem.mount( driveName, location, mount ); m_fileSystem.mount( driveName, location, mount );
} catch( FileSystemException e ) { } catch( FileSystemException e ) {
// fail and return null // fail and return null
} }
} }
} }
if( location != null ) if( location != null )
{ {
m_mounts.add( location ); m_mounts.add( location );
} }
return location; return location;
} }
@Override @Override
public String mountWritable( String desiredLoc, IWritableMount mount ) public String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount )
{ {
return mountWritable( desiredLoc, mount, m_side ); return mountWritable( desiredLoc, mount, m_side );
} }
@Override @Override
public synchronized String mountWritable( String desiredLoc, IWritableMount mount, String driveName ) public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName )
{ {
if( !m_attached ) if( !m_attached )
{ {
throw new RuntimeException( "You are not attached to this Computer" ); throw new RuntimeException( "You are not attached to this Computer" );
} }
// Mount the location // Mount the location
String location = null; String location;
synchronized( m_fileSystem ) synchronized( m_fileSystem )
{ {
location = findFreeLocation( desiredLoc ); location = findFreeLocation( desiredLoc );
if( location != null ) if( location != null )
{ {
try { try {
m_fileSystem.mountWritable( driveName, location, mount ); m_fileSystem.mountWritable( driveName, location, mount );
} catch( FileSystemException e ) { } catch( FileSystemException e ) {
// fail and return null // fail and return null
} }
} }
} }
if( location != null ) if( location != null )
{ {
m_mounts.add( location ); m_mounts.add( location );
} }
return location; return location;
} }
@Override @Override
public synchronized void unmount( String location ) public synchronized void unmount( String location )
{ {
if( !m_attached ) { if( !m_attached ) {
throw new RuntimeException( "You are not attached to this Computer" ); throw new RuntimeException( "You are not attached to this Computer" );
} }
if( location != null ) if( location != null )
{ {
if( !m_mounts.contains( location ) ) { if( !m_mounts.contains( location ) ) {
throw new RuntimeException( "You didn't mount this location" ); throw new RuntimeException( "You didn't mount this location" );
} }
m_fileSystem.unmount( location ); m_fileSystem.unmount( location );
m_mounts.remove( location ); m_mounts.remove( location );
} }
} }
@Override @Override
public synchronized int getID() public synchronized int getID()
{ {
if( !m_attached ) { if( !m_attached ) {
throw new RuntimeException( "You are not attached to this Computer" ); throw new RuntimeException( "You are not attached to this Computer" );
} }
return m_environment.getComputerID(); return m_environment.getComputerID();
} }
@Override @Override
public synchronized void queueEvent( final String event, final Object[] arguments ) public synchronized void queueEvent( @Nonnull final String event, final Object[] arguments )
{ {
if( !m_attached ) { if( !m_attached ) {
throw new RuntimeException( "You are not attached to this Computer" ); throw new RuntimeException( "You are not attached to this Computer" );
} }
m_environment.queueEvent( event, arguments ); m_environment.queueEvent( event, arguments );
} }
@Override @Nonnull
public synchronized String getAttachmentName() @Override
{ public synchronized String getAttachmentName()
if( !m_attached ) { {
throw new RuntimeException( "You are not attached to this Computer" ); if( !m_attached ) {
} throw new RuntimeException( "You are not attached to this Computer" );
return m_side; }
} return m_side;
} }
}
private IAPIEnvironment m_environment;
private FileSystem m_fileSystem; private final IAPIEnvironment m_environment;
private PeripheralWrapper[] m_peripherals; private FileSystem m_fileSystem;
private boolean m_running; private final PeripheralWrapper[] m_peripherals;
private boolean m_running;
public PeripheralAPI( IAPIEnvironment _environment ) public PeripheralAPI( IAPIEnvironment _environment )
{ {
m_environment = _environment; m_environment = _environment;
m_environment.setPeripheralChangeListener( this ); m_environment.setPeripheralChangeListener( this );
m_peripherals = new PeripheralWrapper[6]; m_peripherals = new PeripheralWrapper[6];
for(int i=0; i<6; ++i) for(int i=0; i<6; ++i)
{ {
m_peripherals[i] = null; m_peripherals[i] = null;
} }
m_running = false; m_running = false;
} }
// IPeripheralChangeListener // IPeripheralChangeListener
@Override @Override
public void onPeripheralChanged( int side, IPeripheral newPeripheral ) public void onPeripheralChanged( int side, IPeripheral newPeripheral )
{ {
synchronized( m_peripherals ) synchronized( m_peripherals )
{ {
if( m_peripherals[side] != null ) if( m_peripherals[side] != null )
{ {
// Queue a detachment // Queue a detachment
final PeripheralWrapper wrapper = m_peripherals[side]; final PeripheralWrapper wrapper = m_peripherals[side];
ComputerThread.queueTask(new ITask() { ComputerThread.queueTask(new ITask() {
@Override @Override
public Computer getOwner() { public Computer getOwner() {
return m_environment.getComputer(); return m_environment.getComputer();
@@ -278,257 +282,249 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
} }
} }
}, null); }, null);
// Queue a detachment event // Queue a detachment event
m_environment.queueEvent( "peripheral_detach", new Object[] { Computer.s_sideNames[side] } ); m_environment.queueEvent( "peripheral_detach", new Object[] { Computer.s_sideNames[side] } );
} }
// Assign the new peripheral // Assign the new peripheral
if( newPeripheral != null ) if( newPeripheral != null )
{ {
m_peripherals[side] = new PeripheralWrapper( newPeripheral, Computer.s_sideNames[side] ); m_peripherals[side] = new PeripheralWrapper( newPeripheral, Computer.s_sideNames[side] );
} }
else else
{ {
m_peripherals[side] = null; m_peripherals[side] = null;
} }
if( m_peripherals[side] != null ) if( m_peripherals[side] != null )
{ {
// Queue an attachment // Queue an attachment
final PeripheralWrapper wrapper = m_peripherals[side]; final PeripheralWrapper wrapper = m_peripherals[side];
ComputerThread.queueTask( new ITask() { ComputerThread.queueTask( new ITask() {
@Override @Override
public Computer getOwner() { public Computer getOwner() {
return m_environment.getComputer(); return m_environment.getComputer();
} }
@Override @Override
public void execute() { public void execute() {
synchronized( m_peripherals ) synchronized( m_peripherals )
{ {
if( m_running && !wrapper.isAttached() ) if( m_running && !wrapper.isAttached() )
{ {
wrapper.attach(); wrapper.attach();
} }
} }
} }
}, null ); }, null );
// Queue an attachment event // Queue an attachment event
m_environment.queueEvent( "peripheral", new Object[] { Computer.s_sideNames[side] } ); m_environment.queueEvent( "peripheral", new Object[] { Computer.s_sideNames[side] } );
} }
} }
} }
// ILuaAPI implementation // ILuaAPI implementation
@Override @Override
public String[] getNames() public String[] getNames()
{ {
return new String[] { return new String[] {
"peripheral" "peripheral"
}; };
} }
@Override @Override
public void startup( ) public void startup( )
{ {
synchronized( m_peripherals ) synchronized( m_peripherals )
{ {
m_fileSystem = m_environment.getFileSystem(); m_fileSystem = m_environment.getFileSystem();
m_running = true; m_running = true;
for( int i=0; i<6; ++i ) for( int i=0; i<6; ++i )
{ {
PeripheralWrapper wrapper = m_peripherals[i]; PeripheralWrapper wrapper = m_peripherals[i];
if( wrapper != null && !wrapper.isAttached() ) if( wrapper != null && !wrapper.isAttached() )
{ {
wrapper.attach(); wrapper.attach();
} }
} }
} }
} }
@Override @Override
public void advance( double _dt ) public void advance( double _dt )
{ {
} }
@Override @Override
public void shutdown( ) public void shutdown( )
{ {
synchronized( m_peripherals ) synchronized( m_peripherals )
{ {
m_running = false; m_running = false;
for( int i=0; i<6; ++i ) for( int i=0; i<6; ++i )
{ {
PeripheralWrapper wrapper = m_peripherals[i]; PeripheralWrapper wrapper = m_peripherals[i];
if( wrapper != null && wrapper.isAttached() ) if( wrapper != null && wrapper.isAttached() )
{ {
wrapper.detach(); wrapper.detach();
} }
} }
m_fileSystem = null; m_fileSystem = null;
} }
} }
@Override @Nonnull
@Override
public String[] getMethodNames() public String[] getMethodNames()
{ {
return new String[] { return new String[] {
"isPresent", "isPresent",
"getType", "getType",
"getMethods", "getMethods",
"call" "call"
}; };
} }
@Override @Override
public Object[] callMethod( ILuaContext context, int method, Object[] args ) throws LuaException, InterruptedException public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException
{ {
switch( method ) switch( method )
{
case 0:
{
// isPresent
boolean present = false;
int side = parseSide( args );
if( side >= 0 )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[ side ];
if( p != null )
{
present = true;
}
}
}
return new Object[] { present };
}
case 1:
{
// getType
String type = null;
int side = parseSide( args );
if( side >= 0 )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[ side ];
if( p != null )
{
type = p.getType();
}
}
if( type != null )
{
return new Object[] { type };
}
}
return null;
}
case 2:
{
// getMethods
String[] methods = null;
int side = parseSide( args );
if( side >= 0 )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[ side ];
if( p != null )
{
methods = p.getMethods();
}
}
}
if( methods != null )
{
Map<Object,Object> table = new HashMap<Object,Object>();
for(int i=0; i<methods.length; ++i ) {
table.put( i+1, methods[i] );
}
return new Object[] { table };
}
return null;
}
case 3:
{
// call
if( args.length < 2 || args[1] == null || !(args[1] instanceof String) )
{
throw new LuaException( "Expected string, string" );
}
String methodName = (String)args[1];
Object[] methodArgs = trimArray( args, 2 );
int side = parseSide( args );
if( side >= 0 )
{
PeripheralWrapper p = null;
synchronized( m_peripherals )
{
p = m_peripherals[ side ];
}
if( p != null )
{
Object[] results = p.call( context, methodName, methodArgs );
return results;
}
}
throw new LuaException( "No peripheral attached" );
}
default:
{
return null;
}
}
}
// Privates
private Object[] trimArray( Object[] array, int skip )
{
return Arrays.copyOfRange( array, skip, array.length );
}
private int parseSide( Object[] args ) throws LuaException
{
if( args.length < 1 || args[0] == null || !(args[0] instanceof String) )
{
throw new LuaException( "Expected string" );
}
String side = (String)args[0];
for( int n=0; n<Computer.s_sideNames.length; ++n )
{ {
if( side.equals( Computer.s_sideNames[n] ) ) case 0:
{ {
return n; // isPresent
} boolean present = false;
} int side = parseSide( args );
return -1; if( side >= 0 )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[ side ];
if( p != null )
{
present = true;
}
}
}
return new Object[] { present };
}
case 1:
{
// getType
String type = null;
int side = parseSide( args );
if( side >= 0 )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[ side ];
if( p != null )
{
type = p.getType();
}
}
if( type != null )
{
return new Object[] { type };
}
}
return null;
}
case 2:
{
// getMethods
String[] methods = null;
int side = parseSide( args );
if( side >= 0 )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[ side ];
if( p != null )
{
methods = p.getMethods();
}
}
}
if( methods != null )
{
Map<Object,Object> table = new HashMap<>();
for(int i=0; i<methods.length; ++i ) {
table.put( i+1, methods[i] );
}
return new Object[] { table };
}
return null;
}
case 3:
{
// call
int side = parseSide( args );
String methodName = getString( args, 1 );
Object[] methodArgs = trimArray( args, 2 );
if( side >= 0 )
{
PeripheralWrapper p;
synchronized( m_peripherals )
{
p = m_peripherals[ side ];
}
if( p != null )
{
return p.call( context, methodName, methodArgs );
}
}
throw new LuaException( "No peripheral attached" );
}
default:
{
return null;
}
}
}
// Privates
private Object[] trimArray( Object[] array, int skip )
{
return Arrays.copyOfRange( array, skip, array.length );
}
private int parseSide( Object[] args ) throws LuaException
{
String side = getString( args, 0 );
for( int n=0; n<Computer.s_sideNames.length; ++n )
{
if( side.equals( Computer.s_sideNames[n] ) )
{
return n;
}
}
return -1;
}
private String findFreeLocation( String desiredLoc )
{
try
{
synchronized( m_fileSystem )
{
if( !m_fileSystem.exists( desiredLoc ) )
{
return desiredLoc;
}
// We used to check foo2,foo3,foo4,etc here
// but the disk drive does this itself now
return null;
}
}
catch( FileSystemException e )
{
return null;
}
} }
private String findFreeLocation( String desiredLoc )
{
try
{
synchronized( m_fileSystem )
{
if( !m_fileSystem.exists( desiredLoc ) )
{
return desiredLoc;
}
// We used to check foo2,foo3,foo4,etc here
// but the disk drive does this itself now
return null;
}
}
catch( FileSystemException e )
{
return null;
}
}
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -10,189 +10,173 @@ import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.Computer;
import javax.annotation.Nonnull;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static dan200.computercraft.core.apis.ArgumentHelper.*;
public class RedstoneAPI implements ILuaAPI public class RedstoneAPI implements ILuaAPI
{ {
private IAPIEnvironment m_environment; private IAPIEnvironment m_environment;
public RedstoneAPI( IAPIEnvironment environment ) public RedstoneAPI( IAPIEnvironment environment )
{ {
m_environment = environment; m_environment = environment;
} }
@Override @Override
public String[] getNames() public String[] getNames()
{ {
return new String[] { return new String[] {
"rs", "redstone" "rs", "redstone"
}; };
} }
@Override @Override
public void startup( ) public void startup( )
{ {
} }
@Override @Override
public void advance( double _dt ) public void advance( double _dt )
{ {
} }
@Override @Override
public void shutdown( ) public void shutdown( )
{ {
} }
@Override @Nonnull
@Override
public String[] getMethodNames() public String[] getMethodNames()
{ {
return new String[] { return new String[] {
"getSides", "getSides",
"setOutput", "setOutput",
"getOutput", "getOutput",
"getInput", "getInput",
"setBundledOutput", "setBundledOutput",
"getBundledOutput", "getBundledOutput",
"getBundledInput", "getBundledInput",
"testBundledInput", "testBundledInput",
"setAnalogOutput", "setAnalogOutput",
"setAnalogueOutput", "setAnalogueOutput",
"getAnalogOutput", "getAnalogOutput",
"getAnalogueOutput", "getAnalogueOutput",
"getAnalogInput", "getAnalogInput",
"getAnalogueInput", "getAnalogueInput",
}; };
} }
@Override @Override
public Object[] callMethod( ILuaContext context, int method, Object[] args ) throws LuaException public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{ {
switch( method ) switch( method )
{
case 0:
{
// getSides
Map<Object,Object> table = new HashMap<Object,Object>();
for(int i=0; i< Computer.s_sideNames.length; ++i )
{
table.put( i+1, Computer.s_sideNames[i] );
}
return new Object[] { table };
}
case 1:
{
// setOutput
if( args.length < 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof Boolean) )
{
throw new LuaException( "Expected string, boolean" );
}
int side = parseSide( args );
boolean output = ((Boolean)args[1]).booleanValue();
m_environment.setOutput( side, output ? 15 : 0 );
return null;
}
case 2:
{
// getOutput
int side = parseSide( args );
return new Object[] { m_environment.getOutput( side ) > 0 };
}
case 3:
{
// getInput
int side = parseSide( args );
return new Object[] { m_environment.getInput( side ) > 0 };
}
case 4:
{
// setBundledOutput
if( args.length < 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof Double) )
{
throw new LuaException( "Expected string, number" );
}
int side = parseSide( args );
int output = ((Double)args[1]).intValue();
m_environment.setBundledOutput( side, output );
return null;
}
case 5:
{
// getBundledOutput
int side = parseSide( args );
return new Object[] { m_environment.getBundledOutput( side ) };
}
case 6:
{
// getBundledInput
int side = parseSide( args );
return new Object[] { m_environment.getBundledInput( side ) };
}
case 7:
{
// testBundledInput
if( args.length < 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof Double) )
{
throw new LuaException( "Expected string, number" );
}
int side = parseSide( args );
int mask = ((Double)args[1]).intValue();
int input = m_environment.getBundledInput( side );
return new Object[] { ((input & mask) == mask) };
}
case 8:
case 9:
{
// setAnalogOutput/setAnalogueOutput
if( args.length < 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof Double) )
{
throw new LuaException( "Expected string, number" );
}
int side = parseSide( args );
int output = ((Double)args[1]).intValue();
if( output < 0 || output > 15 )
{
throw new LuaException( "Expected number in range 0-15" );
}
m_environment.setOutput( side, output );
return null;
}
case 10:
case 11:
{
// getAnalogOutput/getAnalogueOutput
int side = parseSide( args );
return new Object[] { m_environment.getOutput( side ) };
}
case 12:
case 13:
{
// getAnalogInput/getAnalogueInput
int side = parseSide( args );
return new Object[] { m_environment.getInput( side ) };
}
default:
{
return null;
}
}
}
private int parseSide( Object[] args ) throws LuaException
{
if( args.length < 1 || args[0] == null || !(args[0] instanceof String) )
{
throw new LuaException( "Expected string" );
}
String side = (String)args[0];
for( int n=0; n<Computer.s_sideNames.length; ++n )
{ {
if( side.equals( Computer.s_sideNames[n] ) ) case 0:
{ {
return n; // getSides
} Map<Object,Object> table = new HashMap<>();
} for(int i=0; i< Computer.s_sideNames.length; ++i )
throw new LuaException( "Invalid side." ); {
table.put( i+1, Computer.s_sideNames[i] );
}
return new Object[] { table };
}
case 1:
{
// setOutput
int side = parseSide( args );
boolean output = getBoolean( args, 1 );
m_environment.setOutput( side, output ? 15 : 0 );
return null;
}
case 2:
{
// getOutput
int side = parseSide( args );
return new Object[] { m_environment.getOutput( side ) > 0 };
}
case 3:
{
// getInput
int side = parseSide( args );
return new Object[] { m_environment.getInput( side ) > 0 };
}
case 4:
{
// setBundledOutput
int side = parseSide( args );
int output = getInt( args, 1 );
m_environment.setBundledOutput( side, output );
return null;
}
case 5:
{
// getBundledOutput
int side = parseSide( args );
return new Object[] { m_environment.getBundledOutput( side ) };
}
case 6:
{
// getBundledInput
int side = parseSide( args );
return new Object[] { m_environment.getBundledInput( side ) };
}
case 7:
{
// testBundledInput
int side = parseSide( args );
int mask = getInt( args, 1 );
int input = m_environment.getBundledInput( side );
return new Object[] { ((input & mask) == mask) };
}
case 8:
case 9:
{
// setAnalogOutput/setAnalogueOutput
int side = parseSide( args );
int output = getInt( args, 1 );
if( output < 0 || output > 15 )
{
throw new LuaException( "Expected number in range 0-15" );
}
m_environment.setOutput( side, output );
return null;
}
case 10:
case 11:
{
// getAnalogOutput/getAnalogueOutput
int side = parseSide( args );
return new Object[] { m_environment.getOutput( side ) };
}
case 12:
case 13:
{
// getAnalogInput/getAnalogueInput
int side = parseSide( args );
return new Object[] { m_environment.getInput( side ) };
}
default:
{
return null;
}
}
}
private int parseSide( Object[] args ) throws LuaException
{
String side = getString( args, 0 );
for( int n=0; n<Computer.s_sideNames.length; ++n )
{
if( side.equals( Computer.s_sideNames[n] ) )
{
return n;
}
}
throw new LuaException( "Invalid side." );
} }
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -10,88 +10,91 @@ import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.computer.IComputerEnvironment; import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.util.Palette;
import org.apache.commons.lang3.ArrayUtils;
import javax.annotation.Nonnull;
import static dan200.computercraft.core.apis.ArgumentHelper.*;
public class TermAPI implements ILuaAPI public class TermAPI implements ILuaAPI
{ {
private Terminal m_terminal; private final Terminal m_terminal;
private IComputerEnvironment m_environment; private final IComputerEnvironment m_environment;
public TermAPI( IAPIEnvironment _environment ) public TermAPI( IAPIEnvironment _environment )
{ {
m_terminal = _environment.getTerminal(); m_terminal = _environment.getTerminal();
m_environment = _environment.getComputerEnvironment(); m_environment = _environment.getComputerEnvironment();
} }
@Override @Override
public String[] getNames() public String[] getNames()
{ {
return new String[] { return new String[] {
"term" "term"
}; };
} }
@Override @Override
public void startup( ) public void startup( )
{ {
} }
@Override @Override
public void advance( double _dt ) public void advance( double _dt )
{ {
} }
@Override @Override
public void shutdown( ) public void shutdown( )
{ {
} }
@Override @Nonnull
@Override
public String[] getMethodNames() public String[] getMethodNames()
{ {
return new String[] { return new String[] {
"write", "write",
"scroll", "scroll",
"setCursorPos", "setCursorPos",
"setCursorBlink", "setCursorBlink",
"getCursorPos", "getCursorPos",
"getSize", "getSize",
"clear", "clear",
"clearLine", "clearLine",
"setTextColour", "setTextColour",
"setTextColor", "setTextColor",
"setBackgroundColour", "setBackgroundColour",
"setBackgroundColor", "setBackgroundColor",
"isColour", "isColour",
"isColor", "isColor",
"getTextColour", "getTextColour",
"getTextColor", "getTextColor",
"getBackgroundColour", "getBackgroundColour",
"getBackgroundColor", "getBackgroundColor",
"blit" "blit",
}; "setPaletteColour",
"setPaletteColor",
"getPaletteColour",
"getPaletteColor"
};
} }
public static int parseColour( Object[] args, boolean _enableColours ) throws LuaException public static int parseColour( Object[] args ) throws LuaException
{ {
if( args.length != 1 || args[0] == null || !(args[0] instanceof Double) ) int colour = getInt( args, 0 );
{ if( colour <= 0 )
throw new LuaException( "Expected number" ); {
} throw new LuaException( "Colour out of range" );
int colour = (int)((Double)args[0]).doubleValue(); }
if( colour <= 0 ) colour = getHighestBit( colour ) - 1;
{ if( colour < 0 || colour > 15 )
throw new LuaException( "Colour out of range" ); {
} throw new LuaException( "Colour out of range" );
colour = getHighestBit( colour ) - 1; }
if( colour < 0 || colour > 15 ) return colour;
{
throw new LuaException( "Colour out of range" );
}
if( !_enableColours && (colour != 0 && colour != 15 && colour != 7 && colour != 8) )
{
throw new LuaException( "Colour not supported" );
}
return colour;
} }
public static Object[] encodeColour( int colour ) throws LuaException public static Object[] encodeColour( int colour ) throws LuaException
@@ -101,140 +104,136 @@ public class TermAPI implements ILuaAPI
}; };
} }
@Override public static void setColour( Terminal terminal, int colour, double r, double g, double b )
public Object[] callMethod( ILuaContext context, int method, Object[] args ) throws LuaException
{ {
switch( method ) if( terminal.getPalette() != null )
{ {
case 0: terminal.getPalette().setColour( colour, r, g, b );
{ terminal.setChanged();
// write }
String text; }
if( args.length > 0 && args[0] != null ) {
text = args[0].toString(); @Override
} else { public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
text = ""; {
} switch( method )
{
synchronized( m_terminal ) case 0:
{ {
m_terminal.write( text ); // write
m_terminal.setCursorPos( m_terminal.getCursorX() + text.length(), m_terminal.getCursorY() ); String text;
} if( args.length > 0 && args[0] != null ) {
return null; text = args[0].toString();
} } else {
case 1: text = "";
{ }
// scroll
if( args.length != 1 || args[0] == null || !(args[0] instanceof Double) ) synchronized( m_terminal )
{ {
throw new LuaException( "Expected number" ); m_terminal.write( text );
} m_terminal.setCursorPos( m_terminal.getCursorX() + text.length(), m_terminal.getCursorY() );
}
int y = (int)((Double)args[0]).doubleValue(); return null;
synchronized( m_terminal ) }
{ case 1:
m_terminal.scroll(y); {
} // scroll
return null; int y = getInt( args, 0 );
} synchronized( m_terminal )
case 2: {
{ m_terminal.scroll(y);
// setCursorPos }
if( args.length != 2 || args[0] == null || !(args[0] instanceof Double) || args[1] == null || !(args[1] instanceof Double) ) return null;
{ }
throw new LuaException( "Expected number, number" ); case 2:
} {
int x = (int)((Double)args[0]).doubleValue() - 1; // setCursorPos
int y = (int)((Double)args[1]).doubleValue() - 1; int x = getInt( args, 0 ) - 1;
synchronized( m_terminal ) int y = getInt( args, 1 ) - 1;
{ synchronized( m_terminal )
m_terminal.setCursorPos( x, y ); {
} m_terminal.setCursorPos( x, y );
return null; }
} return null;
case 3: }
{ case 3:
// setCursorBlink {
if( args.length != 1 || args[0] == null || !(args[0] instanceof Boolean) ) // setCursorBlink
{ boolean b = getBoolean( args, 0 );
throw new LuaException( "Expected boolean" ); synchronized( m_terminal )
} {
boolean b = ((Boolean)args[0]).booleanValue(); m_terminal.setCursorBlink( b );
synchronized( m_terminal ) }
{ return null;
m_terminal.setCursorBlink( b ); }
} case 4:
return null; {
} // getCursorPos
case 4: int x, y;
{ synchronized( m_terminal )
// getCursorPos {
int x, y; x = m_terminal.getCursorX();
synchronized( m_terminal ) y = m_terminal.getCursorY();
{ }
x = m_terminal.getCursorX(); return new Object[] { x + 1, y + 1 };
y = m_terminal.getCursorY(); }
} case 5:
return new Object[] { x + 1, y + 1 }; {
} // getSize
case 5: int width, height;
{ synchronized( m_terminal )
// getSize {
int width, height; width = m_terminal.getWidth();
synchronized( m_terminal ) height = m_terminal.getHeight();
{ }
width = m_terminal.getWidth(); return new Object[] { width, height };
height = m_terminal.getHeight(); }
} case 6:
return new Object[] { width, height }; {
} // clear
case 6: synchronized( m_terminal )
{ {
// clear m_terminal.clear();
synchronized( m_terminal ) }
{ return null;
m_terminal.clear(); }
} case 7:
return null; {
} // clearLine
case 7: synchronized( m_terminal )
{ {
// clearLine m_terminal.clearLine();
synchronized( m_terminal ) }
{ return null;
m_terminal.clearLine(); }
} case 8:
return null; case 9:
} {
case 8: // setTextColour/setTextColor
case 9: int colour = parseColour( args );
{ synchronized( m_terminal )
// setTextColour/setTextColor {
int colour = parseColour( args, m_environment.isColour() ); m_terminal.setTextColour( colour );
synchronized( m_terminal ) }
{ return null;
m_terminal.setTextColour( colour ); }
} case 10:
return null; case 11:
} {
case 10: // setBackgroundColour/setBackgroundColor
case 11: int colour = parseColour( args );
{ synchronized( m_terminal )
// setBackgroundColour/setBackgroundColor {
int colour = parseColour( args, m_environment.isColour() ); m_terminal.setBackgroundColour( colour );
synchronized( m_terminal ) }
{ return null;
m_terminal.setBackgroundColour( colour ); }
} case 12:
return null; case 13:
} {
case 12: // isColour/isColor
case 13: return new Object[] { m_environment.isColour() };
{ }
// isColour/isColor
return new Object[] { m_environment.isColour() };
}
case 14: case 14:
case 15: case 15:
{ {
@@ -250,14 +249,9 @@ public class TermAPI implements ILuaAPI
case 18: case 18:
{ {
// blit // blit
if( args.length < 3 || !(args[0] instanceof String) || !(args[1] instanceof String) || !(args[2] instanceof String) ) String text = getString( args, 0 );
{ String textColour = getString( args, 1 );
throw new LuaException( "Expected string, string, string" ); String backgroundColour = getString( args, 2 );
}
String text = (String)args[0];
String textColour = (String)args[1];
String backgroundColour = (String)args[2];
if( textColour.length() != text.length() || backgroundColour.length() != text.length() ) if( textColour.length() != text.length() || backgroundColour.length() != text.length() )
{ {
throw new LuaException( "Arguments must be the same length" ); throw new LuaException( "Arguments must be the same length" );
@@ -270,21 +264,55 @@ public class TermAPI implements ILuaAPI
} }
return null; return null;
} }
default: case 19:
{ case 20:
return null; {
} // setPaletteColour/setPaletteColor
} int colour = 15 - parseColour( args );
} if( args.length == 2 )
{
private static int getHighestBit( int group ) int hex = getInt( args, 1 );
{ double[] rgb = Palette.decodeRGB8( hex );
int bit = 0; setColour( m_terminal, colour, rgb[ 0 ], rgb[ 1 ], rgb[ 2 ] );
while( group > 0 ) }
{ else
group >>= 1; {
bit++; double r = getReal( args, 1 );
} double g = getReal( args, 2 );
return bit; double b = getReal( args, 3 );
} setColour( m_terminal, colour, r, g, b );
}
return null;
}
case 21:
case 22:
{
// getPaletteColour/getPaletteColor
int colour = 15 - parseColour( args );
synchronized( m_terminal )
{
if ( m_terminal.getPalette() != null )
{
return ArrayUtils.toObject( m_terminal.getPalette().getColour( colour ) );
}
}
return null;
}
default:
{
return null;
}
}
}
private static int getHighestBit( int group )
{
int bit = 0;
while( group > 0 )
{
group >>= 1;
bit++;
}
return bit;
}
} }

View File

@@ -0,0 +1,89 @@
package dan200.computercraft.core.apis.handles;
import com.google.common.io.ByteStreams;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
public class BinaryInputHandle extends HandleGeneric
{
private final InputStream m_stream;
public BinaryInputHandle( InputStream reader )
{
super( reader );
this.m_stream = reader;
}
@Nonnull
@Override
public String[] getMethodNames()
{
return new String[] {
"read",
"readAll",
"close",
};
}
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
case 0:
// read
checkOpen();
try
{
if( args.length > 0 && args[ 0 ] != null )
{
int count = getInt( args, 0 );
if( count <= 0 || count >= 1024 * 16 )
{
throw new LuaException( "Count out of range" );
}
byte[] bytes = new byte[ count ];
count = m_stream.read( bytes );
if( count < 0 ) return null;
if( count < bytes.length ) bytes = Arrays.copyOf( bytes, count );
return new Object[] { bytes };
}
else
{
int b = m_stream.read();
return b == -1 ? null : new Object[] { b };
}
}
catch( IOException e )
{
return null;
}
case 1:
// readAll
checkOpen();
try
{
byte[] out = ByteStreams.toByteArray( m_stream );
return out == null ? null : new Object[] { out };
}
catch( IOException e )
{
return null;
}
case 2:
//close
close();
return null;
default:
return null;
}
}
}

View File

@@ -0,0 +1,83 @@
package dan200.computercraft.core.apis.handles;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.apis.ArgumentHelper;
import dan200.computercraft.shared.util.StringUtil;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.OutputStream;
public class BinaryOutputHandle extends HandleGeneric
{
private final OutputStream m_writer;
public BinaryOutputHandle( OutputStream writer )
{
super( writer );
this.m_writer = writer;
}
@Nonnull
@Override
public String[] getMethodNames()
{
return new String[] {
"write",
"flush",
"close",
};
}
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
case 0:
// write
checkOpen();
try
{
if( args.length > 0 && args[ 0 ] instanceof Number )
{
int number = ((Number) args[ 0 ]).intValue();
m_writer.write( number );
}
else if( args.length > 0 && args[ 0 ] instanceof String )
{
String value = (String) args[ 0 ];
m_writer.write( StringUtil.encodeString( value ) );
}
else
{
throw ArgumentHelper.badArgument( 0, "string or number", args.length > 0 ? args[ 0 ] : null );
}
return null;
}
catch( IOException e )
{
throw new LuaException( e.getMessage() );
}
case 1:
// flush
checkOpen();
try
{
m_writer.flush();
return null;
}
catch( IOException e )
{
return null;
}
case 2:
//close
close();
return null;
default:
return null;
}
}
}

View File

@@ -0,0 +1,109 @@
package dan200.computercraft.core.apis.handles;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nonnull;
import java.io.*;
public class EncodedInputHandle extends HandleGeneric
{
private final BufferedReader m_reader;
public EncodedInputHandle( BufferedReader reader )
{
super( reader );
this.m_reader = reader;
}
public EncodedInputHandle( InputStream stream )
{
this( stream, "UTF-8" );
}
public EncodedInputHandle( InputStream stream, String encoding )
{
this( makeReader( stream, encoding ) );
}
private static BufferedReader makeReader( InputStream stream, String encoding )
{
if( encoding == null ) encoding = "UTF-8";
InputStreamReader streamReader;
try
{
streamReader = new InputStreamReader( stream, encoding );
}
catch( UnsupportedEncodingException e )
{
streamReader = new InputStreamReader( stream );
}
return new BufferedReader( streamReader );
}
@Nonnull
@Override
public String[] getMethodNames()
{
return new String[] {
"readLine",
"readAll",
"close",
};
}
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
case 0:
// readLine
checkOpen();
try
{
String line = m_reader.readLine();
if( line != null )
{
return new Object[] { line };
}
else
{
return null;
}
}
catch( IOException e )
{
return null;
}
case 1:
// readAll
checkOpen();
try
{
StringBuilder result = new StringBuilder( "" );
String line = m_reader.readLine();
while( line != null )
{
result.append( line );
line = m_reader.readLine();
if( line != null )
{
result.append( "\n" );
}
}
return new Object[] { result.toString() };
}
catch( IOException e )
{
return null;
}
case 2:
// close
close();
return null;
default:
return null;
}
}
}

View File

@@ -0,0 +1,128 @@
package dan200.computercraft.core.apis.handles;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nonnull;
import java.io.*;
public class EncodedOutputHandle extends HandleGeneric
{
private final BufferedWriter m_writer;
public EncodedOutputHandle( BufferedWriter writer )
{
super( writer );
this.m_writer = writer;
}
public EncodedOutputHandle( OutputStream stream )
{
this( stream, "UTF-8" );
}
public EncodedOutputHandle( OutputStream stream, String encoding )
{
this( makeWriter( stream, encoding ) );
}
private static BufferedWriter makeWriter( OutputStream stream, String encoding )
{
if( encoding == null ) encoding = "UTF-8";
OutputStreamWriter streamWriter;
try
{
streamWriter = new OutputStreamWriter( stream, encoding );
}
catch( UnsupportedEncodingException e )
{
streamWriter = new OutputStreamWriter( stream );
}
return new BufferedWriter( streamWriter );
}
@Nonnull
@Override
public String[] getMethodNames()
{
return new String[] {
"write",
"writeLine",
"flush",
"close",
};
}
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
case 0:
{
// write
checkOpen();
String text;
if( args.length > 0 && args[ 0 ] != null )
{
text = args[ 0 ].toString();
}
else
{
text = "";
}
try
{
m_writer.write( text, 0, text.length() );
return null;
}
catch( IOException e )
{
throw new LuaException( e.getMessage() );
}
}
case 1:
{
// writeLine
checkOpen();
String text;
if( args.length > 0 && args[ 0 ] != null )
{
text = args[ 0 ].toString();
}
else
{
text = "";
}
try
{
m_writer.write( text, 0, text.length() );
m_writer.newLine();
return null;
}
catch( IOException e )
{
throw new LuaException( e.getMessage() );
}
}
case 2:
// flush
checkOpen();
try
{
m_writer.flush();
return null;
}
catch( IOException e )
{
return null;
}
case 3:
// close
close();
return null;
default:
return null;
}
}
}

View File

@@ -0,0 +1,35 @@
package dan200.computercraft.core.apis.handles;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException;
import java.io.Closeable;
import java.io.IOException;
public abstract class HandleGeneric implements ILuaObject
{
protected final Closeable m_closable;
protected boolean m_open = true;
public HandleGeneric( Closeable m_closable )
{
this.m_closable = m_closable;
}
protected void checkOpen() throws LuaException
{
if( !m_open ) throw new LuaException( "attempt to use a closed file" );
}
protected void close()
{
try
{
m_closable.close();
m_open = false;
}
catch( IOException ignored )
{
}
}
}

View File

@@ -0,0 +1,45 @@
package dan200.computercraft.core.apis.http;
import dan200.computercraft.core.apis.HTTPRequestException;
import dan200.computercraft.core.apis.IAPIEnvironment;
import java.net.URL;
public class HTTPCheck implements HTTPTask.IHTTPTask
{
private final String urlString;
private final URL url;
private String error;
public HTTPCheck( String urlString, URL url )
{
this.urlString = urlString;
this.url = url;
}
@Override
public void run()
{
try
{
HTTPRequest.checkHost( url );
}
catch( HTTPRequestException e )
{
error = e.getMessage();
}
}
@Override
public void whenFinished( IAPIEnvironment environment )
{
if( error == null )
{
environment.queueEvent( "http_check", new Object[] { urlString, true } );
}
else
{
environment.queueEvent( "http_check", new Object[] { urlString, false, error } );
}
}
}

View File

@@ -0,0 +1,289 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.apis.http;
import com.google.common.base.Joiner;
import com.google.common.io.ByteStreams;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.apis.HTTPRequestException;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.apis.handles.BinaryInputHandle;
import dan200.computercraft.core.apis.handles.EncodedInputHandle;
import javax.annotation.Nonnull;
import java.io.*;
import java.net.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HTTPRequest implements HTTPTask.IHTTPTask
{
public static URL checkURL( String urlString ) throws HTTPRequestException
{
URL url;
try
{
url = new URL( urlString );
}
catch( MalformedURLException e )
{
throw new HTTPRequestException( "URL malformed" );
}
// Validate the URL
String protocol = url.getProtocol().toLowerCase();
if( !protocol.equals( "http" ) && !protocol.equals( "https" ) )
{
throw new HTTPRequestException( "URL not http" );
}
// Compare the URL to the whitelist
if( !ComputerCraft.http_whitelist.matches( url.getHost() ) || ComputerCraft.http_blacklist.matches( url.getHost() ) )
{
throw new HTTPRequestException( "Domain not permitted" );
}
return url;
}
public static InetAddress checkHost( URL url ) throws HTTPRequestException
{
try
{
InetAddress resolved = InetAddress.getByName( url.getHost() );
if( !ComputerCraft.http_whitelist.matches( resolved ) || ComputerCraft.http_blacklist.matches( resolved ) )
{
throw new HTTPRequestException( "Domain not permitted" );
}
return resolved;
}
catch( UnknownHostException e )
{
throw new HTTPRequestException( "Unknown host" );
}
}
private final URL m_url;
private final String m_urlString;
private final String m_postText;
private final Map<String, String> m_headers;
private boolean m_success = false;
private String m_encoding;
private byte[] m_result;
private boolean m_binary;
private int m_responseCode = -1;
private Map<String, String> m_responseHeaders;
private String m_errorMessage;
public HTTPRequest( String urlString, URL url, final String postText, final Map<String, String> headers, boolean binary ) throws HTTPRequestException
{
// Parse the URL
m_urlString = urlString;
m_url = url;
m_binary = binary;
m_postText = postText;
m_headers = headers;
}
public InputStream getContents()
{
byte[] result = m_result;
if( result != null )
{
return new ByteArrayInputStream( result );
}
return null;
}
@Override
public void run()
{
// First verify the address is allowed.
try
{
checkHost( m_url );
}
catch( HTTPRequestException e )
{
m_success = false;
m_errorMessage = e.getMessage();
return;
}
try
{
// Connect to the URL
HttpURLConnection connection = (HttpURLConnection) m_url.openConnection();
if( m_postText != null )
{
connection.setRequestMethod( "POST" );
connection.setDoOutput( true );
}
else
{
connection.setRequestMethod( "GET" );
}
// Set headers
connection.setRequestProperty( "accept-charset", "UTF-8" );
if( m_postText != null )
{
connection.setRequestProperty( "content-type", "application/x-www-form-urlencoded; charset=utf-8" );
}
if( m_headers != null )
{
for( Map.Entry<String, String> header : m_headers.entrySet() )
{
connection.setRequestProperty( header.getKey(), header.getValue() );
}
}
// Send POST text
if( m_postText != null )
{
OutputStream os = connection.getOutputStream();
OutputStreamWriter osw;
try
{
osw = new OutputStreamWriter( os, "UTF-8" );
}
catch( UnsupportedEncodingException e )
{
osw = new OutputStreamWriter( os );
}
BufferedWriter writer = new BufferedWriter( osw );
writer.write( m_postText, 0, m_postText.length() );
writer.close();
}
// Read response
InputStream is;
int code = connection.getResponseCode();
boolean responseSuccess;
if( code >= 200 && code < 400 )
{
is = connection.getInputStream();
responseSuccess = true;
}
else
{
is = connection.getErrorStream();
responseSuccess = false;
}
byte[] result = ByteStreams.toByteArray( is );
is.close();
// We completed
m_success = responseSuccess;
m_result = result;
m_responseCode = connection.getResponseCode();
m_encoding = connection.getContentEncoding();
Joiner joiner = Joiner.on( ',' );
Map<String, String> headers = m_responseHeaders = new HashMap<String, String>();
for( Map.Entry<String, List<String>> header : connection.getHeaderFields().entrySet() )
{
headers.put( header.getKey(), joiner.join( header.getValue() ) );
}
connection.disconnect(); // disconnect
}
catch( IOException e )
{
// There was an error
m_success = false;
}
}
@Override
public void whenFinished( IAPIEnvironment environment )
{
final String url = m_urlString;
if( m_success )
{
// Queue the "http_success" event
InputStream contents = getContents();
Object result = wrapStream(
m_binary ? new BinaryInputHandle( contents ) : new EncodedInputHandle( contents, m_encoding ),
m_responseCode, m_responseHeaders
);
environment.queueEvent( "http_success", new Object[] { url, result } );
}
else
{
// Queue the "http_failure" event
String error = "Could not connect";
if( m_errorMessage != null ) error = m_errorMessage;
InputStream contents = getContents();
Object result = null;
if( contents != null )
{
result = wrapStream(
m_binary ? new BinaryInputHandle( contents ) : new EncodedInputHandle( contents, m_encoding ),
m_responseCode, m_responseHeaders
);
}
environment.queueEvent( "http_failure", new Object[] { url, error, result } );
}
}
private static ILuaObject wrapStream( final ILuaObject reader, final int responseCode, final Map<String, String> responseHeaders )
{
String[] oldMethods = reader.getMethodNames();
final int methodOffset = oldMethods.length;
final String[] newMethods = Arrays.copyOf( oldMethods, oldMethods.length + 2 );
newMethods[ methodOffset + 0 ] = "getResponseCode";
newMethods[ methodOffset + 1 ] = "getResponseHeaders";
return new ILuaObject()
{
@Nonnull
@Override
public String[] getMethodNames()
{
return newMethods;
}
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException
{
if( method < methodOffset )
{
return reader.callMethod( context, method, args );
}
switch( method - methodOffset )
{
case 0:
{
// getResponseCode
return new Object[] { responseCode };
}
case 1:
{
// getResponseHeaders
return new Object[] { responseHeaders };
}
default:
{
return null;
}
}
}
};
}
}

View File

@@ -0,0 +1,61 @@
package dan200.computercraft.core.apis.http;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import dan200.computercraft.core.apis.IAPIEnvironment;
import java.util.concurrent.*;
/**
* A task which executes asynchronously on a new thread.
*
* This functions very similarly to a {@link Future}, but with an additional
* method which is called on the main thread when the task is completed.
*/
public class HTTPTask
{
public interface IHTTPTask extends Runnable
{
void whenFinished( IAPIEnvironment environment );
}
private static final ExecutorService httpThreads = new ThreadPoolExecutor(
4, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadFactoryBuilder()
.setDaemon( true )
.setPriority( Thread.MIN_PRIORITY + (Thread.NORM_PRIORITY - Thread.MIN_PRIORITY) / 2 )
.setNameFormat( "ComputerCraft-HTTP-%d" )
.build()
);
private final Future<?> future;
private final IHTTPTask task;
private HTTPTask( Future<?> future, IHTTPTask task )
{
this.future = future;
this.task = task;
}
public static HTTPTask submit( IHTTPTask task )
{
Future<?> future = httpThreads.submit( task );
return new HTTPTask( future, task );
}
public void cancel()
{
future.cancel( false );
}
public boolean isFinished()
{
return future.isDone();
}
public void whenFinished( IAPIEnvironment environment )
{
task.whenFinished( environment );
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,215 +1,215 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.core.computer; package dan200.computercraft.core.computer;
import dan200.computercraft.ComputerCraft;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
public class ComputerThread public class ComputerThread
{ {
private static Object m_lock; private static final Object m_lock;
private static Thread m_thread; private static Thread m_thread;
private static WeakHashMap <Object, LinkedBlockingQueue<ITask>> m_computerTasks; private static final WeakHashMap <Object, LinkedBlockingQueue<ITask>> m_computerTasks;
private static ArrayList <LinkedBlockingQueue<ITask>> m_computerTasksActive; private static final ArrayList <LinkedBlockingQueue<ITask>> m_computerTasksActive;
private static ArrayList <LinkedBlockingQueue<ITask>> m_computerTasksPending; private static final ArrayList <LinkedBlockingQueue<ITask>> m_computerTasksPending;
private static Object m_defaultQueue; private static final Object m_defaultQueue;
private static Object m_monitor; private static final Object m_monitor;
private static boolean m_running; private static boolean m_running;
private static boolean m_stopped; private static boolean m_stopped;
static static
{ {
m_lock = new Object(); m_lock = new Object();
m_thread = null; m_thread = null;
m_computerTasks = new WeakHashMap<Object, LinkedBlockingQueue<ITask>>(); m_computerTasks = new WeakHashMap<>();
m_computerTasksPending = new ArrayList<LinkedBlockingQueue<ITask>>(); m_computerTasksPending = new ArrayList<>();
m_computerTasksActive = new ArrayList<LinkedBlockingQueue<ITask>>(); m_computerTasksActive = new ArrayList<>();
m_defaultQueue = new Object(); m_defaultQueue = new Object();
m_monitor = new Object(); m_monitor = new Object();
m_running = false; m_running = false;
m_stopped = false; m_stopped = false;
} }
public static void start() public static void start()
{ {
synchronized( m_lock ) synchronized( m_lock )
{ {
if( m_running ) if( m_running )
{ {
m_stopped = false; m_stopped = false;
return; return;
} }
m_thread = new Thread( new Runnable() { m_thread = new Thread( () ->
public void run() {
{ while( true )
while( true ) {
{ synchronized( m_computerTasksPending )
synchronized( m_computerTasksPending ) {
{ if (!m_computerTasksPending.isEmpty())
if (!m_computerTasksPending.isEmpty()) {
{ Iterator<LinkedBlockingQueue<ITask>> it = m_computerTasksPending.iterator();
Iterator<LinkedBlockingQueue<ITask>> it = m_computerTasksPending.iterator(); while(it.hasNext())
while(it.hasNext()) {
{ LinkedBlockingQueue<ITask> queue = it.next();
LinkedBlockingQueue<ITask> queue = it.next();
if (!m_computerTasksActive.contains(queue))
if (!m_computerTasksActive.contains(queue)) {
{ m_computerTasksActive.add(queue);
m_computerTasksActive.add(queue); }
} it.remove();
it.remove(); }
} /*
/* m_computerTasksActive.addAll(m_computerTasksPending); // put any that have been added since
m_computerTasksActive.addAll(m_computerTasksPending); // put any that have been added since m_computerTasksPending.clear();
m_computerTasksPending.clear(); */
*/ }
} }
}
Iterator<LinkedBlockingQueue<ITask>> it = m_computerTasksActive.iterator();
Iterator<LinkedBlockingQueue<ITask>> it = m_computerTasksActive.iterator();
while (it.hasNext())
while (it.hasNext()) {
{ LinkedBlockingQueue<ITask> queue = it.next();
LinkedBlockingQueue<ITask> queue = it.next();
if (queue == null || queue.isEmpty()) // we don't need the blocking part of the queue. Null check to ensure it exists due to a weird NPE I got
if (queue == null || queue.isEmpty()) // we don't need the blocking part of the queue. Null check to ensure it exists due to a weird NPE I got {
{ continue;
continue; }
}
synchronized( m_lock )
synchronized( m_lock ) {
{ if( m_stopped )
if( m_stopped ) {
{ m_running = false;
m_running = false; m_thread = null;
m_thread = null; return;
return; }
} }
}
try
try {
{ final ITask task = queue.take();
final ITask task = queue.take();
// Create the task // Create the task
Thread worker = new Thread( new Runnable() { Thread worker = new Thread( () ->
public void run() { {
try { try {
task.execute(); task.execute();
} catch( Throwable e ) { } catch( Throwable e ) {
System.out.println( "ComputerCraft: Error running task." ); ComputerCraft.log.error( "Error running task", e );
e.printStackTrace(); }
} } );
}
} ); // Run the task
worker.setDaemon(true);
// Run the task worker.start();
worker.start(); worker.join( 7000 );
worker.join( 7000 );
if( worker.isAlive() )
if( worker.isAlive() ) {
{ // Task ran for too long
// Task ran for too long // Initiate escape plan
// Initiate escape plan Computer computer = task.getOwner();
Computer computer = task.getOwner(); if( computer != null )
if( computer != null ) {
{ // Step 1: Soft abort
// Step 1: Soft abort computer.abort( false );
computer.abort( false ); worker.join( 1500 );
worker.join( 1500 );
if( worker.isAlive() )
if( worker.isAlive() ) {
{ // Step 2: Hard abort
// Step 2: Hard abort computer.abort( true );
computer.abort( true ); worker.join( 1500 );
worker.join( 1500 ); }
} }
}
// Step 3: abandon
// Step 3: abandon if( worker.isAlive() )
if( worker.isAlive() ) {
{ // ComputerCraft.log.warn( "Failed to abort Computer " + computer.getID() + ". Dangling lua thread could cause errors." );
//System.out.println( "computercraft: Warning! Failed to abort Computer " + computercraft.getDescription() + ". Dangling lua thread could cause errors." ); worker.interrupt();
worker.interrupt(); }
} }
} }
} catch( InterruptedException e )
catch( InterruptedException e ) {
{ continue;
continue; }
}
synchronized (queue) synchronized (queue)
{ {
if (queue.isEmpty()) if (queue.isEmpty())
{ {
it.remove(); it.remove();
} }
} }
} }
while (m_computerTasksActive.isEmpty() && m_computerTasksPending.isEmpty()) while (m_computerTasksActive.isEmpty() && m_computerTasksPending.isEmpty())
{ {
synchronized (m_monitor) synchronized (m_monitor)
{ {
try try
{ {
m_monitor.wait(); m_monitor.wait();
} }
catch( InterruptedException e ) catch( InterruptedException e )
{ {
} }
} }
} }
} }
} }, "Computer Dispatch Thread" );
}, "Computer Dispatch Thread" );
m_thread.start();
m_running = true;
}
}
public static void stop()
{
synchronized( m_lock )
{
if( m_running )
{
m_stopped = true;
m_thread.interrupt();
}
}
}
public static void queueTask( ITask _task, Computer computer )
{
Object queueObject = computer;
if (queueObject == null)
{
queueObject = m_defaultQueue;
}
LinkedBlockingQueue<ITask> queue = m_computerTasks.get(queueObject);
if (queue == null) m_thread.setDaemon(true);
{ m_thread.start();
m_computerTasks.put(queueObject, queue = new LinkedBlockingQueue<ITask>(256)); m_running = true;
} }
}
synchronized ( m_computerTasksPending )
{ public static void stop()
if( queue.offer( _task ) ) {
synchronized( m_lock )
{
if( m_running )
{
m_stopped = true;
m_thread.interrupt();
}
}
}
public static void queueTask( ITask _task, Computer computer )
{
Object queueObject = computer;
if (queueObject == null)
{
queueObject = m_defaultQueue;
}
LinkedBlockingQueue<ITask> queue = m_computerTasks.get(queueObject);
if (queue == null)
{
m_computerTasks.put(queueObject, queue = new LinkedBlockingQueue<>( 256 ));
}
synchronized ( m_computerTasksPending )
{
if( queue.offer( _task ) )
{ {
if( !m_computerTasksPending.contains( queue ) ) if( !m_computerTasksPending.contains( queue ) )
{ {
@@ -220,11 +220,11 @@ public class ComputerThread
{ {
//System.out.println( "Event queue overflow" ); //System.out.println( "Event queue overflow" );
} }
} }
synchronized (m_monitor) synchronized (m_monitor)
{ {
m_monitor.notify(); m_monitor.notify();
} }
} }
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -8,15 +8,18 @@ package dan200.computercraft.core.computer;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.filesystem.IWritableMount;
import java.io.InputStream;
public interface IComputerEnvironment public interface IComputerEnvironment
{ {
public int getDay(); int getDay();
public double getTimeOfDay(); double getTimeOfDay();
public boolean isColour(); boolean isColour();
public long getComputerSpaceLimit(); long getComputerSpaceLimit();
public String getHostString(); String getHostString();
public int assignNewID(); int assignNewID();
public IWritableMount createSaveDirMount( String subPath, long capacity ); IWritableMount createSaveDirMount( String subPath, long capacity );
public IMount createResourceMount( String domain, String subPath ); IMount createResourceMount( String domain, String subPath );
InputStream createResourceFile( String domain, String subPath );
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -8,6 +8,6 @@ package dan200.computercraft.core.computer;
public interface ITask public interface ITask
{ {
public Computer getOwner(); Computer getOwner();
public void execute(); void execute();
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -13,7 +13,7 @@ public class MainThread
private static final int MAX_TASKS_PER_TICK = 1000; private static final int MAX_TASKS_PER_TICK = 1000;
private static final int MAX_TASKS_TOTAL = 50000; private static final int MAX_TASKS_TOTAL = 50000;
private static final LinkedList<ITask> m_outstandingTasks = new LinkedList<ITask>(); private static final LinkedList<ITask> m_outstandingTasks = new LinkedList<>();
private static final Object m_nextUnusedTaskIDLock = new Object(); private static final Object m_nextUnusedTaskIDLock = new Object();
private static long m_nextUnusedTaskID = 0; private static long m_nextUnusedTaskID = 0;

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -8,6 +8,7 @@ package dan200.computercraft.core.filesystem;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
@@ -16,113 +17,113 @@ import java.util.List;
import java.util.Set; import java.util.Set;
public class ComboMount implements IMount public class ComboMount implements IMount
{ {
private IMount[] m_parts; private IMount[] m_parts;
public ComboMount( IMount[] parts ) public ComboMount( IMount[] parts )
{ {
m_parts = parts; m_parts = parts;
} }
// IMount implementation // IMount implementation
@Override @Override
public boolean exists( String path ) throws IOException public boolean exists( @Nonnull String path ) throws IOException
{ {
for( int i=m_parts.length-1; i>=0; --i ) for( int i=m_parts.length-1; i>=0; --i )
{ {
IMount part = m_parts[i]; IMount part = m_parts[i];
if( part.exists( path ) ) if( part.exists( path ) )
{ {
return true; return true;
} }
} }
return false; return false;
} }
@Override @Override
public boolean isDirectory( String path ) throws IOException public boolean isDirectory( @Nonnull String path ) throws IOException
{ {
for( int i=m_parts.length-1; i>=0; --i ) for( int i=m_parts.length-1; i>=0; --i )
{ {
IMount part = m_parts[i]; IMount part = m_parts[i];
if( part.isDirectory( path ) ) if( part.isDirectory( path ) )
{ {
return true; return true;
} }
} }
return false; return false;
} }
@Override @Override
public void list( String path, List<String> contents ) throws IOException public void list( @Nonnull String path, @Nonnull List<String> contents ) throws IOException
{ {
// Combine the lists from all the mounts // Combine the lists from all the mounts
List<String> foundFiles = null; List<String> foundFiles = null;
int foundDirs = 0; int foundDirs = 0;
for( int i=m_parts.length-1; i>=0; --i ) for( int i=m_parts.length-1; i>=0; --i )
{ {
IMount part = m_parts[i]; IMount part = m_parts[i];
if( part.exists( path ) && part.isDirectory( path ) ) if( part.exists( path ) && part.isDirectory( path ) )
{ {
if( foundFiles == null ) if( foundFiles == null )
{ {
foundFiles = new ArrayList<String>(); foundFiles = new ArrayList<>();
} }
part.list( path, foundFiles ); part.list( path, foundFiles );
foundDirs++; foundDirs++;
} }
} }
if( foundDirs == 1 ) if( foundDirs == 1 )
{ {
// We found one directory, so we know it already doesn't contain duplicates // We found one directory, so we know it already doesn't contain duplicates
contents.addAll( foundFiles ); contents.addAll( foundFiles );
} }
else if( foundDirs > 1 ) else if( foundDirs > 1 )
{ {
// We found multiple directories, so filter for duplicates // We found multiple directories, so filter for duplicates
Set<String> seen = new HashSet<String>(); Set<String> seen = new HashSet<>();
for( int i=0; i<foundFiles.size(); ++i ) for(String file : foundFiles)
{ {
String file = foundFiles.get(i); if( seen.add( file ) )
if( seen.add( file ) ) {
{ contents.add( file );
contents.add( file ); }
} }
} }
} else
else {
{ throw new IOException( "/" + path + ": Not a directory" );
throw new IOException( "Not a directory" ); }
} }
}
@Override
@Override public long getSize( @Nonnull String path ) throws IOException
public long getSize( String path ) throws IOException {
{ for( int i=m_parts.length-1; i>=0; --i )
for( int i=m_parts.length-1; i>=0; --i ) {
{ IMount part = m_parts[i];
IMount part = m_parts[i]; if( part.exists( path ) )
if( part.exists( path ) ) {
{ return part.getSize( path );
return part.getSize( path ); }
} }
} throw new IOException( "/" + path + ": No such file" );
throw new IOException( "No such file" ); }
}
@Override @Nonnull
public InputStream openForRead( String path ) throws IOException @Override
{ public InputStream openForRead( @Nonnull String path ) throws IOException
for( int i=m_parts.length-1; i>=0; --i ) {
{ for( int i=m_parts.length-1; i>=0; --i )
IMount part = m_parts[i]; {
if( part.exists( path ) && !part.isDirectory( path ) ) IMount part = m_parts[i];
{ if( part.exists( path ) && !part.isDirectory( path ) )
return part.openForRead( path ); {
} return part.openForRead( path );
} }
throw new IOException( "No such file" ); }
} throw new IOException( "/" + path + ": No such file" );
}
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -8,44 +8,46 @@ package dan200.computercraft.core.filesystem;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
public class EmptyMount implements IMount public class EmptyMount implements IMount
{ {
public EmptyMount() public EmptyMount()
{ {
} }
// IMount implementation // IMount implementation
@Override @Override
public boolean exists( String path ) throws IOException public boolean exists( @Nonnull String path ) throws IOException
{ {
return path.isEmpty(); return path.isEmpty();
} }
@Override @Override
public boolean isDirectory( String path ) throws IOException public boolean isDirectory( @Nonnull String path ) throws IOException
{ {
return path.isEmpty(); return path.isEmpty();
} }
@Override @Override
public void list( String path, List<String> contents ) throws IOException public void list( @Nonnull String path, @Nonnull List<String> contents ) throws IOException
{ {
} }
@Override @Override
public long getSize( String path ) throws IOException public long getSize( @Nonnull String path ) throws IOException
{ {
return 0; return 0;
} }
@Override @Nonnull
public InputStream openForRead( String path ) throws IOException @Override
{ public InputStream openForRead( @Nonnull String path ) throws IOException
return null; {
} return null;
}
} }

View File

@@ -1,6 +1,6 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
@@ -8,208 +8,210 @@ package dan200.computercraft.core.filesystem;
import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.filesystem.IWritableMount;
import javax.annotation.Nonnull;
import java.io.*; import java.io.*;
import java.util.List; import java.util.List;
public class FileMount implements IWritableMount public class FileMount implements IWritableMount
{ {
private static int MINIMUM_FILE_SIZE = 500; private static int MINIMUM_FILE_SIZE = 500;
private class CountingOutputStream extends OutputStream private class CountingOutputStream extends OutputStream
{ {
private OutputStream m_innerStream; private OutputStream m_innerStream;
private long m_ignoredBytesLeft; private long m_ignoredBytesLeft;
public CountingOutputStream( OutputStream innerStream, long bytesToIgnore ) public CountingOutputStream( OutputStream innerStream, long bytesToIgnore )
{ {
m_innerStream = innerStream; m_innerStream = innerStream;
m_ignoredBytesLeft = bytesToIgnore; m_ignoredBytesLeft = bytesToIgnore;
} }
@Override @Override
public void close() throws IOException public void close() throws IOException
{ {
m_innerStream.close(); m_innerStream.close();
} }
@Override @Override
public void flush() throws IOException public void flush() throws IOException
{ {
m_innerStream.flush(); m_innerStream.flush();
} }
@Override @Override
public void write( byte[] b ) throws IOException public void write( @Nonnull byte[] b ) throws IOException
{ {
count( b.length ); count( b.length );
m_innerStream.write( b ); m_innerStream.write( b );
} }
@Override @Override
public void write( byte[] b, int off, int len ) throws IOException public void write( @Nonnull byte[] b, int off, int len ) throws IOException
{ {
count( len ); count( len );
m_innerStream.write( b, off, len ); m_innerStream.write( b, off, len );
} }
@Override @Override
public void write( int b ) throws IOException public void write( int b ) throws IOException
{ {
count( 1 ); count( 1 );
m_innerStream.write( b ); m_innerStream.write( b );
} }
private void count( long n ) throws IOException private void count( long n ) throws IOException
{ {
m_ignoredBytesLeft -= n; m_ignoredBytesLeft -= n;
if( m_ignoredBytesLeft < 0 ) if( m_ignoredBytesLeft < 0 )
{ {
long newBytes = -m_ignoredBytesLeft; long newBytes = -m_ignoredBytesLeft;
m_ignoredBytesLeft = 0; m_ignoredBytesLeft = 0;
long bytesLeft = m_capacity - m_usedSpace; long bytesLeft = m_capacity - m_usedSpace;
if( newBytes > bytesLeft ) if( newBytes > bytesLeft )
{ {
throw new IOException( "Out of space" ); throw new IOException( "Out of space" );
} }
else else
{ {
m_usedSpace += newBytes; m_usedSpace += newBytes;
} }
} }
} }
} }
private File m_rootPath; private File m_rootPath;
private long m_capacity; private long m_capacity;
private long m_usedSpace; private long m_usedSpace;
public FileMount( File rootPath, long capacity ) public FileMount( File rootPath, long capacity )
{ {
m_rootPath = rootPath; m_rootPath = rootPath;
m_capacity = capacity + MINIMUM_FILE_SIZE; m_capacity = capacity + MINIMUM_FILE_SIZE;
m_usedSpace = created() ? measureUsedSpace( m_rootPath ) : MINIMUM_FILE_SIZE; m_usedSpace = created() ? measureUsedSpace( m_rootPath ) : MINIMUM_FILE_SIZE;
} }
// IMount implementation // IMount implementation
@Override @Override
public boolean exists( String path ) throws IOException public boolean exists( @Nonnull String path ) throws IOException
{ {
if( !created() ) if( !created() )
{ {
return path.length() == 0; return path.length() == 0;
} }
else else
{ {
File file = getRealPath( path ); File file = getRealPath( path );
return file.exists(); return file.exists();
} }
} }
@Override @Override
public boolean isDirectory( String path ) throws IOException public boolean isDirectory( @Nonnull String path ) throws IOException
{ {
if( !created() ) if( !created() )
{ {
return path.length() == 0; return path.length() == 0;
} }
else else
{ {
File file = getRealPath( path ); File file = getRealPath( path );
return file.exists() && file.isDirectory(); return file.exists() && file.isDirectory();
} }
} }
@Override @Override
public void list( String path, List<String> contents ) throws IOException public void list( @Nonnull String path, @Nonnull List<String> contents ) throws IOException
{ {
if( !created() ) if( !created() )
{ {
if( path.length() != 0 ) if( path.length() != 0 )
{ {
throw new IOException( "Not a directory" ); throw new IOException( "/" + path + ": Not a directory" );
} }
} }
else else
{ {
File file = getRealPath( path ); File file = getRealPath( path );
if( file.exists() && file.isDirectory() ) if( file.exists() && file.isDirectory() )
{ {
String[] paths = file.list(); String[] paths = file.list();
for( String subPath : paths ) for( String subPath : paths )
{ {
if( new File( file, subPath ).exists() ) if( new File( file, subPath ).exists() )
{ {
contents.add( subPath ); contents.add( subPath );
} }
} }
} }
else else
{ {
throw new IOException( "Not a directory" ); throw new IOException( "/" + path + ": Not a directory" );
} }
} }
} }
@Override @Override
public long getSize( String path ) throws IOException public long getSize( @Nonnull String path ) throws IOException
{ {
if( !created() ) if( !created() )
{ {
if( path.length() == 0 ) if( path.length() == 0 )
{ {
return 0; return 0;
} }
} }
else else
{ {
File file = getRealPath( path ); File file = getRealPath( path );
if( file.exists() ) if( file.exists() )
{ {
if( file.isDirectory() ) if( file.isDirectory() )
{ {
return 0; return 0;
} }
else else
{ {
return file.length(); return file.length();
} }
} }
} }
throw new IOException( "No such file" ); throw new IOException( "/" + path + ": No such file" );
} }
@Override @Nonnull
public InputStream openForRead( String path ) throws IOException @Override
{ public InputStream openForRead( @Nonnull String path ) throws IOException
if( created() ) {
{ if( created() )
File file = getRealPath( path ); {
if( file.exists() && !file.isDirectory() ) File file = getRealPath( path );
{ if( file.exists() && !file.isDirectory() )
return new FileInputStream( file ); {
} return new FileInputStream( file );
} }
throw new IOException( "No such file" ); }
} throw new IOException( "/" + path + ": No such file" );
}
// IWritableMount implementation
// IWritableMount implementation
@Override
public void makeDirectory( String path ) throws IOException @Override
{ public void makeDirectory( @Nonnull String path ) throws IOException
create(); {
File file = getRealPath( path ); create();
if( file.exists() ) File file = getRealPath( path );
{ if( file.exists() )
if( !file.isDirectory() ) {
{ if( !file.isDirectory() )
throw new IOException( "File exists" ); {
} throw new IOException( "/" + path + ": File exists" );
} }
else }
{ else
{
int dirsToCreate = 1; int dirsToCreate = 1;
File parent = file.getParentFile(); File parent = file.getParentFile();
while( !parent.exists() ) while( !parent.exists() )
@@ -218,169 +220,171 @@ public class FileMount implements IWritableMount
parent = parent.getParentFile(); parent = parent.getParentFile();
} }
if( getRemainingSpace() < dirsToCreate * MINIMUM_FILE_SIZE ) if( getRemainingSpace() < dirsToCreate * MINIMUM_FILE_SIZE )
{ {
throw new IOException( "Out of space" ); throw new IOException( "/" + path + ": Out of space" );
} }
boolean success = file.mkdirs(); boolean success = file.mkdirs();
if( success ) if( success )
{ {
m_usedSpace += dirsToCreate * MINIMUM_FILE_SIZE; m_usedSpace += dirsToCreate * MINIMUM_FILE_SIZE;
} }
else else
{ {
throw new IOException( "Access denied" ); throw new IOException( "/" + path + ": Access denied" );
} }
} }
}
@Override
public void delete( String path ) throws IOException
{
if( path.length() == 0 )
{
throw new IOException( "Access denied" );
}
if( created() )
{
File file = getRealPath( path );
if( file.exists() )
{
deleteRecursively( file );
}
}
}
private void deleteRecursively( File file ) throws IOException
{
// Empty directories first
if( file.isDirectory() )
{
String[] children = file.list();
for( int i=0; i<children.length; i++ )
{
deleteRecursively( new File( file, children[i] ) );
}
}
// Then delete
long fileSize = file.isDirectory() ? 0 : file.length();
boolean success = file.delete();
if( success )
{
m_usedSpace -= Math.max( MINIMUM_FILE_SIZE, fileSize );
}
else
{
throw new IOException( "Access denied" );
}
} }
@Override @Override
public OutputStream openForWrite( String path ) throws IOException public void delete( @Nonnull String path ) throws IOException
{ {
create(); if( path.length() == 0 )
File file = getRealPath( path ); {
if( file.exists() && file.isDirectory() ) throw new IOException( "/" + path + ": Access denied" );
{ }
throw new IOException( "Cannot write to directory" );
} if( created() )
else {
{ File file = getRealPath( path );
if( !file.exists() ) if( file.exists() )
{ {
if( getRemainingSpace() < MINIMUM_FILE_SIZE ) deleteRecursively( file );
{ }
throw new IOException( "Out of space" ); }
} }
else
{ private void deleteRecursively( File file ) throws IOException
m_usedSpace += MINIMUM_FILE_SIZE; {
} // Empty directories first
} if( file.isDirectory() )
else {
{ String[] children = file.list();
m_usedSpace -= Math.max( file.length(), MINIMUM_FILE_SIZE ); for( String aChildren : children )
m_usedSpace += MINIMUM_FILE_SIZE; {
} deleteRecursively( new File( file, aChildren ) );
return new CountingOutputStream( new FileOutputStream( file, false ), MINIMUM_FILE_SIZE ); }
} }
}
// Then delete
@Override long fileSize = file.isDirectory() ? 0 : file.length();
public OutputStream openForAppend( String path ) throws IOException boolean success = file.delete();
{ if( success )
if( created() ) {
{ m_usedSpace -= Math.max( MINIMUM_FILE_SIZE, fileSize );
File file = getRealPath( path ); }
if( !file.exists() ) else
{ {
throw new IOException( "No such file" ); throw new IOException( "Access denied" );
} }
else if( file.isDirectory() ) }
{
throw new IOException( "Cannot write to directory" ); @Nonnull
} @Override
else public OutputStream openForWrite( @Nonnull String path ) throws IOException
{ {
return new CountingOutputStream( new FileOutputStream( file, true ), Math.max( MINIMUM_FILE_SIZE - file.length(), 0 ) ); create();
} File file = getRealPath( path );
} if( file.exists() && file.isDirectory() )
else {
{ throw new IOException( "/" + path + ": Cannot write to directory" );
throw new IOException( "No such file" ); }
} else
} {
if( !file.exists() )
@Override {
public long getRemainingSpace() throws IOException if( getRemainingSpace() < MINIMUM_FILE_SIZE )
{ {
return Math.max( m_capacity - m_usedSpace, 0 ); throw new IOException( "/" + path + ": Out of space" );
} }
else
public File getRealPath( String path ) {
{ m_usedSpace += MINIMUM_FILE_SIZE;
return new File( m_rootPath, path ); }
} }
else
private boolean created() {
{ m_usedSpace -= Math.max( file.length(), MINIMUM_FILE_SIZE );
return m_rootPath.exists(); m_usedSpace += MINIMUM_FILE_SIZE;
} }
return new CountingOutputStream( new FileOutputStream( file, false ), MINIMUM_FILE_SIZE );
private void create() throws IOException }
{ }
if( !m_rootPath.exists() )
{ @Nonnull
boolean success = m_rootPath.mkdirs(); @Override
if( !success ) public OutputStream openForAppend( @Nonnull String path ) throws IOException
{ {
throw new IOException( "Access denied" ); if( created() )
} {
} File file = getRealPath( path );
} if( !file.exists() )
{
private long measureUsedSpace( File file ) throw new IOException( "/" + path + ": No such file" );
{ }
if( !file.exists() ) else if( file.isDirectory() )
{ {
return 0; throw new IOException( "/" + path + ": Cannot write to directory" );
} }
if( file.isDirectory() ) else
{ {
long size = MINIMUM_FILE_SIZE; return new CountingOutputStream( new FileOutputStream( file, true ), Math.max( MINIMUM_FILE_SIZE - file.length(), 0 ) );
String[] contents = file.list(); }
for( int i=0; i<contents.length; ++i ) }
{ else
size += measureUsedSpace( new File( file, contents[i] ) ); {
} throw new IOException( "/" + path + ": No such file" );
return size; }
} }
else
{ @Override
return Math.max( file.length(), MINIMUM_FILE_SIZE ); public long getRemainingSpace() throws IOException
} {
} return Math.max( m_capacity - m_usedSpace, 0 );
}
public File getRealPath( String path )
{
return new File( m_rootPath, path );
}
private boolean created()
{
return m_rootPath.exists();
}
private void create() throws IOException
{
if( !m_rootPath.exists() )
{
boolean success = m_rootPath.mkdirs();
if( !success )
{
throw new IOException( "Access denied" );
}
}
}
private long measureUsedSpace( File file )
{
if( !file.exists() )
{
return 0;
}
if( file.isDirectory() )
{
long size = MINIMUM_FILE_SIZE;
String[] contents = file.list();
for( String content : contents )
{
size += measureUsedSpace( new File( file, content ) );
}
return size;
}
else
{
return Math.max( file.length(), MINIMUM_FILE_SIZE );
}
}
} }

View File

@@ -1,13 +1,15 @@
/** /*
* This file is part of ComputerCraft - http://www.computercraft.info * This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.core.filesystem; package dan200.computercraft.core.filesystem;
public class FileSystemException extends Exception { public class FileSystemException extends Exception {
FileSystemException( String s ) { private static final long serialVersionUID = -2500631644868104029L;
super( s );
} FileSystemException( String s ) {
super( s );
}
} }

View File

@@ -1,13 +0,0 @@
/**
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.filesystem;
import java.io.IOException;
public interface IMountedFile {
public void close() throws IOException;
}

View File

@@ -1,16 +0,0 @@
/**
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.filesystem;
import java.io.IOException;
public interface IMountedFileBinary extends IMountedFile {
public int read() throws IOException;
public void write(int i) throws IOException;
public void close() throws IOException;
public void flush() throws IOException;
}

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