mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-21 08:57:38 +00:00
Compare commits
94 Commits
v1.80pr1.1
...
v1.80pr1.5
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ebb50cba48 | ||
![]() |
7c218361d9 | ||
![]() |
bb2eab0bed | ||
![]() |
e8c0cf3857 | ||
![]() |
db825a7aab | ||
![]() |
dbcae810f0 | ||
![]() |
f753513289 | ||
![]() |
7bb8efed1d | ||
![]() |
0cec4aee8c | ||
![]() |
e0c9dc24e7 | ||
![]() |
244907a39a | ||
![]() |
9be61abd6b | ||
![]() |
922f424a78 | ||
![]() |
5c7828dd79 | ||
![]() |
74f5093d2a | ||
![]() |
4651e362c9 | ||
![]() |
a2e2a5cb37 | ||
![]() |
15a3882016 | ||
![]() |
d3ecd5214b | ||
![]() |
0a8a8a742e | ||
![]() |
ecff23d027 | ||
![]() |
20dcb32bae | ||
![]() |
678462d2db | ||
![]() |
61fdfec09b | ||
![]() |
2d3cd5dc80 | ||
![]() |
5208ad0b98 | ||
![]() |
662fb96beb | ||
![]() |
4c14431a3d | ||
![]() |
5ae38a3f18 | ||
![]() |
94e10d1f67 | ||
![]() |
0a50676884 | ||
![]() |
41cce78fcb | ||
![]() |
4c0fa1fabe | ||
![]() |
54e1dafa3f | ||
![]() |
3ac76bc05b | ||
![]() |
83030df3ee | ||
![]() |
07d15caf6f | ||
![]() |
3298efe652 | ||
![]() |
01d9919a3e | ||
![]() |
80b1170b63 | ||
![]() |
2e7302e654 | ||
![]() |
ca7fb8a0b4 | ||
![]() |
c9b0894f26 | ||
![]() |
c3454a195d | ||
![]() |
3b3dd8071b | ||
![]() |
0d28c67534 | ||
![]() |
d0af85754a | ||
![]() |
3e265c27ff | ||
![]() |
8d356f50c4 | ||
![]() |
f30c4f16c0 | ||
![]() |
8bb8caa315 | ||
![]() |
0f17a3d72e | ||
![]() |
7647369e2d | ||
![]() |
4b4208e724 | ||
![]() |
2a16a1df85 | ||
![]() |
25f7c58400 | ||
![]() |
c3db91f11f | ||
![]() |
8c66ce03d4 | ||
![]() |
2be2a0625e | ||
![]() |
c904d5041b | ||
![]() |
632762768e | ||
![]() |
c69ba205f8 | ||
![]() |
019f4dbea9 | ||
![]() |
259ea41ce3 | ||
![]() |
11290f7204 | ||
![]() |
abd06133fb | ||
![]() |
29a3a0c48f | ||
![]() |
2728c63512 | ||
![]() |
f3b11bc1c2 | ||
![]() |
04590befb3 | ||
![]() |
4e9034f910 | ||
![]() |
ba9cfa3764 | ||
![]() |
341e3e2f89 | ||
![]() |
3f70ca5192 | ||
![]() |
f11bfc53ee | ||
![]() |
61e3967b8e | ||
![]() |
add86ea100 | ||
![]() |
dd51c89278 | ||
![]() |
788d783745 | ||
![]() |
35da60543e | ||
![]() |
ce7923d248 | ||
![]() |
55847460c5 | ||
![]() |
893524b0a8 | ||
![]() |
8fb3ae405f | ||
![]() |
aa447ec101 | ||
![]() |
56b1cb4521 | ||
![]() |
90cc24614c | ||
![]() |
4fb0240a36 | ||
![]() |
f20a7afa7f | ||
![]() |
5be2202b2e | ||
![]() |
b8630f739a | ||
![]() |
1415dd0dae | ||
![]() |
5989d021c7 | ||
![]() |
90c4ebd208 |
@@ -5,7 +5,9 @@ indent_style = space
|
|||||||
indent_size = 4
|
indent_size = 4
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
# Sadly too many files have whitespace errors, so we leave this as is for
|
||||||
|
# now and just make sure we don't introduce any more.
|
||||||
|
# trim_trailing_whitespace = true
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
# CC: Tweaked
|
# 
|
||||||
[](https://travis-ci.org/SquidDev-CC/CC-Tweaked)
|
[](https://travis-ci.org/SquidDev-CC/CC-Tweaked)
|
||||||
|
|
||||||
CC: Tweaked is a fork of ComputerCraft which aims to provide more earlier access to the more experimental and
|
CC: Tweaked is a fork of ComputerCraft which aims to provide earlier access to the more experimental and in-development
|
||||||
in-development features of the mod. For a more stable experience, I recommend checking out the
|
features of the mod. For a more stable experience, I recommend checking out the
|
||||||
[original mod](https://github.com/dan200/ComputerCraft).
|
[original mod](https://github.com/dan200/ComputerCraft).
|
||||||
|
|
||||||
## What?
|
## What?
|
||||||
|
28
build.gradle
28
build.gradle
@@ -13,17 +13,15 @@ buildscript {
|
|||||||
classpath 'org.ajoberstar:gradle-git:1.6.0'
|
classpath 'org.ajoberstar:gradle-git:1.6.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'com.matthewprenger.cursegradle' version '1.0.9'
|
||||||
|
}
|
||||||
|
|
||||||
apply plugin: 'net.minecraftforge.gradle.forge'
|
apply plugin: 'net.minecraftforge.gradle.forge'
|
||||||
apply plugin: 'org.ajoberstar.grgit'
|
apply plugin: 'org.ajoberstar.grgit'
|
||||||
|
|
||||||
/*
|
version = "1.80pr1.5"
|
||||||
// for people who want stable - not yet functional for MC 1.8.8 - we require the forgegradle 2.1 snapshot
|
|
||||||
plugins {
|
|
||||||
id "net.minecraftforge.gradle.forge" version "2.0.2"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
version = "1.80pr1.1"
|
|
||||||
group = "org.squiddev"
|
group = "org.squiddev"
|
||||||
archivesBaseName = "cc-tweaked"
|
archivesBaseName = "cc-tweaked"
|
||||||
|
|
||||||
@@ -60,7 +58,9 @@ configurations {
|
|||||||
dependencies {
|
dependencies {
|
||||||
deobfProvided "mezz.jei:jei_1.12:4.7.5.86:api"
|
deobfProvided "mezz.jei:jei_1.12:4.7.5.86:api"
|
||||||
runtime "mezz.jei:jei_1.12:4.7.5.86"
|
runtime "mezz.jei:jei_1.12:4.7.5.86"
|
||||||
shade 'org.squiddev:Cobalt:0.3.0'
|
shade 'org.squiddev:Cobalt:0.3.1'
|
||||||
|
|
||||||
|
testCompile 'junit:junit:4.11'
|
||||||
}
|
}
|
||||||
|
|
||||||
javadoc {
|
javadoc {
|
||||||
@@ -115,6 +115,16 @@ processResources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
curseforge {
|
||||||
|
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
|
||||||
|
project {
|
||||||
|
id = '282001'
|
||||||
|
releaseType = 'beta'
|
||||||
|
changelog = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gradle.projectsEvaluated {
|
gradle.projectsEvaluated {
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
options.compilerArgs << "-Xlint"
|
options.compilerArgs << "-Xlint"
|
||||||
|
@@ -7,27 +7,37 @@
|
|||||||
package dan200.computercraft;
|
package dan200.computercraft;
|
||||||
|
|
||||||
import com.google.common.base.CaseFormat;
|
import com.google.common.base.CaseFormat;
|
||||||
|
import com.google.common.base.Converter;
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||||
import dan200.computercraft.api.media.IMedia;
|
import dan200.computercraft.api.media.IMedia;
|
||||||
import dan200.computercraft.api.media.IMediaProvider;
|
import dan200.computercraft.api.media.IMediaProvider;
|
||||||
import dan200.computercraft.api.network.IPacketNetwork;
|
import dan200.computercraft.api.network.IPacketNetwork;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredElement;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredProvider;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
||||||
import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
|
import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.event.TurtleAction;
|
||||||
import dan200.computercraft.core.apis.AddressPredicate;
|
import dan200.computercraft.core.apis.AddressPredicate;
|
||||||
import dan200.computercraft.core.filesystem.ComboMount;
|
import dan200.computercraft.core.filesystem.ComboMount;
|
||||||
import dan200.computercraft.core.filesystem.FileMount;
|
import dan200.computercraft.core.filesystem.FileMount;
|
||||||
import dan200.computercraft.core.filesystem.JarMount;
|
import dan200.computercraft.core.filesystem.JarMount;
|
||||||
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
import dan200.computercraft.shared.command.CommandComputer;
|
import dan200.computercraft.shared.command.CommandComputer;
|
||||||
|
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||||
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
|
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
|
||||||
import dan200.computercraft.shared.computer.blocks.BlockCommandComputer;
|
import dan200.computercraft.shared.computer.blocks.BlockCommandComputer;
|
||||||
import dan200.computercraft.shared.computer.blocks.BlockComputer;
|
import dan200.computercraft.shared.computer.blocks.BlockComputer;
|
||||||
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
||||||
import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
|
import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
|
||||||
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputerRegistry;
|
import dan200.computercraft.shared.computer.core.ServerComputerRegistry;
|
||||||
import dan200.computercraft.shared.media.items.ItemDiskExpanded;
|
import dan200.computercraft.shared.media.items.ItemDiskExpanded;
|
||||||
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
|
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
|
||||||
@@ -37,6 +47,7 @@ import dan200.computercraft.shared.network.ComputerCraftPacket;
|
|||||||
import dan200.computercraft.shared.network.PacketHandler;
|
import dan200.computercraft.shared.network.PacketHandler;
|
||||||
import dan200.computercraft.shared.peripheral.common.BlockCable;
|
import dan200.computercraft.shared.peripheral.common.BlockCable;
|
||||||
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
|
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
|
||||||
|
import dan200.computercraft.shared.peripheral.common.BlockWiredModemFull;
|
||||||
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
|
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
|
||||||
import dan200.computercraft.shared.peripheral.modem.BlockAdvancedModem;
|
import dan200.computercraft.shared.peripheral.modem.BlockAdvancedModem;
|
||||||
import dan200.computercraft.shared.peripheral.modem.WirelessNetwork;
|
import dan200.computercraft.shared.peripheral.modem.WirelessNetwork;
|
||||||
@@ -50,6 +61,7 @@ import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
|
|||||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||||
import dan200.computercraft.shared.turtle.upgrades.*;
|
import dan200.computercraft.shared.turtle.upgrades.*;
|
||||||
import dan200.computercraft.shared.util.*;
|
import dan200.computercraft.shared.util.*;
|
||||||
|
import dan200.computercraft.shared.wired.WiredNode;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
@@ -62,6 +74,7 @@ import net.minecraft.util.EnumHand;
|
|||||||
import net.minecraft.util.NonNullList;
|
import net.minecraft.util.NonNullList;
|
||||||
import net.minecraft.util.SoundEvent;
|
import net.minecraft.util.SoundEvent;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.IBlockAccess;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.config.ConfigCategory;
|
import net.minecraftforge.common.config.ConfigCategory;
|
||||||
import net.minecraftforge.common.config.Configuration;
|
import net.minecraftforge.common.config.Configuration;
|
||||||
@@ -82,10 +95,7 @@ import java.io.*;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
@@ -110,6 +120,7 @@ public class ComputerCraft
|
|||||||
// ComputerCraftEdu uses ID 104
|
// ComputerCraftEdu uses ID 104
|
||||||
public static final int printoutGUIID = 105;
|
public static final int printoutGUIID = 105;
|
||||||
public static final int pocketComputerGUIID = 106;
|
public static final int pocketComputerGUIID = 106;
|
||||||
|
public static final int viewComputerGUIID = 110;
|
||||||
|
|
||||||
// Configuration options
|
// Configuration options
|
||||||
private static final String[] DEFAULT_HTTP_WHITELIST = new String[] { "*" };
|
private static final String[] DEFAULT_HTTP_WHITELIST = new String[] { "*" };
|
||||||
@@ -137,6 +148,7 @@ public class ComputerCraft
|
|||||||
public static int advancedTurtleFuelLimit = 100000;
|
public static int advancedTurtleFuelLimit = 100000;
|
||||||
public static boolean turtlesObeyBlockProtection = true;
|
public static boolean turtlesObeyBlockProtection = true;
|
||||||
public static boolean turtlesCanPush = true;
|
public static boolean turtlesCanPush = true;
|
||||||
|
public static EnumSet<TurtleAction> turtleDisabledActions = EnumSet.noneOf( TurtleAction.class );
|
||||||
|
|
||||||
public static final int terminalWidth_computer = 51;
|
public static final int terminalWidth_computer = 51;
|
||||||
public static final int terminalHeight_computer = 19;
|
public static final int terminalHeight_computer = 19;
|
||||||
@@ -169,6 +181,7 @@ public class ComputerCraft
|
|||||||
public static BlockTurtle turtleAdvanced;
|
public static BlockTurtle turtleAdvanced;
|
||||||
public static BlockCommandComputer commandComputer;
|
public static BlockCommandComputer commandComputer;
|
||||||
public static BlockAdvancedModem advancedModem;
|
public static BlockAdvancedModem advancedModem;
|
||||||
|
public static BlockWiredModemFull wiredModemFull;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Items
|
public static class Items
|
||||||
@@ -219,6 +232,7 @@ public class ComputerCraft
|
|||||||
public static Property advancedTurtleFuelLimit;
|
public static Property advancedTurtleFuelLimit;
|
||||||
public static Property turtlesObeyBlockProtection;
|
public static Property turtlesObeyBlockProtection;
|
||||||
public static Property turtlesCanPush;
|
public static Property turtlesCanPush;
|
||||||
|
public static Property turtleDisabledActions;
|
||||||
|
|
||||||
public static Property modem_range;
|
public static Property modem_range;
|
||||||
public static Property modem_highAltitudeRange;
|
public static Property modem_highAltitudeRange;
|
||||||
@@ -251,6 +265,8 @@ public class ComputerCraft
|
|||||||
private static List<IMediaProvider> mediaProviders = new ArrayList<>();
|
private static List<IMediaProvider> mediaProviders = new ArrayList<>();
|
||||||
private static List<ITurtlePermissionProvider> permissionProviders = new ArrayList<>();
|
private static List<ITurtlePermissionProvider> permissionProviders = new ArrayList<>();
|
||||||
private static final Map<String, IPocketUpgrade> pocketUpgrades = new HashMap<>();
|
private static final Map<String, IPocketUpgrade> pocketUpgrades = new HashMap<>();
|
||||||
|
private static final Set<ILuaAPIFactory> apiFactories = new LinkedHashSet<>();
|
||||||
|
private static final Set<IWiredProvider> wiredProviders = new LinkedHashSet<>();
|
||||||
|
|
||||||
// Implementation
|
// Implementation
|
||||||
@Mod.Instance( value = ComputerCraft.MOD_ID )
|
@Mod.Instance( value = ComputerCraft.MOD_ID )
|
||||||
@@ -273,6 +289,18 @@ public class ComputerCraft
|
|||||||
|
|
||||||
// Load config
|
// Load config
|
||||||
Config.config = new Configuration( event.getSuggestedConfigurationFile() );
|
Config.config = new Configuration( event.getSuggestedConfigurationFile() );
|
||||||
|
loadConfig();
|
||||||
|
|
||||||
|
// Setup network
|
||||||
|
networkEventChannel = NetworkRegistry.INSTANCE.newEventDrivenChannel( "CC" );
|
||||||
|
networkEventChannel.register( new PacketHandler() );
|
||||||
|
|
||||||
|
proxy.preInit();
|
||||||
|
turtleProxy.preInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadConfig()
|
||||||
|
{
|
||||||
Config.config.load();
|
Config.config.load();
|
||||||
|
|
||||||
Config.http_enable = Config.config.get( Configuration.CATEGORY_GENERAL, "http_enable", http_enable );
|
Config.http_enable = Config.config.get( Configuration.CATEGORY_GENERAL, "http_enable", http_enable );
|
||||||
@@ -361,6 +389,9 @@ public class ComputerCraft
|
|||||||
Config.turtlesCanPush = Config.config.get( Configuration.CATEGORY_GENERAL, "turtlesCanPush", turtlesCanPush );
|
Config.turtlesCanPush = Config.config.get( Configuration.CATEGORY_GENERAL, "turtlesCanPush", turtlesCanPush );
|
||||||
Config.turtlesCanPush.setComment( "If set to true, Turtles will push entities out of the way instead of stopping if there is space to do so" );
|
Config.turtlesCanPush.setComment( "If set to true, Turtles will push entities out of the way instead of stopping if there is space to do so" );
|
||||||
|
|
||||||
|
Config.turtleDisabledActions = Config.config.get( Configuration.CATEGORY_GENERAL, "turtle_disabled_actions", new String[ 0 ] );
|
||||||
|
Config.turtleDisabledActions.setComment( "A list of turtle actions which are disabled." );
|
||||||
|
|
||||||
Config.maxNotesPerTick = Config.config.get( Configuration.CATEGORY_GENERAL, "maxNotesPerTick", maxNotesPerTick );
|
Config.maxNotesPerTick = Config.config.get( Configuration.CATEGORY_GENERAL, "maxNotesPerTick", maxNotesPerTick );
|
||||||
Config.maxNotesPerTick.setComment( "Maximum amount of notes a speaker can play at once" );
|
Config.maxNotesPerTick.setComment( "Maximum amount of notes a speaker can play at once" );
|
||||||
|
|
||||||
@@ -370,13 +401,6 @@ public class ComputerCraft
|
|||||||
}
|
}
|
||||||
|
|
||||||
syncConfig();
|
syncConfig();
|
||||||
|
|
||||||
// Setup network
|
|
||||||
networkEventChannel = NetworkRegistry.INSTANCE.newEventDrivenChannel( "CC" );
|
|
||||||
networkEventChannel.register( new PacketHandler() );
|
|
||||||
|
|
||||||
proxy.preInit();
|
|
||||||
turtleProxy.preInit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void syncConfig() {
|
public static void syncConfig() {
|
||||||
@@ -408,6 +432,20 @@ public class ComputerCraft
|
|||||||
turtlesObeyBlockProtection = Config.turtlesObeyBlockProtection.getBoolean();
|
turtlesObeyBlockProtection = Config.turtlesObeyBlockProtection.getBoolean();
|
||||||
turtlesCanPush = Config.turtlesCanPush.getBoolean();
|
turtlesCanPush = Config.turtlesCanPush.getBoolean();
|
||||||
|
|
||||||
|
turtleDisabledActions.clear();
|
||||||
|
Converter<String, String> converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE );
|
||||||
|
for( String value : Config.turtleDisabledActions.getStringList() )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
turtleDisabledActions.add( TurtleAction.valueOf( converter.convert( value ) ) );
|
||||||
|
}
|
||||||
|
catch( IllegalArgumentException e )
|
||||||
|
{
|
||||||
|
ComputerCraft.log.error( "Unknown turtle action " + value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
maxNotesPerTick = Math.max(1, Config.maxNotesPerTick.getInt());
|
maxNotesPerTick = Math.max(1, Config.maxNotesPerTick.getInt());
|
||||||
|
|
||||||
Config.config.save();
|
Config.config.save();
|
||||||
@@ -424,6 +462,7 @@ public class ComputerCraft
|
|||||||
public void onServerStarting( FMLServerStartingEvent event )
|
public void onServerStarting( FMLServerStartingEvent event )
|
||||||
{
|
{
|
||||||
event.registerServerCommand( new CommandComputer() );
|
event.registerServerCommand( new CommandComputer() );
|
||||||
|
event.registerServerCommand( new CommandComputerCraft() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mod.EventHandler
|
@Mod.EventHandler
|
||||||
@@ -466,11 +505,6 @@ public class ComputerCraft
|
|||||||
return proxy.getRenderFrame();
|
return proxy.getRenderFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteDisplayLists( int list, int range )
|
|
||||||
{
|
|
||||||
proxy.deleteDisplayLists( list, range );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object getFixedWidthFontRenderer()
|
public static Object getFixedWidthFontRenderer()
|
||||||
{
|
{
|
||||||
return proxy.getFixedWidthFontRenderer();
|
return proxy.getFixedWidthFontRenderer();
|
||||||
@@ -520,6 +554,24 @@ public class ComputerCraft
|
|||||||
player.openGui( ComputerCraft.instance, ComputerCraft.pocketComputerGUIID, player.getEntityWorld(), hand.ordinal(), 0, 0 );
|
player.openGui( ComputerCraft.instance, ComputerCraft.pocketComputerGUIID, player.getEntityWorld(), hand.ordinal(), 0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void openComputerGUI( EntityPlayer player, ServerComputer computer )
|
||||||
|
{
|
||||||
|
ComputerFamily family = computer.getFamily();
|
||||||
|
int width = 0, height = 0;
|
||||||
|
Terminal terminal = computer.getTerminal();
|
||||||
|
if( terminal != null )
|
||||||
|
{
|
||||||
|
width = terminal.getWidth();
|
||||||
|
height = terminal.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pack useful terminal information into the various coordinate bits.
|
||||||
|
// These are extracted in ComputerCraftProxyCommon.getClientGuiElement
|
||||||
|
player.openGui( ComputerCraft.instance, ComputerCraft.viewComputerGUIID, player.getEntityWorld(),
|
||||||
|
computer.getInstanceID(), family.ordinal(), (width & 0xFFFF) << 16 | (height & 0xFFFF)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static File getBaseDir()
|
public static File getBaseDir()
|
||||||
{
|
{
|
||||||
return FMLCommonHandler.instance().getMinecraftServerInstance().getFile(".");
|
return FMLCommonHandler.instance().getMinecraftServerInstance().getFile(".");
|
||||||
@@ -673,6 +725,24 @@ public class ComputerCraft
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void registerAPIFactory( ILuaAPIFactory provider )
|
||||||
|
{
|
||||||
|
if( provider != null )
|
||||||
|
{
|
||||||
|
apiFactories.add( provider );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerWiredProvider( IWiredProvider provider )
|
||||||
|
{
|
||||||
|
if( provider != null ) wiredProviders.add( provider );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IWiredNode createWiredNodeForElement( IWiredElement element )
|
||||||
|
{
|
||||||
|
return new WiredNode( element );
|
||||||
|
}
|
||||||
|
|
||||||
public static IPeripheral getPeripheralAt( World world, BlockPos pos, EnumFacing side )
|
public static IPeripheral getPeripheralAt( World world, BlockPos pos, EnumFacing side )
|
||||||
{
|
{
|
||||||
// Try the handlers in order:
|
// Try the handlers in order:
|
||||||
@@ -694,6 +764,24 @@ public class ComputerCraft
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IWiredElement getWiredElementAt( IBlockAccess world, BlockPos pos, EnumFacing side )
|
||||||
|
{
|
||||||
|
// Try the handlers in order:
|
||||||
|
for( IWiredProvider provider : wiredProviders )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IWiredElement element = provider.getElement( world, pos, side );
|
||||||
|
if( element != null ) return element;
|
||||||
|
}
|
||||||
|
catch( Exception e )
|
||||||
|
{
|
||||||
|
ComputerCraft.log.error( "Wired element provider " + provider + " errored.", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side )
|
public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side )
|
||||||
{
|
{
|
||||||
if( WorldUtil.isBlockInWorld( world, pos ) )
|
if( WorldUtil.isBlockInWorld( world, pos ) )
|
||||||
@@ -795,11 +883,16 @@ public class ComputerCraft
|
|||||||
return upgrades;
|
return upgrades;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPacketNetwork getWirelessNetwork()
|
public static IPacketNetwork getWirelessNetwork()
|
||||||
{
|
{
|
||||||
return WirelessNetwork.getUniversal();
|
return WirelessNetwork.getUniversal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Iterable<ILuaAPIFactory> getAPIFactories()
|
||||||
|
{
|
||||||
|
return apiFactories;
|
||||||
|
}
|
||||||
|
|
||||||
public static int createUniqueNumberedSaveDir( World world, String parentSubPath )
|
public static int createUniqueNumberedSaveDir( World world, String parentSubPath )
|
||||||
{
|
{
|
||||||
return IDAssigner.getNextIDFromDirectory(new File(getWorldDir(world), parentSubPath));
|
return IDAssigner.getNextIDFromDirectory(new File(getWorldDir(world), parentSubPath));
|
||||||
|
@@ -8,9 +8,13 @@ package dan200.computercraft.api;
|
|||||||
|
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||||
import dan200.computercraft.api.media.IMedia;
|
import dan200.computercraft.api.media.IMedia;
|
||||||
import dan200.computercraft.api.media.IMediaProvider;
|
import dan200.computercraft.api.media.IMediaProvider;
|
||||||
import dan200.computercraft.api.network.IPacketNetwork;
|
import dan200.computercraft.api.network.IPacketNetwork;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredElement;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredProvider;
|
||||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
||||||
@@ -20,6 +24,7 @@ import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
|||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.IBlockAccess;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@@ -311,6 +316,97 @@ public final class ComputerCraftAPI
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void registerAPIFactory( @Nonnull ILuaAPIFactory upgrade )
|
||||||
|
{
|
||||||
|
findCC();
|
||||||
|
if( computerCraft_registerAPIFactory != null )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
computerCraft_registerAPIFactory.invoke( null, upgrade );
|
||||||
|
}
|
||||||
|
catch( Exception e )
|
||||||
|
{
|
||||||
|
// It failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a peripheral handler to convert blocks into {@link IPeripheral} implementations.
|
||||||
|
*
|
||||||
|
* @param handler The peripheral provider to register.
|
||||||
|
* @see dan200.computercraft.api.peripheral.IPeripheral
|
||||||
|
* @see dan200.computercraft.api.peripheral.IPeripheralProvider
|
||||||
|
*/
|
||||||
|
public static void registerWiredProvider( @Nonnull IWiredProvider handler )
|
||||||
|
{
|
||||||
|
findCC();
|
||||||
|
if ( computerCraft_registerWiredProvider != null)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
computerCraft_registerWiredProvider.invoke( null, handler );
|
||||||
|
} catch (Exception e){
|
||||||
|
// It failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new wired node for a given wired element
|
||||||
|
*
|
||||||
|
* @param element The element to construct it for
|
||||||
|
* @return The element's node
|
||||||
|
* @see IWiredElement#getNode()
|
||||||
|
*/
|
||||||
|
@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" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the wired network element for a block in world
|
||||||
|
*
|
||||||
|
* @param world The world the block exists in
|
||||||
|
* @param pos The position the block exists in
|
||||||
|
* @param side The side to extract the network element from
|
||||||
|
* @return The element's node
|
||||||
|
* @see IWiredElement#getNode()
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static IWiredElement getWiredElementAt( @Nonnull IBlockAccess world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
|
||||||
|
{
|
||||||
|
findCC();
|
||||||
|
if( computerCraft_getWiredElementAt != null )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (IWiredElement) computerCraft_getWiredElementAt.invoke( null, world, pos, side );
|
||||||
|
}
|
||||||
|
catch( ReflectiveOperationException ignored )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// The functions below here are private, and are used to interface with the non-API ComputerCraft classes.
|
// The functions below here are private, and are used to interface with the non-API ComputerCraft classes.
|
||||||
// Reflection is used here so you can develop your mod without decompiling ComputerCraft and including
|
// Reflection is used here so you can develop your mod without decompiling ComputerCraft and including
|
||||||
// it in your solution, and so your mod won't crash if ComputerCraft is installed.
|
// it in your solution, and so your mod won't crash if ComputerCraft is installed.
|
||||||
@@ -354,6 +450,18 @@ public final class ComputerCraftAPI
|
|||||||
} );
|
} );
|
||||||
computerCraft_getWirelessNetwork = findCCMethod( "getWirelessNetwork", new Class<?>[] {
|
computerCraft_getWirelessNetwork = findCCMethod( "getWirelessNetwork", new Class<?>[] {
|
||||||
} );
|
} );
|
||||||
|
computerCraft_registerAPIFactory = findCCMethod( "registerAPIFactory", new Class<?>[] {
|
||||||
|
ILuaAPIFactory.class
|
||||||
|
} );
|
||||||
|
computerCraft_registerWiredProvider = findCCMethod( "registerWiredProvider", new Class<?>[] {
|
||||||
|
IWiredProvider.class
|
||||||
|
} );
|
||||||
|
computerCraft_createWiredNodeForElement = findCCMethod( "createWiredNodeForElement", new Class<?>[] {
|
||||||
|
IWiredElement.class
|
||||||
|
} );
|
||||||
|
computerCraft_getWiredElementAt = findCCMethod( "getWiredElementAt", new Class<?>[]{
|
||||||
|
IBlockAccess.class, BlockPos.class, EnumFacing.class
|
||||||
|
} );
|
||||||
} catch( Exception e ) {
|
} catch( Exception e ) {
|
||||||
System.out.println( "ComputerCraftAPI: ComputerCraft not found." );
|
System.out.println( "ComputerCraftAPI: ComputerCraft not found." );
|
||||||
} finally {
|
} finally {
|
||||||
@@ -390,4 +498,8 @@ public final class ComputerCraftAPI
|
|||||||
private static Method computerCraft_registerPermissionProvider = null;
|
private static Method computerCraft_registerPermissionProvider = null;
|
||||||
private static Method computerCraft_registerPocketUpgrade = null;
|
private static Method computerCraft_registerPocketUpgrade = null;
|
||||||
private static Method computerCraft_getWirelessNetwork = null;
|
private static Method computerCraft_getWirelessNetwork = null;
|
||||||
|
private static Method computerCraft_registerAPIFactory = null;
|
||||||
|
private static Method computerCraft_registerWiredProvider = null;
|
||||||
|
private static Method computerCraft_createWiredNodeForElement = null;
|
||||||
|
private static Method computerCraft_getWiredElementAt = null;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,38 @@
|
|||||||
|
package dan200.computercraft.api.filesystem;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a mount of the entire computer's file system.
|
||||||
|
*
|
||||||
|
* This exists for use by various APIs - one should not attempt to mount it.
|
||||||
|
*/
|
||||||
|
public interface IFileSystem extends IWritableMount
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Combine two paths together, reducing them into a normalised form.
|
||||||
|
*
|
||||||
|
* @param path The main path.
|
||||||
|
* @param child The path to append.
|
||||||
|
* @return The combined, normalised path.
|
||||||
|
*/
|
||||||
|
String combine( String path, String child );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy files from one location to another.
|
||||||
|
*
|
||||||
|
* @param from The location to copy from.
|
||||||
|
* @param to The location to copy to. This should not exist.
|
||||||
|
* @throws IOException If the copy failed.
|
||||||
|
*/
|
||||||
|
void copy( String from, String to ) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move files from one location to another.
|
||||||
|
*
|
||||||
|
* @param from The location to move from.
|
||||||
|
* @param to The location to move to. This should not exist.
|
||||||
|
* @throws IOException If the move failed.
|
||||||
|
*/
|
||||||
|
void move( String from, String to ) throws IOException;
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.filesystem.IFileSystem;
|
||||||
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface passed to {@link ILuaAPIFactory} in order to provide additional information
|
||||||
|
* about a computer.
|
||||||
|
*/
|
||||||
|
public interface IComputerSystem extends IComputerAccess
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the file system for this computer.
|
||||||
|
*
|
||||||
|
* @return The computer's file system, or {@code null} if it is not initialised.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
IFileSystem getFileSystem();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the label for this computer
|
||||||
|
*
|
||||||
|
* @return This computer's label, or {@code null} if it is not set.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
String getLabel();
|
||||||
|
}
|
47
src/main/java/dan200/computercraft/api/lua/ILuaAPI.java
Normal file
47
src/main/java/dan200/computercraft/api/lua/ILuaAPI.java
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a {@link ILuaObject} which is stored as a global variable on computer startup.
|
||||||
|
*
|
||||||
|
* Before implementing this interface, consider alternative methods of providing methods. It is generally preferred
|
||||||
|
* to use peripherals to provide functionality to users.
|
||||||
|
*
|
||||||
|
* @see ILuaAPIFactory
|
||||||
|
* @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
|
||||||
|
*/
|
||||||
|
public interface ILuaAPI extends ILuaObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the globals this API will be assigned to. This will override any other global, so you should
|
||||||
|
*
|
||||||
|
* @return A list of globals this API will be assigned to.
|
||||||
|
*/
|
||||||
|
String[] getNames();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the computer is turned on.
|
||||||
|
*
|
||||||
|
* One should only interact with the file system.
|
||||||
|
*/
|
||||||
|
default void startup() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called every time the computer is ticked. This can be used to process various.
|
||||||
|
*/
|
||||||
|
default void update() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the computer is turned off or unloaded.
|
||||||
|
*
|
||||||
|
* This should reset the state of the object, disposing any remaining file handles, or other resources.
|
||||||
|
*/
|
||||||
|
default void shutdown() { }
|
||||||
|
}
|
@@ -0,0 +1,24 @@
|
|||||||
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an {@link ILuaAPI} for a specific computer.
|
||||||
|
*
|
||||||
|
* @see ILuaAPI
|
||||||
|
* @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
|
||||||
|
*/
|
||||||
|
public interface ILuaAPIFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new API instance for a given computer.
|
||||||
|
*
|
||||||
|
* @param computer The computer this API is for.
|
||||||
|
* @return The created API, or {@code null} if one should not be injected.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
ILuaAPI create( @Nonnull IComputerSystem computer );
|
||||||
|
}
|
@@ -41,7 +41,8 @@ public interface IPacketNetwork
|
|||||||
* to all receivers within range (or any interdimensional ones).
|
* to all receivers within range (or any interdimensional ones).
|
||||||
*
|
*
|
||||||
* @param packet The packet to send.
|
* @param packet The packet to send.
|
||||||
* @see #transmitInterdimensional(Packet)
|
* @param range The maximum distance this packet will be sent.
|
||||||
|
* @see #transmitInterdimensional(Packet)
|
||||||
* @see IPacketReceiver#receiveSameDimension(Packet, double)
|
* @see IPacketReceiver#receiveSameDimension(Packet, double)
|
||||||
*/
|
*/
|
||||||
void transmitSameDimension( @Nonnull Packet packet, double range );
|
void transmitSameDimension( @Nonnull Packet packet, double range );
|
||||||
@@ -51,7 +52,7 @@ public interface IPacketNetwork
|
|||||||
* to all receivers across all dimensions.
|
* to all receivers across all dimensions.
|
||||||
*
|
*
|
||||||
* @param packet The packet to send.
|
* @param packet The packet to send.
|
||||||
* @see #transmitSameDimension(Packet, double)
|
* @see #transmitSameDimension(Packet, double)
|
||||||
* @see IPacketReceiver#receiveDifferentDimension(Packet)
|
* @see IPacketReceiver#receiveDifferentDimension(Packet)
|
||||||
*/
|
*/
|
||||||
void transmitInterdimensional( @Nonnull Packet packet );
|
void transmitInterdimensional( @Nonnull Packet packet );
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object which may be part of a wired network.
|
||||||
|
*
|
||||||
|
* Elements should construct a node using {@link ComputerCraftAPI#createWiredNodeForElement(IWiredElement)}. This acts
|
||||||
|
* as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant
|
||||||
|
* for its lifespan.
|
||||||
|
*
|
||||||
|
* Elements are generally tied to a block or tile entity in world. One should either register an {@link IWiredProvider}
|
||||||
|
* or implement {@link IWiredElementTile} on your tile entity.
|
||||||
|
*
|
||||||
|
* @see IWiredProvider
|
||||||
|
* @see ComputerCraftAPI#registerWiredProvider(IWiredProvider)
|
||||||
|
* @see IWiredElementTile
|
||||||
|
*/
|
||||||
|
public interface IWiredElement extends IWiredSender
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Fetch the peripherals this network element provides.
|
||||||
|
*
|
||||||
|
* This is only called when initially attaching to a network and after a call to {@link IWiredNode#invalidate()}}, so
|
||||||
|
* one does not <em>need</em> to cache the return value.
|
||||||
|
*
|
||||||
|
* @return The peripherals this node provides.
|
||||||
|
* @see IWiredNode#invalidate()
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
default Map<String, IPeripheral> getPeripherals()
|
||||||
|
{
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when objects on the network change. This may occur when network nodes are added or removed, or when
|
||||||
|
* peripherals change.
|
||||||
|
*
|
||||||
|
* @param change The change which occurred.
|
||||||
|
* @see IWiredNetworkChange
|
||||||
|
*/
|
||||||
|
default void networkChanged( @Nonnull IWiredNetworkChange change )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link net.minecraft.tileentity.TileEntity} which provides a {@link IWiredElement}. This acts
|
||||||
|
* as a simpler alternative to a full-blown {@link IWiredProvider}.
|
||||||
|
*/
|
||||||
|
public interface IWiredElementTile
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the wired element of this tile for a given side.
|
||||||
|
*
|
||||||
|
* @param side The side to get the network element from.
|
||||||
|
* @return A network element, or {@code null} if there is no element here.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
IWiredElement getWiredElement( @Nonnull EnumFacing side );
|
||||||
|
}
|
@@ -0,0 +1,74 @@
|
|||||||
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series
|
||||||
|
* of peripherals.
|
||||||
|
*
|
||||||
|
* Networks from a connected graph. This means there is some path between all nodes on the network. Further more, if
|
||||||
|
* there is some path between two nodes then they must be on the same network. {@link IWiredNetwork} will automatically
|
||||||
|
* handle the merging and splitting of networks (and thus changing of available nodes and peripherals) as connections
|
||||||
|
* change.
|
||||||
|
*
|
||||||
|
* This does mean one can not rely on the network remaining consistent between subsequent operations. Consequently,
|
||||||
|
* it is generally preferred to use the methods provided by {@link IWiredNode}.
|
||||||
|
*
|
||||||
|
* @see IWiredNode#getNetwork()
|
||||||
|
*/
|
||||||
|
public interface IWiredNetwork
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a connection between two nodes.
|
||||||
|
*
|
||||||
|
* This should only be used on the server thread.
|
||||||
|
*
|
||||||
|
* @param left The first node to connect
|
||||||
|
* @param right The second node to connect
|
||||||
|
* @return {@code true} if a connection was created or {@code false} if the connection already exists.
|
||||||
|
* @throws IllegalStateException If neither node is on the network.
|
||||||
|
* @throws IllegalArgumentException If {@code left} and {@code right} are equal.
|
||||||
|
* @see IWiredNode#connectTo(IWiredNode)
|
||||||
|
* @see IWiredNetwork#connect(IWiredNode, IWiredNode)
|
||||||
|
*/
|
||||||
|
boolean connect( @Nonnull IWiredNode left, @Nonnull IWiredNode right );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a connection between this node and another.
|
||||||
|
*
|
||||||
|
* This should only be used on the server thread.
|
||||||
|
*
|
||||||
|
* @param left The first node in the connection.
|
||||||
|
* @param right The second node in the connection.
|
||||||
|
* @return {@code true} if a connection was destroyed or {@code false} if no connection exists.
|
||||||
|
* @throws IllegalArgumentException If either node is not on the network.
|
||||||
|
* @throws IllegalArgumentException If {@code left} and {@code right} are equal.
|
||||||
|
* @see IWiredNode#disconnectFrom(IWiredNode)
|
||||||
|
* @see IWiredNetwork#connect(IWiredNode, IWiredNode)
|
||||||
|
*/
|
||||||
|
boolean disconnect( @Nonnull IWiredNode left, @Nonnull IWiredNode right );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sever all connections this node has, removing it from this network.
|
||||||
|
*
|
||||||
|
* This should only be used on the server thread.
|
||||||
|
*
|
||||||
|
* @param node The node to remove
|
||||||
|
* @return Whether this node was removed from the network. One cannot remove a node from a network where it is the
|
||||||
|
* only element.
|
||||||
|
* @throws IllegalArgumentException If the node is not in the network.
|
||||||
|
* @see IWiredNode#remove()
|
||||||
|
*/
|
||||||
|
boolean remove( @Nonnull IWiredNode node );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark this node's peripherals as having changed.
|
||||||
|
*
|
||||||
|
* This should only be used on the server thread.
|
||||||
|
*
|
||||||
|
* @param node The node to mark as invalid.
|
||||||
|
* @throws IllegalArgumentException If the node is not in the network.
|
||||||
|
* @see IWiredElement#getPeripherals()
|
||||||
|
*/
|
||||||
|
void invalidate( @Nonnull IWiredNode node );
|
||||||
|
}
|
@@ -0,0 +1,32 @@
|
|||||||
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a change to the objects on a wired network.
|
||||||
|
*
|
||||||
|
* @see IWiredElement#networkChanged(IWiredNetworkChange)
|
||||||
|
*/
|
||||||
|
public interface IWiredNetworkChange
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A set of peripherals which have been removed. Note that there may be entries with the same name
|
||||||
|
* in the added and removed set, but with a different peripheral.
|
||||||
|
*
|
||||||
|
* @return The set of removed peripherals.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
Map<String, IPeripheral> peripheralsRemoved();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of peripherals which have been added. Note that there may be entries with the same name
|
||||||
|
* in the added and removed set, but with a different peripheral.
|
||||||
|
*
|
||||||
|
* @return The set of added peripherals.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
Map<String, IPeripheral> peripheralsAdded();
|
||||||
|
}
|
@@ -0,0 +1,98 @@
|
|||||||
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.network.IPacketNetwork;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wired nodes act as a layer between {@link IWiredElement}s and {@link IWiredNetwork}s.
|
||||||
|
*
|
||||||
|
* Firstly, a node acts as a packet network, capable of sending and receiving modem messages to connected nodes. These
|
||||||
|
* methods may be safely used on any thread.
|
||||||
|
*
|
||||||
|
* When sending a packet, the system will attempt to find the shortest path between the two nodes based on their
|
||||||
|
* element's position. Note that packet senders and receivers can have different locations from their associated
|
||||||
|
* element: the distance between the two will be added to the total packet's distance.
|
||||||
|
*
|
||||||
|
* Wired nodes also provide several convenience methods for interacting with a wired network. These should only ever
|
||||||
|
* be used on the main server thread.
|
||||||
|
*/
|
||||||
|
public interface IWiredNode extends IPacketNetwork
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The associated element for this network node.
|
||||||
|
*
|
||||||
|
* @return This node's element.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
IWiredElement getElement();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The network this node is currently connected to. Note that this may change
|
||||||
|
* after any network operation, so it should not be cached.
|
||||||
|
*
|
||||||
|
* This should only be used on the server thread.
|
||||||
|
*
|
||||||
|
* @return This node's network.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
IWiredNetwork getNetwork();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a connection from this node to another.
|
||||||
|
*
|
||||||
|
* This should only be used on the server thread.
|
||||||
|
*
|
||||||
|
* @param node The other node to connect to.
|
||||||
|
* @return {@code true} if a connection was created or {@code false} if the connection already exists.
|
||||||
|
* @see IWiredNetwork#connect(IWiredNode, IWiredNode)
|
||||||
|
* @see IWiredNode#disconnectFrom(IWiredNode)
|
||||||
|
*/
|
||||||
|
default boolean connectTo( @Nonnull IWiredNode node )
|
||||||
|
{
|
||||||
|
return getNetwork().connect( this, node );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a connection between this node and another.
|
||||||
|
*
|
||||||
|
* This should only be used on the server thread.
|
||||||
|
*
|
||||||
|
* @param node The other node to disconnect from.
|
||||||
|
* @return {@code true} if a connection was destroyed or {@code false} if no connection exists.
|
||||||
|
* @throws IllegalArgumentException If {@code node} is not on the same network.
|
||||||
|
* @see IWiredNetwork#disconnect(IWiredNode, IWiredNode)
|
||||||
|
* @see IWiredNode#connectTo(IWiredNode)
|
||||||
|
*/
|
||||||
|
default boolean disconnectFrom( @Nonnull IWiredNode node )
|
||||||
|
{
|
||||||
|
return getNetwork().disconnect( this, node );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sever all connections this node has, removing it from this network.
|
||||||
|
*
|
||||||
|
* This should only be used on the server thread.
|
||||||
|
*
|
||||||
|
* @return Whether this node was removed from the network. One cannot remove a node from a network where it is the
|
||||||
|
* only element.
|
||||||
|
* @throws IllegalArgumentException If the node is not in the network.
|
||||||
|
* @see IWiredNetwork#remove(IWiredNode)
|
||||||
|
*/
|
||||||
|
default boolean remove()
|
||||||
|
{
|
||||||
|
return getNetwork().remove( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark this node's peripherals as having changed.
|
||||||
|
*
|
||||||
|
* This should only be used on the server thread.
|
||||||
|
*
|
||||||
|
* @see IWiredElement#getPeripherals()
|
||||||
|
*/
|
||||||
|
default void invalidate()
|
||||||
|
{
|
||||||
|
getNetwork().invalidate( this );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.IBlockAccess;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch or create an {@link IWiredElement} for a block at a given position.
|
||||||
|
*
|
||||||
|
* @see dan200.computercraft.api.ComputerCraftAPI#registerWiredProvider(IWiredProvider)
|
||||||
|
* @see IWiredElementTile
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface IWiredProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Extract a wired network element from a block location.
|
||||||
|
*
|
||||||
|
* @param world The world the block is in.
|
||||||
|
* @param pos The position the block is at.
|
||||||
|
* @param side The side to get the network element from.
|
||||||
|
* @return A network element, or {@code null} if there is not an element here you'd like to handle.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
IWiredElement getElement( @Nonnull IBlockAccess world, @Nonnull BlockPos pos, @Nonnull EnumFacing side );
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.network.IPacketSender;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object on a {@link IWiredNetwork} capable of sending packets.
|
||||||
|
*
|
||||||
|
* Unlike a regular {@link IPacketSender}, this must be associated with the node you are attempting to
|
||||||
|
* to send the packet from.
|
||||||
|
*/
|
||||||
|
public interface IWiredSender extends IPacketSender
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The node in the network representing this object.
|
||||||
|
*
|
||||||
|
* This should be used as a proxy for the main network. One should send packets
|
||||||
|
* and register receivers through this object.
|
||||||
|
*
|
||||||
|
* @return The node for this element.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
IWiredNode getNode();
|
||||||
|
}
|
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@API( owner="ComputerCraft", provides="ComputerCraft|API|Network|Wired", apiVersion="${version}" )
|
||||||
|
package dan200.computercraft.api.network.wired;
|
||||||
|
|
||||||
|
import net.minecraftforge.fml.common.API;
|
@@ -13,6 +13,8 @@ import net.minecraft.world.World;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interface passed to peripherals by computers or turtles, providing methods
|
* The interface passed to peripherals by computers or turtles, providing methods
|
||||||
@@ -154,4 +156,33 @@ public interface IComputerAccess
|
|||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
String getAttachmentName();
|
String getAttachmentName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a set of peripherals that this computer access can "see", along with their attachment name.
|
||||||
|
*
|
||||||
|
* This may include other peripherals on the wired network or peripherals on other sides of the computer.
|
||||||
|
*
|
||||||
|
* @return All reachable peripherals
|
||||||
|
* @see #getAttachmentName()
|
||||||
|
* @see #getAvailablePeripheral(String)
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
default Map<String, IPeripheral> getAvailablePeripherals()
|
||||||
|
{
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a reachable peripheral with the given attachement name. This is a equivalent to
|
||||||
|
* {@link #getAvailablePeripherals()}{@code .get(name)}, though may be more performant.
|
||||||
|
*
|
||||||
|
* @param name The peripheral's attached name
|
||||||
|
* @return The reachable peripheral, or {@code null} if none can be found.
|
||||||
|
* @see #getAvailablePeripherals()
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default IPeripheral getAvailablePeripheral( @Nonnull String name )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -114,6 +114,18 @@ public interface IPeripheral
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the object that this peripheral provides methods for. This will generally be the tile entity
|
||||||
|
* or block, but may be an inventory, entity, etc...
|
||||||
|
*
|
||||||
|
* @return The object this peripheral targets
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
default Object getTarget()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether this peripheral is equivalent to another one.
|
* Determine whether this peripheral is equivalent to another one.
|
||||||
*
|
*
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.turtle;
|
package dan200.computercraft.api.turtle;
|
||||||
|
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
@@ -135,6 +136,14 @@ public interface ITurtleAccess
|
|||||||
*/
|
*/
|
||||||
int getColour();
|
int getColour();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the player who owns this turtle, namely whoever placed it.
|
||||||
|
*
|
||||||
|
* @return This turtle's owner.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
GameProfile getOwningPlayer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the inventory of this turtle
|
* Get the inventory of this turtle
|
||||||
*
|
*
|
||||||
@@ -148,7 +157,7 @@ public interface ITurtleAccess
|
|||||||
* Get the inventory of this turtle as an {@link IItemHandlerModifiable}.
|
* Get the inventory of this turtle as an {@link IItemHandlerModifiable}.
|
||||||
*
|
*
|
||||||
* @return This turtle's inventory
|
* @return This turtle's inventory
|
||||||
* @see #getInventory()
|
* @see #getInventory()
|
||||||
* @see IItemHandlerModifiable
|
* @see IItemHandlerModifiable
|
||||||
* @see net.minecraftforge.items.CapabilityItemHandler#ITEM_HANDLER_CAPABILITY
|
* @see net.minecraftforge.items.CapabilityItemHandler#ITEM_HANDLER_CAPABILITY
|
||||||
*/
|
*/
|
||||||
|
@@ -8,11 +8,15 @@ package dan200.computercraft.api.turtle;
|
|||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
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.IBakedModel;
|
||||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
||||||
|
import net.minecraftforge.event.world.BlockEvent;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
@@ -100,6 +104,9 @@ public interface ITurtleUpgrade
|
|||||||
* Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called
|
* Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called
|
||||||
* by the turtle, and the tool is required to do some work.
|
* by the turtle, and the tool is required to do some work.
|
||||||
*
|
*
|
||||||
|
* Conforming implementations should fire {@link BlockEvent.BreakEvent} and {@link TurtleBlockEvent.Dig}for digging,
|
||||||
|
* {@link AttackEntityEvent} and {@link TurtleAttackEvent} for attacking.
|
||||||
|
*
|
||||||
* @param turtle Access to the turtle that the tool resides on.
|
* @param turtle Access to the turtle that the tool resides on.
|
||||||
* @param side Which side of the turtle (left or right) the tool resides on.
|
* @param side Which side of the turtle (left or right) the tool resides on.
|
||||||
* @param verb Which action (dig or attack) the turtle is being called on to perform.
|
* @param verb Which action (dig or attack) the turtle is being called on to perform.
|
||||||
|
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.api.turtle.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A basic action that a turtle may perform, as accessed by the {@code turtle} API.
|
||||||
|
*
|
||||||
|
* @see TurtleActionEvent
|
||||||
|
*/
|
||||||
|
public enum TurtleAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A turtle moves to a new position.
|
||||||
|
*
|
||||||
|
* @see TurtleBlockEvent.Move
|
||||||
|
*/
|
||||||
|
MOVE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A turtle turns in a specific direction.
|
||||||
|
*/
|
||||||
|
TURN,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A turtle attempts to dig a block.
|
||||||
|
*
|
||||||
|
* @see TurtleBlockEvent.Dig
|
||||||
|
*/
|
||||||
|
DIG,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A turtle attempts to place a block or item in the world.
|
||||||
|
*
|
||||||
|
* @see TurtleBlockEvent.Place
|
||||||
|
*/
|
||||||
|
PLACE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A turtle attempts to attack an entity.
|
||||||
|
*
|
||||||
|
* @see TurtleActionEvent
|
||||||
|
*/
|
||||||
|
ATTACK,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop an item into an inventory/the world.
|
||||||
|
*
|
||||||
|
* @see TurtleInventoryEvent.Drop
|
||||||
|
*/
|
||||||
|
DROP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suck an item from an inventory or the world.
|
||||||
|
*
|
||||||
|
* @see TurtleInventoryEvent.Suck
|
||||||
|
*/
|
||||||
|
SUCK,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refuel the turtle's fuel levels.
|
||||||
|
*/
|
||||||
|
REFUEL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equip or unequip an item.
|
||||||
|
*/
|
||||||
|
EQUIP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inspect a block in world
|
||||||
|
*
|
||||||
|
* @see TurtleBlockEvent.Inspect
|
||||||
|
*/
|
||||||
|
INSPECT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather metdata about an item in the turtle's inventory.
|
||||||
|
*/
|
||||||
|
INSPECT_ITEM,
|
||||||
|
}
|
@@ -0,0 +1,76 @@
|
|||||||
|
package dan200.computercraft.api.turtle.event;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleCommandResult;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event fired when a turtle is performing a known action.
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public class TurtleActionEvent extends TurtleEvent
|
||||||
|
{
|
||||||
|
private final TurtleAction action;
|
||||||
|
private String failureMessage;
|
||||||
|
|
||||||
|
public TurtleActionEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action )
|
||||||
|
{
|
||||||
|
super( turtle );
|
||||||
|
|
||||||
|
Preconditions.checkNotNull( action, "action cannot be null" );
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TurtleAction getAction()
|
||||||
|
{
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the cancellation state of this action.
|
||||||
|
*
|
||||||
|
* If {@code cancel} is {@code true}, this action will not be carried out.
|
||||||
|
*
|
||||||
|
* @param cancel The new canceled value.
|
||||||
|
* @see TurtleCommandResult#failure()
|
||||||
|
* @deprecated Use {@link #setCanceled(boolean, String)} instead.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void setCanceled( boolean cancel )
|
||||||
|
{
|
||||||
|
setCanceled( cancel, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the cancellation state of this action, setting a failure message if required.
|
||||||
|
*
|
||||||
|
* If {@code cancel} is {@code true}, this action will not be carried out.
|
||||||
|
*
|
||||||
|
* @param cancel The new canceled value.
|
||||||
|
* @param failureMessage The message to return to the user explaining the failure.
|
||||||
|
* @see TurtleCommandResult#failure(String)
|
||||||
|
*/
|
||||||
|
public void setCanceled( boolean cancel, @Nullable String failureMessage )
|
||||||
|
{
|
||||||
|
super.setCanceled( cancel );
|
||||||
|
this.failureMessage = cancel ? failureMessage : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message with which this will fail.
|
||||||
|
*
|
||||||
|
* @return The failure message.
|
||||||
|
* @see TurtleCommandResult#failure()
|
||||||
|
* @see #setCanceled(boolean, String)
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getFailureMessage()
|
||||||
|
{
|
||||||
|
return failureMessage;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.api.turtle.event;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
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.entity.Entity;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired when a turtle attempts to attack an entity.
|
||||||
|
*
|
||||||
|
* This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)},
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @see TurtleAction#ATTACK
|
||||||
|
*/
|
||||||
|
public class TurtleAttackEvent extends TurtlePlayerEvent
|
||||||
|
{
|
||||||
|
private final Entity target;
|
||||||
|
private final ITurtleUpgrade upgrade;
|
||||||
|
private final TurtleSide side;
|
||||||
|
|
||||||
|
public TurtleAttackEvent( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Entity target, @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side )
|
||||||
|
{
|
||||||
|
super( turtle, TurtleAction.ATTACK, player );
|
||||||
|
Preconditions.checkNotNull( target, "target cannot be null" );
|
||||||
|
Preconditions.checkNotNull( upgrade, "upgrade cannot be null" );
|
||||||
|
Preconditions.checkNotNull( side, "side cannot be null" );
|
||||||
|
this.target = target;
|
||||||
|
this.upgrade = upgrade;
|
||||||
|
this.side = side;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the entity being attacked by this turtle.
|
||||||
|
*
|
||||||
|
* @return The entity being attacked.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public Entity getTarget()
|
||||||
|
{
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the upgrade responsible for attacking.
|
||||||
|
*
|
||||||
|
* @return The upgrade responsible for attacking.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public ITurtleUpgrade getUpgrade()
|
||||||
|
{
|
||||||
|
return upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the side the attacking upgrade is on.
|
||||||
|
*
|
||||||
|
* @return The upgrade's side.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public TurtleSide getSide()
|
||||||
|
{
|
||||||
|
return side;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.api.turtle.event;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
|
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.item.ItemStack;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
import net.minecraftforge.event.world.BlockEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A general event for when a turtle interacts with a block or region.
|
||||||
|
*
|
||||||
|
* You should generally listen to one of the sub-events instead, cancelling them where
|
||||||
|
* appropriate.
|
||||||
|
*
|
||||||
|
* Note that you are not guaranteed to receive this event, if it has been cancelled by other
|
||||||
|
* mechanisms, such as block protection systems.
|
||||||
|
*
|
||||||
|
* Be aware that some events (such as {@link TurtleInventoryEvent}) do not necessarily interact
|
||||||
|
* with a block, simply objects within that block space.
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public abstract class TurtleBlockEvent extends TurtlePlayerEvent
|
||||||
|
{
|
||||||
|
private final World world;
|
||||||
|
private final BlockPos pos;
|
||||||
|
|
||||||
|
protected TurtleBlockEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos )
|
||||||
|
{
|
||||||
|
super( turtle, action, player );
|
||||||
|
|
||||||
|
Preconditions.checkNotNull( world, "world cannot be null" );
|
||||||
|
Preconditions.checkNotNull( pos, "pos cannot be null" );
|
||||||
|
this.world = world;
|
||||||
|
this.pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the world the turtle is interacting in.
|
||||||
|
*
|
||||||
|
* @return The world the turtle is interacting in.
|
||||||
|
*/
|
||||||
|
public World getWorld()
|
||||||
|
{
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position the turtle is interacting with. Note that this is different
|
||||||
|
* to {@link ITurtleAccess#getPosition()}.
|
||||||
|
*
|
||||||
|
* @return The position the turtle is interacting with.
|
||||||
|
*/
|
||||||
|
public BlockPos getPos()
|
||||||
|
{
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired when a turtle attempts to dig a block.
|
||||||
|
*
|
||||||
|
* This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)},
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @see TurtleAction#DIG
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public static class Dig extends TurtleBlockEvent
|
||||||
|
{
|
||||||
|
private final IBlockState 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 )
|
||||||
|
{
|
||||||
|
super( turtle, TurtleAction.DIG, player, world, pos );
|
||||||
|
|
||||||
|
Preconditions.checkNotNull( block, "block cannot be null" );
|
||||||
|
Preconditions.checkNotNull( upgrade, "upgrade cannot be null" );
|
||||||
|
Preconditions.checkNotNull( side, "side cannot be null" );
|
||||||
|
this.block = block;
|
||||||
|
this.upgrade = upgrade;
|
||||||
|
this.side = side;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block which is about to be broken.
|
||||||
|
*
|
||||||
|
* @return The block which is going to be broken.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public IBlockState getBlock()
|
||||||
|
{
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the upgrade doing the digging
|
||||||
|
*
|
||||||
|
* @return The upgrade doing the digging.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public ITurtleUpgrade getUpgrade()
|
||||||
|
{
|
||||||
|
return upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the side the upgrade doing the digging is on.
|
||||||
|
*
|
||||||
|
* @return The upgrade's side.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public TurtleSide getSide()
|
||||||
|
{
|
||||||
|
return side;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired when a turtle attempts to move into a block.
|
||||||
|
*
|
||||||
|
* @see TurtleAction#MOVE
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public static class Move extends TurtleBlockEvent
|
||||||
|
{
|
||||||
|
public Move( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos )
|
||||||
|
{
|
||||||
|
super( turtle, TurtleAction.MOVE, player, world, pos );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired when a turtle attempts to place a block in the world.
|
||||||
|
*
|
||||||
|
* @see TurtleAction#PLACE
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public static class Place extends TurtleBlockEvent
|
||||||
|
{
|
||||||
|
private final ItemStack stack;
|
||||||
|
|
||||||
|
public Place( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull ItemStack stack )
|
||||||
|
{
|
||||||
|
super( turtle, TurtleAction.PLACE, player, world, pos );
|
||||||
|
|
||||||
|
Preconditions.checkNotNull( stack, "stack cannot be null" );
|
||||||
|
this.stack = stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the item stack that will be placed. This should not be modified.
|
||||||
|
*
|
||||||
|
* @return The item stack to be placed.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public ItemStack getStack()
|
||||||
|
{
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired when a turtle gathers data on a block in world.
|
||||||
|
*
|
||||||
|
* You may prevent blocks being inspected, or add additional information to the result.
|
||||||
|
*
|
||||||
|
* @see TurtleAction#INSPECT
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public static class Inspect extends TurtleBlockEvent
|
||||||
|
{
|
||||||
|
private final IBlockState 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 )
|
||||||
|
{
|
||||||
|
super( turtle, TurtleAction.INSPECT, player, world, pos );
|
||||||
|
|
||||||
|
Preconditions.checkNotNull( state, "state cannot be null" );
|
||||||
|
Preconditions.checkNotNull( data, "data cannot be null" );
|
||||||
|
this.data = data;
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block state which is being inspected.
|
||||||
|
*
|
||||||
|
* @return The inspected block state.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public IBlockState getState()
|
||||||
|
{
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the "inspection data" from this block, which will be returned to the user.
|
||||||
|
*
|
||||||
|
* @return This block's inspection data.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public Map<String, Object> getData()
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add new information to the inspection result. Note this will override fields with the same name.
|
||||||
|
*
|
||||||
|
* @param newData The data to add. Note all values should be convertable to Lua (see
|
||||||
|
* {@link dan200.computercraft.api.peripheral.IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}).
|
||||||
|
*/
|
||||||
|
public void addData( @Nonnull Map<String, ?> newData )
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull( newData, "newData cannot be null" );
|
||||||
|
data.putAll( newData );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.api.turtle.event;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class for all events concerning a turtle. This will only ever constructed and fired on the server side,
|
||||||
|
* so sever specific methods on {@link ITurtleAccess} are safe to use.
|
||||||
|
*
|
||||||
|
* You should generally not need to subscribe to this event, preferring one of the more specific classes.
|
||||||
|
*
|
||||||
|
* @see TurtleActionEvent
|
||||||
|
*/
|
||||||
|
public abstract class TurtleEvent extends Event
|
||||||
|
{
|
||||||
|
private final ITurtleAccess turtle;
|
||||||
|
|
||||||
|
protected TurtleEvent( @Nonnull ITurtleAccess turtle )
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull( turtle, "turtle cannot be null" );
|
||||||
|
this.turtle = turtle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the turtle which is performing this action.
|
||||||
|
*
|
||||||
|
* @return The access for this turtle.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public ITurtleAccess getTurtle()
|
||||||
|
{
|
||||||
|
return turtle;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,84 @@
|
|||||||
|
package dan200.computercraft.api.turtle.event;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||||
|
import net.minecraftforge.items.IItemHandler;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired when a turtle attempts to interact with an inventory.
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public abstract class TurtleInventoryEvent extends TurtleBlockEvent
|
||||||
|
{
|
||||||
|
private final IItemHandler handler;
|
||||||
|
|
||||||
|
protected TurtleInventoryEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable IItemHandler handler )
|
||||||
|
{
|
||||||
|
super( turtle, action, player, world, pos );
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the inventory being interacted with
|
||||||
|
*
|
||||||
|
* @return The inventory being interacted with, {@code null} if the item will be dropped to/sucked from the world.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public IItemHandler getItemHandler()
|
||||||
|
{
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired when a turtle attempts to suck from an inventory.
|
||||||
|
*
|
||||||
|
* @see TurtleAction#SUCK
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public static class Suck extends TurtleInventoryEvent
|
||||||
|
{
|
||||||
|
public Suck( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable IItemHandler handler )
|
||||||
|
{
|
||||||
|
super( turtle, TurtleAction.SUCK, player, world, pos, handler );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired when a turtle attempts to drop an item into an inventory.
|
||||||
|
*
|
||||||
|
* @see TurtleAction#DROP
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public static class Drop extends TurtleInventoryEvent
|
||||||
|
{
|
||||||
|
private final ItemStack stack;
|
||||||
|
|
||||||
|
public Drop( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable IItemHandler handler, @Nonnull ItemStack stack )
|
||||||
|
{
|
||||||
|
super( turtle, TurtleAction.DROP, player, world, pos, handler );
|
||||||
|
|
||||||
|
Preconditions.checkNotNull( stack, "stack cannot be null" );
|
||||||
|
this.stack = stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The item which will be inserted into the inventory/dropped on the ground.
|
||||||
|
*
|
||||||
|
* Note that this is a copy of the original stack, and so should not be modified, as that will have no effect.
|
||||||
|
*
|
||||||
|
* @return The item stack which will be dropped.
|
||||||
|
*/
|
||||||
|
public ItemStack getStack()
|
||||||
|
{
|
||||||
|
return stack.copy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.api.turtle.event;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action done by a turtle which is normally done by a player.
|
||||||
|
*
|
||||||
|
* {@link #getPlayer()} may be used to modify the player's attributes or perform permission checks.
|
||||||
|
*/
|
||||||
|
public abstract class TurtlePlayerEvent extends TurtleActionEvent
|
||||||
|
{
|
||||||
|
private final FakePlayer player;
|
||||||
|
|
||||||
|
protected TurtlePlayerEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player )
|
||||||
|
{
|
||||||
|
super( turtle, action );
|
||||||
|
|
||||||
|
Preconditions.checkNotNull( player, "player cannot be null" );
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fake player, representing this turtle.
|
||||||
|
*
|
||||||
|
* This may be used for triggering permission checks.
|
||||||
|
*
|
||||||
|
* @return A {@link FakePlayer} representing this turtle.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public FakePlayer getPlayer()
|
||||||
|
{
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@API(owner = "ComputerCraft", provides = "ComputerCraft|API|Turtle|Event", apiVersion = "${version}")
|
||||||
|
package dan200.computercraft.api.turtle.event;
|
||||||
|
|
||||||
|
import net.minecraftforge.fml.common.API;
|
@@ -33,7 +33,7 @@ public class GuiComputer extends GuiContainer
|
|||||||
private final int m_termHeight;
|
private final int m_termHeight;
|
||||||
private WidgetTerminal m_terminal;
|
private WidgetTerminal m_terminal;
|
||||||
|
|
||||||
protected GuiComputer( Container container, ComputerFamily family, IComputer computer, int termWidth, int termHeight )
|
public GuiComputer( Container container, ComputerFamily family, IComputer computer, int termWidth, int termHeight )
|
||||||
{
|
{
|
||||||
super( container );
|
super( container );
|
||||||
m_family = family;
|
m_family = family;
|
||||||
|
@@ -20,6 +20,7 @@ import net.minecraft.client.renderer.block.model.IBakedModel;
|
|||||||
import net.minecraft.client.renderer.block.model.ModelBakery;
|
import net.minecraft.client.renderer.block.model.ModelBakery;
|
||||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||||
import net.minecraft.client.renderer.color.IItemColor;
|
import net.minecraft.client.renderer.color.IItemColor;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureMap;
|
||||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||||
import net.minecraft.client.resources.IResourceManager;
|
import net.minecraft.client.resources.IResourceManager;
|
||||||
import net.minecraft.client.resources.SimpleReloadableResourceManager;
|
import net.minecraft.client.resources.SimpleReloadableResourceManager;
|
||||||
@@ -115,8 +116,23 @@ public class CCTurtleProxyClient extends CCTurtleProxyCommon
|
|||||||
MinecraftForge.EVENT_BUS.register( handlers );
|
MinecraftForge.EVENT_BUS.register( handlers );
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ForgeHandlers
|
public static class ForgeHandlers
|
||||||
{
|
{
|
||||||
|
private static final String[] TURTLE_UPGRADES = {
|
||||||
|
"turtle_modem_off_left",
|
||||||
|
"turtle_modem_on_left",
|
||||||
|
"turtle_modem_off_right",
|
||||||
|
"turtle_modem_on_right",
|
||||||
|
"turtle_crafting_table_left",
|
||||||
|
"turtle_crafting_table_right",
|
||||||
|
"advanced_turtle_modem_off_left",
|
||||||
|
"advanced_turtle_modem_on_left",
|
||||||
|
"advanced_turtle_modem_off_right",
|
||||||
|
"advanced_turtle_modem_on_right",
|
||||||
|
"turtle_speaker_upgrade_left",
|
||||||
|
"turtle_speaker_upgrade_right",
|
||||||
|
};
|
||||||
|
|
||||||
private TurtleSmartItemModel m_turtleSmartItemModel;
|
private TurtleSmartItemModel m_turtleSmartItemModel;
|
||||||
|
|
||||||
public ForgeHandlers()
|
public ForgeHandlers()
|
||||||
@@ -142,24 +158,27 @@ public class CCTurtleProxyClient extends CCTurtleProxyCommon
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onTextureStitchEvent( TextureStitchEvent.Pre event )
|
public void onTextureStitchEvent( TextureStitchEvent.Pre event )
|
||||||
{
|
{
|
||||||
event.getMap().registerSprite( new ResourceLocation( "computercraft", "blocks/crafty_upgrade" ) );
|
// Load all textures for upgrades
|
||||||
|
TextureMap map = event.getMap();
|
||||||
|
for( String upgrade : TURTLE_UPGRADES )
|
||||||
|
{
|
||||||
|
IModel model = ModelLoaderRegistry.getModelOrMissing( new ResourceLocation( "computercraft", "block/" + upgrade ) );
|
||||||
|
for( ResourceLocation texture : model.getTextures() )
|
||||||
|
{
|
||||||
|
map.registerSprite( texture );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onModelBakeEvent( ModelBakeEvent event )
|
public void onModelBakeEvent( ModelBakeEvent event )
|
||||||
{
|
{
|
||||||
loadModel( event, "turtle_modem_off_left" );
|
// Load all upgrade models
|
||||||
loadModel( event, "turtle_modem_on_left" );
|
for( String upgrade : TURTLE_UPGRADES )
|
||||||
loadModel( event, "turtle_modem_off_right" );
|
{
|
||||||
loadModel( event, "turtle_modem_on_right" );
|
loadModel( event, upgrade );
|
||||||
loadModel( event, "turtle_crafting_table_left" );
|
}
|
||||||
loadModel( event, "turtle_crafting_table_right" );
|
|
||||||
loadModel( event, "advanced_turtle_modem_off_left" );
|
|
||||||
loadModel( event, "advanced_turtle_modem_on_left" );
|
|
||||||
loadModel( event, "advanced_turtle_modem_off_right" );
|
|
||||||
loadModel( event, "advanced_turtle_modem_on_right" );
|
|
||||||
loadModel( event, "turtle_speaker_upgrade_left" );
|
|
||||||
loadModel( event, "turtle_speaker_upgrade_right" );
|
|
||||||
loadSmartModel( event, "turtle_dynamic", m_turtleSmartItemModel );
|
loadSmartModel( event, "turtle_dynamic", m_turtleSmartItemModel );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,13 +8,16 @@ package dan200.computercraft.client.proxy;
|
|||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.client.gui.*;
|
import dan200.computercraft.client.gui.*;
|
||||||
|
import dan200.computercraft.client.render.ItemPocketRenderer;
|
||||||
import dan200.computercraft.client.render.RenderOverlayCable;
|
import dan200.computercraft.client.render.RenderOverlayCable;
|
||||||
import dan200.computercraft.client.render.TileEntityCableRenderer;
|
import dan200.computercraft.client.render.TileEntityCableRenderer;
|
||||||
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
|
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
|
||||||
|
import dan200.computercraft.shared.command.ContainerViewComputer;
|
||||||
import dan200.computercraft.shared.computer.blocks.ComputerState;
|
import dan200.computercraft.shared.computer.blocks.ComputerState;
|
||||||
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
||||||
import dan200.computercraft.shared.computer.core.ClientComputer;
|
import dan200.computercraft.shared.computer.core.ClientComputer;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
|
import dan200.computercraft.shared.computer.core.IComputer;
|
||||||
import dan200.computercraft.shared.computer.items.ItemComputer;
|
import dan200.computercraft.shared.computer.items.ItemComputer;
|
||||||
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
|
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
|
||||||
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
|
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
|
||||||
@@ -22,6 +25,7 @@ import dan200.computercraft.shared.media.items.ItemPrintout;
|
|||||||
import dan200.computercraft.shared.network.ComputerCraftPacket;
|
import dan200.computercraft.shared.network.ComputerCraftPacket;
|
||||||
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
|
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
|
||||||
import dan200.computercraft.shared.peripheral.modem.TileCable;
|
import dan200.computercraft.shared.peripheral.modem.TileCable;
|
||||||
|
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||||
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
||||||
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
|
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
|
||||||
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
|
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
|
||||||
@@ -32,7 +36,6 @@ import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera;
|
|||||||
import dan200.computercraft.shared.util.Colour;
|
import dan200.computercraft.shared.util.Colour;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
|
||||||
import net.minecraft.client.renderer.ItemMeshDefinition;
|
import net.minecraft.client.renderer.ItemMeshDefinition;
|
||||||
import net.minecraft.client.renderer.block.model.ModelBakery;
|
import net.minecraft.client.renderer.block.model.ModelBakery;
|
||||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||||
@@ -54,6 +57,7 @@ import net.minecraftforge.client.event.RenderHandEvent;
|
|||||||
import net.minecraftforge.client.event.RenderPlayerEvent;
|
import net.minecraftforge.client.event.RenderPlayerEvent;
|
||||||
import net.minecraftforge.client.model.ModelLoader;
|
import net.minecraftforge.client.model.ModelLoader;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
import net.minecraftforge.fml.client.registry.ClientRegistry;
|
import net.minecraftforge.fml.client.registry.ClientRegistry;
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||||
@@ -112,6 +116,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
|||||||
registerItemModel( ComputerCraft.Blocks.commandComputer, "command_computer" );
|
registerItemModel( ComputerCraft.Blocks.commandComputer, "command_computer" );
|
||||||
registerItemModel( ComputerCraft.Blocks.advancedModem, "advanced_modem" );
|
registerItemModel( ComputerCraft.Blocks.advancedModem, "advanced_modem" );
|
||||||
registerItemModel( ComputerCraft.Blocks.peripheral, 5, "speaker" );
|
registerItemModel( ComputerCraft.Blocks.peripheral, 5, "speaker" );
|
||||||
|
registerItemModel( ComputerCraft.Blocks.wiredModemFull, "wired_modem_full" );
|
||||||
|
|
||||||
registerItemModel( ComputerCraft.Items.disk, "disk" );
|
registerItemModel( ComputerCraft.Items.disk, "disk" );
|
||||||
registerItemModel( ComputerCraft.Items.diskExpanded, "disk_expanded" );
|
registerItemModel( ComputerCraft.Items.diskExpanded, "disk_expanded" );
|
||||||
@@ -293,12 +298,6 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
|||||||
return m_renderFrame;
|
return m_renderFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteDisplayLists( int list, int range )
|
|
||||||
{
|
|
||||||
GlStateManager.glDeleteLists( list, range );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getFixedWidthFontRenderer()
|
public Object getFixedWidthFontRenderer()
|
||||||
{
|
{
|
||||||
@@ -363,6 +362,13 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getComputerGUI( IComputer computer, int width, int height, ComputerFamily family )
|
||||||
|
{
|
||||||
|
ContainerViewComputer container = new ContainerViewComputer( computer );
|
||||||
|
return new GuiComputer( container, family, computer, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getWorldDir( World world )
|
public File getWorldDir( World world )
|
||||||
{
|
{
|
||||||
@@ -454,6 +460,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
|||||||
ForgeHandlers handlers = new ForgeHandlers();
|
ForgeHandlers handlers = new ForgeHandlers();
|
||||||
MinecraftForge.EVENT_BUS.register( handlers );
|
MinecraftForge.EVENT_BUS.register( handlers );
|
||||||
MinecraftForge.EVENT_BUS.register( new RenderOverlayCable() );
|
MinecraftForge.EVENT_BUS.register( new RenderOverlayCable() );
|
||||||
|
MinecraftForge.EVENT_BUS.register( new ItemPocketRenderer() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ForgeHandlers
|
public class ForgeHandlers
|
||||||
@@ -540,6 +547,15 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
|
|||||||
m_renderFrame++;
|
m_renderFrame++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onWorldUnload( WorldEvent.Unload event )
|
||||||
|
{
|
||||||
|
if( event.getWorld().isRemote )
|
||||||
|
{
|
||||||
|
ClientMonitor.destroyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
|
@@ -0,0 +1,264 @@
|
|||||||
|
package dan200.computercraft.client.render;
|
||||||
|
|
||||||
|
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
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.pocket.items.ItemPocketComputer;
|
||||||
|
import dan200.computercraft.shared.util.Palette;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.ItemRenderer;
|
||||||
|
import net.minecraft.client.renderer.RenderItem;
|
||||||
|
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||||
|
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureManager;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureMap;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraft.util.EnumHandSide;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraftforge.client.ForgeHooksClient;
|
||||||
|
import net.minecraftforge.client.event.RenderSpecificHandEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||||
|
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emulates map rendering for pocket computers
|
||||||
|
*/
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public class ItemPocketRenderer
|
||||||
|
{
|
||||||
|
@SubscribeEvent
|
||||||
|
public void renderItem( RenderSpecificHandEvent event )
|
||||||
|
{
|
||||||
|
ItemStack stack = event.getItemStack();
|
||||||
|
if( !(stack.getItem() instanceof ItemPocketComputer) ) return;
|
||||||
|
|
||||||
|
event.setCanceled( true );
|
||||||
|
|
||||||
|
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||||
|
|
||||||
|
GlStateManager.pushMatrix();
|
||||||
|
if( event.getHand() == EnumHand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() )
|
||||||
|
{
|
||||||
|
renderItemFirstCentre(
|
||||||
|
event.getInterpolatedPitch(),
|
||||||
|
event.getEquipProgress(),
|
||||||
|
event.getSwingProgress(),
|
||||||
|
stack
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
renderItemFirstPersonSide(
|
||||||
|
event.getHand() == EnumHand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(),
|
||||||
|
event.getEquipProgress(),
|
||||||
|
event.getSwingProgress(),
|
||||||
|
stack
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GlStateManager.popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main rendering method for pocket computers and their associated terminal
|
||||||
|
*
|
||||||
|
* @param stack The stack to render
|
||||||
|
* @see ItemRenderer#renderMapFirstPerson(ItemStack)
|
||||||
|
*/
|
||||||
|
private void renderPocketComputerItem( ItemStack stack )
|
||||||
|
{
|
||||||
|
// Setup various transformations. Note that these are partially adapated from the corresponding method
|
||||||
|
// in ItemRenderer
|
||||||
|
GlStateManager.disableLighting();
|
||||||
|
|
||||||
|
GlStateManager.rotate( 180f, 0f, 1f, 0f );
|
||||||
|
GlStateManager.rotate( 180f, 0f, 0f, 1f );
|
||||||
|
GlStateManager.scale( 0.5, 0.5, 0.5 );
|
||||||
|
|
||||||
|
ItemPocketComputer pocketComputer = ComputerCraft.Items.pocketComputer;
|
||||||
|
ClientComputer computer = pocketComputer.createClientComputer( stack );
|
||||||
|
|
||||||
|
{
|
||||||
|
// First render the background item. We use the item's model rather than a direct texture as this ensures
|
||||||
|
// we display the pocket light and other such decorations.
|
||||||
|
GlStateManager.pushMatrix();
|
||||||
|
|
||||||
|
GlStateManager.scale( 1.0f, -1.0f, 1.0f );
|
||||||
|
|
||||||
|
Minecraft minecraft = Minecraft.getMinecraft();
|
||||||
|
TextureManager textureManager = minecraft.getTextureManager();
|
||||||
|
RenderItem renderItem = minecraft.getRenderItem();
|
||||||
|
|
||||||
|
// Copy of RenderItem#renderItemModelIntoGUI but without the translation or scaling
|
||||||
|
textureManager.bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
|
||||||
|
textureManager.getTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ).setBlurMipmap( false, false );
|
||||||
|
|
||||||
|
GlStateManager.enableRescaleNormal();
|
||||||
|
GlStateManager.enableAlpha();
|
||||||
|
GlStateManager.alphaFunc( GL11.GL_GREATER, 0.1F );
|
||||||
|
GlStateManager.enableBlend();
|
||||||
|
GlStateManager.blendFunc( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA );
|
||||||
|
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
|
||||||
|
|
||||||
|
IBakedModel bakedmodel = renderItem.getItemModelWithOverrides( stack, null, null );
|
||||||
|
bakedmodel = ForgeHooksClient.handleCameraTransforms( bakedmodel, ItemCameraTransforms.TransformType.GUI, false );
|
||||||
|
renderItem.renderItem( stack, bakedmodel );
|
||||||
|
|
||||||
|
GlStateManager.disableAlpha();
|
||||||
|
GlStateManager.disableRescaleNormal();
|
||||||
|
|
||||||
|
GlStateManager.popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've a computer and terminal then attempt to render it.
|
||||||
|
if( computer != null )
|
||||||
|
{
|
||||||
|
Terminal terminal = computer.getTerminal();
|
||||||
|
if( terminal != null )
|
||||||
|
{
|
||||||
|
synchronized( terminal )
|
||||||
|
{
|
||||||
|
GlStateManager.pushMatrix();
|
||||||
|
GlStateManager.disableDepth();
|
||||||
|
|
||||||
|
// Reset the position to be at the top left corner of the pocket computer
|
||||||
|
// Note we translate towards the screen slightly too.
|
||||||
|
GlStateManager.translate( -8 / 16.0, -8 / 16.0, 0.5 / 16.0 );
|
||||||
|
// Translate to the top left of the screen.
|
||||||
|
GlStateManager.translate( 4 / 16.0, 3 / 16.0, 0 );
|
||||||
|
|
||||||
|
// Work out the scaling required to resize the terminal in order to fit on the computer
|
||||||
|
final int margin = 2;
|
||||||
|
int tw = terminal.getWidth();
|
||||||
|
int th = terminal.getHeight();
|
||||||
|
int width = tw * FONT_WIDTH + margin * 2;
|
||||||
|
int height = th * FONT_HEIGHT + margin * 2;
|
||||||
|
int max = Math.max( height, width );
|
||||||
|
|
||||||
|
// The grid is 8 * 8 wide, so we start with a base of 1/2 (8 / 16).
|
||||||
|
double scale = 1.0 / 2.0 / max;
|
||||||
|
GlStateManager.scale( scale, scale, scale );
|
||||||
|
|
||||||
|
// The margin/start positions are determined in order for the terminal to be centred.
|
||||||
|
int startX = (max - width) / 2 + margin;
|
||||||
|
int startY = (max - height) / 2 + margin;
|
||||||
|
|
||||||
|
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer();
|
||||||
|
boolean greyscale = !computer.isColour();
|
||||||
|
Palette palette = terminal.getPalette();
|
||||||
|
|
||||||
|
// Render the actual text
|
||||||
|
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, startX, startY + line * FONT_HEIGHT,
|
||||||
|
colour, backgroundColour, margin, margin, greyscale, palette
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// And render the cursor;
|
||||||
|
int tx = terminal.getCursorX(), ty = terminal.getCursorY();
|
||||||
|
if( terminal.getCursorBlink() && ComputerCraft.getGlobalCursorBlink() &&
|
||||||
|
tx >= 0 && ty >= 0 && tx < tw && ty < th )
|
||||||
|
{
|
||||||
|
TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 );
|
||||||
|
fontRenderer.drawString(
|
||||||
|
new TextBuffer( '_', 1 ), startX + FONT_WIDTH * tx, startY + FONT_HEIGHT * ty,
|
||||||
|
cursorColour, null, 0, 0, greyscale, palette
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlStateManager.enableDepth();
|
||||||
|
GlStateManager.popMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GlStateManager.enableLighting();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a pocket computer to one side of the player.
|
||||||
|
*
|
||||||
|
* @param side The side to render on
|
||||||
|
* @param equipProgress The equip progress of this item
|
||||||
|
* @param swingProgress The swing progress of this item
|
||||||
|
* @param stack The stack to render
|
||||||
|
* @see ItemRenderer#renderMapFirstPersonSide(float, EnumHandSide, float, ItemStack)
|
||||||
|
*/
|
||||||
|
private void renderItemFirstPersonSide( EnumHandSide side, float equipProgress, float swingProgress, ItemStack stack )
|
||||||
|
{
|
||||||
|
Minecraft minecraft = Minecraft.getMinecraft();
|
||||||
|
float offset = side == EnumHandSide.RIGHT ? 1f : -1f;
|
||||||
|
GlStateManager.translate( offset * 0.125f, -0.125f, 0f );
|
||||||
|
|
||||||
|
// If the player is not invisible then render a single arm
|
||||||
|
if( !minecraft.player.isInvisible() )
|
||||||
|
{
|
||||||
|
GlStateManager.pushMatrix();
|
||||||
|
GlStateManager.rotate( offset * 10f, 0f, 0f, 1f );
|
||||||
|
minecraft.getItemRenderer().renderArmFirstPerson( equipProgress, swingProgress, side );
|
||||||
|
GlStateManager.popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the appropriate transformations. This is just copied from the
|
||||||
|
// corresponding method in ItemRenderer.
|
||||||
|
GlStateManager.pushMatrix();
|
||||||
|
GlStateManager.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
|
||||||
|
float f1 = MathHelper.sqrt( swingProgress );
|
||||||
|
float f2 = MathHelper.sin( f1 * (float) Math.PI );
|
||||||
|
float f3 = -0.5f * f2;
|
||||||
|
float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) );
|
||||||
|
float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI );
|
||||||
|
GlStateManager.translate( offset * f3, f4 - 0.3f * f2, f5 );
|
||||||
|
GlStateManager.rotate( f2 * -45f, 1f, 0f, 0f );
|
||||||
|
GlStateManager.rotate( offset * f2 * -30f, 0f, 1f, 0f );
|
||||||
|
|
||||||
|
renderPocketComputerItem( stack );
|
||||||
|
|
||||||
|
GlStateManager.popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render an item in the middle of the screen
|
||||||
|
*
|
||||||
|
* @param pitch The pitch of the player
|
||||||
|
* @param equipProgress The equip progress of this item
|
||||||
|
* @param swingProgress The swing progress of this item
|
||||||
|
* @param stack The stack to render
|
||||||
|
* @see ItemRenderer#renderMapFirstPerson(float, float, float)
|
||||||
|
*/
|
||||||
|
private void renderItemFirstCentre( float pitch, float equipProgress, float swingProgress, ItemStack stack )
|
||||||
|
{
|
||||||
|
ItemRenderer itemRenderer = Minecraft.getMinecraft().getItemRenderer();
|
||||||
|
|
||||||
|
// Setup the appropriate transformations. This is just copied from the
|
||||||
|
// corresponding method in ItemRenderer.
|
||||||
|
float swingRt = MathHelper.sqrt( swingProgress );
|
||||||
|
float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI );
|
||||||
|
float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI );
|
||||||
|
GlStateManager.translate( 0f, -tX / 2f, tZ );
|
||||||
|
float pitchAngle = itemRenderer.getMapAngleFromPitch( pitch );
|
||||||
|
GlStateManager.translate( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
|
||||||
|
GlStateManager.rotate( pitchAngle * -85f, 1f, 0f, 0f );
|
||||||
|
itemRenderer.renderArms();
|
||||||
|
float rX = MathHelper.sin( swingRt * (float) Math.PI );
|
||||||
|
GlStateManager.rotate( rX * 20f, 1f, 0f, 0f );
|
||||||
|
GlStateManager.scale( 2f, 2f, 2f );
|
||||||
|
|
||||||
|
renderPocketComputerItem( stack );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,264 @@
|
|||||||
|
package dan200.computercraft.client.render;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
|
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
|
||||||
|
import net.minecraftforge.client.model.pipeline.LightUtil;
|
||||||
|
import net.minecraftforge.client.model.pipeline.VertexTransformer;
|
||||||
|
import net.minecraftforge.common.model.TRSRTransformation;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.vecmath.Matrix4f;
|
||||||
|
import javax.vecmath.Point3f;
|
||||||
|
import javax.vecmath.Vector3f;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms vertices of a model, remaining aware of winding order, and rearranging
|
||||||
|
* vertices if needed.
|
||||||
|
*/
|
||||||
|
public final class ModelTransformer
|
||||||
|
{
|
||||||
|
private static final Matrix4f identity;
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
identity = new Matrix4f();
|
||||||
|
identity.setIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelTransformer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void transformQuadsTo( List<BakedQuad> output, List<BakedQuad> input, Matrix4f transform )
|
||||||
|
{
|
||||||
|
if( transform == null || transform.equals( identity ) )
|
||||||
|
{
|
||||||
|
output.addAll( input );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Matrix4f normalMatrix = new Matrix4f( transform );
|
||||||
|
normalMatrix.invert();
|
||||||
|
normalMatrix.transpose();
|
||||||
|
|
||||||
|
for( BakedQuad quad : input ) output.add( doTransformQuad( quad, transform, normalMatrix ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BakedQuad transformQuad( BakedQuad input, Matrix4f transform )
|
||||||
|
{
|
||||||
|
if( transform == null || transform.equals( identity ) ) return input;
|
||||||
|
|
||||||
|
Matrix4f normalMatrix = new Matrix4f( transform );
|
||||||
|
normalMatrix.invert();
|
||||||
|
normalMatrix.transpose();
|
||||||
|
return doTransformQuad( input, transform, normalMatrix );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BakedQuad doTransformQuad( BakedQuad input, Matrix4f positionMatrix, Matrix4f normalMatrix )
|
||||||
|
{
|
||||||
|
|
||||||
|
BakedQuadBuilder builder = new BakedQuadBuilder( input.getFormat() );
|
||||||
|
NormalAwareTransformer transformer = new NormalAwareTransformer( builder, positionMatrix, normalMatrix );
|
||||||
|
input.pipe( transformer );
|
||||||
|
|
||||||
|
if( transformer.areNormalsInverted() )
|
||||||
|
{
|
||||||
|
builder.swap( 1, 3 );
|
||||||
|
transformer.areNormalsInverted();
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A vertex transformer that tracks whether the normals have been inverted and so the vertices
|
||||||
|
* should be reordered so backface culling works as expected.
|
||||||
|
*/
|
||||||
|
private static class NormalAwareTransformer extends VertexTransformer
|
||||||
|
{
|
||||||
|
private final Matrix4f positionMatrix;
|
||||||
|
private final Matrix4f normalMatrix;
|
||||||
|
|
||||||
|
private int vertexIndex = 0, elementIndex = 0;
|
||||||
|
private final Point3f[] before = new Point3f[ 4 ];
|
||||||
|
private final Point3f[] after = new Point3f[ 4 ];
|
||||||
|
|
||||||
|
public NormalAwareTransformer( IVertexConsumer parent, Matrix4f positionMatrix, Matrix4f normalMatrix )
|
||||||
|
{
|
||||||
|
super( parent );
|
||||||
|
this.positionMatrix = positionMatrix;
|
||||||
|
this.normalMatrix = normalMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setQuadOrientation( EnumFacing orientation )
|
||||||
|
{
|
||||||
|
super.setQuadOrientation( orientation == null ? orientation : TRSRTransformation.rotate( positionMatrix, orientation ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put( int element, @Nonnull float... data )
|
||||||
|
{
|
||||||
|
switch( getVertexFormat().getElement( element ).getUsage() )
|
||||||
|
{
|
||||||
|
case POSITION:
|
||||||
|
{
|
||||||
|
Point3f vec = new Point3f( data );
|
||||||
|
Point3f newVec = new Point3f();
|
||||||
|
positionMatrix.transform( vec, newVec );
|
||||||
|
|
||||||
|
float[] newData = new float[ 4 ];
|
||||||
|
newVec.get( newData );
|
||||||
|
super.put( element, newData );
|
||||||
|
|
||||||
|
|
||||||
|
before[ vertexIndex ] = vec;
|
||||||
|
after[ vertexIndex ] = newVec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NORMAL:
|
||||||
|
{
|
||||||
|
Vector3f vec = new Vector3f( data );
|
||||||
|
normalMatrix.transform( vec );
|
||||||
|
|
||||||
|
float[] newData = new float[ 4 ];
|
||||||
|
vec.get( newData );
|
||||||
|
super.put( element, newData );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
super.put( element, data );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
elementIndex++;
|
||||||
|
if( elementIndex == getVertexFormat().getElementCount() )
|
||||||
|
{
|
||||||
|
vertexIndex++;
|
||||||
|
elementIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean areNormalsInverted()
|
||||||
|
{
|
||||||
|
Vector3f temp1 = new Vector3f(), temp2 = new Vector3f();
|
||||||
|
Vector3f crossBefore = new Vector3f(), crossAfter = new Vector3f();
|
||||||
|
|
||||||
|
// Determine what cross product we expect to have
|
||||||
|
temp1.sub( before[ 1 ], before[ 0 ] );
|
||||||
|
temp2.sub( before[ 1 ], before[ 2 ] );
|
||||||
|
crossBefore.cross( temp1, temp2 );
|
||||||
|
normalMatrix.transform( crossBefore );
|
||||||
|
|
||||||
|
// And determine what cross product we actually have
|
||||||
|
temp1.sub( after[ 1 ], after[ 0 ] );
|
||||||
|
temp2.sub( after[ 1 ], after[ 2 ] );
|
||||||
|
crossAfter.cross( temp1, temp2 );
|
||||||
|
|
||||||
|
// If the angle between expected and actual cross product is greater than
|
||||||
|
// pi/2 radians then we will need to reorder our quads.
|
||||||
|
return Math.abs( crossBefore.angle( crossAfter ) ) >= Math.PI / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A vertex consumer which is capable of building {@link BakedQuad}s.
|
||||||
|
*
|
||||||
|
* Equivalent to {@link net.minecraftforge.client.model.pipeline.UnpackedBakedQuad.Builder} but more memory
|
||||||
|
* efficient.
|
||||||
|
*
|
||||||
|
* This also provides the ability to swap vertices through {@link #swap(int, int)} to allow reordering.
|
||||||
|
*/
|
||||||
|
private static class BakedQuadBuilder implements IVertexConsumer
|
||||||
|
{
|
||||||
|
private final VertexFormat format;
|
||||||
|
|
||||||
|
private final int[] vertexData;
|
||||||
|
private int vertexIndex = 0, elementIndex = 0;
|
||||||
|
|
||||||
|
private EnumFacing orientation;
|
||||||
|
private int quadTint;
|
||||||
|
private boolean diffuse;
|
||||||
|
private TextureAtlasSprite texture;
|
||||||
|
|
||||||
|
private BakedQuadBuilder( VertexFormat format )
|
||||||
|
{
|
||||||
|
this.format = format;
|
||||||
|
this.vertexData = new int[ format.getNextOffset() ];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public VertexFormat getVertexFormat()
|
||||||
|
{
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setQuadTint( int tint )
|
||||||
|
{
|
||||||
|
this.quadTint = tint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setQuadOrientation( @Nonnull EnumFacing orientation )
|
||||||
|
{
|
||||||
|
this.orientation = orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplyDiffuseLighting( boolean diffuse )
|
||||||
|
{
|
||||||
|
this.diffuse = diffuse;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTexture( @Nonnull TextureAtlasSprite texture )
|
||||||
|
{
|
||||||
|
this.texture = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put( int element, @Nonnull float... data )
|
||||||
|
{
|
||||||
|
LightUtil.pack( data, vertexData, format, vertexIndex, element );
|
||||||
|
|
||||||
|
elementIndex++;
|
||||||
|
if( elementIndex == getVertexFormat().getElementCount() )
|
||||||
|
{
|
||||||
|
vertexIndex++;
|
||||||
|
elementIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void swap( int a, int b )
|
||||||
|
{
|
||||||
|
int length = vertexData.length / 4;
|
||||||
|
for( int i = 0; i < length; i++ )
|
||||||
|
{
|
||||||
|
int temp = vertexData[ a * length + i ];
|
||||||
|
vertexData[ a * length + i ] = vertexData[ b * length + i ];
|
||||||
|
vertexData[ b * length + i ] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BakedQuad build()
|
||||||
|
{
|
||||||
|
if( elementIndex != 0 || vertexIndex != 4 )
|
||||||
|
{
|
||||||
|
throw new IllegalStateException( "Got an unexpected number of elements/vertices" );
|
||||||
|
}
|
||||||
|
if( texture == null )
|
||||||
|
{
|
||||||
|
throw new IllegalStateException( "Texture has not been set" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BakedQuad( vertexData, quadTint, orientation, texture, diffuse, format );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -54,8 +54,6 @@ public class RenderOverlayCable
|
|||||||
GlStateManager.depthMask( false );
|
GlStateManager.depthMask( false );
|
||||||
GlStateManager.pushMatrix();
|
GlStateManager.pushMatrix();
|
||||||
|
|
||||||
EnumFacing direction = type != PeripheralType.Cable ? cable.getDirection() : null;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
EntityPlayer player = event.getPlayer();
|
EntityPlayer player = event.getPlayer();
|
||||||
double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks();
|
double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks();
|
||||||
@@ -78,7 +76,7 @@ public class RenderOverlayCable
|
|||||||
|
|
||||||
for( EnumFacing facing : EnumFacing.VALUES )
|
for( EnumFacing facing : EnumFacing.VALUES )
|
||||||
{
|
{
|
||||||
if( direction == facing || BlockCable.isCable( world, pos.offset( facing ) ) )
|
if( BlockCable.doesConnectVisually( state, world, pos, facing ) )
|
||||||
{
|
{
|
||||||
flags |= 1 << facing.ordinal();
|
flags |= 1 << facing.ordinal();
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ import dan200.computercraft.ComputerCraft;
|
|||||||
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
import dan200.computercraft.core.terminal.TextBuffer;
|
import dan200.computercraft.core.terminal.TextBuffer;
|
||||||
import dan200.computercraft.shared.common.ClientTerminal;
|
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||||
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
||||||
import dan200.computercraft.shared.util.Colour;
|
import dan200.computercraft.shared.util.Colour;
|
||||||
import dan200.computercraft.shared.util.DirectionUtil;
|
import dan200.computercraft.shared.util.DirectionUtil;
|
||||||
@@ -43,24 +43,22 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
private void renderMonitorAt( TileMonitor monitor, double posX, double posY, double posZ, float f, int i )
|
private void renderMonitorAt( TileMonitor monitor, double posX, double posY, double posZ, float f, int i )
|
||||||
{
|
{
|
||||||
// Render from the origin monitor
|
// Render from the origin monitor
|
||||||
TileMonitor origin = monitor.getOrigin();
|
ClientMonitor originTerminal = monitor.getClientMonitor();
|
||||||
if( origin == null )
|
|
||||||
{
|
if( originTerminal == null ) return;
|
||||||
return;
|
TileMonitor origin = originTerminal.getOrigin();
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure each monitor is rendered only once
|
// Ensure each monitor is rendered only once
|
||||||
long renderFrame = ComputerCraft.getRenderFrame();
|
long renderFrame = ComputerCraft.getRenderFrame();
|
||||||
if( origin.m_lastRenderFrame == renderFrame )
|
if( originTerminal.lastRenderFrame == renderFrame )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
origin.m_lastRenderFrame = renderFrame;
|
originTerminal.lastRenderFrame = renderFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean redraw = origin.pollChanged();
|
|
||||||
BlockPos monitorPos = monitor.getPos();
|
BlockPos monitorPos = monitor.getPos();
|
||||||
BlockPos originPos = origin.getPos();
|
BlockPos originPos = origin.getPos();
|
||||||
posX += originPos.getX() - monitorPos.getX();
|
posX += originPos.getX() - monitorPos.getX();
|
||||||
@@ -94,9 +92,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
BufferBuilder renderer = tessellator.getBuffer();
|
BufferBuilder renderer = tessellator.getBuffer();
|
||||||
|
|
||||||
// Get terminal
|
// Get terminal
|
||||||
ClientTerminal clientTerminal = (ClientTerminal)origin.getTerminal();
|
boolean redraw = originTerminal.pollTerminalChanged();
|
||||||
Terminal terminal = (clientTerminal != null) ? clientTerminal.getTerminal() : null;
|
|
||||||
redraw = redraw || (clientTerminal != null && clientTerminal.hasTerminalChanged());
|
|
||||||
|
|
||||||
// Draw the contents
|
// Draw the contents
|
||||||
GlStateManager.depthMask( false );
|
GlStateManager.depthMask( false );
|
||||||
@@ -104,24 +100,25 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
mc.entityRenderer.disableLightmap();
|
mc.entityRenderer.disableLightmap();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Terminal terminal = originTerminal.getTerminal();
|
||||||
if( terminal != null )
|
if( terminal != null )
|
||||||
{
|
{
|
||||||
Palette palette = terminal.getPalette();
|
Palette palette = terminal.getPalette();
|
||||||
|
|
||||||
// Allocate display lists
|
// Allocate display lists
|
||||||
if( origin.m_renderDisplayList < 0 )
|
if( originTerminal.renderDisplayLists == null )
|
||||||
{
|
{
|
||||||
origin.m_renderDisplayList = GlStateManager.glGenLists( 3 );
|
originTerminal.createLists();
|
||||||
redraw = true;
|
redraw = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw a terminal
|
// Draw a terminal
|
||||||
boolean greyscale = !clientTerminal.isColour();
|
boolean greyscale = !originTerminal.isColour();
|
||||||
int width = terminal.getWidth();
|
int width = terminal.getWidth();
|
||||||
int height = terminal.getHeight();
|
int height = terminal.getHeight();
|
||||||
int cursorX = terminal.getCursorX();
|
int cursorX = terminal.getCursorX();
|
||||||
int cursorY = terminal.getCursorY();
|
int cursorY = terminal.getCursorY();
|
||||||
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer)ComputerCraft.getFixedWidthFontRenderer();
|
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer();
|
||||||
|
|
||||||
GlStateManager.pushMatrix();
|
GlStateManager.pushMatrix();
|
||||||
try
|
try
|
||||||
@@ -135,7 +132,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
if( redraw )
|
if( redraw )
|
||||||
{
|
{
|
||||||
// Build background display list
|
// Build background display list
|
||||||
GlStateManager.glNewList( origin.m_renderDisplayList, GL11.GL_COMPILE );
|
GlStateManager.glNewList( originTerminal.renderDisplayLists[0], GL11.GL_COMPILE );
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
double marginXSize = TileMonitor.RENDER_MARGIN / xScale;
|
double marginXSize = TileMonitor.RENDER_MARGIN / xScale;
|
||||||
@@ -149,7 +146,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
GlStateManager.scale( 1.0, marginSquash, 1.0 );
|
GlStateManager.scale( 1.0, marginSquash, 1.0 );
|
||||||
GlStateManager.translate( 0.0, -marginYSize / marginSquash, 0.0 );
|
GlStateManager.translate( 0.0, -marginYSize / marginSquash, 0.0 );
|
||||||
fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( 0 ), marginXSize, marginXSize, greyscale, palette );
|
fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( 0 ), marginXSize, marginXSize, greyscale, palette );
|
||||||
GlStateManager.translate( 0.0, ( marginYSize + height * FixedWidthFontRenderer.FONT_HEIGHT ) / marginSquash, 0.0 );
|
GlStateManager.translate( 0.0, (marginYSize + height * FixedWidthFontRenderer.FONT_HEIGHT) / marginSquash, 0.0 );
|
||||||
fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( height - 1 ), marginXSize, marginXSize, greyscale, palette );
|
fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( height - 1 ), marginXSize, marginXSize, greyscale, palette );
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -174,7 +171,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
GlStateManager.glEndList();
|
GlStateManager.glEndList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GlStateManager.callList( origin.m_renderDisplayList );
|
GlStateManager.callList( originTerminal.renderDisplayLists[0] );
|
||||||
GlStateManager.resetColor();
|
GlStateManager.resetColor();
|
||||||
|
|
||||||
// Draw text
|
// Draw text
|
||||||
@@ -182,7 +179,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
if( redraw )
|
if( redraw )
|
||||||
{
|
{
|
||||||
// Build text display list
|
// Build text display list
|
||||||
GlStateManager.glNewList( origin.m_renderDisplayList + 1, GL11.GL_COMPILE );
|
GlStateManager.glNewList( originTerminal.renderDisplayLists[1], GL11.GL_COMPILE );
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Lines
|
// Lines
|
||||||
@@ -202,7 +199,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
GlStateManager.glEndList();
|
GlStateManager.glEndList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GlStateManager.callList( origin.m_renderDisplayList + 1 );
|
GlStateManager.callList( originTerminal.renderDisplayLists[1] );
|
||||||
GlStateManager.resetColor();
|
GlStateManager.resetColor();
|
||||||
|
|
||||||
// Draw cursor
|
// Draw cursor
|
||||||
@@ -210,7 +207,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
if( redraw )
|
if( redraw )
|
||||||
{
|
{
|
||||||
// Build cursor display list
|
// Build cursor display list
|
||||||
GlStateManager.glNewList( origin.m_renderDisplayList + 2, GL11.GL_COMPILE );
|
GlStateManager.glNewList( originTerminal.renderDisplayLists[2], GL11.GL_COMPILE );
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Cursor
|
// Cursor
|
||||||
@@ -236,7 +233,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
|||||||
}
|
}
|
||||||
if( ComputerCraft.getGlobalCursorBlink() )
|
if( ComputerCraft.getGlobalCursorBlink() )
|
||||||
{
|
{
|
||||||
GlStateManager.callList( origin.m_renderDisplayList + 2 );
|
GlStateManager.callList( originTerminal.renderDisplayLists[2] );
|
||||||
GlStateManager.resetColor();
|
GlStateManager.resetColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,6 @@ package dan200.computercraft.client.render;
|
|||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.core.IComputer;
|
|
||||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||||
import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera;
|
import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera;
|
||||||
import dan200.computercraft.shared.util.Holiday;
|
import dan200.computercraft.shared.util.Holiday;
|
||||||
@@ -121,18 +120,22 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
|
|||||||
GlStateManager.translate( posX + offset.x, posY + offset.y, posZ + offset.z );
|
GlStateManager.translate( posX + offset.x, posY + offset.y, posZ + offset.z );
|
||||||
|
|
||||||
// Render the label
|
// Render the label
|
||||||
IComputer computer = turtle.getComputer();
|
String label = turtle.createProxy().getLabel();
|
||||||
String label = (computer != null) ? computer.getLabel() : null;
|
|
||||||
if( label != null )
|
if( label != null )
|
||||||
{
|
{
|
||||||
renderLabel( turtle.getAccess().getPosition(), label );
|
renderLabel( turtle.getAccess().getPosition(), label );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the turtle
|
// Render the turtle
|
||||||
GlStateManager.translate( 0.5f, 0.0f, 0.5f );
|
GlStateManager.translate( 0.5f, 0.5f, 0.5f );
|
||||||
GlStateManager.rotate( 180.0f - yaw, 0.0f, 1.0f, 0.0f );
|
GlStateManager.rotate( 180.0f - yaw, 0.0f, 1.0f, 0.0f );
|
||||||
GlStateManager.translate( -0.5f, 0.0f, -0.5f );
|
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.cullFace( GlStateManager.CullFace.FRONT );
|
||||||
|
}
|
||||||
|
GlStateManager.translate( -0.5f, -0.5f, -0.5f );
|
||||||
// Render the turtle
|
// Render the turtle
|
||||||
int colour;
|
int colour;
|
||||||
ComputerFamily family;
|
ComputerFamily family;
|
||||||
@@ -172,6 +175,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
GlStateManager.popMatrix();
|
GlStateManager.popMatrix();
|
||||||
|
GlStateManager.cullFace( GlStateManager.CullFace.BACK );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,13 +6,10 @@ import net.minecraft.client.renderer.block.model.IBakedModel;
|
|||||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
|
||||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.vecmath.Matrix4f;
|
import javax.vecmath.Matrix4f;
|
||||||
import javax.vecmath.Point3f;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -20,16 +17,17 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class TurtleMultiModel implements IBakedModel
|
public class TurtleMultiModel implements IBakedModel
|
||||||
{
|
{
|
||||||
private IBakedModel m_baseModel;
|
private final IBakedModel m_baseModel;
|
||||||
private IBakedModel m_overlayModel;
|
private final IBakedModel m_overlayModel;
|
||||||
private IBakedModel m_leftUpgradeModel;
|
private final Matrix4f m_generalTransform;
|
||||||
private Matrix4f m_leftUpgradeTransform;
|
private final IBakedModel m_leftUpgradeModel;
|
||||||
private IBakedModel m_rightUpgradeModel;
|
private final Matrix4f m_leftUpgradeTransform;
|
||||||
private Matrix4f m_rightUpgradeTransform;
|
private final IBakedModel m_rightUpgradeModel;
|
||||||
|
private final Matrix4f m_rightUpgradeTransform;
|
||||||
private List<BakedQuad> m_generalQuads;
|
private List<BakedQuad> m_generalQuads;
|
||||||
private Map<EnumFacing, List<BakedQuad>> m_faceQuads;
|
private Map<EnumFacing, List<BakedQuad>> m_faceQuads;
|
||||||
|
|
||||||
public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, IBakedModel leftUpgradeModel, Matrix4f leftUpgradeTransform, IBakedModel rightUpgradeModel, Matrix4f rightUpgradeTransform )
|
public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, Matrix4f generalTransform, IBakedModel leftUpgradeModel, Matrix4f leftUpgradeTransform, IBakedModel rightUpgradeModel, Matrix4f rightUpgradeTransform )
|
||||||
{
|
{
|
||||||
// Get the models
|
// Get the models
|
||||||
m_baseModel = baseModel;
|
m_baseModel = baseModel;
|
||||||
@@ -38,6 +36,7 @@ public class TurtleMultiModel implements IBakedModel
|
|||||||
m_leftUpgradeTransform = leftUpgradeTransform;
|
m_leftUpgradeTransform = leftUpgradeTransform;
|
||||||
m_rightUpgradeModel = rightUpgradeModel;
|
m_rightUpgradeModel = rightUpgradeModel;
|
||||||
m_rightUpgradeTransform = rightUpgradeTransform;
|
m_rightUpgradeTransform = rightUpgradeTransform;
|
||||||
|
m_generalTransform = generalTransform;
|
||||||
m_generalQuads = null;
|
m_generalQuads = null;
|
||||||
m_faceQuads = new HashMap<>();
|
m_faceQuads = new HashMap<>();
|
||||||
}
|
}
|
||||||
@@ -48,51 +47,52 @@ public class TurtleMultiModel implements IBakedModel
|
|||||||
{
|
{
|
||||||
if( side != null )
|
if( side != null )
|
||||||
{
|
{
|
||||||
if( !m_faceQuads.containsKey( side ) )
|
if( !m_faceQuads.containsKey( side ) ) m_faceQuads.put( side, buildQuads( state, side, rand ) );
|
||||||
{
|
|
||||||
ArrayList<BakedQuad> quads = new ArrayList<>();
|
|
||||||
if( m_overlayModel != null )
|
|
||||||
{
|
|
||||||
quads.addAll( m_overlayModel.getQuads( state, side, rand ) );
|
|
||||||
}
|
|
||||||
if( m_leftUpgradeModel != null )
|
|
||||||
{
|
|
||||||
quads.addAll( transformQuads( m_leftUpgradeModel.getQuads( state, side, rand ), m_leftUpgradeTransform ) );
|
|
||||||
}
|
|
||||||
if( m_rightUpgradeModel != null )
|
|
||||||
{
|
|
||||||
quads.addAll( transformQuads( m_rightUpgradeModel.getQuads( state, side, rand ), m_rightUpgradeTransform ) );
|
|
||||||
}
|
|
||||||
quads.trimToSize();
|
|
||||||
m_faceQuads.put( side, quads );
|
|
||||||
}
|
|
||||||
return m_faceQuads.get( side );
|
return m_faceQuads.get( side );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( m_generalQuads == null )
|
if( m_generalQuads == null ) m_generalQuads = buildQuads( state, side, rand );
|
||||||
{
|
|
||||||
ArrayList<BakedQuad> quads = new ArrayList<>();
|
|
||||||
quads.addAll( m_baseModel.getQuads( state, side, rand ) );
|
|
||||||
if( m_overlayModel != null )
|
|
||||||
{
|
|
||||||
quads.addAll( m_overlayModel.getQuads( state, side, rand ) );
|
|
||||||
}
|
|
||||||
if( m_leftUpgradeModel != null )
|
|
||||||
{
|
|
||||||
quads.addAll( transformQuads( m_leftUpgradeModel.getQuads( state, side, rand ), m_leftUpgradeTransform ) );
|
|
||||||
}
|
|
||||||
if( m_rightUpgradeModel != null )
|
|
||||||
{
|
|
||||||
quads.addAll( transformQuads( m_rightUpgradeModel.getQuads( state, side, rand ), m_rightUpgradeTransform ) );
|
|
||||||
}
|
|
||||||
quads.trimToSize();
|
|
||||||
m_generalQuads = quads;
|
|
||||||
}
|
|
||||||
return m_generalQuads;
|
return m_generalQuads;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<BakedQuad> buildQuads( IBlockState state, EnumFacing side, long rand )
|
||||||
|
{
|
||||||
|
ArrayList<BakedQuad> quads = new ArrayList<>();
|
||||||
|
ModelTransformer.transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand ), 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 );
|
||||||
|
}
|
||||||
|
if( m_leftUpgradeModel != null )
|
||||||
|
{
|
||||||
|
Matrix4f upgradeTransform = m_generalTransform;
|
||||||
|
if( m_leftUpgradeTransform != null )
|
||||||
|
{
|
||||||
|
upgradeTransform = new Matrix4f( m_generalTransform );
|
||||||
|
upgradeTransform.mul( m_leftUpgradeTransform );
|
||||||
|
}
|
||||||
|
ModelTransformer.transformQuadsTo( quads, m_leftUpgradeModel.getQuads( state, side, rand ), upgradeTransform );
|
||||||
|
}
|
||||||
|
if( m_rightUpgradeModel != null )
|
||||||
|
{
|
||||||
|
Matrix4f upgradeTransform = m_generalTransform;
|
||||||
|
if( m_rightUpgradeTransform != null )
|
||||||
|
{
|
||||||
|
upgradeTransform = new Matrix4f( m_generalTransform );
|
||||||
|
upgradeTransform.mul( m_rightUpgradeTransform );
|
||||||
|
}
|
||||||
|
ModelTransformer.transformQuadsTo( quads, m_rightUpgradeModel.getQuads( state, side, rand ), upgradeTransform );
|
||||||
|
}
|
||||||
|
quads.trimToSize();
|
||||||
|
return quads;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAmbientOcclusion()
|
public boolean isAmbientOcclusion()
|
||||||
{
|
{
|
||||||
@@ -132,63 +132,4 @@ public class TurtleMultiModel implements IBakedModel
|
|||||||
{
|
{
|
||||||
return ItemOverrideList.NONE;
|
return ItemOverrideList.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<BakedQuad> transformQuads( List<BakedQuad> input, Matrix4f transform )
|
|
||||||
{
|
|
||||||
if( transform == null || input.size() == 0 )
|
|
||||||
{
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
List<BakedQuad> output = new ArrayList<>( input.size() );
|
|
||||||
for( BakedQuad quad : input )
|
|
||||||
{
|
|
||||||
output.add( transformQuad( quad, transform ) );
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private BakedQuad transformQuad( BakedQuad quad, Matrix4f transform )
|
|
||||||
{
|
|
||||||
int[] vertexData = quad.getVertexData().clone();
|
|
||||||
int offset = 0;
|
|
||||||
BakedQuad copy = new BakedQuad( vertexData, -1, quad.getFace(), quad.getSprite(), quad.shouldApplyDiffuseLighting(), quad.getFormat() );
|
|
||||||
VertexFormat format = copy.getFormat();
|
|
||||||
for( int i=0; i<format.getElementCount(); ++i ) // For each vertex element
|
|
||||||
{
|
|
||||||
VertexFormatElement element = format.getElement( i );
|
|
||||||
if( element.isPositionElement() &&
|
|
||||||
element.getType() == VertexFormatElement.EnumType.FLOAT &&
|
|
||||||
element.getElementCount() == 3 ) // When we find a position element
|
|
||||||
{
|
|
||||||
for( int j=0; j<4; ++j ) // For each corner of the quad
|
|
||||||
{
|
|
||||||
int start = offset + j * format.getNextOffset();
|
|
||||||
if( (start % 4) == 0 )
|
|
||||||
{
|
|
||||||
start = start / 4;
|
|
||||||
|
|
||||||
// Extract the position
|
|
||||||
Point3f pos = new Point3f(
|
|
||||||
Float.intBitsToFloat( vertexData[ start ] ),
|
|
||||||
Float.intBitsToFloat( vertexData[ start + 1 ] ),
|
|
||||||
Float.intBitsToFloat( vertexData[ start + 2 ] )
|
|
||||||
);
|
|
||||||
|
|
||||||
// Transform the position
|
|
||||||
transform.transform( pos );
|
|
||||||
|
|
||||||
// Insert the position
|
|
||||||
vertexData[ start ] = Float.floatToRawIntBits( pos.x );
|
|
||||||
vertexData[ start + 1 ] = Float.floatToRawIntBits( pos.y );
|
|
||||||
vertexData[ start + 2 ] = Float.floatToRawIntBits( pos.z );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offset += element.getSize();
|
|
||||||
}
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -35,6 +35,19 @@ import java.util.List;
|
|||||||
|
|
||||||
public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReloadListener
|
public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReloadListener
|
||||||
{
|
{
|
||||||
|
private static final Matrix4f s_identity, s_flip;
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
s_identity = new Matrix4f();
|
||||||
|
s_identity.setIdentity();
|
||||||
|
|
||||||
|
s_flip = new Matrix4f();
|
||||||
|
s_flip.setIdentity();
|
||||||
|
s_flip.m11 = -1; // Flip on the y axis
|
||||||
|
s_flip.m13 = 1; // Models go from (0,0,0) to (1,1,1), so push back up.
|
||||||
|
}
|
||||||
|
|
||||||
private static class TurtleModelCombination
|
private static class TurtleModelCombination
|
||||||
{
|
{
|
||||||
public final ComputerFamily m_family;
|
public final ComputerFamily m_family;
|
||||||
@@ -43,8 +56,9 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
|
|||||||
public final ITurtleUpgrade m_rightUpgrade;
|
public final ITurtleUpgrade m_rightUpgrade;
|
||||||
public final ResourceLocation m_overlay;
|
public final ResourceLocation m_overlay;
|
||||||
public final boolean m_christmas;
|
public final boolean m_christmas;
|
||||||
|
public final boolean m_flip;
|
||||||
|
|
||||||
public TurtleModelCombination( ComputerFamily family, boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas )
|
public TurtleModelCombination( ComputerFamily family, boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas, boolean flip )
|
||||||
{
|
{
|
||||||
m_family = family;
|
m_family = family;
|
||||||
m_colour = colour;
|
m_colour = colour;
|
||||||
@@ -52,22 +66,26 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
|
|||||||
m_rightUpgrade = rightUpgrade;
|
m_rightUpgrade = rightUpgrade;
|
||||||
m_overlay = overlay;
|
m_overlay = overlay;
|
||||||
m_christmas = christmas;
|
m_christmas = christmas;
|
||||||
|
m_flip = flip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals( Object other )
|
public boolean equals( Object other )
|
||||||
{
|
{
|
||||||
if( other == this ) {
|
if( other == this )
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if( other instanceof TurtleModelCombination ) {
|
if( other instanceof TurtleModelCombination )
|
||||||
TurtleModelCombination otherCombo = (TurtleModelCombination)other;
|
{
|
||||||
|
TurtleModelCombination otherCombo = (TurtleModelCombination) other;
|
||||||
if( otherCombo.m_family == m_family &&
|
if( otherCombo.m_family == m_family &&
|
||||||
otherCombo.m_colour == m_colour &&
|
otherCombo.m_colour == m_colour &&
|
||||||
otherCombo.m_leftUpgrade == m_leftUpgrade &&
|
otherCombo.m_leftUpgrade == m_leftUpgrade &&
|
||||||
otherCombo.m_rightUpgrade == m_rightUpgrade &&
|
otherCombo.m_rightUpgrade == m_rightUpgrade &&
|
||||||
Objects.equal( otherCombo.m_overlay, m_overlay ) &&
|
Objects.equal( otherCombo.m_overlay, m_overlay ) &&
|
||||||
otherCombo.m_christmas == m_christmas )
|
otherCombo.m_christmas == m_christmas &&
|
||||||
|
otherCombo.m_flip == m_flip )
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -86,10 +104,11 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
|
|||||||
result = prime * result + (m_rightUpgrade != null ? m_rightUpgrade.hashCode() : 0);
|
result = prime * result + (m_rightUpgrade != null ? m_rightUpgrade.hashCode() : 0);
|
||||||
result = prime * result + (m_overlay != null ? m_overlay.hashCode() : 0);
|
result = prime * result + (m_overlay != null ? m_overlay.hashCode() : 0);
|
||||||
result = prime * result + (m_christmas ? 1 : 0);
|
result = prime * result + (m_christmas ? 1 : 0);
|
||||||
|
result = prime * result + (m_flip ? 1 : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<TurtleModelCombination, IBakedModel> m_cachedModels;
|
private HashMap<TurtleModelCombination, IBakedModel> m_cachedModels;
|
||||||
private ItemOverrideList m_overrides;
|
private ItemOverrideList m_overrides;
|
||||||
private final TurtleModelCombination m_defaultCombination;
|
private final TurtleModelCombination m_defaultCombination;
|
||||||
@@ -97,12 +116,12 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
|
|||||||
public TurtleSmartItemModel()
|
public TurtleSmartItemModel()
|
||||||
{
|
{
|
||||||
m_cachedModels = new HashMap<>();
|
m_cachedModels = new HashMap<>();
|
||||||
m_defaultCombination = new TurtleModelCombination( ComputerFamily.Normal, false, null, null, null, false );
|
m_defaultCombination = new TurtleModelCombination( ComputerFamily.Normal, false, null, null, null, false, false );
|
||||||
m_overrides = new ItemOverrideList( new ArrayList<>() )
|
m_overrides = new ItemOverrideList( new ArrayList<>() )
|
||||||
{
|
{
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public IBakedModel handleItemState( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity)
|
public IBakedModel handleItemState( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity )
|
||||||
{
|
{
|
||||||
ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem();
|
ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem();
|
||||||
ComputerFamily family = turtle.getFamily( stack );
|
ComputerFamily family = turtle.getFamily( stack );
|
||||||
@@ -111,7 +130,9 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
|
|||||||
ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.Right );
|
ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.Right );
|
||||||
ResourceLocation overlay = turtle.getOverlay( stack );
|
ResourceLocation overlay = turtle.getOverlay( stack );
|
||||||
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.Christmas;
|
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.Christmas;
|
||||||
TurtleModelCombination combo = new TurtleModelCombination( family, colour != -1, leftUpgrade, rightUpgrade, overlay, christmas );
|
String label = turtle.getLabel( stack );
|
||||||
|
boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" ));
|
||||||
|
TurtleModelCombination combo = new TurtleModelCombination( family, colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
|
||||||
if( m_cachedModels.containsKey( combo ) )
|
if( m_cachedModels.containsKey( combo ) )
|
||||||
{
|
{
|
||||||
return m_cachedModels.get( combo );
|
return m_cachedModels.get( combo );
|
||||||
@@ -146,28 +167,25 @@ public class TurtleSmartItemModel implements IBakedModel, IResourceManagerReload
|
|||||||
ModelResourceLocation baseModelLocation = TileEntityTurtleRenderer.getTurtleModel( combo.m_family, combo.m_colour );
|
ModelResourceLocation baseModelLocation = TileEntityTurtleRenderer.getTurtleModel( combo.m_family, combo.m_colour );
|
||||||
ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.m_family, combo.m_overlay, combo.m_christmas );
|
ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.m_family, combo.m_overlay, combo.m_christmas );
|
||||||
IBakedModel baseModel = modelManager.getModel( baseModelLocation );
|
IBakedModel baseModel = modelManager.getModel( baseModelLocation );
|
||||||
IBakedModel overlayModel = (overlayModelLocation != null) ? modelManager.getModel( baseModelLocation ) : null;
|
IBakedModel overlayModel = (overlayModelLocation != null) ? modelManager.getModel( overlayModelLocation ) : null;
|
||||||
|
Matrix4f transform = combo.m_flip ? s_flip : s_identity;
|
||||||
Pair<IBakedModel, Matrix4f> leftModel = (combo.m_leftUpgrade != null) ? combo.m_leftUpgrade.getModel( null, TurtleSide.Left ) : null;
|
Pair<IBakedModel, Matrix4f> leftModel = (combo.m_leftUpgrade != null) ? combo.m_leftUpgrade.getModel( null, TurtleSide.Left ) : null;
|
||||||
Pair<IBakedModel, Matrix4f> rightModel = (combo.m_rightUpgrade != null) ? combo.m_rightUpgrade.getModel( null, TurtleSide.Right ) : null;
|
Pair<IBakedModel, Matrix4f> rightModel = (combo.m_rightUpgrade != null) ? combo.m_rightUpgrade.getModel( null, TurtleSide.Right ) : null;
|
||||||
if( leftModel != null && rightModel != null )
|
if( leftModel != null && rightModel != null )
|
||||||
{
|
{
|
||||||
return new TurtleMultiModel( baseModel, overlayModel, leftModel.getLeft(), leftModel.getRight(), rightModel.getLeft(), rightModel.getRight() );
|
return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel.getLeft(), leftModel.getRight(), rightModel.getLeft(), rightModel.getRight() );
|
||||||
}
|
}
|
||||||
else if( leftModel != null )
|
else if( leftModel != null )
|
||||||
{
|
{
|
||||||
return new TurtleMultiModel( baseModel, overlayModel, leftModel.getLeft(), leftModel.getRight(), null, null );
|
return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel.getLeft(), leftModel.getRight(), null, null );
|
||||||
}
|
}
|
||||||
else if( rightModel != null )
|
else if( rightModel != null )
|
||||||
{
|
{
|
||||||
return new TurtleMultiModel( baseModel, overlayModel, null, null, rightModel.getLeft(), rightModel.getRight() );
|
return new TurtleMultiModel( baseModel, overlayModel, transform, null, null, rightModel.getLeft(), rightModel.getRight() );
|
||||||
}
|
|
||||||
else if( overlayModel != null )
|
|
||||||
{
|
|
||||||
return new TurtleMultiModel( baseModel, overlayModel, null, null, null, null );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return baseModel;
|
return new TurtleMultiModel( baseModel, overlayModel, transform, null, null, null, null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.core.apis;
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.ILuaObject;
|
import dan200.computercraft.api.lua.ILuaObject;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
@@ -100,21 +101,6 @@ public class BufferAPI implements ILuaAPI
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startup()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void advance( double _dt )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shutdown()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String[] getMethodNames()
|
public String[] getMethodNames()
|
||||||
|
155
src/main/java/dan200/computercraft/core/apis/ComputerAccess.java
Normal file
155
src/main/java/dan200/computercraft/core/apis/ComputerAccess.java
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
|
import dan200.computercraft.core.filesystem.FileSystem;
|
||||||
|
import dan200.computercraft.core.filesystem.FileSystemException;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public abstract class ComputerAccess implements IComputerAccess
|
||||||
|
{
|
||||||
|
private final IAPIEnvironment m_environment;
|
||||||
|
private final Set<String> m_mounts = new HashSet<>();
|
||||||
|
|
||||||
|
protected ComputerAccess( IAPIEnvironment m_environment )
|
||||||
|
{
|
||||||
|
this.m_environment = m_environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unmountAll()
|
||||||
|
{
|
||||||
|
FileSystem fileSystem = m_environment.getFileSystem();
|
||||||
|
for( String m_mount : m_mounts )
|
||||||
|
{
|
||||||
|
fileSystem.unmount( m_mount );
|
||||||
|
}
|
||||||
|
m_mounts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String mount( @Nonnull String desiredLoc, @Nonnull IMount mount )
|
||||||
|
{
|
||||||
|
return mount( desiredLoc, mount, getAttachmentName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName )
|
||||||
|
{
|
||||||
|
// Mount the location
|
||||||
|
String location;
|
||||||
|
FileSystem fileSystem = m_environment.getFileSystem();
|
||||||
|
if( fileSystem == null )
|
||||||
|
{
|
||||||
|
throw new IllegalStateException( "File system has not been created" );
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized( fileSystem )
|
||||||
|
{
|
||||||
|
location = findFreeLocation( desiredLoc );
|
||||||
|
if( location != null )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fileSystem.mount( driveName, location, mount );
|
||||||
|
}
|
||||||
|
catch( FileSystemException ignored )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( location != null )
|
||||||
|
{
|
||||||
|
m_mounts.add( location );
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount )
|
||||||
|
{
|
||||||
|
return mountWritable( desiredLoc, mount, getAttachmentName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName )
|
||||||
|
{
|
||||||
|
// Mount the location
|
||||||
|
String location;
|
||||||
|
FileSystem fileSystem = m_environment.getFileSystem();
|
||||||
|
if( fileSystem == null )
|
||||||
|
{
|
||||||
|
throw new IllegalStateException( "File system has not been created" );
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized( fileSystem )
|
||||||
|
{
|
||||||
|
location = findFreeLocation( desiredLoc );
|
||||||
|
if( location != null )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fileSystem.mountWritable( driveName, location, mount );
|
||||||
|
}
|
||||||
|
catch( FileSystemException ignored )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( location != null )
|
||||||
|
{
|
||||||
|
m_mounts.add( location );
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unmount( String location )
|
||||||
|
{
|
||||||
|
if( location != null )
|
||||||
|
{
|
||||||
|
if( !m_mounts.contains( location ) )
|
||||||
|
{
|
||||||
|
throw new RuntimeException( "You didn't mount this location" );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_environment.getFileSystem().unmount( location );
|
||||||
|
m_mounts.remove( location );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getID()
|
||||||
|
{
|
||||||
|
return m_environment.getComputerID();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void queueEvent( @Nonnull final String event, final Object[] arguments )
|
||||||
|
{
|
||||||
|
m_environment.queueEvent( event, arguments );
|
||||||
|
}
|
||||||
|
|
||||||
|
private String findFreeLocation( String desiredLoc )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileSystem fileSystem = m_environment.getFileSystem();
|
||||||
|
if( !fileSystem.exists( desiredLoc ) )
|
||||||
|
{
|
||||||
|
return desiredLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We used to check foo2,foo3,foo4,etc here
|
||||||
|
// but the disk drive does this itself now
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.core.apis;
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.core.apis.handles.BinaryInputHandle;
|
import dan200.computercraft.core.apis.handles.BinaryInputHandle;
|
||||||
@@ -48,11 +49,6 @@ public class FSAPI implements ILuaAPI
|
|||||||
m_fileSystem = m_env.getFileSystem();
|
m_fileSystem = m_env.getFileSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void advance( double _dt )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutdown( )
|
public void shutdown( )
|
||||||
{
|
{
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
package dan200.computercraft.core.apis;
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.core.apis.http.*;
|
import dan200.computercraft.core.apis.http.*;
|
||||||
@@ -43,12 +44,7 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startup( )
|
public void update()
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void advance( double _dt )
|
|
||||||
{
|
{
|
||||||
// Wait for all of our http requests
|
// Wait for all of our http requests
|
||||||
synchronized( m_httpTasks )
|
synchronized( m_httpTasks )
|
||||||
|
@@ -1,17 +1,16 @@
|
|||||||
/*
|
|
||||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
|
||||||
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
|
|
||||||
* Send enquiries to dratcliffe@gmail.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
package dan200.computercraft.core.apis;
|
package dan200.computercraft.core.apis;
|
||||||
import dan200.computercraft.api.lua.ILuaObject;
|
|
||||||
|
|
||||||
public interface ILuaAPI extends ILuaObject
|
/**
|
||||||
|
* This exists purely to ensure binary compatibility.
|
||||||
|
*
|
||||||
|
* @see dan200.computercraft.api.lua.ILuaAPI
|
||||||
|
*/
|
||||||
|
public interface ILuaAPI extends dan200.computercraft.api.lua.ILuaAPI
|
||||||
{
|
{
|
||||||
String[] getNames();
|
void advance( double v );
|
||||||
|
|
||||||
void startup(); // LT
|
default void update()
|
||||||
void advance( double _dt ); // MT
|
{
|
||||||
void shutdown(); // LT
|
advance( 0.05 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.core.apis;
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.shared.util.StringUtil;
|
import dan200.computercraft.shared.util.StringUtil;
|
||||||
@@ -102,7 +103,7 @@ public class OSAPI implements ILuaAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void advance( double dt )
|
public void update()
|
||||||
{
|
{
|
||||||
synchronized( m_timers )
|
synchronized( m_timers )
|
||||||
{
|
{
|
||||||
|
@@ -8,24 +8,26 @@ package dan200.computercraft.core.apis;
|
|||||||
|
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.computer.Computer;
|
import dan200.computercraft.core.computer.Computer;
|
||||||
import dan200.computercraft.core.computer.ComputerThread;
|
import dan200.computercraft.core.computer.ComputerThread;
|
||||||
import dan200.computercraft.core.computer.ITask;
|
import dan200.computercraft.core.computer.ITask;
|
||||||
import dan200.computercraft.core.filesystem.FileSystem;
|
|
||||||
import dan200.computercraft.core.filesystem.FileSystemException;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
||||||
|
|
||||||
public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener
|
public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener
|
||||||
{
|
{
|
||||||
private class PeripheralWrapper implements IComputerAccess
|
private class PeripheralWrapper extends ComputerAccess
|
||||||
{
|
{
|
||||||
private final String m_side;
|
private final String m_side;
|
||||||
private final IPeripheral m_peripheral;
|
private final IPeripheral m_peripheral;
|
||||||
@@ -35,10 +37,9 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
private Map<String, Integer> m_methodMap;
|
private Map<String, Integer> m_methodMap;
|
||||||
private boolean m_attached;
|
private boolean m_attached;
|
||||||
|
|
||||||
private Set<String> m_mounts;
|
|
||||||
|
|
||||||
public PeripheralWrapper( IPeripheral peripheral, String side )
|
public PeripheralWrapper( IPeripheral peripheral, String side )
|
||||||
{
|
{
|
||||||
|
super(m_environment);
|
||||||
m_side = side;
|
m_side = side;
|
||||||
m_peripheral = peripheral;
|
m_peripheral = peripheral;
|
||||||
m_attached = false;
|
m_attached = false;
|
||||||
@@ -54,8 +55,6 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
m_methodMap.put( m_methods[i], i );
|
m_methodMap.put( m_methods[i], i );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_mounts = new HashSet<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPeripheral getPeripheral()
|
public IPeripheral getPeripheral()
|
||||||
@@ -91,14 +90,11 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
|
|
||||||
synchronized( this )
|
synchronized( this )
|
||||||
{
|
{
|
||||||
m_attached = false;
|
|
||||||
// Unmount everything the detach function forgot to do
|
// Unmount everything the detach function forgot to do
|
||||||
for( String m_mount : m_mounts )
|
unmountAll();
|
||||||
{
|
|
||||||
m_fileSystem.unmount( m_mount );
|
|
||||||
}
|
|
||||||
m_mounts.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_attached = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object[] call( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException
|
public Object[] call( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException
|
||||||
@@ -122,13 +118,6 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IComputerAccess implementation
|
// IComputerAccess implementation
|
||||||
|
|
||||||
@Override
|
|
||||||
public String mount( @Nonnull String desiredLoc, @Nonnull IMount mount )
|
|
||||||
{
|
|
||||||
return mount( desiredLoc, mount, m_side );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName )
|
public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName )
|
||||||
{
|
{
|
||||||
@@ -137,31 +126,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
throw new RuntimeException( "You are not attached to this Computer" );
|
throw new RuntimeException( "You are not attached to this Computer" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount the location
|
return super.mount( desiredLoc, mount, driveName );
|
||||||
String location;
|
|
||||||
synchronized( m_fileSystem )
|
|
||||||
{
|
|
||||||
location = findFreeLocation( desiredLoc );
|
|
||||||
if( location != null )
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
m_fileSystem.mount( driveName, location, mount );
|
|
||||||
} catch( FileSystemException e ) {
|
|
||||||
// fail and return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( location != null )
|
|
||||||
{
|
|
||||||
m_mounts.add( location );
|
|
||||||
}
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount )
|
|
||||||
{
|
|
||||||
return mountWritable( desiredLoc, mount, m_side );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -172,76 +137,93 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
throw new RuntimeException( "You are not attached to this Computer" );
|
throw new RuntimeException( "You are not attached to this Computer" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount the location
|
return super.mountWritable( desiredLoc, mount, driveName );
|
||||||
String location;
|
|
||||||
synchronized( m_fileSystem )
|
|
||||||
{
|
|
||||||
location = findFreeLocation( desiredLoc );
|
|
||||||
if( location != null )
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
m_fileSystem.mountWritable( driveName, location, mount );
|
|
||||||
} catch( FileSystemException e ) {
|
|
||||||
// fail and return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( location != null )
|
|
||||||
{
|
|
||||||
m_mounts.add( location );
|
|
||||||
}
|
|
||||||
return location;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void unmount( String location )
|
public synchronized void unmount( String location )
|
||||||
{
|
{
|
||||||
if( !m_attached ) {
|
if( !m_attached )
|
||||||
|
{
|
||||||
throw new RuntimeException( "You are not attached to this Computer" );
|
throw new RuntimeException( "You are not attached to this Computer" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( location != null )
|
super.unmount( location );
|
||||||
{
|
|
||||||
if( !m_mounts.contains( location ) ) {
|
|
||||||
throw new RuntimeException( "You didn't mount this location" );
|
|
||||||
}
|
|
||||||
|
|
||||||
m_fileSystem.unmount( location );
|
|
||||||
m_mounts.remove( location );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getID()
|
public int getID()
|
||||||
{
|
{
|
||||||
if( !m_attached ) {
|
if( !m_attached )
|
||||||
|
{
|
||||||
throw new RuntimeException( "You are not attached to this Computer" );
|
throw new RuntimeException( "You are not attached to this Computer" );
|
||||||
}
|
}
|
||||||
return m_environment.getComputerID();
|
return super.getID();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void queueEvent( @Nonnull final String event, final Object[] arguments )
|
public void queueEvent( @Nonnull final String event, final Object[] arguments )
|
||||||
{
|
{
|
||||||
if( !m_attached ) {
|
if( !m_attached )
|
||||||
|
{
|
||||||
throw new RuntimeException( "You are not attached to this Computer" );
|
throw new RuntimeException( "You are not attached to this Computer" );
|
||||||
}
|
}
|
||||||
m_environment.queueEvent( event, arguments );
|
super.queueEvent( event, arguments );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getAttachmentName()
|
public String getAttachmentName()
|
||||||
{
|
{
|
||||||
if( !m_attached ) {
|
if( !m_attached )
|
||||||
|
{
|
||||||
throw new RuntimeException( "You are not attached to this Computer" );
|
throw new RuntimeException( "You are not attached to this Computer" );
|
||||||
}
|
}
|
||||||
return m_side;
|
return m_side;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Map<String, IPeripheral> getAvailablePeripherals()
|
||||||
|
{
|
||||||
|
if( !m_attached )
|
||||||
|
{
|
||||||
|
throw new RuntimeException( "You are not attached to this Computer" );
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, IPeripheral> peripherals = new HashMap<>();
|
||||||
|
for( PeripheralWrapper wrapper : m_peripherals )
|
||||||
|
{
|
||||||
|
if( wrapper != null && wrapper.isAttached() )
|
||||||
|
{
|
||||||
|
peripherals.put( wrapper.getAttachmentName(), wrapper.getPeripheral() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableMap( peripherals );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IPeripheral getAvailablePeripheral( @Nonnull String name )
|
||||||
|
{
|
||||||
|
if( !m_attached )
|
||||||
|
{
|
||||||
|
throw new RuntimeException( "You are not attached to this Computer" );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( PeripheralWrapper wrapper : m_peripherals )
|
||||||
|
{
|
||||||
|
if( wrapper != null && wrapper.isAttached() && wrapper.getAttachmentName().equals( name ) )
|
||||||
|
{
|
||||||
|
return wrapper.getPeripheral();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final IAPIEnvironment m_environment;
|
private final IAPIEnvironment m_environment;
|
||||||
private FileSystem m_fileSystem;
|
|
||||||
private final PeripheralWrapper[] m_peripherals;
|
private final PeripheralWrapper[] m_peripherals;
|
||||||
private boolean m_running;
|
private boolean m_running;
|
||||||
|
|
||||||
@@ -343,7 +325,6 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
{
|
{
|
||||||
synchronized( m_peripherals )
|
synchronized( m_peripherals )
|
||||||
{
|
{
|
||||||
m_fileSystem = m_environment.getFileSystem();
|
|
||||||
m_running = true;
|
m_running = true;
|
||||||
for( int i=0; i<6; ++i )
|
for( int i=0; i<6; ++i )
|
||||||
{
|
{
|
||||||
@@ -356,11 +337,6 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void advance( double _dt )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutdown( )
|
public void shutdown( )
|
||||||
{
|
{
|
||||||
@@ -375,7 +351,6 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
wrapper.detach();
|
wrapper.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_fileSystem = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,25 +479,4 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String findFreeLocation( String desiredLoc )
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
synchronized( m_fileSystem )
|
|
||||||
{
|
|
||||||
if( !m_fileSystem.exists( desiredLoc ) )
|
|
||||||
{
|
|
||||||
return desiredLoc;
|
|
||||||
}
|
|
||||||
// We used to check foo2,foo3,foo4,etc here
|
|
||||||
// but the disk drive does this itself now
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch( FileSystemException e )
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.core.apis;
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.core.computer.Computer;
|
import dan200.computercraft.core.computer.Computer;
|
||||||
@@ -33,21 +34,6 @@ public class RedstoneAPI implements ILuaAPI
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startup( )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void advance( double _dt )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shutdown( )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String[] getMethodNames()
|
public String[] getMethodNames()
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.core.apis;
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.core.computer.IComputerEnvironment;
|
import dan200.computercraft.core.computer.IComputerEnvironment;
|
||||||
@@ -36,21 +37,6 @@ public class TermAPI implements ILuaAPI
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startup( )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void advance( double _dt )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shutdown( )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String[] getMethodNames()
|
public String[] getMethodNames()
|
||||||
|
@@ -8,16 +8,21 @@ package dan200.computercraft.core.computer;
|
|||||||
|
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.filesystem.IFileSystem;
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
|
import dan200.computercraft.api.lua.*;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.apis.*;
|
import dan200.computercraft.core.apis.*;
|
||||||
import dan200.computercraft.core.filesystem.FileSystem;
|
import dan200.computercraft.core.filesystem.FileSystem;
|
||||||
import dan200.computercraft.core.filesystem.FileSystemException;
|
import dan200.computercraft.core.filesystem.FileSystemException;
|
||||||
import dan200.computercraft.core.lua.ILuaMachine;
|
|
||||||
import dan200.computercraft.core.lua.CobaltLuaMachine;
|
import dan200.computercraft.core.lua.CobaltLuaMachine;
|
||||||
|
import dan200.computercraft.core.lua.ILuaMachine;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -173,7 +178,91 @@ public class Computer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class ComputerSystem extends ComputerAccess implements IComputerSystem
|
||||||
|
{
|
||||||
|
private final IAPIEnvironment m_environment;
|
||||||
|
|
||||||
|
private ComputerSystem( IAPIEnvironment m_environment )
|
||||||
|
{
|
||||||
|
super( m_environment );
|
||||||
|
this.m_environment = m_environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getAttachmentName()
|
||||||
|
{
|
||||||
|
return "computer";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IFileSystem getFileSystem()
|
||||||
|
{
|
||||||
|
FileSystem fs = m_environment.getFileSystem();
|
||||||
|
return fs == null ? null : fs.getMountWrapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getLabel()
|
||||||
|
{
|
||||||
|
return m_environment.getLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class APIWrapper implements ILuaAPI
|
||||||
|
{
|
||||||
|
private final ILuaAPI delegate;
|
||||||
|
private final ComputerSystem system;
|
||||||
|
|
||||||
|
private APIWrapper( ILuaAPI delegate, ComputerSystem system )
|
||||||
|
{
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.system = system;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getNames()
|
||||||
|
{
|
||||||
|
return delegate.getNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startup()
|
||||||
|
{
|
||||||
|
delegate.startup();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update()
|
||||||
|
{
|
||||||
|
delegate.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown()
|
||||||
|
{
|
||||||
|
delegate.shutdown();
|
||||||
|
system.unmountAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String[] getMethodNames()
|
||||||
|
{
|
||||||
|
return delegate.getMethodNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
|
||||||
|
{
|
||||||
|
return delegate.callMethod( context, method, arguments );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static IMount s_romMount = null;
|
private static IMount s_romMount = null;
|
||||||
|
|
||||||
private int m_id;
|
private int m_id;
|
||||||
@@ -371,7 +460,7 @@ public class Computer
|
|||||||
{
|
{
|
||||||
for(ILuaAPI api : m_apis)
|
for(ILuaAPI api : m_apis)
|
||||||
{
|
{
|
||||||
api.advance( _dt );
|
api.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -420,14 +509,13 @@ public class Computer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean pollChanged()
|
public boolean pollAndResetChanged()
|
||||||
{
|
{
|
||||||
return m_externalOutputChanged;
|
synchronized(this) {
|
||||||
}
|
boolean changed = m_externalOutputChanged;
|
||||||
|
m_externalOutputChanged = false;
|
||||||
public void clearChanged()
|
return changed;
|
||||||
{
|
}
|
||||||
m_externalOutputChanged = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBlinking()
|
public boolean isBlinking()
|
||||||
@@ -578,6 +666,11 @@ public class Computer
|
|||||||
{
|
{
|
||||||
m_apis.add( api );
|
m_apis.add( api );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addAPI( dan200.computercraft.core.apis.ILuaAPI api )
|
||||||
|
{
|
||||||
|
addAPI( (ILuaAPI) api );
|
||||||
|
}
|
||||||
|
|
||||||
public void setPeripheral( int side, IPeripheral peripheral )
|
public void setPeripheral( int side, IPeripheral peripheral )
|
||||||
{
|
{
|
||||||
@@ -616,6 +709,16 @@ public class Computer
|
|||||||
{
|
{
|
||||||
m_apis.add( new HTTPAPI( m_apiEnvironment ) );
|
m_apis.add( new HTTPAPI( m_apiEnvironment ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( ILuaAPIFactory factory : ComputerCraft.getAPIFactories() )
|
||||||
|
{
|
||||||
|
ComputerSystem system = new ComputerSystem( m_apiEnvironment );
|
||||||
|
ILuaAPI api = factory.create( system );
|
||||||
|
if( api != null )
|
||||||
|
{
|
||||||
|
m_apis.add( api );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initLua()
|
private void initLua()
|
||||||
@@ -687,6 +790,7 @@ public class Computer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_state = State.Starting;
|
m_state = State.Starting;
|
||||||
|
m_externalOutputChanged = true;
|
||||||
m_ticksSinceStart = 0;
|
m_ticksSinceStart = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -746,6 +850,7 @@ public class Computer
|
|||||||
|
|
||||||
// Start a new state
|
// Start a new state
|
||||||
m_state = State.Running;
|
m_state = State.Running;
|
||||||
|
m_externalOutputChanged = true;
|
||||||
synchronized( m_machine )
|
synchronized( m_machine )
|
||||||
{
|
{
|
||||||
m_machine.handleEvent( null, null );
|
m_machine.handleEvent( null, null );
|
||||||
@@ -764,6 +869,7 @@ public class Computer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_state = State.Stopping;
|
m_state = State.Stopping;
|
||||||
|
m_externalOutputChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn the computercraft off
|
// Turn the computercraft off
|
||||||
@@ -788,7 +894,7 @@ public class Computer
|
|||||||
// Shutdown our APIs
|
// Shutdown our APIs
|
||||||
synchronized( m_apis )
|
synchronized( m_apis )
|
||||||
{
|
{
|
||||||
for(ILuaAPI api : m_apis)
|
for( ILuaAPI api : m_apis )
|
||||||
{
|
{
|
||||||
api.shutdown();
|
api.shutdown();
|
||||||
}
|
}
|
||||||
@@ -827,6 +933,7 @@ public class Computer
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_state = State.Off;
|
m_state = State.Off;
|
||||||
|
m_externalOutputChanged = true;
|
||||||
if( reboot )
|
if( reboot )
|
||||||
{
|
{
|
||||||
m_startRequested = true;
|
m_startRequested = true;
|
||||||
|
@@ -195,6 +195,8 @@ public class ComputerThread
|
|||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long start = System.nanoTime();
|
||||||
|
|
||||||
// Execute the task
|
// Execute the task
|
||||||
runner.submit( task );
|
runner.submit( task );
|
||||||
|
|
||||||
@@ -229,6 +231,10 @@ public class ComputerThread
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
long stop = System.nanoTime();
|
||||||
|
Computer computer = task.getOwner();
|
||||||
|
if( computer != null ) ComputerTimeTracker.addTiming( computer, stop - start );
|
||||||
|
|
||||||
// Re-add it back onto the queue or remove it
|
// Re-add it back onto the queue or remove it
|
||||||
synchronized( s_taskLock )
|
synchronized( s_taskLock )
|
||||||
{
|
{
|
||||||
|
@@ -0,0 +1,116 @@
|
|||||||
|
package dan200.computercraft.core.computer;
|
||||||
|
|
||||||
|
import com.google.common.collect.MapMaker;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks timing information about computers, including how long they ran for
|
||||||
|
* and the number of events they handled.
|
||||||
|
*
|
||||||
|
* Note that this <em>will</em> track computers which have been deleted (hence
|
||||||
|
* the presence of {@link #timingLookup} and {@link #timings}
|
||||||
|
*/
|
||||||
|
public class ComputerTimeTracker
|
||||||
|
{
|
||||||
|
public static class Timings
|
||||||
|
{
|
||||||
|
private final WeakReference<Computer> computer;
|
||||||
|
private final int computerId;
|
||||||
|
|
||||||
|
private int tasks;
|
||||||
|
|
||||||
|
private long totalTime;
|
||||||
|
private long maxTime;
|
||||||
|
|
||||||
|
public Timings( @Nonnull Computer computer )
|
||||||
|
{
|
||||||
|
this.computer = new WeakReference<>( computer );
|
||||||
|
this.computerId = computer.getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Computer getComputer()
|
||||||
|
{
|
||||||
|
return computer.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getComputerId()
|
||||||
|
{
|
||||||
|
return computerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTasks()
|
||||||
|
{
|
||||||
|
return tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalTime()
|
||||||
|
{
|
||||||
|
return totalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMaxTime()
|
||||||
|
{
|
||||||
|
return maxTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getAverage()
|
||||||
|
{
|
||||||
|
return totalTime / (double) tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update( long time )
|
||||||
|
{
|
||||||
|
tasks++;
|
||||||
|
totalTime += time;
|
||||||
|
if( time > maxTime ) maxTime = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean tracking;
|
||||||
|
private static final List<Timings> timings = new ArrayList<>();
|
||||||
|
private static final Map<Computer, Timings> timingLookup = new MapMaker().weakKeys().makeMap();
|
||||||
|
|
||||||
|
public synchronized static void start()
|
||||||
|
{
|
||||||
|
tracking = true;
|
||||||
|
|
||||||
|
timings.clear();
|
||||||
|
timingLookup.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized static boolean stop()
|
||||||
|
{
|
||||||
|
if( !tracking ) return false;
|
||||||
|
|
||||||
|
tracking = false;
|
||||||
|
timingLookup.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized List<Timings> getTimings()
|
||||||
|
{
|
||||||
|
return new ArrayList<>( timings );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void addTiming( Computer computer, long time )
|
||||||
|
{
|
||||||
|
if( !tracking ) return;
|
||||||
|
|
||||||
|
Timings timings = ComputerTimeTracker.timingLookup.get( computer );
|
||||||
|
if( timings == null )
|
||||||
|
{
|
||||||
|
timings = new Timings( computer );
|
||||||
|
timingLookup.put( computer, timings );
|
||||||
|
ComputerTimeTracker.timings.add( timings );
|
||||||
|
}
|
||||||
|
|
||||||
|
timings.update( time );
|
||||||
|
}
|
||||||
|
}
|
@@ -7,6 +7,7 @@
|
|||||||
package dan200.computercraft.core.filesystem;
|
package dan200.computercraft.core.filesystem;
|
||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.filesystem.IFileSystem;
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
|
|
||||||
@@ -290,6 +291,7 @@ public class FileSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final FileSystemMount m_wrapper = new FileSystemMount( this );
|
||||||
private final Map<String, MountWrapper> m_mounts = new HashMap<>();
|
private final Map<String, MountWrapper> m_mounts = new HashMap<>();
|
||||||
private final Set<Closeable> m_openFiles = Collections.newSetFromMap( new WeakHashMap<Closeable, Boolean>() );
|
private final Set<Closeable> m_openFiles = Collections.newSetFromMap( new WeakHashMap<Closeable, Boolean>() );
|
||||||
|
|
||||||
@@ -734,6 +736,11 @@ public class FileSystem
|
|||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IFileSystem getMountWrapper()
|
||||||
|
{
|
||||||
|
return m_wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
private static String sanitizePath( String path )
|
private static String sanitizePath( String path )
|
||||||
{
|
{
|
||||||
return sanitizePath( path, false );
|
return sanitizePath( path, false );
|
||||||
|
@@ -0,0 +1,185 @@
|
|||||||
|
package dan200.computercraft.core.filesystem;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.filesystem.IFileSystem;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FileSystemMount implements IFileSystem
|
||||||
|
{
|
||||||
|
private final FileSystem m_filesystem;
|
||||||
|
|
||||||
|
public FileSystemMount( FileSystem m_filesystem )
|
||||||
|
{
|
||||||
|
this.m_filesystem = m_filesystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void makeDirectory( @Nonnull String path ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_filesystem.makeDir( path );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete( @Nonnull String path ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_filesystem.delete( path );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public OutputStream openForWrite( @Nonnull String path ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return m_filesystem.openForWrite( path, false );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public OutputStream openForAppend( @Nonnull String path ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return m_filesystem.openForWrite( path, true );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRemainingSpace() throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return m_filesystem.getFreeSpace( "/" );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exists( @Nonnull String path ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return m_filesystem.exists( path );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDirectory( @Nonnull String path ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return m_filesystem.exists( path );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void list( @Nonnull String path, @Nonnull List<String> contents ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Collections.addAll( contents, m_filesystem.list( path ) );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSize( @Nonnull String path ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return m_filesystem.getSize( path );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public InputStream openForRead( @Nonnull String path ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return m_filesystem.openForRead( path );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String combine( String path, String child )
|
||||||
|
{
|
||||||
|
return m_filesystem.combine( path, child );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy( String from, String to ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_filesystem.copy( from, to );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void move( String from, String to ) throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_filesystem.move( from, to );
|
||||||
|
}
|
||||||
|
catch( FileSystemException e )
|
||||||
|
{
|
||||||
|
throw new IOException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -11,7 +11,7 @@ import dan200.computercraft.api.lua.ILuaContext;
|
|||||||
import dan200.computercraft.api.lua.ILuaObject;
|
import dan200.computercraft.api.lua.ILuaObject;
|
||||||
import dan200.computercraft.api.lua.ILuaTask;
|
import dan200.computercraft.api.lua.ILuaTask;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.core.apis.ILuaAPI;
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.core.computer.Computer;
|
import dan200.computercraft.core.computer.Computer;
|
||||||
import dan200.computercraft.core.computer.ITask;
|
import dan200.computercraft.core.computer.ITask;
|
||||||
import dan200.computercraft.core.computer.MainThread;
|
import dan200.computercraft.core.computer.MainThread;
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
package dan200.computercraft.core.lua;
|
package dan200.computercraft.core.lua;
|
||||||
import dan200.computercraft.core.apis.ILuaAPI;
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@@ -56,7 +56,7 @@ public class Terminal
|
|||||||
m_palette = new Palette();
|
m_palette = new Palette();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset()
|
public synchronized void reset()
|
||||||
{
|
{
|
||||||
m_cursorColour = 0;
|
m_cursorColour = 0;
|
||||||
m_cursorBackgroundColour = 15;
|
m_cursorBackgroundColour = 15;
|
||||||
@@ -76,7 +76,7 @@ public class Terminal
|
|||||||
return m_height;
|
return m_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resize( int width, int height )
|
public synchronized void resize( int width, int height )
|
||||||
{
|
{
|
||||||
if( width == m_width && height == m_height )
|
if( width == m_width && height == m_height )
|
||||||
{
|
{
|
||||||
@@ -189,7 +189,7 @@ public class Terminal
|
|||||||
return m_palette;
|
return m_palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void blit( String text, String textColour, String backgroundColour )
|
public synchronized void blit( String text, String textColour, String backgroundColour )
|
||||||
{
|
{
|
||||||
int x = m_cursorX;
|
int x = m_cursorX;
|
||||||
int y = m_cursorY;
|
int y = m_cursorY;
|
||||||
@@ -202,7 +202,7 @@ public class Terminal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write( String text )
|
public synchronized void write( String text )
|
||||||
{
|
{
|
||||||
int x = m_cursorX;
|
int x = m_cursorX;
|
||||||
int y = m_cursorY;
|
int y = m_cursorY;
|
||||||
@@ -215,7 +215,7 @@ public class Terminal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scroll( int yDiff )
|
public synchronized void scroll( int yDiff )
|
||||||
{
|
{
|
||||||
if( yDiff != 0 )
|
if( yDiff != 0 )
|
||||||
{
|
{
|
||||||
@@ -245,7 +245,7 @@ public class Terminal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear()
|
public synchronized void clear()
|
||||||
{
|
{
|
||||||
for( int y = 0; y < m_height; ++y )
|
for( int y = 0; y < m_height; ++y )
|
||||||
{
|
{
|
||||||
@@ -256,7 +256,7 @@ public class Terminal
|
|||||||
m_changed = true;
|
m_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearLine()
|
public synchronized void clearLine()
|
||||||
{
|
{
|
||||||
int y = m_cursorY;
|
int y = m_cursorY;
|
||||||
if( y >= 0 && y < m_height )
|
if( y >= 0 && y < m_height )
|
||||||
@@ -268,7 +268,7 @@ public class Terminal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextBuffer getLine( int y )
|
public synchronized TextBuffer getLine( int y )
|
||||||
{
|
{
|
||||||
if( y >= 0 && y < m_height )
|
if( y >= 0 && y < m_height )
|
||||||
{
|
{
|
||||||
@@ -277,7 +277,7 @@ public class Terminal
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLine( int y, String text, String textColour, String backgroundColour )
|
public synchronized void setLine( int y, String text, String textColour, String backgroundColour )
|
||||||
{
|
{
|
||||||
m_text[y].write( text );
|
m_text[y].write( text );
|
||||||
m_textColour[y].write( textColour );
|
m_textColour[y].write( textColour );
|
||||||
@@ -285,7 +285,7 @@ public class Terminal
|
|||||||
m_changed = true;
|
m_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextBuffer getTextColourLine( int y )
|
public synchronized TextBuffer getTextColourLine( int y )
|
||||||
{
|
{
|
||||||
if( y>=0 && y<m_height )
|
if( y>=0 && y<m_height )
|
||||||
{
|
{
|
||||||
@@ -294,7 +294,7 @@ public class Terminal
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextBuffer getBackgroundColourLine( int y )
|
public synchronized TextBuffer getBackgroundColourLine( int y )
|
||||||
{
|
{
|
||||||
if( y>=0 && y<m_height )
|
if( y>=0 && y<m_height )
|
||||||
{
|
{
|
||||||
@@ -318,7 +318,7 @@ public class Terminal
|
|||||||
m_changed = false;
|
m_changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NBTTagCompound writeToNBT( NBTTagCompound nbttagcompound )
|
public synchronized NBTTagCompound writeToNBT( NBTTagCompound nbttagcompound )
|
||||||
{
|
{
|
||||||
nbttagcompound.setInteger( "term_cursorX", m_cursorX );
|
nbttagcompound.setInteger( "term_cursorX", m_cursorX );
|
||||||
nbttagcompound.setInteger( "term_cursorY", m_cursorY );
|
nbttagcompound.setInteger( "term_cursorY", m_cursorY );
|
||||||
@@ -338,7 +338,7 @@ public class Terminal
|
|||||||
return nbttagcompound;
|
return nbttagcompound;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFromNBT( NBTTagCompound nbttagcompound )
|
public synchronized void readFromNBT( NBTTagCompound nbttagcompound )
|
||||||
{
|
{
|
||||||
m_cursorX = nbttagcompound.getInteger( "term_cursorX" );
|
m_cursorX = nbttagcompound.getInteger( "term_cursorX" );
|
||||||
m_cursorY = nbttagcompound.getInteger( "term_cursorY" );
|
m_cursorY = nbttagcompound.getInteger( "term_cursorY" );
|
||||||
|
@@ -8,6 +8,8 @@ package dan200.computercraft.server.proxy;
|
|||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
||||||
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
|
import dan200.computercraft.shared.computer.core.IComputer;
|
||||||
import dan200.computercraft.shared.network.ComputerCraftPacket;
|
import dan200.computercraft.shared.network.ComputerCraftPacket;
|
||||||
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
|
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
|
||||||
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
|
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
|
||||||
@@ -97,6 +99,12 @@ public class ComputerCraftProxyServer extends ComputerCraftProxyCommon
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getComputerGUI( IComputer computer, int width, int height, ComputerFamily family )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getWorldDir( World world )
|
public File getWorldDir( World world )
|
||||||
{
|
{
|
||||||
|
@@ -0,0 +1,451 @@
|
|||||||
|
package dan200.computercraft.shared.command;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
import dan200.computercraft.core.computer.Computer;
|
||||||
|
import dan200.computercraft.core.computer.ComputerTimeTracker;
|
||||||
|
import dan200.computercraft.shared.command.framework.*;
|
||||||
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
|
import net.minecraft.command.CommandException;
|
||||||
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.text.ITextComponent;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static dan200.computercraft.shared.command.framework.ChatHelpers.*;
|
||||||
|
|
||||||
|
public final class CommandComputerCraft extends CommandDelegate
|
||||||
|
{
|
||||||
|
public CommandComputerCraft()
|
||||||
|
{
|
||||||
|
super( create() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ISubCommand create()
|
||||||
|
{
|
||||||
|
CommandRoot root = new CommandRoot(
|
||||||
|
"computercraft", "Various commands for controlling computers.",
|
||||||
|
"The /computercraft command provides various debugging and administrator tools for controlling and " +
|
||||||
|
"interacting with computers."
|
||||||
|
);
|
||||||
|
|
||||||
|
root.register( new SubCommandBase(
|
||||||
|
"dump", "[id]", "Display the status of computers.", UserLevel.OWNER_OP,
|
||||||
|
"Display the status of all computers or specific information about one computer. You can specify the " +
|
||||||
|
"computer's instance id (e.g. 123), computer id (e.g #123) or label (e.g. \"@My Computer\")."
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
|
{
|
||||||
|
if( arguments.size() == 0 )
|
||||||
|
{
|
||||||
|
TextTable table = new TextTable( "Instance", "Id", "On", "Position" );
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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.addRow(
|
||||||
|
linkComputer( computer ),
|
||||||
|
text( Integer.toString( computer.getID() ) ),
|
||||||
|
bool( computer.isOn() ),
|
||||||
|
linkPosition( context, computer )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.displayTo( context.getSender() );
|
||||||
|
}
|
||||||
|
else if( arguments.size() == 1 )
|
||||||
|
{
|
||||||
|
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
|
||||||
|
|
||||||
|
TextTable table = new TextTable();
|
||||||
|
table.addRow( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
|
||||||
|
table.addRow( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
|
||||||
|
table.addRow( header( "Label" ), text( computer.getLabel() ) );
|
||||||
|
table.addRow( header( "On" ), bool( computer.isOn() ) );
|
||||||
|
table.addRow( header( "Position" ), linkPosition( context, computer ) );
|
||||||
|
table.addRow( header( "Family" ), text( computer.getFamily().toString() ) );
|
||||||
|
|
||||||
|
for( int i = 0; i < 6; i++ )
|
||||||
|
{
|
||||||
|
IPeripheral peripheral = computer.getPeripheral( i );
|
||||||
|
if( peripheral != null )
|
||||||
|
{
|
||||||
|
table.addRow( header( "Peripheral " + Computer.s_sideNames[i] ), text( peripheral.getType() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table.displayTo( context.getSender() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new CommandException( context.getFullUsage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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", "[ids...]", "Shutdown computers remotely.", UserLevel.OWNER_OP,
|
||||||
|
"Shutdown the listed computers or all if none are specified. You can specify the computer's instance id " +
|
||||||
|
"(e.g. 123), computer id (e.g #123) or label (e.g. \"@My Computer\")."
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
|
{
|
||||||
|
Set<ServerComputer> computers = Sets.newHashSet();
|
||||||
|
if( arguments.size() > 0 )
|
||||||
|
{
|
||||||
|
for( String arg : arguments )
|
||||||
|
{
|
||||||
|
computers.addAll( ComputerSelector.getComputers( arg ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() );
|
||||||
|
}
|
||||||
|
|
||||||
|
int shutdown = 0;
|
||||||
|
for( ServerComputer computer : computers )
|
||||||
|
{
|
||||||
|
if( computer.isOn() ) shutdown++;
|
||||||
|
computer.unload();
|
||||||
|
}
|
||||||
|
context.getSender().sendMessage( text( "Shutdown " + shutdown + " / " + computers.size() + " computers" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
|
||||||
|
{
|
||||||
|
return arguments.size() == 0
|
||||||
|
? Collections.emptyList()
|
||||||
|
: ComputerSelector.completeComputer( arguments.get( arguments.size() - 1 ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
root.register( new SubCommandBase(
|
||||||
|
"turn-on", "ids...", "Turn computers on remotely.", UserLevel.OWNER_OP,
|
||||||
|
"Turn on the listed computers. You can specify the computer's instance id (e.g. 123), computer id (e.g #123) " +
|
||||||
|
"or label (e.g. \"@My Computer\")."
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
|
{
|
||||||
|
Set<ServerComputer> computers = Sets.newHashSet();
|
||||||
|
if( arguments.size() > 0 )
|
||||||
|
{
|
||||||
|
for( String arg : arguments )
|
||||||
|
{
|
||||||
|
computers.addAll( ComputerSelector.getComputers( arg ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() );
|
||||||
|
}
|
||||||
|
|
||||||
|
int on = 0;
|
||||||
|
for( ServerComputer computer : computers )
|
||||||
|
{
|
||||||
|
if( !computer.isOn() ) on++;
|
||||||
|
computer.turnOn();
|
||||||
|
}
|
||||||
|
context.getSender().sendMessage( text( "Turned on " + on + " / " + computers.size() + " computers" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
|
||||||
|
{
|
||||||
|
return arguments.size() == 0
|
||||||
|
? Collections.emptyList()
|
||||||
|
: ComputerSelector.completeComputer( arguments.get( arguments.size() - 1 ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
root.register( new SubCommandBase(
|
||||||
|
"tp", "<id>", "Teleport to a specific computer.", UserLevel.OP,
|
||||||
|
"Teleport to the location of a computer. You can either specify the computer's instance " +
|
||||||
|
"id (e.g. 123) or computer id (e.g #123)."
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
|
{
|
||||||
|
if( arguments.size() != 1 ) throw new CommandException( context.getFullUsage() );
|
||||||
|
|
||||||
|
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
|
||||||
|
World world = computer.getWorld();
|
||||||
|
BlockPos pos = computer.getPosition();
|
||||||
|
|
||||||
|
if( world == null || pos == null ) throw new CommandException( "Cannot locate computer in world" );
|
||||||
|
|
||||||
|
ICommandSender sender = context.getSender();
|
||||||
|
if( !(sender instanceof Entity) ) throw new CommandException( "Sender is not an entity" );
|
||||||
|
|
||||||
|
if( sender instanceof EntityPlayerMP )
|
||||||
|
{
|
||||||
|
EntityPlayerMP entity = (EntityPlayerMP) sender;
|
||||||
|
if( entity.getEntityWorld() != world )
|
||||||
|
{
|
||||||
|
context.getServer().getPlayerList().changePlayerDimension( entity, world.provider.getDimension() );
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setPositionAndUpdate( pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Entity entity = (Entity) sender;
|
||||||
|
if( entity.getEntityWorld() != world )
|
||||||
|
{
|
||||||
|
entity.changeDimension( world.provider.getDimension() );
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setLocationAndAngles(
|
||||||
|
pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5,
|
||||||
|
entity.rotationYaw, entity.rotationPitch
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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", "<id>", "View the terminal of a computer.", UserLevel.OP,
|
||||||
|
"Open the terminal of a computer, allowing remote control of a computer. This does not provide access to " +
|
||||||
|
"turtle's inventories. You can either specify the computer's instance id (e.g. 123) or computer id (e.g #123)."
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@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( "Cannot open terminal for non-player" );
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
|
||||||
|
ComputerCraft.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();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
CommandRoot track = new CommandRoot( "track", "Track execution times for computers.",
|
||||||
|
"Track how long computers execute for, as well as how many events they handle. This presents information in " +
|
||||||
|
"a similar way to /forge track and can be useful for diagnosing lag." );
|
||||||
|
root.register( track );
|
||||||
|
|
||||||
|
track.register( new SubCommandBase(
|
||||||
|
"start", "Start tracking all computers", UserLevel.OWNER_OP,
|
||||||
|
"Start tracking all computers' execution times and event counts. This will discard the results of previous runs."
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments )
|
||||||
|
{
|
||||||
|
ComputerTimeTracker.start();
|
||||||
|
|
||||||
|
String stopCommand = "/" + context.parent().getFullPath() + " stop";
|
||||||
|
context.getSender().sendMessage( list(
|
||||||
|
text( "Run " ),
|
||||||
|
link( text( stopCommand ), stopCommand, "Click to stop tracking" ),
|
||||||
|
text( " to stop tracking and view the results" )
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
track.register( new SubCommandBase(
|
||||||
|
"stop", "Stop tracking all computers", UserLevel.OWNER_OP,
|
||||||
|
"Stop tracking all computers' events and execution times"
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
|
{
|
||||||
|
if( !ComputerTimeTracker.stop() ) throw new CommandException( "Tracking not enabled" );
|
||||||
|
displayTimings( context );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
track.register( new SubCommandBase(
|
||||||
|
"dump", "Dump the latest track results", UserLevel.OWNER_OP,
|
||||||
|
"Dump the latest results of computer tracking."
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
|
{
|
||||||
|
displayTimings( context );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
root.register( new SubCommandBase(
|
||||||
|
"reload", "Reload the ComputerCraft config file", UserLevel.OWNER_OP,
|
||||||
|
"Reload the ComputerCraft config file"
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments )
|
||||||
|
{
|
||||||
|
ComputerCraft.loadConfig();
|
||||||
|
ComputerCraft.syncConfig();
|
||||||
|
context.getSender().sendMessage( new TextComponentString( "Reloaded config" ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ITextComponent linkComputer( ServerComputer computer )
|
||||||
|
{
|
||||||
|
return link(
|
||||||
|
text( Integer.toString( computer.getInstanceID() ) ),
|
||||||
|
"/computercraft dump " + computer.getInstanceID(),
|
||||||
|
"View more info about this computer"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ITextComponent linkPosition( CommandContext context, ServerComputer computer )
|
||||||
|
{
|
||||||
|
if( UserLevel.OP.canExecute( context ) )
|
||||||
|
{
|
||||||
|
return link(
|
||||||
|
position( computer.getPosition() ),
|
||||||
|
"/computercraft tp " + computer.getInstanceID(),
|
||||||
|
"Teleport to this computer"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return position( computer.getPosition() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void displayTimings( CommandContext context ) throws CommandException
|
||||||
|
{
|
||||||
|
List<ComputerTimeTracker.Timings> timings = ComputerTimeTracker.getTimings();
|
||||||
|
if( timings.isEmpty() ) throw new CommandException( "No timings available" );
|
||||||
|
|
||||||
|
timings.sort( Comparator.comparing( ComputerTimeTracker.Timings::getAverage ).reversed() );
|
||||||
|
TextTable table = new TextTable( "Computer", "Tasks", "Total", "Average", "Maximum" );
|
||||||
|
|
||||||
|
Map<Computer, ServerComputer> lookup = new HashMap<>();
|
||||||
|
int maxId = 0, maxInstance = 0;
|
||||||
|
for( ServerComputer server : ComputerCraft.serverComputerRegistry.getComputers() )
|
||||||
|
{
|
||||||
|
lookup.put( server.getComputer(), server );
|
||||||
|
|
||||||
|
if( server.getInstanceID() > maxInstance ) maxInstance = server.getInstanceID();
|
||||||
|
if( server.getID() > maxId ) maxId = server.getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
ICommandSender sender = context.getSender();
|
||||||
|
boolean isPlayer = sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
|
||||||
|
|
||||||
|
for( ComputerTimeTracker.Timings entry : timings )
|
||||||
|
{
|
||||||
|
Computer computer = entry.getComputer();
|
||||||
|
ServerComputer serverComputer = computer == null ? null : lookup.get( computer );
|
||||||
|
|
||||||
|
ITextComponent computerComponent = new TextComponentString( "" )
|
||||||
|
.appendSibling( serverComputer == null ? text( "?" ) : linkComputer( serverComputer ) )
|
||||||
|
.appendText( " (id " + entry.getComputerId() + ")" );
|
||||||
|
|
||||||
|
if( serverComputer != null && UserLevel.OP.canExecute( context ) && isPlayer )
|
||||||
|
{
|
||||||
|
computerComponent
|
||||||
|
.appendText( " " )
|
||||||
|
.appendSibling( link(
|
||||||
|
text( "\u261b" ),
|
||||||
|
"/computercraft tp " + serverComputer.getInstanceID(),
|
||||||
|
"Teleport to this computer"
|
||||||
|
) )
|
||||||
|
.appendText( " " )
|
||||||
|
.appendSibling( link(
|
||||||
|
text( "\u20e2" ),
|
||||||
|
"/computercraft view " + serverComputer.getInstanceID(),
|
||||||
|
"View this computer"
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
table.addRow(
|
||||||
|
computerComponent,
|
||||||
|
formatted( "%4d", entry.getTasks() ),
|
||||||
|
text( String.format( "%7.1f", entry.getTotalTime() / 1e6 ) + "ms" ),
|
||||||
|
text( String.format( "%4.1f", entry.getAverage() / 1e6 ) + "ms" ),
|
||||||
|
text( String.format( "%5.1f", entry.getMaxTime() / 1e6 ) + "ms" )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.displayTo( context.getSender() );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,172 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
public final class ComputerSelector
|
||||||
|
{
|
||||||
|
private static List<ServerComputer> getComputers( Predicate<ServerComputer> predicate, String selector ) throws CommandException
|
||||||
|
{
|
||||||
|
// We copy it to prevent concurrent modifications.
|
||||||
|
List<ServerComputer> computers = Lists.newArrayList( ComputerCraft.serverComputerRegistry.getComputers() );
|
||||||
|
List<ServerComputer> candidates = Lists.newArrayList();
|
||||||
|
for( ServerComputer searchComputer : computers )
|
||||||
|
{
|
||||||
|
if( predicate.test( searchComputer ) ) candidates.add( searchComputer );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( candidates.isEmpty() )
|
||||||
|
{
|
||||||
|
throw new CommandException( "No computer matching " + selector );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return candidates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerComputer getComputer( String selector ) throws CommandException
|
||||||
|
{
|
||||||
|
List<ServerComputer> computers = getComputers( selector );
|
||||||
|
if( computers.size() == 1 )
|
||||||
|
{
|
||||||
|
return computers.get( 0 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder( "Multiple computers matching " )
|
||||||
|
.append( selector ).append( " (instances " );
|
||||||
|
|
||||||
|
for( int i = 0; i < computers.size(); i++ )
|
||||||
|
{
|
||||||
|
if( i > 1 ) builder.append( ", " );
|
||||||
|
builder.append( computers.get( i ).getInstanceID() );
|
||||||
|
}
|
||||||
|
builder.append( ")" );
|
||||||
|
|
||||||
|
throw new CommandException( builder.toString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ServerComputer> getComputers( String selector ) throws CommandException
|
||||||
|
{
|
||||||
|
if( selector.length() > 0 && selector.charAt( 0 ) == '#' )
|
||||||
|
{
|
||||||
|
selector = selector.substring( 1 );
|
||||||
|
|
||||||
|
int id;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
id = Integer.parseInt( selector );
|
||||||
|
}
|
||||||
|
catch( NumberFormatException e )
|
||||||
|
{
|
||||||
|
throw new CommandException( "'" + selector + "' is not a valid number" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return getComputers( x -> x.getID() == id, selector );
|
||||||
|
}
|
||||||
|
else if( selector.length() > 0 && selector.charAt( 0 ) == '@' )
|
||||||
|
{
|
||||||
|
String label = selector.substring( 1 );
|
||||||
|
return getComputers( x -> Objects.equals( label, x.getLabel() ), selector );
|
||||||
|
}
|
||||||
|
else if( selector.length() > 0 && selector.charAt( 0 ) == '~' )
|
||||||
|
{
|
||||||
|
String familyName = selector.substring( 1 );
|
||||||
|
return getComputers( x -> x.getFamily().name().equalsIgnoreCase( familyName ), selector );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int instance;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
instance = Integer.parseInt( selector );
|
||||||
|
}
|
||||||
|
catch( NumberFormatException e )
|
||||||
|
{
|
||||||
|
throw new CommandException( "'" + selector + "' is not a valid number" );
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance );
|
||||||
|
if( computer == null )
|
||||||
|
{
|
||||||
|
throw new CommandException( "No such computer for instance id " + instance );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Collections.singletonList( computer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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.length() > 0 && 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.length() > 0 && 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.length() > 0 && 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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,64 @@
|
|||||||
|
package dan200.computercraft.shared.command;
|
||||||
|
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
|
import dan200.computercraft.shared.computer.core.IComputer;
|
||||||
|
import dan200.computercraft.shared.computer.core.IContainerComputer;
|
||||||
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.inventory.Container;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.util.text.TextComponentTranslation;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class ContainerViewComputer extends Container implements IContainerComputer
|
||||||
|
{
|
||||||
|
private final IComputer computer;
|
||||||
|
|
||||||
|
public ContainerViewComputer( IComputer computer )
|
||||||
|
{
|
||||||
|
this.computer = computer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IComputer getComputer()
|
||||||
|
{
|
||||||
|
return computer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canInteractWith( @Nonnull EntityPlayer player )
|
||||||
|
{
|
||||||
|
if( computer instanceof ServerComputer )
|
||||||
|
{
|
||||||
|
ServerComputer serverComputer = (ServerComputer) computer;
|
||||||
|
|
||||||
|
// If this computer no longer exists then discard it.
|
||||||
|
if( ComputerCraft.serverComputerRegistry.get( serverComputer.getInstanceID() ) != serverComputer )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're a command computer then ensure we're in creative
|
||||||
|
if( serverComputer.getFamily() == ComputerFamily.Command )
|
||||||
|
{
|
||||||
|
MinecraftServer server = player.getServer();
|
||||||
|
if( server == null || !server.isCommandBlockEnabled() )
|
||||||
|
{
|
||||||
|
player.sendMessage( new TextComponentTranslation( "advMode.notEnabled" ) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if( !ComputerCraft.canPlayerUseCommands( player ) || !player.capabilities.isCreativeMode )
|
||||||
|
{
|
||||||
|
player.sendMessage( new TextComponentTranslation( "advMode.notAllowed" ) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,117 @@
|
|||||||
|
package dan200.computercraft.shared.command.framework;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.text.ITextComponent;
|
||||||
|
import net.minecraft.util.text.Style;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
|
import net.minecraft.util.text.TextFormatting;
|
||||||
|
import net.minecraft.util.text.event.ClickEvent;
|
||||||
|
import net.minecraft.util.text.event.HoverEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various helpers for building chat messages
|
||||||
|
*/
|
||||||
|
public final class ChatHelpers
|
||||||
|
{
|
||||||
|
private static final TextFormatting HEADER = TextFormatting.LIGHT_PURPLE;
|
||||||
|
private static final TextFormatting SYNOPSIS = TextFormatting.AQUA;
|
||||||
|
private static final TextFormatting NAME = TextFormatting.GREEN;
|
||||||
|
|
||||||
|
public static ITextComponent coloured( String text, TextFormatting colour )
|
||||||
|
{
|
||||||
|
ITextComponent component = new TextComponentString( text == null ? "" : text );
|
||||||
|
component.getStyle().setColor( colour );
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITextComponent text( String text )
|
||||||
|
{
|
||||||
|
return new TextComponentString( text == null ? "" : text );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITextComponent list( ITextComponent... children )
|
||||||
|
{
|
||||||
|
ITextComponent component = new TextComponentString( "" );
|
||||||
|
for( ITextComponent child : children )
|
||||||
|
{
|
||||||
|
component.appendSibling( child );
|
||||||
|
}
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITextComponent getHelp( CommandContext context, ISubCommand command, String prefix )
|
||||||
|
{
|
||||||
|
ITextComponent output = new TextComponentString( "" )
|
||||||
|
.appendSibling( coloured( "/" + prefix + " " + command.getUsage( context ), HEADER ) )
|
||||||
|
.appendText( " " )
|
||||||
|
.appendSibling( coloured( command.getSynopsis(), SYNOPSIS ) );
|
||||||
|
|
||||||
|
String desc = command.getDescription();
|
||||||
|
if( !Strings.isNullOrEmpty( desc ) ) output.appendText( "\n" + desc );
|
||||||
|
|
||||||
|
if( command instanceof CommandRoot )
|
||||||
|
{
|
||||||
|
for( ISubCommand subCommand : ((CommandRoot) command).getSubCommands().values() )
|
||||||
|
{
|
||||||
|
if( !subCommand.checkPermission( context ) ) continue;
|
||||||
|
|
||||||
|
output.appendText( "\n" );
|
||||||
|
|
||||||
|
ITextComponent component = coloured( subCommand.getName(), NAME );
|
||||||
|
component.getStyle().setClickEvent( new ClickEvent(
|
||||||
|
ClickEvent.Action.SUGGEST_COMMAND,
|
||||||
|
"/" + prefix + " " + subCommand.getName()
|
||||||
|
) );
|
||||||
|
output.appendSibling( component );
|
||||||
|
|
||||||
|
output.appendText( " - " + subCommand.getSynopsis() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITextComponent position( BlockPos pos )
|
||||||
|
{
|
||||||
|
if( pos == null ) return text( "<no pos>" );
|
||||||
|
return formatted( "%d, %d, %d", pos.getX(), pos.getY(), pos.getZ() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITextComponent bool( boolean value )
|
||||||
|
{
|
||||||
|
if( value )
|
||||||
|
{
|
||||||
|
ITextComponent component = new TextComponentString( "Y" );
|
||||||
|
component.getStyle().setColor( TextFormatting.GREEN );
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ITextComponent component = new TextComponentString( "N" );
|
||||||
|
component.getStyle().setColor( TextFormatting.RED );
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITextComponent formatted( String format, Object... args )
|
||||||
|
{
|
||||||
|
return new TextComponentString( String.format( format, args ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITextComponent link( ITextComponent component, String command, String toolTip )
|
||||||
|
{
|
||||||
|
Style style = component.getStyle();
|
||||||
|
|
||||||
|
if( style.getColor() == null ) style.setColor( TextFormatting.YELLOW );
|
||||||
|
style.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ) );
|
||||||
|
style.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TextComponentString( toolTip ) ) );
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITextComponent header( String text )
|
||||||
|
{
|
||||||
|
return coloured( text, HEADER );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,93 @@
|
|||||||
|
package dan200.computercraft.shared.command.framework;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
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;
|
||||||
|
this.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() + " " + 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;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,91 @@
|
|||||||
|
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 net.minecraft.command.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( "Unhandled 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() );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,149 @@
|
|||||||
|
package dan200.computercraft.shared.command.framework;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
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 final String synopsis;
|
||||||
|
private final String description;
|
||||||
|
private final Map<String, ISubCommand> subCommands = Maps.newHashMap();
|
||||||
|
|
||||||
|
public CommandRoot( String name, String synopsis, String description )
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.synopsis = synopsis;
|
||||||
|
this.description = description;
|
||||||
|
|
||||||
|
register( new SubCommandHelp( this ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register( ISubCommand command )
|
||||||
|
{
|
||||||
|
subCommands.put( command.getName(), command );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getSynopsis()
|
||||||
|
{
|
||||||
|
return synopsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getDescription()
|
||||||
|
{
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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.size() == 0 )
|
||||||
|
{
|
||||||
|
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.size() == 0 )
|
||||||
|
{
|
||||||
|
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() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,80 @@
|
|||||||
|
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.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 usage of this command
|
||||||
|
*
|
||||||
|
* @param context The context this command is executed in
|
||||||
|
* @return The usage of this command
|
||||||
|
* @see ICommand#getUsage(ICommandSender)
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
String getUsage( CommandContext context );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a short description of this command, including its usage.
|
||||||
|
*
|
||||||
|
* @return The command's synopsis
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
String getSynopsis();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the lengthy description of this command. This synopsis is prepended to this.
|
||||||
|
*
|
||||||
|
* @return The command's description
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
String getDescription();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments );
|
||||||
|
}
|
@@ -0,0 +1,69 @@
|
|||||||
|
package dan200.computercraft.shared.command.framework;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class SubCommandBase implements ISubCommand
|
||||||
|
{
|
||||||
|
private final String name;
|
||||||
|
private final String usage;
|
||||||
|
private final String synopsis;
|
||||||
|
private final String description;
|
||||||
|
private final UserLevel level;
|
||||||
|
|
||||||
|
public SubCommandBase( String name, String usage, String synopsis, UserLevel level, String description )
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.usage = usage;
|
||||||
|
this.synopsis = synopsis;
|
||||||
|
this.description = description;
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubCommandBase( String name, String synopsis, UserLevel level, String description )
|
||||||
|
{
|
||||||
|
this( name, "", synopsis, level, description );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getUsage( CommandContext context )
|
||||||
|
{
|
||||||
|
return usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getSynopsis()
|
||||||
|
{
|
||||||
|
return synopsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getDescription()
|
||||||
|
{
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkPermission( @Nonnull CommandContext context )
|
||||||
|
{
|
||||||
|
return level.canExecute( context );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
|
||||||
|
{
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,127 @@
|
|||||||
|
package dan200.computercraft.shared.command.framework;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import joptsimple.internal.Strings;
|
||||||
|
import net.minecraft.command.CommandBase;
|
||||||
|
import net.minecraft.command.CommandException;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SubCommandHelp implements ISubCommand
|
||||||
|
{
|
||||||
|
private final CommandRoot branchCommand;
|
||||||
|
|
||||||
|
public SubCommandHelp( CommandRoot branchCommand )
|
||||||
|
{
|
||||||
|
this.branchCommand = branchCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return "help";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getUsage( CommandContext context )
|
||||||
|
{
|
||||||
|
return "[command]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getSynopsis()
|
||||||
|
{
|
||||||
|
return "Provide help for a specific command";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getDescription()
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkPermission( @Nonnull CommandContext context )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
|
{
|
||||||
|
ISubCommand command = branchCommand;
|
||||||
|
|
||||||
|
for( int i = 0; i < arguments.size(); i++ )
|
||||||
|
{
|
||||||
|
String commandName = arguments.get( i );
|
||||||
|
if( command instanceof CommandRoot )
|
||||||
|
{
|
||||||
|
command = ((CommandRoot) command).getSubCommands().get( commandName );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new CommandException( Strings.join( arguments.subList( 0, i ), " " ) + " has no sub-commands" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( command == null )
|
||||||
|
{
|
||||||
|
throw new CommandException( "No such command " + Strings.join( arguments.subList( 0, i + 1 ), " " ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder prefix = new StringBuilder( context.parent().getFullPath() );
|
||||||
|
for( String argument : arguments )
|
||||||
|
{
|
||||||
|
prefix.append( ' ' ).append( argument );
|
||||||
|
}
|
||||||
|
context.getSender().sendMessage( ChatHelpers.getHelp( context, command, prefix.toString() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
|
||||||
|
{
|
||||||
|
CommandRoot command = branchCommand;
|
||||||
|
|
||||||
|
for( int i = 0; i < arguments.size() - 1; i++ )
|
||||||
|
{
|
||||||
|
String commandName = arguments.get( i );
|
||||||
|
ISubCommand subCommand = command.getSubCommands().get( commandName );
|
||||||
|
|
||||||
|
if( subCommand instanceof CommandRoot )
|
||||||
|
{
|
||||||
|
command = (CommandRoot) subCommand;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( arguments.size() == 0 )
|
||||||
|
{
|
||||||
|
return Lists.newArrayList( command.getSubCommands().keySet() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<String> list = Lists.newArrayList();
|
||||||
|
String match = arguments.get( arguments.size() - 1 );
|
||||||
|
|
||||||
|
for( String entry : command.getSubCommands().keySet() )
|
||||||
|
{
|
||||||
|
if( CommandBase.doesStringStartWith( match, entry ) )
|
||||||
|
{
|
||||||
|
list.add( entry );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,261 @@
|
|||||||
|
package dan200.computercraft.shared.command.framework;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.util.text.ITextComponent;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
|
import net.minecraft.util.text.TextFormatting;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static dan200.computercraft.shared.command.framework.ChatHelpers.coloured;
|
||||||
|
import static dan200.computercraft.shared.command.framework.ChatHelpers.text;
|
||||||
|
|
||||||
|
public class TextTable
|
||||||
|
{
|
||||||
|
private static final String CHARACTERS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
|
||||||
|
private static final int[] CHAR_WIDTHS = new int[]{
|
||||||
|
6, 6, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 4,
|
||||||
|
4, 6, 7, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 2, 5, 6, 6, 6, 6, 3, 5, 5, 5, 6, 2, 6, 2, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 5, 6, 5, 6,
|
||||||
|
7, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 6, 6,
|
||||||
|
3, 6, 6, 6, 6, 6, 5, 6, 6, 2, 6, 5, 3, 6, 6, 6,
|
||||||
|
6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 5, 2, 5, 7, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 3, 6, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6,
|
||||||
|
6, 3, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 2, 6, 6,
|
||||||
|
8, 9, 9, 6, 6, 6, 8, 8, 6, 8, 8, 8, 8, 8, 6, 6,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 9, 9, 9, 5, 9, 9,
|
||||||
|
8, 7, 7, 8, 7, 8, 8, 8, 7, 8, 8, 7, 9, 9, 6, 7,
|
||||||
|
7, 7, 7, 7, 9, 6, 7, 8, 7, 6, 6, 9, 7, 6, 7, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final ITextComponent SEPARATOR = coloured( " | ", TextFormatting.GRAY );
|
||||||
|
private static final ITextComponent LINE = text( "\n" );
|
||||||
|
|
||||||
|
private static int getWidth( char character, ICommandSender sender )
|
||||||
|
{
|
||||||
|
if( sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer) )
|
||||||
|
{
|
||||||
|
// Use font widths here.
|
||||||
|
if( character == 167 )
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if( character == 32 )
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
else if( CHARACTERS.indexOf( character ) != -1 )
|
||||||
|
{
|
||||||
|
return CHAR_WIDTHS[character];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Eh, close enough.
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getWidth( ITextComponent text, ICommandSender sender )
|
||||||
|
{
|
||||||
|
int sum = 0;
|
||||||
|
String chars = text.getUnformattedText();
|
||||||
|
for( int i = 0; i < chars.length(); i++ )
|
||||||
|
{
|
||||||
|
sum += getWidth( chars.charAt( i ), sender );
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPlayer( ICommandSender sender )
|
||||||
|
{
|
||||||
|
return sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getMaxWidth( ICommandSender sender )
|
||||||
|
{
|
||||||
|
return isPlayer( sender ) ? 320 : 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int columns = -1;
|
||||||
|
private final ITextComponent[] header;
|
||||||
|
private final List<ITextComponent[]> rows = Lists.newArrayList();
|
||||||
|
|
||||||
|
public TextTable( @Nonnull ITextComponent... header )
|
||||||
|
{
|
||||||
|
this.header = header;
|
||||||
|
this.columns = header.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextTable()
|
||||||
|
{
|
||||||
|
header = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextTable( @Nonnull String... header )
|
||||||
|
{
|
||||||
|
this.header = new ITextComponent[header.length];
|
||||||
|
for( int i = 0; i < header.length; i++ )
|
||||||
|
{
|
||||||
|
this.header[i] = ChatHelpers.header( header[i] );
|
||||||
|
}
|
||||||
|
this.columns = header.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRow( @Nonnull ITextComponent... row )
|
||||||
|
{
|
||||||
|
if( columns == -1 )
|
||||||
|
{
|
||||||
|
columns = row.length;
|
||||||
|
}
|
||||||
|
else if( row.length != columns )
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException( "Row is the incorrect length" );
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.add( row );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayTo( ICommandSender sender )
|
||||||
|
{
|
||||||
|
if( columns <= 0 ) return;
|
||||||
|
|
||||||
|
final int maxWidth = getMaxWidth( sender );
|
||||||
|
|
||||||
|
int[] minWidths = new int[columns];
|
||||||
|
int[] maxWidths = new int[columns];
|
||||||
|
int[] rowWidths = new int[columns];
|
||||||
|
|
||||||
|
if( header != null )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < columns; i++ )
|
||||||
|
{
|
||||||
|
maxWidths[i] = minWidths[i] = getWidth( header[i], sender );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit the number of rows to something sensible.
|
||||||
|
int limit = isPlayer( sender ) ? 30 : 100;
|
||||||
|
if( limit > rows.size() ) limit = rows.size();
|
||||||
|
|
||||||
|
for( int y = 0; y < limit; y++ )
|
||||||
|
{
|
||||||
|
ITextComponent[] row = rows.get( y );
|
||||||
|
for( int i = 0; i < row.length; i++ )
|
||||||
|
{
|
||||||
|
int width = getWidth( row[i], sender );
|
||||||
|
rowWidths[i] += width;
|
||||||
|
if( width > maxWidths[i] )
|
||||||
|
{
|
||||||
|
maxWidths[i] = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the average width
|
||||||
|
for( int i = 0; i < columns; i++ )
|
||||||
|
{
|
||||||
|
rowWidths[i] = Math.max( rowWidths[i], rows.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalWidth = (columns - 1) * getWidth( SEPARATOR, sender );
|
||||||
|
for( int x : maxWidths ) totalWidth += x;
|
||||||
|
|
||||||
|
// TODO: Limit the widths of some entries if totalWidth > maxWidth
|
||||||
|
|
||||||
|
ITextComponent out = new TextComponentString( "" );
|
||||||
|
|
||||||
|
if( header != null )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < columns; i++ )
|
||||||
|
{
|
||||||
|
if( i != 0 ) out.appendSibling( SEPARATOR );
|
||||||
|
appendFixed( out, sender, header[i], maxWidths[i] );
|
||||||
|
}
|
||||||
|
out.appendSibling( LINE );
|
||||||
|
|
||||||
|
// Round the width up rather than down
|
||||||
|
int rowCharWidth = getWidth( '=', sender );
|
||||||
|
int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1);
|
||||||
|
out.appendSibling( coloured( StringUtils.repeat( '=', rowWidth ), TextFormatting.GRAY ) );
|
||||||
|
out.appendSibling( LINE );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i = 0; i < limit; i++ )
|
||||||
|
{
|
||||||
|
ITextComponent[] row = rows.get( i );
|
||||||
|
if( i != 0 ) out.appendSibling( LINE );
|
||||||
|
for( int j = 0; j < columns; j++ )
|
||||||
|
{
|
||||||
|
if( j != 0 ) out.appendSibling( SEPARATOR );
|
||||||
|
appendFixed( out, sender, row[j], maxWidths[j] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( limit != rows.size() )
|
||||||
|
{
|
||||||
|
out.appendSibling( LINE );
|
||||||
|
out.appendSibling( coloured( (rows.size() - limit) + " additional rows...", TextFormatting.AQUA ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage( out );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendFixed( ITextComponent out, ICommandSender sender, ITextComponent entry, int maxWidth )
|
||||||
|
{
|
||||||
|
int length = getWidth( entry, sender );
|
||||||
|
int delta = length - maxWidth;
|
||||||
|
if( delta < 0 )
|
||||||
|
{
|
||||||
|
// Convert to overflow;
|
||||||
|
delta = -delta;
|
||||||
|
|
||||||
|
// We have to remove some padding as there is a padding added between formatted and unformatted text
|
||||||
|
if( !entry.getStyle().isEmpty() && isPlayer( sender ) ) delta -= 1;
|
||||||
|
|
||||||
|
out.appendSibling( entry );
|
||||||
|
|
||||||
|
int spaceWidth = getWidth( ' ', sender );
|
||||||
|
|
||||||
|
int spaces = delta / spaceWidth;
|
||||||
|
int missing = delta % spaceWidth;
|
||||||
|
spaces -= missing;
|
||||||
|
|
||||||
|
ITextComponent component = new TextComponentString( StringUtils.repeat( ' ', spaces < 0 ? 0 : spaces ) );
|
||||||
|
if( missing > 0 )
|
||||||
|
{
|
||||||
|
ITextComponent bold = new TextComponentString( StringUtils.repeat( ' ', missing ) );
|
||||||
|
bold.getStyle().setBold( true );
|
||||||
|
component.appendSibling( bold );
|
||||||
|
}
|
||||||
|
|
||||||
|
out.appendSibling( component );
|
||||||
|
}
|
||||||
|
else if( delta > 0 )
|
||||||
|
{
|
||||||
|
out.appendSibling( entry );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.appendSibling( entry );
|
||||||
|
|
||||||
|
// We have to add some padding as we expect a padding between formatted and unformatted text
|
||||||
|
// and there won't be.
|
||||||
|
if( entry.getStyle().isEmpty() && isPlayer( sender ) ) out.appendText( " " );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,63 @@
|
|||||||
|
package dan200.computercraft.shared.command.framework;
|
||||||
|
|
||||||
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The level a user must be at in order to execute a command.
|
||||||
|
*/
|
||||||
|
public enum UserLevel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Only can be used by the owner of the server: namely the server console or the player in SSP.
|
||||||
|
*/
|
||||||
|
OWNER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can only be used by ops.
|
||||||
|
*/
|
||||||
|
OP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used by any op, or the player in SSP.
|
||||||
|
*/
|
||||||
|
OWNER_OP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used by anyone.
|
||||||
|
*/
|
||||||
|
ANYONE;
|
||||||
|
|
||||||
|
public int toLevel()
|
||||||
|
{
|
||||||
|
switch( this )
|
||||||
|
{
|
||||||
|
case OWNER:
|
||||||
|
return 4;
|
||||||
|
case OP:
|
||||||
|
case OWNER_OP:
|
||||||
|
return 2;
|
||||||
|
case ANYONE:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canExecute( CommandContext context )
|
||||||
|
{
|
||||||
|
if( this == ANYONE ) return true;
|
||||||
|
|
||||||
|
// We *always* allow level 0 stuff, even if the
|
||||||
|
MinecraftServer server = context.getServer();
|
||||||
|
ICommandSender sender = context.getSender();
|
||||||
|
|
||||||
|
if( server.isSinglePlayer() && sender instanceof EntityPlayerMP &&
|
||||||
|
((EntityPlayerMP) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerOwner() ) )
|
||||||
|
{
|
||||||
|
if( this == OWNER || this == OWNER_OP ) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sender.canUseCommand( toLevel(), context.getRootCommand() );
|
||||||
|
}
|
||||||
|
}
|
@@ -241,10 +241,9 @@ public abstract class BlockGeneric extends Block implements
|
|||||||
if( collision.size() > 0 )
|
if( collision.size() > 0 )
|
||||||
{
|
{
|
||||||
AxisAlignedBB aabb = collision.get( 0 );
|
AxisAlignedBB aabb = collision.get( 0 );
|
||||||
for (int i=1; i<collision.size(); ++i )
|
for( int i = 1; i < collision.size(); i++ )
|
||||||
{
|
{
|
||||||
AxisAlignedBB other = collision.get( 1 );
|
aabb = aabb.union( collision.get( i ) );
|
||||||
aabb = aabb.union( other );
|
|
||||||
}
|
}
|
||||||
return aabb;
|
return aabb;
|
||||||
}
|
}
|
||||||
|
@@ -14,29 +14,28 @@ public class ClientTerminal implements ITerminal
|
|||||||
private boolean m_colour;
|
private boolean m_colour;
|
||||||
private Terminal m_terminal;
|
private Terminal m_terminal;
|
||||||
private boolean m_terminalChanged;
|
private boolean m_terminalChanged;
|
||||||
private boolean m_terminalChangedLastFrame;
|
|
||||||
|
|
||||||
public ClientTerminal( boolean colour )
|
public ClientTerminal( boolean colour )
|
||||||
{
|
{
|
||||||
m_colour = colour;
|
m_colour = colour;
|
||||||
m_terminal = null;
|
m_terminal = null;
|
||||||
m_terminalChanged = false;
|
m_terminalChanged = false;
|
||||||
m_terminalChangedLastFrame = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update()
|
public void update()
|
||||||
{
|
{
|
||||||
m_terminalChangedLastFrame = m_terminalChanged || (m_terminal != null && m_terminal.getChanged());
|
|
||||||
if( m_terminal != null )
|
if( m_terminal != null )
|
||||||
{
|
{
|
||||||
|
m_terminalChanged |= m_terminal.getChanged();
|
||||||
m_terminal.clearChanged();
|
m_terminal.clearChanged();
|
||||||
}
|
}
|
||||||
m_terminalChanged = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasTerminalChanged()
|
public boolean pollTerminalChanged()
|
||||||
{
|
{
|
||||||
return m_terminalChangedLastFrame;
|
boolean changed = m_terminalChanged;
|
||||||
|
m_terminalChanged = false;
|
||||||
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ITerminal implementation
|
// ITerminal implementation
|
||||||
|
@@ -8,9 +8,9 @@ package dan200.computercraft.shared.computer.apis;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.core.apis.ILuaAPI;
|
|
||||||
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
|
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
|
||||||
import dan200.computercraft.shared.util.WorldUtil;
|
import dan200.computercraft.shared.util.WorldUtil;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
@@ -49,21 +49,6 @@ public class CommandAPI implements ILuaAPI
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startup()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void advance( double dt )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shutdown()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String[] getMethodNames()
|
public String[] getMethodNames()
|
||||||
|
@@ -97,4 +97,11 @@ public class ComputerPeripheral
|
|||||||
{
|
{
|
||||||
return (other != null && other.getClass() == this.getClass());
|
return (other != null && other.getClass() == this.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Object getTarget()
|
||||||
|
{
|
||||||
|
return m_computer.getTile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
package dan200.computercraft.shared.computer.blocks;
|
package dan200.computercraft.shared.computer.blocks;
|
||||||
|
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
import dan200.computercraft.shared.computer.core.IComputer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A proxy object for computer objects, delegating to {@link ServerComputer} or {@link TileComputer} where appropriate.
|
* A proxy object for computer objects, delegating to {@link IComputer} or {@link TileComputer} where appropriate.
|
||||||
*/
|
*/
|
||||||
public abstract class ComputerProxy
|
public abstract class ComputerProxy
|
||||||
{
|
{
|
||||||
@@ -12,7 +12,7 @@ public abstract class ComputerProxy
|
|||||||
public void turnOn()
|
public void turnOn()
|
||||||
{
|
{
|
||||||
TileComputerBase tile = getTile();
|
TileComputerBase tile = getTile();
|
||||||
ServerComputer computer = tile.getServerComputer();
|
IComputer computer = tile.getComputer();
|
||||||
if( computer == null )
|
if( computer == null )
|
||||||
{
|
{
|
||||||
tile.m_startOn = true;
|
tile.m_startOn = true;
|
||||||
@@ -26,7 +26,7 @@ public abstract class ComputerProxy
|
|||||||
public void shutdown()
|
public void shutdown()
|
||||||
{
|
{
|
||||||
TileComputerBase tile = getTile();
|
TileComputerBase tile = getTile();
|
||||||
ServerComputer computer = tile.getServerComputer();
|
IComputer computer = tile.getComputer();
|
||||||
if( computer == null )
|
if( computer == null )
|
||||||
{
|
{
|
||||||
tile.m_startOn = false;
|
tile.m_startOn = false;
|
||||||
@@ -40,7 +40,7 @@ public abstract class ComputerProxy
|
|||||||
public void reboot()
|
public void reboot()
|
||||||
{
|
{
|
||||||
TileComputerBase tile = getTile();
|
TileComputerBase tile = getTile();
|
||||||
ServerComputer computer = tile.getServerComputer();
|
IComputer computer = tile.getComputer();
|
||||||
if( computer == null )
|
if( computer == null )
|
||||||
{
|
{
|
||||||
tile.m_startOn = true;
|
tile.m_startOn = true;
|
||||||
@@ -54,7 +54,7 @@ public abstract class ComputerProxy
|
|||||||
public int assignID()
|
public int assignID()
|
||||||
{
|
{
|
||||||
TileComputerBase tile = getTile();
|
TileComputerBase tile = getTile();
|
||||||
ServerComputer computer = tile.getServerComputer();
|
IComputer computer = tile.getComputer();
|
||||||
if( computer == null )
|
if( computer == null )
|
||||||
{
|
{
|
||||||
return tile.m_computerID;
|
return tile.m_computerID;
|
||||||
@@ -67,14 +67,14 @@ public abstract class ComputerProxy
|
|||||||
|
|
||||||
public boolean isOn()
|
public boolean isOn()
|
||||||
{
|
{
|
||||||
ServerComputer computer = getTile().getServerComputer();
|
IComputer computer = getTile().getComputer();
|
||||||
return computer != null && computer.isOn();
|
return computer != null && computer.isOn();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLabel()
|
public String getLabel()
|
||||||
{
|
{
|
||||||
TileComputerBase tile = getTile();
|
TileComputerBase tile = getTile();
|
||||||
ServerComputer computer = tile.getServerComputer();
|
IComputer computer = tile.getComputer();
|
||||||
if( computer == null )
|
if( computer == null )
|
||||||
{
|
{
|
||||||
return tile.m_label;
|
return tile.m_label;
|
||||||
|
@@ -10,9 +10,9 @@ import dan200.computercraft.ComputerCraft;
|
|||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.apis.IAPIEnvironment;
|
import dan200.computercraft.core.apis.IAPIEnvironment;
|
||||||
import dan200.computercraft.core.apis.ILuaAPI;
|
|
||||||
import dan200.computercraft.core.computer.Computer;
|
import dan200.computercraft.core.computer.Computer;
|
||||||
import dan200.computercraft.core.computer.IComputerEnvironment;
|
import dan200.computercraft.core.computer.IComputerEnvironment;
|
||||||
import dan200.computercraft.shared.common.ServerTerminal;
|
import dan200.computercraft.shared.common.ServerTerminal;
|
||||||
@@ -94,14 +94,18 @@ public class ServerComputer extends ServerTerminal
|
|||||||
return m_computer.getAPIEnvironment();
|
return m_computer.getAPIEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Computer getComputer()
|
||||||
|
{
|
||||||
|
return m_computer;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update()
|
public void update()
|
||||||
{
|
{
|
||||||
super.update();
|
super.update();
|
||||||
m_computer.advance( 0.05 );
|
m_computer.advance( 0.05 );
|
||||||
|
|
||||||
m_changedLastFrame = m_changed || m_computer.pollChanged();
|
m_changedLastFrame = m_computer.pollAndResetChanged() || m_changed;
|
||||||
m_computer.clearChanged();
|
|
||||||
m_changed = false;
|
m_changed = false;
|
||||||
|
|
||||||
m_ticksSincePing++;
|
m_ticksSincePing++;
|
||||||
@@ -314,6 +318,11 @@ public class ServerComputer extends ServerTerminal
|
|||||||
m_computer.addAPI( api );
|
m_computer.addAPI( api );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addAPI( dan200.computercraft.core.apis.ILuaAPI api )
|
||||||
|
{
|
||||||
|
m_computer.addAPI( api );
|
||||||
|
}
|
||||||
|
|
||||||
public void setPeripheral( int side, IPeripheral peripheral )
|
public void setPeripheral( int side, IPeripheral peripheral )
|
||||||
{
|
{
|
||||||
m_computer.setPeripheral( side, peripheral );
|
m_computer.setPeripheral( side, peripheral );
|
||||||
|
@@ -16,4 +16,5 @@ public interface IComputerItem
|
|||||||
int getComputerID( @Nonnull ItemStack stack );
|
int getComputerID( @Nonnull ItemStack stack );
|
||||||
String getLabel( @Nonnull ItemStack stack );
|
String getLabel( @Nonnull ItemStack stack );
|
||||||
ComputerFamily getFamily( @Nonnull ItemStack stack );
|
ComputerFamily getFamily( @Nonnull ItemStack stack );
|
||||||
|
ItemStack withFamily(@Nonnull ItemStack stack, @Nonnull ComputerFamily family);
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@ import javax.annotation.Nullable;
|
|||||||
public class ItemComputer extends ItemComputerBase
|
public class ItemComputer extends ItemComputerBase
|
||||||
{
|
{
|
||||||
public static int HIGHEST_DAMAGE_VALUE_ID = 16382;
|
public static int HIGHEST_DAMAGE_VALUE_ID = 16382;
|
||||||
|
|
||||||
public ItemComputer( Block block )
|
public ItemComputer( Block block )
|
||||||
{
|
{
|
||||||
super( block );
|
super( block );
|
||||||
@@ -87,7 +87,7 @@ public class ItemComputer extends ItemComputerBase
|
|||||||
TileEntity tile = world.getTileEntity( pos );
|
TileEntity tile = world.getTileEntity( pos );
|
||||||
if( tile != null && tile instanceof IComputerTile )
|
if( tile != null && tile instanceof IComputerTile )
|
||||||
{
|
{
|
||||||
IComputerTile computer = (IComputerTile)tile;
|
IComputerTile computer = (IComputerTile) tile;
|
||||||
setupComputerAfterPlacement( stack, computer );
|
setupComputerAfterPlacement( stack, computer );
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -146,10 +146,16 @@ public class ItemComputer extends ItemComputerBase
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
int damage = stack.getItemDamage() & 0x3fff;
|
int damage = stack.getItemDamage() & 0x3fff;
|
||||||
return ( damage - 1 );
|
return (damage - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack withFamily( @Nonnull ItemStack stack, @Nonnull ComputerFamily family )
|
||||||
|
{
|
||||||
|
return ComputerItemFactory.create( getComputerID( stack ), getLabel( stack ), family );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ComputerFamily getFamily( int damage )
|
public ComputerFamily getFamily( int damage )
|
||||||
{
|
{
|
||||||
|
@@ -0,0 +1,66 @@
|
|||||||
|
package dan200.computercraft.shared.computer.recipe;
|
||||||
|
|
||||||
|
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||||
|
import net.minecraft.inventory.InventoryCrafting;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.crafting.Ingredient;
|
||||||
|
import net.minecraft.item.crafting.ShapedRecipes;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.crafting.CraftingHelper;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a recipe which converts a computer from one form into another.
|
||||||
|
*/
|
||||||
|
public abstract class ComputerConvertRecipe extends ShapedRecipes
|
||||||
|
{
|
||||||
|
public ComputerConvertRecipe( String group, @Nonnull CraftingHelper.ShapedPrimer primer, @Nonnull ItemStack result )
|
||||||
|
{
|
||||||
|
super( group, primer.width, primer.height, primer.input, result );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
protected abstract ItemStack convert( @Nonnull ItemStack stack );
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches( @Nonnull InventoryCrafting inventory, @Nonnull World world )
|
||||||
|
{
|
||||||
|
// See if we match the recipe, and extract the input computercraft ID
|
||||||
|
ItemStack computerStack = null;
|
||||||
|
for( int y = 0; y < 3; ++y )
|
||||||
|
{
|
||||||
|
for( int x = 0; x < 3; ++x )
|
||||||
|
{
|
||||||
|
ItemStack stack = inventory.getStackInRowAndColumn( x, y );
|
||||||
|
Ingredient target = getIngredients().get( x + y * 3 );
|
||||||
|
|
||||||
|
// First verify we match the ingredient
|
||||||
|
if( !target.apply( stack ) ) return false;
|
||||||
|
|
||||||
|
// We want to ensure we have a computer item somewhere in the recipe
|
||||||
|
if( stack.getItem() instanceof IComputerItem ) computerStack = stack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return computerStack != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public ItemStack getCraftingResult( @Nonnull InventoryCrafting inventory )
|
||||||
|
{
|
||||||
|
for( int y = 0; y < 3; ++y )
|
||||||
|
{
|
||||||
|
for( int x = 0; x < 3; ++x )
|
||||||
|
{
|
||||||
|
ItemStack item = inventory.getStackInRowAndColumn( x, y );
|
||||||
|
|
||||||
|
// If we're a computer, convert!
|
||||||
|
if( item.getItem() instanceof IComputerItem ) return convert( item );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,47 @@
|
|||||||
|
package dan200.computercraft.shared.computer.recipe;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
|
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||||
|
import dan200.computercraft.shared.util.RecipeUtil;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.crafting.IRecipe;
|
||||||
|
import net.minecraft.util.JsonUtils;
|
||||||
|
import net.minecraftforge.common.crafting.CraftingHelper;
|
||||||
|
import net.minecraftforge.common.crafting.IRecipeFactory;
|
||||||
|
import net.minecraftforge.common.crafting.JsonContext;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public class ComputerFamilyRecipe extends ComputerConvertRecipe
|
||||||
|
{
|
||||||
|
private final ComputerFamily family;
|
||||||
|
|
||||||
|
public ComputerFamilyRecipe( String group, @Nonnull CraftingHelper.ShapedPrimer primer, @Nonnull ItemStack result, ComputerFamily family )
|
||||||
|
{
|
||||||
|
super( group, primer, result );
|
||||||
|
this.family = family;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
protected ItemStack convert( @Nonnull ItemStack stack )
|
||||||
|
{
|
||||||
|
return ((IComputerItem) stack.getItem()).withFamily( stack, family );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Factory implements IRecipeFactory
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public IRecipe parse( JsonContext context, JsonObject json )
|
||||||
|
{
|
||||||
|
String group = JsonUtils.getString( json, "group", "" );
|
||||||
|
ComputerFamily family = RecipeUtil.getFamily( json, "family" );
|
||||||
|
|
||||||
|
CraftingHelper.ShapedPrimer primer = RecipeUtil.getPrimer( context, json );
|
||||||
|
ItemStack result = deserializeItem( JsonUtils.getJsonObject( json, "result" ), false );
|
||||||
|
|
||||||
|
return new ComputerFamilyRecipe( group, primer, result, family );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,66 @@
|
|||||||
|
package dan200.computercraft.shared.computer.recipe;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
|
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||||
|
import dan200.computercraft.shared.util.RecipeUtil;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.crafting.Ingredient;
|
||||||
|
import net.minecraft.util.JsonUtils;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraftforge.common.crafting.IIngredientFactory;
|
||||||
|
import net.minecraftforge.common.crafting.JsonContext;
|
||||||
|
import net.minecraftforge.fml.common.registry.ForgeRegistries;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an ingredient which requires an item to have a specific
|
||||||
|
* computer family. This allows us to have operations which only work
|
||||||
|
* on normal or
|
||||||
|
*/
|
||||||
|
public class ComputerIngredient extends Ingredient
|
||||||
|
{
|
||||||
|
private final IComputerItem item;
|
||||||
|
private final ComputerFamily family;
|
||||||
|
|
||||||
|
public <T extends Item & IComputerItem> ComputerIngredient( T item, int data, ComputerFamily family )
|
||||||
|
{
|
||||||
|
super( new ItemStack( item, 1, data ) );
|
||||||
|
|
||||||
|
this.item = item;
|
||||||
|
this.family = family;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply( @Nullable ItemStack stack )
|
||||||
|
{
|
||||||
|
return stack != null && stack.getItem() == item && item.getFamily( stack ) == family;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Factory implements IIngredientFactory
|
||||||
|
{
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Ingredient parse( JsonContext context, JsonObject json )
|
||||||
|
{
|
||||||
|
String itemName = context.appendModId( JsonUtils.getString( json, "item" ) );
|
||||||
|
int data = JsonUtils.getInt( json, "data", 0 );
|
||||||
|
ComputerFamily family = RecipeUtil.getFamily( json, "family" );
|
||||||
|
|
||||||
|
Item item = ForgeRegistries.ITEMS.getValue( new ResourceLocation( itemName ) );
|
||||||
|
|
||||||
|
if( item == null ) throw new JsonSyntaxException( "Unknown item '" + itemName + "'" );
|
||||||
|
if( !(item instanceof IComputerItem) )
|
||||||
|
{
|
||||||
|
throw new JsonSyntaxException( "Item '" + itemName + "' is not a computer item" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return new ComputerIngredient( (Item & IComputerItem) item, data, family );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -10,19 +10,23 @@ import dan200.computercraft.shared.media.items.ItemDiskLegacy;
|
|||||||
import dan200.computercraft.shared.util.Colour;
|
import dan200.computercraft.shared.util.Colour;
|
||||||
import dan200.computercraft.shared.util.ColourTracker;
|
import dan200.computercraft.shared.util.ColourTracker;
|
||||||
import dan200.computercraft.shared.util.ColourUtils;
|
import dan200.computercraft.shared.util.ColourUtils;
|
||||||
import net.minecraft.init.Items;
|
|
||||||
import net.minecraft.inventory.InventoryCrafting;
|
import net.minecraft.inventory.InventoryCrafting;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.item.crafting.IRecipe;
|
import net.minecraft.item.crafting.IRecipe;
|
||||||
|
import net.minecraft.item.crafting.Ingredient;
|
||||||
import net.minecraft.util.NonNullList;
|
import net.minecraft.util.NonNullList;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.ForgeHooks;
|
import net.minecraftforge.common.ForgeHooks;
|
||||||
|
import net.minecraftforge.oredict.OreIngredient;
|
||||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
public class DiskRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements IRecipe
|
public class DiskRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements IRecipe
|
||||||
{
|
{
|
||||||
|
private final Ingredient paper = new OreIngredient( "paper" );
|
||||||
|
private final Ingredient redstone = new OreIngredient( "dustRedstone" );
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches( @Nonnull InventoryCrafting inv, @Nonnull World world )
|
public boolean matches( @Nonnull InventoryCrafting inv, @Nonnull World world )
|
||||||
{
|
{
|
||||||
@@ -35,12 +39,12 @@ public class DiskRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements IRe
|
|||||||
|
|
||||||
if( !stack.isEmpty() )
|
if( !stack.isEmpty() )
|
||||||
{
|
{
|
||||||
if( stack.getItem() == Items.PAPER )
|
if( paper.apply( stack ) )
|
||||||
{
|
{
|
||||||
if( paperFound ) return false;
|
if( paperFound ) return false;
|
||||||
paperFound = true;
|
paperFound = true;
|
||||||
}
|
}
|
||||||
else if( stack.getItem() == Items.REDSTONE )
|
else if( redstone.apply( stack ) )
|
||||||
{
|
{
|
||||||
if( redstoneFound ) return false;
|
if( redstoneFound ) return false;
|
||||||
redstoneFound = true;
|
redstoneFound = true;
|
||||||
@@ -66,8 +70,8 @@ public class DiskRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements IRe
|
|||||||
ItemStack stack = inv.getStackInSlot( i );
|
ItemStack stack = inv.getStackInSlot( i );
|
||||||
|
|
||||||
if( stack.isEmpty() ) continue;
|
if( stack.isEmpty() ) continue;
|
||||||
|
|
||||||
if( stack.getItem() != Items.PAPER && stack.getItem() != Items.REDSTONE )
|
if( !paper.apply( stack ) && !redstone.apply( stack ) )
|
||||||
{
|
{
|
||||||
int index = ColourUtils.getStackColour( stack );
|
int index = ColourUtils.getStackColour( stack );
|
||||||
if( index < 0 ) continue;
|
if( index < 0 ) continue;
|
||||||
|
@@ -7,23 +7,24 @@
|
|||||||
package dan200.computercraft.shared.media.recipes;
|
package dan200.computercraft.shared.media.recipes;
|
||||||
|
|
||||||
import dan200.computercraft.shared.media.items.ItemPrintout;
|
import dan200.computercraft.shared.media.items.ItemPrintout;
|
||||||
import net.minecraft.init.Items;
|
|
||||||
import net.minecraft.inventory.InventoryCrafting;
|
import net.minecraft.inventory.InventoryCrafting;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.item.crafting.IRecipe;
|
import net.minecraft.item.crafting.IRecipe;
|
||||||
|
import net.minecraft.item.crafting.Ingredient;
|
||||||
import net.minecraft.util.NonNullList;
|
import net.minecraft.util.NonNullList;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.ForgeHooks;
|
import net.minecraftforge.common.ForgeHooks;
|
||||||
|
import net.minecraftforge.oredict.OreIngredient;
|
||||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
public class PrintoutRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements IRecipe
|
public class PrintoutRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements IRecipe
|
||||||
{
|
{
|
||||||
public PrintoutRecipe( )
|
private final Ingredient paper = new OreIngredient( "paper" );
|
||||||
{
|
private final Ingredient leather = new OreIngredient( "leather" );
|
||||||
}
|
private final Ingredient string = new OreIngredient( "string" );
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canFit( int x, int y )
|
public boolean canFit( int x, int y )
|
||||||
@@ -68,8 +69,7 @@ public class PrintoutRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements
|
|||||||
ItemStack stack = inventory.getStackInRowAndColumn(x, y);
|
ItemStack stack = inventory.getStackInRowAndColumn(x, y);
|
||||||
if( !stack.isEmpty() )
|
if( !stack.isEmpty() )
|
||||||
{
|
{
|
||||||
Item item = stack.getItem();
|
if( stack.getItem() instanceof ItemPrintout && ItemPrintout.getType( stack ) != ItemPrintout.Type.Book )
|
||||||
if( item instanceof ItemPrintout && ItemPrintout.getType( stack ) != ItemPrintout.Type.Book )
|
|
||||||
{
|
{
|
||||||
if( printouts == null )
|
if( printouts == null )
|
||||||
{
|
{
|
||||||
@@ -80,7 +80,7 @@ public class PrintoutRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements
|
|||||||
numPrintouts++;
|
numPrintouts++;
|
||||||
printoutFound = true;
|
printoutFound = true;
|
||||||
}
|
}
|
||||||
else if( item == Items.PAPER )
|
else if( paper.apply( stack ) )
|
||||||
{
|
{
|
||||||
if( printouts == null )
|
if( printouts == null )
|
||||||
{
|
{
|
||||||
@@ -90,11 +90,11 @@ public class PrintoutRecipe extends IForgeRegistryEntry.Impl<IRecipe> implements
|
|||||||
numPages++;
|
numPages++;
|
||||||
numPrintouts++;
|
numPrintouts++;
|
||||||
}
|
}
|
||||||
else if( item == Items.STRING && !stringFound )
|
else if( string.apply( stack ) && !stringFound )
|
||||||
{
|
{
|
||||||
stringFound = true;
|
stringFound = true;
|
||||||
}
|
}
|
||||||
else if( item == Items.LEATHER && !leatherFound )
|
else if( leather.apply( stack ) && !leatherFound )
|
||||||
{
|
{
|
||||||
leatherFound = true;
|
leatherFound = true;
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,8 @@ public enum PeripheralType implements IStringSerializable
|
|||||||
Cable( "cable" ),
|
Cable( "cable" ),
|
||||||
WiredModemWithCable( "wired_modem_with_cable" ),
|
WiredModemWithCable( "wired_modem_with_cable" ),
|
||||||
AdvancedModem( "advanced_modem" ),
|
AdvancedModem( "advanced_modem" ),
|
||||||
Speaker( "speaker" );
|
Speaker( "speaker" ),
|
||||||
|
WiredModemFull( "wired_modem_full" );
|
||||||
|
|
||||||
private String m_name;
|
private String m_name;
|
||||||
|
|
||||||
|
@@ -11,7 +11,6 @@ import dan200.computercraft.shared.common.TileGeneric;
|
|||||||
import dan200.computercraft.shared.peripheral.PeripheralType;
|
import dan200.computercraft.shared.peripheral.PeripheralType;
|
||||||
import dan200.computercraft.shared.peripheral.modem.TileCable;
|
import dan200.computercraft.shared.peripheral.modem.TileCable;
|
||||||
import dan200.computercraft.shared.util.WorldUtil;
|
import dan200.computercraft.shared.util.WorldUtil;
|
||||||
import net.minecraft.block.Block;
|
|
||||||
import net.minecraft.block.properties.PropertyBool;
|
import net.minecraft.block.properties.PropertyBool;
|
||||||
import net.minecraft.block.properties.PropertyEnum;
|
import net.minecraft.block.properties.PropertyEnum;
|
||||||
import net.minecraft.block.state.BlockFaceShape;
|
import net.minecraft.block.state.BlockFaceShape;
|
||||||
@@ -51,23 +50,6 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
public static final PropertyBool DOWN = PropertyBool.create( "down" );
|
public static final PropertyBool DOWN = PropertyBool.create( "down" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isCable( IBlockAccess world, BlockPos pos )
|
|
||||||
{
|
|
||||||
Block block = world.getBlockState( pos ).getBlock();
|
|
||||||
if( block == ComputerCraft.Blocks.cable )
|
|
||||||
{
|
|
||||||
switch( ComputerCraft.Blocks.cable.getPeripheralType( world, pos ) )
|
|
||||||
{
|
|
||||||
case Cable:
|
|
||||||
case WiredModemWithCable:
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
|
|
||||||
public BlockCable()
|
public BlockCable()
|
||||||
@@ -175,20 +157,17 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean doesConnect( IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing dir )
|
public static boolean canConnectIn( IBlockState state, EnumFacing direction )
|
||||||
{
|
{
|
||||||
if( state.getValue( Properties.CABLE ) == BlockCableCableVariant.NONE )
|
return state.getValue( BlockCable.Properties.CABLE ) != BlockCableCableVariant.NONE
|
||||||
{
|
&& state.getValue( BlockCable.Properties.MODEM ).getFacing() != direction;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
else if( state.getValue( Properties.MODEM ).getFacing() == dir )
|
public static boolean doesConnectVisually( IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing direction )
|
||||||
{
|
{
|
||||||
return true;
|
if( state.getValue( Properties.CABLE ) == BlockCableCableVariant.NONE ) return false;
|
||||||
}
|
if( state.getValue( Properties.MODEM ).getFacing() == direction ) return true;
|
||||||
else
|
return ComputerCraft.getWiredElementAt( world, pos.offset( direction ), direction.getOpposite() ) != null;
|
||||||
{
|
|
||||||
return isCable( world, pos.offset( dir ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@@ -196,12 +175,12 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos )
|
public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos )
|
||||||
{
|
{
|
||||||
state = state.withProperty( Properties.NORTH, doesConnect( state, world, pos, EnumFacing.NORTH ) );
|
state = state.withProperty( Properties.NORTH, doesConnectVisually( state, world, pos, EnumFacing.NORTH ) );
|
||||||
state = state.withProperty( Properties.SOUTH, doesConnect( state, world, pos, EnumFacing.SOUTH ) );
|
state = state.withProperty( Properties.SOUTH, doesConnectVisually( state, world, pos, EnumFacing.SOUTH ) );
|
||||||
state = state.withProperty( Properties.EAST, doesConnect( state, world, pos, EnumFacing.EAST ) );
|
state = state.withProperty( Properties.EAST, doesConnectVisually( state, world, pos, EnumFacing.EAST ) );
|
||||||
state = state.withProperty( Properties.WEST, doesConnect( state, world, pos, EnumFacing.WEST ) );
|
state = state.withProperty( Properties.WEST, doesConnectVisually( state, world, pos, EnumFacing.WEST ) );
|
||||||
state = state.withProperty( Properties.UP, doesConnect( state, world, pos, EnumFacing.UP ) );
|
state = state.withProperty( Properties.UP, doesConnectVisually( state, world, pos, EnumFacing.UP ) );
|
||||||
state = state.withProperty( Properties.DOWN, doesConnect( state, world, pos, EnumFacing.DOWN ) );
|
state = state.withProperty( Properties.DOWN, doesConnectVisually( state, world, pos, EnumFacing.DOWN ) );
|
||||||
|
|
||||||
if( state.getValue( Properties.CABLE ) != BlockCableCableVariant.NONE )
|
if( state.getValue( Properties.CABLE ) != BlockCableCableVariant.NONE )
|
||||||
{
|
{
|
||||||
@@ -345,7 +324,6 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
if( WorldUtil.isVecInsideInclusive( bb, hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
|
if( WorldUtil.isVecInsideInclusive( bb, hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
|
||||||
{
|
{
|
||||||
world.setBlockState( pos, state.withProperty( Properties.MODEM, BlockCableModemVariant.None ), 3 );
|
world.setBlockState( pos, state.withProperty( Properties.MODEM, BlockCableModemVariant.None ), 3 );
|
||||||
cable.modemChanged();
|
|
||||||
item = PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 );
|
item = PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -365,6 +343,7 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
return super.removedByPlayer( state, world, pos, player, willHarvest );
|
return super.removedByPlayer( state, world, pos, player, willHarvest );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult hit, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
|
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult hit, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
|
||||||
{
|
{
|
||||||
@@ -373,7 +352,7 @@ public class BlockCable extends BlockPeripheralBase
|
|||||||
{
|
{
|
||||||
TileCable cable = (TileCable) tile;
|
TileCable cable = (TileCable) tile;
|
||||||
PeripheralType type = getPeripheralType( state );
|
PeripheralType type = getPeripheralType( state );
|
||||||
|
|
||||||
if( type == PeripheralType.WiredModemWithCable )
|
if( type == PeripheralType.WiredModemWithCable )
|
||||||
{
|
{
|
||||||
if( hit == null || WorldUtil.isVecInsideInclusive( cable.getModemBounds(), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
|
if( hit == null || WorldUtil.isVecInsideInclusive( cable.getModemBounds(), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
|
||||||
|
@@ -631,6 +631,13 @@ public class BlockPeripheral extends BlockPeripheralBase
|
|||||||
return isOpaqueCube( state );
|
return isOpaqueCube( state );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public boolean isFullBlock( IBlockState state )
|
||||||
|
{
|
||||||
|
return isOpaqueCube( state );
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@@ -638,4 +645,20 @@ public class BlockPeripheral extends BlockPeripheralBase
|
|||||||
{
|
{
|
||||||
return isOpaqueCube( state ) ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED;
|
return isOpaqueCube( state ) ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public boolean causesSuffocation(IBlockState state)
|
||||||
|
{
|
||||||
|
// This normally uses the default state
|
||||||
|
return blockMaterial.blocksMovement() && state.isOpaqueCube();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public int getLightOpacity( IBlockState state )
|
||||||
|
{
|
||||||
|
// This normally uses the default state
|
||||||
|
return isOpaqueCube( state ) ? 255 : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.shared.peripheral.common;
|
||||||
|
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.shared.peripheral.PeripheralType;
|
||||||
|
import dan200.computercraft.shared.peripheral.modem.TileWiredModemFull;
|
||||||
|
import net.minecraft.block.properties.PropertyBool;
|
||||||
|
import net.minecraft.block.state.BlockStateContainer;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.IBlockAccess;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public class BlockWiredModemFull extends BlockPeripheralBase
|
||||||
|
{
|
||||||
|
// Statics
|
||||||
|
|
||||||
|
public static class Properties
|
||||||
|
{
|
||||||
|
public static final PropertyBool MODEM_ON = PropertyBool.create( "modem" );
|
||||||
|
public static final PropertyBool PERIPHERAL_ON = PropertyBool.create( "peripheral" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Members
|
||||||
|
|
||||||
|
public BlockWiredModemFull()
|
||||||
|
{
|
||||||
|
setHardness( 1.5f );
|
||||||
|
setUnlocalizedName( "computercraft:wired_modem_full" );
|
||||||
|
setCreativeTab( ComputerCraft.mainCreativeTab );
|
||||||
|
setDefaultState( blockState.getBaseState()
|
||||||
|
.withProperty( Properties.MODEM_ON, false )
|
||||||
|
.withProperty( Properties.PERIPHERAL_ON, false )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IBlockState getDefaultBlockState( PeripheralType type, EnumFacing placedSide )
|
||||||
|
{
|
||||||
|
return getDefaultState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
protected BlockStateContainer createBlockState()
|
||||||
|
{
|
||||||
|
return new BlockStateContainer( this,
|
||||||
|
Properties.MODEM_ON,
|
||||||
|
Properties.PERIPHERAL_ON
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetaFromState( IBlockState state )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos )
|
||||||
|
{
|
||||||
|
TileEntity te = world.getTileEntity( pos );
|
||||||
|
if( te instanceof TileWiredModemFull )
|
||||||
|
{
|
||||||
|
TileWiredModemFull modem = (TileWiredModemFull) te;
|
||||||
|
int anim = modem.getAnim();
|
||||||
|
state = state
|
||||||
|
.withProperty( Properties.MODEM_ON, (anim & 1) != 0 )
|
||||||
|
.withProperty( Properties.PERIPHERAL_ON, (anim & 2) != 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PeripheralType getPeripheralType( int damage )
|
||||||
|
{
|
||||||
|
return PeripheralType.WiredModemFull;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PeripheralType getPeripheralType( IBlockState state )
|
||||||
|
{
|
||||||
|
return PeripheralType.WiredModemFull;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TilePeripheralBase createTile( PeripheralType type )
|
||||||
|
{
|
||||||
|
return new TileWiredModemFull();
|
||||||
|
}
|
||||||
|
}
|
@@ -11,8 +11,8 @@ import net.minecraft.block.Block;
|
|||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.item.ItemBlock;
|
import net.minecraft.item.ItemBlock;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@@ -102,6 +102,8 @@ public abstract class ItemPeripheralBase extends ItemBlock implements IPeriphera
|
|||||||
{
|
{
|
||||||
return "tile.computercraft:speaker";
|
return "tile.computercraft:speaker";
|
||||||
}
|
}
|
||||||
|
case WiredModemFull:
|
||||||
|
return "tile.computercraft:wired_modem";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,18 @@
|
|||||||
|
package dan200.computercraft.shared.peripheral.common;
|
||||||
|
|
||||||
|
import dan200.computercraft.shared.peripheral.PeripheralType;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
|
||||||
|
public class ItemWiredModemFull extends ItemPeripheralBase
|
||||||
|
{
|
||||||
|
public ItemWiredModemFull( Block block )
|
||||||
|
{
|
||||||
|
super( block );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PeripheralType getPeripheralType( int damage )
|
||||||
|
{
|
||||||
|
return PeripheralType.WiredModemFull;
|
||||||
|
}
|
||||||
|
}
|
@@ -47,6 +47,8 @@ public class PeripheralItemFactory
|
|||||||
{
|
{
|
||||||
return advancedModem.create( type, label, quantity );
|
return advancedModem.create( type, label, quantity );
|
||||||
}
|
}
|
||||||
|
case WiredModemFull:
|
||||||
|
return new ItemStack( ComputerCraft.Blocks.wiredModemFull, quantity );
|
||||||
}
|
}
|
||||||
return ItemStack.EMPTY;
|
return ItemStack.EMPTY;
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ public abstract class TilePeripheralBase extends TileGeneric
|
|||||||
{
|
{
|
||||||
// Statics
|
// Statics
|
||||||
|
|
||||||
private EnumFacing m_dir;
|
protected EnumFacing m_dir;
|
||||||
private int m_anim;
|
private int m_anim;
|
||||||
private boolean m_changed;
|
private boolean m_changed;
|
||||||
|
|
||||||
@@ -97,6 +97,11 @@ public abstract class TilePeripheralBase extends TileGeneric
|
|||||||
return m_dir;
|
return m_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EnumFacing getCachedDirection()
|
||||||
|
{
|
||||||
|
return m_dir;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDirection( EnumFacing dir )
|
public void setDirection( EnumFacing dir )
|
||||||
{
|
{
|
||||||
|
@@ -196,4 +196,11 @@ public class DiskDrivePeripheral implements IPeripheral
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Object getTarget()
|
||||||
|
{
|
||||||
|
return m_diskDrive;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,8 +8,8 @@ package dan200.computercraft.shared.peripheral.modem;
|
|||||||
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import net.minecraft.block.state.IBlockState;
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ public class TileAdvancedModem extends TileModemBase
|
|||||||
@Override
|
@Override
|
||||||
public Vec3d getPosition()
|
public Vec3d getPosition()
|
||||||
{
|
{
|
||||||
BlockPos pos = m_entity.getPos().offset( m_entity.getDirection() );
|
BlockPos pos = m_entity.getPos().offset( m_entity.getCachedDirection() );
|
||||||
return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
|
return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,9 +57,40 @@ public class TileAdvancedModem extends TileModemBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
|
private boolean m_hasDirection = false;
|
||||||
|
|
||||||
public TileAdvancedModem()
|
public TileAdvancedModem()
|
||||||
{
|
{
|
||||||
|
m_dir = EnumFacing.DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad()
|
||||||
|
{
|
||||||
|
super.onLoad();
|
||||||
|
updateDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateContainingBlockInfo()
|
||||||
|
{
|
||||||
|
m_hasDirection = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update()
|
||||||
|
{
|
||||||
|
super.update();
|
||||||
|
updateDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDirection()
|
||||||
|
{
|
||||||
|
if( !m_hasDirection )
|
||||||
|
{
|
||||||
|
m_hasDirection = true;
|
||||||
|
m_dir = getDirection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,416 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.shared.peripheral.modem;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredElement;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredElementTile;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
import dan200.computercraft.shared.peripheral.common.BlockCable;
|
||||||
|
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
|
||||||
|
import dan200.computercraft.shared.util.IDAssigner;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.util.text.TextComponentTranslation;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.Constants;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class TileWiredModemFull extends TilePeripheralBase implements IWiredElementTile
|
||||||
|
{
|
||||||
|
private static class FullElement extends WiredModemElement
|
||||||
|
{
|
||||||
|
private final TileWiredModemFull m_entity;
|
||||||
|
|
||||||
|
private FullElement( TileWiredModemFull m_entity )
|
||||||
|
{
|
||||||
|
this.m_entity = m_entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void attachPeripheral( String name, IPeripheral peripheral )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < 6; i++ )
|
||||||
|
{
|
||||||
|
WiredModemPeripheral modem = m_entity.m_modems[i];
|
||||||
|
if( modem != null && !name.equals( m_entity.getCachedPeripheralName( EnumFacing.VALUES[i] ) ) )
|
||||||
|
{
|
||||||
|
modem.attachPeripheral( name, peripheral );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void detachPeripheral( String name )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < 6; i++ )
|
||||||
|
{
|
||||||
|
WiredModemPeripheral modem = m_entity.m_modems[i];
|
||||||
|
if( modem != null ) modem.detachPeripheral( name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public World getWorld()
|
||||||
|
{
|
||||||
|
return m_entity.getWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Vec3d getPosition()
|
||||||
|
{
|
||||||
|
BlockPos pos = m_entity.getPos();
|
||||||
|
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Map<String, IPeripheral> getPeripherals()
|
||||||
|
{
|
||||||
|
return m_entity.getPeripherals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WiredModemPeripheral[] m_modems = new WiredModemPeripheral[6];
|
||||||
|
|
||||||
|
private boolean m_peripheralAccessAllowed = false;
|
||||||
|
private int[] m_attachedPeripheralIDs = new int[6];
|
||||||
|
private String[] m_attachedPeripheralTypes = new String[6];
|
||||||
|
|
||||||
|
private boolean m_destroyed = false;
|
||||||
|
private boolean m_connectionsFormed = false;
|
||||||
|
|
||||||
|
private final WiredModemElement m_element = new FullElement( this );
|
||||||
|
private final IWiredNode node = m_element.getNode();
|
||||||
|
|
||||||
|
public TileWiredModemFull()
|
||||||
|
{
|
||||||
|
Arrays.fill( m_attachedPeripheralIDs, -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void remove()
|
||||||
|
{
|
||||||
|
if( world == null || !world.isRemote )
|
||||||
|
{
|
||||||
|
node.remove();
|
||||||
|
m_connectionsFormed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy()
|
||||||
|
{
|
||||||
|
if( !m_destroyed )
|
||||||
|
{
|
||||||
|
m_destroyed = true;
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChunkUnload()
|
||||||
|
{
|
||||||
|
super.onChunkUnload();
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidate()
|
||||||
|
{
|
||||||
|
super.invalidate();
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumFacing getDirection()
|
||||||
|
{
|
||||||
|
return EnumFacing.NORTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDirection( EnumFacing dir )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNeighbourChange()
|
||||||
|
{
|
||||||
|
if( !world.isRemote && m_peripheralAccessAllowed )
|
||||||
|
{
|
||||||
|
Map<String, IPeripheral> updated = getPeripherals();
|
||||||
|
|
||||||
|
if( updated.isEmpty() )
|
||||||
|
{
|
||||||
|
// If there are no peripherals then disable access and update the display state.
|
||||||
|
m_peripheralAccessAllowed = false;
|
||||||
|
updateAnim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always invalidate the node: it's more accurate than checking if the peripherals
|
||||||
|
// have changed
|
||||||
|
node.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public AxisAlignedBB getBounds()
|
||||||
|
{
|
||||||
|
return BlockCable.FULL_BLOCK_AABB;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onActivate( EntityPlayer player, EnumFacing side, float hitX, float hitY, float hitZ )
|
||||||
|
{
|
||||||
|
if( !getWorld().isRemote )
|
||||||
|
{
|
||||||
|
// On server, we interacted if a peripheral was found
|
||||||
|
Set<String> oldPeriphName = getPeripherals().keySet();
|
||||||
|
togglePeripheralAccess();
|
||||||
|
Set<String> periphName = getPeripherals().keySet();
|
||||||
|
|
||||||
|
if( !Objects.equal( periphName, oldPeriphName ) )
|
||||||
|
{
|
||||||
|
if( !oldPeriphName.isEmpty() )
|
||||||
|
{
|
||||||
|
List<String> names = new ArrayList<>( oldPeriphName );
|
||||||
|
names.sort( Comparator.naturalOrder() );
|
||||||
|
|
||||||
|
player.sendMessage(
|
||||||
|
new TextComponentTranslation( "gui.computercraft:wired_modem.peripheral_disconnected", String.join( ", ", names ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if( !periphName.isEmpty() )
|
||||||
|
{
|
||||||
|
List<String> names = new ArrayList<>( periphName );
|
||||||
|
names.sort( Comparator.naturalOrder() );
|
||||||
|
player.sendMessage(
|
||||||
|
new TextComponentTranslation( "gui.computercraft:wired_modem.peripheral_connected", String.join( ", ", names ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// On client, we can't know this, so we assume so to be safe
|
||||||
|
// The server will correct us if we're wrong
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFromNBT( NBTTagCompound tag )
|
||||||
|
{
|
||||||
|
super.readFromNBT( tag );
|
||||||
|
m_peripheralAccessAllowed = tag.getBoolean( "peripheralAccess" );
|
||||||
|
for( int i = 0; i < m_attachedPeripheralIDs.length; i++ )
|
||||||
|
{
|
||||||
|
if( tag.hasKey( "peripheralID_" + i, Constants.NBT.TAG_ANY_NUMERIC ) )
|
||||||
|
{
|
||||||
|
m_attachedPeripheralIDs[i] = tag.getInteger( "peripheralID_" + i );
|
||||||
|
}
|
||||||
|
if( tag.hasKey( "peripheralType_" + i, Constants.NBT.TAG_STRING ) )
|
||||||
|
{
|
||||||
|
m_attachedPeripheralTypes[i] = tag.getString( "peripheralType_" + i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public NBTTagCompound writeToNBT( NBTTagCompound tag )
|
||||||
|
{
|
||||||
|
tag = super.writeToNBT( tag );
|
||||||
|
tag.setBoolean( "peripheralAccess", m_peripheralAccessAllowed );
|
||||||
|
for( int i = 0; i < m_attachedPeripheralIDs.length; i++ )
|
||||||
|
{
|
||||||
|
if( m_attachedPeripheralIDs[i] >= 0 )
|
||||||
|
{
|
||||||
|
tag.setInteger( "peripheralID_" + i, m_attachedPeripheralIDs[i] );
|
||||||
|
}
|
||||||
|
if( m_attachedPeripheralTypes[i] != null )
|
||||||
|
{
|
||||||
|
tag.setString( "peripheralType_" + i, m_attachedPeripheralTypes[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateAnim()
|
||||||
|
{
|
||||||
|
int anim = 0;
|
||||||
|
for( WiredModemPeripheral modem : m_modems )
|
||||||
|
{
|
||||||
|
if( modem != null && modem.isActive() )
|
||||||
|
{
|
||||||
|
anim += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_peripheralAccessAllowed )
|
||||||
|
{
|
||||||
|
anim += 2;
|
||||||
|
}
|
||||||
|
setAnim( anim );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void readDescription( @Nonnull NBTTagCompound tag )
|
||||||
|
{
|
||||||
|
super.readDescription( tag );
|
||||||
|
updateBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update()
|
||||||
|
{
|
||||||
|
if( !getWorld().isRemote )
|
||||||
|
{
|
||||||
|
boolean changed = false;
|
||||||
|
for( WiredModemPeripheral peripheral : m_modems )
|
||||||
|
{
|
||||||
|
if( peripheral != null && peripheral.pollChanged() ) changed = true;
|
||||||
|
}
|
||||||
|
if( changed ) updateAnim();
|
||||||
|
|
||||||
|
if( !m_connectionsFormed )
|
||||||
|
{
|
||||||
|
networkChanged();
|
||||||
|
m_connectionsFormed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void networkChanged()
|
||||||
|
{
|
||||||
|
if( getWorld().isRemote ) return;
|
||||||
|
|
||||||
|
World world = getWorld();
|
||||||
|
BlockPos current = getPos();
|
||||||
|
for( EnumFacing facing : EnumFacing.VALUES )
|
||||||
|
{
|
||||||
|
if( !world.isBlockLoaded( pos ) ) continue;
|
||||||
|
|
||||||
|
IWiredElement element = ComputerCraft.getWiredElementAt( world, current.offset( facing ), facing.getOpposite() );
|
||||||
|
if( element == null ) continue;
|
||||||
|
|
||||||
|
// If we can connect to it then do so
|
||||||
|
node.connectTo( element.getNode() );
|
||||||
|
}
|
||||||
|
|
||||||
|
node.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// private stuff
|
||||||
|
private void togglePeripheralAccess()
|
||||||
|
{
|
||||||
|
if( !m_peripheralAccessAllowed )
|
||||||
|
{
|
||||||
|
m_peripheralAccessAllowed = true;
|
||||||
|
if( getPeripherals().isEmpty() )
|
||||||
|
{
|
||||||
|
m_peripheralAccessAllowed = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_peripheralAccessAllowed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAnim();
|
||||||
|
node.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private Map<String, IPeripheral> getPeripherals()
|
||||||
|
{
|
||||||
|
if( !m_peripheralAccessAllowed ) return Collections.emptyMap();
|
||||||
|
|
||||||
|
Map<String, IPeripheral> peripherals = new HashMap<>( 6 );
|
||||||
|
for( EnumFacing facing : EnumFacing.VALUES )
|
||||||
|
{
|
||||||
|
BlockPos neighbour = getPos().offset( facing );
|
||||||
|
IPeripheral peripheral = TileCable.getPeripheral( getWorld(), neighbour, facing.getOpposite() );
|
||||||
|
if( peripheral != null && !(peripheral instanceof WiredModemPeripheral) )
|
||||||
|
{
|
||||||
|
String type = peripheral.getType();
|
||||||
|
int id = m_attachedPeripheralIDs[facing.ordinal()];
|
||||||
|
String oldType = m_attachedPeripheralTypes[facing.ordinal()];
|
||||||
|
if( id < 0 || !type.equals( oldType ) )
|
||||||
|
{
|
||||||
|
m_attachedPeripheralTypes[facing.ordinal()] = type;
|
||||||
|
id = m_attachedPeripheralIDs[facing.ordinal()] = IDAssigner.getNextIDFromFile( new File(
|
||||||
|
ComputerCraft.getWorldDir( getWorld() ),
|
||||||
|
"computer/lastid_" + type + ".txt"
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
peripherals.put( type + "_" + id, peripheral );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return peripherals;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getCachedPeripheralName( EnumFacing facing )
|
||||||
|
{
|
||||||
|
if( !m_peripheralAccessAllowed ) return null;
|
||||||
|
|
||||||
|
int id = m_attachedPeripheralIDs[facing.ordinal()];
|
||||||
|
String type = m_attachedPeripheralTypes[facing.ordinal()];
|
||||||
|
return id < 0 || type == null ? null : type + "_" + id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IWiredElementTile
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public IWiredElement getWiredElement( @Nonnull EnumFacing side )
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPeripheralTile
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IPeripheral getPeripheral( EnumFacing side )
|
||||||
|
{
|
||||||
|
WiredModemPeripheral peripheral = m_modems[side.ordinal()];
|
||||||
|
if( peripheral == null )
|
||||||
|
{
|
||||||
|
peripheral = m_modems[side.ordinal()] = new WiredModemPeripheral( m_element )
|
||||||
|
{
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Vec3d getPosition()
|
||||||
|
{
|
||||||
|
BlockPos pos = getPos().offset( side );
|
||||||
|
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return peripheral;
|
||||||
|
}
|
||||||
|
}
|
@@ -12,8 +12,8 @@ import dan200.computercraft.shared.peripheral.PeripheralType;
|
|||||||
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
|
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
|
||||||
import dan200.computercraft.shared.peripheral.common.BlockPeripheralVariant;
|
import dan200.computercraft.shared.peripheral.common.BlockPeripheralVariant;
|
||||||
import net.minecraft.block.state.IBlockState;
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ public class TileWirelessModem extends TileModemBase
|
|||||||
private static class Peripheral extends WirelessModemPeripheral
|
private static class Peripheral extends WirelessModemPeripheral
|
||||||
{
|
{
|
||||||
private TileModemBase m_entity;
|
private TileModemBase m_entity;
|
||||||
|
|
||||||
public Peripheral( TileModemBase entity )
|
public Peripheral( TileModemBase entity )
|
||||||
{
|
{
|
||||||
super( false );
|
super( false );
|
||||||
@@ -39,12 +39,12 @@ public class TileWirelessModem extends TileModemBase
|
|||||||
{
|
{
|
||||||
return m_entity.getWorld();
|
return m_entity.getWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Vec3d getPosition()
|
public Vec3d getPosition()
|
||||||
{
|
{
|
||||||
BlockPos pos = m_entity.getPos().offset( m_entity.getDirection() );
|
BlockPos pos = m_entity.getPos().offset( m_entity.getCachedDirection() );
|
||||||
return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
|
return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ public class TileWirelessModem extends TileModemBase
|
|||||||
{
|
{
|
||||||
if( other instanceof Peripheral )
|
if( other instanceof Peripheral )
|
||||||
{
|
{
|
||||||
Peripheral otherModem = (Peripheral)other;
|
Peripheral otherModem = (Peripheral) other;
|
||||||
return otherModem.m_entity == m_entity;
|
return otherModem.m_entity == m_entity;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -62,8 +62,40 @@ public class TileWirelessModem extends TileModemBase
|
|||||||
|
|
||||||
// Members
|
// Members
|
||||||
|
|
||||||
|
private boolean m_hasDirection = false;
|
||||||
|
|
||||||
public TileWirelessModem()
|
public TileWirelessModem()
|
||||||
{
|
{
|
||||||
|
m_dir = EnumFacing.DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad()
|
||||||
|
{
|
||||||
|
super.onLoad();
|
||||||
|
updateDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateContainingBlockInfo()
|
||||||
|
{
|
||||||
|
m_hasDirection = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update()
|
||||||
|
{
|
||||||
|
super.update();
|
||||||
|
updateDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDirection()
|
||||||
|
{
|
||||||
|
if( !m_hasDirection )
|
||||||
|
{
|
||||||
|
m_hasDirection = true;
|
||||||
|
m_dir = getDirection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -0,0 +1,59 @@
|
|||||||
|
package dan200.computercraft.shared.peripheral.modem;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredNetworkChange;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredElement;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
import dan200.computercraft.shared.wired.WiredNode;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public abstract class WiredModemElement implements IWiredElement
|
||||||
|
{
|
||||||
|
private final IWiredNode node = new WiredNode( this );
|
||||||
|
private final Map<String, IPeripheral> remotePeripherals = new HashMap<>();
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public IWiredNode getNode()
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getSenderID()
|
||||||
|
{
|
||||||
|
return "modem";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void networkChanged( @Nonnull IWiredNetworkChange change )
|
||||||
|
{
|
||||||
|
synchronized( remotePeripherals )
|
||||||
|
{
|
||||||
|
remotePeripherals.keySet().removeAll( change.peripheralsRemoved().keySet() );
|
||||||
|
for( String name : change.peripheralsRemoved().keySet() )
|
||||||
|
{
|
||||||
|
detachPeripheral( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( Map.Entry<String, IPeripheral> peripheral : change.peripheralsAdded().entrySet() )
|
||||||
|
{
|
||||||
|
attachPeripheral( peripheral.getKey(), peripheral.getValue() );
|
||||||
|
}
|
||||||
|
remotePeripherals.putAll( change.peripheralsAdded() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, IPeripheral> getRemotePeripherals()
|
||||||
|
{
|
||||||
|
return remotePeripherals;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void attachPeripheral( String name, IPeripheral peripheral );
|
||||||
|
|
||||||
|
protected abstract void detachPeripheral( String name );
|
||||||
|
}
|
@@ -0,0 +1,410 @@
|
|||||||
|
package dan200.computercraft.shared.peripheral.modem;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
|
import dan200.computercraft.api.network.IPacketNetwork;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||||
|
import dan200.computercraft.api.network.wired.IWiredSender;
|
||||||
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
||||||
|
|
||||||
|
public class WiredModemPeripheral extends ModemPeripheral implements IWiredSender
|
||||||
|
{
|
||||||
|
private final WiredModemElement modem;
|
||||||
|
|
||||||
|
private final Map<String, RemotePeripheralWrapper> peripheralWrappers = new HashMap<>();
|
||||||
|
|
||||||
|
public WiredModemPeripheral( WiredModemElement modem )
|
||||||
|
{
|
||||||
|
this.modem = modem;
|
||||||
|
}
|
||||||
|
|
||||||
|
//region IPacketSender implementation
|
||||||
|
@Override
|
||||||
|
public boolean isInterdimensional()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getRange()
|
||||||
|
{
|
||||||
|
return 256.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IPacketNetwork getNetwork()
|
||||||
|
{
|
||||||
|
return modem.getNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public World getWorld()
|
||||||
|
{
|
||||||
|
return modem.getWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Vec3d getPosition()
|
||||||
|
{
|
||||||
|
return modem.getPosition();
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region IPeripheral
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String[] getMethodNames()
|
||||||
|
{
|
||||||
|
String[] methods = super.getMethodNames();
|
||||||
|
String[] newMethods = new String[methods.length + 5];
|
||||||
|
System.arraycopy( methods, 0, newMethods, 0, methods.length );
|
||||||
|
newMethods[methods.length] = "getNamesRemote";
|
||||||
|
newMethods[methods.length + 1] = "isPresentRemote";
|
||||||
|
newMethods[methods.length + 2] = "getTypeRemote";
|
||||||
|
newMethods[methods.length + 3] = "getMethodsRemote";
|
||||||
|
newMethods[methods.length + 4] = "callRemote";
|
||||||
|
return newMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
|
||||||
|
{
|
||||||
|
String[] methods = super.getMethodNames();
|
||||||
|
switch( method - methods.length )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
// getNamesRemote
|
||||||
|
synchronized( peripheralWrappers )
|
||||||
|
{
|
||||||
|
int idx = 1;
|
||||||
|
Map<Object, Object> table = new HashMap<>();
|
||||||
|
for( String name : peripheralWrappers.keySet() )
|
||||||
|
{
|
||||||
|
table.put( idx++, name );
|
||||||
|
}
|
||||||
|
return new Object[]{ table };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
// isPresentRemote
|
||||||
|
String type = getTypeRemote( getString( arguments, 0 ) );
|
||||||
|
return new Object[]{ type != null };
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
// getTypeRemote
|
||||||
|
String type = getTypeRemote( getString( arguments, 0 ) );
|
||||||
|
if( type != null )
|
||||||
|
{
|
||||||
|
return new Object[]{ type };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
// getMethodsRemote
|
||||||
|
String[] methodNames = getMethodNamesRemote( getString( arguments, 0 ) );
|
||||||
|
if( methodNames != null )
|
||||||
|
{
|
||||||
|
Map<Object, Object> table = new HashMap<>();
|
||||||
|
for( int i = 0; i < methodNames.length; ++i )
|
||||||
|
{
|
||||||
|
table.put( i + 1, methodNames[i] );
|
||||||
|
}
|
||||||
|
return new Object[]{ table };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
// callRemote
|
||||||
|
String remoteName = getString( arguments, 0 );
|
||||||
|
String methodName = getString( arguments, 1 );
|
||||||
|
Object[] methodArgs = new Object[arguments.length - 2];
|
||||||
|
System.arraycopy( arguments, 2, methodArgs, 0, arguments.length - 2 );
|
||||||
|
return callMethodRemote( remoteName, context, methodName, methodArgs );
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// The regular modem methods
|
||||||
|
return super.callMethod( computer, context, method, arguments );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attach( @Nonnull IComputerAccess computer )
|
||||||
|
{
|
||||||
|
super.attach( computer );
|
||||||
|
synchronized( modem.getRemotePeripherals() )
|
||||||
|
{
|
||||||
|
synchronized( peripheralWrappers )
|
||||||
|
{
|
||||||
|
for( Map.Entry<String, IPeripheral> entry : modem.getRemotePeripherals().entrySet() )
|
||||||
|
{
|
||||||
|
attachPeripheralImpl( entry.getKey(), entry.getValue() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void detach( @Nonnull IComputerAccess computer )
|
||||||
|
{
|
||||||
|
synchronized( peripheralWrappers )
|
||||||
|
{
|
||||||
|
for( RemotePeripheralWrapper wrapper : peripheralWrappers.values() )
|
||||||
|
{
|
||||||
|
wrapper.detach();
|
||||||
|
}
|
||||||
|
peripheralWrappers.clear();
|
||||||
|
}
|
||||||
|
super.detach( computer );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals( IPeripheral other )
|
||||||
|
{
|
||||||
|
if( other instanceof WiredModemPeripheral )
|
||||||
|
{
|
||||||
|
WiredModemPeripheral otherModem = (WiredModemPeripheral) other;
|
||||||
|
return otherModem.modem == modem;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public IWiredNode getNode()
|
||||||
|
{
|
||||||
|
return modem.getNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attachPeripheral( String name, IPeripheral peripheral )
|
||||||
|
{
|
||||||
|
if( getComputer() == null ) return;
|
||||||
|
|
||||||
|
synchronized( peripheralWrappers )
|
||||||
|
{
|
||||||
|
attachPeripheralImpl( name, peripheral );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void detachPeripheral( String name )
|
||||||
|
{
|
||||||
|
synchronized( peripheralWrappers )
|
||||||
|
{
|
||||||
|
RemotePeripheralWrapper wrapper = peripheralWrappers.get( name );
|
||||||
|
if( wrapper != null )
|
||||||
|
{
|
||||||
|
peripheralWrappers.remove( name );
|
||||||
|
wrapper.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attachPeripheralImpl( String periphName, IPeripheral peripheral )
|
||||||
|
{
|
||||||
|
if( !peripheralWrappers.containsKey( periphName ) )
|
||||||
|
{
|
||||||
|
RemotePeripheralWrapper wrapper = new RemotePeripheralWrapper( modem, peripheral, getComputer(), periphName );
|
||||||
|
peripheralWrappers.put( periphName, wrapper );
|
||||||
|
wrapper.attach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTypeRemote( String remoteName )
|
||||||
|
{
|
||||||
|
synchronized( peripheralWrappers )
|
||||||
|
{
|
||||||
|
RemotePeripheralWrapper wrapper = peripheralWrappers.get( remoteName );
|
||||||
|
if( wrapper != null )
|
||||||
|
{
|
||||||
|
return wrapper.getType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] getMethodNamesRemote( String remoteName )
|
||||||
|
{
|
||||||
|
synchronized( peripheralWrappers )
|
||||||
|
{
|
||||||
|
RemotePeripheralWrapper wrapper = peripheralWrappers.get( remoteName );
|
||||||
|
if( wrapper != null )
|
||||||
|
{
|
||||||
|
return wrapper.getMethodNames();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object[] callMethodRemote( String remoteName, ILuaContext context, String method, Object[] arguments ) throws LuaException, InterruptedException
|
||||||
|
{
|
||||||
|
RemotePeripheralWrapper wrapper;
|
||||||
|
synchronized( peripheralWrappers )
|
||||||
|
{
|
||||||
|
wrapper = peripheralWrappers.get( remoteName );
|
||||||
|
}
|
||||||
|
if( wrapper != null )
|
||||||
|
{
|
||||||
|
return wrapper.callMethod( context, method, arguments );
|
||||||
|
}
|
||||||
|
throw new LuaException( "No peripheral: " + remoteName );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RemotePeripheralWrapper implements IComputerAccess
|
||||||
|
{
|
||||||
|
private final WiredModemElement m_element;
|
||||||
|
private final IPeripheral m_peripheral;
|
||||||
|
private final IComputerAccess m_computer;
|
||||||
|
private final String m_name;
|
||||||
|
|
||||||
|
private final String m_type;
|
||||||
|
private final String[] m_methods;
|
||||||
|
private final Map<String, Integer> m_methodMap;
|
||||||
|
|
||||||
|
public RemotePeripheralWrapper( WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name )
|
||||||
|
{
|
||||||
|
m_element = element;
|
||||||
|
m_peripheral = peripheral;
|
||||||
|
m_computer = computer;
|
||||||
|
m_name = name;
|
||||||
|
|
||||||
|
m_type = peripheral.getType();
|
||||||
|
m_methods = peripheral.getMethodNames();
|
||||||
|
assert (m_type != null);
|
||||||
|
assert (m_methods != null);
|
||||||
|
|
||||||
|
m_methodMap = new HashMap<>();
|
||||||
|
for( int i = 0; i < m_methods.length; ++i )
|
||||||
|
{
|
||||||
|
if( m_methods[i] != null )
|
||||||
|
{
|
||||||
|
m_methodMap.put( m_methods[i], i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attach()
|
||||||
|
{
|
||||||
|
m_peripheral.attach( this );
|
||||||
|
m_computer.queueEvent( "peripheral", new Object[]{ getAttachmentName() } );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void detach()
|
||||||
|
{
|
||||||
|
m_peripheral.detach( this );
|
||||||
|
m_computer.queueEvent( "peripheral_detach", new Object[]{ getAttachmentName() } );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType()
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getMethodNames()
|
||||||
|
{
|
||||||
|
return m_methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] callMethod( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException
|
||||||
|
{
|
||||||
|
if( m_methodMap.containsKey( methodName ) )
|
||||||
|
{
|
||||||
|
int method = m_methodMap.get( methodName );
|
||||||
|
return m_peripheral.callMethod( this, context, method, arguments );
|
||||||
|
}
|
||||||
|
throw new LuaException( "No such method " + methodName );
|
||||||
|
}
|
||||||
|
|
||||||
|
// IComputerAccess implementation
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String mount( @Nonnull String desiredLocation, @Nonnull IMount mount )
|
||||||
|
{
|
||||||
|
return m_computer.mount( desiredLocation, mount, m_name );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String mount( @Nonnull String desiredLocation, @Nonnull IMount mount, @Nonnull String driveName )
|
||||||
|
{
|
||||||
|
return m_computer.mount( desiredLocation, mount, driveName );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount )
|
||||||
|
{
|
||||||
|
return m_computer.mountWritable( desiredLocation, mount, m_name );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount, @Nonnull String driveName )
|
||||||
|
{
|
||||||
|
return m_computer.mountWritable( desiredLocation, mount, driveName );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unmount( String location )
|
||||||
|
{
|
||||||
|
m_computer.unmount( location );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getID()
|
||||||
|
{
|
||||||
|
return m_computer.getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void queueEvent( @Nonnull String event, Object[] arguments )
|
||||||
|
{
|
||||||
|
m_computer.queueEvent( event, arguments );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getAttachmentName()
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Map<String, IPeripheral> getAvailablePeripherals()
|
||||||
|
{
|
||||||
|
synchronized( m_element.getRemotePeripherals() )
|
||||||
|
{
|
||||||
|
return ImmutableMap.copyOf( m_element.getRemotePeripherals() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IPeripheral getAvailablePeripheral( @Nonnull String name )
|
||||||
|
{
|
||||||
|
synchronized( m_element.getRemotePeripherals() )
|
||||||
|
{
|
||||||
|
return m_element.getRemotePeripherals().get( name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,86 @@
|
|||||||
|
package dan200.computercraft.shared.peripheral.monitor;
|
||||||
|
|
||||||
|
import dan200.computercraft.shared.common.ClientTerminal;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ClientMonitor extends ClientTerminal
|
||||||
|
{
|
||||||
|
private static final Set<ClientMonitor> allMonitors = new HashSet<>();
|
||||||
|
|
||||||
|
private final TileMonitor origin;
|
||||||
|
|
||||||
|
public long lastRenderFrame = -1;
|
||||||
|
public int[] renderDisplayLists = null;
|
||||||
|
|
||||||
|
public ClientMonitor( boolean colour, TileMonitor origin )
|
||||||
|
{
|
||||||
|
super( colour );
|
||||||
|
this.origin = origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TileMonitor getOrigin()
|
||||||
|
{
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createLists()
|
||||||
|
{
|
||||||
|
if( renderDisplayLists == null )
|
||||||
|
{
|
||||||
|
renderDisplayLists = new int[3];
|
||||||
|
|
||||||
|
for( int i = 0; i < renderDisplayLists.length; i++ )
|
||||||
|
{
|
||||||
|
renderDisplayLists[i] = GlStateManager.glGenLists( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized( allMonitors )
|
||||||
|
{
|
||||||
|
allMonitors.add( this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy()
|
||||||
|
{
|
||||||
|
if( renderDisplayLists != null )
|
||||||
|
{
|
||||||
|
synchronized( allMonitors )
|
||||||
|
{
|
||||||
|
allMonitors.remove( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int list : renderDisplayLists )
|
||||||
|
{
|
||||||
|
GlStateManager.glDeleteLists( list, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
renderDisplayLists = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void destroyAll()
|
||||||
|
{
|
||||||
|
synchronized( allMonitors )
|
||||||
|
{
|
||||||
|
for( Iterator<ClientMonitor> iterator = allMonitors.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
ClientMonitor monitor = iterator.next();
|
||||||
|
if( monitor.renderDisplayLists != null )
|
||||||
|
{
|
||||||
|
for( int list : monitor.renderDisplayLists )
|
||||||
|
{
|
||||||
|
GlStateManager.glDeleteLists( list, 1 );
|
||||||
|
}
|
||||||
|
monitor.renderDisplayLists = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user