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

Compare commits

...

54 Commits

Author SHA1 Message Date
SquidDev
07a56454a0 Bumpity bumpity bump 2019-08-09 09:38:30 +01:00
SquidDev
a0e72d02c8 Bump Forge version 2019-08-06 08:33:39 +01:00
SquidDev
455a59ca85 Sure, you can be an actual release now 2019-08-04 17:01:52 +01:00
SquidDev
08d22fd3df Fix changelog being out-of-sync 2019-08-04 11:05:14 +01:00
SquidDev
e6c691a8f8 Fix rom's location
This isn't going to get annoying or anything
2019-08-04 11:02:07 +01:00
SquidDev
4b0e5c445c Merge branch 'master' into mc-1.14.x 2019-08-04 10:57:20 +01:00
SquidDev
cef2657048 Fix turtles being replaced by leaves
And logs. Well, hopefully at least.

Fixes #278
2019-07-21 10:28:22 +01:00
SquidDev
ccd85eb055 Bump Forge version 2019-07-21 09:41:58 +01:00
SquidDev
acfb72246c Bump JEI version 2019-07-07 15:52:52 +01:00
SquidDev
9d51c4c340 Use world-specific collider entity
This is equally an ugly hack, but means we're at least not constructing
entities with null worlds any more.

Ideally we could always use the turtle entity, but this will require a
bit more of a refactor.

Fixes #265
2019-07-05 22:09:42 +01:00
SquidDev
18068effec Use reflection to get the record's sound
getSound is client side only - I could have sworn it became shared at
some point, but that may have been reverted again (or I imagined it).

Fixes #263
2019-07-05 21:51:54 +01:00
SquidDev
6ea8ca991b Bump Forge to 1.14.3
Guess it's time for another release?
2019-06-26 08:25:32 +01:00
SquidDev
f1e551b960 Bump Forge version
Turtle models now work (though texture registration is still broken).
2019-06-23 15:30:29 +01:00
SquidDev
772c54ec74 Copy the item stack before merging
Otherwise we would mutate the stack, and so the current mount was
considered empty. Closes #240 (though would be nice to improve this).
2019-06-21 22:00:21 +01:00
SquidDev
13cb789c18 Fix "can deploy" check being entirely incorrect
Closes #258
2019-06-21 21:51:22 +01:00
SquidDev
42220c4268 Fix several other client-only methods 2019-06-21 21:32:15 +01:00
SquidDev
3052506e2e Reload configs from the file 2019-06-21 21:32:02 +01:00
SquidDev
0741daa7eb Fix usage of a client-only method
Should probably run forge-lint on this at some point, but it's a good
start.

Fixes #255
2019-06-21 21:02:09 +01:00
SquidDev
b4aa554279 Do not fetch the current block within onLoad
The chunk has not been fully loaded when onLoad is called, which means
we try to load it again, and so the server deadlocks.
2019-06-21 20:57:38 +01:00
SquidDev
8fe2abe0ae Forward tab key directly to the terminal
Fixes #256
2019-06-21 20:31:28 +01:00
SquidDev
5af789ae11 Bump Forge version 2019-06-21 20:31:17 +01:00
SquidDev
68542aca3a Fix cable breaking rendering
Texture locations have changed a little
2019-06-15 09:19:41 +01:00
SquidDev
594bc4203c Fix block drops for computers and turtles 2019-06-15 09:07:31 +01:00
SquidDev
57318b022d Merge branch 'master' into mc-1.14.x 2019-06-15 08:00:20 +01:00
SquidDev
761159aa93 Bump Forge version 2019-06-15 07:40:27 +01:00
SquidDev
8dd1c2a6cc Finish off containers, somewhat fix block drops
- Add Forge's "name" field to the loot tables. This doesn't resolve all
   our missing loot providers, but it's a start.
 - Add back GUIs for pocket computers, printouts, view computer, etc...
2019-06-12 08:40:20 +01:00
SquidDev
d10b657a54 Initial work on GUIs
Needs a bit of a cleanup, but it's a start!
2019-06-11 21:03:40 +01:00
SquidDev
f90da739eb And bump Forge again 2019-06-09 10:15:53 +01:00
SquidDev
d9cadf64e8 Get the build working I guess? 2019-06-09 09:07:31 +01:00
SquidDev
15d4a55cd8 Bump mappings and Forge versions
Things are shaping up nicely!
2019-06-09 08:58:49 +01:00
SquidDev
39a9ad0ce7 Initial update to 1.14
So very little works, but it compiles and runs.

Things to resolve over the next few days:
 - Horrible mappings (should largely be resolved by tomorrow).
 - Cannot send extra data over containers - we'll have to see what Forge
   does here.
 - Turtle models are broken
 - No block drops yet - this will largely be cherry-picking whatever I
   did on Fabric.
 - Weird inventory desyncs (items don't show up initially when
   interacting with a CC inventory).
 - Probably lots of other things.
2019-06-08 13:36:31 +01:00
SquidDev
0f3c44c926 Merge branch 'master' into mc-1.13.x 2019-06-08 08:21:08 +01:00
SquidDev
b6715bd812 Fix a couple of build failures 2019-06-02 18:36:34 +01:00
SquidDev
18aee02221 Mark CurseForge builds as release
They're almost definitely not, but I've had no bug reports so they must
work!
2019-06-02 17:28:13 +01:00
SquidDev
401bbf2e6a Fix turtle block placing failing 2019-06-02 17:25:49 +01:00
SquidDev
7467b7f88a Fix several deprecated warnings 2019-06-02 17:23:33 +01:00
SquidDev
c82d8a7c2a Merge branch 'master' into mc-1.13.x 2019-06-02 16:46:45 +01:00
SquidDev
3d67421d98 Bump Forge version 2019-06-02 16:18:44 +01:00
SquidDev
bb138326df Use correct model for blinking pocket computers
Fixes #211211211211211211211211211211211211211211211211211211211211211
2019-05-25 09:28:15 +01:00
xuyu0v0
e0660b1dab Create zh_cn.json 2019-05-06 21:47:43 +01:00
SquidDev
2182cfbeb7 Merge branch 'master' into mc-1.13.x 2019-05-06 21:32:56 +01:00
SquidDev
2c027adb68 Fix advancements
Looks like these were never properly updated. Woops.
2019-04-24 12:15:03 +01:00
SquidDev
4a25e7a178 Fix GH release uploading 2019-04-24 10:40:44 +01:00
SquidDev
55d54fec63 Bump versions 2019-04-24 10:33:50 +01:00
SquidDev
220e4bd660 Merge branch 'master' into mc-1.13.x 2019-04-24 10:15:33 +01:00
SquidDev
362dbd97ac Correctly handle capability creation & invalidation
Also make cable part detection more consistent.
2019-04-09 17:29:23 +01:00
SquidDev
aa0e1883d1 Add check for if item/block registration has failed
If mod loading fails, we'll continue to load colour handlers. As
blocks/items have not been registered, then we'll throw an NPE.

See MinecraftForge/MinecraftForge#5682. Somewhat fixes #168.
2019-04-09 16:32:20 +01:00
SquidDev
9cdbcb4332 Use int instead of long for configs
Forge's config system will read the default values as integers, meaning
it fails to validate against the config spec. Ideally this'd be fixed in
forge, but this is a suitable work around.
2019-04-09 16:31:00 +01:00
SquidDev
23ddd4feb5 Fix several deprecation warnings 2019-04-09 16:30:44 +01:00
SquidDev
fcaa777c95 Merge branch 'master' into mc-1.13.x 2019-04-09 11:11:12 +01:00
SquidDev
7afc3e5260 And fix the build failing 2019-04-02 21:33:55 +01:00
SquidDev
f9e13ca67a Update CC: Tweaked to 1.13
Look, I originally had this split into several commits, but lots of
other cleanups got mixed in. I then backported some of the cleanups to
1.12, did other tidy ups there, and eventually the web of merges was
unreadable.

Yes, this is a horrible mess, but it's still nicer than it was. Anyway,
changes:

 - Flatten everything. For instance, there are now three instances of
   BlockComputer, two BlockTurtle, ItemPocketComputer. There's also no
   more BlockPeripheral (thank heavens) - there's separate block classes
   for each peripheral type.

 - Remove pretty much all legacy code. As we're breaking world
   compatibility anyway, we can remove all the code to load worlds from
   1.4 days.
 - The command system is largely rewriten to take advantage of 1.13's
   new system. It's very fancy!

 - WidgetTerminal now uses Minecraft's "GUI listener" system.

 - BREAKING CHANGE: All the codes in keys.lua are different, due to the
   move to LWJGL 3. Hopefully this won't have too much of an impact.

   I don't want to map to the old key codes on the Java side, as there
   always ends up being small but slight inconsistencies. IMO it's
   better to make a clean break - people should be using keys rather
   than hard coding the constants anyway.

 - commands.list now allows fetching sub-commands. The ROM has already
   been updated to allow fancy usage such as commands.time.set("noon").

 - Turtles, modems and cables can be waterlogged.
2019-04-02 20:59:48 +01:00
SquidDev
810258e9b8 Update and rename all resources
- Languages are converted to JSON
 - Rename most *(_advanced) blocks to *_{advanced,normal}. It's more
   verbose, but means they're sorted together.
 - A couple of changes to the ROM to work with some Java changes.
 - Update recipes and advancements to not use damage values.
2019-04-02 13:18:43 +01:00
SquidDev
5e462adc5c Relocate all resource files
- textures/{block,item}s -> textures/{block,item}
 - assets/*/{advancements,lua,recipes} -> data/*/...
2019-04-02 13:18:43 +01:00
1087 changed files with 13259 additions and 15634 deletions

View File

@@ -41,7 +41,7 @@ Any contribution is welcome, be that using the mod, reporting bugs or contributi
develop CC:T, you'll need to follow these steps:
- **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked`
- **Setup Forge:** `./gradlew setupDecompWorkspace`
- **Setup Forge:** `./gradlew build`
- **Test your changes:** `./gradlew runClient` (or run the `GradleStart` class from your IDE).
If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`.

View File

@@ -1,8 +1,7 @@
// For those who want the bleeding edge
buildscript {
repositories {
jcenter()
mavenCentral()
maven {
name = "forge"
url = "https://files.minecraftforge.net/maven"
@@ -10,8 +9,8 @@ buildscript {
}
dependencies {
classpath 'com.google.code.gson:gson:2.8.1'
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta1'
classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.134'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
}
}
@@ -23,7 +22,7 @@ plugins {
id "com.github.breadmoirai.github-release" version "2.2.4"
}
apply plugin: 'net.minecraftforge.gradle.forge'
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'org.ajoberstar.grgit'
apply plugin: 'maven-publish'
apply plugin: 'maven'
@@ -34,12 +33,35 @@ group = "org.squiddev"
archivesBaseName = "cc-tweaked-${mc_version}"
minecraft {
version = "${mc_version}-${forge_version}"
runDir = "run"
replace '${version}', mod_version
runs {
client {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
mappings = mappings_version
makeObfSourceJar = false
mods {
computercraft {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
mods {
computercraft {
source sourceSets.main
}
}
}
}
mappings channel: 'snapshot', version: "${mappings_version}".toString()
accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg')
}
repositories {
@@ -70,11 +92,13 @@ configurations {
dependencies {
checkstyle "com.puppycrawl.tools:checkstyle:8.21"
deobfProvided "mezz.jei:jei_1.12.2:4.15.0.269:api"
deobfProvided "pl.asie:Charset-Lib:0.5.4.6"
deobfProvided "MCMultiPart2:MCMultiPart:2.5.3"
minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
runtime "mezz.jei:jei_1.12.2:4.15.0.269"
compileOnly fg.deobf("mezz.jei:jei-1.14.3:6.0.0.7:api")
// deobfProvided "pl.asie:Charset-Lib:0.5.4.6"
// deobfProvided "MCMultiPart2:MCMultiPart:2.5.3"
runtimeOnly fg.deobf("mezz.jei:jei-1.14.3:6.0.0.7")
shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT'
@@ -84,6 +108,15 @@ dependencies {
deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0"
}
sourceSets {
main {
java {
exclude 'dan200/computercraft/shared/integration/mcmp'
exclude 'dan200/computercraft/shared/integration/charset'
}
}
}
// Compile tasks
javadoc {
@@ -94,7 +127,13 @@ jar {
dependsOn javadoc
manifest {
attributes('FMLAT': 'computercraft_at.cfg')
attributes(["Specification-Title": "computercraft",
"Specification-Vendor": "SquidDev",
"Specification-Version": "1",
"Implementation-Title": "CC: Tweaked",
"Implementation-Version": "${mod_version}",
"Implementation-Vendor" :"SquidDev",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")])
}
from (sourceSets.main.allSource) {
@@ -142,13 +181,17 @@ task proguard(type: ProGuardTask, dependsOn: jar) {
dontobfuscate; dontoptimize; keepattributes; keepparameternames
// Proguard will remove directories by default, but that breaks JarMount.
keepdirectories 'assets/computercraft/lua**'
keepdirectories 'data/computercraft/lua**'
// Preserve ComputerCraft classes - we only want to strip shadowed files.
keep 'class dan200.computercraft.** { *; }'
// Preserve the constructors in Cobalt library class, as we init them via reflection
keepclassmembers 'class org.squiddev.cobalt.lib.** { <init>(...); }'
// LWJGL and Apache bundle Java 9 versions, which is great, but rather breaks Proguard
dontwarn 'module-info'
dontwarn 'org.apache.**,org.lwjgl.**'
}
task proguardMove(dependsOn: proguard) {
@@ -164,7 +207,7 @@ task proguardMove(dependsOn: proguard) {
}
}
reobfJar.dependsOn proguardMove
processResources {
inputs.property "version", mod_version
@@ -186,8 +229,8 @@ processResources {
inputs.property "commithash", hash
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
include 'assets/computercraft/lua/rom/help/credits.txt'
include 'META-INF/mods.toml'
include 'data/computercraft/lua/rom/help/credits.txt'
expand 'version': mod_version,
'mcversion': mc_version,
@@ -195,12 +238,12 @@ processResources {
}
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
exclude 'assets/computercraft/lua/rom/help/credits.txt'
exclude 'META-INF/mods.toml'
exclude 'data/computercraft/lua/rom/help/credits.txt'
}
}
task compressJson(dependsOn: extractAnnotationsJar) {
task compressJson(dependsOn: jar) {
group "compact"
description "Minifies all JSON files, stripping whitespace"
@@ -298,14 +341,14 @@ task checkRelease {
description "Verifies that everything is ready for a release"
inputs.property "version", mod_version
inputs.file("src/main/resources/assets/computercraft/lua/rom/help/changelog.txt")
inputs.file("src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt")
inputs.file("src/main/resources/data/computercraft/lua/rom/help/changelog.txt")
inputs.file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt")
doLast {
def ok = true
// Check we're targetting the current version
def whatsnew = new File("src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt").readLines()
def whatsnew = new File("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt").readLines()
if (whatsnew[0] != "New features in CC: Tweaked $mod_version") {
ok = false
project.logger.error("Expected `whatsnew.txt' to target $mod_version.")
@@ -322,7 +365,7 @@ task checkRelease {
// Check whatsnew and changelog match.
def versionChangelog = "# " + whatsnew.join("\n")
def changelog = new File("src/main/resources/assets/computercraft/lua/rom/help/changelog.txt").getText()
def changelog = new File("src/main/resources/data/computercraft/lua/rom/help/changelog.txt").getText()
if (!changelog.startsWith(versionChangelog)) {
ok = false
project.logger.error("whatsnew and changelog are not in sync")
@@ -349,7 +392,7 @@ publishing {
publications {
mavenJava(MavenPublication) {
from components.java
artifact sourceJar
// artifact sourceJar
}
}
}
@@ -407,7 +450,7 @@ githubRelease {
tagName "v${mc_version}-${mod_version}"
releaseName "[${mc_version}] ${mod_version}"
body {
"## " + new File("src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt")
"## " + new File("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt")
.readLines()
.takeWhile { it != 'Type "help changelog" to see the full version history.' }
.join("\n").trim()
@@ -422,6 +465,3 @@ task uploadAll(dependsOn: uploadTasks) {
group "upload"
description "Uploads to all repositories (Maven, Curse, GitHub release)"
}
runClient.outputs.upToDateWhen { false }
runServer.outputs.upToDateWhen { false }

View File

@@ -149,7 +149,7 @@
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true" />
<property name="ignoreEnhancedForColon" value="false" />
<property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,DO_WHILE,EQUAL,GE,GT,LAMBDA,LAND,LCURLY,LE,LITERAL_RETURN,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,RCURLY,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND" />
<property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,EQUAL,GE,GT,LAMBDA,LAND,LCURLY,LE,LITERAL_RETURN,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,RCURLY,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND" />
</module>
</module>

View File

@@ -1,7 +1,7 @@
# Mod properties
mod_version=1.84.0
mod_version=1.84.1
# Minecraft properties
mc_version=1.12.2
forge_version=14.23.4.2749
mappings_version=snapshot_20180724
mc_version=1.14.4
forge_version=28.0.45
mappings_version=20190806-1.14.3

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip

View File

@@ -1,30 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.network.NetworkCheckHandler;
import net.minecraftforge.fml.relauncher.Side;
import java.util.Map;
/**
* A stub mod for CC: Tweaked. This doesn't have any functionality (everything of note is done in
* {@link ComputerCraft}), but people may depend on this if they require CC: Tweaked functionality.
*/
@Mod(
modid = "cctweaked", name = ComputerCraft.NAME, version = ComputerCraft.VERSION,
acceptableRemoteVersions = "*"
)
public class CCTweaked
{
@NetworkCheckHandler
public boolean onNetworkConnect( Map<String, String> mods, Side side )
{
return true;
}
}

View File

@@ -7,95 +7,50 @@
package dan200.computercraft;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.media.IMediaProvider;
import dan200.computercraft.api.network.IPacketNetwork;
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.core.apis.AddressPredicate;
import dan200.computercraft.core.apis.ApiFactories;
import dan200.computercraft.core.apis.http.websocket.Websocket;
import dan200.computercraft.core.computer.MainThread;
import dan200.computercraft.core.filesystem.ComboMount;
import dan200.computercraft.core.filesystem.FileMount;
import dan200.computercraft.core.filesystem.JarMount;
import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.shared.*;
import dan200.computercraft.shared.computer.blocks.BlockCommandComputer;
import dan200.computercraft.core.filesystem.ResourceMount;
import dan200.computercraft.shared.Config;
import dan200.computercraft.shared.computer.blocks.BlockComputer;
import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
import dan200.computercraft.shared.computer.core.ServerComputerRegistry;
import dan200.computercraft.shared.computer.items.ItemCommandComputer;
import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.media.items.ItemDiskExpanded;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.ItemPeripheral;
import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive;
import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
import dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull;
import dan200.computercraft.shared.peripheral.modem.wired.ItemCable;
import dan200.computercraft.shared.peripheral.modem.wireless.BlockAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.ItemAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
import dan200.computercraft.shared.peripheral.modem.wired.ItemBlockCable;
import dan200.computercraft.shared.peripheral.modem.wireless.BlockWirelessModem;
import dan200.computercraft.shared.peripheral.monitor.BlockMonitor;
import dan200.computercraft.shared.peripheral.printer.BlockPrinter;
import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
import dan200.computercraft.shared.turtle.items.ItemTurtleAdvanced;
import dan200.computercraft.shared.turtle.items.ItemTurtleLegacy;
import dan200.computercraft.shared.turtle.items.ItemTurtleNormal;
import dan200.computercraft.shared.turtle.items.ItemTurtle;
import dan200.computercraft.shared.turtle.upgrades.*;
import dan200.computercraft.shared.util.CreativeTabMain;
import dan200.computercraft.shared.util.IDAssigner;
import dan200.computercraft.shared.util.IoUtil;
import dan200.computercraft.shared.wired.CapabilityWiredElement;
import dan200.computercraft.shared.wired.WiredNode;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.fml.common.*;
import net.minecraftforge.fml.common.event.*;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumSet;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@Mod(
modid = ComputerCraft.MOD_ID, name = ComputerCraft.NAME, version = ComputerCraft.VERSION,
guiFactory = "dan200.computercraft.client.gui.GuiConfigCC$Factory",
dependencies = "required:forge@[14.23.4.2746,)"
)
public class ComputerCraft
@Mod( ComputerCraft.MOD_ID )
public final class ComputerCraft
{
public static final String MOD_ID = "computercraft";
static final String VERSION = "${version}";
static final String NAME = "CC: Tweaked";
public static final int DATAFIXER_VERSION = 0;
// Configuration options
public static final String[] DEFAULT_HTTP_WHITELIST = new String[] { "*" };
@@ -157,46 +112,54 @@ public class ComputerCraft
// Blocks and Items
public static final class Blocks
{
public static BlockComputer computer;
public static BlockCommandComputer commandComputer;
public static BlockComputer computerNormal;
public static BlockComputer computerAdvanced;
public static BlockComputer computerCommand;
public static BlockTurtle turtle;
public static BlockTurtle turtleExpanded;
public static BlockTurtle turtleNormal;
public static BlockTurtle turtleAdvanced;
public static BlockPeripheral peripheral;
public static BlockCable cable;
public static BlockAdvancedModem advancedModem;
public static BlockSpeaker speaker;
public static BlockDiskDrive diskDrive;
public static BlockPrinter printer;
public static BlockMonitor monitorNormal;
public static BlockMonitor monitorAdvanced;
public static BlockWirelessModem wirelessModemNormal;
public static BlockWirelessModem wirelessModemAdvanced;
public static BlockWiredModemFull wiredModemFull;
public static BlockCable cable;
}
public static final class Items
{
public static ItemComputer computer;
public static ItemCommandComputer commandComputer;
public static ItemComputer computerNormal;
public static ItemComputer computerAdvanced;
public static ItemComputer computerCommand;
public static ItemTurtleLegacy turtle;
public static ItemTurtleNormal turtleExpanded;
public static ItemTurtleAdvanced turtleAdvanced;
public static ItemPocketComputer pocketComputerNormal;
public static ItemPocketComputer pocketComputerAdvanced;
public static ItemPocketComputer pocketComputer;
public static ItemTurtle turtleNormal;
public static ItemTurtle turtleAdvanced;
public static ItemDiskLegacy disk;
public static ItemDiskExpanded diskExpanded;
public static ItemDisk disk;
public static ItemTreasureDisk treasureDisk;
public static ItemPrintout printout;
public static ItemPrintout printedPage;
public static ItemPrintout printedPages;
public static ItemPrintout printedBook;
public static ItemPeripheral peripheral;
public static ItemAdvancedModem advancedModem;
public static ItemCable cable;
public static ItemBlock wiredModemFull;
public static ItemBlockCable.Cable cable;
public static ItemBlockCable.WiredModem wiredModem;
}
public static final class TurtleUpgrades
{
public static TurtleModem wirelessModem;
public static TurtleModem advancedModem;
public static TurtleModem wirelessModemNormal;
public static TurtleModem wirelessModemAdvanced;
public static TurtleSpeaker speaker;
public static TurtleCraftingTable craftingTable;
@@ -209,457 +172,45 @@ public class ComputerCraft
public static final class PocketUpgrades
{
public static PocketModem wirelessModem;
public static PocketModem advancedModem;
public static PocketModem wirelessModemNormal;
public static PocketModem wirelessModemAdvanced;
public static PocketSpeaker speaker;
@Deprecated
public static PocketSpeaker pocketSpeaker;
}
@Deprecated
public static final class Upgrades
{
public static TurtleModem advancedModem;
}
// Registries
public static final ClientComputerRegistry clientComputerRegistry = new ClientComputerRegistry();
public static final ServerComputerRegistry serverComputerRegistry = new ServerComputerRegistry();
// Creative
public static CreativeTabMain mainCreativeTab;
// Logging
public static Logger log;
public static final Logger log = LogManager.getLogger( MOD_ID );
// Peripheral providers. This is still here to ensure compatibility with Plethora and Computronics
public static List<IPeripheralProvider> peripheralProviders = new ArrayList<>();
// Implementation
@Mod.Instance( ComputerCraft.MOD_ID )
public static ComputerCraft instance;
@SidedProxy(
clientSide = "dan200.computercraft.client.proxy.ComputerCraftProxyClient",
serverSide = "dan200.computercraft.shared.proxy.ComputerCraftProxyCommon"
)
private static ComputerCraftProxyCommon proxy;
@Mod.EventHandler
public void preInit( FMLPreInitializationEvent event )
public ComputerCraft()
{
log = event.getModLog();
// Load config
Config.load( event.getSuggestedConfigurationFile() );
proxy.preInit();
}
@Mod.EventHandler
public void init( FMLInitializationEvent event )
{
proxy.init();
}
@Mod.EventHandler
public void onServerStarting( FMLServerStartingEvent event )
{
ComputerCraftProxyCommon.initServer( event.getServer() );
}
@Mod.EventHandler
public void onServerStart( FMLServerStartedEvent event )
{
if( FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER )
{
ComputerCraft.serverComputerRegistry.reset();
WirelessNetwork.resetNetworks();
MainThread.reset();
Tracking.reset();
}
}
@Mod.EventHandler
public void onServerStopped( FMLServerStoppedEvent event )
{
if( FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER )
{
ComputerCraft.serverComputerRegistry.reset();
WirelessNetwork.resetNetworks();
MainThread.reset();
Tracking.reset();
}
Config.load();
}
public static String getVersion()
{
return VERSION;
return "${version}";
}
private static File getBaseDir()
static IMount createResourceMount( String domain, String subPath )
{
return FMLCommonHandler.instance().getMinecraftServerInstance().getDataDirectory();
IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager();
ResourceMount mount = new ResourceMount( domain, subPath, manager );
return mount.exists( "" ) ? mount : null;
}
private static File getResourcePackDir()
{
return new File( getBaseDir(), "resourcepacks" );
}
@Deprecated
public static void registerPermissionProvider( ITurtlePermissionProvider provider )
{
TurtlePermissions.register( provider );
}
@Deprecated
public static void registerPocketUpgrade( IPocketUpgrade upgrade )
{
dan200.computercraft.shared.PocketUpgrades.register( upgrade );
}
@Deprecated
public static void registerPeripheralProvider( IPeripheralProvider provider )
{
Peripherals.register( provider );
}
@Deprecated
public static void registerBundledRedstoneProvider( IBundledRedstoneProvider provider )
{
BundledRedstone.register( provider );
}
@Deprecated
public static void registerMediaProvider( IMediaProvider provider )
{
MediaProviders.register( provider );
}
@Deprecated
public static void registerAPIFactory( ILuaAPIFactory factory )
{
ApiFactories.register( factory );
}
@Deprecated
public static IWiredNode createWiredNodeForElement( IWiredElement element )
{
return new WiredNode( element );
}
@Deprecated
public static IWiredElement getWiredElementAt( IBlockAccess world, BlockPos pos, EnumFacing side )
{
TileEntity tile = world.getTileEntity( pos );
return tile != null && tile.hasCapability( CapabilityWiredElement.CAPABILITY, side )
? tile.getCapability( CapabilityWiredElement.CAPABILITY, side )
: null;
}
@Deprecated
public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side )
{
return BundledRedstone.getDefaultOutput( world, pos, side );
}
@Deprecated
public static IPacketNetwork getWirelessNetwork()
{
return WirelessNetwork.getUniversal();
}
@Deprecated
public static int createUniqueNumberedSaveDir( World world, String parentSubPath )
{
return IDAssigner.getNextIDFromDirectory( parentSubPath );
}
@Deprecated
public static IWritableMount createSaveDirMount( World world, String subPath, long capacity )
public static InputStream getResourceFile( String domain, String subPath )
{
IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager();
try
{
return new FileMount( new File( getWorldDir(), subPath ), capacity );
return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream();
}
catch( Exception e )
catch( IOException ignored )
{
return null;
}
}
private static void loadFromFile( List<IMount> mounts, File file, String path, boolean allowMissing )
{
try
{
if( file.isFile() )
{
mounts.add( new JarMount( file, path ) );
}
else
{
File subResource = new File( file, path );
if( subResource.exists() ) mounts.add( new FileMount( subResource, 0 ) );
}
}
catch( IOException | RuntimeException e )
{
if( allowMissing && e instanceof FileNotFoundException ) return;
ComputerCraft.log.error( "Could not load mount '" + path + " 'from '" + file.getName() + "'", e );
}
}
@Deprecated
public static IMount createResourceMount( Class<?> modClass, String domain, String subPath )
{
// Start building list of mounts
List<IMount> mounts = new ArrayList<>();
subPath = "assets/" + domain + "/" + subPath;
// Mount from debug dir
File codeDir = getDebugCodeDir( modClass );
if( codeDir != null )
{
File subResource = new File( codeDir, subPath );
if( subResource.exists() )
{
IMount resourcePackMount = new FileMount( subResource, 0 );
mounts.add( resourcePackMount );
}
}
// Mount from mod jars, preferring the specified one.
File modJar = getContainingJar( modClass );
Set<File> otherMods = new HashSet<>();
for( ModContainer container : Loader.instance().getActiveModList() )
{
File modFile = container.getSource();
if( modFile != null && !modFile.equals( modJar ) && modFile.exists() )
{
otherMods.add( container.getSource() );
}
}
for( File file : otherMods )
{
loadFromFile( mounts, file, subPath, true );
}
if( modJar != null )
{
loadFromFile( mounts, modJar, subPath, false );
}
// Mount from resource packs
File resourcePackDir = getResourcePackDir();
if( resourcePackDir.exists() && resourcePackDir.isDirectory() )
{
String[] resourcePacks = resourcePackDir.list();
for( String resourcePackName : resourcePacks )
{
File resourcePack = new File( resourcePackDir, resourcePackName );
loadFromFile( mounts, resourcePack, subPath, true );
}
}
// Return the combination of all the mounts found
if( mounts.size() >= 2 )
{
IMount[] mountArray = new IMount[mounts.size()];
mounts.toArray( mountArray );
return new ComboMount( mountArray );
}
else if( mounts.size() == 1 )
{
return mounts.get( 0 );
}
else
{
return null;
}
}
public static InputStream getResourceFile( Class<?> modClass, String domain, String subPath )
{
// Start searching in possible locations
subPath = "assets/" + domain + "/" + subPath;
// Look in resource packs
File resourcePackDir = getResourcePackDir();
if( resourcePackDir.exists() && resourcePackDir.isDirectory() )
{
String[] resourcePacks = resourcePackDir.list();
for( String resourcePackPath : resourcePacks )
{
File resourcePack = new File( resourcePackDir, resourcePackPath );
if( resourcePack.isDirectory() )
{
// Mount a resource pack from a folder
File subResource = new File( resourcePack, subPath );
if( subResource.exists() && subResource.isFile() )
{
try
{
return new FileInputStream( subResource );
}
catch( FileNotFoundException ignored )
{
}
}
}
else
{
ZipFile zipFile = null;
try
{
final ZipFile zip = zipFile = new ZipFile( resourcePack );
ZipEntry entry = zipFile.getEntry( subPath );
if( entry != null )
{
// Return a custom InputStream which will close the original zip when finished.
return new FilterInputStream( zipFile.getInputStream( entry ) )
{
@Override
public void close() throws IOException
{
super.close();
zip.close();
}
};
}
else
{
IoUtil.closeQuietly( zipFile );
}
}
catch( IOException e )
{
if( zipFile != null ) IoUtil.closeQuietly( zipFile );
}
}
}
}
// Look in debug dir
File codeDir = getDebugCodeDir( modClass );
if( codeDir != null )
{
File subResource = new File( codeDir, subPath );
if( subResource.exists() && subResource.isFile() )
{
try
{
return new FileInputStream( subResource );
}
catch( FileNotFoundException ignored )
{
}
}
}
// Look in class loader
return modClass.getClassLoader().getResourceAsStream( subPath );
}
private static File getContainingJar( Class<?> modClass )
{
String path = modClass.getProtectionDomain().getCodeSource().getLocation().getPath();
int bangIndex = path.indexOf( '!' );
if( bangIndex >= 0 )
{
path = path.substring( 0, bangIndex );
}
URL url;
try
{
url = new URL( path );
}
catch( MalformedURLException e1 )
{
return null;
}
File file;
try
{
file = new File( url.toURI() );
}
catch( URISyntaxException e )
{
file = new File( url.getPath() );
}
return file;
}
private static File getDebugCodeDir( Class<?> modClass )
{
String path = modClass.getProtectionDomain().getCodeSource().getLocation().getPath();
int bangIndex = path.indexOf( '!' );
return bangIndex >= 0 ? null : new File( new File( path ).getParentFile(), "../.." );
}
@Deprecated
public static void registerTurtleUpgrade( ITurtleUpgrade upgrade )
{
dan200.computercraft.shared.TurtleUpgrades.register( upgrade );
}
public static File getWorldDir()
{
return DimensionManager.getCurrentSaveRootDirectory();
}
//region Compatibility
@Deprecated
public static File getWorldDir( World world )
{
return DimensionManager.getCurrentSaveRootDirectory();
}
@Deprecated
public static IMedia getMedia( ItemStack stack )
{
return MediaProviders.get( stack );
}
@Deprecated
public static IPocketUpgrade getPocketUpgrade( ItemStack stack )
{
return dan200.computercraft.shared.PocketUpgrades.get( stack );
}
@Deprecated
public static ITurtleUpgrade getTurtleUpgrade( ItemStack stack )
{
return dan200.computercraft.shared.TurtleUpgrades.get( stack );
}
@Deprecated
public static IPocketUpgrade getPocketUpgrade( String id )
{
return dan200.computercraft.shared.PocketUpgrades.get( id );
}
@Deprecated
public static ITurtleUpgrade getTurtleUpgrade( String id )
{
return dan200.computercraft.shared.TurtleUpgrades.get( id );
}
@Deprecated
public static IPeripheral getPeripheralAt( World world, BlockPos pos, EnumFacing side )
{
return Peripherals.getPeripheral( world, pos, side );
}
@Deprecated
public static boolean canPlayerUseCommands( EntityPlayer player )
{
MinecraftServer server = player.getServer();
return server != null && server.getPlayerList().canSendCommands( player.getGameProfile() );
}
//endregion
}

View File

@@ -0,0 +1,141 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft;
import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.media.IMediaProvider;
import dan200.computercraft.api.network.IPacketNetwork;
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.core.apis.ApiFactories;
import dan200.computercraft.core.filesystem.FileMount;
import dan200.computercraft.shared.*;
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
import dan200.computercraft.shared.util.IDAssigner;
import dan200.computercraft.shared.wired.CapabilityWiredElement;
import dan200.computercraft.shared.wired.WiredNode;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nonnull;
import java.io.File;
public final class ComputerCraftAPIImpl implements IComputerCraftAPI
{
public static final ComputerCraftAPIImpl INSTANCE = new ComputerCraftAPIImpl();
private ComputerCraftAPIImpl()
{
}
@Nonnull
@Override
public String getInstalledVersion()
{
return "${version}";
}
@Override
public int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath )
{
return IDAssigner.getNextId( parentSubPath );
}
@Override
public IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity )
{
try
{
return new FileMount( new File( IDAssigner.getDir(), subPath ), capacity );
}
catch( Exception e )
{
return null;
}
}
@Override
public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath )
{
return ComputerCraft.createResourceMount( domain, subPath );
}
@Override
public void registerPeripheralProvider( @Nonnull IPeripheralProvider provider )
{
Peripherals.register( provider );
}
@Override
public void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade )
{
TurtleUpgrades.register( upgrade );
}
@Override
public void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider )
{
BundledRedstone.register( provider );
}
@Override
public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side )
{
return BundledRedstone.getDefaultOutput( world, pos, side );
}
@Override
public void registerMediaProvider( @Nonnull IMediaProvider provider )
{
MediaProviders.register( provider );
}
@Override
public void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade )
{
PocketUpgrades.register( upgrade );
}
@Nonnull
@Override
public IPacketNetwork getWirelessNetwork()
{
return WirelessNetwork.getUniversal();
}
@Override
public void registerAPIFactory( @Nonnull ILuaAPIFactory factory )
{
ApiFactories.register( factory );
}
@Nonnull
@Override
public IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element )
{
return new WiredNode( element );
}
@Nonnull
@Override
public LazyOptional<IWiredElement> getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction side )
{
TileEntity tile = world.getTileEntity( pos );
return tile == null ? LazyOptional.empty() : tile.getCapability( CapabilityWiredElement.CAPABILITY, side );
}
}

View File

@@ -7,10 +7,10 @@ package dan200.computercraft.api;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleUpgradeType;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IItemProvider;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.Util;
import javax.annotation.Nonnull;
@@ -22,43 +22,31 @@ import javax.annotation.Nonnull;
public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
{
private final ResourceLocation id;
private final int legacyId;
private final TurtleUpgradeType type;
private final String adjective;
private final ItemStack stack;
protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, String adjective, ItemStack stack )
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, ItemStack stack )
{
this.id = id;
this.legacyId = legacyId;
this.type = type;
this.adjective = adjective;
this.stack = stack;
}
protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, String adjective, Item item )
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, IItemProvider item )
{
this( id, legacyId, type, adjective, new ItemStack( item ) );
this( id, type, adjective, new ItemStack( item ) );
}
protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, String adjective, Block block )
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, ItemStack stack )
{
this( id, legacyId, type, adjective, new ItemStack( block ) );
this( id, type, Util.makeTranslationKey( "upgrade", id ) + ".adjective", stack );
}
protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, ItemStack stack )
protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, IItemProvider item )
{
this( id, legacyId, type, "upgrade." + id + ".adjective", stack );
}
protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, Item item )
{
this( id, legacyId, type, new ItemStack( item ) );
}
protected AbstractTurtleUpgrade( ResourceLocation id, int legacyId, TurtleUpgradeType type, Block block )
{
this( id, legacyId, type, new ItemStack( block ) );
this( id, type, new ItemStack( item ) );
}
@Nonnull
@@ -68,12 +56,6 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
return id;
}
@Override
public final int getLegacyUpgradeID()
{
return legacyId;
}
@Nonnull
@Override
public final String getUnlocalisedAdjective()

View File

@@ -17,18 +17,17 @@ import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.Method;
/**
* The static entry point to the ComputerCraft API.
@@ -37,28 +36,10 @@ import java.lang.reflect.Method;
*/
public final class ComputerCraftAPI
{
public static boolean isInstalled()
{
findCC();
return computerCraft != null;
}
@Nonnull
public static String getInstalledVersion()
{
findCC();
if( computerCraft_getVersion != null )
{
try
{
return (String) computerCraft_getVersion.invoke( null );
}
catch( Exception e )
{
// It failed
}
}
return "";
return getInstance().getInstalledVersion();
}
@Nonnull
@@ -82,19 +63,7 @@ public final class ComputerCraftAPI
*/
public static int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath )
{
findCC();
if( computerCraft_createUniqueNumberedSaveDir != null )
{
try
{
return (Integer) computerCraft_createUniqueNumberedSaveDir.invoke( null, world, parentSubPath );
}
catch( Exception e )
{
// It failed
}
}
return -1;
return getInstance().createUniqueNumberedSaveDir( world, parentSubPath );
}
/**
@@ -118,55 +87,54 @@ public final class ComputerCraftAPI
@Nullable
public static IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity )
{
findCC();
if( computerCraft_createSaveDirMount != null )
{
try
{
return (IWritableMount) computerCraft_createSaveDirMount.invoke( null, world, subPath, capacity );
}
catch( Exception e )
{
// It failed
}
}
return null;
return getInstance().createSaveDirMount( world, subPath, capacity );
}
/**
* Creates a file system mount to a resource folder, and returns it.
*
* Use in conjunction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a resource folder
* onto a computer's file system.
* Use in conjunction with {@link IComputerAccess#mount} or {@link IComputerAccess#mountWritable} to mount a
* resource folder onto a computer's file system.
*
* The files in this mount will be a combination of files in the specified mod jar, and resource packs that contain
* The files in this mount will be a combination of files in all mod jar, and data packs that contain
* resources with the same domain and path.
*
* @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".
* @param subPath The domain under which to look for resources. eg: "mymod/lua/myfiles".
* @return The mount, or {@code null} if it could be created for some reason. Use IComputerAccess.mount() or
* IComputerAccess.mountWritable() to mount this on a Computers' file system.
* @param domain The domain under which to look for resources. eg: "mymod".
* @param subPath The subPath under which to look for resources. eg: "lua/myfiles".
* @return The mount, or {@code null} if it could be created for some reason.
* @see IComputerAccess#mount(String, IMount)
* @see IComputerAccess#mountWritable(String, IWritableMount)
* @see IMount
*/
@Nullable
public static IMount createResourceMount( @Nonnull Class<?> modClass, @Nonnull String domain, @Nonnull String subPath )
public static IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath )
{
findCC();
if( computerCraft_createResourceMount != null )
{
try
{
return (IMount) computerCraft_createResourceMount.invoke( null, modClass, domain, subPath );
}
catch( Exception e )
{
// It failed
}
}
return null;
return getInstance().createResourceMount( domain, subPath );
}
/**
* Creates a file system mount to a resource folder, and returns it.
*
* Use in conjunction with {@link IComputerAccess#mount} or {@link IComputerAccess#mountWritable} to mount a
* resource folder onto a computer's file system.
*
* The files in this mount will be a combination of files in all mod jar, and data packs that contain
* resources with the same domain and path.
*
* @param klass The mod class to which the files belong.
* @param domain The domain under which to look for resources. eg: "mymod".
* @param subPath The subPath under which to look for resources. eg: "lua/myfiles".
* @return The mount, or {@code null} if it could be created for some reason.
* @see IComputerAccess#mount(String, IMount)
* @see IComputerAccess#mountWritable(String, IWritableMount)
* @see IMount
* @deprecated Use {@link #createResourceMount(String, String)} instead.
*/
@Nullable
@Deprecated
public static IMount createResourceMount( Class<?> klass, @Nonnull String domain, @Nonnull String subPath )
{
return getInstance().createResourceMount( domain, subPath );
}
/**
@@ -178,18 +146,7 @@ public final class ComputerCraftAPI
*/
public static void registerPeripheralProvider( @Nonnull IPeripheralProvider provider )
{
findCC();
if( computerCraft_registerPeripheralProvider != null )
{
try
{
computerCraft_registerPeripheralProvider.invoke( null, provider );
}
catch( Exception e )
{
// It failed
}
}
getInstance().registerPeripheralProvider( provider );
}
/**
@@ -202,21 +159,7 @@ public final class ComputerCraftAPI
*/
public static void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade )
{
if( upgrade != null )
{
findCC();
if( computerCraft_registerTurtleUpgrade != null )
{
try
{
computerCraft_registerTurtleUpgrade.invoke( null, upgrade );
}
catch( Exception e )
{
// It failed
}
}
}
getInstance().registerTurtleUpgrade( upgrade );
}
/**
@@ -227,18 +170,7 @@ public final class ComputerCraftAPI
*/
public static void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider )
{
findCC();
if( computerCraft_registerBundledRedstoneProvider != null )
{
try
{
computerCraft_registerBundledRedstoneProvider.invoke( null, provider );
}
catch( Exception e )
{
// It failed
}
}
getInstance().registerBundledRedstoneProvider( provider );
}
/**
@@ -251,21 +183,9 @@ public final class ComputerCraftAPI
* If there is no block capable of emitting bundled redstone at the location, -1 will be returned.
* @see IBundledRedstoneProvider
*/
public static int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
public static int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side )
{
findCC();
if( computerCraft_getDefaultBundledRedstoneOutput != null )
{
try
{
return (Integer) computerCraft_getDefaultBundledRedstoneOutput.invoke( null, world, pos, side );
}
catch( Exception e )
{
// It failed
}
}
return -1;
return getInstance().getBundledRedstoneOutput( world, pos, side );
}
/**
@@ -276,58 +196,12 @@ public final class ComputerCraftAPI
*/
public static void registerMediaProvider( @Nonnull IMediaProvider provider )
{
findCC();
if( computerCraft_registerMediaProvider != null )
{
try
{
computerCraft_registerMediaProvider.invoke( null, provider );
}
catch( Exception e )
{
// It failed
}
}
}
/**
* Registers a permission provider to restrict where turtles can move or build.
*
* @param provider The turtle permission provider to register.
* @see ITurtlePermissionProvider
* @deprecated Prefer using {@link dan200.computercraft.api.turtle.event.TurtleBlockEvent} or the standard Forge events.
*/
@Deprecated
public static void registerPermissionProvider( @Nonnull ITurtlePermissionProvider provider )
{
findCC();
if( computerCraft_registerPermissionProvider != null )
{
try
{
computerCraft_registerPermissionProvider.invoke( null, provider );
}
catch( Exception e )
{
// It failed
}
}
getInstance().registerMediaProvider( provider );
}
public static void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade )
{
findCC();
if( computerCraft_registerPocketUpgrade != null )
{
try
{
computerCraft_registerPocketUpgrade.invoke( null, upgrade );
}
catch( Exception e )
{
// It failed
}
}
getInstance().registerPocketUpgrade( upgrade );
}
/**
@@ -337,36 +211,12 @@ public final class ComputerCraftAPI
*/
public static IPacketNetwork getWirelessNetwork()
{
findCC();
if( computerCraft_getWirelessNetwork != null )
{
try
{
return (IPacketNetwork) computerCraft_getWirelessNetwork.invoke( null );
}
catch( Exception e )
{
// It failed;
}
}
return null;
return getInstance().getWirelessNetwork();
}
public static void registerAPIFactory( @Nonnull ILuaAPIFactory upgrade )
public static void registerAPIFactory( @Nonnull ILuaAPIFactory factory )
{
findCC();
if( computerCraft_registerAPIFactory != null )
{
try
{
computerCraft_registerAPIFactory.invoke( null, upgrade );
}
catch( Exception e )
{
// It failed
}
}
getInstance().registerAPIFactory( factory );
}
/**
@@ -379,22 +229,7 @@ public final class ComputerCraftAPI
@Nonnull
public static IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element )
{
findCC();
if( computerCraft_createWiredNodeForElement != null )
{
try
{
return (IWiredNode) computerCraft_createWiredNodeForElement.invoke( null, element );
}
catch( ReflectiveOperationException e )
{
throw new IllegalStateException( "Error creating wired node", e );
}
}
else
{
throw new IllegalStateException( "ComputerCraft cannot be found" );
}
return getInstance().createWiredNodeForElement( element );
}
/**
@@ -406,118 +241,64 @@ public final class ComputerCraftAPI
* @return The element's node
* @see IWiredElement#getNode()
*/
@Nullable
public static IWiredElement getWiredElementAt( @Nonnull IBlockAccess world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
@Nonnull
public static LazyOptional<IWiredElement> getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction side )
{
findCC();
if( computerCraft_getWiredElementAt != null )
{
try
{
return (IWiredElement) computerCraft_getWiredElementAt.invoke( null, world, pos, side );
}
catch( ReflectiveOperationException ignored )
{
}
}
return null;
return getInstance().getWiredElementAt( world, pos, side );
}
// 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
// it in your solution, and so your mod won't crash if ComputerCraft is installed.
private static IComputerCraftAPI instance;
private static void findCC()
@Nonnull
private static IComputerCraftAPI getInstance()
{
if( !ccSearched )
{
try
{
computerCraft = Class.forName( "dan200.computercraft.ComputerCraft" );
computerCraft_getVersion = findCCMethod( "getVersion", new Class<?>[] {
} );
computerCraft_createUniqueNumberedSaveDir = findCCMethod( "createUniqueNumberedSaveDir", new Class<?>[] {
World.class, String.class,
} );
computerCraft_createSaveDirMount = findCCMethod( "createSaveDirMount", new Class<?>[] {
World.class, String.class, Long.TYPE,
} );
computerCraft_createResourceMount = findCCMethod( "createResourceMount", new Class<?>[] {
Class.class, String.class, String.class,
} );
computerCraft_registerPeripheralProvider = findCCMethod( "registerPeripheralProvider", new Class<?>[] {
IPeripheralProvider.class,
} );
computerCraft_registerTurtleUpgrade = findCCMethod( "registerTurtleUpgrade", new Class<?>[] {
ITurtleUpgrade.class,
} );
computerCraft_registerBundledRedstoneProvider = findCCMethod( "registerBundledRedstoneProvider", new Class<?>[] {
IBundledRedstoneProvider.class,
} );
computerCraft_getDefaultBundledRedstoneOutput = findCCMethod( "getDefaultBundledRedstoneOutput", new Class<?>[] {
World.class, BlockPos.class, EnumFacing.class,
} );
computerCraft_registerMediaProvider = findCCMethod( "registerMediaProvider", new Class<?>[] {
IMediaProvider.class,
} );
computerCraft_registerPermissionProvider = findCCMethod( "registerPermissionProvider", new Class<?>[] {
ITurtlePermissionProvider.class,
} );
computerCraft_registerPocketUpgrade = findCCMethod( "registerPocketUpgrade", new Class<?>[] {
IPocketUpgrade.class,
} );
computerCraft_getWirelessNetwork = findCCMethod( "getWirelessNetwork", new Class<?>[] {
} );
computerCraft_registerAPIFactory = findCCMethod( "registerAPIFactory", new Class<?>[] {
ILuaAPIFactory.class,
} );
computerCraft_createWiredNodeForElement = findCCMethod( "createWiredNodeForElement", new Class<?>[] {
IWiredElement.class,
} );
computerCraft_getWiredElementAt = findCCMethod( "getWiredElementAt", new Class<?>[] {
IBlockAccess.class, BlockPos.class, EnumFacing.class,
} );
}
catch( Exception e )
{
System.err.println( "ComputerCraftAPI: ComputerCraft not found." );
}
finally
{
ccSearched = true;
}
}
}
if( instance != null ) return instance;
private static Method findCCMethod( String name, Class<?>[] args )
{
try
{
return computerCraft != null ? computerCraft.getMethod( name, args ) : null;
return instance = (IComputerCraftAPI) Class.forName( "dan200.computercraft.ComputerCraftAPIImpl" )
.getField( "INSTANCE" ).get( null );
}
catch( NoSuchMethodException e )
catch( ReflectiveOperationException e )
{
System.err.println( "ComputerCraftAPI: ComputerCraft method " + name + " not found." );
return null;
throw new IllegalStateException( "Cannot find ComputerCraft API", e );
}
}
private static boolean ccSearched = false;
private static Class<?> computerCraft = null;
private static Method computerCraft_getVersion = null;
private static Method computerCraft_createUniqueNumberedSaveDir = null;
private static Method computerCraft_createSaveDirMount = null;
private static Method computerCraft_createResourceMount = null;
private static Method computerCraft_registerPeripheralProvider = null;
private static Method computerCraft_registerTurtleUpgrade = null;
private static Method computerCraft_registerBundledRedstoneProvider = null;
private static Method computerCraft_getDefaultBundledRedstoneOutput = null;
private static Method computerCraft_registerMediaProvider = null;
private static Method computerCraft_registerPermissionProvider = null;
private static Method computerCraft_registerPocketUpgrade = null;
private static Method computerCraft_getWirelessNetwork = null;
private static Method computerCraft_registerAPIFactory = null;
private static Method computerCraft_createWiredNodeForElement = null;
private static Method computerCraft_getWiredElementAt = null;
public interface IComputerCraftAPI
{
@Nonnull
String getInstalledVersion();
int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath );
@Nullable
IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity );
@Nullable
IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath );
void registerPeripheralProvider( @Nonnull IPeripheralProvider provider );
void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade );
void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider );
int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side );
void registerMediaProvider( @Nonnull IMediaProvider provider );
void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade );
@Nonnull
IPacketNetwork getWirelessNetwork();
void registerAPIFactory( @Nonnull ILuaAPIFactory factory );
@Nonnull
IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element );
@Nonnull
LazyOptional<IWiredElement> getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction side );
}
}

View File

@@ -1,10 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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|FileSystem", apiVersion = "${version}" )
package dan200.computercraft.api.filesystem;
import net.minecraftforge.fml.common.API;

View File

@@ -1,10 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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|Lua", apiVersion = "${version}" )
package dan200.computercraft.api.lua;
import net.minecraftforge.fml.common.API;

View File

@@ -1,10 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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|Media", apiVersion = "${version}" )
package dan200.computercraft.api.media;
import net.minecraftforge.fml.common.API;

View File

@@ -1,10 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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|Wired", apiVersion = "${version}" )
package dan200.computercraft.api.network.wired;
import net.minecraftforge.fml.common.API;

View File

@@ -1,10 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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", apiVersion = "${version}" )
package dan200.computercraft.api;
import net.minecraftforge.fml.common.API;

View File

@@ -7,7 +7,7 @@
package dan200.computercraft.api.peripheral;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@@ -34,5 +34,5 @@ public interface IPeripheralProvider
* @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider)
*/
@Nullable
IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side );
IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side );
}

View File

@@ -5,7 +5,7 @@
*/
package dan200.computercraft.api.peripheral;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@@ -25,8 +25,8 @@ public interface IPeripheralTile
*
* @param side The side to get the peripheral from.
* @return A peripheral, or {@code null} if there is not a peripheral here.
* @see IPeripheralProvider#getPeripheral(World, BlockPos, EnumFacing)
* @see IPeripheralProvider#getPeripheral(World, BlockPos, Direction)
*/
@Nullable
IPeripheral getPeripheral( @Nonnull EnumFacing side );
IPeripheral getPeripheral( @Nonnull Direction side );
}

View File

@@ -1,10 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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|Peripheral", apiVersion = "${version}" )
package dan200.computercraft.api.peripheral;
import net.minecraftforge.fml.common.API;

View File

@@ -1,42 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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.
*/
package dan200.computercraft.api.permissions;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
/**
* 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)
*/
public interface ITurtlePermissionProvider
{
/**
* 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 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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|Permissions", apiVersion = "${version}" )
package dan200.computercraft.api.permissions;
import net.minecraftforge.fml.common.API;

View File

@@ -6,7 +6,9 @@
package dan200.computercraft.api.pocket;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IItemProvider;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.Util;
import javax.annotation.Nonnull;
@@ -28,9 +30,14 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade
this.stack = stack;
}
protected AbstractPocketUpgrade( ResourceLocation id, ItemStack stack )
protected AbstractPocketUpgrade( ResourceLocation id, String adjective, IItemProvider item )
{
this( id, "upgrade." + id + ".adjective", stack );
this( id, adjective, new ItemStack( item ) );
}
protected AbstractPocketUpgrade( ResourceLocation id, IItemProvider item )
{
this( id, Util.makeTranslationKey( "upgrade", id ) + ".adjective", new ItemStack( item ) );
}
@Nonnull

View File

@@ -8,7 +8,7 @@ package dan200.computercraft.api.pocket;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull;
@@ -23,22 +23,12 @@ public interface IPocketAccess
/**
* Gets the entity holding this item.
*
* @return The holding entity. This may be {@code null}.
* @deprecated Use {@link #getValidEntity()} where possible.
*/
@Nullable
@Deprecated
Entity getEntity();
/**
* Gets the entity holding this item with additional safety checks.
*
* This must be called on the server thread.
*
* @return The holding entity, or {@code null} if none exists.
*/
@Nullable
Entity getValidEntity();
Entity getEntity();
/**
* Get the colour of this pocket computer as a RGB number.
@@ -85,7 +75,7 @@ public interface IPocketAccess
* @see #updateUpgradeNBTData()
*/
@Nonnull
NBTTagCompound getUpgradeNBTData();
CompoundNBT getUpgradeNBTData();
/**
* Mark the upgrade-specific NBT as dirty.

View File

@@ -6,7 +6,7 @@
package dan200.computercraft.api.redstone;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@@ -30,5 +30,5 @@ public interface IBundledRedstoneProvider
* handle this block.
* @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider)
*/
int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side );
int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side );
}

View File

@@ -1,10 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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|Redstone", apiVersion = "${version}" )
package dan200.computercraft.api.redstone;
import net.minecraftforge.fml.common.API;

View File

@@ -11,8 +11,8 @@ import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.inventory.IInventory;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
@@ -54,8 +54,7 @@ public interface ITurtleAccess
* @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)}.
* was cancelled.
* @throws UnsupportedOperationException When attempting to teleport on the client side.
*/
boolean teleportTo( @Nonnull World world, @Nonnull BlockPos pos );
@@ -84,10 +83,10 @@ public interface ITurtleAccess
* Returns the world direction the turtle is currently facing.
*
* @return The world direction the turtle is currently facing.
* @see #setDirection(EnumFacing)
* @see #setDirection(Direction)
*/
@Nonnull
EnumFacing getDirection();
Direction getDirection();
/**
* Set the direction the turtle is facing. Note that this will not play a rotation animation, you will also need to
@@ -96,7 +95,7 @@ public interface ITurtleAccess
* @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()
*/
void setDirection( @Nonnull EnumFacing dir );
void setDirection( @Nonnull Direction dir );
/**
* Get the currently selected slot in the turtle's inventory.
@@ -295,7 +294,7 @@ public interface ITurtleAccess
* @see #updateUpgradeNBTData(TurtleSide)
*/
@Nonnull
NBTTagCompound getUpgradeNBTData( @Nullable TurtleSide side );
CompoundNBT 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

View File

@@ -10,15 +10,15 @@ import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.turtle.event.TurtleAttackEvent;
import dan200.computercraft.api.turtle.event.TurtleBlockEvent;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.event.entity.player.AttackEntityEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
@@ -44,17 +44,6 @@ public interface ITurtleUpgrade
@Nonnull
ResourceLocation getUpgradeID();
/**
* Gets a numerical identifier representing this type of turtle upgrade,
* for backwards compatibility with pre-1.76 worlds. If your upgrade was
* not released for older ComputerCraft versions, you can return -1 here.
* The turtle will fail registration if an already used positive ID is specified.
*
* @return The legacy ID, or -1 if is needed.
* @see ComputerCraftAPI#registerTurtleUpgrade(ITurtleUpgrade)
*/
int getLegacyUpgradeID();
/**
* Return an unlocalised string to describe this type of turtle in turtle item names.
*
@@ -124,7 +113,7 @@ public interface ITurtleUpgrade
* to be called.
*/
@Nonnull
default TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull EnumFacing direction )
default TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction )
{
return TurtleCommandResult.failure();
}
@@ -133,7 +122,7 @@ public interface ITurtleUpgrade
* 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
* {@link net.minecraft.client.renderer.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!
@@ -142,7 +131,7 @@ public interface ITurtleUpgrade
* a transformation of {@code null} has the same effect as the identify matrix.
*/
@Nonnull
@SideOnly( Side.CLIENT )
@OnlyIn( Dist.CLIENT )
Pair<IBakedModel, Matrix4f> getModel( @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side );
/**

View File

@@ -6,7 +6,7 @@
package dan200.computercraft.api.turtle;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -15,7 +15,7 @@ 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)
* @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction)
*/
public final class TurtleCommandResult
{

View File

@@ -6,14 +6,14 @@
package dan200.computercraft.api.turtle;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
/**
* An enum representing the different actions that an {@link ITurtleUpgrade} of type Tool may be called on to perform by
* a turtle.
*
* @see ITurtleUpgrade#getType()
* @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)
* @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction)
*/
public enum TurtleVerb
{

View File

@@ -8,7 +8,7 @@ package dan200.computercraft.api.turtle.event;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.TurtleCommandResult;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import net.minecraftforge.eventbus.api.Cancelable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

View File

@@ -11,7 +11,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.turtle.TurtleVerb;
import net.minecraft.entity.Entity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.entity.player.AttackEntityEvent;
@@ -21,7 +21,7 @@ import java.util.Objects;
/**
* Fired when a turtle attempts to attack an entity.
*
* This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)},
* This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction)},
* as the base {@code turtle.attack()} command does not fire it.
*
* Note that such commands should also fire {@link AttackEntityEvent}, so you do not need to listen to both.

View File

@@ -12,9 +12,9 @@ import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.turtle.TurtleVerb;
import net.minecraft.block.state.IBlockState;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer;
@@ -75,7 +75,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent
/**
* Fired when a turtle attempts to dig a block.
*
* This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)},
* This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction)},
* as the base {@code turtle.dig()} command does not fire it.
*
* Note that such commands should also fire {@link BlockEvent.BreakEvent}, so you do not need to listen to both.
@@ -84,11 +84,11 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent
*/
public static class Dig extends TurtleBlockEvent
{
private final IBlockState block;
private final BlockState block;
private final ITurtleUpgrade upgrade;
private final TurtleSide side;
public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState block, @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side )
public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState block, @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side )
{
super( turtle, TurtleAction.DIG, player, world, pos );
@@ -106,7 +106,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent
* @return The block which is going to be broken.
*/
@Nonnull
public IBlockState getBlock()
public BlockState getBlock()
{
return block;
}
@@ -185,10 +185,10 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent
*/
public static class Inspect extends TurtleBlockEvent
{
private final IBlockState state;
private final BlockState state;
private final Map<String, Object> data;
public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull Map<String, Object> data )
public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull Map<String, Object> data )
{
super( turtle, TurtleAction.INSPECT, player, world, pos );
@@ -204,7 +204,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent
* @return The inspected block state.
*/
@Nonnull
public IBlockState getState()
public BlockState getState()
{
return state;
}

View File

@@ -7,7 +7,7 @@
package dan200.computercraft.api.turtle.event;
import dan200.computercraft.api.turtle.ITurtleAccess;
import net.minecraftforge.fml.common.eventhandler.Event;
import net.minecraftforge.eventbus.api.Event;
import javax.annotation.Nonnull;
import java.util.Objects;

View File

@@ -1,10 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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|Turtle|Event", apiVersion = "${version}" )
package dan200.computercraft.api.turtle.event;
import net.minecraftforge.fml.common.API;

View File

@@ -1,10 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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|Turtle", apiVersion = "${version}" )
package dan200.computercraft.api.turtle;
import net.minecraftforge.fml.common.API;

View File

@@ -8,178 +8,161 @@ package dan200.computercraft.client;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.TurtleModelLoader;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.turtle.items.ItemTurtleBase;
import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemMeshDefinition;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ModelBakery;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.IUnbakedModel;
import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ColorHandlerEvent;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.BasicState;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Map;
/**
* Registers textures and models for items.
*/
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD )
public final class ClientRegistry
{
private static final String[] EXTRA_MODELS = new String[] {
"turtle_modem_off_left",
"turtle_modem_on_left",
"turtle_modem_off_right",
"turtle_modem_on_right",
"turtle_modem_normal_off_left",
"turtle_modem_normal_on_left",
"turtle_modem_normal_off_right",
"turtle_modem_normal_on_right",
"turtle_modem_advanced_off_left",
"turtle_modem_advanced_on_left",
"turtle_modem_advanced_off_right",
"turtle_modem_advanced_on_right",
"turtle_crafting_table_left",
"turtle_crafting_table_right",
"advanced_turtle_modem_off_left",
"advanced_turtle_modem_on_left",
"advanced_turtle_modem_off_right",
"advanced_turtle_modem_on_right",
"turtle_speaker_upgrade_left",
"turtle_speaker_upgrade_right",
"turtle_white",
"turtle_colour",
"turtle_elf_overlay",
};
private static final String[] EXTRA_TEXTURES = new String[] {
// TODO: Gather these automatically from the model. I'm unable to get this working with Forge's current
// model loading code.
"block/turtle_colour",
"block/turtle_elf_overlay",
"block/turtle_crafty_face",
"block/turtle_speaker_face",
};
private ClientRegistry() {}
@SubscribeEvent
public static void registerModels( ModelRegistryEvent event )
{
ModelLoaderRegistry.registerLoader( TurtleModelLoader.INSTANCE );
// Register item models
registerUniversalItemModel( ComputerCraft.Items.computer, "computer" );
registerItemModel( ComputerCraft.Items.commandComputer, 0, "command_computer" );
registerItemModel( ComputerCraft.Items.pocketComputer, 0, "pocket_computer" );
registerItemModel( ComputerCraft.Items.pocketComputer, 1, "advanced_pocket_computer" );
registerItemModel( ComputerCraft.Items.peripheral, 0, "peripheral" );
registerItemModel( ComputerCraft.Items.peripheral, 1, "wireless_modem" );
registerItemModel( ComputerCraft.Items.peripheral, 2, "monitor" );
registerItemModel( ComputerCraft.Items.peripheral, 3, "printer" );
registerItemModel( ComputerCraft.Items.peripheral, 4, "advanced_monitor" );
registerItemModel( ComputerCraft.Items.cable, 0, "cable" );
registerItemModel( ComputerCraft.Items.cable, 1, "wired_modem" );
registerItemModel( ComputerCraft.Items.advancedModem, 0, "advanced_modem" );
registerItemModel( ComputerCraft.Items.peripheral, 5, "speaker" );
registerItemModel( ComputerCraft.Items.wiredModemFull, 0, "wired_modem_full" );
registerUniversalItemModel( ComputerCraft.Items.disk, "disk" );
registerItemModel( ComputerCraft.Items.diskExpanded, 0, "disk_expanded" );
registerItemModel( ComputerCraft.Items.treasureDisk, 0, "treasure_disk" );
registerItemModel( ComputerCraft.Items.printout, 0, "printout" );
registerItemModel( ComputerCraft.Items.printout, 1, "pages" );
registerItemModel( ComputerCraft.Items.printout, 2, "book" );
registerUniversalItemModel( ComputerCraft.Items.turtle, "turtle" );
registerUniversalItemModel( ComputerCraft.Items.turtleExpanded, "turtle" );
registerUniversalItemModel( ComputerCraft.Items.turtleAdvanced, "turtle_advanced" );
}
@SubscribeEvent
public static void onTextureStitchEvent( TextureStitchEvent.Pre event )
{
// Load all textures for the extra models
TextureMap map = event.getMap();
for( String upgrade : EXTRA_MODELS )
/*
IResourceManager manager = Minecraft.getInstance().getResourceManager();
for( String extra : EXTRA_TEXTURES )
{
IModel model = ModelLoaderRegistry.getModelOrMissing( new ResourceLocation( "computercraft", "block/" + upgrade ) );
for( ResourceLocation texture : model.getTextures() ) map.registerSprite( texture );
// TODO: event.getMap().registerSprite( manager, new ResourceLocation( ComputerCraft.MOD_ID, extra ) );
}
*/
}
@SubscribeEvent
public static void onModelBakeEvent( ModelBakeEvent event )
{
// Load all extra models
for( String model : EXTRA_MODELS ) loadBlockModel( event, model );
ModelLoader loader = event.getModelLoader();
Map<ResourceLocation, IBakedModel> registry = event.getModelRegistry();
for( String model : EXTRA_MODELS )
{
IBakedModel bakedModel = bake( loader, loader.getUnbakedModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/" + model ) ) );
if( bakedModel != null )
{
registry.put(
new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, model ), "inventory" ),
bakedModel
);
}
}
// And load the custom turtle models in too.
registry.put(
new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ), "inventory" ),
bake( loader, TurtleModelLoader.INSTANCE.loadModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/turtle_normal" ) ) )
);
registry.put(
new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ), "inventory" ),
bake( loader, TurtleModelLoader.INSTANCE.loadModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/turtle_advanced" ) ) )
);
}
@SubscribeEvent
public static void onItemColours( ColorHandlerEvent.Item event )
{
event.getItemColors().registerItemColorHandler(
( stack, layer ) -> layer == 1 ? ((ItemDiskLegacy) stack.getItem()).getColour( stack ) : 0xFFFFFF,
ComputerCraft.Items.disk, ComputerCraft.Items.diskExpanded
if( ComputerCraft.Items.disk == null || ComputerCraft.Blocks.turtleNormal == null )
{
ComputerCraft.log.warn( "Block/item registration has failed. Skipping registration of item colours." );
return;
}
event.getItemColors().register(
( stack, layer ) -> layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF,
ComputerCraft.Items.disk
);
event.getItemColors().registerItemColorHandler( ( stack, layer ) -> {
event.getItemColors().register( ( stack, layer ) -> {
switch( layer )
{
case 0:
default:
return 0xFFFFFF;
case 1: // Frame colour
return ComputerCraft.Items.pocketComputer.getColour( stack );
return IColouredItem.getColourBasic( stack );
case 2: // Light colour
{
int light = ItemPocketComputer.getLightState( stack );
return light == -1 ? Colour.Black.getHex() : light;
}
}
}, ComputerCraft.Items.pocketComputer );
}, ComputerCraft.Items.pocketComputerNormal, ComputerCraft.Items.pocketComputerAdvanced );
// Setup turtle colours
event.getItemColors().registerItemColorHandler(
( stack, tintIndex ) -> tintIndex == 0 ? ((ItemTurtleBase) stack.getItem()).getColour( stack ) : 0xFFFFFF,
ComputerCraft.Blocks.turtle, ComputerCraft.Blocks.turtleExpanded, ComputerCraft.Blocks.turtleAdvanced
event.getItemColors().register(
( stack, tintIndex ) -> tintIndex == 0 ? ((IColouredItem) stack.getItem()).getColour( stack ) : 0xFFFFFF,
ComputerCraft.Blocks.turtleNormal, ComputerCraft.Blocks.turtleAdvanced
);
}
private static void registerItemModel( Item item, int damage, String name )
private static IBakedModel bake( ModelLoader loader, IUnbakedModel model )
{
ResourceLocation location = new ResourceLocation( ComputerCraft.MOD_ID, name );
final ModelResourceLocation res = new ModelResourceLocation( location, "inventory" );
ModelBakery.registerItemVariants( item, location );
ModelLoader.setCustomModelResourceLocation( item, damage, res );
}
model.getTextures( loader::getUnbakedModel, new HashSet<>() );
private static void registerUniversalItemModel( Item item, String mainModel )
{
ResourceLocation mainLocation = new ResourceLocation( ComputerCraft.MOD_ID, mainModel );
ModelBakery.registerItemVariants( item, mainLocation );
final ModelResourceLocation mainModelLocation = new ModelResourceLocation( mainLocation, "inventory" );
ModelLoader.setCustomMeshDefinition( item, new ItemMeshDefinition()
{
@Nonnull
@Override
public ModelResourceLocation getModelLocation( @Nonnull ItemStack stack )
{
return mainModelLocation;
}
} );
}
private static void loadBlockModel( ModelBakeEvent event, String name )
{
IModel model = ModelLoaderRegistry.getModelOrMissing( new ResourceLocation( ComputerCraft.MOD_ID, "block/" + name ) );
IBakedModel bakedModel = model.bake(
model.getDefaultState(), DefaultVertexFormats.ITEM,
location -> Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( location.toString() )
return model.bake(
loader,
ModelLoader.defaultTextureGetter(),
new BasicState( model.getDefaultState(), false ), DefaultVertexFormats.BLOCK
);
event.getModelRegistry().putObject( new ModelResourceLocation( ComputerCraft.MOD_ID + ":" + name, "inventory" ), bakedModel );
}
}

View File

@@ -12,8 +12,8 @@ import dan200.computercraft.shared.command.text.TableFormatter;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.client.gui.GuiUtilRenderComponents;
import net.minecraft.client.gui.NewChatGui;
import net.minecraft.client.gui.RenderComponentsUtil;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextFormatting;
@@ -30,7 +30,7 @@ public class ClientTableFormatter implements TableFormatter
private static FontRenderer renderer()
{
return Minecraft.getMinecraft().fontRenderer;
return Minecraft.getInstance().fontRenderer;
}
@Override
@@ -42,7 +42,7 @@ public class ClientTableFormatter implements TableFormatter
FontRenderer renderer = renderer();
float spaceWidth = renderer.getCharWidth( ' ' );
float spaceWidth = renderer.getStringWidth( " " );
int spaces = MathHelper.floor( extraWidth / spaceWidth );
int extra = extraWidth - (int) (spaces * spaceWidth);
@@ -64,19 +64,19 @@ public class ClientTableFormatter implements TableFormatter
@Override
public void writeLine( int id, ITextComponent component )
{
Minecraft mc = Minecraft.getMinecraft();
GuiNewChat chat = mc.ingameGUI.getChatGUI();
Minecraft mc = Minecraft.getInstance();
NewChatGui chat = mc.ingameGUI.getChatGUI();
// Trim the text if it goes over the allowed length
int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getChatScale() );
List<ITextComponent> list = GuiUtilRenderComponents.splitText( component, maxWidth, mc.fontRenderer, false, false );
int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() );
List<ITextComponent> list = RenderComponentsUtil.splitText( component, maxWidth, mc.fontRenderer, false, false );
if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id );
}
@Override
public int display( TableBuilder table )
{
GuiNewChat chat = Minecraft.getMinecraft().ingameGUI.getChatGUI();
NewChatGui chat = Minecraft.getInstance().ingameGUI.getChatGUI();
int lastHeight = lastHeights.get( table.getId() );

View File

@@ -7,12 +7,12 @@
package dan200.computercraft.client;
import dan200.computercraft.ComputerCraft;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class FrameInfo
{
private static int tick;

View File

@@ -6,11 +6,11 @@
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
@@ -39,7 +39,7 @@ public final class FixedWidthFontRenderer
private FixedWidthFontRenderer()
{
m_textureManager = Minecraft.getMinecraft().getTextureManager();
m_textureManager = Minecraft.getInstance().getTextureManager();
}
private static void greyscaleify( double[] rgb )
@@ -129,9 +129,9 @@ public final class FixedWidthFontRenderer
}
drawQuad( renderer, x + i * FONT_WIDTH, y, colour, FONT_WIDTH, p, greyScale );
}
GlStateManager.disableTexture2D();
GlStateManager.disableTexture();
tessellator.draw();
GlStateManager.enableTexture2D();
GlStateManager.enableTexture();
}
public void drawStringTextPart( int x, int y, TextBuffer s, TextBuffer textColour, boolean greyScale, Palette p )
@@ -195,6 +195,6 @@ public final class FixedWidthFontRenderer
public void bindFont()
{
m_textureManager.bindTexture( FONT );
GlStateManager.glTexParameteri( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP );
GlStateManager.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP );
}
}

View File

@@ -6,25 +6,25 @@
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.client.gui.widgets.WidgetWrapper;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.inventory.Container;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import net.minecraft.util.text.ITextComponent;
import org.lwjgl.glfw.GLFW;
import java.io.IOException;
public class GuiComputer extends GuiContainer
public final class GuiComputer<T extends ContainerComputerBase> extends ContainerScreen<T>
{
public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners.png" );
public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" );
public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" );
public static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" );
public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_colour.png" );
@@ -33,151 +33,154 @@ public class GuiComputer extends GuiContainer
private final ClientComputer m_computer;
private final int m_termWidth;
private final int m_termHeight;
private WidgetTerminal m_terminal;
public GuiComputer( Container container, ComputerFamily family, ClientComputer computer, int termWidth, int termHeight )
private WidgetTerminal terminal;
private WidgetWrapper terminalWrapper;
private GuiComputer(
T container, PlayerInventory player, ITextComponent title, int termWidth, int termHeight
)
{
super( container );
m_family = family;
m_computer = computer;
super( container, player, title );
m_family = container.getFamily();
m_computer = (ClientComputer) container.getComputer();
m_termWidth = termWidth;
m_termHeight = termHeight;
m_terminal = null;
terminal = null;
}
@Deprecated
public GuiComputer( Container container, ComputerFamily family, IComputer computer, int termWidth, int termHeight )
public static GuiComputer<ContainerComputer> create( ContainerComputer container, PlayerInventory inventory, ITextComponent component )
{
this( container, family, (ClientComputer) computer, termWidth, termHeight );
}
public GuiComputer( TileComputer computer )
{
this(
new ContainerComputer( computer ),
computer.getFamily(),
computer.createClientComputer(),
ComputerCraft.terminalWidth_computer,
ComputerCraft.terminalHeight_computer
return new GuiComputer<>(
container, inventory, component,
ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer
);
}
@Override
public void initGui()
public static GuiComputer<ContainerPocketComputer> createPocket( ContainerPocketComputer container, PlayerInventory inventory, ITextComponent component )
{
super.initGui();
Keyboard.enableRepeatEvents( true );
return new GuiComputer<>(
container, inventory, component,
ComputerCraft.terminalWidth_pocketComputer, ComputerCraft.terminalHeight_pocketComputer
);
}
m_terminal = new WidgetTerminal( 0, 0, m_termWidth, m_termHeight, () -> m_computer, 2, 2, 2, 2 );
m_terminal.setAllowFocusLoss( false );
xSize = m_terminal.getWidth() + 24;
ySize = m_terminal.getHeight() + 24;
public static GuiComputer<ContainerViewComputer> createView( ContainerViewComputer container, PlayerInventory inventory, ITextComponent component )
{
return new GuiComputer<>(
container, inventory, component,
container.getWidth(), container.getHeight()
);
}
@Override
protected void init()
{
minecraft.keyboardListener.enableRepeatEvents( true );
int termPxWidth = m_termWidth * FixedWidthFontRenderer.FONT_WIDTH;
int termPxHeight = m_termHeight * FixedWidthFontRenderer.FONT_HEIGHT;
xSize = termPxWidth + 4 + 24;
ySize = termPxHeight + 4 + 24;
super.init();
terminal = new WidgetTerminal( minecraft, () -> m_computer, m_termWidth, m_termHeight, 2, 2, 2, 2 );
terminalWrapper = new WidgetWrapper( terminal, 2 + 12 + guiLeft, 2 + 12 + guiTop, termPxWidth, termPxHeight );
children.add( terminalWrapper );
setFocused( terminalWrapper );
}
@Override
public void onGuiClosed()
public void removed()
{
super.onGuiClosed();
Keyboard.enableRepeatEvents( false );
super.removed();
children.remove( terminal );
terminal = null;
minecraft.keyboardListener.enableRepeatEvents( false );
}
@Override
public void updateScreen()
public void tick()
{
super.updateScreen();
m_terminal.update();
super.tick();
terminal.update();
}
@Override
protected void keyTyped( char c, int k ) throws IOException
public boolean keyPressed( int key, int scancode, int modifiers )
{
if( k == 1 )
// Forward the tab key to the terminal, rather than moving between controls.
if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminalWrapper )
{
super.keyTyped( c, k );
}
else
{
if( m_terminal.onKeyTyped( c, k ) ) keyHandled = true;
return getFocused().keyPressed( key, scancode, modifiers );
}
return super.keyPressed( key, scancode, modifiers );
}
@Override
protected void mouseClicked( int x, int y, int button )
{
int startX = (width - m_terminal.getWidth()) / 2;
int startY = (height - m_terminal.getHeight()) / 2;
m_terminal.mouseClicked( x - startX, y - startY, button );
}
@Override
public void handleMouseInput() throws IOException
{
super.handleMouseInput();
int x = Mouse.getEventX() * width / mc.displayWidth;
int y = height - Mouse.getEventY() * height / mc.displayHeight - 1;
int startX = (width - m_terminal.getWidth()) / 2;
int startY = (height - m_terminal.getHeight()) / 2;
m_terminal.handleMouseInput( x - startX, y - startY );
}
@Override
public void handleKeyboardInput() throws IOException
{
super.handleKeyboardInput();
if( m_terminal.onKeyboardInput() ) keyHandled = true;
}
@Override
protected void drawGuiContainerForegroundLayer( int par1, int par2 )
{
}
@Override
protected void drawGuiContainerBackgroundLayer( float var1, int var2, int var3 )
{
}
@Override
public void drawScreen( int mouseX, int mouseY, float partialTicks )
public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
{
// Work out where to draw
int startX = (width - m_terminal.getWidth()) / 2;
int startY = (height - m_terminal.getHeight()) / 2;
int endX = startX + m_terminal.getWidth();
int endY = startY + m_terminal.getHeight();
// Draw background
drawDefaultBackground();
int startX = terminalWrapper.getX() - 2;
int startY = terminalWrapper.getY() - 2;
int endX = startX + terminalWrapper.getWidth() + 4;
int endY = startY + terminalWrapper.getHeight() + 4;
// Draw terminal
m_terminal.draw( mc, startX, startY, mouseX, mouseY );
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
// Draw a border around the terminal
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
switch( m_family )
{
case Normal:
default:
mc.getTextureManager().bindTexture( BACKGROUND_NORMAL );
minecraft.getTextureManager().bindTexture( BACKGROUND_NORMAL );
break;
case Advanced:
mc.getTextureManager().bindTexture( BACKGROUND_ADVANCED );
minecraft.getTextureManager().bindTexture( BACKGROUND_ADVANCED );
break;
case Command:
mc.getTextureManager().bindTexture( BACKGROUND_COMMAND );
minecraft.getTextureManager().bindTexture( BACKGROUND_COMMAND );
break;
}
drawTexturedModalRect( startX - 12, startY - 12, 12, 28, 12, 12 );
drawTexturedModalRect( startX - 12, endY, 12, 40, 12, 12 );
drawTexturedModalRect( endX, startY - 12, 24, 28, 12, 12 );
drawTexturedModalRect( endX, endY, 24, 40, 12, 12 );
blit( startX - 12, startY - 12, 12, 28, 12, 12 );
blit( startX - 12, endY, 12, 40, 12, 12 );
blit( endX, startY - 12, 24, 28, 12, 12 );
blit( endX, endY, 24, 40, 12, 12 );
drawTexturedModalRect( startX, startY - 12, 0, 0, endX - startX, 12 );
drawTexturedModalRect( startX, endY, 0, 12, endX - startX, 12 );
blit( startX, startY - 12, 0, 0, endX - startX, 12 );
blit( startX, endY, 0, 12, endX - startX, 12 );
drawTexturedModalRect( startX - 12, startY, 0, 28, 12, endY - startY );
drawTexturedModalRect( endX, startY, 36, 28, 12, endY - startY );
blit( startX - 12, startY, 0, 28, 12, endY - startY );
blit( endX, startY, 36, 28, 12, endY - startY );
}
@Override
public void render( int mouseX, int mouseY, float partialTicks )
{
renderBackground();
super.render( mouseX, mouseY, partialTicks );
renderHoveredToolTip( mouseX, mouseY );
}
@Override
public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
{
return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ))
|| super.mouseDragged( x, y, button, deltaX, deltaY );
}
@Override
public boolean mouseReleased( double x, double y, int button )
{
return (getFocused() != null && getFocused().mouseReleased( x, y, button ))
|| super.mouseReleased( x, y, button );
}
}

View File

@@ -1,50 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.Config;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.IModGuiFactory;
import net.minecraftforge.fml.client.config.GuiConfig;
import java.util.Set;
public class GuiConfigCC extends GuiConfig
{
public GuiConfigCC( GuiScreen parentScreen )
{
super( parentScreen, Config.getConfigElements(), ComputerCraft.MOD_ID, false, false, "CC: Tweaked" );
}
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

@@ -6,45 +6,43 @@
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
public class GuiDiskDrive extends GuiContainer
public class GuiDiskDrive extends ContainerScreen<ContainerDiskDrive>
{
private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/diskdrive.png" );
private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/disk_drive.png" );
private final ContainerDiskDrive m_container;
public GuiDiskDrive( ContainerDiskDrive container )
public GuiDiskDrive( ContainerDiskDrive container, PlayerInventory player, ITextComponent title )
{
super( container );
m_container = container;
super( container, player, title );
}
@Override
protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY )
{
String title = m_container.getDiskDrive().getDisplayName().getUnformattedText();
fontRenderer.drawString( title, (xSize - fontRenderer.getStringWidth( title )) / 2, 6, 0x404040 );
fontRenderer.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 );
String title = this.title.getFormattedText();
font.drawString( title, (xSize - font.getStringWidth( title )) / 2.0f, 6, 0x404040 );
font.drawString( title, 8, ySize - 96 + 2, 0x404040 );
}
@Override
protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
{
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
mc.getTextureManager().bindTexture( BACKGROUND );
drawTexturedModalRect( guiLeft, guiTop, 0, 0, xSize, ySize );
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bindTexture( BACKGROUND );
blit( guiLeft, guiTop, 0, 0, xSize, ySize );
}
@Override
public void drawScreen( int mouseX, int mouseY, float partialTicks )
public void render( int mouseX, int mouseY, float partialTicks )
{
drawDefaultBackground();
super.drawScreen( mouseX, mouseY, partialTicks );
renderBackground();
super.render( mouseX, mouseY, partialTicks );
renderHoveredToolTip( mouseX, mouseY );
}
}

View File

@@ -1,25 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
public class GuiPocketComputer extends GuiComputer
{
public GuiPocketComputer( ContainerHeldItem container )
{
super(
container,
ComputerCraft.Items.pocketComputer.getFamily( container.getStack() ),
ItemPocketComputer.createClientComputer( container.getStack() ),
ComputerCraft.terminalWidth_pocketComputer,
ComputerCraft.terminalHeight_pocketComputer
);
}
}

View File

@@ -6,47 +6,46 @@
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
public class GuiPrinter extends GuiContainer
public class GuiPrinter extends ContainerScreen<ContainerPrinter>
{
private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/printer.png" );
private final ContainerPrinter container;
public GuiPrinter( ContainerPrinter container )
public GuiPrinter( ContainerPrinter container, PlayerInventory player, ITextComponent title )
{
super( container );
this.container = container;
super( container, player, title );
}
@Override
protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY )
{
String title = container.getPrinter().getDisplayName().getUnformattedText();
fontRenderer.drawString( title, (xSize - fontRenderer.getStringWidth( title )) / 2, 6, 0x404040 );
fontRenderer.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 );
String title = getTitle().getFormattedText();
font.drawString( title, (xSize - font.getStringWidth( title )) / 2.0f, 6, 0x404040 );
font.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 );
}
@Override
protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
{
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
mc.getTextureManager().bindTexture( BACKGROUND );
drawTexturedModalRect( guiLeft, guiTop, 0, 0, xSize, ySize );
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bindTexture( BACKGROUND );
blit( guiLeft, guiTop, 0, 0, xSize, ySize );
if( container.isPrinting() ) drawTexturedModalRect( guiLeft + 34, guiTop + 21, 176, 0, 25, 45 );
if( getContainer().isPrinting() ) blit( guiLeft + 34, guiTop + 21, 176, 0, 25, 45 );
}
@Override
public void drawScreen( int mouseX, int mouseY, float partialTicks )
public void render( int mouseX, int mouseY, float partialTicks )
{
drawDefaultBackground();
super.drawScreen( mouseX, mouseY, partialTicks );
renderBackground();
super.render( mouseX, mouseY, partialTicks );
renderHoveredToolTip( mouseX, mouseY );
}
}

View File

@@ -6,18 +6,18 @@
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import org.lwjgl.input.Mouse;
import java.io.IOException;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.text.ITextComponent;
import org.lwjgl.glfw.GLFW;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
public class GuiPrintout extends GuiContainer
public class GuiPrintout extends ContainerScreen<ContainerHeldItem>
{
private final boolean m_book;
private final int m_pages;
@@ -25,9 +25,9 @@ public class GuiPrintout extends GuiContainer
private final TextBuffer[] m_colours;
private int m_page;
public GuiPrintout( ContainerHeldItem container )
public GuiPrintout( ContainerHeldItem container, PlayerInventory player, ITextComponent title )
{
super( container );
super( container, player, title );
ySize = Y_SIZE;
@@ -41,63 +41,70 @@ public class GuiPrintout extends GuiContainer
m_page = 0;
m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 );
m_book = ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book;
m_book = ((ItemPrintout) container.getStack().getItem()).getType() == ItemPrintout.Type.BOOK;
}
@Override
protected void keyTyped( char c, int k ) throws IOException
public boolean keyPressed( int key, int scancode, int modifiers )
{
super.keyTyped( c, k );
if( super.keyPressed( key, scancode, modifiers ) ) return true;
if( k == 205 )
if( key == GLFW.GLFW_KEY_RIGHT )
{
// Right
if( m_page < m_pages - 1 ) m_page++;
return true;
}
else if( k == 203 )
if( key == GLFW.GLFW_KEY_LEFT )
{
// Left
if( m_page > 0 ) m_page--;
return true;
}
return false;
}
@Override
public void handleMouseInput() throws IOException
public boolean mouseScrolled( double x, double y, double delta )
{
super.handleMouseInput();
int mouseWheelChange = Mouse.getEventDWheel();
if( mouseWheelChange < 0 )
if( super.mouseScrolled( x, y, delta ) ) return true;
if( delta < 0 )
{
// Scroll up goes to the next page
if( m_page < m_pages - 1 ) m_page++;
return true;
}
else if( mouseWheelChange > 0 )
if( delta > 0 )
{
// Scroll down goes to the previous page
if( m_page > 0 ) m_page--;
return true;
}
return false;
}
@Override
protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
{
// Draw the printout
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.enableDepthTest();
drawBorder( guiLeft, guiTop, zLevel, m_page, m_pages, m_book );
drawBorder( guiLeft, guiTop, blitOffset, m_page, m_pages, m_book );
drawText( guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours );
}
@Override
public void drawScreen( int mouseX, int mouseY, float partialTicks )
public void render( int mouseX, int mouseY, float partialTicks )
{
// We must take the background further back in order to not overlap with our printed pages.
zLevel--;
drawDefaultBackground();
zLevel++;
blitOffset--;
renderBackground();
blitOffset++;
super.drawScreen( mouseX, mouseY, partialTicks );
super.render( mouseX, mouseY, partialTicks );
renderHoveredToolTip( mouseX, mouseY );
}
}

View File

@@ -6,121 +6,104 @@
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.client.gui.widgets.WidgetWrapper;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import net.minecraft.util.text.ITextComponent;
import org.lwjgl.glfw.GLFW;
import java.io.IOException;
public class GuiTurtle extends GuiContainer
public class GuiTurtle extends ContainerScreen<ContainerTurtle>
{
private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/turtle.png" );
private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/turtle_normal.png" );
private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( "computercraft", "textures/gui/turtle_advanced.png" );
private ContainerTurtle m_container;
private final ComputerFamily m_family;
private final ClientComputer m_computer;
private WidgetTerminal m_terminalGui;
public GuiTurtle( TileTurtle turtle, ContainerTurtle container )
private WidgetTerminal terminal;
private WidgetWrapper terminalWrapper;
public GuiTurtle( ContainerTurtle container, PlayerInventory player, ITextComponent title )
{
super( container );
super( container, player, title );
m_container = container;
m_family = turtle.getFamily();
m_computer = turtle.getClientComputer();
m_family = container.getFamily();
m_computer = (ClientComputer) container.getComputer();
xSize = 254;
ySize = 217;
}
@Override
public void initGui()
protected void init()
{
super.initGui();
Keyboard.enableRepeatEvents( true );
m_terminalGui = new WidgetTerminal(
guiLeft + 8,
guiTop + 8,
super.init();
minecraft.keyboardListener.enableRepeatEvents( true );
int termPxWidth = ComputerCraft.terminalWidth_turtle * FixedWidthFontRenderer.FONT_WIDTH;
int termPxHeight = ComputerCraft.terminalHeight_turtle * FixedWidthFontRenderer.FONT_HEIGHT;
terminal = new WidgetTerminal(
minecraft, () -> m_computer,
ComputerCraft.terminalWidth_turtle,
ComputerCraft.terminalHeight_turtle,
() -> m_computer,
2, 2, 2, 2
);
m_terminalGui.setAllowFocusLoss( false );
terminalWrapper = new WidgetWrapper( terminal, 2 + 8 + guiLeft, 2 + 8 + guiTop, termPxWidth, termPxHeight );
children.add( terminalWrapper );
setFocused( terminalWrapper );
}
@Override
public void onGuiClosed()
public void removed()
{
super.onGuiClosed();
Keyboard.enableRepeatEvents( false );
super.removed();
children.remove( terminal );
terminal = null;
minecraft.keyboardListener.enableRepeatEvents( false );
}
@Override
public void updateScreen()
public void tick()
{
super.updateScreen();
m_terminalGui.update();
super.tick();
terminal.update();
}
@Override
protected void keyTyped( char c, int k ) throws IOException
public boolean keyPressed( int key, int scancode, int modifiers )
{
if( k == 1 )
// Forward the tab key to the terminal, rather than moving between controls.
if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminalWrapper )
{
super.keyTyped( c, k );
}
else
{
if( m_terminalGui.onKeyTyped( c, k ) ) keyHandled = true;
return getFocused().keyPressed( key, scancode, modifiers );
}
return super.keyPressed( key, scancode, modifiers );
}
@Override
protected void mouseClicked( int x, int y, int button ) throws IOException
{
super.mouseClicked( x, y, button );
m_terminalGui.mouseClicked( x, y, button );
}
@Override
public void handleMouseInput() throws IOException
{
super.handleMouseInput();
int x = Mouse.getEventX() * width / mc.displayWidth;
int y = height - Mouse.getEventY() * height / mc.displayHeight - 1;
m_terminalGui.handleMouseInput( x, y );
}
@Override
public void handleKeyboardInput() throws IOException
{
super.handleKeyboardInput();
if( m_terminalGui.onKeyboardInput() ) keyHandled = true;
}
protected void drawSelectionSlot( boolean advanced )
private void drawSelectionSlot( boolean advanced )
{
// Draw selection slot
int slot = m_container.getSelectedSlot();
if( slot >= 0 )
{
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
int slotX = slot % 4;
int slotY = slot / 4;
mc.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
drawTexturedModalRect( guiLeft + m_container.turtleInvStartX - 2 + slotX * 18, guiTop + m_container.playerInvStartY - 2 + slotY * 18, 0, 217, 24, 24 );
minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
blit( guiLeft + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, guiTop + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, 0, 217, 24, 24 );
}
}
@@ -129,21 +112,21 @@ public class GuiTurtle extends GuiContainer
{
// Draw term
boolean advanced = m_family == ComputerFamily.Advanced;
m_terminalGui.draw( Minecraft.getMinecraft(), 0, 0, mouseX, mouseY );
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
// Draw border/inventory
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
mc.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
drawTexturedModalRect( guiLeft, guiTop, 0, 0, xSize, ySize );
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
blit( guiLeft, guiTop, 0, 0, xSize, ySize );
drawSelectionSlot( advanced );
}
@Override
public void drawScreen( int mouseX, int mouseY, float partialTicks )
public void render( int mouseX, int mouseY, float partialTicks )
{
drawDefaultBackground();
super.drawScreen( mouseX, mouseY, partialTicks );
renderBackground();
super.render( mouseX, mouseY, partialTicks );
renderHoveredToolTip( mouseX, mouseY );
}
}

View File

@@ -1,84 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui.widgets;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
public abstract class Widget extends Gui
{
private int m_xPosition;
private int m_yPosition;
private int m_width;
private int m_height;
protected Widget( int x, int y, int width, int height )
{
m_xPosition = x;
m_yPosition = y;
m_width = width;
m_height = height;
}
public int getXPosition()
{
return m_xPosition;
}
public int getYPosition()
{
return m_yPosition;
}
public int getWidth()
{
return m_width;
}
public int getHeight()
{
return m_height;
}
public void update()
{
}
public void draw( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY )
{
}
public void handleMouseInput( int mouseX, int mouseY )
{
}
public boolean onKeyboardInput()
{
return false;
}
@Deprecated
public void handleKeyboardInput()
{
onKeyboardInput();
}
public void mouseClicked( int mouseX, int mouseY, int mouseButton )
{
}
public boolean onKeyTyped( char c, int k )
{
return false;
}
@Deprecated
public void keyTyped( char c, int k )
{
onKeyTyped( c, k );
}
}

View File

@@ -6,375 +6,366 @@
package dan200.computercraft.client.gui.widgets;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.computer.core.IComputerContainer;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.ChatAllowedCharacters;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import net.minecraft.client.gui.IGuiEventListener;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.SharedConstants;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL11;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.function.Supplier;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.BACKGROUND;
public class WidgetTerminal extends Widget
public class WidgetTerminal implements IGuiEventListener
{
private static final float TERMINATE_TIME = 0.5f;
private final IComputerContainer m_computer;
private final Minecraft client;
private float m_terminateTimer = 0.0f;
private float m_rebootTimer = 0.0f;
private float m_shutdownTimer = 0.0f;
private boolean focused;
private int m_lastClickButton = -1;
private int m_lastClickX = -1;
private int m_lastClickY = -1;
private final Supplier<ClientComputer> computer;
private final int termWidth;
private final int termHeight;
private boolean m_focus = false;
private boolean m_allowFocusLoss = true;
private float terminateTimer = -1;
private float rebootTimer = -1;
private float shutdownTimer = -1;
private int m_leftMargin;
private int m_rightMargin;
private int m_topMargin;
private int m_bottomMargin;
private int lastMouseButton = -1;
private int lastMouseX = -1;
private int lastMouseY = -1;
private final ArrayList<Integer> m_keysDown = new ArrayList<>();
private final int leftMargin;
private final int rightMargin;
private final int topMargin;
private final int bottomMargin;
public WidgetTerminal( int x, int y, int termWidth, int termHeight, IComputerContainer computer, int leftMargin, int rightMargin, int topMargin, int bottomMargin )
private final BitSet keysDown = new BitSet( 256 );
public WidgetTerminal( Minecraft client, Supplier<ClientComputer> computer, int termWidth, int termHeight, int leftMargin, int rightMargin, int topMargin, int bottomMargin )
{
super(
x, y,
leftMargin + rightMargin + termWidth * FixedWidthFontRenderer.FONT_WIDTH,
topMargin + bottomMargin + termHeight * FixedWidthFontRenderer.FONT_HEIGHT
);
m_computer = computer;
m_leftMargin = leftMargin;
m_rightMargin = rightMargin;
m_topMargin = topMargin;
m_bottomMargin = bottomMargin;
}
public void setAllowFocusLoss( boolean allowFocusLoss )
{
m_allowFocusLoss = allowFocusLoss;
m_focus = m_focus || !allowFocusLoss;
this.client = client;
this.computer = computer;
this.termWidth = termWidth;
this.termHeight = termHeight;
this.leftMargin = leftMargin;
this.rightMargin = rightMargin;
this.topMargin = topMargin;
this.bottomMargin = bottomMargin;
}
@Override
public boolean onKeyTyped( char ch, int key )
public boolean charTyped( char ch, int modifiers )
{
if( m_focus )
if( ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255 ) // printable chars in byte range
{
// Ctrl+V for paste
if( ch == 22 )
// Queue the "char" event
queueEvent( "char", Character.toString( ch ) );
}
return true;
}
@Override
public boolean keyPressed( int key, int scancode, int modifiers )
{
if( key == GLFW.GLFW_KEY_ESCAPE ) return false;
if( (modifiers & GLFW.GLFW_MOD_CONTROL) != 0 )
{
switch( key )
{
String clipboard = GuiScreen.getClipboardString();
if( clipboard != null )
{
// Clip to the first occurrence of \r or \n
int newLineIndex1 = clipboard.indexOf( '\r' );
int newLineIndex2 = clipboard.indexOf( '\n' );
if( newLineIndex1 >= 0 && newLineIndex2 >= 0 )
{
clipboard = clipboard.substring( 0, Math.min( newLineIndex1, newLineIndex2 ) );
}
else if( newLineIndex1 >= 0 )
{
clipboard = clipboard.substring( 0, newLineIndex1 );
}
else if( newLineIndex2 >= 0 )
{
clipboard = clipboard.substring( 0, newLineIndex2 );
}
case GLFW.GLFW_KEY_T:
if( terminateTimer < 0 ) terminateTimer = 0;
return true;
case GLFW.GLFW_KEY_S:
if( shutdownTimer < 0 ) shutdownTimer = 0;
return true;
case GLFW.GLFW_KEY_R:
if( rebootTimer < 0 ) rebootTimer = 0;
return true;
// Filter the string
clipboard = ChatAllowedCharacters.filterAllowedCharacters( clipboard );
if( !clipboard.isEmpty() )
case GLFW.GLFW_KEY_V:
// Ctrl+V for paste
String clipboard = client.keyboardListener.getClipboardString();
if( clipboard != null )
{
// Clip to 512 characters
if( clipboard.length() > 512 )
// Clip to the first occurrence of \r or \n
int newLineIndex1 = clipboard.indexOf( "\r" );
int newLineIndex2 = clipboard.indexOf( "\n" );
if( newLineIndex1 >= 0 && newLineIndex2 >= 0 )
{
clipboard = clipboard.substring( 0, 512 );
clipboard = clipboard.substring( 0, Math.min( newLineIndex1, newLineIndex2 ) );
}
else if( newLineIndex1 >= 0 )
{
clipboard = clipboard.substring( 0, newLineIndex1 );
}
else if( newLineIndex2 >= 0 )
{
clipboard = clipboard.substring( 0, newLineIndex2 );
}
// Queue the "paste" event
queueEvent( "paste", new Object[] { clipboard } );
}
}
return true;
}
// Filter the string
clipboard = SharedConstants.filterAllowedCharacters( clipboard );
if( !clipboard.isEmpty() )
{
// Clip to 512 characters and queue the event
if( clipboard.length() > 512 ) clipboard = clipboard.substring( 0, 512 );
queueEvent( "paste", clipboard );
}
// Regular keys normally
if( m_terminateTimer <= 0.0f && m_rebootTimer <= 0.0f && m_shutdownTimer <= 0.0f )
return true;
}
}
}
if( key >= 0 && terminateTimer < 0 && rebootTimer < 0 && shutdownTimer < 0 )
{
// Queue the "key" event and add to the down set
boolean repeat = keysDown.get( key );
keysDown.set( key );
IComputer computer = this.computer.get();
if( computer != null ) computer.keyDown( key, repeat );
}
return true;
}
@Override
public boolean keyReleased( int key, int scancode, int modifiers )
{
// Queue the "key_up" event and remove from the down set
if( key >= 0 && keysDown.get( key ) )
{
keysDown.set( key, false );
IComputer computer = this.computer.get();
if( computer != null ) computer.keyUp( key );
}
switch( key )
{
case GLFW.GLFW_KEY_T:
terminateTimer = -1;
break;
case GLFW.GLFW_KEY_R:
rebootTimer = -1;
break;
case GLFW.GLFW_KEY_S:
shutdownTimer = -1;
break;
case GLFW.GLFW_KEY_LEFT_CONTROL:
case GLFW.GLFW_KEY_RIGHT_CONTROL:
terminateTimer = rebootTimer = shutdownTimer = -1;
break;
}
return true;
}
@Override
public boolean mouseClicked( double mouseX, double mouseY, int button )
{
ClientComputer computer = this.computer.get();
if( computer == null || !computer.isColour() || button < 0 || button > 2 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
{
int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH);
int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
computer.mouseClick( button + 1, charX + 1, charY + 1 );
lastMouseButton = button;
lastMouseX = charX;
lastMouseY = charY;
}
return true;
}
@Override
public boolean mouseReleased( double mouseX, double mouseY, int button )
{
ClientComputer computer = this.computer.get();
if( computer == null || !computer.isColour() || button < 0 || button > 2 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
{
int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH);
int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
if( lastMouseButton == button )
{
boolean repeat = Keyboard.isRepeatEvent();
boolean handled = false;
if( key > 0 )
{
if( !repeat )
{
m_keysDown.add( key );
}
// Queue the "key" event
IComputer computer = m_computer.getComputer();
if( computer != null ) computer.keyDown( key, repeat );
handled = true;
}
if( (ch >= 32 && ch <= 126) || (ch >= 160 && ch <= 255) ) // printable chars in byte range
{
// Queue the "char" event
queueEvent( "char", new Object[] { Character.toString( ch ) } );
handled = true;
}
return handled;
computer.mouseUp( lastMouseButton + 1, charX + 1, charY + 1 );
lastMouseButton = -1;
}
lastMouseX = charX;
lastMouseY = charY;
}
return false;
}
@Override
public void mouseClicked( int mouseX, int mouseY, int button )
public boolean mouseDragged( double mouseX, double mouseY, int button, double v2, double v3 )
{
if( mouseX >= getXPosition() && mouseX < getXPosition() + getWidth() &&
mouseY >= getYPosition() && mouseY < getYPosition() + getHeight() )
ClientComputer computer = this.computer.get();
if( computer == null || !computer.isColour() || button < 0 || button > 2 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
{
if( !m_focus && button == 0 )
{
m_focus = true;
}
int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH);
int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
if( m_focus )
{
IComputer computer = m_computer.getComputer();
if( computer != null && computer.isColour() && button >= 0 && button <= 2 )
{
Terminal term = computer.getTerminal();
if( term != null )
{
int charX = (mouseX - (getXPosition() + m_leftMargin)) / FixedWidthFontRenderer.FONT_WIDTH;
int charY = (mouseY - (getYPosition() + m_topMargin)) / FixedWidthFontRenderer.FONT_HEIGHT;
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
computer.mouseDrag( button + 1, charX + 1, charY + 1 );
computer.mouseClick( button + 1, charX + 1, charY + 1 );
m_lastClickButton = button;
m_lastClickX = charX;
m_lastClickY = charY;
}
}
}
}
else
{
if( m_focus && button == 0 && m_allowFocusLoss )
{
m_focus = false;
}
lastMouseX = charX;
lastMouseY = charY;
lastMouseButton = button;
}
return false;
}
@Override
public boolean onKeyboardInput()
public boolean mouseScrolled( double mouseX, double mouseY, double delta )
{
boolean handled = false;
for( int i = m_keysDown.size() - 1; i >= 0; --i )
ClientComputer computer = this.computer.get();
if( computer == null || !computer.isColour() || delta == 0 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
{
int key = m_keysDown.get( i );
if( !Keyboard.isKeyDown( key ) )
{
m_keysDown.remove( i );
if( m_focus )
{
// Queue the "key_up" event
IComputer computer = m_computer.getComputer();
if( computer != null ) computer.keyUp( key );
handled = true;
}
}
int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH);
int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
computer.mouseScroll( delta < 0 ? 1 : -1, charX + 1, charY + 1 );
lastMouseX = charX;
lastMouseY = charY;
}
return handled;
return true;
}
@Override
public void handleMouseInput( int mouseX, int mouseY )
{
IComputer computer = m_computer.getComputer();
if( mouseX >= getXPosition() && mouseX < getXPosition() + getWidth() &&
mouseY >= getYPosition() && mouseY < getYPosition() + getHeight() &&
computer != null && computer.isColour() )
{
Terminal term = computer.getTerminal();
if( term != null )
{
int charX = (mouseX - (getXPosition() + m_leftMargin)) / FixedWidthFontRenderer.FONT_WIDTH;
int charY = (mouseY - (getYPosition() + m_topMargin)) / FixedWidthFontRenderer.FONT_HEIGHT;
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
if( m_lastClickButton >= 0 && !Mouse.isButtonDown( m_lastClickButton ) )
{
if( m_focus ) computer.mouseUp( m_lastClickButton + 1, charX + 1, charY + 1 );
m_lastClickButton = -1;
}
int wheelChange = Mouse.getEventDWheel();
if( wheelChange == 0 && m_lastClickButton == -1 )
{
return;
}
if( m_focus )
{
if( wheelChange < 0 )
{
computer.mouseScroll( 1, charX + 1, charY + 1 );
}
else if( wheelChange > 0 )
{
computer.mouseScroll( -1, charX + 1, charY + 1 );
}
if( m_lastClickButton >= 0 && (charX != m_lastClickX || charY != m_lastClickY) )
{
computer.mouseDrag( m_lastClickButton + 1, charX + 1, charY + 1 );
m_lastClickX = charX;
m_lastClickY = charY;
}
}
}
}
}
@Override
public void update()
{
// Handle special keys
if( m_focus && (Keyboard.isKeyDown( 29 ) || Keyboard.isKeyDown( 157 )) )
if( terminateTimer >= 0 && terminateTimer < TERMINATE_TIME && (terminateTimer += 0.05f) > TERMINATE_TIME )
{
// Ctrl+T for terminate
if( Keyboard.isKeyDown( 20 ) )
{
if( m_terminateTimer < TERMINATE_TIME )
{
m_terminateTimer += 0.05f;
if( m_terminateTimer >= TERMINATE_TIME ) queueEvent( "terminate" );
}
}
else
{
m_terminateTimer = 0.0f;
}
// Ctrl+R for reboot
if( Keyboard.isKeyDown( 19 ) )
{
if( m_rebootTimer < TERMINATE_TIME )
{
m_rebootTimer += 0.05f;
if( m_rebootTimer >= TERMINATE_TIME )
{
IComputer computer = m_computer.getComputer();
if( computer != null ) computer.reboot();
}
}
}
else
{
m_rebootTimer = 0.0f;
}
// Ctrl+S for shutdown
if( Keyboard.isKeyDown( 31 ) )
{
if( m_shutdownTimer < TERMINATE_TIME )
{
m_shutdownTimer += 0.05f;
if( m_shutdownTimer >= TERMINATE_TIME )
{
IComputer computer = m_computer.getComputer();
if( computer != null ) computer.shutdown();
}
}
}
else
{
m_shutdownTimer = 0.0f;
}
queueEvent( "terminate" );
}
else
if( shutdownTimer >= 0 && shutdownTimer < TERMINATE_TIME && (shutdownTimer += 0.05f) > TERMINATE_TIME )
{
m_terminateTimer = 0.0f;
m_rebootTimer = 0.0f;
m_shutdownTimer = 0.0f;
ClientComputer computer = this.computer.get();
if( computer != null ) computer.shutdown();
}
if( rebootTimer >= 0 && rebootTimer < TERMINATE_TIME && (rebootTimer += 0.05f) > TERMINATE_TIME )
{
ClientComputer computer = this.computer.get();
if( computer != null ) computer.reboot();
}
}
@Override
public void draw( Minecraft mc, int xOrigin, int yOrigin, int mouseX, int mouseY )
public boolean changeFocus( boolean reversed )
{
int startX = xOrigin + getXPosition();
int startY = yOrigin + getYPosition();
if( focused )
{
// When blurring, we should make all keys go up
for( int key = 0; key < keysDown.size(); key++ )
{
if( keysDown.get( key ) ) queueEvent( "key_up", key );
}
keysDown.clear();
synchronized( m_computer )
// When blurring, we should make the last mouse button go up
if( lastMouseButton > 0 )
{
IComputer computer = this.computer.get();
if( computer != null ) computer.mouseUp( lastMouseButton + 1, lastMouseX + 1, lastMouseY + 1 );
lastMouseButton = -1;
}
shutdownTimer = terminateTimer = rebootTimer = -1;
}
focused = !focused;
return true;
}
public void draw( int originX, int originY )
{
synchronized( computer )
{
// Draw the screen contents
IComputer computer = m_computer.getComputer();
ClientComputer computer = this.computer.get();
Terminal terminal = computer != null ? computer.getTerminal() : null;
if( terminal != null )
{
// Draw the terminal
boolean greyscale = !computer.isColour();
Palette palette = terminal.getPalette();
// Get the data from the terminal first
// Unfortunately we have to keep the lock for the whole of drawing, so the text doesn't change under us.
FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance();
boolean tblink = m_focus && terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink();
boolean tblink = terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink();
int tw = terminal.getWidth();
int th = terminal.getHeight();
int tx = terminal.getCursorX();
int ty = terminal.getCursorY();
int x = startX + m_leftMargin;
int y = startY + m_topMargin;
// Draw margins
TextBuffer emptyLine = new TextBuffer( ' ', tw );
if( m_topMargin > 0 )
if( topMargin > 0 )
{
fontRenderer.drawString( emptyLine, x, startY, terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), m_leftMargin, m_rightMargin, greyscale, palette );
fontRenderer.drawString( emptyLine, originX, originY - topMargin,
terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ),
leftMargin, rightMargin, greyscale, palette );
}
if( m_bottomMargin > 0 )
if( 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, palette );
fontRenderer.drawString( emptyLine, originX, originY + bottomMargin + (th - 1) * FixedWidthFontRenderer.FONT_HEIGHT,
terminal.getTextColourLine( th - 1 ), terminal.getBackgroundColourLine( th - 1 ),
leftMargin, rightMargin, greyscale, palette );
}
// Draw lines
int y = originY;
for( int line = 0; line < th; line++ )
{
TextBuffer text = terminal.getLine( line );
TextBuffer colour = terminal.getTextColourLine( line );
TextBuffer backgroundColour = terminal.getBackgroundColourLine( line );
fontRenderer.drawString( text, x, y, colour, backgroundColour, m_leftMargin, m_rightMargin, greyscale, palette );
fontRenderer.drawString( text, originX, y, colour, backgroundColour, leftMargin, rightMargin, greyscale, palette );
y += FixedWidthFontRenderer.FONT_HEIGHT;
}
@@ -385,8 +376,8 @@ public class WidgetTerminal extends Widget
fontRenderer.drawString(
cursor,
x + FixedWidthFontRenderer.FONT_WIDTH * tx,
startY + m_topMargin + FixedWidthFontRenderer.FONT_HEIGHT * ty,
originX + FixedWidthFontRenderer.FONT_WIDTH * tx,
originY + FixedWidthFontRenderer.FONT_HEIGHT * ty,
cursorColour, null,
0, 0,
greyscale,
@@ -397,16 +388,29 @@ public class WidgetTerminal extends Widget
else
{
// Draw a black background
mc.getTextureManager().bindTexture( BACKGROUND );
Colour black = Colour.Black;
GlStateManager.color( black.getR(), black.getG(), black.getB(), 1.0f );
GlStateManager.color4f( black.getR(), black.getG(), black.getB(), 1.0f );
try
{
drawTexturedModalRect( startX, startY, 0, 0, getWidth(), getHeight() );
int x = originX - leftMargin;
int y = originY - rightMargin;
int width = termWidth * FixedWidthFontRenderer.FONT_WIDTH + leftMargin + rightMargin;
int height = termHeight * FixedWidthFontRenderer.FONT_HEIGHT + topMargin + bottomMargin;
client.getTextureManager().bindTexture( BACKGROUND );
Tessellator tesslector = Tessellator.getInstance();
BufferBuilder buffer = tesslector.getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX );
buffer.pos( x, y + height, 0 ).tex( 0 / 256.0, height / 256.0 ).endVertex();
buffer.pos( x + width, y + height, 0 ).tex( width / 256.0, height / 256.0 ).endVertex();
buffer.pos( x + width, y, 0 ).tex( width / 256.0, 0 / 256.0 ).endVertex();
buffer.pos( x, y, 0 ).tex( 0 / 256.0, 0 / 256.0 ).endVertex();
tesslector.draw();
}
finally
{
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
}
}
}
@@ -414,13 +418,13 @@ public class WidgetTerminal extends Widget
private void queueEvent( String event )
{
IComputer computer = m_computer.getComputer();
ClientComputer computer = this.computer.get();
if( computer != null ) computer.queueEvent( event );
}
private void queueEvent( String event, Object[] args )
private void queueEvent( String event, Object... args )
{
IComputer computer = m_computer.getComputer();
ClientComputer computer = this.computer.get();
if( computer != null ) computer.queueEvent( event, args );
}
}

View File

@@ -0,0 +1,98 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui.widgets;
import net.minecraft.client.gui.IGuiEventListener;
public class WidgetWrapper implements IGuiEventListener
{
private final IGuiEventListener listener;
private final int x;
private final int y;
private final int width;
private final int height;
public WidgetWrapper( IGuiEventListener listener, int x, int y, int width, int height )
{
this.listener = listener;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
public boolean changeFocus( boolean b )
{
return listener.changeFocus( b );
}
@Override
public boolean mouseClicked( double x, double y, int button )
{
double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseClicked( dx, dy, button );
}
@Override
public boolean mouseReleased( double x, double y, int button )
{
double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseReleased( dx, dy, button );
}
@Override
public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
{
double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseDragged( dx, dy, button, deltaX, deltaY );
}
@Override
public boolean mouseScrolled( double x, double y, double delta )
{
return listener.mouseScrolled( x, y, delta );
}
@Override
public boolean keyPressed( int key, int scancode, int modifiers )
{
return listener.keyPressed( key, scancode, modifiers );
}
@Override
public boolean keyReleased( int key, int scancode, int modifiers )
{
return listener.keyReleased( key, scancode, modifiers );
}
@Override
public boolean charTyped( char character, int modifiers )
{
return listener.charTyped( character, modifiers );
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
}

View File

@@ -7,56 +7,68 @@
package dan200.computercraft.client.proxy;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.render.TileEntityCableRenderer;
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.shared.command.CommandCopy;
import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import net.minecraftforge.client.ClientCommandHandler;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import net.minecraft.client.gui.ScreenManager;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD )
public final class ComputerCraftProxyClient
{
@Override
public void preInit()
@SubscribeEvent
public static void setupClient( FMLClientSetupEvent event )
{
super.preInit();
registerContainers();
// Register any client-specific commands
ClientCommandHandler.instance.registerCommand( CommandCopy.INSTANCE );
}
@Override
public void init()
{
super.init();
// Setup renderers
// Setup TESRs
ClientRegistry.bindTileEntitySpecialRenderer( TileMonitor.class, new TileEntityMonitorRenderer() );
ClientRegistry.bindTileEntitySpecialRenderer( TileCable.class, new TileEntityCableRenderer() );
ClientRegistry.bindTileEntitySpecialRenderer( TileTurtle.class, new TileEntityTurtleRenderer() );
}
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
private static void registerContainers()
{
// My IDE doesn't think so, but we do actually need these generics.
ScreenManager.<ContainerComputer, GuiComputer<ContainerComputer>>registerFactory( ContainerComputer.TYPE, GuiComputer::create );
ScreenManager.<ContainerPocketComputer, GuiComputer<ContainerPocketComputer>>registerFactory( ContainerPocketComputer.TYPE, GuiComputer::createPocket );
ScreenManager.registerFactory( ContainerTurtle.TYPE, GuiTurtle::new );
ScreenManager.registerFactory( ContainerPrinter.TYPE, GuiPrinter::new );
ScreenManager.registerFactory( ContainerDiskDrive.TYPE, GuiDiskDrive::new );
ScreenManager.registerFactory( ContainerHeldItem.PRINTOUT_TYPE, GuiPrintout::new );
ScreenManager.<ContainerViewComputer, GuiComputer<ContainerViewComputer>>registerFactory( ContainerViewComputer.TYPE, GuiComputer::createView );
}
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public static final class ForgeHandlers
{
@SubscribeEvent
public static void onWorldUnload( WorldEvent.Unload event )
{
if( event.getWorld().isRemote )
if( event.getWorld().isRemote() )
{
ClientMonitor.destroyAll();
}
}
}
}

View File

@@ -6,217 +6,85 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
import dan200.computercraft.shared.peripheral.modem.wired.CableBounds;
import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import org.lwjgl.opengl.GL11;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class CableHighlightRenderer
{
private static final float EXPAND = 0.002f;
private static final double MIN = CableBounds.MIN - EXPAND;
private static final double MAX = CableBounds.MAX + EXPAND;
private CableHighlightRenderer()
{
}
/**
* Draw an outline for a specific part of a cable "Multipart".
*
* @param event The event to observe
* @see WorldRenderer#drawSelectionBox(ActiveRenderInfo, RayTraceResult, int)
*/
@SubscribeEvent
public static void drawHighlight( DrawBlockHighlightEvent event )
{
if( event.getTarget().typeOfHit != RayTraceResult.Type.BLOCK ) return;
if( event.getTarget().getType() != RayTraceResult.Type.BLOCK ) return;
BlockPos pos = event.getTarget().getBlockPos();
World world = event.getPlayer().getEntityWorld();
BlockRayTraceResult hit = (BlockRayTraceResult) event.getTarget();
BlockPos pos = hit.getPos();
World world = event.getInfo().getRenderViewEntity().getEntityWorld();
ActiveRenderInfo info = event.getInfo();
IBlockState state = world.getBlockState( pos );
if( state.getBlock() != ComputerCraft.Blocks.cable ) return;
BlockState state = world.getBlockState( pos );
state = state.getActualState( world, pos );
// We only care about instances with both cable and modem.
if( state.getBlock() != ComputerCraft.Blocks.cable || state.get( BlockCable.MODEM ).getFacing() == null || !state.get( BlockCable.CABLE ) )
{
return;
}
event.setCanceled( true );
PeripheralType type = BlockCable.getPeripheralType( state );
Minecraft mc = Minecraft.getInstance();
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0 );
GlStateManager.color( 0.0f, 0.0f, 0.0f, 0.4f );
GL11.glLineWidth( 2.0F );
GlStateManager.disableTexture2D();
GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO );
GlStateManager.lineWidth( Math.max( 2.5F, mc.mainWindow.getFramebufferWidth() / 1920.0F * 2.5F ) );
GlStateManager.disableTexture();
GlStateManager.depthMask( false );
GlStateManager.matrixMode( GL11.GL_PROJECTION );
GlStateManager.pushMatrix();
GlStateManager.scalef( 1.0F, 1.0F, 0.999F );
{
EntityPlayer player = event.getPlayer();
double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks();
double y = player.lastTickPosY + (player.posY - player.lastTickPosY) * event.getPartialTicks();
double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * event.getPartialTicks();
VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) )
? CableShapes.getModemShape( state )
: CableShapes.getCableShape( state );
GlStateManager.translate( -x + pos.getX(), -y + pos.getY(), -z + pos.getZ() );
}
if( type != PeripheralType.Cable && WorldUtil.isVecInsideInclusive( CableBounds.getModemBounds( state ), event.getTarget().hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
{
RenderGlobal.drawSelectionBoundingBox( CableBounds.getModemBounds( state ), 0, 0, 0, 0.4f );
}
else
{
int flags = 0;
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
for( EnumFacing facing : EnumFacing.VALUES )
{
if( BlockCable.doesConnectVisually( state, world, pos, facing ) )
{
flags |= 1 << facing.ordinal();
switch( facing.getAxis() )
{
case X:
{
double offset = facing == EnumFacing.WEST ? -EXPAND : 1 + EXPAND;
double centre = facing == EnumFacing.WEST ? MIN : MAX;
buffer.begin( GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION );
buffer.pos( offset, MIN, MIN ).endVertex();
buffer.pos( offset, MAX, MIN ).endVertex();
buffer.pos( offset, MAX, MAX ).endVertex();
buffer.pos( offset, MIN, MAX ).endVertex();
buffer.pos( offset, MIN, MIN ).endVertex();
tessellator.draw();
buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION );
buffer.pos( offset, MIN, MIN ).endVertex();
buffer.pos( centre, MIN, MIN ).endVertex();
buffer.pos( offset, MAX, MIN ).endVertex();
buffer.pos( centre, MAX, MIN ).endVertex();
buffer.pos( offset, MAX, MAX ).endVertex();
buffer.pos( centre, MAX, MAX ).endVertex();
buffer.pos( offset, MIN, MAX ).endVertex();
buffer.pos( centre, MIN, MAX ).endVertex();
tessellator.draw();
break;
}
case Y:
{
double offset = facing == EnumFacing.DOWN ? -EXPAND : 1 + EXPAND;
double centre = facing == EnumFacing.DOWN ? MIN : MAX;
buffer.begin( GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION );
buffer.pos( MIN, offset, MIN ).endVertex();
buffer.pos( MAX, offset, MIN ).endVertex();
buffer.pos( MAX, offset, MAX ).endVertex();
buffer.pos( MIN, offset, MAX ).endVertex();
buffer.pos( MIN, offset, MIN ).endVertex();
tessellator.draw();
buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION );
buffer.pos( MIN, offset, MIN ).endVertex();
buffer.pos( MIN, centre, MIN ).endVertex();
buffer.pos( MAX, offset, MIN ).endVertex();
buffer.pos( MAX, centre, MIN ).endVertex();
buffer.pos( MAX, offset, MAX ).endVertex();
buffer.pos( MAX, centre, MAX ).endVertex();
buffer.pos( MIN, offset, MAX ).endVertex();
buffer.pos( MIN, centre, MAX ).endVertex();
tessellator.draw();
break;
}
case Z:
{
double offset = facing == EnumFacing.NORTH ? -EXPAND : 1 + EXPAND;
double centre = facing == EnumFacing.NORTH ? MIN : MAX;
buffer.begin( GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION );
buffer.pos( MIN, MIN, offset ).endVertex();
buffer.pos( MAX, MIN, offset ).endVertex();
buffer.pos( MAX, MAX, offset ).endVertex();
buffer.pos( MIN, MAX, offset ).endVertex();
buffer.pos( MIN, MIN, offset ).endVertex();
tessellator.draw();
buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION );
buffer.pos( MIN, MIN, offset ).endVertex();
buffer.pos( MIN, MIN, centre ).endVertex();
buffer.pos( MAX, MIN, offset ).endVertex();
buffer.pos( MAX, MIN, centre ).endVertex();
buffer.pos( MAX, MAX, offset ).endVertex();
buffer.pos( MAX, MAX, centre ).endVertex();
buffer.pos( MIN, MAX, offset ).endVertex();
buffer.pos( MIN, MAX, centre ).endVertex();
tessellator.draw();
break;
}
}
}
}
buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION );
draw( buffer, flags, EnumFacing.WEST, EnumFacing.DOWN, EnumFacing.Axis.Z );
draw( buffer, flags, EnumFacing.WEST, EnumFacing.UP, EnumFacing.Axis.Z );
draw( buffer, flags, EnumFacing.EAST, EnumFacing.DOWN, EnumFacing.Axis.Z );
draw( buffer, flags, EnumFacing.EAST, EnumFacing.UP, EnumFacing.Axis.Z );
draw( buffer, flags, EnumFacing.WEST, EnumFacing.NORTH, EnumFacing.Axis.Y );
draw( buffer, flags, EnumFacing.WEST, EnumFacing.SOUTH, EnumFacing.Axis.Y );
draw( buffer, flags, EnumFacing.EAST, EnumFacing.NORTH, EnumFacing.Axis.Y );
draw( buffer, flags, EnumFacing.EAST, EnumFacing.SOUTH, EnumFacing.Axis.Y );
draw( buffer, flags, EnumFacing.DOWN, EnumFacing.NORTH, EnumFacing.Axis.X );
draw( buffer, flags, EnumFacing.DOWN, EnumFacing.SOUTH, EnumFacing.Axis.X );
draw( buffer, flags, EnumFacing.UP, EnumFacing.NORTH, EnumFacing.Axis.X );
draw( buffer, flags, EnumFacing.UP, EnumFacing.SOUTH, EnumFacing.Axis.X );
tessellator.draw();
}
Vec3d cameraPos = info.getProjectedView();
WorldRenderer.drawShape(
shape, pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ(),
0.0F, 0.0F, 0.0F, 0.4F
);
GlStateManager.popMatrix();
GlStateManager.matrixMode( GL11.GL_MODELVIEW );
GlStateManager.depthMask( true );
GlStateManager.enableTexture2D();
GlStateManager.enableTexture();
GlStateManager.disableBlend();
}
private static void draw( BufferBuilder buffer, int flags, EnumFacing a, EnumFacing b, EnumFacing.Axis other )
{
if( ((flags >> a.ordinal()) & 1) != ((flags >> b.ordinal()) & 1) ) return;
double offA = a.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE ? MIN : MAX;
double offB = b.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE ? MIN : MAX;
switch( other )
{
case X:
buffer.pos( MIN, offA, offB ).endVertex();
buffer.pos( MAX, offA, offB ).endVertex();
break;
case Y:
buffer.pos( offA, MIN, offB ).endVertex();
buffer.pos( offA, MAX, offB ).endVertex();
break;
case Z:
buffer.pos( offA, offB, MIN ).endVertex();
buffer.pos( offA, offB, MAX ).endVertex();
break;
}
}
}

View File

@@ -6,13 +6,13 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.ItemRenderer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.client.renderer.FirstPersonRenderer;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumHandSide;
import net.minecraft.util.Hand;
import net.minecraft.util.HandSide;
import net.minecraft.util.math.MathHelper;
public abstract class ItemMapLikeRenderer
@@ -21,23 +21,23 @@ public abstract class ItemMapLikeRenderer
* The main rendering method for the item
*
* @param stack The stack to render
* @see ItemRenderer#renderMapFirstPerson(ItemStack)
* @see FirstPersonRenderer#renderMapFirstPerson(ItemStack)
*/
protected abstract void renderItem( ItemStack stack );
protected void renderItemFirstPerson( EnumHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack )
protected void renderItemFirstPerson( Hand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack )
{
EntityPlayer player = Minecraft.getMinecraft().player;
PlayerEntity player = Minecraft.getInstance().player;
GlStateManager.pushMatrix();
if( hand == EnumHand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() )
if( hand == Hand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() )
{
renderItemFirstPersonCenter( pitch, equipProgress, swingProgress, stack );
}
else
{
renderItemFirstPersonSide(
hand == EnumHand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(),
hand == Hand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(),
equipProgress, swingProgress, stack
);
}
@@ -51,35 +51,35 @@ public abstract class ItemMapLikeRenderer
* @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item
* @param stack The stack to render
* @see ItemRenderer#renderMapFirstPersonSide(float, EnumHandSide, float, ItemStack)
* @see FirstPersonRenderer#renderMapFirstPersonSide(float, HandSide, float, ItemStack)
*/
private void renderItemFirstPersonSide( EnumHandSide side, float equipProgress, float swingProgress, ItemStack stack )
private void renderItemFirstPersonSide( HandSide side, float equipProgress, float swingProgress, ItemStack stack )
{
Minecraft minecraft = Minecraft.getMinecraft();
float offset = side == EnumHandSide.RIGHT ? 1f : -1f;
GlStateManager.translate( offset * 0.125f, -0.125f, 0f );
Minecraft minecraft = Minecraft.getInstance();
float offset = side == HandSide.RIGHT ? 1f : -1f;
GlStateManager.translatef( offset * 0.125f, -0.125f, 0f );
// If the player is not invisible then render a single arm
if( !minecraft.player.isInvisible() )
{
GlStateManager.pushMatrix();
GlStateManager.rotate( offset * 10f, 0f, 0f, 1f );
minecraft.getItemRenderer().renderArmFirstPerson( equipProgress, swingProgress, side );
GlStateManager.rotatef( offset * 10f, 0f, 0f, 1f );
minecraft.getFirstPersonRenderer().renderArmFirstPerson( equipProgress, swingProgress, side );
GlStateManager.popMatrix();
}
// Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer.
GlStateManager.pushMatrix();
GlStateManager.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
GlStateManager.translatef( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
float f1 = MathHelper.sqrt( swingProgress );
float f2 = MathHelper.sin( f1 * (float) Math.PI );
float f3 = -0.5f * f2;
float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) );
float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI );
GlStateManager.translate( offset * f3, f4 - 0.3f * f2, f5 );
GlStateManager.rotate( f2 * -45f, 1f, 0f, 0f );
GlStateManager.rotate( offset * f2 * -30f, 0f, 1f, 0f );
GlStateManager.translatef( offset * f3, f4 - 0.3f * f2, f5 );
GlStateManager.rotatef( f2 * -45f, 1f, 0f, 0f );
GlStateManager.rotatef( offset * f2 * -30f, 0f, 1f, 0f );
renderItem( stack );
@@ -93,25 +93,25 @@ public abstract class ItemMapLikeRenderer
* @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item
* @param stack The stack to render
* @see ItemRenderer#renderMapFirstPerson(float, float, float)
* @see FirstPersonRenderer#renderMapFirstPerson(float, float, float)
*/
private void renderItemFirstPersonCenter( float pitch, float equipProgress, float swingProgress, ItemStack stack )
{
ItemRenderer itemRenderer = Minecraft.getMinecraft().getItemRenderer();
FirstPersonRenderer renderer = Minecraft.getInstance().getFirstPersonRenderer();
// Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer.
float swingRt = MathHelper.sqrt( swingProgress );
float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI );
float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI );
GlStateManager.translate( 0f, -tX / 2f, tZ );
float pitchAngle = itemRenderer.getMapAngleFromPitch( pitch );
GlStateManager.translate( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
GlStateManager.rotate( pitchAngle * -85f, 1f, 0f, 0f );
itemRenderer.renderArms();
GlStateManager.translatef( 0f, -tX / 2f, tZ );
float pitchAngle = renderer.getMapAngleFromPitch( pitch );
GlStateManager.translatef( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
GlStateManager.rotatef( pitchAngle * -85f, 1f, 0f, 0f );
renderer.renderArms();
float rX = MathHelper.sin( swingRt * (float) Math.PI );
GlStateManager.rotate( rX * 20f, 1f, 0f, 0f );
GlStateManager.scale( 2f, 2f, 2f );
GlStateManager.rotatef( rX * 20f, 1f, 0f, 0f );
GlStateManager.scalef( 2f, 2f, 2f );
renderItem( stack );
}

View File

@@ -6,6 +6,7 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
@@ -18,14 +19,13 @@ import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import org.lwjgl.opengl.GL11;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*;
@@ -34,7 +34,7 @@ import static dan200.computercraft.client.gui.GuiComputer.*;
/**
* Emulates map rendering for pocket computers
*/
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class ItemPocketRenderer extends ItemMapLikeRenderer
{
private static final int MARGIN = 2;
@@ -83,19 +83,20 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
GlStateManager.disableDepth();
GlStateManager.disableDepthTest();
GlStateManager.rotate( 180f, 0f, 1f, 0f );
GlStateManager.rotate( 180f, 0f, 0f, 1f );
GlStateManager.scale( 0.5, 0.5, 0.5 );
GlStateManager.rotatef( 180f, 0f, 1f, 0f );
GlStateManager.rotatef( 180f, 0f, 0f, 1f );
GlStateManager.scalef( 0.5f, 0.5f, 0.5f );
double scale = 0.75 / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT );
GlStateManager.scale( scale, scale, 0 );
GlStateManager.translate( -0.5 * width, -0.5 * height, 0 );
GlStateManager.scaled( scale, scale, 0 );
GlStateManager.translated( -0.5 * width, -0.5 * height, 0 );
// Render the main frame
ComputerFamily family = ComputerCraft.Items.pocketComputer.getFamily( stack );
int frameColour = ComputerCraft.Items.pocketComputer.getColour( stack );
ItemPocketComputer item = (ItemPocketComputer) stack.getItem();
ComputerFamily family = item.getFamily();
int frameColour = item.getColour( stack );
renderFrame( family, frameColour, width, height );
// Render the light
@@ -111,7 +112,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
else
{
// Otherwise render a plain background
Minecraft.getMinecraft().getTextureManager().bindTexture( BACKGROUND );
Minecraft.getInstance().getTextureManager().bindTexture( BACKGROUND );
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
@@ -122,7 +123,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
tessellator.draw();
}
GlStateManager.enableDepth();
GlStateManager.enableDepthTest();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
@@ -130,7 +131,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
private static void renderFrame( ComputerFamily family, int colour, int width, int height )
{
Minecraft.getMinecraft().getTextureManager().bindTexture( colour != -1
Minecraft.getInstance().getTextureManager().bindTexture( colour != -1
? BACKGROUND_COLOUR
: family == ComputerFamily.Normal ? BACKGROUND_NORMAL : BACKGROUND_ADVANCED
);
@@ -172,7 +173,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
private static void renderLight( int colour, int width, int height )
{
GlStateManager.enableBlend();
GlStateManager.disableTexture2D();
GlStateManager.disableTexture();
float r = ((colour >>> 16) & 0xFF) / 255.0f;
float g = ((colour >>> 8) & 0xFF) / 255.0f;
@@ -187,7 +188,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
buffer.pos( width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
tessellator.draw();
GlStateManager.enableTexture2D();
GlStateManager.enableTexture();
}
private static void renderTerminal( Terminal terminal, boolean greyscale, int width, int height )

View File

@@ -6,15 +6,15 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderItemInFrameEvent;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
@@ -25,7 +25,7 @@ import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENG
/**
* Emulates map and item-frame rendering for printouts
*/
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
{
private static final ItemPrintoutRenderer INSTANCE = new ItemPrintoutRenderer();
@@ -38,10 +38,9 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
public static void onRenderInHand( RenderSpecificHandEvent event )
{
ItemStack stack = event.getItemStack();
if( stack.getItem() != ComputerCraft.Items.printout ) return;
if( !(stack.getItem() instanceof ItemPrintout) ) return;
event.setCanceled( true );
INSTANCE.renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() );
}
@@ -49,13 +48,13 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
protected void renderItem( ItemStack stack )
{
// Setup various transformations. Note that these are partially adapated from the corresponding method
// in ItemRenderer.renderMapFirstPerson
// in FirstPersonRenderer.renderFirstPersonMap
GlStateManager.disableLighting();
GlStateManager.rotate( 180f, 0f, 1f, 0f );
GlStateManager.rotate( 180f, 0f, 0f, 1f );
GlStateManager.scale( 0.42f, 0.42f, -0.42f );
GlStateManager.translate( -0.5f, -0.48f, 0.0f );
GlStateManager.rotatef( 180f, 0f, 1f, 0f );
GlStateManager.rotatef( 180f, 0f, 0f, 1f );
GlStateManager.scalef( 0.42f, 0.42f, -0.42f );
GlStateManager.translatef( -0.5f, -0.48f, 0.0f );
drawPrintout( stack );
@@ -66,17 +65,17 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
public static void onRenderInFrame( RenderItemInFrameEvent event )
{
ItemStack stack = event.getItem();
if( stack.getItem() != ComputerCraft.Items.printout ) return;
if( !(stack.getItem() instanceof ItemPrintout) ) return;
event.setCanceled( true );
GlStateManager.disableLighting();
// Move a little bit forward to ensure we're not clipping with the frame
GlStateManager.translate( 0.0f, 0.0f, -0.001f );
GlStateManager.rotate( 180f, 0f, 0f, 1f );
GlStateManager.scale( 0.95f, 0.95f, -0.95f );
GlStateManager.translate( -0.5f, -0.5f, 0.0f );
GlStateManager.translatef( 0.0f, 0.0f, -0.001f );
GlStateManager.rotatef( 180f, 0f, 0f, 1f );
GlStateManager.scalef( 0.95f, 0.95f, -0.95f );
GlStateManager.translatef( -0.5f, -0.5f, 0.0f );
drawPrintout( stack );
@@ -87,7 +86,7 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
private static void drawPrintout( ItemStack stack )
{
int pages = ItemPrintout.getPageCount( stack );
boolean book = ItemPrintout.getType( stack ) == ItemPrintout.Type.Book;
boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK;
double width = LINE_MAX_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2;
double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2;
@@ -108,8 +107,8 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
// Scale the printout to fit correctly.
double scale = 1.0 / max;
GlStateManager.scale( scale, scale, scale );
GlStateManager.translate( (max - width) / 2.0f, (max - height) / 2.0f, 0.0f );
GlStateManager.scaled( scale, scale, scale );
GlStateManager.translated( (max - width) / 2.0, (max - height) / 2.0, 0.0 );
drawBorder( 0, 0, -0.01, 0, pages, book );
drawText( X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) );

View File

@@ -6,10 +6,10 @@
package dan200.computercraft.client.render;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import net.minecraftforge.client.model.pipeline.LightUtil;
import net.minecraftforge.client.model.pipeline.VertexTransformer;
@@ -102,7 +102,7 @@ public final class ModelTransformer
}
@Override
public void setQuadOrientation( @Nonnull EnumFacing orientation )
public void setQuadOrientation( @Nonnull Direction orientation )
{
super.setQuadOrientation( orientation == null ? orientation : TRSRTransformation.rotate( positionMatrix, orientation ) );
}
@@ -187,7 +187,7 @@ public final class ModelTransformer
private final int[] vertexData;
private int vertexIndex = 0, elementIndex = 0;
private EnumFacing orientation;
private Direction orientation;
private int quadTint;
private boolean diffuse;
private TextureAtlasSprite texture;
@@ -212,7 +212,7 @@ public final class ModelTransformer
}
@Override
public void setQuadOrientation( @Nonnull EnumFacing orientation )
public void setQuadOrientation( @Nonnull Direction orientation )
{
this.orientation = orientation;
}

View File

@@ -6,29 +6,31 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import org.lwjgl.opengl.GL11;
import java.util.EnumSet;
import static net.minecraft.util.EnumFacing.*;
import static net.minecraft.util.Direction.*;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class MonitorHighlightRenderer
{
private static final float EXPAND = 0.002f;
@@ -40,12 +42,13 @@ public final class MonitorHighlightRenderer
@SubscribeEvent
public static void drawHighlight( DrawBlockHighlightEvent event )
{
if( event.getTarget().typeOfHit != RayTraceResult.Type.BLOCK || event.getPlayer().isSneaking() ) return;
if( event.getTarget().getType() != RayTraceResult.Type.BLOCK || event.getInfo().getRenderViewEntity().isSneaking() )
{
return;
}
World world = event.getPlayer().getEntityWorld();
BlockPos pos = event.getTarget().getBlockPos();
if( world.getBlockState( pos ).getBlock() != ComputerCraft.Blocks.peripheral ) return;
World world = event.getInfo().getRenderViewEntity().getEntityWorld();
BlockPos pos = ((BlockRayTraceResult) event.getTarget()).getPos();
TileEntity tile = world.getTileEntity( pos );
if( !(tile instanceof TileMonitor) ) return;
@@ -54,8 +57,8 @@ public final class MonitorHighlightRenderer
event.setCanceled( true );
// Determine which sides are part of the external faces of the monitor, and so which need to be rendered.
EnumSet<EnumFacing> faces = EnumSet.allOf( EnumFacing.class );
EnumFacing front = monitor.getFront();
EnumSet<Direction> faces = EnumSet.allOf( Direction.class );
Direction front = monitor.getFront();
faces.remove( front );
if( monitor.getXIndex() != 0 ) faces.remove( monitor.getRight().getOpposite() );
if( monitor.getXIndex() != monitor.getWidth() - 1 ) faces.remove( monitor.getRight() );
@@ -63,18 +66,14 @@ public final class MonitorHighlightRenderer
if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() );
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO );
GL11.glLineWidth( 2.0F );
GlStateManager.disableTexture2D();
GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO );
GlStateManager.lineWidth( Math.max( 2.5F, (float) Minecraft.getInstance().mainWindow.getFramebufferWidth() / 1920.0F * 2.5F ) );
GlStateManager.disableTexture();
GlStateManager.depthMask( false );
GlStateManager.pushMatrix();
EntityPlayer player = event.getPlayer();
double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks();
double y = player.lastTickPosY + (player.posY - player.lastTickPosY) * event.getPartialTicks();
double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * event.getPartialTicks();
GlStateManager.translate( -x + pos.getX(), -y + pos.getY(), -z + pos.getZ() );
Vec3d cameraPos = event.getInfo().getProjectedView();
GlStateManager.translated( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() );
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
@@ -98,11 +97,11 @@ public final class MonitorHighlightRenderer
GlStateManager.popMatrix();
GlStateManager.depthMask( true );
GlStateManager.enableTexture2D();
GlStateManager.enableTexture();
GlStateManager.disableBlend();
}
private static void line( BufferBuilder buffer, int x, int y, int z, EnumFacing direction )
private static void line( BufferBuilder buffer, int x, int y, int z, Direction direction )
{
double minX = x == 0 ? -EXPAND : 1 + EXPAND;
double minY = y == 0 ? -EXPAND : 1 + EXPAND;

View File

@@ -6,14 +6,14 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.platform.GlStateManager.DestFactor;
import com.mojang.blaze3d.platform.GlStateManager.SourceFactor;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
@@ -74,10 +74,10 @@ public final class PrintoutRenderer
public static void drawText( int x, int y, int start, String[] text, String[] colours )
{
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.enableBlend();
GlStateManager.enableTexture2D();
GlStateManager.tryBlendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO );
GlStateManager.enableTexture();
GlStateManager.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO );
FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance();
@@ -89,12 +89,12 @@ public final class PrintoutRenderer
public static void drawBorder( double x, double y, double z, int page, int pages, boolean isBook )
{
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.enableBlend();
GlStateManager.enableTexture2D();
GlStateManager.tryBlendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO );
GlStateManager.enableTexture();
GlStateManager.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO );
Minecraft.getMinecraft().getTextureManager().bindTexture( BG );
Minecraft.getInstance().getTextureManager().bindTexture( BG );
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();

View File

@@ -6,86 +6,94 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
import dan200.computercraft.shared.peripheral.modem.wired.BlockCableModemVariant;
import dan200.computercraft.shared.peripheral.modem.wired.CableBounds;
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant;
import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.client.model.data.EmptyModelData;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nonnull;
import java.util.Random;
/**
* Render breaking animation only over part of a {@link TileCable}.
*/
public class TileEntityCableRenderer extends TileEntitySpecialRenderer<TileCable>
public class TileEntityCableRenderer extends TileEntityRenderer<TileCable>
{
private static final ResourceLocation[] DESTROY_STAGES = new ResourceLocation[10];
private static final Random random = new Random();
static
{
for( int i = 0; i < DESTROY_STAGES.length; i++ )
{
DESTROY_STAGES[i] = new ResourceLocation( "block/destroy_stage_" + i );
}
}
@Override
public void render( @Nonnull TileCable te, double x, double y, double z, float partialTicks, int destroyStage, float alpha )
public void render( @Nonnull TileCable te, double x, double y, double z, float partialTicks, int destroyStage )
{
if( destroyStage < 0 ) return;
BlockPos pos = te.getPos();
Minecraft mc = Minecraft.getMinecraft();
Minecraft mc = Minecraft.getInstance();
RayTraceResult hit = mc.objectMouseOver;
if( hit == null || !hit.getBlockPos().equals( pos ) ) return;
if( MinecraftForgeClient.getRenderPass() != 0 ) return;
if( hit == null || hit.getType() != RayTraceResult.Type.BLOCK || !((BlockRayTraceResult) hit).getPos().equals( pos ) )
{
return;
}
World world = te.getWorld();
IBlockState state = world.getBlockState( pos );
BlockState state = world.getBlockState( pos );
Block block = state.getBlock();
if( block != ComputerCraft.Blocks.cable ) return;
state = state.getActualState( world, pos );
if( te.getPeripheralType() != PeripheralType.Cable && WorldUtil.isVecInsideInclusive( CableBounds.getModemBounds( state ), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
{
state = block.getDefaultState().withProperty( BlockCable.MODEM, state.getValue( BlockCable.MODEM ) );
}
else
{
state = state.withProperty( BlockCable.MODEM, BlockCableModemVariant.None );
}
state = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) )
? block.getDefaultState().with( BlockCable.MODEM, state.get( BlockCable.MODEM ) )
: state.with( BlockCable.MODEM, CableModemVariant.None );
IBakedModel model = mc.getBlockRendererDispatcher().getModelForState( state );
if( model == null ) return;
preRenderDamagedBlocks();
ForgeHooksClient.setRenderLayer( block.getRenderLayer() );
// See BlockRendererDispatcher#renderBlockDamage
TextureAtlasSprite breakingTexture = mc.getTextureMap().getSprite( DESTROY_STAGES[destroyStage] );
BufferBuilder buffer = Tessellator.getInstance().getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.BLOCK );
buffer.setTranslation( x - pos.getX(), y - pos.getY(), z - pos.getZ() );
buffer.noColor();
ForgeHooksClient.setRenderLayer( block.getRenderLayer() );
// See BlockRendererDispatcher#renderBlockDamage
TextureAtlasSprite breakingTexture = mc.getTextureMapBlocks().getAtlasSprite( "minecraft:blocks/destroy_stage_" + destroyStage );
Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelRenderer().renderModel(
mc.getBlockRendererDispatcher().getBlockModelRenderer().renderModel(
world,
ForgeHooksClient.getDamageModel( model, breakingTexture, state, world, pos ),
state, pos, buffer, true
ForgeHooksClient.getDamageModel( model, breakingTexture, state, world, pos, 0 ),
state, pos, buffer, true, random, state.getPositionRandom( pos ), EmptyModelData.INSTANCE
);
ForgeHooksClient.setRenderLayer( BlockRenderLayer.SOLID );
@@ -97,30 +105,30 @@ public class TileEntityCableRenderer extends TileEntitySpecialRenderer<TileCable
}
/**
* @see RenderGlobal#preRenderDamagedBlocks()
* @see WorldRenderer#preRenderDamagedBlocks()
*/
private void preRenderDamagedBlocks()
{
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate( GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO );
GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO );
GlStateManager.enableBlend();
GlStateManager.color( 1.0F, 1.0F, 1.0F, 0.5F );
GlStateManager.doPolygonOffset( -3.0F, -3.0F );
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 0.5F );
GlStateManager.polygonOffset( -3.0F, -3.0F );
GlStateManager.enablePolygonOffset();
GlStateManager.alphaFunc( 516, 0.1F );
GlStateManager.enableAlpha();
GlStateManager.enableAlphaTest();
GlStateManager.pushMatrix();
}
/**
* @see RenderGlobal#postRenderDamagedBlocks()
* @see WorldRenderer#postRenderDamagedBlocks()
*/
private void postRenderDamagedBlocks()
{
GlStateManager.disableAlpha();
GlStateManager.doPolygonOffset( 0.0F, 0.0F );
GlStateManager.disableAlphaTest();
GlStateManager.polygonOffset( 0.0F, 0.0F );
GlStateManager.disablePolygonOffset();
GlStateManager.disablePolygonOffset();
GlStateManager.depthMask( true );

View File

@@ -6,6 +6,8 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GLX;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
@@ -17,19 +19,17 @@ import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import org.lwjgl.opengl.GL11;
public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMonitor>
public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
{
@Override
public void render( TileMonitor tileEntity, double posX, double posY, double posZ, float f, int i, float f2 )
public void render( TileMonitor tileEntity, double posX, double posY, double posZ, float f, int i )
{
if( tileEntity != null )
{
@@ -64,8 +64,8 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
posZ += originPos.getZ() - monitorPos.getZ();
// Determine orientation
EnumFacing dir = origin.getDirection();
EnumFacing front = origin.getFront();
Direction dir = origin.getDirection();
Direction front = origin.getFront();
float yaw = dir.getHorizontalAngle();
float pitch = DirectionUtil.toPitchAngle( front );
@@ -73,19 +73,19 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
try
{
// Setup initial transform
GlStateManager.translate( posX + 0.5, posY + 0.5, posZ + 0.5 );
GlStateManager.rotate( -yaw, 0.0f, 1.0f, 0.0f );
GlStateManager.rotate( pitch, 1.0f, 0.0f, 0.0f );
GlStateManager.translate(
GlStateManager.translated( posX + 0.5, posY + 0.5, posZ + 0.5 );
GlStateManager.rotatef( -yaw, 0.0f, 1.0f, 0.0f );
GlStateManager.rotatef( pitch, 1.0f, 0.0f, 0.0f );
GlStateManager.translated(
-0.5 + TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN,
origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN),
origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN) + 0,
0.5
);
double xSize = origin.getWidth() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER);
double ySize = origin.getHeight() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER);
// Get renderers
Minecraft mc = Minecraft.getMinecraft();
Minecraft mc = Minecraft.getInstance();
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder renderer = tessellator.getBuffer();
@@ -94,9 +94,9 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
// Draw the contents
GlStateManager.depthMask( false );
OpenGlHelper.setLightmapTextureCoords( OpenGlHelper.lightmapTexUnit, 0xFF, 0xFF );
GLX.glMultiTexCoord2f( GLX.GL_TEXTURE1, 0xFFFF, 0xFFFF );
GlStateManager.disableLighting();
mc.entityRenderer.disableLightmap();
mc.gameRenderer.disableLightmap();
try
{
Terminal terminal = originTerminal.getTerminal();
@@ -124,14 +124,14 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
{
double xScale = xSize / (width * FixedWidthFontRenderer.FONT_WIDTH);
double yScale = ySize / (height * FixedWidthFontRenderer.FONT_HEIGHT);
GlStateManager.scale( xScale, -yScale, 1.0 );
GlStateManager.scaled( xScale, -yScale, 1.0 );
// Draw background
mc.getTextureManager().bindTexture( FixedWidthFontRenderer.BACKGROUND );
if( redraw )
{
// Build background display list
GlStateManager.glNewList( originTerminal.renderDisplayLists[0], GL11.GL_COMPILE );
GlStateManager.newList( originTerminal.renderDisplayLists[0], GL11.GL_COMPILE );
try
{
double marginXSize = TileMonitor.RENDER_MARGIN / xScale;
@@ -142,10 +142,10 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
GlStateManager.pushMatrix();
try
{
GlStateManager.scale( 1.0, marginSquash, 1.0 );
GlStateManager.translate( 0.0, -marginYSize / marginSquash, 0.0 );
GlStateManager.scaled( 1.0, marginSquash, 1.0 );
GlStateManager.translated( 0.0, -marginYSize / marginSquash, 0.0 );
fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( 0 ), marginXSize, marginXSize, greyscale, palette );
GlStateManager.translate( 0.0, (marginYSize + height * FixedWidthFontRenderer.FONT_HEIGHT) / marginSquash, 0.0 );
GlStateManager.translated( 0.0, (marginYSize + height * FixedWidthFontRenderer.FONT_HEIGHT) / marginSquash, 0.0 );
fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( height - 1 ), marginXSize, marginXSize, greyscale, palette );
}
finally
@@ -167,18 +167,18 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
}
finally
{
GlStateManager.glEndList();
GlStateManager.endList();
}
}
GlStateManager.callList( originTerminal.renderDisplayLists[0] );
GlStateManager.resetColor();
GlStateManager.clearCurrentColor();
// Draw text
fontRenderer.bindFont();
if( redraw )
{
// Build text display list
GlStateManager.glNewList( originTerminal.renderDisplayLists[1], GL11.GL_COMPILE );
GlStateManager.newList( originTerminal.renderDisplayLists[1], GL11.GL_COMPILE );
try
{
// Lines
@@ -195,18 +195,18 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
}
finally
{
GlStateManager.glEndList();
GlStateManager.endList();
}
}
GlStateManager.callList( originTerminal.renderDisplayLists[1] );
GlStateManager.resetColor();
GlStateManager.clearCurrentColor();
// Draw cursor
fontRenderer.bindFont();
if( redraw )
{
// Build cursor display list
GlStateManager.glNewList( originTerminal.renderDisplayLists[2], GL11.GL_COMPILE );
GlStateManager.newList( originTerminal.renderDisplayLists[2], GL11.GL_COMPILE );
try
{
// Cursor
@@ -227,13 +227,13 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
}
finally
{
GlStateManager.glEndList();
GlStateManager.endList();
}
}
if( FrameInfo.getGlobalCursorBlink() )
{
GlStateManager.callList( originTerminal.renderDisplayLists[2] );
GlStateManager.resetColor();
GlStateManager.clearCurrentColor();
}
}
finally
@@ -262,7 +262,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
finally
{
GlStateManager.depthMask( true );
mc.entityRenderer.enableLightmap();
mc.gameRenderer.enableLightmap();
GlStateManager.enableLighting();
}
@@ -285,7 +285,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
}
finally
{
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.popMatrix();
}
}

View File

@@ -6,46 +6,51 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.block.state.IBlockState;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ModelManager;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ModelManager;
import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.pipeline.LightUtil;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.opengl.GL11;
import javax.vecmath.Matrix4f;
import java.util.List;
import java.util.Random;
public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurtle>
public class TileEntityTurtleRenderer extends TileEntityRenderer<TileTurtle>
{
private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle", "inventory" );
private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_normal", "inventory" );
private static final ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_advanced", "inventory" );
private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_white", "inventory" );
private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_colour", "inventory" );
private static final ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" );
@Override
public void render( TileTurtle tileEntity, double posX, double posY, double posZ, float partialTicks, int breaking, float f2 )
public void render( TileTurtle tileEntity, double posX, double posY, double posZ, float partialTicks, int breaking )
{
if( tileEntity != null ) renderTurtleAt( tileEntity, posX, posY, posZ, partialTicks );
}
@@ -82,13 +87,14 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
{
// Render the label
String label = turtle.createProxy().getLabel();
if( label != null && rendererDispatcher.cameraHitResult != null && turtle.getPos().equals( rendererDispatcher.cameraHitResult.getBlockPos() ) )
RayTraceResult hit = rendererDispatcher.cameraHitResult;
if( label != null && hit.getType() == RayTraceResult.Type.BLOCK && turtle.getPos().equals( ((BlockRayTraceResult) hit).getPos() ) )
{
setLightmapDisabled( true );
EntityRenderer.drawNameplate(
GameRenderer.drawNameplate(
getFontRenderer(), label,
(float) posX + 0.5F, (float) posY + 1.2F, (float) posZ + 0.5F, 0,
rendererDispatcher.entityYaw, rendererDispatcher.entityPitch, false, false
rendererDispatcher.renderInfo.getYaw(), rendererDispatcher.renderInfo.getPitch(), false
);
setLightmapDisabled( false );
}
@@ -96,22 +102,21 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
GlStateManager.pushMatrix();
try
{
IBlockState state = turtle.getWorld().getBlockState( turtle.getPos() );
BlockState state = turtle.getBlockState();
// Setup the transform
Vec3d offset = turtle.getRenderOffset( partialTicks );
float yaw = turtle.getRenderYaw( partialTicks );
GlStateManager.translate( posX + offset.x, posY + offset.y, posZ + offset.z );
GlStateManager.translated( posX + offset.x, posY + offset.y, posZ + offset.z );
// Render the turtle
GlStateManager.translate( 0.5f, 0.5f, 0.5f );
GlStateManager.rotate( 180.0f - yaw, 0.0f, 1.0f, 0.0f );
GlStateManager.translatef( 0.5f, 0.5f, 0.5f );
GlStateManager.rotatef( 180.0f - yaw, 0.0f, 1.0f, 0.0f );
if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) )
{
// Flip the model and swap the cull face as winding order will have changed.
GlStateManager.scale( 1.0f, -1.0f, 1.0f );
GlStateManager.scalef( 1.0f, -1.0f, 1.0f );
GlStateManager.cullFace( GlStateManager.CullFace.FRONT );
}
GlStateManager.translate( -0.5f, -0.5f, -0.5f );
GlStateManager.translatef( -0.5f, -0.5f, -0.5f );
// Render the turtle
int colour = turtle.getColour();
ComputerFamily family = turtle.getFamily();
@@ -151,7 +156,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
}
}
private static void renderUpgrade( IBlockState state, TileTurtle turtle, TurtleSide side, float f )
private void renderUpgrade( BlockState state, TileTurtle turtle, TurtleSide side, float f )
{
ITurtleUpgrade upgrade = turtle.getUpgrade( side );
if( upgrade != null )
@@ -160,9 +165,9 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
try
{
float toolAngle = turtle.getToolRenderAngle( side, f );
GlStateManager.translate( 0.0f, 0.5f, 0.5f );
GlStateManager.rotate( -toolAngle, 1.0f, 0.0f, 0.0f );
GlStateManager.translate( 0.0f, -0.5f, -0.5f );
GlStateManager.translatef( 0.0f, 0.5f, 0.5f );
GlStateManager.rotatef( -toolAngle, 1.0f, 0.0f, 0.0f );
GlStateManager.translatef( 0.0f, -0.5f, -0.5f );
Pair<IBakedModel, Matrix4f> pair = upgrade.getModel( turtle.getAccess(), side );
if( pair != null )
@@ -184,22 +189,22 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
}
}
private static void renderModel( IBlockState state, ModelResourceLocation modelLocation, int[] tints )
private void renderModel( BlockState state, ModelResourceLocation modelLocation, int[] tints )
{
Minecraft mc = Minecraft.getMinecraft();
ModelManager modelManager = mc.getRenderItem().getItemModelMesher().getModelManager();
Minecraft mc = Minecraft.getInstance();
ModelManager modelManager = mc.getItemRenderer().getItemModelMesher().getModelManager();
renderModel( state, modelManager.getModel( modelLocation ), tints );
}
private static void renderModel( IBlockState state, IBakedModel model, int[] tints )
private void renderModel( BlockState state, IBakedModel model, int[] tints )
{
Minecraft mc = Minecraft.getMinecraft();
Random random = new Random( 0 );
Tessellator tessellator = Tessellator.getInstance();
mc.getTextureManager().bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
renderQuads( tessellator, model.getQuads( state, null, 0 ), tints );
for( EnumFacing facing : EnumFacing.VALUES )
rendererDispatcher.textureManager.bindTexture( AtlasTexture.LOCATION_BLOCKS_TEXTURE );
renderQuads( tessellator, model.getQuads( state, null, random, EmptyModelData.INSTANCE ), tints );
for( Direction facing : DirectionUtil.FACINGS )
{
renderQuads( tessellator, model.getQuads( state, facing, 0 ), tints );
renderQuads( tessellator, model.getQuads( state, facing, random, EmptyModelData.INSTANCE ), tints );
}
}

View File

@@ -6,26 +6,29 @@
package dan200.computercraft.client.render;
import com.google.common.collect.ImmutableMap;
import dan200.computercraft.ComputerCraft;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.IUnbakedModel;
import net.minecraft.client.renderer.model.ModelBakery;
import net.minecraft.client.renderer.texture.ISprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ICustomModelLoader;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.common.model.IModelState;
import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
public final class TurtleModelLoader implements ICustomModelLoader
{
private static final ResourceLocation NORMAL_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle" );
private static final ResourceLocation ADVANCED_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/advanced_turtle" );
private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_white" );
private static final ResourceLocation NORMAL_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_normal" );
private static final ResourceLocation ADVANCED_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_advanced" );
private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_colour" );
public static final TurtleModelLoader INSTANCE = new TurtleModelLoader();
@@ -42,80 +45,60 @@ public final class TurtleModelLoader implements ICustomModelLoader
public boolean accepts( @Nonnull ResourceLocation name )
{
return name.getNamespace().equals( ComputerCraft.MOD_ID )
&& (name.getPath().equals( "turtle" ) || name.getPath().equals( "turtle_advanced" ));
&& (name.getPath().equals( "item/turtle_normal" ) || name.getPath().equals( "item/turtle_advanced" ));
}
@Nonnull
@Override
public IModel loadModel( @Nonnull ResourceLocation name ) throws Exception
public IUnbakedModel loadModel( @Nonnull ResourceLocation name )
{
if( name.getNamespace().equals( ComputerCraft.MOD_ID ) )
{
IModel colourModel = ModelLoaderRegistry.getModel( COLOUR_TURTLE_MODEL );
switch( name.getPath() )
{
case "turtle":
return new TurtleModel( ModelLoaderRegistry.getModel( NORMAL_TURTLE_MODEL ), colourModel );
case "turtle_advanced":
return new TurtleModel( ModelLoaderRegistry.getModel( ADVANCED_TURTLE_MODEL ), colourModel );
case "item/turtle_normal":
return new TurtleModel( NORMAL_TURTLE_MODEL );
case "item/turtle_advanced":
return new TurtleModel( ADVANCED_TURTLE_MODEL );
}
}
throw new IllegalStateException( "Loader does not accept " + name );
}
private static final class TurtleModel implements IModel
private static final class TurtleModel implements IUnbakedModel
{
private final IModel family;
private final IModel colour;
private final ResourceLocation family;
private TurtleModel( IModel family, IModel colour )
private TurtleModel( ResourceLocation family )
{
this.family = family;
this.colour = colour;
}
@Nonnull
@Override
public IBakedModel bake( @Nonnull IModelState state, @Nonnull VertexFormat format, @Nonnull Function<ResourceLocation, TextureAtlasSprite> function )
public Collection<ResourceLocation> getDependencies()
{
return Arrays.asList( family, COLOUR_TURTLE_MODEL );
}
@Nonnull
@Override
public Collection<ResourceLocation> getTextures( @Nonnull Function<ResourceLocation, IUnbakedModel> modelGetter, @Nonnull Set<String> missingTextureErrors )
{
return getDependencies().stream()
.flatMap( x -> modelGetter.apply( x ).getTextures( modelGetter, missingTextureErrors ).stream() )
.collect( Collectors.toSet() );
}
@Nonnull
@Override
public IBakedModel bake( @Nonnull ModelBakery bakery, @Nonnull Function<ResourceLocation, TextureAtlasSprite> spriteGetter, @Nonnull ISprite sprite, @Nonnull VertexFormat format )
{
return new TurtleSmartItemModel(
family.bake( state, format, function ),
colour.bake( state, format, function )
bakery.getBakedModel( family, sprite, spriteGetter, format ),
bakery.getBakedModel( COLOUR_TURTLE_MODEL, sprite, spriteGetter, format )
);
}
private TurtleModel copy( IModel family, IModel colour )
{
return this.family == family && this.colour == colour ? this : new TurtleModel( family, colour );
}
@Nonnull
@Override
public IModel smoothLighting( boolean value )
{
return copy( family.smoothLighting( value ), colour.smoothLighting( value ) );
}
@Nonnull
@Override
public IModel gui3d( boolean value )
{
return copy( family.gui3d( value ), colour.gui3d( value ) );
}
@Nonnull
@Override
public IModel uvlock( boolean value )
{
return copy( family.uvlock( value ), colour.uvlock( value ) );
}
@Nonnull
@Override
public IModel retexture( ImmutableMap<String, String> textures )
{
return copy( family.retexture( textures ), colour.retexture( textures ) );
}
}
}

View File

@@ -6,20 +6,18 @@
package dan200.computercraft.client.render;
import net.minecraft.block.state.IBlockState;
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.block.BlockState;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData;
import javax.annotation.Nonnull;
import javax.vecmath.Matrix4f;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class TurtleMultiModel implements IBakedModel
{
@@ -31,7 +29,7 @@ public class TurtleMultiModel implements IBakedModel
private final IBakedModel m_rightUpgradeModel;
private final Matrix4f m_rightUpgradeTransform;
private List<BakedQuad> m_generalQuads = null;
private Map<EnumFacing, List<BakedQuad>> m_faceQuads = new EnumMap<>( EnumFacing.class );
private Map<Direction, List<BakedQuad>> m_faceQuads = new EnumMap<>( Direction.class );
public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, Matrix4f generalTransform, IBakedModel leftUpgradeModel, Matrix4f leftUpgradeTransform, IBakedModel rightUpgradeModel, Matrix4f rightUpgradeTransform )
{
@@ -47,7 +45,15 @@ public class TurtleMultiModel implements IBakedModel
@Nonnull
@Override
public List<BakedQuad> getQuads( IBlockState state, EnumFacing side, long rand )
@Deprecated
public List<BakedQuad> getQuads( BlockState state, Direction side, @Nonnull Random rand )
{
return getQuads( state, side, rand, EmptyModelData.INSTANCE );
}
@Nonnull
@Override
public List<BakedQuad> getQuads( BlockState state, Direction side, @Nonnull Random rand, @Nonnull IModelData data )
{
if( side != null )
{
@@ -61,17 +67,13 @@ public class TurtleMultiModel implements IBakedModel
}
}
private List<BakedQuad> buildQuads( IBlockState state, EnumFacing side, long rand )
private List<BakedQuad> buildQuads( BlockState state, Direction side, Random rand )
{
ArrayList<BakedQuad> quads = new ArrayList<>();
ModelTransformer.transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand ), m_generalTransform );
ModelTransformer.transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform );
if( m_overlayModel != null )
{
ModelTransformer.transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand ), m_generalTransform );
}
if( m_overlayModel != null )
{
ModelTransformer.transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand ), m_generalTransform );
ModelTransformer.transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform );
}
if( m_leftUpgradeModel != null )
{
@@ -81,7 +83,7 @@ public class TurtleMultiModel implements IBakedModel
upgradeTransform = new Matrix4f( m_generalTransform );
upgradeTransform.mul( m_leftUpgradeTransform );
}
ModelTransformer.transformQuadsTo( quads, m_leftUpgradeModel.getQuads( state, side, rand ), upgradeTransform );
ModelTransformer.transformQuadsTo( quads, m_leftUpgradeModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform );
}
if( m_rightUpgradeModel != null )
{
@@ -91,7 +93,7 @@ public class TurtleMultiModel implements IBakedModel
upgradeTransform = new Matrix4f( m_generalTransform );
upgradeTransform.mul( m_rightUpgradeTransform );
}
ModelTransformer.transformQuadsTo( quads, m_rightUpgradeModel.getQuads( state, side, rand ), upgradeTransform );
ModelTransformer.transformQuadsTo( quads, m_rightUpgradeModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform );
}
quads.trimToSize();
return quads;
@@ -117,6 +119,7 @@ public class TurtleMultiModel implements IBakedModel
@Nonnull
@Override
@Deprecated
public TextureAtlasSprite getParticleTexture()
{
return m_baseModel.getParticleTexture();
@@ -125,7 +128,7 @@ public class TurtleMultiModel implements IBakedModel
@Nonnull
@Override
@Deprecated
public ItemCameraTransforms getItemCameraTransforms()
public net.minecraft.client.renderer.model.ItemCameraTransforms getItemCameraTransforms()
{
return m_baseModel.getItemCameraTransforms();
}
@@ -134,6 +137,6 @@ public class TurtleMultiModel implements IBakedModel
@Override
public ItemOverrideList getOverrides()
{
return ItemOverrideList.NONE;
return ItemOverrideList.EMPTY;
}
}

View File

@@ -9,26 +9,27 @@ package dan200.computercraft.client.render;
import com.google.common.base.Objects;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.turtle.items.ItemTurtleBase;
import dan200.computercraft.shared.turtle.items.ItemTurtle;
import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.block.state.IBlockState;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.*;
import net.minecraft.client.renderer.model.*;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.client.model.data.IModelData;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.vecmath.Matrix4f;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
public class TurtleSmartItemModel implements IBakedModel
{
@@ -106,13 +107,13 @@ public class TurtleSmartItemModel implements IBakedModel
this.colourModel = colourModel;
m_cachedModels = new HashMap<>();
m_overrides = new ItemOverrideList( new ArrayList<>() )
m_overrides = new ItemOverrideList()
{
@Nonnull
@Override
public IBakedModel handleItemState( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity )
public IBakedModel getModelWithOverrides( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable LivingEntity entity )
{
ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem();
ItemTurtle turtle = (ItemTurtle) stack.getItem();
int colour = turtle.getColour( stack );
ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.Left );
ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.Right );
@@ -138,8 +139,8 @@ public class TurtleSmartItemModel implements IBakedModel
private IBakedModel buildModel( TurtleModelCombination combo )
{
Minecraft mc = Minecraft.getMinecraft();
ModelManager modelManager = mc.getRenderItem().getItemModelMesher().getModelManager();
Minecraft mc = Minecraft.getInstance();
ModelManager modelManager = mc.getItemRenderer().getItemModelMesher().getModelManager();
ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.m_overlay, combo.m_christmas );
IBakedModel baseModel = combo.m_colour ? colourModel : familyModel;
@@ -167,11 +168,20 @@ public class TurtleSmartItemModel implements IBakedModel
@Nonnull
@Override
public List<BakedQuad> getQuads( IBlockState state, EnumFacing facing, long rand )
@Deprecated
public List<BakedQuad> getQuads( BlockState state, Direction facing, @Nonnull Random rand )
{
return familyModel.getQuads( state, facing, rand );
}
@Nonnull
@Override
@Deprecated
public List<BakedQuad> getQuads( BlockState state, Direction facing, @Nonnull Random rand, @Nonnull IModelData data )
{
return familyModel.getQuads( state, facing, rand, data );
}
@Override
public boolean isAmbientOcclusion()
{
@@ -192,6 +202,7 @@ public class TurtleSmartItemModel implements IBakedModel
@Nonnull
@Override
@Deprecated
public TextureAtlasSprite getParticleTexture()
{
return familyModel.getParticleTexture();

View File

@@ -12,6 +12,7 @@ import dan200.computercraft.ComputerCraft;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
@@ -50,6 +51,11 @@ public class AddressPredicate
private final List<HostRange> ranges;
public AddressPredicate( String... filters )
{
this( Arrays.asList( filters ) );
}
public AddressPredicate( Iterable<? extends String> filters )
{
List<Pattern> wildcards = this.wildcards = new ArrayList<>();
List<HostRange> ranges = this.ranges = new ArrayList<>();

View File

@@ -23,7 +23,7 @@ public final class ApiFactories
private static final Collection<ILuaAPIFactory> factories = new LinkedHashSet<>();
private static final Collection<ILuaAPIFactory> factoriesView = Collections.unmodifiableCollection( factories );
public static void register( @Nonnull ILuaAPIFactory factory )
public static synchronized void register( @Nonnull ILuaAPIFactory factory )
{
Objects.requireNonNull( factory, "provider cannot be null" );
factories.add( factory );

View File

@@ -7,9 +7,7 @@
package dan200.computercraft.core.computer;
import com.google.common.base.Objects;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IWorkMonitor;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.filesystem.FileSystem;
@@ -219,37 +217,4 @@ public class Computer
{
executor.addApi( api );
}
@Deprecated
public IPeripheral getPeripheral( int side )
{
return internalEnvironment.getPeripheral( ComputerSide.valueOf( side ) );
}
@Deprecated
public void setPeripheral( int side, IPeripheral peripheral )
{
internalEnvironment.setPeripheral( ComputerSide.valueOf( side ), peripheral );
}
@Deprecated
public void addAPI( dan200.computercraft.core.apis.ILuaAPI api )
{
addApi( api );
}
@Deprecated
public void advance( double dt )
{
tick();
}
@Deprecated
public IWritableMount getRootMount()
{
return executor.getRootMount();
}
@Deprecated
public static final String[] s_sideNames = ComputerSide.NAMES;
}

View File

@@ -6,11 +6,13 @@
package dan200.computercraft.core.computer;
import net.minecraft.util.Direction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A side on a computer. Unlike {@link net.minecraft.util.EnumFacing}, this is relative to the direction the computer is
* A side on a computer. Unlike {@link Direction}, this is relative to the direction the computer is
* facing..
*/
public enum ComputerSide

View File

@@ -0,0 +1,274 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.filesystem;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.io.ByteStreams;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.core.apis.handles.ArrayByteChannel;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResource;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.resource.IResourceType;
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
public class ResourceMount implements IMount
{
/**
* Only cache files smaller than 1MiB.
*/
private static final int MAX_CACHED_SIZE = 1 << 20;
/**
* Limit the entire cache to 64MiB.
*/
private static final int MAX_CACHE_SIZE = 64 << 20;
private static final byte[] TEMP_BUFFER = new byte[8192];
/**
* We maintain a cache of the contents of all files in the mount. This allows us to allow
* seeking within ROM files, and reduces the amount we need to access disk for computer startup.
*/
private static final Cache<FileEntry, byte[]> CONTENTS_CACHE = CacheBuilder.newBuilder()
.concurrencyLevel( 4 )
.expireAfterAccess( 60, TimeUnit.SECONDS )
.maximumWeight( MAX_CACHE_SIZE )
.weakKeys()
.<FileEntry, byte[]>weigher( ( k, v ) -> v.length )
.build();
private final String namespace;
private final String subPath;
private final IReloadableResourceManager manager;
@Nullable
private FileEntry root;
public ResourceMount( String namespace, String subPath, IReloadableResourceManager manager )
{
this.namespace = namespace;
this.subPath = subPath;
this.manager = manager;
Listener.INSTANCE.add( manager, this );
if( root == null ) load();
}
private void load()
{
boolean hasAny = false;
FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) );
for( ResourceLocation file : manager.getAllResourceLocations( subPath, s -> true ) )
{
if( !file.getNamespace().equals( namespace ) ) continue;
String localPath = FileSystem.toLocal( file.getPath(), subPath );
create( newRoot, localPath );
hasAny = true;
}
root = hasAny ? newRoot : null;
}
private FileEntry get( String path )
{
FileEntry lastEntry = root;
int lastIndex = 0;
while( lastEntry != null && lastIndex < path.length() )
{
int nextIndex = path.indexOf( '/', lastIndex );
if( nextIndex < 0 ) nextIndex = path.length();
lastEntry = lastEntry.children == null ? null : lastEntry.children.get( path.substring( lastIndex, nextIndex ) );
lastIndex = nextIndex + 1;
}
return lastEntry;
}
private void create( FileEntry lastEntry, String path )
{
int lastIndex = 0;
while( lastIndex < path.length() )
{
int nextIndex = path.indexOf( '/', lastIndex );
if( nextIndex < 0 ) nextIndex = path.length();
String part = path.substring( lastIndex, nextIndex );
if( lastEntry.children == null ) lastEntry.children = new HashMap<>();
FileEntry nextEntry = lastEntry.children.get( part );
if( nextEntry == null )
{
lastEntry.children.put( part, nextEntry = new FileEntry( new ResourceLocation( namespace, subPath + "/" + path ) ) );
}
lastEntry = nextEntry;
lastIndex = nextIndex + 1;
}
}
@Override
public boolean exists( @Nonnull String path )
{
return get( path ) != null;
}
@Override
public boolean isDirectory( @Nonnull String path )
{
FileEntry file = get( path );
return file != null && file.isDirectory();
}
@Override
public void list( @Nonnull String path, @Nonnull List<String> contents ) throws IOException
{
FileEntry file = get( path );
if( file == null || !file.isDirectory() ) throw new IOException( "/" + path + ": Not a directory" );
file.list( contents );
}
@Override
public long getSize( @Nonnull String path ) throws IOException
{
FileEntry file = get( path );
if( file != null )
{
if( file.size != -1 ) return file.size;
if( file.isDirectory() ) return file.size = 0;
byte[] contents = CONTENTS_CACHE.getIfPresent( file );
if( contents != null ) return file.size = contents.length;
try
{
IResource resource = manager.getResource( file.identifier );
InputStream s = resource.getInputStream();
int total = 0, read = 0;
do
{
total += read;
read = s.read( TEMP_BUFFER );
} while( read > 0 );
return file.size = total;
}
catch( IOException e )
{
return file.size = 0;
}
}
throw new IOException( "/" + path + ": No such file" );
}
@Nonnull
@Override
@Deprecated
public InputStream openForRead( @Nonnull String path ) throws IOException
{
return Channels.newInputStream( openChannelForRead( path ) );
}
@Nonnull
@Override
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{
FileEntry file = get( path );
if( file != null && !file.isDirectory() )
{
byte[] contents = CONTENTS_CACHE.getIfPresent( file );
if( contents != null ) return new ArrayByteChannel( contents );
try( InputStream stream = manager.getResource( file.identifier ).getInputStream() )
{
if( stream.available() > MAX_CACHED_SIZE ) return Channels.newChannel( stream );
contents = ByteStreams.toByteArray( stream );
CONTENTS_CACHE.put( file, contents );
return new ArrayByteChannel( contents );
}
catch( FileNotFoundException ignored )
{
}
}
throw new IOException( "/" + path + ": No such file" );
}
private static class FileEntry
{
final ResourceLocation identifier;
Map<String, FileEntry> children;
long size = -1;
FileEntry( ResourceLocation identifier )
{
this.identifier = identifier;
}
boolean isDirectory()
{
return children != null;
}
void list( List<String> contents )
{
if( children != null ) contents.addAll( children.keySet() );
}
}
/**
* A {@link ISelectiveResourceReloadListener} which reloads any associated mounts.
*
* While people should really be keeping a permanent reference to this, some people construct it every
* method call, so let's make this as small as possible.
*/
static class Listener implements ISelectiveResourceReloadListener
{
private static final Listener INSTANCE = new Listener();
private final Set<ResourceMount> mounts = Collections.newSetFromMap( new WeakHashMap<>() );
private final Set<IReloadableResourceManager> managers = Collections.newSetFromMap( new WeakHashMap<>() );
@Override
public void onResourceManagerReload( @Nonnull IResourceManager manager )
{
// FIXME: Remove this. We need this patch in order to prevent trying to load ReloadRequirements.
onResourceManagerReload( manager, x -> true );
}
@Override
public synchronized void onResourceManagerReload( @Nonnull IResourceManager manager, @Nonnull Predicate<IResourceType> predicate )
{
for( ResourceMount mount : mounts ) mount.load();
}
synchronized void add( IReloadableResourceManager manager, ResourceMount mount )
{
if( managers.add( manager ) ) manager.addReloadListener( this );
mounts.add( mount );
}
}
}

View File

@@ -7,7 +7,7 @@
package dan200.computercraft.core.terminal;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.CompoundNBT;
public class Terminal
{
@@ -334,18 +334,18 @@ public class Terminal
m_changed = false;
}
public synchronized NBTTagCompound writeToNBT( NBTTagCompound nbt )
public synchronized CompoundNBT writeToNBT( CompoundNBT nbt )
{
nbt.setInteger( "term_cursorX", m_cursorX );
nbt.setInteger( "term_cursorY", m_cursorY );
nbt.setBoolean( "term_cursorBlink", m_cursorBlink );
nbt.setInteger( "term_textColour", m_cursorColour );
nbt.setInteger( "term_bgColour", m_cursorBackgroundColour );
nbt.putInt( "term_cursorX", m_cursorX );
nbt.putInt( "term_cursorY", m_cursorY );
nbt.putBoolean( "term_cursorBlink", m_cursorBlink );
nbt.putInt( "term_textColour", m_cursorColour );
nbt.putInt( "term_bgColour", m_cursorBackgroundColour );
for( int n = 0; n < m_height; n++ )
{
nbt.setString( "term_text_" + n, m_text[n].toString() );
nbt.setString( "term_textColour_" + n, m_textColour[n].toString() );
nbt.setString( "term_textBgColour_" + n, m_backgroundColour[n].toString() );
nbt.putString( "term_text_" + n, m_text[n].toString() );
nbt.putString( "term_textColour_" + n, m_textColour[n].toString() );
nbt.putString( "term_textBgColour_" + n, m_backgroundColour[n].toString() );
}
if( m_palette != null )
{
@@ -354,28 +354,28 @@ public class Terminal
return nbt;
}
public synchronized void readFromNBT( NBTTagCompound nbt )
public synchronized void readFromNBT( CompoundNBT nbt )
{
m_cursorX = nbt.getInteger( "term_cursorX" );
m_cursorY = nbt.getInteger( "term_cursorY" );
m_cursorX = nbt.getInt( "term_cursorX" );
m_cursorY = nbt.getInt( "term_cursorY" );
m_cursorBlink = nbt.getBoolean( "term_cursorBlink" );
m_cursorColour = nbt.getInteger( "term_textColour" );
m_cursorBackgroundColour = nbt.getInteger( "term_bgColour" );
m_cursorColour = nbt.getInt( "term_textColour" );
m_cursorBackgroundColour = nbt.getInt( "term_bgColour" );
for( int n = 0; n < m_height; n++ )
{
m_text[n].fill( ' ' );
if( nbt.hasKey( "term_text_" + n ) )
if( nbt.contains( "term_text_" + n ) )
{
m_text[n].write( nbt.getString( "term_text_" + n ) );
}
m_textColour[n].fill( base16.charAt( m_cursorColour ) );
if( nbt.hasKey( "term_textColour_" + n ) )
if( nbt.contains( "term_textColour_" + n ) )
{
m_textColour[n].write( nbt.getString( "term_textColour_" + n ) );
}
m_backgroundColour[n].fill( base16.charAt( m_cursorBackgroundColour ) );
if( nbt.hasKey( "term_textBgColour_" + n ) )
if( nbt.contains( "term_textBgColour_" + n ) )
{
m_backgroundColour[n].write( nbt.getString( "term_textBgColour_" + n ) );
}

View File

@@ -10,11 +10,6 @@ import dan200.computercraft.core.computer.Computer;
public interface Tracker
{
@Deprecated
default void addTiming( Computer computer, long time )
{
}
/**
* Report how long a task executed on the computer thread took.
*
@@ -25,8 +20,6 @@ public interface Tracker
*/
default void addTaskTiming( Computer computer, long time )
{
//noinspection deprecation
addTiming( computer, time );
}
/**

View File

@@ -6,8 +6,6 @@
package dan200.computercraft.core.tracking;
import dan200.computercraft.shared.util.StringUtil;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -15,31 +13,29 @@ import java.util.function.LongFunction;
public final class TrackingField
{
public static final String TRANSLATE_PREFIX = "tracking_field.computercraft.";
private static final Map<String, TrackingField> fields = new HashMap<>();
public static final TrackingField TASKS = TrackingField.of( "tasks", "Tasks", x -> String.format( "%4d", x ) );
public static final TrackingField TOTAL_TIME = TrackingField.of( "total", "Total time", x -> String.format( "%7.1fms", x / 1e6 ) );
public static final TrackingField AVERAGE_TIME = TrackingField.of( "average", "Average time", x -> String.format( "%4.1fms", x / 1e6 ) );
public static final TrackingField MAX_TIME = TrackingField.of( "max", "Max time", x -> String.format( "%5.1fms", x / 1e6 ) );
public static final TrackingField TASKS = TrackingField.of( "tasks", x -> String.format( "%4d", x ) );
public static final TrackingField TOTAL_TIME = TrackingField.of( "total", x -> String.format( "%7.1fms", x / 1e6 ) );
public static final TrackingField AVERAGE_TIME = TrackingField.of( "average", x -> String.format( "%4.1fms", x / 1e6 ) );
public static final TrackingField MAX_TIME = TrackingField.of( "max", x -> String.format( "%5.1fms", x / 1e6 ) );
public static final TrackingField SERVER_COUNT = TrackingField.of( "server_count", "Server task count", x -> String.format( "%4d", x ) );
public static final TrackingField SERVER_TIME = TrackingField.of( "server_time", "Server task time", x -> String.format( "%7.1fms", x / 1e6 ) );
public static final TrackingField SERVER_COUNT = TrackingField.of( "server_count", x -> String.format( "%4d", x ) );
public static final TrackingField SERVER_TIME = TrackingField.of( "server_time", x -> String.format( "%7.1fms", x / 1e6 ) );
public static final TrackingField PERIPHERAL_OPS = TrackingField.of( "peripheral", "Peripheral calls", TrackingField::formatDefault );
public static final TrackingField FS_OPS = TrackingField.of( "fs", "Filesystem operations", TrackingField::formatDefault );
public static final TrackingField TURTLE_OPS = TrackingField.of( "turtle", "Turtle operations", TrackingField::formatDefault );
public static final TrackingField PERIPHERAL_OPS = TrackingField.of( "peripheral", TrackingField::formatDefault );
public static final TrackingField FS_OPS = TrackingField.of( "fs", TrackingField::formatDefault );
public static final TrackingField TURTLE_OPS = TrackingField.of( "turtle", TrackingField::formatDefault );
public static final TrackingField HTTP_REQUESTS = TrackingField.of( "http", "HTTP requests", TrackingField::formatDefault );
public static final TrackingField HTTP_UPLOAD = TrackingField.of( "http_upload", "HTTP upload", TrackingField::formatBytes );
public static final TrackingField HTTP_DOWNLOAD = TrackingField.of( "http_download", "HTTP download", TrackingField::formatBytes );
public static final TrackingField HTTP_REQUESTS = TrackingField.of( "http", TrackingField::formatDefault );
public static final TrackingField HTTP_UPLOAD = TrackingField.of( "http_upload", TrackingField::formatBytes );
public static final TrackingField HTTP_DOWNLOAD = TrackingField.of( "http_download", TrackingField::formatBytes );
public static final TrackingField WEBSOCKET_INCOMING = TrackingField.of( "websocket_incoming", "Websocket incoming", TrackingField::formatBytes );
public static final TrackingField WEBSOCKET_OUTGOING = TrackingField.of( "websocket_outgoing", "Websocket outgoing", TrackingField::formatBytes );
public static final TrackingField WEBSOCKET_INCOMING = TrackingField.of( "websocket_incoming", TrackingField::formatBytes );
public static final TrackingField WEBSOCKET_OUTGOING = TrackingField.of( "websocket_outgoing", TrackingField::formatBytes );
public static final TrackingField COROUTINES_CREATED = TrackingField.of( "coroutines_created", "Coroutines created", x -> String.format( "%4d", x ) );
public static final TrackingField COROUTINES_DISPOSED = TrackingField.of( "coroutines_dead", "Coroutines disposed", x -> String.format( "%4d", x ) );
public static final TrackingField COROUTINES_CREATED = TrackingField.of( "coroutines_created", x -> String.format( "%4d", x ) );
public static final TrackingField COROUTINES_DISPOSED = TrackingField.of( "coroutines_dead", x -> String.format( "%4d", x ) );
private final String id;
private final String translationKey;
@@ -55,12 +51,6 @@ public final class TrackingField
return translationKey;
}
@Deprecated
public String displayName()
{
return StringUtil.translate( translationKey() );
}
private TrackingField( String id, LongFunction<String> format )
{
this.id = id;
@@ -73,7 +63,7 @@ public final class TrackingField
return format.apply( value );
}
public static TrackingField of( String id, String displayName, LongFunction<String> format )
public static TrackingField of( String id, LongFunction<String> format )
{
TrackingField field = new TrackingField( id, format );
fields.put( id, field );

View File

@@ -9,7 +9,7 @@ package dan200.computercraft.shared;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@@ -24,20 +24,20 @@ public final class BundledRedstone
private BundledRedstone() {}
public static void register( @Nonnull IBundledRedstoneProvider provider )
public static synchronized void register( @Nonnull IBundledRedstoneProvider provider )
{
Objects.requireNonNull( provider, "provider cannot be null" );
providers.add( provider );
}
public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side )
{
return world.isValid( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1;
return World.isValid( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1;
}
private static int getUnmaskedOutput( World world, BlockPos pos, EnumFacing side )
private static int getUnmaskedOutput( World world, BlockPos pos, Direction side )
{
if( !world.isValid( pos ) ) return -1;
if( !World.isValid( pos ) ) return -1;
// Try the providers in order:
int combinedSignal = -1;
@@ -60,7 +60,7 @@ public final class BundledRedstone
return combinedSignal;
}
public static int getOutput( World world, BlockPos pos, EnumFacing side )
public static int getOutput( World world, BlockPos pos, Direction side )
{
int signal = getUnmaskedOutput( world, pos, side );
return signal >= 0 ? signal : 0;

View File

@@ -6,502 +6,345 @@
package dan200.computercraft.shared;
import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.google.common.base.CaseFormat;
import com.google.common.base.Converter;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.core.apis.AddressPredicate;
import dan200.computercraft.core.apis.http.websocket.Websocket;
import net.minecraftforge.common.config.ConfigCategory;
import net.minecraftforge.common.config.ConfigElement;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.fml.client.config.IConfigElement;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static dan200.computercraft.ComputerCraft.DEFAULT_HTTP_BLACKLIST;
import static dan200.computercraft.ComputerCraft.DEFAULT_HTTP_WHITELIST;
import static net.minecraftforge.common.ForgeConfigSpec.Builder;
import static net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD )
public final class Config
{
private static final int MODEM_MAX_RANGE = 100000;
private static final String CATEGORY_GENERAL = "general";
private static final String CATEGORY_EXECUTION = "execution";
private static final String CATEGORY_HTTP = "http";
private static final String CATEGORY_PERIPHERAL = "peripheral";
private static final String CATEGORY_TURTLE = "turtle";
private static final String TRANSLATION_PREFIX = "gui.computercraft.config.";
private static Configuration config;
private static ConfigValue<Integer> computerSpaceLimit;
private static ConfigValue<Integer> floppySpaceLimit;
private static ConfigValue<Integer> maximumFilesOpen;
private static ConfigValue<Boolean> disableLua51Features;
private static ConfigValue<String> defaultComputerSettings;
private static ConfigValue<Boolean> debugEnabled;
private static ConfigValue<Boolean> logComputerErrors;
private static Property computerSpaceLimit;
private static Property floppySpaceLimit;
private static Property maximumFilesOpen;
private static Property disableLua51Features;
private static Property defaultComputerSettings;
private static Property debugEnabled;
private static Property logComputerErrors;
private static ConfigValue<Integer> computerThreads;
private static ConfigValue<Integer> maxMainGlobalTime;
private static ConfigValue<Integer> maxMainComputerTime;
private static Property computerThreads;
private static Property maxMainGlobalTime;
private static Property maxMainComputerTime;
private static ConfigValue<Boolean> httpEnabled;
private static ConfigValue<Boolean> httpWebsocketEnabled;
private static ConfigValue<List<? extends String>> httpWhitelist;
private static ConfigValue<List<? extends String>> httpBlacklist;
private static Property httpEnable;
private static Property httpWebsocketEnable;
private static Property httpWhitelist;
private static Property httpBlacklist;
private static ConfigValue<Integer> httpTimeout;
private static ConfigValue<Integer> httpMaxRequests;
private static ConfigValue<Integer> httpMaxDownload;
private static ConfigValue<Integer> httpMaxUpload;
private static ConfigValue<Integer> httpMaxWebsockets;
private static ConfigValue<Integer> httpMaxWebsocketMessage;
private static Property httpTimeout;
private static Property httpMaxRequests;
private static Property httpMaxDownload;
private static Property httpMaxUpload;
private static Property httpMaxWebsockets;
private static Property httpMaxWebsocketMessage;
private static ConfigValue<Boolean> commandBlockEnabled;
private static ConfigValue<Integer> modemRange;
private static ConfigValue<Integer> modemHighAltitudeRange;
private static ConfigValue<Integer> modemRangeDuringStorm;
private static ConfigValue<Integer> modemHighAltitudeRangeDuringStorm;
private static ConfigValue<Integer> maxNotesPerTick;
private static Property commandBlockEnabled;
private static Property modemRange;
private static Property modemHighAltitudeRange;
private static Property modemRangeDuringStorm;
private static Property modemHighAltitudeRangeDuringStorm;
private static Property maxNotesPerTick;
private static ConfigValue<Boolean> turtlesNeedFuel;
private static ConfigValue<Integer> turtleFuelLimit;
private static ConfigValue<Integer> advancedTurtleFuelLimit;
private static ConfigValue<Boolean> turtlesObeyBlockProtection;
private static ConfigValue<Boolean> turtlesCanPush;
private static ConfigValue<List<? extends String>> turtleDisabledActions;
private static Property turtlesNeedFuel;
private static Property turtleFuelLimit;
private static Property advancedTurtleFuelLimit;
private static Property turtlesObeyBlockProtection;
private static Property turtlesCanPush;
private static Property turtleDisabledActions;
private static final ForgeConfigSpec spec;
private Config() {}
public static void load( File configFile )
static
{
config = new Configuration( configFile, ComputerCraft.getVersion() );
config.load();
Builder builder = new Builder();
{ // General computers
renameProperty( CATEGORY_GENERAL, "computerSpaceLimit", CATEGORY_GENERAL, "computer_space_limit" );
renameProperty( CATEGORY_GENERAL, "floppySpaceLimit", CATEGORY_GENERAL, "floppy_space_limit" );
renameProperty( CATEGORY_GENERAL, "maximumFilesOpen", CATEGORY_GENERAL, "maximum_open_files" );
renameProperty( CATEGORY_GENERAL, "debug_enable", CATEGORY_GENERAL, "debug_enabled" );
renameProperty( CATEGORY_GENERAL, "logPeripheralErrors", CATEGORY_GENERAL, "log_computer_errors" );
computerSpaceLimit = builder
.comment( "The disk space limit for computers and turtles, in bytes" )
.translation( TRANSLATION_PREFIX + "computer_space_limit" )
.define( "computer_space_limit", ComputerCraft.computerSpaceLimit );
computerSpaceLimit = config.get( CATEGORY_GENERAL, "computer_space_limit", ComputerCraft.computerSpaceLimit );
computerSpaceLimit.setComment( "The disk space limit for computers and turtles, in bytes" );
floppySpaceLimit = builder
.comment( "The disk space limit for floppy disks, in bytes" )
.translation( TRANSLATION_PREFIX + "floppy_space_limit" )
.define( "floppy_space_limit", ComputerCraft.floppySpaceLimit );
floppySpaceLimit = config.get( CATEGORY_GENERAL, "floppy_space_limit", ComputerCraft.floppySpaceLimit );
floppySpaceLimit.setComment( "The disk space limit for floppy disks, in bytes" );
maximumFilesOpen = builder
.comment( "Set how many files a computer can have open at the same time. Set to 0 for unlimited." )
.translation( TRANSLATION_PREFIX + "maximum_open_files" )
.defineInRange( "maximum_open_files", ComputerCraft.maximumFilesOpen, 0, Integer.MAX_VALUE );
maximumFilesOpen = config.get( CATEGORY_GENERAL, "maximum_open_files", ComputerCraft.maximumFilesOpen );
maximumFilesOpen.setComment( "Set how many files a computer can have open at the same time. Set to 0 for unlimited." );
maximumFilesOpen.setMinValue( 0 );
disableLua51Features = builder
.comment( "Set this to true to disable Lua 5.1 functions that will be removed in a future update. " +
"Useful for ensuring forward compatibility of your programs now." )
.define( "disable_lua51_features", ComputerCraft.disable_lua51_features );
disableLua51Features = config.get( CATEGORY_GENERAL, "disable_lua51_features", ComputerCraft.disable_lua51_features );
disableLua51Features.setComment( "Set this to true to disable Lua 5.1 functions that will be removed in a future " +
"update. Useful for ensuring forward compatibility of your programs now." );
defaultComputerSettings = builder
.comment( "A comma separated list of default system settings to set on new computers. Example: " +
"\"shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false\" will disable all " +
"autocompletion" )
.define( "default_computer_settings", ComputerCraft.default_computer_settings );
defaultComputerSettings = config.get( CATEGORY_GENERAL, "default_computer_settings", ComputerCraft.default_computer_settings );
defaultComputerSettings.setComment( "A comma separated list of default system settings to set on new computers. Example: " +
"\"shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false\" will disable all autocompletion" );
debugEnabled = builder
.comment( "Enable Lua's debug library. This is sandboxed to each computer, so is generally safe to be used by players." )
.define( "debug_enabled", ComputerCraft.debug_enable );
debugEnabled = config.get( CATEGORY_GENERAL, "debug_enabled", ComputerCraft.debug_enable );
debugEnabled.setComment( "Enable Lua's debug library. This is sandboxed to each computer, so is generally safe to be used by players." );
logComputerErrors = config.get( CATEGORY_GENERAL, "log_computer_errors", ComputerCraft.logPeripheralErrors );
logComputerErrors.setComment( "Log exceptions thrown by peripherals and other Lua objects.\n" +
"This makes it easier for mod authors to debug problems, but may result in log spam should people use buggy methods." );
setOrder(
CATEGORY_GENERAL,
computerSpaceLimit, floppySpaceLimit, maximumFilesOpen,
disableLua51Features, defaultComputerSettings, debugEnabled, logComputerErrors
);
logComputerErrors = builder
.comment( "Log exceptions thrown by peripherals and other Lua objects.\n" +
"This makes it easier for mod authors to debug problems, but may result in log spam should people use buggy methods." )
.define( "log_computer_errors", ComputerCraft.logPeripheralErrors );
}
{ // Execution
renameProperty( CATEGORY_GENERAL, "computer_threads", CATEGORY_EXECUTION, "computer_threads" );
{
builder.comment( "Controls execution behaviour of computers. This is largely intended for fine-tuning " +
"servers, and generally shouldn't need to be touched" );
builder.push( "execution" );
config.getCategory( CATEGORY_EXECUTION )
.setComment( "Controls execution behaviour of computers. This is largely intended for fine-tuning " +
"servers, and generally shouldn't need to be touched" );
computerThreads = builder
.comment( "Set the number of threads computers can run on. A higher number means more computers can run " +
"at once, but may induce lag.\n" +
"Please note that some mods may not work with a thread count higher than 1. Use with caution." )
.worldRestart()
.defineInRange( "computer_threads", ComputerCraft.computer_threads, 1, Integer.MAX_VALUE );
computerThreads = config.get( CATEGORY_EXECUTION, "computer_threads", ComputerCraft.computer_threads );
computerThreads
.setMinValue( 1 )
.setRequiresMcRestart( true )
.setComment( "Set the number of threads computers can run on. A higher number means more computers can " +
"run at once, but may induce lag.\n" +
"Please note that some mods may not work with a thread count higher than 1. Use with caution." );
maxMainGlobalTime = builder
.comment( "The maximum time that can be spent executing tasks in a single tick, in milliseconds.\n" +
"Note, we will quite possibly go over this limit, as there's no way to tell how long a will take " +
"- this aims to be the upper bound of the average time." )
.defineInRange( "max_main_global_time", (int) TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainGlobalTime ), 1, Integer.MAX_VALUE );
maxMainGlobalTime = config.get( CATEGORY_EXECUTION, "max_main_global_time", (int) TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainGlobalTime ) );
maxMainGlobalTime
.setMinValue( 1 )
.setComment( "The maximum time that can be spent executing tasks in a single tick, in milliseconds.\n" +
"Note, we will quite possibly go over this limit, as there's no way to tell how long a will take - this aims " +
"to be the upper bound of the average time." );
maxMainComputerTime = builder
.comment( "The ideal maximum time a computer can execute for in a tick, in milliseconds.\n" +
"Note, we will quite possibly go over this limit, as there's no way to tell how long a will take " +
"- this aims to be the upper bound of the average time." )
.defineInRange( "max_main_computer_time", (int) TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainComputerTime ), 1, Integer.MAX_VALUE );
maxMainComputerTime = config.get( CATEGORY_EXECUTION, "max_main_computer_time", (int) TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainComputerTime ) );
maxMainComputerTime
.setMinValue( 1 )
.setComment( "The ideal maximum time a computer can execute for in a tick, in milliseconds.\n" +
"Note, we will quite possibly go over this limit, as there's no way to tell how long a will take - this aims " +
"to be the upper bound of the average time." );
setOrder(
CATEGORY_EXECUTION,
computerThreads, maxMainGlobalTime, maxMainComputerTime
);
builder.pop();
}
{ // HTTP
renameProperty( CATEGORY_GENERAL, "http_enable", CATEGORY_HTTP, "enabled" );
renameProperty( CATEGORY_GENERAL, "http_websocket_enable", CATEGORY_HTTP, "websocket_enabled" );
renameProperty( CATEGORY_GENERAL, "http_whitelist", CATEGORY_HTTP, "whitelist" );
renameProperty( CATEGORY_GENERAL, "http_blacklist", CATEGORY_HTTP, "blacklist" );
builder.comment( "Controls the HTTP API" );
builder.push( "http" );
config.getCategory( CATEGORY_HTTP )
.setComment( "Controls the HTTP API" );
httpEnabled = builder
.comment( "Enable the \"http\" API on Computers (see \"http_whitelist\" and \"http_blacklist\" for more " +
"fine grained control than this)" )
.define( "enabled", ComputerCraft.http_enable );
httpEnable = config.get( CATEGORY_HTTP, "enabled", ComputerCraft.http_enable );
httpEnable.setComment( "Enable the \"http\" API on Computers (see \"http_whitelist\" and \"http_blacklist\" for " +
"more fine grained control than this)" );
httpWebsocketEnabled = builder
.comment( "Enable use of http websockets. This requires the \"http_enable\" option to also be true." )
.define( "websocket_enabled", ComputerCraft.http_websocket_enable );
httpWebsocketEnable = config.get( CATEGORY_HTTP, "websocket_enabled", ComputerCraft.http_websocket_enable );
httpWebsocketEnable.setComment( "Enable use of http websockets. This requires the \"http_enable\" option to also be true." );
httpWhitelist = builder
.comment( "A list of wildcards for domains or IP ranges that can be accessed through the \"http\" API on Computers.\n" +
"Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com\" will restrict access to just subdomains of pastebin.com.\n" +
"You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." )
.defineList( "whitelist", Arrays.asList( DEFAULT_HTTP_WHITELIST ), x -> true );
httpWhitelist = config.get( CATEGORY_HTTP, "whitelist", DEFAULT_HTTP_WHITELIST );
httpWhitelist.setComment( "A list of wildcards for domains or IP ranges that can be accessed through the " +
"\"http\" API on Computers.\n" +
"Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com\" will restrict access to " +
"just subdomains of pastebin.com.\n" +
"You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." );
httpBlacklist = builder
.comment( "A list of wildcards for domains or IP ranges that cannot be accessed through the \"http\" API on Computers.\n" +
"If this is empty then all whitelisted domains will be accessible. Example: \"*.github.com\" will block access to all subdomains of github.com.\n" +
"You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." )
.defineList( "blacklist", Arrays.asList( DEFAULT_HTTP_BLACKLIST ), x -> true );
httpBlacklist = config.get( CATEGORY_HTTP, "blacklist", DEFAULT_HTTP_BLACKLIST );
httpBlacklist.setComment( "A list of wildcards for domains or IP ranges that cannot be accessed through the " +
"\"http\" API on Computers.\n" +
"If this is empty then all whitelisted domains will be accessible. Example: \"*.github.com\" will block " +
"access to all subdomains of github.com.\n" +
"You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." );
httpTimeout = builder
.comment( "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." )
.defineInRange( "timeout", ComputerCraft.httpTimeout, 0, Integer.MAX_VALUE );
httpTimeout = config.get( CATEGORY_HTTP, "timeout", ComputerCraft.httpTimeout );
httpTimeout.setComment( "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." );
httpTimeout.setMinValue( 0 );
httpMaxRequests = builder
.comment( "The number of http requests a computer can make at one time. Additional requests will be queued, and sent when the running requests have finished. Set to 0 for unlimited." )
.defineInRange( "max_requests", ComputerCraft.httpMaxRequests, 0, Integer.MAX_VALUE );
httpMaxRequests = config.get( CATEGORY_HTTP, "max_requests", ComputerCraft.httpMaxRequests );
httpMaxRequests.setComment( "The number of http requests a computer can make at one time. Additional requests " +
"will be queued, and sent when the running requests have finished. Set to 0 for unlimited." );
httpMaxRequests.setMinValue( 0 );
httpMaxDownload = builder
.comment( "The maximum size (in bytes) that a computer can download in a single request. Note that responses may receive more data than allowed, but this data will not be returned to the client." )
.defineInRange( "max_download", (int) ComputerCraft.httpMaxDownload, 0, Integer.MAX_VALUE );
httpMaxDownload = config.get( CATEGORY_HTTP, "max_download", (int) ComputerCraft.httpMaxDownload );
httpMaxDownload.setComment( "The maximum size (in bytes) that a computer can download in a single request. " +
"Note that responses may receive more data than allowed, but this data will not be returned to the client." );
httpMaxDownload.setMinValue( 0 );
httpMaxUpload = builder
.comment( "The maximum size (in bytes) that a computer can upload in a single request. This includes headers and POST text." )
.defineInRange( "max_upload", (int) ComputerCraft.httpMaxUpload, 0, Integer.MAX_VALUE );
httpMaxUpload = config.get( CATEGORY_HTTP, "max_upload", (int) ComputerCraft.httpMaxUpload );
httpMaxUpload.setComment( "The maximum size (in bytes) that a computer can upload in a single request. This " +
"includes headers and POST text." );
httpMaxUpload.setMinValue( 0 );
httpMaxWebsockets = builder
.comment( "The number of websockets a computer can have open at one time. Set to 0 for unlimited." )
.defineInRange( "max_websockets", ComputerCraft.httpMaxWebsockets, 1, Integer.MAX_VALUE );
httpMaxWebsockets = config.get( CATEGORY_HTTP, "max_websockets", ComputerCraft.httpMaxWebsockets );
httpMaxWebsockets.setComment( "The number of websockets a computer can have open at one time. Set to 0 for unlimited." );
httpMaxWebsockets.setMinValue( 1 );
httpMaxWebsocketMessage = builder
.comment( "The maximum size (in bytes) that a computer can send or receive in one websocket packet." )
.defineInRange( "max_websocket_message", ComputerCraft.httpMaxWebsocketMessage, 0, Websocket.MAX_MESSAGE_SIZE );
httpMaxWebsocketMessage = config.get( CATEGORY_HTTP, "max_websocket_message", ComputerCraft.httpMaxWebsocketMessage );
httpMaxWebsocketMessage.setComment( "The maximum size (in bytes) that a computer can send or receive in one websocket packet." );
httpMaxWebsocketMessage.setMinValue( 0 );
httpMaxWebsocketMessage.setMaxValue( Websocket.MAX_MESSAGE_SIZE );
setOrder(
CATEGORY_HTTP,
httpEnable, httpWebsocketEnable, httpWhitelist, httpBlacklist,
httpTimeout, httpMaxRequests, httpMaxDownload, httpMaxUpload, httpMaxWebsockets, httpMaxWebsocketMessage
);
builder.pop();
}
{ // Peripherals
renameProperty( CATEGORY_GENERAL, "enableCommandBlock", CATEGORY_PERIPHERAL, "command_block_enabled" );
renameProperty( CATEGORY_GENERAL, "modem_range", CATEGORY_PERIPHERAL, "modem_range" );
renameProperty( CATEGORY_GENERAL, "modem_highAltitudeRange", CATEGORY_PERIPHERAL, "modem_high_altitude_range" );
renameProperty( CATEGORY_GENERAL, "modem_rangeDuringStorm", CATEGORY_PERIPHERAL, "modem_range_during_storm" );
renameProperty( CATEGORY_GENERAL, "modem_highAltitudeRangeDuringStorm", CATEGORY_PERIPHERAL, "modem_high_altitude_range_during_storm" );
renameProperty( CATEGORY_GENERAL, "maxNotesPerTick", CATEGORY_PERIPHERAL, "max_notes_per_tick" );
builder.comment( "Various options relating to peripherals." );
builder.push( "peripheral" );
config.getCategory( CATEGORY_PERIPHERAL )
.setComment( "Various options relating to peripherals." );
commandBlockEnabled = builder
.comment( "Enable Command Block peripheral support" )
.define( "command_block_enabled", ComputerCraft.enableCommandBlock );
commandBlockEnabled = config.get( CATEGORY_PERIPHERAL, "command_block_enabled", ComputerCraft.enableCommandBlock );
commandBlockEnabled.setComment( "Enable Command Block peripheral support" );
modemRange = builder
.comment( "The range of Wireless Modems at low altitude in clear weather, in meters" )
.defineInRange( "modem_range", ComputerCraft.modem_range, 0, MODEM_MAX_RANGE );
modemRange = config.get( CATEGORY_PERIPHERAL, "modem_range", ComputerCraft.modem_range );
modemRange.setComment( "The range of Wireless Modems at low altitude in clear weather, in meters" );
modemRange.setMinValue( 0 );
modemRange.setMaxValue( MODEM_MAX_RANGE );
modemHighAltitudeRange = builder
.comment( "The range of Wireless Modems at maximum altitude in clear weather, in meters" )
.defineInRange( "modem_high_altitude_range", ComputerCraft.modem_highAltitudeRange, 0, MODEM_MAX_RANGE );
modemHighAltitudeRange = config.get( CATEGORY_PERIPHERAL, "modem_high_altitude_range", ComputerCraft.modem_highAltitudeRange );
modemHighAltitudeRange.setComment( "The range of Wireless Modems at maximum altitude in clear weather, in meters" );
modemHighAltitudeRange.setMinValue( 0 );
modemHighAltitudeRange.setMaxValue( MODEM_MAX_RANGE );
modemRangeDuringStorm = builder
.comment( "The range of Wireless Modems at low altitude in stormy weather, in meters" )
.defineInRange( "modem_range_during_storm", ComputerCraft.modem_rangeDuringStorm, 0, MODEM_MAX_RANGE );
modemRangeDuringStorm = config.get( CATEGORY_PERIPHERAL, "modem_range_during_storm", ComputerCraft.modem_rangeDuringStorm );
modemRangeDuringStorm.setComment( "The range of Wireless Modems at low altitude in stormy weather, in meters" );
modemRangeDuringStorm.setMinValue( 0 );
modemRangeDuringStorm.setMaxValue( MODEM_MAX_RANGE );
modemHighAltitudeRangeDuringStorm = builder
.comment( "The range of Wireless Modems at maximum altitude in stormy weather, in meters" )
.defineInRange( "modem_high_altitude_range_during_storm", ComputerCraft.modem_highAltitudeRangeDuringStorm, 0, MODEM_MAX_RANGE );
modemHighAltitudeRangeDuringStorm = config.get( CATEGORY_PERIPHERAL, "modem_high_altitude_range_during_storm", ComputerCraft.modem_highAltitudeRangeDuringStorm );
modemHighAltitudeRangeDuringStorm.setComment( "The range of Wireless Modems at maximum altitude in stormy weather, in meters" );
modemHighAltitudeRangeDuringStorm.setMinValue( 0 );
modemHighAltitudeRangeDuringStorm.setMaxValue( MODEM_MAX_RANGE );
maxNotesPerTick = builder
.comment( "Maximum amount of notes a speaker can play at once" )
.defineInRange( "max_notes_per_tick", ComputerCraft.maxNotesPerTick, 1, Integer.MAX_VALUE );
maxNotesPerTick = config.get( CATEGORY_PERIPHERAL, "max_notes_per_tick", ComputerCraft.maxNotesPerTick );
maxNotesPerTick.setComment( "Maximum amount of notes a speaker can play at once" );
maxNotesPerTick.setMinValue( 1 );
setOrder(
CATEGORY_PERIPHERAL,
commandBlockEnabled, modemRange, modemHighAltitudeRange, modemRangeDuringStorm, modemHighAltitudeRangeDuringStorm, maxNotesPerTick
);
builder.pop();
}
{ // Turtles
renameProperty( CATEGORY_GENERAL, "turtlesNeedFuel", CATEGORY_TURTLE, "need_fuel" );
renameProperty( CATEGORY_GENERAL, "turtleFuelLimit", CATEGORY_TURTLE, "normal_fuel_limit" );
renameProperty( CATEGORY_GENERAL, "advancedTurtleFuelLimit", CATEGORY_TURTLE, "advanced_fuel_limit" );
renameProperty( CATEGORY_GENERAL, "turtlesObeyBlockProtection", CATEGORY_TURTLE, "obey_block_protection" );
renameProperty( CATEGORY_GENERAL, "turtlesCanPush", CATEGORY_TURTLE, "can_push" );
renameProperty( CATEGORY_GENERAL, "turtle_disabled_actions", CATEGORY_TURTLE, "disabled_actions" );
builder.comment( "Various options relating to turtles." );
builder.push( "turtle" );
config.getCategory( CATEGORY_HTTP )
.setComment( "Various options relating to turtles." );
turtlesNeedFuel = builder
.comment( "Set whether Turtles require fuel to move" )
.define( "need_fuel", ComputerCraft.turtlesNeedFuel );
turtlesNeedFuel = config.get( CATEGORY_TURTLE, "need_fuel", ComputerCraft.turtlesNeedFuel );
turtlesNeedFuel.setComment( "Set whether Turtles require fuel to move" );
turtleFuelLimit = builder
.comment( "The fuel limit for Turtles" )
.defineInRange( "normal_fuel_limit", ComputerCraft.turtleFuelLimit, 0, Integer.MAX_VALUE );
turtleFuelLimit = config.get( CATEGORY_TURTLE, "normal_fuel_limit", ComputerCraft.turtleFuelLimit );
turtleFuelLimit.setComment( "The fuel limit for Turtles" );
turtleFuelLimit.setMinValue( 0 );
advancedTurtleFuelLimit = builder
.comment( "The fuel limit for Advanced Turtles" )
.defineInRange( "advanced_fuel_limit", ComputerCraft.advancedTurtleFuelLimit, 0, Integer.MAX_VALUE );
advancedTurtleFuelLimit = config.get( CATEGORY_TURTLE, "advanced_fuel_limit", ComputerCraft.advancedTurtleFuelLimit );
advancedTurtleFuelLimit.setComment( "The fuel limit for Advanced Turtles" );
advancedTurtleFuelLimit.setMinValue( 0 );
turtlesObeyBlockProtection = builder
.comment( "If set to true, Turtles will be unable to build, dig, or enter protected areas (such as near the server spawn point)" )
.define( "obey_block_protection", ComputerCraft.turtlesObeyBlockProtection );
turtlesObeyBlockProtection = config.get( CATEGORY_TURTLE, "obey_block_protection", ComputerCraft.turtlesObeyBlockProtection );
turtlesObeyBlockProtection.setComment( "If set to true, Turtles will be unable to build, dig, or enter protected " +
"areas (such as near the server spawn point)" );
turtlesCanPush = builder
.comment( "If set to true, Turtles will push entities out of the way instead of stopping if there is space to do so" )
.define( "can_push", ComputerCraft.turtlesCanPush );
turtlesCanPush = config.get( CATEGORY_TURTLE, "can_push", ComputerCraft.turtlesCanPush );
turtlesCanPush.setComment( "If set to true, Turtles will push entities out of the way instead of stopping if " +
"there is space to do so" );
turtleDisabledActions = builder
.comment( "A list of turtle actions which are disabled." )
.defineList( "disabled_actions", Collections.emptyList(), x -> x instanceof String && getAction( (String) x ) != null );
turtleDisabledActions = config.get( CATEGORY_TURTLE, "disabled_actions", new String[0] );
turtleDisabledActions.setComment( "A list of turtle actions which are disabled." );
setOrder(
CATEGORY_TURTLE,
turtlesNeedFuel, turtleFuelLimit, advancedTurtleFuelLimit, turtlesObeyBlockProtection, turtlesCanPush, turtleDisabledActions
);
builder.pop();
}
for( String child : config.getCategoryNames() )
{
setupLanguage(
config.getCategory( child ),
child.equals( CATEGORY_GENERAL ) ? "gui.computercraft:config" : "gui.computercraft:config." + child
);
}
sync();
spec = builder.build();
}
private static void setOrder( String category, Property... properties )
public static void load()
{
List<String> names = new ArrayList<>( properties.length );
for( Property property : properties ) names.add( property.getName() );
config.getCategory( category ).setPropertyOrder( names );
}
private static void renameProperty( String oldCat, String oldProp, String newCat, String newProp )
{
if( !config.hasCategory( oldCat ) ) return;
ConfigCategory cat = config.getCategory( oldCat );
if( !cat.containsKey( oldProp ) ) return;
Property prop = cat.remove( oldProp );
prop.setName( newProp );
config.getCategory( newCat ).put( newProp, prop );
// Clean up old categories
if( cat.isEmpty() ) config.removeCategory( cat );
}
private static void setupLanguage( ConfigCategory category, String key )
{
category.setLanguageKey( key );
for( Property property : category.getOrderedValues() )
{
property.setLanguageKey( key + "." + property.getName() );
}
for( ConfigCategory child : category.getChildren() )
{
setupLanguage( child, key + "." + child.getName() );
}
}
public static void reload()
{
Configuration newConfig = new Configuration( config.getConfigFile(), ComputerCraft.getVersion() );
Set<String> oldCategories = config.getCategoryNames(), newCategories = newConfig.getCategoryNames();
// Sync any categories on the original config
for( String category : oldCategories )
{
if( newCategories.contains( category ) )
{
reloadCategory( config.getCategory( category ), newConfig.getCategory( category ) );
}
else
{
for( Property property : config.getCategory( category ).getValues().values() ) property.setToDefault();
}
}
// And drop any unexpected ones.
for( String category : newCategories )
{
if( !oldCategories.contains( category ) )
{
ComputerCraft.log.warn( "Cannot sync unknown config category {}", category );
}
}
sync();
}
private static void reloadCategory( ConfigCategory oldCat, ConfigCategory newCat )
{
// Copy the config values across to the original config.
for( Map.Entry<String, Property> child : newCat.getValues().entrySet() )
{
Property oldProperty = oldCat.get( child.getKey() ), newProperty = child.getValue();
if( oldProperty.getType() != newProperty.getType() || oldProperty.isList() != newProperty.isList() )
{
ComputerCraft.log.warn(
"Cannot sync config property {} (type changed from {} to {})",
child.getKey(), getType( oldProperty ), getType( newProperty )
);
continue;
}
if( oldProperty.isList() )
{
oldProperty.setValues( newProperty.getStringList() );
}
else
{
oldProperty.setValue( newProperty.getString() );
}
}
// Reset any missing properties.
for( Map.Entry<String, Property> child : oldCat.getValues().entrySet() )
{
if( !newCat.containsKey( child.getKey() ) ) child.getValue().setToDefault();
}
}
private static String getType( Property property )
{
return property.getType() + (property.isList() ? " list" : "");
ModLoadingContext.get().registerConfig( ModConfig.Type.COMMON, spec );
}
public static void sync()
{
// General
ComputerCraft.computerSpaceLimit = computerSpaceLimit.getInt();
ComputerCraft.floppySpaceLimit = floppySpaceLimit.getInt();
ComputerCraft.maximumFilesOpen = Math.max( 0, maximumFilesOpen.getInt() );
ComputerCraft.disable_lua51_features = disableLua51Features.getBoolean();
ComputerCraft.default_computer_settings = defaultComputerSettings.getString();
ComputerCraft.debug_enable = debugEnabled.getBoolean();
ComputerCraft.logPeripheralErrors = logComputerErrors.getBoolean();
ComputerCraft.computerSpaceLimit = computerSpaceLimit.get();
ComputerCraft.floppySpaceLimit = floppySpaceLimit.get();
ComputerCraft.maximumFilesOpen = maximumFilesOpen.get();
ComputerCraft.disable_lua51_features = disableLua51Features.get();
ComputerCraft.default_computer_settings = defaultComputerSettings.get();
ComputerCraft.debug_enable = debugEnabled.get();
ComputerCraft.computer_threads = computerThreads.get();
ComputerCraft.logPeripheralErrors = logComputerErrors.get();
// Execution
ComputerCraft.computer_threads = computerThreads.getInt();
ComputerCraft.maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( Math.max( 1, maxMainGlobalTime.getLong() ) );
ComputerCraft.maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( Math.max( 1, maxMainComputerTime.getLong() ) );
ComputerCraft.computer_threads = computerThreads.get();
ComputerCraft.maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( maxMainGlobalTime.get() );
ComputerCraft.maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( maxMainComputerTime.get() );
// HTTP
ComputerCraft.http_enable = httpEnable.getBoolean();
ComputerCraft.http_websocket_enable = httpWebsocketEnable.getBoolean();
ComputerCraft.http_whitelist = new AddressPredicate( httpWhitelist.getStringList() );
ComputerCraft.http_blacklist = new AddressPredicate( httpBlacklist.getStringList() );
ComputerCraft.http_enable = httpEnabled.get();
ComputerCraft.http_websocket_enable = httpWebsocketEnabled.get();
ComputerCraft.http_whitelist = new AddressPredicate( httpWhitelist.get() );
ComputerCraft.http_blacklist = new AddressPredicate( httpBlacklist.get() );
ComputerCraft.httpTimeout = Math.max( 0, httpTimeout.getInt() );
ComputerCraft.httpMaxRequests = Math.max( 1, httpMaxRequests.getInt() );
ComputerCraft.httpMaxDownload = Math.max( 0, httpMaxDownload.getLong() );
ComputerCraft.httpMaxUpload = Math.max( 0, httpMaxUpload.getLong() );
ComputerCraft.httpMaxWebsockets = Math.max( 1, httpMaxWebsockets.getInt() );
ComputerCraft.httpMaxWebsocketMessage = Math.max( 0, httpMaxWebsocketMessage.getInt() );
ComputerCraft.httpTimeout = httpTimeout.get();
ComputerCraft.httpMaxRequests = httpMaxRequests.get();
ComputerCraft.httpMaxDownload = httpMaxDownload.get();
ComputerCraft.httpMaxUpload = httpMaxUpload.get();
ComputerCraft.httpMaxWebsockets = httpMaxWebsockets.get();
ComputerCraft.httpMaxWebsocketMessage = httpMaxWebsocketMessage.get();
// Peripheral
ComputerCraft.enableCommandBlock = commandBlockEnabled.getBoolean();
ComputerCraft.maxNotesPerTick = Math.max( 1, maxNotesPerTick.getInt() );
ComputerCraft.modem_range = Math.min( modemRange.getInt(), MODEM_MAX_RANGE );
ComputerCraft.modem_highAltitudeRange = Math.min( modemHighAltitudeRange.getInt(), MODEM_MAX_RANGE );
ComputerCraft.modem_rangeDuringStorm = Math.min( modemRangeDuringStorm.getInt(), MODEM_MAX_RANGE );
ComputerCraft.modem_highAltitudeRangeDuringStorm = Math.min( modemHighAltitudeRangeDuringStorm.getInt(), MODEM_MAX_RANGE );
ComputerCraft.enableCommandBlock = commandBlockEnabled.get();
ComputerCraft.maxNotesPerTick = maxNotesPerTick.get();
ComputerCraft.modem_range = modemRange.get();
ComputerCraft.modem_highAltitudeRange = modemHighAltitudeRange.get();
ComputerCraft.modem_rangeDuringStorm = modemRangeDuringStorm.get();
ComputerCraft.modem_highAltitudeRangeDuringStorm = modemHighAltitudeRangeDuringStorm.get();
// Turtles
ComputerCraft.turtlesNeedFuel = turtlesNeedFuel.getBoolean();
ComputerCraft.turtleFuelLimit = turtleFuelLimit.getInt();
ComputerCraft.advancedTurtleFuelLimit = advancedTurtleFuelLimit.getInt();
ComputerCraft.turtlesObeyBlockProtection = turtlesObeyBlockProtection.getBoolean();
ComputerCraft.turtlesCanPush = turtlesCanPush.getBoolean();
ComputerCraft.turtlesNeedFuel = turtlesNeedFuel.get();
ComputerCraft.turtleFuelLimit = turtleFuelLimit.get();
ComputerCraft.advancedTurtleFuelLimit = advancedTurtleFuelLimit.get();
ComputerCraft.turtlesObeyBlockProtection = turtlesObeyBlockProtection.get();
ComputerCraft.turtlesCanPush = turtlesCanPush.get();
ComputerCraft.turtleDisabledActions.clear();
Converter<String, String> converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE );
for( String value : turtleDisabledActions.getStringList() )
{
try
{
ComputerCraft.turtleDisabledActions.add( TurtleAction.valueOf( converter.convert( value ) ) );
}
catch( IllegalArgumentException e )
{
ComputerCraft.log.error( "Unknown turtle action " + value );
}
}
config.save();
for( String value : turtleDisabledActions.get() ) ComputerCraft.turtleDisabledActions.add( getAction( value ) );
}
public static List<IConfigElement> getConfigElements()
@SubscribeEvent
public static void sync( ModConfig.Loading event )
{
ArrayList<IConfigElement> elements = new ArrayList<>();
// Add all child categories
for( String categoryName : config.getCategoryNames() )
{
if( categoryName.equals( CATEGORY_GENERAL ) ) continue;
ConfigCategory category = config.getCategory( categoryName );
elements.add( new ConfigElement( category ) );
}
// Add the general category
for( Property property : config.getCategory( CATEGORY_GENERAL ).getOrderedValues() )
{
elements.add( new ConfigElement( property ) );
}
return elements;
sync();
}
@SubscribeEvent
public static void sync( ModConfig.ConfigReloading event )
{
// Ensure file configs are reloaded. Forge should probably do this, so worth checking in the future.
CommentedConfig config = event.getConfig().getConfigData();
if( config instanceof CommentedFileConfig ) ((CommentedFileConfig) config).load();
sync();
}
private static final Converter<String, String> converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE );
private static TurtleAction getAction( String value )
{
try
{
return TurtleAction.valueOf( converter.convert( value ) );
}
catch( IllegalArgumentException e )
{
return null;
}
}
}

View File

@@ -22,7 +22,7 @@ public final class MediaProviders
private MediaProviders() {}
public static void register( @Nonnull IMediaProvider provider )
public static synchronized void register( @Nonnull IMediaProvider provider )
{
Objects.requireNonNull( provider, "provider cannot be null" );
providers.add( provider );

View File

@@ -9,32 +9,33 @@ package dan200.computercraft.shared;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Objects;
public final class Peripherals
{
private static final Collection<IPeripheralProvider> providers = ComputerCraft.peripheralProviders;
private static final Collection<IPeripheralProvider> providers = new LinkedHashSet<>();
private Peripherals() {}
public static void register( @Nonnull IPeripheralProvider provider )
public static synchronized void register( @Nonnull IPeripheralProvider provider )
{
Objects.requireNonNull( provider, "provider cannot be null" );
if( !providers.contains( provider ) ) providers.add( provider );
providers.add( provider );
}
public static IPeripheral getPeripheral( World world, BlockPos pos, EnumFacing side )
public static IPeripheral getPeripheral( World world, BlockPos pos, Direction side )
{
return world.isValid( pos ) && !world.isRemote ? getPeripheralAt( world, pos, side ) : null;
return World.isValid( pos ) && !world.isRemote ? getPeripheralAt( world, pos, side ) : null;
}
private static IPeripheral getPeripheralAt( World world, BlockPos pos, EnumFacing side )
private static IPeripheral getPeripheralAt( World world, BlockPos pos, Direction side )
{
// Try the handlers in order:
for( IPeripheralProvider peripheralProvider : providers )

View File

@@ -10,8 +10,8 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.shared.util.InventoryUtil;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModLoadingContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -24,7 +24,7 @@ public final class PocketUpgrades
private PocketUpgrades() {}
public static void register( @Nonnull IPocketUpgrade upgrade )
public static synchronized void register( @Nonnull IPocketUpgrade upgrade )
{
Objects.requireNonNull( upgrade, "upgrade cannot be null" );
@@ -37,7 +37,7 @@ public final class PocketUpgrades
upgrades.put( id, upgrade );
ModContainer mc = Loader.instance().activeModContainer();
ModContainer mc = ModLoadingContext.get().getActiveContainer();
if( mc != null && mc.getModId() != null ) upgradeOwners.put( upgrade, mc.getModId() );
}
@@ -74,8 +74,8 @@ public final class PocketUpgrades
public static Iterable<IPocketUpgrade> getVanillaUpgrades()
{
List<IPocketUpgrade> vanilla = new ArrayList<>();
vanilla.add( ComputerCraft.PocketUpgrades.wirelessModem );
vanilla.add( ComputerCraft.PocketUpgrades.advancedModem );
vanilla.add( ComputerCraft.PocketUpgrades.wirelessModemNormal );
vanilla.add( ComputerCraft.PocketUpgrades.wirelessModemAdvanced );
vanilla.add( ComputerCraft.PocketUpgrades.speaker );
return vanilla;
}

View File

@@ -8,52 +8,71 @@ package dan200.computercraft.shared;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.computer.blocks.BlockCommandComputer;
import dan200.computercraft.shared.common.ColourableRecipe;
import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.computer.blocks.BlockComputer;
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.items.ItemCommandComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.media.items.ItemDiskExpanded;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.computer.recipe.ComputerUpgradeRecipe;
import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.ItemPeripheral;
import dan200.computercraft.shared.media.recipes.DiskRecipe;
import dan200.computercraft.shared.media.recipes.PrintoutRecipe;
import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.modem.wired.*;
import dan200.computercraft.shared.peripheral.modem.wireless.BlockAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.ItemAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.TileAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.BlockWirelessModem;
import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem;
import dan200.computercraft.shared.peripheral.monitor.BlockMonitor;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.peripheral.printer.BlockPrinter;
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker;
import dan200.computercraft.shared.peripheral.speaker.TileSpeaker;
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe;
import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.blocks.TileTurtleAdvanced;
import dan200.computercraft.shared.turtle.blocks.TileTurtleExpanded;
import dan200.computercraft.shared.turtle.items.ItemTurtleAdvanced;
import dan200.computercraft.shared.turtle.items.ItemTurtleLegacy;
import dan200.computercraft.shared.turtle.items.ItemTurtleNormal;
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import dan200.computercraft.shared.turtle.items.ItemTurtle;
import dan200.computercraft.shared.turtle.recipes.TurtleRecipe;
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
import dan200.computercraft.shared.turtle.upgrades.*;
import dan200.computercraft.shared.util.CreativeTabMain;
import dan200.computercraft.shared.util.ImpostorRecipe;
import dan200.computercraft.shared.util.ImpostorShapelessRecipe;
import net.minecraft.block.Block;
import net.minecraft.init.Items;
import net.minecraft.block.material.Material;
import net.minecraft.entity.EntityType;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.Items;
import net.minecraft.item.crafting.IRecipeSerializer;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.registries.IForgeRegistry;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID )
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD )
public final class Registry
{
private static final ItemGroup mainItemGroup = new CreativeTabMain();
private Registry()
{
}
@@ -64,266 +83,283 @@ public final class Registry
IForgeRegistry<Block> registry = event.getRegistry();
// Computers
ComputerCraft.Blocks.computer = new BlockComputer();
ComputerCraft.Blocks.commandComputer = new BlockCommandComputer();
registry.registerAll(
ComputerCraft.Blocks.computer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ),
ComputerCraft.Blocks.commandComputer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ) )
ComputerCraft.Blocks.computerNormal = new BlockComputer(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ),
ComputerFamily.Normal, TileComputer.FACTORY_NORMAL
);
// Turtle
ComputerCraft.Blocks.turtle = new BlockTurtle();
ComputerCraft.Blocks.turtleExpanded = new BlockTurtle();
ComputerCraft.Blocks.turtleAdvanced = new BlockTurtle();
ComputerCraft.Blocks.computerAdvanced = new BlockComputer(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ),
ComputerFamily.Advanced, TileComputer.FACTORY_ADVANCED
);
ComputerCraft.Blocks.computerCommand = new BlockComputer(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( -1, 6000000.0F ),
ComputerFamily.Command, TileCommandComputer.FACTORY
);
registry.registerAll(
ComputerCraft.Blocks.turtle.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ),
ComputerCraft.Blocks.turtleExpanded.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_expanded" ) ),
ComputerCraft.Blocks.computerNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_normal" ) ),
ComputerCraft.Blocks.computerAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_advanced" ) ),
ComputerCraft.Blocks.computerCommand.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_command" ) )
);
// Turtles
ComputerCraft.Blocks.turtleNormal = new BlockTurtle(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ),
ComputerFamily.Normal, TileTurtle.FACTORY_NORMAL
);
ComputerCraft.Blocks.turtleAdvanced = new BlockTurtle(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ),
ComputerFamily.Advanced, TileTurtle.FACTORY_ADVANCED
);
registry.registerAll(
ComputerCraft.Blocks.turtleNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ) ),
ComputerCraft.Blocks.turtleAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ) )
);
// Peripheral
ComputerCraft.Blocks.peripheral = new BlockPeripheral();
registry.register( ComputerCraft.Blocks.peripheral.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "peripheral" ) ) );
// Peripherals
ComputerCraft.Blocks.speaker = new BlockSpeaker(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 )
);
// Cable
ComputerCraft.Blocks.cable = new BlockCable();
registry.register( ComputerCraft.Blocks.cable.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ) ) );
ComputerCraft.Blocks.diskDrive = new BlockDiskDrive(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 )
);
// Advanced modem
ComputerCraft.Blocks.advancedModem = new BlockAdvancedModem();
registry.register( ComputerCraft.Blocks.advancedModem.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "advanced_modem" ) ) );
ComputerCraft.Blocks.monitorNormal = new BlockMonitor(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ),
TileMonitor.FACTORY_NORMAL
);
// Full block modem
ComputerCraft.Blocks.wiredModemFull = new BlockWiredModemFull();
registry.register( ComputerCraft.Blocks.wiredModemFull.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ) ) );
ComputerCraft.Blocks.monitorAdvanced = new BlockMonitor(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ),
TileMonitor.FACTORY_ADVANCED
);
registerTileEntities();
ComputerCraft.Blocks.printer = new BlockPrinter(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 )
);
ComputerCraft.Blocks.wirelessModemNormal = new BlockWirelessModem(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ),
TileWirelessModem.FACTORY_NORMAL
);
ComputerCraft.Blocks.wirelessModemAdvanced = new BlockWirelessModem(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ),
TileWirelessModem.FACTORY_ADVANCED
);
ComputerCraft.Blocks.wiredModemFull = new BlockWiredModemFull(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 1.5f )
);
ComputerCraft.Blocks.cable = new BlockCable(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 1.5f )
);
registry.registerAll(
ComputerCraft.Blocks.speaker.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ) ),
ComputerCraft.Blocks.diskDrive.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ) ),
ComputerCraft.Blocks.monitorNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "monitor_normal" ) ),
ComputerCraft.Blocks.monitorAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "monitor_advanced" ) ),
ComputerCraft.Blocks.printer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printer" ) ),
ComputerCraft.Blocks.wirelessModemNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) ),
ComputerCraft.Blocks.wirelessModemAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) ),
ComputerCraft.Blocks.wiredModemFull.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ) ),
ComputerCraft.Blocks.cable.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ) )
);
}
private static void registerTileEntities()
@SubscribeEvent
public static void registerTileEntities( RegistryEvent.Register<TileEntityType<?>> event )
{
GameRegistry.registerTileEntity( TileComputer.class, new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) );
GameRegistry.registerTileEntity( TileCommandComputer.class, new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ) );
IForgeRegistry<TileEntityType<?>> registry = event.getRegistry();
GameRegistry.registerTileEntity( TileTurtle.class, new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) );
GameRegistry.registerTileEntity( TileTurtleExpanded.class, new ResourceLocation( ComputerCraft.MOD_ID, "turtleex" ) );
GameRegistry.registerTileEntity( TileTurtleAdvanced.class, new ResourceLocation( ComputerCraft.MOD_ID, "turtleadv" ) );
// Computers
registry.registerAll( TileComputer.FACTORY_NORMAL, TileComputer.FACTORY_ADVANCED, TileCommandComputer.FACTORY );
GameRegistry.registerTileEntity( TileDiskDrive.class, new ResourceLocation( ComputerCraft.MOD_ID, "diskdrive" ) );
GameRegistry.registerTileEntity( TileWirelessModem.class, new ResourceLocation( ComputerCraft.MOD_ID, "wirelessmodem" ) );
GameRegistry.registerTileEntity( TileMonitor.class, new ResourceLocation( ComputerCraft.MOD_ID, "monitor" ) );
GameRegistry.registerTileEntity( TilePrinter.class, new ResourceLocation( ComputerCraft.MOD_ID, "ccprinter" ) );
GameRegistry.registerTileEntity( TileCable.class, new ResourceLocation( ComputerCraft.MOD_ID, "wiredmodem" ) );
GameRegistry.registerTileEntity( TileAdvancedModem.class, new ResourceLocation( ComputerCraft.MOD_ID, "advanced_modem" ) );
GameRegistry.registerTileEntity( TileSpeaker.class, new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ) );
GameRegistry.registerTileEntity( TileWiredModemFull.class, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ) );
// Turtles
registry.registerAll( TileTurtle.FACTORY_NORMAL, TileTurtle.FACTORY_ADVANCED );
// Peripherals
registry.registerAll(
TileSpeaker.FACTORY,
TileDiskDrive.FACTORY,
TileMonitor.FACTORY_NORMAL,
TileMonitor.FACTORY_ADVANCED,
TilePrinter.FACTORY,
TileWirelessModem.FACTORY_NORMAL,
TileWirelessModem.FACTORY_ADVANCED,
TileWiredModemFull.FACTORY,
TileCable.FACTORY
);
}
private static <T extends ItemBlock> T setupItemBlock( T item )
private static <T extends BlockItem> T setupItemBlock( T item )
{
item.setRegistryName( item.getBlock().getRegistryName() );
return item;
}
private static Item.Properties defaultItem()
{
return new Item.Properties().group( mainItemGroup );
}
@SubscribeEvent
public static void registerItems( RegistryEvent.Register<Item> event )
{
IForgeRegistry<Item> registry = event.getRegistry();
// Computers
ComputerCraft.Items.computer = new ItemComputer( ComputerCraft.Blocks.computer );
ComputerCraft.Items.commandComputer = new ItemCommandComputer( ComputerCraft.Blocks.commandComputer );
// Computer
ComputerCraft.Items.computerNormal = new ItemComputer( ComputerCraft.Blocks.computerNormal, defaultItem() );
ComputerCraft.Items.computerAdvanced = new ItemComputer( ComputerCraft.Blocks.computerAdvanced, defaultItem() );
ComputerCraft.Items.computerCommand = new ItemComputer( ComputerCraft.Blocks.computerCommand, defaultItem() );
registry.registerAll(
setupItemBlock( ComputerCraft.Items.computer ),
setupItemBlock( ComputerCraft.Items.commandComputer )
);
// Pocket computer
ComputerCraft.Items.pocketComputer = new ItemPocketComputer();
registry.register(
ComputerCraft.Items.pocketComputer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer" ) )
setupItemBlock( ComputerCraft.Items.computerNormal ),
setupItemBlock( ComputerCraft.Items.computerAdvanced ),
setupItemBlock( ComputerCraft.Items.computerCommand )
);
// Turtle
ComputerCraft.Items.turtle = new ItemTurtleLegacy( ComputerCraft.Blocks.turtle );
ComputerCraft.Items.turtleExpanded = new ItemTurtleNormal( ComputerCraft.Blocks.turtleExpanded );
ComputerCraft.Items.turtleAdvanced = new ItemTurtleAdvanced( ComputerCraft.Blocks.turtleAdvanced );
ComputerCraft.Items.turtleNormal = new ItemTurtle( ComputerCraft.Blocks.turtleNormal, defaultItem() );
ComputerCraft.Items.turtleAdvanced = new ItemTurtle( ComputerCraft.Blocks.turtleAdvanced, defaultItem() );
registry.registerAll(
setupItemBlock( ComputerCraft.Items.turtle ),
setupItemBlock( ComputerCraft.Items.turtleExpanded ),
setupItemBlock( ComputerCraft.Items.turtleNormal ),
setupItemBlock( ComputerCraft.Items.turtleAdvanced )
);
// Printouts
ComputerCraft.Items.printout = new ItemPrintout();
registry.register( ComputerCraft.Items.printout.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printout" ) ) );
// Pocket computer
ComputerCraft.Items.pocketComputerNormal = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.Normal );
ComputerCraft.Items.pocketComputerAdvanced = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.Advanced );
// Disks
ComputerCraft.Items.disk = new ItemDiskLegacy();
ComputerCraft.Items.diskExpanded = new ItemDiskExpanded();
ComputerCraft.Items.treasureDisk = new ItemTreasureDisk();
registry.registerAll(
ComputerCraft.Items.pocketComputerNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_normal" ) ),
ComputerCraft.Items.pocketComputerAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_advanced" ) )
);
// Floppy disk
ComputerCraft.Items.disk = new ItemDisk( defaultItem().maxStackSize( 1 ) );
ComputerCraft.Items.treasureDisk = new ItemTreasureDisk( defaultItem().maxStackSize( 1 ) );
registry.registerAll(
ComputerCraft.Items.disk.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk" ) ),
ComputerCraft.Items.diskExpanded.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk_expanded" ) ),
ComputerCraft.Items.treasureDisk.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "treasure_disk" ) )
);
// Peripherals
ComputerCraft.Items.peripheral = new ItemPeripheral( ComputerCraft.Blocks.peripheral );
ComputerCraft.Items.advancedModem = new ItemAdvancedModem( ComputerCraft.Blocks.advancedModem );
ComputerCraft.Items.cable = new ItemCable( ComputerCraft.Blocks.cable );
ComputerCraft.Items.wiredModemFull = new ItemWiredModemFull( ComputerCraft.Blocks.wiredModemFull );
// Printouts
ComputerCraft.Items.printedPage = new ItemPrintout( defaultItem().maxStackSize( 1 ), ItemPrintout.Type.PAGE );
ComputerCraft.Items.printedPages = new ItemPrintout( defaultItem().maxStackSize( 1 ), ItemPrintout.Type.PAGES );
ComputerCraft.Items.printedBook = new ItemPrintout( defaultItem().maxStackSize( 1 ), ItemPrintout.Type.BOOK );
registry.registerAll(
setupItemBlock( ComputerCraft.Items.peripheral ),
setupItemBlock( ComputerCraft.Items.advancedModem ),
setupItemBlock( ComputerCraft.Items.cable ),
setupItemBlock( ComputerCraft.Items.wiredModemFull )
ComputerCraft.Items.printedPage.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printed_page" ) ),
ComputerCraft.Items.printedPages.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printed_pages" ) ),
ComputerCraft.Items.printedBook.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printed_book" ) )
);
// Peripherals
registry.registerAll(
setupItemBlock( new BlockItem( ComputerCraft.Blocks.speaker, defaultItem() ) ),
setupItemBlock( new BlockItem( ComputerCraft.Blocks.diskDrive, defaultItem() ) ),
setupItemBlock( new BlockItem( ComputerCraft.Blocks.printer, defaultItem() ) ),
setupItemBlock( new BlockItem( ComputerCraft.Blocks.monitorNormal, defaultItem() ) ),
setupItemBlock( new BlockItem( ComputerCraft.Blocks.monitorAdvanced, defaultItem() ) ),
setupItemBlock( new BlockItem( ComputerCraft.Blocks.wirelessModemNormal, defaultItem() ) ),
setupItemBlock( new BlockItem( ComputerCraft.Blocks.wirelessModemAdvanced, defaultItem() ) ),
setupItemBlock( new BlockItem( ComputerCraft.Blocks.wiredModemFull, defaultItem() ) )
);
ComputerCraft.Items.cable = new ItemBlockCable.Cable( ComputerCraft.Blocks.cable, defaultItem() );
ComputerCraft.Items.wiredModem = new ItemBlockCable.WiredModem( ComputerCraft.Blocks.cable, defaultItem() );
registry.registerAll(
ComputerCraft.Items.cable.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ) ),
ComputerCraft.Items.wiredModem.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem" ) )
);
registerTurtleUpgrades();
registerPocketUpgrades();
registerLegacyUpgrades();
}
private static void registerTurtleUpgrades()
{
// Upgrades
ComputerCraft.TurtleUpgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.wirelessModem );
ComputerCraft.TurtleUpgrades.wirelessModemNormal = new TurtleModem( false, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) );
TurtleUpgrades.register( ComputerCraft.TurtleUpgrades.wirelessModemNormal );
ComputerCraft.TurtleUpgrades.advancedModem = new TurtleModem( true, new ResourceLocation( "computercraft", "advanced_modem" ), -1 );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.advancedModem );
ComputerCraft.TurtleUpgrades.wirelessModemAdvanced = new TurtleModem( true, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) );
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.wirelessModemAdvanced );
ComputerCraft.TurtleUpgrades.speaker = new TurtleSpeaker( new ResourceLocation( "computercraft", "speaker" ), 8 );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.speaker );
ComputerCraft.TurtleUpgrades.speaker = new TurtleSpeaker( new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ) );
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.speaker );
ComputerCraft.TurtleUpgrades.craftingTable = new TurtleCraftingTable( new ResourceLocation( "minecraft", "crafting_table" ), 2 );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.craftingTable );
ComputerCraft.TurtleUpgrades.craftingTable = new TurtleCraftingTable( new ResourceLocation( "minecraft", "crafting_table" ) );
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.craftingTable );
ComputerCraft.TurtleUpgrades.diamondSword = new TurtleSword( new ResourceLocation( "minecraft", "diamond_sword" ), 3, Items.DIAMOND_SWORD );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondSword );
ComputerCraft.TurtleUpgrades.diamondSword = new TurtleSword( new ResourceLocation( "minecraft", "diamond_sword" ), Items.DIAMOND_SWORD );
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondSword );
ComputerCraft.TurtleUpgrades.diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), 4, Items.DIAMOND_SHOVEL );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondShovel );
ComputerCraft.TurtleUpgrades.diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), net.minecraft.item.Items.DIAMOND_SHOVEL );
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondShovel );
ComputerCraft.TurtleUpgrades.diamondPickaxe = new TurtleTool( new ResourceLocation( "minecraft", "diamond_pickaxe" ), 5, Items.DIAMOND_PICKAXE );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondPickaxe );
ComputerCraft.TurtleUpgrades.diamondPickaxe = new TurtleTool( new ResourceLocation( "minecraft", "diamond_pickaxe" ), Items.DIAMOND_PICKAXE );
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondPickaxe );
ComputerCraft.TurtleUpgrades.diamondAxe = new TurtleAxe( new ResourceLocation( "minecraft", "diamond_axe" ), 6, Items.DIAMOND_AXE );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondAxe );
ComputerCraft.TurtleUpgrades.diamondAxe = new TurtleAxe( new ResourceLocation( "minecraft", "diamond_axe" ), Items.DIAMOND_AXE );
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondAxe );
ComputerCraft.TurtleUpgrades.diamondHoe = new TurtleHoe( new ResourceLocation( "minecraft", "diamond_hoe" ), 7, Items.DIAMOND_HOE );
TurtleUpgrades.registerInternal( ComputerCraft.TurtleUpgrades.diamondHoe );
ComputerCraft.TurtleUpgrades.diamondHoe = new TurtleHoe( new ResourceLocation( "minecraft", "diamond_hoe" ), Items.DIAMOND_HOE );
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondHoe );
}
private static void registerPocketUpgrades()
{
// Register pocket upgrades
ComputerCraft.PocketUpgrades.wirelessModem = new PocketModem( false );
ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.wirelessModem );
ComputerCraft.PocketUpgrades.advancedModem = new PocketModem( true );
ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.advancedModem );
ComputerCraft.PocketUpgrades.speaker = new PocketSpeaker();
ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.speaker );
}
@SuppressWarnings( "deprecation" )
private static void registerLegacyUpgrades()
{
ComputerCraft.PocketUpgrades.pocketSpeaker = ComputerCraft.PocketUpgrades.speaker;
ComputerCraft.Upgrades.advancedModem = ComputerCraft.TurtleUpgrades.advancedModem;
ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.wirelessModemNormal = new PocketModem( false ) );
ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.wirelessModemAdvanced = new PocketModem( true ) );
ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.speaker = new PocketSpeaker() );
}
@SubscribeEvent
public static void remapItems( RegistryEvent.MissingMappings<Item> mappings )
public static void registerEntities( RegistryEvent.Register<EntityType<?>> registry )
{
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
for( RegistryEvent.MissingMappings.Mapping<Item> mapping : mappings.getAllMappings() )
{
String domain = mapping.key.getNamespace();
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
String key = mapping.key.getPath();
if( key.equalsIgnoreCase( "CC-Computer" ) )
{
mapping.remap( ComputerCraft.Items.computer );
}
else if( key.equalsIgnoreCase( "CC-Peripheral" ) )
{
mapping.remap( ComputerCraft.Items.peripheral );
}
else if( key.equalsIgnoreCase( "CC-Cable" ) )
{
mapping.remap( ComputerCraft.Items.cable );
}
else if( key.equalsIgnoreCase( "diskExpanded" ) )
{
mapping.remap( ComputerCraft.Items.diskExpanded );
}
else if( key.equalsIgnoreCase( "treasureDisk" ) )
{
mapping.remap( ComputerCraft.Items.treasureDisk );
}
else if( key.equalsIgnoreCase( "pocketComputer" ) )
{
mapping.remap( ComputerCraft.Items.pocketComputer );
}
else if( key.equalsIgnoreCase( "CC-Turtle" ) )
{
mapping.remap( ComputerCraft.Items.turtle );
}
else if( key.equalsIgnoreCase( "CC-TurtleExpanded" ) )
{
mapping.remap( ComputerCraft.Items.turtleExpanded );
}
else if( key.equalsIgnoreCase( "CC-TurtleAdvanced" ) )
{
mapping.remap( ComputerCraft.Items.turtleAdvanced );
}
}
registry.getRegistry().register( TurtlePlayer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_player" ) ) );
}
@SubscribeEvent
public static void remapBlocks( RegistryEvent.MissingMappings<Block> mappings )
public static void registerContainers( RegistryEvent.Register<ContainerType<?>> event )
{
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
for( RegistryEvent.MissingMappings.Mapping<Block> mapping : mappings.getAllMappings() )
{
String domain = mapping.key.getNamespace();
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
event.getRegistry().registerAll(
ContainerComputer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ),
ContainerPocketComputer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer" ) ),
ContainerTurtle.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ),
String key = mapping.key.getPath();
if( key.equalsIgnoreCase( "CC-Computer" ) )
{
mapping.remap( ComputerCraft.Blocks.computer );
}
else if( key.equalsIgnoreCase( "CC-Peripheral" ) )
{
mapping.remap( ComputerCraft.Blocks.peripheral );
}
else if( key.equalsIgnoreCase( "CC-Cable" ) )
{
mapping.remap( ComputerCraft.Blocks.cable );
}
else if( key.equalsIgnoreCase( "CC-Turtle" ) )
{
mapping.remap( ComputerCraft.Blocks.turtle );
}
else if( key.equalsIgnoreCase( "CC-TurtleExpanded" ) )
{
mapping.remap( ComputerCraft.Blocks.turtleExpanded );
}
else if( key.equalsIgnoreCase( "CC-TurtleAdvanced" ) )
{
mapping.remap( ComputerCraft.Blocks.turtleAdvanced );
}
}
ContainerDiskDrive.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ) ),
ContainerPrinter.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printer" ) ),
ContainerHeldItem.PRINTOUT_TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printout" ) ),
ContainerViewComputer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "view_computer" ) )
);
}
@SubscribeEvent
public static void regsterRecipeSerializers( RegistryEvent.Register<IRecipeSerializer<?>> event )
{
event.getRegistry().registerAll(
ColourableRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "colour" ) ),
ComputerUpgradeRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_upgrade" ) ),
PocketComputerUpgradeRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_upgrade" ) ),
DiskRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk" ) ),
PrintoutRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printout" ) ),
TurtleRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ),
TurtleUpgradeRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_upgrade" ) ),
ImpostorShapelessRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shapeless" ) ),
ImpostorRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shaped" ) )
);
}
}

View File

@@ -7,64 +7,27 @@
package dan200.computercraft.shared;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
import dan200.computercraft.api.turtle.event.TurtleActionEvent;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Objects;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID )
public final class TurtlePermissions
{
private static final Collection<ITurtlePermissionProvider> providers = new LinkedHashSet<>();
private TurtlePermissions()
public static boolean isBlockEnterable( World world, BlockPos pos, PlayerEntity player )
{
MinecraftServer server = world.getServer();
return server == null || world.isRemote || !server.isBlockProtected( world, pos, player );
}
public static void register( @Nonnull ITurtlePermissionProvider upgrade )
public static boolean isBlockEditable( World world, BlockPos pos, PlayerEntity player )
{
Objects.requireNonNull( upgrade, "upgrade cannot be null" );
providers.add( upgrade );
}
public static boolean isBlockEnterable( World world, BlockPos pos, EntityPlayer player )
{
MinecraftServer server = player.getServer();
if( server != null && !world.isRemote && server.isBlockProtected( world, pos, player ) )
{
return false;
}
for( ITurtlePermissionProvider provider : providers )
{
if( !provider.isBlockEnterable( world, pos ) ) return false;
}
return true;
}
public static boolean isBlockEditable( World world, BlockPos pos, EntityPlayer player )
{
MinecraftServer server = player.getServer();
if( server != null && !world.isRemote && server.isBlockProtected( world, pos, player ) )
{
return false;
}
for( ITurtlePermissionProvider provider : providers )
{
if( !provider.isBlockEditable( world, pos ) ) return false;
}
return true;
MinecraftServer server = world.getServer();
return server == null || world.isRemote || !server.isBlockProtected( world, pos, player );
}
@SubscribeEvent

View File

@@ -10,11 +10,9 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.util.InventoryUtil;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModLoadingContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -23,7 +21,6 @@ import java.util.*;
public final class TurtleUpgrades
{
private static final Map<String, ITurtleUpgrade> upgrades = new HashMap<>();
private static final Int2ObjectMap<ITurtleUpgrade> legacyUpgrades = new Int2ObjectOpenHashMap<>();
private static final IdentityHashMap<ITurtleUpgrade, String> upgradeOwners = new IdentityHashMap<>();
private TurtleUpgrades() {}
@@ -32,73 +29,25 @@ public final class TurtleUpgrades
{
Objects.requireNonNull( upgrade, "upgrade cannot be null" );
int id = upgrade.getLegacyUpgradeID();
if( id >= 0 && id < 64 )
{
String message = getMessage( upgrade, "Legacy UpgradeID '" + id + "' is reserved by ComputerCraft" );
ComputerCraft.log.error( message );
throw new RuntimeException( message );
}
registerInternal( upgrade );
}
static void registerInternal( ITurtleUpgrade upgrade )
{
Objects.requireNonNull( upgrade, "upgrade cannot be null" );
// Check conditions
int legacyId = upgrade.getLegacyUpgradeID();
if( legacyId >= 0 )
{
if( legacyId >= Short.MAX_VALUE )
{
String message = getMessage( upgrade, "UpgradeID '" + legacyId + "' is out of range" );
ComputerCraft.log.error( message );
throw new RuntimeException( message );
}
ITurtleUpgrade existing = legacyUpgrades.get( legacyId );
if( existing != null )
{
String message = getMessage( upgrade, "UpgradeID '" + legacyId + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" );
ComputerCraft.log.error( message );
throw new RuntimeException( message );
}
}
String id = upgrade.getUpgradeID().toString();
ITurtleUpgrade existing = upgrades.get( id );
if( existing != null )
{
String message = getMessage( upgrade, "UpgradeID '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" );
ComputerCraft.log.error( message );
throw new RuntimeException( message );
throw new IllegalStateException( "Error registering '" + upgrade.getUnlocalisedAdjective() + " Turle'. UpgradeID '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" );
}
// Register
if( legacyId >= 0 ) legacyUpgrades.put( legacyId, upgrade );
upgrades.put( id, upgrade );
ModContainer mc = Loader.instance().activeModContainer();
ModContainer mc = ModLoadingContext.get().getActiveContainer();
if( mc != null && mc.getModId() != null ) upgradeOwners.put( upgrade, mc.getModId() );
}
private static String getMessage( ITurtleUpgrade upgrade, String rest )
{
return "Error registering '" + upgrade.getUnlocalisedAdjective() + " Turtle'. " + rest;
}
public static ITurtleUpgrade get( String id )
{
return upgrades.get( id );
}
public static ITurtleUpgrade get( int id )
{
return legacyUpgrades.get( id );
}
public static ITurtleUpgrade get( @Nonnull ItemStack stack )
{
if( stack.isEmpty() ) return null;
@@ -118,15 +67,20 @@ public final class TurtleUpgrades
public static Iterable<ITurtleUpgrade> getVanillaUpgrades()
{
List<ITurtleUpgrade> vanilla = new ArrayList<>();
// ComputerCraft upgrades
vanilla.add( ComputerCraft.TurtleUpgrades.wirelessModemNormal );
vanilla.add( ComputerCraft.TurtleUpgrades.wirelessModemAdvanced );
vanilla.add( ComputerCraft.TurtleUpgrades.speaker );
// Vanilla Minecraft upgrades
vanilla.add( ComputerCraft.TurtleUpgrades.diamondPickaxe );
vanilla.add( ComputerCraft.TurtleUpgrades.diamondAxe );
vanilla.add( ComputerCraft.TurtleUpgrades.diamondSword );
vanilla.add( ComputerCraft.TurtleUpgrades.diamondShovel );
vanilla.add( ComputerCraft.TurtleUpgrades.diamondHoe );
vanilla.add( ComputerCraft.TurtleUpgrades.craftingTable );
vanilla.add( ComputerCraft.TurtleUpgrades.wirelessModem );
vanilla.add( ComputerCraft.TurtleUpgrades.advancedModem );
vanilla.add( ComputerCraft.TurtleUpgrades.speaker );
return vanilla;
}

View File

@@ -6,7 +6,9 @@
package dan200.computercraft.shared.command;
import com.google.common.collect.Sets;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.computer.Computer;
@@ -15,30 +17,42 @@ import dan200.computercraft.core.tracking.ComputerTracker;
import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.core.tracking.TrackingContext;
import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.shared.Config;
import dan200.computercraft.shared.command.framework.*;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.network.Containers;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.network.container.ViewComputerContainerData;
import net.minecraft.command.CommandSource;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.network.play.server.SPlayerPositionLookPacket;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import javax.annotation.Nonnull;
import java.util.*;
import java.util.function.Consumer;
import static dan200.computercraft.shared.command.CommandUtils.isPlayer;
import static dan200.computercraft.shared.command.Exceptions.*;
import static dan200.computercraft.shared.command.arguments.ComputerArgumentType.getComputerArgument;
import static dan200.computercraft.shared.command.arguments.ComputerArgumentType.oneComputer;
import static dan200.computercraft.shared.command.arguments.ComputersArgumentType.*;
import static dan200.computercraft.shared.command.arguments.TrackingFieldArgumentType.trackingField;
import static dan200.computercraft.shared.command.builder.CommandBuilder.args;
import static dan200.computercraft.shared.command.builder.CommandBuilder.command;
import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.choice;
import static dan200.computercraft.shared.command.text.ChatHelpers.*;
import static net.minecraft.command.Commands.literal;
public final class CommandComputerCraft extends CommandDelegate
public final class CommandComputerCraft
{
public static final UUID SYSTEM_UUID = new UUID( 0, 0 );
@@ -46,337 +60,231 @@ public final class CommandComputerCraft extends CommandDelegate
private static final int DUMP_SINGLE_ID = 1844510720;
private static final int TRACK_ID = 373882880;
public CommandComputerCraft()
private CommandComputerCraft()
{
super( create() );
}
private static ISubCommand create()
public static void register( CommandDispatcher<CommandSource> dispatcher )
{
CommandRoot root = new CommandRoot( "computercraft" );
root.register( new SubCommandBase( "dump", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
if( arguments.isEmpty() )
{
dispatcher.register( choice( "computercraft" )
.then( literal( "dump" )
.requires( UserLevel.OWNER_OP )
.executes( context -> {
TableBuilder table = new TableBuilder( DUMP_LIST_ID, "Computer", "On", "Position" );
CommandSource source = context.getSource();
List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
// Unless we're on a server, limit the number of rows we can send.
if( !(context.getSender() instanceof MinecraftServer) )
{
World world = context.getSender().getEntityWorld();
BlockPos pos = context.getSender().getPosition();
World world = source.getWorld();
BlockPos pos = new BlockPos( source.getPos() );
computers.sort( ( a, b ) -> {
if( a.getWorld() == b.getWorld() && a.getWorld() == world )
{
return Double.compare( a.getPosition().distanceSq( pos ), b.getPosition().distanceSq( pos ) );
}
else if( a.getWorld() == world )
{
return -1;
}
else if( b.getWorld() == world )
{
return 1;
}
else
{
return Integer.compare( a.getInstanceID(), b.getInstanceID() );
}
} );
}
computers.sort( ( a, b ) -> {
if( a.getWorld() == b.getWorld() && a.getWorld() == world )
{
return Double.compare( a.getPosition().distanceSq( pos ), b.getPosition().distanceSq( pos ) );
}
else if( a.getWorld() == world )
{
return -1;
}
else if( b.getWorld() == world )
{
return 1;
}
else
{
return Integer.compare( a.getInstanceID(), b.getInstanceID() );
}
} );
for( ServerComputer computer : computers )
{
table.row(
linkComputer( context, computer, computer.getID() ),
linkComputer( source, computer, computer.getID() ),
bool( computer.isOn() ),
linkPosition( context, computer )
linkPosition( source, computer )
);
}
table.display( context.getSender() );
}
else if( arguments.size() == 1 )
{
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
table.display( context.getSource() );
return computers.size();
} )
.then( args()
.arg( "computer", oneComputer() )
.executes( context -> {
ServerComputer computer = getComputerArgument( context, "computer" );
TableBuilder table = new TableBuilder( DUMP_SINGLE_ID );
table.row( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
table.row( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
table.row( header( "Label" ), text( computer.getLabel() ) );
table.row( header( "On" ), bool( computer.isOn() ) );
table.row( header( "Position" ), linkPosition( context, computer ) );
table.row( header( "Family" ), text( computer.getFamily().toString() ) );
TableBuilder table = new TableBuilder( DUMP_SINGLE_ID );
table.row( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
table.row( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
table.row( header( "Label" ), text( computer.getLabel() ) );
table.row( header( "On" ), bool( computer.isOn() ) );
table.row( header( "Position" ), linkPosition( context.getSource(), computer ) );
table.row( header( "Family" ), text( computer.getFamily().toString() ) );
for( ComputerSide side : ComputerSide.values() )
{
IPeripheral peripheral = computer.getPeripheral( side );
if( peripheral != null )
for( ComputerSide side : ComputerSide.values() )
{
table.row( header( "Peripheral " + side.getName() ), text( peripheral.getType() ) );
IPeripheral peripheral = computer.getPeripheral( side );
if( peripheral != null )
{
table.row( header( "Peripheral " + side.getName() ), text( peripheral.getType() ) );
}
}
}
table.display( context.getSender() );
}
else
{
throw new CommandException( context.getFullUsage() );
}
}
table.display( context.getSource() );
return 1;
} ) ) )
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return arguments.size() == 1
? ComputerSelector.completeComputer( arguments.get( 0 ) )
: Collections.emptyList();
}
} );
root.register( new SubCommandBase( "shutdown", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
withComputers( arguments, computers -> {
.then( command( "shutdown" )
.requires( UserLevel.OWNER_OP )
.argManyValue( "computers", manyComputers(), s -> ComputerCraft.serverComputerRegistry.getComputers() )
.executes( ( context, computers ) -> {
int shutdown = 0;
for( ServerComputer computer : computers )
for( ServerComputer computer : unwrap( context.getSource(), computers ) )
{
if( computer.isOn() ) shutdown++;
computer.shutdown();
}
context.getSender().sendMessage( translate( "commands.computercraft.shutdown.done", shutdown, computers.size() ) );
} );
}
context.getSource().sendFeedback( translate( "commands.computercraft.shutdown.done", shutdown, computers.size() ), false );
return shutdown;
} ) )
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return arguments.isEmpty()
? Collections.emptyList()
: ComputerSelector.completeComputer( arguments.get( arguments.size() - 1 ) );
}
} );
root.register( new SubCommandBase( "turn-on", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
withComputers( arguments, computers -> {
.then( command( "turn-on" )
.requires( UserLevel.OWNER_OP )
.argManyValue( "computers", manyComputers(), s -> ComputerCraft.serverComputerRegistry.getComputers() )
.executes( ( context, computers ) -> {
int on = 0;
for( ServerComputer computer : computers )
for( ServerComputer computer : unwrap( context.getSource(), computers ) )
{
if( !computer.isOn() ) on++;
computer.turnOn();
}
context.getSender().sendMessage( translate( "commands.computercraft.turn_on.done", on, computers.size() ) );
} );
}
context.getSource().sendFeedback( translate( "commands.computercraft.turn_on.done", on, computers.size() ), false );
return on;
} ) )
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return arguments.isEmpty()
? Collections.emptyList()
: ComputerSelector.completeComputer( arguments.get( arguments.size() - 1 ) );
}
} );
.then( command( "tp" )
.requires( UserLevel.OP )
.arg( "computer", oneComputer() )
.executes( context -> {
ServerComputer computer = getComputerArgument( context, "computer" );
World world = computer.getWorld();
BlockPos pos = computer.getPosition();
root.register( new SubCommandBase( "tp", UserLevel.OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
if( arguments.size() != 1 ) throw new CommandException( context.getFullUsage() );
if( world == null || pos == null ) throw TP_NOT_THERE.create();
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
World world = computer.getWorld();
BlockPos pos = computer.getPosition();
Entity entity = context.getSource().assertIsEntity();
if( !(entity instanceof ServerPlayerEntity) ) throw TP_NOT_PLAYER.create();
if( world == null || pos == null ) throw new CommandException( "commands.computercraft.tp.not_there" );
ICommandSender sender = context.getSender();
if( !(sender instanceof Entity) ) throw new CommandException( "commands.computercraft.tp.not_entity" );
if( sender instanceof EntityPlayerMP )
{
EntityPlayerMP entity = (EntityPlayerMP) sender;
if( entity.getEntityWorld() != world )
ServerPlayerEntity player = (ServerPlayerEntity) entity;
if( player.getEntityWorld() == world )
{
context.getServer().getPlayerList().changePlayerDimension( entity, world.provider.getDimension() );
player.connection.setPlayerLocation(
pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0,
EnumSet.noneOf( SPlayerPositionLookPacket.Flags.class )
);
}
else
{
player.teleport( (ServerWorld) world,
pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0
);
}
entity.setPositionAndUpdate( pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5 );
}
else
{
Entity entity = (Entity) sender;
if( entity.getEntityWorld() != world )
return 1;
} ) )
.then( command( "queue" )
.requires( UserLevel.ANYONE )
.arg( "computer", manyComputers() )
.argManyValue( "args", StringArgumentType.string(), Collections.emptyList() )
.executes( ( ctx, args ) -> {
Collection<ServerComputer> computers = getComputersArgument( ctx, "computer" );
Object[] rest = args.toArray();
int queued = 0;
for( ServerComputer computer : computers )
{
entity.changeDimension( world.provider.getDimension() );
if( computer.getFamily() == ComputerFamily.Command && computer.isOn() )
{
computer.queueEvent( "computer_command", rest );
queued++;
}
}
entity.setLocationAndAngles(
pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5,
entity.rotationYaw, entity.rotationPitch
);
}
}
return queued;
} ) )
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return arguments.size() == 1
? ComputerSelector.completeComputer( arguments.get( 0 ) )
: Collections.emptyList();
}
} );
root.register( new SubCommandBase( "view", UserLevel.OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
if( arguments.size() != 1 ) throw new CommandException( context.getFullUsage() );
ICommandSender sender = context.getSender();
if( !(sender instanceof EntityPlayerMP) )
{
throw new CommandException( "commands.computercraft.view.not_player" );
}
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
Containers.openComputerGUI( (EntityPlayerMP) sender, computer );
}
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return arguments.size() == 1
? ComputerSelector.completeComputer( arguments.get( 0 ) )
: Collections.emptyList();
}
} );
root.register( new CommandRoot( "track" ).register( new SubCommandBase( "start", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
getTimingContext( context ).start();
String stopCommand = "/" + context.parent().getFullPath() + " stop";
context.getSender().sendMessage( list(
translate( "commands.computercraft.track.start.stop",
link( text( stopCommand ), stopCommand, translate( "commands.computercraft.track.stop.action" ) ) )
) );
}
} ).register( new SubCommandBase( "stop", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
TrackingContext timings = getTimingContext( context );
if( !timings.stop() ) throw new CommandException( "commands.computercraft.track.stop.not_enabled" );
displayTimings( context, timings.getImmutableTimings(), TrackingField.AVERAGE_TIME );
}
} ).register( new SubCommandBase( "dump", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
TrackingField field = TrackingField.AVERAGE_TIME;
if( arguments.size() >= 1 )
{
field = TrackingField.fields().get( arguments.get( 0 ) );
if( field == null )
.then( command( "view" )
.requires( UserLevel.OP )
.arg( "computer", oneComputer() )
.executes( context -> {
ServerPlayerEntity player = context.getSource().asPlayer();
ServerComputer computer = getComputerArgument( context, "computer" );
new ViewComputerContainerData( computer ).open( player, new INamedContainerProvider()
{
throw new CommandException( "commands.computercraft.track.dump.no_field", arguments.get( 0 ) );
}
}
@Nonnull
@Override
public ITextComponent getDisplayName()
{
return new TranslationTextComponent( "gui.computercraft.view_computer" );
}
displayTimings( context, getTimingContext( context ).getImmutableTimings(), field );
}
@Nonnull
@Override
public Container createMenu( int id, @Nonnull PlayerInventory player, @Nonnull PlayerEntity entity )
{
return new ContainerViewComputer( id, computer );
}
} );
return 1;
} ) )
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
if( arguments.size() == 1 )
{
String match = arguments.get( 0 );
.then( choice( "track" )
.then( command( "start" )
.requires( UserLevel.OWNER_OP )
.executes( context -> {
getTimingContext( context.getSource() ).start();
List<String> out = new ArrayList<>();
for( String key : TrackingField.fields().keySet() )
{
if( CommandBase.doesStringStartWith( match, key ) ) out.add( key );
}
String stopCommand = "/computercraft track stop";
context.getSource().sendFeedback( translate( "commands.computercraft.track.start.stop",
link( text( stopCommand ), stopCommand, translate( "commands.computercraft.track.stop.action" ) ) ), false );
return 1;
} ) )
out.sort( Comparator.naturalOrder() );
return out;
}
else
{
return super.getCompletion( context, arguments );
}
}
} ) );
.then( command( "stop" )
.requires( UserLevel.OWNER_OP )
.executes( context -> {
TrackingContext timings = getTimingContext( context.getSource() );
if( !timings.stop() ) throw NOT_TRACKING_EXCEPTION.create();
displayTimings( context.getSource(), timings.getImmutableTimings(), TrackingField.AVERAGE_TIME, DEFAULT_FIELDS );
return 1;
} ) )
root.register( new SubCommandBase( "reload", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
Config.reload();
context.getSender().sendMessage( translate( "commands.computercraft.reload.done" ) );
}
} );
.then( command( "dump" )
.requires( UserLevel.OWNER_OP )
.argManyValue( "fields", trackingField(), DEFAULT_FIELDS )
.executes( ( context, fields ) -> {
TrackingField sort;
if( fields.size() == 1 && DEFAULT_FIELDS.contains( fields.get( 0 ) ) )
{
sort = fields.get( 0 );
fields = DEFAULT_FIELDS;
}
else
{
sort = fields.get( 0 );
}
root.register( new SubCommandBase( "queue", UserLevel.ANYONE )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
if( arguments.size() < 1 ) throw new CommandException( context.getFullUsage() );
String selector = arguments.get( 0 );
Object[] rest = arguments.subList( 1, arguments.size() ).toArray();
boolean found = false;
for( ServerComputer computer : ComputerSelector.getComputers( selector ) )
{
if( computer.getFamily() != ComputerFamily.Command || !computer.isOn() ) continue;
found = true;
computer.queueEvent( "computer_command", rest );
}
if( !found )
{
throw new CommandException( "commands.computercraft.argument.no_matching", selector );
}
}
} );
return root;
return displayTimings( context.getSource(), sort, fields );
} ) ) )
);
}
private static ITextComponent linkComputer( CommandContext context, ServerComputer serverComputer, int computerId )
private static ITextComponent linkComputer( CommandSource source, ServerComputer serverComputer, int computerId )
{
ITextComponent out = new TextComponentString( "" );
ITextComponent out = new StringTextComponent( "" );
// Append the computer instance
if( serverComputer == null )
@@ -396,7 +304,7 @@ public final class CommandComputerCraft extends CommandDelegate
out.appendText( " (id " + computerId + ")" );
// And, if we're a player, some useful links
if( serverComputer != null && UserLevel.OP.canExecute( context ) && context.fromPlayer() )
if( serverComputer != null && UserLevel.OP.test( source ) && isPlayer( source ) )
{
out
.appendText( " " )
@@ -416,9 +324,9 @@ public final class CommandComputerCraft extends CommandDelegate
return out;
}
private static ITextComponent linkPosition( CommandContext context, ServerComputer computer )
private static ITextComponent linkPosition( CommandSource context, ServerComputer computer )
{
if( UserLevel.OP.canExecute( context ) )
if( UserLevel.OP.test( context ) )
{
return link(
position( computer.getPosition() ),
@@ -432,22 +340,23 @@ public final class CommandComputerCraft extends CommandDelegate
}
}
private static TrackingContext getTimingContext( CommandContext context )
@Nonnull
private static TrackingContext getTimingContext( CommandSource source )
{
Entity entity = context.getSender().getCommandSenderEntity();
if( entity instanceof EntityPlayerMP )
{
return Tracking.getContext( entity.getUniqueID() );
}
else
{
return Tracking.getContext( SYSTEM_UUID );
}
Entity entity = source.getEntity();
return entity instanceof PlayerEntity ? Tracking.getContext( entity.getUniqueID() ) : Tracking.getContext( SYSTEM_UUID );
}
private static void displayTimings( CommandContext context, List<ComputerTracker> timings, TrackingField field ) throws CommandException
private static final List<TrackingField> DEFAULT_FIELDS = Arrays.asList( TrackingField.TASKS, TrackingField.TOTAL_TIME, TrackingField.AVERAGE_TIME, TrackingField.MAX_TIME );
private static int displayTimings( CommandSource source, TrackingField sortField, List<TrackingField> fields ) throws CommandSyntaxException
{
if( timings.isEmpty() ) throw new CommandException( "commands.computercraft.track.dump.no_timings" );
return displayTimings( source, getTimingContext( source ).getTimings(), sortField, fields );
}
private static int displayTimings( CommandSource source, @Nonnull List<ComputerTracker> timings, @Nonnull TrackingField sortField, @Nonnull List<TrackingField> fields ) throws CommandSyntaxException
{
if( timings.isEmpty() ) throw NO_TIMINGS_EXCEPTION.create();
Map<Computer, ServerComputer> lookup = new HashMap<>();
int maxId = 0, maxInstance = 0;
@@ -459,74 +368,27 @@ public final class CommandComputerCraft extends CommandDelegate
if( server.getID() > maxId ) maxId = server.getID();
}
timings.sort( Comparator.<ComputerTracker, Long>comparing( x -> x.get( field ) ).reversed() );
timings.sort( Comparator.<ComputerTracker, Long>comparing( x -> x.get( sortField ) ).reversed() );
boolean defaultLayout = field == TrackingField.TASKS || field == TrackingField.TOTAL_TIME
|| field == TrackingField.AVERAGE_TIME || field == TrackingField.MAX_TIME;
TableBuilder table = defaultLayout ? new TableBuilder(
TRACK_ID,
translate( "commands.computercraft.track.dump.computer" ),
translate( TrackingField.TASKS.translationKey() ),
translate( TrackingField.TOTAL_TIME.translationKey() ),
translate( TrackingField.AVERAGE_TIME.translationKey() ),
translate( TrackingField.MAX_TIME.translationKey() )
) : new TableBuilder(
TRACK_ID,
translate( "commands.computercraft.track.dump.computer" ),
translate( field.translationKey() )
);
ITextComponent[] headers = new ITextComponent[1 + fields.size()];
headers[0] = translate( "commands.computercraft.track.dump.computer" );
for( int i = 0; i < fields.size(); i++ ) headers[i + 1] = translate( fields.get( i ).translationKey() );
TableBuilder table = new TableBuilder( TRACK_ID, headers );
for( ComputerTracker entry : timings )
{
Computer computer = entry.getComputer();
ServerComputer serverComputer = computer == null ? null : lookup.get( computer );
ITextComponent computerComponent = linkComputer( context, serverComputer, entry.getComputerId() );
ITextComponent computerComponent = linkComputer( source, serverComputer, entry.getComputerId() );
if( defaultLayout )
{
table.row(
computerComponent,
text( entry.getFormatted( TrackingField.TASKS ) ),
text( entry.getFormatted( TrackingField.TOTAL_TIME ) ),
text( entry.getFormatted( TrackingField.AVERAGE_TIME ) ),
text( entry.getFormatted( TrackingField.MAX_TIME ) )
);
}
else
{
table.row( computerComponent, text( entry.getFormatted( field ) ) );
}
ITextComponent[] row = new ITextComponent[1 + fields.size()];
row[0] = computerComponent;
for( int i = 0; i < fields.size(); i++ ) row[i + 1] = text( entry.getFormatted( fields.get( i ) ) );
table.row( row );
}
table.display( context.getSender() );
}
private static void withComputers( List<String> selectors, Consumer<Collection<ServerComputer>> action ) throws CommandException
{
Set<ServerComputer> computers = Sets.newHashSet();
List<String> failed = new ArrayList<>();
if( selectors.isEmpty() )
{
computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() );
}
else
{
for( String selector : selectors )
{
List<ServerComputer> selected = ComputerSelector.getComputers( selector );
computers.addAll( selected );
if( selected.isEmpty() ) failed.add( selector );
}
}
action.accept( computers );
if( !failed.isEmpty() )
{
throw new CommandException( "commands.computercraft.argument.no_matching", String.join( ", ", failed ) );
}
table.display( source );
return timings.size();
}
}

View File

@@ -6,74 +6,62 @@
package dan200.computercraft.shared.command;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.server.MinecraftServer;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import dan200.computercraft.ComputerCraft;
import net.minecraft.client.Minecraft;
import net.minecraft.command.CommandSource;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.util.text.event.ClickEvent;
import net.minecraft.util.text.event.HoverEvent;
import net.minecraftforge.client.IClientCommand;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ClientChatEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import javax.annotation.Nonnull;
import static net.minecraft.command.Commands.argument;
import static net.minecraft.command.Commands.literal;
public final class CommandCopy extends CommandBase implements IClientCommand
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class CommandCopy
{
public static final CommandCopy INSTANCE = new CommandCopy();
/**
* We start with a "~" so we're less likely to show up on completions.
*/
private static final String NAME = "~computercraft_copy";
private static final String PREFIX = "/computercraft copy ";
private CommandCopy()
{
}
@Override
public boolean allowUsageWithoutPrefix( ICommandSender sender, String message )
public static void register( CommandDispatcher<CommandSource> registry )
{
return false;
registry.register( literal( "computercraft" )
.then( literal( "copy" ) )
.then( argument( "message", StringArgumentType.greedyString() ) )
.executes( context -> {
Minecraft.getInstance().keyboardListener.setClipboardString( context.getArgument( "message", String.class ) );
return 1;
} )
);
}
@Nonnull
@Override
public String getName()
@SubscribeEvent
public static void onClientSendMessage( ClientChatEvent event )
{
return NAME;
}
@Nonnull
@Override
public String getUsage( @Nonnull ICommandSender sender )
{
return "/" + NAME + " <text>";
}
@Override
public int getRequiredPermissionLevel()
{
return 0;
}
@Override
@SideOnly( Side.CLIENT )
public void execute( @Nonnull MinecraftServer server, @Nonnull ICommandSender sender, @Nonnull String[] args )
{
String message = String.join( " ", args );
if( !message.isEmpty() ) GuiScreen.setClipboardString( message );
// Emulate the command on the client side
if( event.getMessage().startsWith( PREFIX ) )
{
Minecraft.getInstance().keyboardListener.setClipboardString( event.getMessage().substring( PREFIX.length() ) );
event.setCanceled( true );
}
}
public static ITextComponent createCopyText( String text )
{
TextComponentString name = new TextComponentString( text );
StringTextComponent name = new StringTextComponent( text );
name.getStyle()
.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/" + NAME + " " + text ) )
.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TextComponentTranslation( "gui.computercraft.tooltip.copy" ) ) );
.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, PREFIX + text ) )
.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) );
return name;
}
}

View File

@@ -6,18 +6,65 @@
package dan200.computercraft.shared.command;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.command.CommandSource;
import net.minecraft.command.ISuggestionProvider;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraftforge.common.util.FakePlayer;
import java.util.Arrays;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
public final class CommandUtils
{
private CommandUtils() {}
public static boolean isPlayer( ICommandSender sender )
public static boolean isPlayer( CommandSource output )
{
return sender instanceof EntityPlayerMP
Entity sender = output.getEntity();
return sender instanceof ServerPlayerEntity
&& !(sender instanceof FakePlayer)
&& ((EntityPlayerMP) sender).connection != null;
&& ((ServerPlayerEntity) sender).connection != null;
}
@SuppressWarnings( "unchecked" )
public static CompletableFuture<Suggestions> suggestOnServer( CommandContext<?> context, SuggestionsBuilder builder, Function<CommandContext<CommandSource>, CompletableFuture<Suggestions>> supplier )
{
Object source = context.getSource();
if( !(source instanceof ISuggestionProvider) )
{
return Suggestions.empty();
}
else if( source instanceof CommandSource )
{
return supplier.apply( (CommandContext<CommandSource>) context );
}
else
{
return ((ISuggestionProvider) source).getSuggestionsFromServer( (CommandContext<ISuggestionProvider>) context, builder );
}
}
public static <T> CompletableFuture<Suggestions> suggest( SuggestionsBuilder builder, Iterable<T> candidates, Function<T, String> toString )
{
String remaining = builder.getRemaining().toLowerCase( Locale.ROOT );
for( T choice : candidates )
{
String name = toString.apply( choice );
if( !name.toLowerCase( Locale.ROOT ).startsWith( remaining ) ) continue;
builder.suggest( name );
}
return builder.buildFuture();
}
public static <T> CompletableFuture<Suggestions> suggest( SuggestionsBuilder builder, T[] candidates, Function<T, String> toString )
{
return suggest( builder, Arrays.asList( candidates ), toString );
}
}

View File

@@ -1,163 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import net.minecraft.command.CommandException;
import java.util.*;
import java.util.function.Predicate;
final class ComputerSelector
{
private ComputerSelector() {}
private static List<ServerComputer> getComputers( Predicate<ServerComputer> predicate )
{
// We copy it to prevent concurrent modifications.
ArrayList<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
computers.removeIf( predicate.negate() );
return computers;
}
static ServerComputer getComputer( String selector ) throws CommandException
{
List<ServerComputer> computers = getComputers( selector );
if( computers.isEmpty() )
{
throw new CommandException( "commands.computercraft.argument.no_matching", selector );
}
else if( computers.size() == 1 )
{
return computers.get( 0 );
}
else
{
StringBuilder builder = new StringBuilder();
for( int i = 0; i < computers.size(); i++ )
{
if( i > 0 ) builder.append( ", " );
builder.append( computers.get( i ).getInstanceID() );
}
throw new CommandException( "commands.computercraft.argument.many_matching", selector, builder.toString() );
}
}
static List<ServerComputer> getComputers( String selector ) throws CommandException
{
if( !selector.isEmpty() && selector.charAt( 0 ) == '#' )
{
selector = selector.substring( 1 );
int id;
try
{
id = Integer.parseInt( selector );
}
catch( NumberFormatException e )
{
throw new CommandException( "commands.computercraft.argument.not_number", selector );
}
return getComputers( x -> x.getID() == id );
}
else if( !selector.isEmpty() && selector.charAt( 0 ) == '@' )
{
String label = selector.substring( 1 );
return getComputers( x -> Objects.equals( label, x.getLabel() ) );
}
else if( !selector.isEmpty() && selector.charAt( 0 ) == '~' )
{
String familyName = selector.substring( 1 );
return getComputers( x -> x.getFamily().name().equalsIgnoreCase( familyName ) );
}
else
{
int instance;
try
{
instance = Integer.parseInt( selector );
}
catch( NumberFormatException e )
{
throw new CommandException( "commands.computercraft.argument.not_number", selector );
}
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance );
return computer == null ? Collections.emptyList() : Collections.singletonList( computer );
}
}
static List<String> completeComputer( String selector )
{
TreeSet<String> options = Sets.newTreeSet();
// We copy it to prevent concurrent modifications.
List<ServerComputer> computers = Lists.newArrayList( ComputerCraft.serverComputerRegistry.getComputers() );
if( !selector.isEmpty() && selector.charAt( 0 ) == '#' )
{
selector = selector.substring( 1 );
for( ServerComputer computer : computers )
{
String id = Integer.toString( computer.getID() );
if( id.startsWith( selector ) ) options.add( "#" + id );
}
}
else if( !selector.isEmpty() && selector.charAt( 0 ) == '@' )
{
String label = selector.substring( 1 );
for( ServerComputer computer : computers )
{
String thisLabel = computer.getLabel();
if( thisLabel != null && thisLabel.startsWith( label ) ) options.add( "@" + thisLabel );
}
}
else if( !selector.isEmpty() && selector.charAt( 0 ) == '~' )
{
String familyName = selector.substring( 1 ).toLowerCase( Locale.ENGLISH );
for( ComputerFamily family : ComputerFamily.values() )
{
if( family.name().toLowerCase( Locale.ENGLISH ).startsWith( familyName ) )
{
options.add( "~" + family.name() );
}
}
}
else
{
for( ServerComputer computer : computers )
{
String id = Integer.toString( computer.getInstanceID() );
if( id.startsWith( selector ) ) options.add( id );
}
}
if( options.size() > 100 )
{
ArrayList<String> result = Lists.newArrayListWithCapacity( 100 );
for( String element : options )
{
if( result.size() > 100 ) break;
result.add( element );
}
return result;
}
else
{
return Lists.newArrayList( options );
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command;
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import net.minecraft.util.text.TranslationTextComponent;
public final class Exceptions
{
public static final DynamicCommandExceptionType COMPUTER_ARG_NONE = translated1( "argument.computercraft.computer.no_matching" );
public static final Dynamic2CommandExceptionType COMPUTER_ARG_MANY = translated2( "argument.computercraft.computer.many_matching" );
public static final DynamicCommandExceptionType TRACKING_FIELD_ARG_NONE = translated1( "argument.computercraft.tracking_field.no_field" );
static final SimpleCommandExceptionType NOT_TRACKING_EXCEPTION = translated( "commands.computercraft.track.stop.not_enabled" );
static final SimpleCommandExceptionType NO_TIMINGS_EXCEPTION = translated( "commands.computercraft.track.dump.no_timings" );
static final SimpleCommandExceptionType TP_NOT_THERE = translated( "commands.computercraft.tp.not_there" );
static final SimpleCommandExceptionType TP_NOT_PLAYER = translated( "commands.computercraft.tp.not_player" );
public static final SimpleCommandExceptionType ARGUMENT_EXPECTED = translated( "argument.computercraft.argument_expected" );
private static SimpleCommandExceptionType translated( String key )
{
return new SimpleCommandExceptionType( new TranslationTextComponent( key ) );
}
private static DynamicCommandExceptionType translated1( String key )
{
return new DynamicCommandExceptionType( x -> new TranslationTextComponent( key, x ) );
}
private static Dynamic2CommandExceptionType translated2( String key )
{
return new Dynamic2CommandExceptionType( ( x, y ) -> new TranslationTextComponent( key, x, y ) );
}
}

View File

@@ -6,15 +6,17 @@
package dan200.computercraft.shared.command;
import dan200.computercraft.shared.command.framework.CommandContext;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.command.CommandSource;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer;
import java.util.function.Predicate;
/**
* The level a user must be at in order to execute a command.
*/
public enum UserLevel
public enum UserLevel implements Predicate<CommandSource>
{
/**
* Only can be used by the owner of the server: namely the server console or the player in SSP.
@@ -51,20 +53,21 @@ public enum UserLevel
}
}
public boolean canExecute( CommandContext context )
@Override
public boolean test( CommandSource source )
{
if( this == ANYONE ) return true;
// We *always* allow level 0 stuff, even if the
MinecraftServer server = context.getServer();
ICommandSender sender = context.getSender();
MinecraftServer server = source.getServer();
Entity sender = source.getEntity();
if( server.isSinglePlayer() && sender instanceof EntityPlayerMP &&
((EntityPlayerMP) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerOwner() ) )
if( server.isSinglePlayer() && sender instanceof PlayerEntity &&
((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) )
{
if( this == OWNER || this == OWNER_OP ) return true;
}
return sender.canUseCommand( toLevel(), context.getRootCommand() );
return source.hasPermissionLevel( toLevel() );
}
}

View File

@@ -0,0 +1,41 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.arguments;
import com.mojang.brigadier.arguments.ArgumentType;
import dan200.computercraft.ComputerCraft;
import net.minecraft.command.arguments.ArgumentSerializer;
import net.minecraft.command.arguments.ArgumentTypes;
import net.minecraft.command.arguments.IArgumentSerializer;
import net.minecraft.util.ResourceLocation;
public final class ArgumentSerializers
{
@SuppressWarnings( "unchecked" )
private static <T extends ArgumentType<?>> void registerUnsafe( ResourceLocation id, Class<T> type, IArgumentSerializer<?> serializer )
{
ArgumentTypes.register( id.toString(), type, (IArgumentSerializer<T>) serializer );
}
private static <T extends ArgumentType<?>> void register( ResourceLocation id, Class<T> type, IArgumentSerializer<T> serializer )
{
ArgumentTypes.register( id.toString(), type, serializer );
}
private static <T extends ArgumentType<?>> void register( ResourceLocation id, T instance )
{
registerUnsafe( id, instance.getClass(), new ArgumentSerializer<>( () -> instance ) );
}
public static void register()
{
register( new ResourceLocation( ComputerCraft.MOD_ID, "tracking_field" ), TrackingFieldArgumentType.trackingField() );
register( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ), ComputerArgumentType.oneComputer() );
register( new ResourceLocation( ComputerCraft.MOD_ID, "computers" ), ComputersArgumentType.class, new ComputersArgumentType.Serializer() );
registerUnsafe( new ResourceLocation( ComputerCraft.MOD_ID, "repeat" ), RepeatArgumentType.class, new RepeatArgumentType.Serializer() );
}
}

View File

@@ -0,0 +1,75 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.arguments;
import com.mojang.brigadier.Message;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
public abstract class ChoiceArgumentType<T> implements ArgumentType<T>
{
private final Iterable<T> choices;
private final Function<T, String> name;
private final Function<T, Message> tooltip;
private final DynamicCommandExceptionType exception;
protected ChoiceArgumentType( Iterable<T> choices, Function<T, String> name, Function<T, Message> tooltip, DynamicCommandExceptionType exception )
{
this.choices = choices;
this.name = name;
this.tooltip = tooltip;
this.exception = exception;
}
@Override
public T parse( StringReader reader ) throws CommandSyntaxException
{
int start = reader.getCursor();
String name = reader.readUnquotedString();
for( T choice : choices )
{
String choiceName = this.name.apply( choice );
if( name.equals( choiceName ) ) return choice;
}
reader.setCursor( start );
throw exception.createWithContext( reader, name );
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions( CommandContext<S> context, SuggestionsBuilder builder )
{
String remaining = builder.getRemaining().toLowerCase( Locale.ROOT );
for( T choice : choices )
{
String name = this.name.apply( choice );
if( !name.toLowerCase( Locale.ROOT ).startsWith( remaining ) ) continue;
builder.suggest( name, tooltip.apply( choice ) );
}
return builder.buildFuture();
}
@Override
public Collection<String> getExamples()
{
List<String> items = choices instanceof Collection<?> ? new ArrayList<>( ((Collection<T>) choices).size() ) : new ArrayList<>();
for( T choice : choices ) items.add( name.apply( choice ) );
items.sort( Comparator.naturalOrder() );
return items;
}
}

View File

@@ -0,0 +1,94 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.arguments;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import dan200.computercraft.shared.command.arguments.ComputersArgumentType.ComputersSupplier;
import dan200.computercraft.shared.computer.core.ServerComputer;
import net.minecraft.command.CommandSource;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import static dan200.computercraft.shared.command.Exceptions.COMPUTER_ARG_MANY;
public final class ComputerArgumentType implements ArgumentType<ComputerArgumentType.ComputerSupplier>
{
private static final ComputerArgumentType INSTANCE = new ComputerArgumentType();
public static ComputerArgumentType oneComputer()
{
return INSTANCE;
}
public static ServerComputer getComputerArgument( CommandContext<CommandSource> context, String name ) throws CommandSyntaxException
{
return context.getArgument( name, ComputerSupplier.class ).unwrap( context.getSource() );
}
private ComputerArgumentType()
{
}
@Override
public ComputerSupplier parse( StringReader reader ) throws CommandSyntaxException
{
int start = reader.getCursor();
ComputersSupplier supplier = ComputersArgumentType.someComputers().parse( reader );
String selector = reader.getString().substring( start, reader.getCursor() );
return s -> {
Collection<ServerComputer> computers = supplier.unwrap( s );
if( computers.size() == 1 ) return computers.iterator().next();
StringBuilder builder = new StringBuilder();
boolean first = true;
for( ServerComputer computer : computers )
{
if( first )
{
first = false;
}
else
{
builder.append( ", " );
}
builder.append( computer.getInstanceID() );
}
// We have an incorrect number of computers: reset and throw an error
reader.setCursor( start );
throw COMPUTER_ARG_MANY.createWithContext( reader, selector, builder.toString() );
};
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions( CommandContext<S> context, SuggestionsBuilder builder )
{
return ComputersArgumentType.someComputers().listSuggestions( context, builder );
}
@Override
public Collection<String> getExamples()
{
return ComputersArgumentType.someComputers().getExamples();
}
@FunctionalInterface
public interface ComputerSupplier
{
ServerComputer unwrap( CommandSource source ) throws CommandSyntaxException;
}
}

View File

@@ -0,0 +1,210 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.arguments;
import com.google.gson.JsonObject;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import net.minecraft.command.CommandSource;
import net.minecraft.command.arguments.IArgumentSerializer;
import net.minecraft.network.PacketBuffer;
import javax.annotation.Nonnull;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static dan200.computercraft.shared.command.CommandUtils.suggest;
import static dan200.computercraft.shared.command.CommandUtils.suggestOnServer;
import static dan200.computercraft.shared.command.Exceptions.COMPUTER_ARG_NONE;
public final class ComputersArgumentType implements ArgumentType<ComputersArgumentType.ComputersSupplier>
{
private static final ComputersArgumentType MANY = new ComputersArgumentType( false );
private static final ComputersArgumentType SOME = new ComputersArgumentType( true );
private static final List<String> EXAMPLES = Arrays.asList(
"0", "#0", "@Label", "~Advanced"
);
public static ComputersArgumentType manyComputers()
{
return MANY;
}
public static ComputersArgumentType someComputers()
{
return SOME;
}
public static Collection<ServerComputer> getComputersArgument( CommandContext<CommandSource> context, String name ) throws CommandSyntaxException
{
return context.getArgument( name, ComputersSupplier.class ).unwrap( context.getSource() );
}
private final boolean requireSome;
private ComputersArgumentType( boolean requireSome )
{
this.requireSome = requireSome;
}
@Override
public ComputersSupplier parse( StringReader reader ) throws CommandSyntaxException
{
int start = reader.getCursor();
char kind = reader.peek();
ComputersSupplier computers;
if( kind == '@' )
{
reader.skip();
String label = reader.readUnquotedString();
computers = getComputers( x -> Objects.equals( label, x.getLabel() ) );
}
else if( kind == '~' )
{
reader.skip();
String family = reader.readUnquotedString();
computers = getComputers( x -> x.getFamily().name().equalsIgnoreCase( family ) );
}
else if( kind == '#' )
{
reader.skip();
int id = reader.readInt();
computers = getComputers( x -> x.getID() == id );
}
else
{
int instance = reader.readInt();
computers = s -> {
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance );
return computer == null ? Collections.emptyList() : Collections.singletonList( computer );
};
}
if( requireSome )
{
String selector = reader.getString().substring( start, reader.getCursor() );
return source -> {
Collection<ServerComputer> matched = computers.unwrap( source );
if( matched.isEmpty() ) throw COMPUTER_ARG_NONE.create( selector );
return matched;
};
}
else
{
return computers;
}
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions( CommandContext<S> context, SuggestionsBuilder builder )
{
String remaining = builder.getRemaining();
// We can run this one on the client, for obvious reasons.
if( remaining.startsWith( "~" ) )
{
return suggest( builder, ComputerFamily.values(), x -> "~" + x.name() );
}
// Verify we've a command source and we're running on the server
return suggestOnServer( context, builder, s -> {
if( remaining.startsWith( "@" ) )
{
suggestComputers( builder, remaining, x -> {
String label = x.getLabel();
return label == null ? null : "@" + label;
} );
}
else if( remaining.startsWith( "#" ) )
{
suggestComputers( builder, remaining, c -> "#" + c.getID() );
}
else
{
suggestComputers( builder, remaining, c -> Integer.toString( c.getInstanceID() ) );
}
return builder.buildFuture();
} );
}
@Override
public Collection<String> getExamples()
{
return EXAMPLES;
}
private static void suggestComputers( SuggestionsBuilder builder, String remaining, Function<ServerComputer, String> renderer )
{
remaining = remaining.toLowerCase( Locale.ROOT );
for( ServerComputer computer : ComputerCraft.serverComputerRegistry.getComputers() )
{
String converted = renderer.apply( computer );
if( converted != null && converted.toLowerCase( Locale.ROOT ).startsWith( remaining ) )
{
builder.suggest( converted );
}
}
}
private static ComputersSupplier getComputers( Predicate<ServerComputer> predicate )
{
return s -> Collections.unmodifiableList( ComputerCraft.serverComputerRegistry
.getComputers()
.stream()
.filter( predicate )
.collect( Collectors.toList() )
);
}
public static class Serializer implements IArgumentSerializer<ComputersArgumentType>
{
@Override
public void write( @Nonnull ComputersArgumentType arg, @Nonnull PacketBuffer buf )
{
buf.writeBoolean( arg.requireSome );
}
@Nonnull
@Override
public ComputersArgumentType read( @Nonnull PacketBuffer buf )
{
return buf.readBoolean() ? SOME : MANY;
}
@Override
public void write( @Nonnull ComputersArgumentType arg, @Nonnull JsonObject json )
{
json.addProperty( "requireSome", arg.requireSome );
}
}
@FunctionalInterface
public interface ComputersSupplier
{
Collection<ServerComputer> unwrap( CommandSource source ) throws CommandSyntaxException;
}
public static Set<ServerComputer> unwrap( CommandSource source, Collection<ComputersSupplier> suppliers ) throws CommandSyntaxException
{
Set<ServerComputer> computers = new HashSet<>();
for( ComputersSupplier supplier : suppliers ) computers.addAll( supplier.unwrap( source ) );
return computers;
}
}

View File

@@ -0,0 +1,166 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.arguments;
import com.google.gson.JsonObject;
import com.mojang.brigadier.Message;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.command.arguments.ArgumentTypes;
import net.minecraft.command.arguments.IArgumentSerializer;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
/**
* Reads one argument multiple times.
*
* Note that this must be the last element in an argument chain: in order to improve the quality of error messages,
* we will always try to consume another argument while there is input remaining.
*
* One problem with how parsers function, is that they must consume some input: and thus we
*
* @param <T> The type of each value returned
* @param <U> The type of the inner parser. This will normally be a {@link List} or {@code T}.
*/
public final class RepeatArgumentType<T, U> implements ArgumentType<List<T>>
{
private final ArgumentType<U> child;
private final BiConsumer<List<T>, U> appender;
private final boolean flatten;
private final SimpleCommandExceptionType some;
private RepeatArgumentType( ArgumentType<U> child, BiConsumer<List<T>, U> appender, boolean flatten, SimpleCommandExceptionType some )
{
this.child = child;
this.appender = appender;
this.flatten = flatten;
this.some = some;
}
public static <T> RepeatArgumentType<T, T> some( ArgumentType<T> appender, SimpleCommandExceptionType missing )
{
return new RepeatArgumentType<>( appender, List::add, true, missing );
}
public static <T> RepeatArgumentType<T, List<T>> someFlat( ArgumentType<List<T>> appender, SimpleCommandExceptionType missing )
{
return new RepeatArgumentType<>( appender, List::addAll, true, missing );
}
@Override
public List<T> parse( StringReader reader ) throws CommandSyntaxException
{
boolean hadSome = false;
List<T> out = new ArrayList<>();
while( true )
{
reader.skipWhitespace();
if( !reader.canRead() ) break;
int startParse = reader.getCursor();
appender.accept( out, child.parse( reader ) );
hadSome = true;
if( reader.getCursor() == startParse )
{
throw new IllegalStateException( child + " did not consume any input on " + reader.getRemaining() );
}
}
// Note that each child may return an empty list, we just require that some actual input
// was consumed.
// We should probably review that this is sensible in the future.
if( !hadSome ) throw some.createWithContext( reader );
return Collections.unmodifiableList( out );
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions( CommandContext<S> context, SuggestionsBuilder builder )
{
StringReader reader = new StringReader( builder.getInput() );
reader.setCursor( builder.getStart() );
int previous = reader.getCursor();
while( reader.canRead() )
{
try
{
child.parse( reader );
}
catch( CommandSyntaxException e )
{
break;
}
int cursor = reader.getCursor();
reader.skipWhitespace();
if( cursor == reader.getCursor() ) break;
previous = reader.getCursor();
}
reader.setCursor( previous );
return child.listSuggestions( context, builder.createOffset( previous ) );
}
@Override
public Collection<String> getExamples()
{
return child.getExamples();
}
public static class Serializer implements IArgumentSerializer<RepeatArgumentType<?, ?>>
{
@Override
public void write( @Nonnull RepeatArgumentType<?, ?> arg, @Nonnull PacketBuffer buf )
{
buf.writeBoolean( arg.flatten );
ArgumentTypes.serialize( buf, arg.child );
buf.writeTextComponent( getMessage( arg ) );
}
@Nonnull
@Override
@SuppressWarnings( { "unchecked", "rawtypes" } )
public RepeatArgumentType<?, ?> read( @Nonnull PacketBuffer buf )
{
boolean isList = buf.readBoolean();
ArgumentType<?> child = ArgumentTypes.deserialize( buf );
ITextComponent message = buf.readTextComponent();
BiConsumer<List<Object>, ?> appender = isList ? ( list, x ) -> list.addAll( (Collection) x ) : List::add;
return new RepeatArgumentType( child, appender, isList, new SimpleCommandExceptionType( message ) );
}
@Override
public void write( @Nonnull RepeatArgumentType<?, ?> arg, @Nonnull JsonObject json )
{
json.addProperty( "flatten", arg.flatten );
json.addProperty( "child", "<<cannot serialize>>" ); // TODO: Potentially serialize this using reflection.
json.addProperty( "error", ITextComponent.Serializer.toJson( getMessage( arg ) ) );
}
private static ITextComponent getMessage( RepeatArgumentType<?, ?> arg )
{
Message message = arg.some.create().getRawMessage();
if( message instanceof ITextComponent ) return (ITextComponent) message;
return new StringTextComponent( message.getString() );
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.arguments;
import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.shared.command.Exceptions;
import static dan200.computercraft.shared.command.text.ChatHelpers.translate;
public final class TrackingFieldArgumentType extends ChoiceArgumentType<TrackingField>
{
private static final TrackingFieldArgumentType INSTANCE = new TrackingFieldArgumentType();
private TrackingFieldArgumentType()
{
super( TrackingField.fields().values(), TrackingField::id, x -> translate( x.translationKey() ), Exceptions.TRACKING_FIELD_ARG_NONE );
}
public static TrackingFieldArgumentType trackingField()
{
return INSTANCE;
}
}

View File

@@ -0,0 +1,20 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.builder;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
/**
* A {@link Command} which accepts an argument
*/
@FunctionalInterface
public interface ArgCommand<S, T>
{
int run( CommandContext<S> ctx, T arg ) throws CommandSyntaxException;
}

View File

@@ -0,0 +1,126 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.builder;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.tree.CommandNode;
import dan200.computercraft.shared.command.arguments.RepeatArgumentType;
import net.minecraft.command.CommandSource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.function.Supplier;
import static dan200.computercraft.shared.command.Exceptions.ARGUMENT_EXPECTED;
import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.literal;
/**
* An alternative way of building command nodes, so one does not have to nest
* {@link ArgumentBuilder#then(CommandNode)}s.
*/
public class CommandBuilder<S> implements CommandNodeBuilder<S, Command<S>>
{
private List<ArgumentBuilder<S, ?>> args = new ArrayList<>();
private Predicate<S> requires;
public static CommandBuilder<CommandSource> args()
{
return new CommandBuilder<>();
}
public static CommandBuilder<CommandSource> command( String literal )
{
CommandBuilder<CommandSource> builder = new CommandBuilder<>();
builder.args.add( literal( literal ) );
return builder;
}
public CommandBuilder<S> requires( Predicate<S> predicate )
{
requires = requires == null ? predicate : requires.and( predicate );
return this;
}
public CommandBuilder<S> arg( String name, ArgumentType<?> type )
{
args.add( RequiredArgumentBuilder.argument( name, type ) );
return this;
}
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyValue( String name, ArgumentType<T> type, List<T> empty )
{
return argMany( name, type, () -> empty );
}
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyValue( String name, ArgumentType<T> type, T defaultValue )
{
return argManyValue( name, type, Collections.singletonList( defaultValue ) );
}
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argMany( String name, ArgumentType<T> type, Supplier<List<T>> empty )
{
return argMany( name, RepeatArgumentType.some( type, ARGUMENT_EXPECTED ), empty );
}
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyFlatten( String name, ArgumentType<List<T>> type, Supplier<List<T>> empty )
{
return argMany( name, RepeatArgumentType.someFlat( type, ARGUMENT_EXPECTED ), empty );
}
private <T, U> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argMany( String name, RepeatArgumentType<T, ?> type, Supplier<List<T>> empty )
{
if( args.isEmpty() ) throw new IllegalStateException( "Cannot have empty arg chain builder" );
return command -> {
// The node for no arguments
ArgumentBuilder<S, ?> tail = tail( ctx -> command.run( ctx, empty.get() ) );
// The node for one or more arguments
ArgumentBuilder<S, ?> moreArg = RequiredArgumentBuilder
.<S, List<T>>argument( name, type )
.executes( ctx -> command.run( ctx, getList( ctx, name ) ) );
// Chain all of them together!
tail.then( moreArg );
return link( tail );
};
}
@SuppressWarnings( "unchecked" )
private static <T> List<T> getList( CommandContext<?> context, String name )
{
return (List<T>) context.getArgument( name, List.class );
}
@Override
public CommandNode<S> executes( Command<S> command )
{
if( args.isEmpty() ) throw new IllegalStateException( "Cannot have empty arg chain builder" );
return link( tail( command ) );
}
private ArgumentBuilder<S, ?> tail( Command<S> command )
{
ArgumentBuilder<S, ?> defaultTail = args.get( args.size() - 1 );
defaultTail.executes( command );
if( requires != null ) defaultTail.requires( requires );
return defaultTail;
}
private CommandNode<S> link( ArgumentBuilder<S, ?> tail )
{
for( int i = args.size() - 2; i >= 0; i-- ) tail = args.get( i ).then( tail );
return tail.build();
}
}

View File

@@ -0,0 +1,24 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.builder;
import com.mojang.brigadier.tree.CommandNode;
/**
* A builder which generates a {@link CommandNode} from the provided action.
*/
@FunctionalInterface
public interface CommandNodeBuilder<S, T>
{
/**
* Generate a command node which executes this command.
*
* @param command The command to run
* @return The constructed node.
*/
CommandNode<S> executes( T command );
}

View File

@@ -0,0 +1,205 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.builder;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import net.minecraft.command.CommandSource;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.event.ClickEvent;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import static dan200.computercraft.shared.command.text.ChatHelpers.coloured;
import static dan200.computercraft.shared.command.text.ChatHelpers.translate;
/**
* An alternative to {@link LiteralArgumentBuilder} which also provides a {@code /... help} command, and defaults
* to that command when no arguments are given.
*/
public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<CommandSource>
{
private final Collection<HelpingArgumentBuilder> children = new ArrayList<>();
private HelpingArgumentBuilder( String literal )
{
super( literal );
}
public static HelpingArgumentBuilder choice( String literal )
{
return new HelpingArgumentBuilder( literal );
}
@Override
public LiteralArgumentBuilder<CommandSource> executes( final Command<CommandSource> command )
{
throw new IllegalStateException( "Cannot use executes on a HelpingArgumentBuilder" );
}
@Override
public LiteralArgumentBuilder<CommandSource> then( final ArgumentBuilder<CommandSource, ?> argument )
{
if( getRedirect() != null ) throw new IllegalStateException( "Cannot add children to a redirected node" );
if( argument instanceof HelpingArgumentBuilder )
{
children.add( (HelpingArgumentBuilder) argument );
}
else if( argument instanceof LiteralArgumentBuilder )
{
super.then( argument );
}
else
{
throw new IllegalStateException( "HelpingArgumentBuilder can only accept literal children" );
}
return this;
}
@Override
public LiteralArgumentBuilder<CommandSource> then( CommandNode<CommandSource> argument )
{
if( !(argument instanceof LiteralCommandNode) )
{
throw new IllegalStateException( "HelpingArgumentBuilder can only accept literal children" );
}
return super.then( argument );
}
@Override
public LiteralCommandNode<CommandSource> build()
{
return buildImpl( getLiteral().replace( '-', '_' ), getLiteral() );
}
private LiteralCommandNode<CommandSource> build( @Nonnull String id, @Nonnull String command )
{
return buildImpl( id + "." + getLiteral().replace( '-', '_' ), command + " " + getLiteral() );
}
private LiteralCommandNode<CommandSource> buildImpl( String id, String command )
{
HelpCommand helpCommand = new HelpCommand( id, command );
LiteralCommandNode<CommandSource> node = new LiteralCommandNode<>( getLiteral(), helpCommand, getRequirement(), getRedirect(), getRedirectModifier(), isFork() );
helpCommand.node = node;
// Set up a /... help command
LiteralArgumentBuilder<CommandSource> helpNode = LiteralArgumentBuilder.<CommandSource>literal( "help" )
.requires( x -> getArguments().stream().anyMatch( y -> y.getRequirement().test( x ) ) )
.executes( helpCommand );
// Add all normal command children to this and the help node
for( CommandNode<CommandSource> child : getArguments() )
{
node.addChild( child );
helpNode.then( LiteralArgumentBuilder.<CommandSource>literal( child.getName() )
.requires( child.getRequirement() )
.executes( helpForChild( child, id, command ) )
.build()
);
}
// And add alternative versions of which forward instead
for( HelpingArgumentBuilder childBuilder : children )
{
LiteralCommandNode<CommandSource> child = childBuilder.build( id, command );
node.addChild( child );
helpNode.then( LiteralArgumentBuilder.<CommandSource>literal( child.getName() )
.requires( child.getRequirement() )
.executes( helpForChild( child, id, command ) )
.redirect( child.getChild( "help" ) )
.build()
);
}
node.addChild( helpNode.build() );
return node;
}
private static final TextFormatting HEADER = TextFormatting.LIGHT_PURPLE;
private static final TextFormatting SYNOPSIS = TextFormatting.AQUA;
private static final TextFormatting NAME = TextFormatting.GREEN;
private static final class HelpCommand implements Command<CommandSource>
{
private final String id;
private final String command;
LiteralCommandNode<CommandSource> node;
private HelpCommand( String id, String command )
{
this.id = id;
this.command = command;
}
@Override
public int run( CommandContext<CommandSource> context )
{
context.getSource().sendFeedback( getHelp( context, node, id, command ), false );
return 0;
}
}
private static Command<CommandSource> helpForChild( CommandNode<CommandSource> node, String id, String command )
{
return context -> {
context.getSource().sendFeedback( getHelp( context, node, id + "." + node.getName().replace( '-', '_' ), command + " " + node.getName() ), false );
return 0;
};
}
private static ITextComponent getHelp( CommandContext<CommandSource> context, CommandNode<CommandSource> node, String id, String command )
{
// An ugly hack to extract usage information from the dispatcher. We generate a temporary node, generate
// the shorthand usage, and emit that.
CommandDispatcher<CommandSource> dispatcher = context.getSource().getServer().getCommandManager().getDispatcher();
CommandNode<CommandSource> temp = new LiteralCommandNode<>( "_", null, x -> true, null, null, false );
temp.addChild( node );
String usage = dispatcher.getSmartUsage( temp, context.getSource() ).get( node ).substring( node.getName().length() );
ITextComponent output = new StringTextComponent( "" )
.appendSibling( coloured( "/" + command + usage, HEADER ) )
.appendText( " " )
.appendSibling( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) )
.appendText( "\n" )
.appendSibling( translate( "commands." + id + ".desc" ) );
for( CommandNode<CommandSource> child : node.getChildren() )
{
if( !child.getRequirement().test( context.getSource() ) || !(child instanceof LiteralCommandNode) )
{
continue;
}
output.appendText( "\n" );
ITextComponent component = coloured( child.getName(), NAME );
component.getStyle().setClickEvent( new ClickEvent(
ClickEvent.Action.SUGGEST_COMMAND,
"/" + command + " " + child.getName()
) );
output.appendSibling( component );
output.appendText( " - " ).appendSibling( translate( "commands." + id + "." + child.getName() + ".synopsis" ) );
}
return output;
}
}

View File

@@ -1,107 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.framework;
import com.google.common.collect.Lists;
import dan200.computercraft.shared.util.StringUtil;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.common.util.FakePlayer;
import java.util.Collections;
import java.util.List;
/**
* Represents the way a command was invoked, including the command sender, the current server and
* the "path" to this command.
*/
public final class CommandContext
{
private final MinecraftServer server;
private final ICommandSender sender;
private final List<ISubCommand> path;
public CommandContext( MinecraftServer server, ICommandSender sender, ISubCommand initial )
{
this.server = server;
this.sender = sender;
path = Collections.singletonList( initial );
}
private CommandContext( MinecraftServer server, ICommandSender sender, List<ISubCommand> path )
{
this.server = server;
this.sender = sender;
this.path = path;
}
public CommandContext enter( ISubCommand child )
{
List<ISubCommand> newPath = Lists.newArrayListWithExpectedSize( path.size() + 1 );
newPath.addAll( path );
newPath.add( child );
return new CommandContext( server, sender, newPath );
}
public CommandContext parent()
{
if( path.size() == 1 ) throw new IllegalStateException( "No parent command" );
return new CommandContext( server, sender, path.subList( 0, path.size() - 1 ) );
}
public String getFullPath()
{
StringBuilder out = new StringBuilder();
boolean first = true;
for( ISubCommand command : path )
{
if( first )
{
first = false;
}
else
{
out.append( ' ' );
}
out.append( command.getName() );
}
return out.toString();
}
public String getFullUsage()
{
return "/" + getFullPath() + " " + StringUtil.translate( path.get( path.size() - 1 ).getUsage( this ) );
}
public List<ISubCommand> getPath()
{
return Collections.unmodifiableList( path );
}
public String getRootCommand()
{
return path.get( 0 ).getName();
}
public MinecraftServer getServer()
{
return server;
}
public ICommandSender getSender()
{
return sender;
}
public boolean fromPlayer()
{
return sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
}
}

View File

@@ -1,97 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.framework;
import dan200.computercraft.ComputerCraft;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* {@link ICommand} which delegates to a {@link ISubCommand}.
*/
public class CommandDelegate implements ICommand
{
private final ISubCommand command;
public CommandDelegate( ISubCommand command )
{
this.command = command;
}
@Nonnull
@Override
public String getName()
{
return command.getName();
}
@Nonnull
@Override
public String getUsage( @Nonnull ICommandSender sender )
{
return new CommandContext( sender.getServer(), sender, command ).getFullUsage();
}
@Nonnull
@Override
public List<String> getAliases()
{
return Collections.emptyList();
}
@Override
public void execute( @Nonnull MinecraftServer server, @Nonnull ICommandSender sender, @Nonnull String[] args ) throws CommandException
{
try
{
command.execute( new CommandContext( server, sender, command ), Arrays.asList( args ) );
}
catch( CommandException e )
{
throw e;
}
catch( Throwable e )
{
ComputerCraft.log.error( "Unhandled exception in command", e );
throw new CommandException( "commands.computercraft.generic.exception", e.toString() );
}
}
@Nonnull
@Override
public List<String> getTabCompletions( @Nonnull MinecraftServer server, @Nonnull ICommandSender sender, @Nonnull String[] args, @Nullable BlockPos pos )
{
return command.getCompletion( new CommandContext( server, sender, command ), Arrays.asList( args ) );
}
@Override
public boolean checkPermission( @Nonnull MinecraftServer server, @Nonnull ICommandSender sender )
{
return command.checkPermission( new CommandContext( server, sender, command ) );
}
@Override
public boolean isUsernameIndex( @Nonnull String[] args, int index )
{
return false;
}
@Override
public int compareTo( @Nonnull ICommand o )
{
return getName().compareTo( o.getName() );
}
}

View File

@@ -1,161 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.framework;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import dan200.computercraft.shared.command.text.ChatHelpers;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* A command which delegates to a series of sub commands
*/
public class CommandRoot implements ISubCommand
{
private final String name;
private ISubCommand parent;
private final Map<String, ISubCommand> subCommands = Maps.newHashMap();
public CommandRoot( String name )
{
this.name = name;
register( new SubCommandHelp( this ) );
}
public CommandRoot register( ISubCommand command )
{
subCommands.put( command.getName(), command );
if( command instanceof SubCommandBase )
{
((SubCommandBase) command).setParent( this );
}
else if( command instanceof CommandRoot )
{
((CommandRoot) command).setParent( this );
}
return this;
}
@Nonnull
@Override
public String getName()
{
return name;
}
@Nonnull
@Override
public String getFullName()
{
return parent == null ? name : parent.getFullName() + "." + name;
}
@Nonnull
@Override
public String getUsage( CommandContext context )
{
StringBuilder out = new StringBuilder( "<" );
boolean first = true;
for( ISubCommand command : subCommands.values() )
{
if( command.checkPermission( context ) )
{
if( first )
{
first = false;
}
else
{
out.append( "|" );
}
out.append( command.getName() );
}
}
return out.append( ">" ).toString();
}
@Override
public boolean checkPermission( @Nonnull CommandContext context )
{
for( ISubCommand command : subCommands.values() )
{
if( !(command instanceof SubCommandHelp) && command.checkPermission( context ) ) return true;
}
return false;
}
public Map<String, ISubCommand> getSubCommands()
{
return Collections.unmodifiableMap( subCommands );
}
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
if( arguments.isEmpty() )
{
context.getSender().sendMessage( ChatHelpers.getHelp( context, this, context.getFullPath() ) );
}
else
{
ISubCommand command = subCommands.get( arguments.get( 0 ) );
if( command == null || !command.checkPermission( context ) )
{
throw new CommandException( context.getFullUsage() );
}
command.execute( context.enter( command ), arguments.subList( 1, arguments.size() ) );
}
}
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
if( arguments.isEmpty() )
{
return Lists.newArrayList( subCommands.keySet() );
}
else if( arguments.size() == 1 )
{
List<String> list = Lists.newArrayList();
String match = arguments.get( 0 );
for( ISubCommand command : subCommands.values() )
{
if( CommandBase.doesStringStartWith( match, command.getName() ) && command.checkPermission( context ) )
{
list.add( command.getName() );
}
}
return list;
}
else
{
ISubCommand command = subCommands.get( arguments.get( 0 ) );
if( command == null || !command.checkPermission( context ) ) return Collections.emptyList();
return command.getCompletion( context, arguments.subList( 1, arguments.size() ) );
}
}
void setParent( @Nonnull ISubCommand parent )
{
if( this.parent != null ) throw new IllegalStateException( "Cannot have multiple parents" );
this.parent = parent;
}
}

View File

@@ -1,86 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command.framework;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.List;
/**
* A slightly different implementation of {@link ICommand} which is delegated to.
*/
public interface ISubCommand
{
/**
* Get the name of this command
*
* @return The name of this command
* @see ICommand#getName()
*/
@Nonnull
String getName();
/**
* Get the full name of this command. This is equal to the command parent's full name, plus this command's name.
*
* @return The full name of this command
* @see ISubCommand#getName()
*/
@Nonnull
String getFullName();
/**
* Get the usage of this command
*
* @param context The context this command is executed in
* @return The usage of this command
* @see ICommand#getUsage(ICommandSender)
*/
@Nonnull
default String getUsage( CommandContext context )
{
return "commands." + getFullName() + ".usage";
}
/**
* Determine whether a given command sender has permission to execute this command.
*
* @param context The current command context.
* @return Whether this command can be executed.
* @see ICommand#checkPermission(MinecraftServer, ICommandSender)
*/
boolean checkPermission( @Nonnull CommandContext context );
/**
* Execute this command
*
* @param context The current command context.
* @param arguments The arguments passed @throws CommandException When an error occurs
* @see ICommand#execute(MinecraftServer, ICommandSender, String[])
*/
void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException;
/**
* Get a list of possible completions
*
* @param context The current command context.
* @param arguments The arguments passed. You should complete the last one.
* @return List of possible completions
* @see ICommand#getTabCompletions(MinecraftServer, ICommandSender, String[], BlockPos)
*/
@Nonnull
default List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return Collections.emptyList();
}
}

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