Upload base

This commit is contained in:
oxmc
2025-03-28 11:36:56 -04:00
commit 6e91539412
307 changed files with 21459 additions and 0 deletions

23
.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
# eclipse
bin
*.launch
.settings
.metadata
.classpath
.project
# idea
out
*.ipr
*.iws
*.iml
.idea
# gradle
build
.gradle
# other
eclipse
run
/_OLD

1
LICENSE Normal file
View File

@@ -0,0 +1 @@
This mod and its source code is now in public domain. Feel free to do whatever you want with it; make forks, distribute it... whatever I would appreciate it, of course, if you credited me 😊 Thank you!

18
README.md Normal file
View File

@@ -0,0 +1,18 @@
# WebDisplays for Minecraft 1.12.2
This is the WebDisplays mod for Minecraft 1.12.2. I don't have time to maintain it anymore, so I changed the license recently and anybody is welcome to create forks and/or re-distribute it. For more info see [LICENSE](LICENSE).
### Wiki
* The Wiki that details all blocks/items can be found on my website https://montoyo.net/wdwiki/
### Things before release
* Release ready. Targeted release date: 17/02/2018.
### Delayed things
* Plugin API
* The Shop
* CC Interface, if CC gets updated...
* Center camera to screen when using keyboard
* minePad management: check GuiContainer.draggedStack for minePad
* In-game command to add/remove blacklisted domains
* Config: RPMP (Real pixels per Minecraft pixels)
* Disable miniserv in solo

80
build.gradle Normal file
View File

@@ -0,0 +1,80 @@
buildscript {
repositories {
jcenter()
maven { url = "http://files.minecraftforge.net/maven" }
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
version = "1.12.2-1.4"
group = "net.montoyo.wd" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "webdisplays"
sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
compileJava {
sourceCompatibility = targetCompatibility = '1.8'
}
minecraft {
version = "1.12.2-14.23.5.2768"
runDir = "run"
// the mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD snapshot are built nightly.
// stable_# stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not always work.
// simply re-run your setup task after changing the mappings to update your workspace.
mappings = "snapshot_20171003"
makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
}
repositories {
mavenCentral()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
maven {
name = "ComputerCraft and CC:Tweaked"
url = 'https://maven.squiddev.cc/'
}
maven {
name = "OpenComputers"
url = "http://maven.cil.li/"
}
}
dependencies {
deobfCompile "org.squiddev:cc-tweaked-1.12.2:1.89.2"
compile "li.cil.oc:OpenComputers:MC1.12.2-1.7.5.+:api"
}
jar {
exclude 'org/**'
exclude 'net/montoyo/mcef/**'
exclude 'assets/mcef/**'
}
processResources {
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
// replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
// replace version and mcversion
expand 'version':project.version, 'mcversion':project.minecraft.version
}
// copy everything else except the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}

3
gradle.properties Normal file
View File

@@ -0,0 +1,3 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Mon Sep 14 12:28:28 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip

164
gradlew vendored Normal file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
gradlew.bat vendored Normal file
View File

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

BIN
libs/mcef.jar Normal file

Binary file not shown.

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.fml.server.FMLServerHandler;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.core.HasAdvancement;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.data.GuiData;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.*;
import javax.annotation.Nonnull;
public class SharedProxy {
public static final int CURRENT_DIMENSION = Integer.MAX_VALUE;
public void preInit() {
}
public void init() {
}
public void postInit() {
}
public World getWorld(int dim) {
if(dim == CURRENT_DIMENSION)
throw new RuntimeException("Current dimension not available server side...");
return DimensionManager.getWorld(dim);
}
public void enqueue(Runnable r) {
FMLServerHandler.instance().getServer().addScheduledTask(r);
}
public void displayGui(GuiData data) {
Log.error("Called SharedProxy.displayGui() on server side...");
}
public void trackScreen(TileEntityScreen tes, boolean track) {
}
public void onAutocompleteResult(NameUUIDPair pairs[]) {
}
public GameProfile[] getOnlineGameProfiles() {
return FMLServerHandler.instance().getServer().getOnlinePlayerProfiles();
}
public void screenUpdateResolutionInGui(Vector3i pos, BlockSide side, Vector2i res) {
}
public void screenUpdateRotationInGui(Vector3i pos, BlockSide side, Rotation rot) {
}
public void screenUpdateAutoVolumeInGui(Vector3i pos, BlockSide side, boolean av) {
}
public void displaySetPadURLGui(String padURL) {
Log.error("Called SharedProxy.displaySetPadURLGui() on server side...");
}
public void openMinePadGui(int padId) {
Log.error("Called SharedProxy.openMinePadGui() on server side...");
}
public void handleJSResponseSuccess(int reqId, JSServerRequest type, byte[] data) {
Log.error("Called SharedProxy.handleJSResponseSuccess() on server side...");
}
public void handleJSResponseError(int reqId, JSServerRequest type, int errCode, String err) {
Log.error("Called SharedProxy.handleJSResponseError() on server side...");
}
@Nonnull
public HasAdvancement hasClientPlayerAdvancement(@Nonnull ResourceLocation rl) {
return HasAdvancement.DONT_KNOW;
}
public MinecraftServer getServer() {
return FMLServerHandler.instance().getServer();
}
public void setMiniservClientPort(int port) {
}
public void startMiniservClient() {
}
public boolean isMiniservDisabled() {
return false;
}
public void closeGui(BlockPos bp, BlockSide bs) {
}
public void renderRecipes() {
}
public boolean isShiftDown() {
return false;
}
}

View File

@@ -0,0 +1,512 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd;
import com.google.gson.Gson;
import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.client.event.ClientChatEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.ServerChatEvent;
import net.minecraftforge.event.entity.item.ItemTossEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.*;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.montoyo.wd.block.BlockKeyboardRight;
import net.montoyo.wd.block.BlockPeripheral;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.core.*;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.item.*;
import net.montoyo.wd.miniserv.server.Server;
import net.montoyo.wd.net.client.CMessageServerInfo;
import net.montoyo.wd.net.Messages;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Util;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.UUID;
@Mod(modid = "webdisplays", version = WebDisplays.MOD_VERSION, dependencies = "required-after:mcef@[1.0,3.0);after:opencomputers;after:computercraft;")
public class WebDisplays {
public static final String MOD_VERSION = "1.4";
@Mod.Instance(owner = "webdisplays")
public static WebDisplays INSTANCE;
@SidedProxy(serverSide = "net.montoyo.wd.SharedProxy", clientSide = "net.montoyo.wd.client.ClientProxy")
public static SharedProxy PROXY;
public static SimpleNetworkWrapper NET_HANDLER;
public static WDCreativeTab CREATIVE_TAB;
public static final ResourceLocation ADV_PAD_BREAK = new ResourceLocation("webdisplays", "webdisplays/pad_break");
public static final String BLACKLIST_URL = "mod://webdisplays/blacklisted.html";
public static final Gson GSON = new Gson();
public static final ResourceLocation CAPABILITY = new ResourceLocation("webdisplays", "customdatacap");
//Blocks
public BlockScreen blockScreen;
public BlockPeripheral blockPeripheral;
public BlockKeyboardRight blockKbRight;
//Items
public ItemScreenConfigurator itemScreenCfg;
public ItemOwnershipThief itemOwnerThief;
public ItemLinker itemLinker;
public ItemMinePad2 itemMinePad;
public ItemUpgrade itemUpgrade;
public ItemLaserPointer itemLaserPointer;
public ItemCraftComponent itemCraftComp;
public ItemMulti itemAdvIcon;
//Sounds
public SoundEvent soundTyping;
public SoundEvent soundUpgradeAdd;
public SoundEvent soundUpgradeDel;
public SoundEvent soundScreenCfg;
public SoundEvent soundServer;
public SoundEvent soundIronic;
//Criterions
public Criterion criterionPadBreak;
public Criterion criterionUpgradeScreen;
public Criterion criterionLinkPeripheral;
public Criterion criterionKeyboardCat;
//Config
public static final double PAD_RATIO = 59.0 / 30.0;
public String homePage;
public double padResX;
public double padResY;
private int lastPadId = 0;
public boolean doHardRecipe;
private boolean hasOC;
private boolean hasCC;
private String[] blacklist;
public boolean disableOwnershipThief;
public double unloadDistance2;
public double loadDistance2;
public int maxResX;
public int maxResY;
public int maxScreenX;
public int maxScreenY;
public int miniservPort;
public long miniservQuota;
public boolean enableSoundDistance;
public float ytVolume;
public float avDist100;
public float avDist0;
@Mod.EventHandler
public void onPreInit(FMLPreInitializationEvent ev) {
//Load config
Configuration cfg = new Configuration(ev.getSuggestedConfigurationFile());
cfg.load();
//CAT: Main
Property blacklist = cfg.get("main", "blacklist", new String[0]);
Property padHeight = cfg.get("main", "padHeight", 480);
Property hardRecipe = cfg.get("main", "hardRecipes", true);
Property homePage = cfg.get("main", "homepage", "mod://webdisplays/main.html");
Property disableOT = cfg.get("main", "disableOwnershipThief", false);
Property maxResX = cfg.get("main", "maxResolutionX", 1920);
Property maxResY = cfg.get("main", "maxResolutionY", 1080);
Property miniservPort = cfg.get("main", "miniservPort", 25566);
Property miniservQuota = cfg.get("main", "miniservQuota", 1024); //It's stored as a string anyway
Property maxScreenX = cfg.get("main", "maxScreenSizeX", 16);
Property maxScreenY = cfg.get("main", "maxScreenSizeY", 16);
//CAT: Client options
Property loadDistance = cfg.get("client", "loadDistance", 30.0);
Property unloadDistance = cfg.get("client", "unloadDistance", 32.0);
//CAT: Auto volume config (client-side)
Property enableAutoVol = cfg.get("clientAutoVolume", "enableAutoVolume", true);
Property ytVolume = cfg.get("clientAutoVolume", "ytVolume", 100.0);
Property dist100 = cfg.get("clientAutoVolume", "dist100", 10.0);
Property dist0 = cfg.get("clientAutoVolume", "dist0", 30.0);
//Comments & shit
blacklist.setComment("An array of domain names you don't want to load.");
padHeight.setComment("The minePad Y resolution in pixels. padWidth = padHeight * " + PAD_RATIO);
hardRecipe.setComment("If true, breaking the minePad is required to craft upgrades.");
homePage.setComment("The URL that will be loaded each time you create a screen");
disableOT.setComment("If true, the ownership thief item will be disabled");
loadDistance.setComment("All screens outside this range will be unloaded");
unloadDistance.setComment("All unloaded screens inside this range will be loaded");
maxResX.setComment("Maximum horizontal screen resolution, in pixels");
maxResY.setComment("Maximum vertical screen resolution, in pixels");
miniservPort.setComment("The port used by miniserv. 0 to disable.");
miniservPort.setMaxValue(Short.MAX_VALUE);
miniservQuota.setComment("The amount of data that can be uploaded to miniserv, in KiB (so 1024 = 1 MiO)");
maxScreenX.setComment("Maximum screen width, in blocks. Resolution will be clamped by maxResolutionX.");
maxScreenY.setComment("Maximum screen height, in blocks. Resolution will be clamped by maxResolutionY.");
enableAutoVol.setComment("If true, the volume of YouTube videos will change depending on how far you are");
ytVolume.setComment("Volume for YouTube videos. This will have no effect if enableSoundDistance is set to false");
ytVolume.setMinValue(0.0);
ytVolume.setMaxValue(100.0);
dist100.setComment("Distance after which the sound starts dropping (in blocks)");
dist100.setMinValue(0.0);
dist0.setComment("Distance after which you can't hear anything (in blocks)");
dist0.setMinValue(0.0);
if(unloadDistance.getDouble() < loadDistance.getDouble() + 2.0)
unloadDistance.set(loadDistance.getDouble() + 2.0);
if(dist0.getDouble() < dist100.getDouble() + 0.1)
dist0.set(dist100.getDouble() + 0.1);
cfg.save();
this.blacklist = blacklist.getStringList();
doHardRecipe = hardRecipe.getBoolean();
this.homePage = homePage.getString();
disableOwnershipThief = disableOT.getBoolean();
unloadDistance2 = unloadDistance.getDouble() * unloadDistance.getDouble();
loadDistance2 = loadDistance.getDouble() * loadDistance.getDouble();
this.maxResX = maxResX.getInt();
this.maxResY = maxResY.getInt();
this.miniservPort = miniservPort.getInt();
this.miniservQuota = miniservQuota.getLong() * 1024L;
this.maxScreenX = maxScreenX.getInt();
this.maxScreenY = maxScreenY.getInt();
enableSoundDistance = enableAutoVol.getBoolean();
this.ytVolume = (float) ytVolume.getDouble();
avDist100 = (float) dist100.getDouble();
avDist0 = (float) dist0.getDouble();
CREATIVE_TAB = new WDCreativeTab();
//Criterions
criterionPadBreak = new Criterion("pad_break");
criterionUpgradeScreen = new Criterion("upgrade_screen");
criterionLinkPeripheral = new Criterion("link_peripheral");
criterionKeyboardCat = new Criterion("keyboard_cat");
registerTrigger(criterionPadBreak, criterionUpgradeScreen, criterionLinkPeripheral, criterionKeyboardCat);
//Read configuration
padResY = (double) padHeight.getInt();
padResX = padResY * PAD_RATIO;
//Init blocks
blockScreen = new BlockScreen();
blockScreen.makeItemBlock();
blockPeripheral = new BlockPeripheral();
blockPeripheral.makeItemBlock();
blockKbRight = new BlockKeyboardRight();
//Init items
itemScreenCfg = new ItemScreenConfigurator();
itemOwnerThief = new ItemOwnershipThief();
itemLinker = new ItemLinker();
itemMinePad = new ItemMinePad2();
itemUpgrade = new ItemUpgrade();
itemLaserPointer = new ItemLaserPointer();
itemCraftComp = new ItemCraftComponent();
itemAdvIcon = new ItemMulti(AdvancementIcon.class);
itemAdvIcon.setUnlocalizedName("webdisplays.advicon");
itemAdvIcon.setRegistryName("advicon");
PROXY.preInit();
MinecraftForge.EVENT_BUS.register(this);
}
@Mod.EventHandler
public void onInit(FMLInitializationEvent ev) {
//Register tile entities
GameRegistry.registerTileEntity(TileEntityScreen.class, new ResourceLocation("webdisplays", "screen"));
for(DefaultPeripheral dp: DefaultPeripheral.values()) {
if(dp.getTEClass() != null)
GameRegistry.registerTileEntity(dp.getTEClass(), new ResourceLocation("webdisplays", dp.getName()));
}
//Other things
CapabilityManager.INSTANCE.register(IWDDCapability.class, new WDDCapability.Storage(), new WDDCapability.Factory());
PROXY.init();
NET_HANDLER = NetworkRegistry.INSTANCE.newSimpleChannel("webdisplays");
Messages.registerAll(NET_HANDLER);
}
@Mod.EventHandler
public void onPostInit(FMLPostInitializationEvent ev) {
PROXY.postInit();
hasOC = Loader.isModLoaded("opencomputers");
hasCC = Loader.isModLoaded("computercraft");
if(hasCC) {
try {
//We have to do this because the "register" method might be stripped out if CC isn't loaded
CCPeripheralProvider.class.getMethod("register").invoke(null);
} catch(Throwable t) {
Log.error("ComputerCraft was found, but WebDisplays wasn't able to register its CC Interface Peripheral");
t.printStackTrace();
}
}
}
@SubscribeEvent
public void onRegisterBlocks(RegistryEvent.Register<Block> ev) {
ev.getRegistry().registerAll(blockScreen, blockPeripheral, blockKbRight);
}
@SubscribeEvent
public void onRegisterItems(RegistryEvent.Register<Item> ev) {
ev.getRegistry().registerAll(blockScreen.getItem(), blockPeripheral.getItem());
ev.getRegistry().registerAll(itemScreenCfg, itemOwnerThief, itemLinker, itemMinePad, itemUpgrade, itemLaserPointer, itemCraftComp, itemAdvIcon);
}
@SubscribeEvent
public void onRegisterSounds(RegistryEvent.Register<SoundEvent> ev) {
soundTyping = registerSound(ev, "keyboardType");
soundUpgradeAdd = registerSound(ev, "upgradeAdd");
soundUpgradeDel = registerSound(ev, "upgradeDel");
soundScreenCfg = registerSound(ev, "screencfgOpen");
soundServer = registerSound(ev, "server");
soundIronic = registerSound(ev, "ironic");
}
@SubscribeEvent
public void onWorldLoad(WorldEvent.Load ev) {
if(ev.getWorld().isRemote || ev.getWorld().provider.getDimension() != 0)
return;
File worldDir = ev.getWorld().getSaveHandler().getWorldDirectory();
File f = new File(worldDir, "wd_next.txt");
if(f.exists()) {
try {
BufferedReader br = new BufferedReader(new FileReader(f));
String idx = br.readLine();
Util.silentClose(br);
if(idx == null)
throw new RuntimeException("Seems like the file is empty (1)");
idx = idx.trim();
if(idx.isEmpty())
throw new RuntimeException("Seems like the file is empty (2)");
lastPadId = Integer.parseInt(idx); //This will throw NumberFormatException if it goes wrong
} catch(Throwable t) {
Log.warningEx("Could not read last minePad ID from %s. I'm afraid this might break all minePads.", t, f.getAbsolutePath());
}
}
if(miniservPort != 0) {
Server sv = Server.getInstance();
sv.setPort(miniservPort);
sv.setDirectory(new File(worldDir, "wd_filehost"));
sv.start();
}
}
@SubscribeEvent
public void onWorldSave(WorldEvent.Save ev) {
if(ev.getWorld().isRemote || ev.getWorld().provider.getDimension() != 0)
return;
File f = new File(ev.getWorld().getSaveHandler().getWorldDirectory(), "wd_next.txt");
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
bw.write("" + lastPadId + "\n");
Util.silentClose(bw);
} catch(Throwable t) {
Log.warningEx("Could not save last minePad ID (%d) to %s. I'm afraid this might break all minePads.", t, lastPadId, f.getAbsolutePath());
}
}
@SubscribeEvent
public void onToss(ItemTossEvent ev) {
if(!ev.getEntityItem().world.isRemote) {
ItemStack is = ev.getEntityItem().getItem();
if(is.getItem() == itemMinePad) {
NBTTagCompound tag = is.getTagCompound();
if(tag == null) {
tag = new NBTTagCompound();
is.setTagCompound(tag);
}
UUID thrower = ev.getPlayer().getGameProfile().getId();
tag.setLong("ThrowerMSB", thrower.getMostSignificantBits());
tag.setLong("ThrowerLSB", thrower.getLeastSignificantBits());
tag.setDouble("ThrowHeight", ev.getPlayer().posY + ev.getPlayer().getEyeHeight());
}
}
}
@SubscribeEvent
public void onPlayerCraft(PlayerEvent.ItemCraftedEvent ev) {
if(doHardRecipe && ev.crafting.getItem() == itemCraftComp && ev.crafting.getMetadata() == CraftComponent.EXTENSION_CARD.ordinal()) {
if((ev.player instanceof EntityPlayerMP && !hasPlayerAdvancement((EntityPlayerMP) ev.player, ADV_PAD_BREAK)) || PROXY.hasClientPlayerAdvancement(ADV_PAD_BREAK) != HasAdvancement.YES) {
ev.crafting.setItemDamage(CraftComponent.BAD_EXTENSION_CARD.ordinal());
if(!ev.player.world.isRemote)
ev.player.world.playSound(null, ev.player.posX, ev.player.posY, ev.player.posZ, SoundEvents.ENTITY_ITEM_BREAK, SoundCategory.MASTER, 1.0f, 1.0f);
}
}
}
@Mod.EventHandler
public void onServerStop(FMLServerStoppingEvent ev) {
Server.getInstance().stopServer();
}
@SubscribeEvent
public void onLogIn(PlayerEvent.PlayerLoggedInEvent ev) {
if(!ev.player.world.isRemote && ev.player instanceof EntityPlayerMP) {
WebDisplays.NET_HANDLER.sendTo(new CMessageServerInfo(miniservPort), (EntityPlayerMP) ev.player);
IWDDCapability cap = ev.player.getCapability(WDDCapability.INSTANCE, null);
if(cap == null)
Log.warning("Player %s (%s) has null IWDDCapability!", ev.player.getName(), ev.player.getGameProfile().getId().toString());
else if(cap.isFirstRun()) {
Util.toast(ev.player, TextFormatting.LIGHT_PURPLE, "welcome1");
Util.toast(ev.player, TextFormatting.LIGHT_PURPLE, "welcome2");
Util.toast(ev.player, TextFormatting.LIGHT_PURPLE, "welcome3");
cap.clearFirstRun();
}
}
}
@SubscribeEvent
public void onLogOut(PlayerEvent.PlayerLoggedOutEvent ev) {
if(!ev.player.world.isRemote)
Server.getInstance().getClientManager().revokeClientKey(ev.player.getGameProfile().getId());
}
@SubscribeEvent
public void attachEntityCaps(AttachCapabilitiesEvent<Entity> ev) {
if(ev.getObject() instanceof EntityPlayer)
ev.addCapability(CAPABILITY, new WDDCapability.Provider());
}
@SubscribeEvent
public void onPlayerClone(net.minecraftforge.event.entity.player.PlayerEvent.Clone ev) {
IWDDCapability src = ev.getOriginal().getCapability(WDDCapability.INSTANCE, null);
IWDDCapability dst = ev.getEntityPlayer().getCapability(WDDCapability.INSTANCE, null);
if(src == null) {
Log.error("src is null");
return;
}
if(dst == null) {
Log.error("dst is null");
return;
}
src.cloneTo(dst);
}
@SubscribeEvent
public void onServerChat(ServerChatEvent ev) {
String msg = ev.getMessage().trim().replaceAll("\\s+", " ").toLowerCase();
StringBuilder sb = new StringBuilder(msg.length());
for(int i = 0; i < msg.length(); i++) {
char chr = msg.charAt(i);
if(chr != '.' && chr != ',' && chr != ';' && chr != '!' && chr != '?' && chr != ':' && chr != '\'' && chr != '\"' && chr != '`')
sb.append(chr);
}
if(sb.toString().equals("ironic he could save others from death but not himself")) {
EntityPlayer ply = ev.getPlayer();
ply.world.playSound(null, ply.posX, ply.posY, ply.posZ, soundIronic, SoundCategory.PLAYERS, 1.0f, 1.0f);
}
}
@SubscribeEvent
public void onClientChat(ClientChatEvent ev) {
if(ev.getMessage().equals("!WD render recipes"))
PROXY.renderRecipes();
}
private boolean hasPlayerAdvancement(EntityPlayerMP ply, ResourceLocation rl) {
MinecraftServer server = PROXY.getServer();
if(server == null)
return false;
Advancement adv = server.getAdvancementManager().getAdvancement(rl);
return adv != null && ply.getAdvancements().getProgress(adv).isDone();
}
public static int getNextAvailablePadID() {
return INSTANCE.lastPadId++;
}
private static SoundEvent registerSound(RegistryEvent.Register<SoundEvent> ev, String resName) {
ResourceLocation resLoc = new ResourceLocation("webdisplays", resName);
SoundEvent ret = new SoundEvent(resLoc);
ret.setRegistryName(resLoc);
ev.getRegistry().register(ret);
return ret;
}
private static void registerTrigger(Criterion ... criteria) {
for(Criterion c: criteria)
CriteriaTriggers.register(c);
}
public static boolean isOpenComputersAvailable() {
return INSTANCE.hasOC;
}
public static boolean isComputerCraftAvailable() {
return INSTANCE.hasCC;
}
public static boolean isSiteBlacklisted(String url) {
try {
URL url2 = new URL(Util.addProtocol(url));
return Arrays.stream(INSTANCE.blacklist).anyMatch(str -> str.equalsIgnoreCase(url2.getHost()));
} catch(MalformedURLException ex) {
return false;
}
}
public static String applyBlacklist(String url) {
return isSiteBlacklisted(url) ? BLACKLIST_URL : url;
}
}

View File

@@ -0,0 +1,224 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.block;
import net.minecraft.block.Block;
import net.minecraft.block.material.EnumPushReaction;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.DefaultPeripheral;
import net.montoyo.wd.core.IPeripheral;
import net.montoyo.wd.entity.TileEntityKeyboard;
import net.montoyo.wd.item.ItemLinker;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Vector3i;
import javax.annotation.Nonnull;
import java.util.Random;
public class BlockKeyboardRight extends Block implements IPeripheral {
public static final PropertyInteger facing = PropertyInteger.create("facing", 0, 3);
private static final IProperty[] properties = new IProperty[] { facing };
public static final AxisAlignedBB KEYBOARD_AABB = new AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 1.0 / 16.0, 1.0);
public BlockKeyboardRight() {
super(Material.ROCK);
setHardness(1.5f);
setResistance(10.f);
setUnlocalizedName("webdisplays.peripheral.keyboard");
setRegistryName("keyboard");
fullBlock = false;
}
@Override
@Nonnull
protected BlockStateContainer createBlockState() {
return new BlockStateContainer(this, properties);
}
@Override
public int quantityDropped(Random random) {
return 0;
}
@Override
public boolean isFullCube(IBlockState state) {
return false;
}
@Override
public boolean isFullBlock(IBlockState state) {
return false;
}
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) {
return false;
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
@Override
public boolean doesSideBlockRendering(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing face) {
return false;
}
@Override
@Nonnull
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
return KEYBOARD_AABB;
}
@Override
@Nonnull
public IBlockState getStateFromMeta(int meta) {
return getDefaultState().withProperty(facing, meta);
}
@Override
public int getMetaFromState(IBlockState state) {
return state.getValue(facing);
}
@Override
@Nonnull
public ItemStack getPickBlock(@Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player) {
return new ItemStack(WebDisplays.INSTANCE.blockPeripheral, 1, 0);
}
private TileEntityKeyboard getTileEntity(World world, BlockPos pos) {
for(EnumFacing nf: EnumFacing.HORIZONTALS) {
BlockPos np = pos.add(nf.getDirectionVec());
IBlockState ns = world.getBlockState(np);
if(ns.getBlock() instanceof BlockPeripheral && ns.getValue(BlockPeripheral.type) == DefaultPeripheral.KEYBOARD) {
TileEntity te = world.getTileEntity(np);
if(te != null && te instanceof TileEntityKeyboard)
return (TileEntityKeyboard) te;
break;
}
}
return null;
}
@Override
public boolean connect(World world, BlockPos pos, IBlockState state, Vector3i scrPos, BlockSide scrSide) {
TileEntityKeyboard keyboard = getTileEntity(world, pos);
return keyboard != null && keyboard.connect(world, pos, state, scrPos, scrSide);
}
@Override
@Nonnull
public EnumPushReaction getMobilityFlag(IBlockState state) {
return EnumPushReaction.IGNORE;
}
public static boolean checkNeighborhood(IBlockAccess world, BlockPos bp, BlockPos ignore) {
for(EnumFacing neighbor: EnumFacing.HORIZONTALS) {
BlockPos np = bp.add(neighbor.getDirectionVec());
if(ignore == null || !np.equals(ignore)) {
IBlockState state = world.getBlockState(np);
if(state.getBlock() instanceof BlockPeripheral) {
if(state.getValue(BlockPeripheral.type) == DefaultPeripheral.KEYBOARD)
return false;
} else if(state.getBlock() instanceof BlockKeyboardRight)
return false;
}
}
return true;
}
public void removeLeftPiece(World world, BlockPos pos, boolean dropItem) {
for(EnumFacing nf: EnumFacing.HORIZONTALS) {
BlockPos np = pos.add(nf.getDirectionVec());
IBlockState ns = world.getBlockState(np);
if(ns.getBlock() instanceof BlockPeripheral && ns.getValue(BlockPeripheral.type) == DefaultPeripheral.KEYBOARD) {
if(dropItem)
ns.getBlock().dropBlockAsItem(world, np, ns, 0);
world.setBlockToAir(np);
break;
}
}
}
@Override
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block neighborType, BlockPos neighbor) {
if(world.isRemote)
return;
if(neighbor.getX() == pos.getX() && neighbor.getY() == pos.getY() - 1 && neighbor.getZ() == pos.getZ() && world.isAirBlock(neighbor)) {
removeLeftPiece(world, pos, true);
world.setBlockToAir(pos);
}
}
@Override
public boolean removedByPlayer(@Nonnull IBlockState state, World world, @Nonnull BlockPos pos, @Nonnull EntityPlayer ply, boolean willHarvest) {
if(!world.isRemote)
removeLeftPiece(world, pos, !ply.isCreative());
return super.removedByPlayer(state, world, pos, ply, willHarvest);
}
@Override
public void onBlockDestroyedByExplosion(World world, BlockPos pos, Explosion explosionIn) {
if(!world.isRemote)
removeLeftPiece(world, pos, true);
}
@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
double rpos = (entity.posY - ((double) pos.getY())) * 16.0;
if(!world.isRemote && rpos >= 1.0 && rpos <= 2.0 && Math.random() < 0.25) {
TileEntityKeyboard tek = getTileEntity(world, pos);
if(tek != null)
tek.simulateCat(entity);
}
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
if(player.isSneaking())
return false;
if(player.getHeldItem(hand).getItem() instanceof ItemLinker)
return false;
TileEntityKeyboard tek = getTileEntity(world, pos);
if(tek != null)
return tek.onRightClick(player, hand, BlockSide.values()[facing.ordinal()]);
return false;
}
}

View File

@@ -0,0 +1,281 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.block;
import net.minecraft.block.Block;
import net.minecraft.block.material.EnumPushReaction;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.DefaultPeripheral;
import net.montoyo.wd.entity.*;
import net.montoyo.wd.item.ItemLinker;
import net.montoyo.wd.item.ItemPeripheral;
import net.montoyo.wd.net.client.CMessageCloseGui;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import javax.annotation.Nonnull;
public class BlockPeripheral extends WDBlockContainer {
public static final PropertyEnum<DefaultPeripheral> type = PropertyEnum.create("type", DefaultPeripheral.class);
public static final PropertyInteger facing = PropertyInteger.create("facing", 0, 3);
private static final IProperty[] properties = new IProperty[] { type, facing };
public BlockPeripheral() {
super(Material.ROCK);
setHardness(1.5f);
setResistance(10.f);
setCreativeTab(WebDisplays.CREATIVE_TAB);
setName("peripheral");
}
@Override
protected ItemBlock createItemBlock() {
return new ItemPeripheral(this);
}
@Override
@Nonnull
protected BlockStateContainer createBlockState() {
return new BlockStateContainer(this, properties);
}
@Override
@Nonnull
public IBlockState getStateForPlacement(@Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing nocare, float hitX,
float hitY, float hitZ, int meta, @Nonnull EntityLivingBase placer, EnumHand hand) {
int rot = MathHelper.floor(((double) (placer.rotationYaw * 4.0f / 360.0f)) + 2.5) & 3;
return getDefaultState().withProperty(type, DefaultPeripheral.fromMetadata(meta)).withProperty(facing, rot);
}
@Override
public void getSubBlocks(CreativeTabs tab, NonNullList<ItemStack> list) {
for(DefaultPeripheral dp : DefaultPeripheral.values())
list.add(new ItemStack(getItem(), 1, dp.toMetadata(0)));
}
@Override
@Nonnull
public IBlockState getStateFromMeta(int meta) {
DefaultPeripheral dp = DefaultPeripheral.fromMetadata(meta);
IBlockState state = getDefaultState().withProperty(type, dp);
if(dp.hasFacing())
state = state.withProperty(facing, (meta >> 2) & 3);
return state;
}
@Override
public int getMetaFromState(IBlockState state) {
return state.getValue(type).toMetadata(state.getValue(facing));
}
@Override
public TileEntity createNewTileEntity(@Nonnull World world, int meta) {
Class<? extends TileEntity> cls = DefaultPeripheral.fromMetadata(meta).getTEClass();
if(cls == null)
return null;
try {
return cls.newInstance();
} catch(Throwable t) {
Log.errorEx("Couldn't instantiate peripheral TileEntity:", t);
}
return null;
}
@Override
@Nonnull
public EnumBlockRenderType getRenderType(IBlockState state) {
return EnumBlockRenderType.MODEL;
}
@Override
public int damageDropped(IBlockState state) {
return state.getValue(type).toMetadata(0);
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
if(player.isSneaking())
return false;
if(player.getHeldItem(hand).getItem() instanceof ItemLinker)
return false;
TileEntity te = world.getTileEntity(pos);
if(te instanceof TileEntityPeripheralBase)
return ((TileEntityPeripheralBase) te).onRightClick(player, hand, BlockSide.values()[facing.ordinal()]);
else if(te instanceof TileEntityServer) {
((TileEntityServer) te).onPlayerRightClick(player);
return true;
} else
return false;
}
@Override
public boolean isFullCube(IBlockState state) {
return state.getValue(type) != DefaultPeripheral.KEYBOARD;
}
@Override
public boolean isFullBlock(IBlockState state) {
return state.getValue(type) != DefaultPeripheral.KEYBOARD;
}
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) {
return state.getValue(type) != DefaultPeripheral.KEYBOARD;
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return state.getValue(type) != DefaultPeripheral.KEYBOARD;
}
@Override
public boolean doesSideBlockRendering(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing face) {
return state.getValue(type) != DefaultPeripheral.KEYBOARD;
}
@Override
@Nonnull
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
return state.getValue(type) == DefaultPeripheral.KEYBOARD ? BlockKeyboardRight.KEYBOARD_AABB : FULL_BLOCK_AABB;
}
@Override
public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) {
if(world.isRemote)
return;
if(state.getValue(type) == DefaultPeripheral.KEYBOARD) {
//Keyboard special treatment
int f = state.getValue(facing);
Vec3i dir = EnumFacing.getHorizontal(f).rotateY().getDirectionVec();
BlockPos left = pos.add(dir);
BlockPos right = pos.subtract(dir);
if(!world.isAirBlock(pos.down()) && BlockKeyboardRight.checkNeighborhood(world, pos, null)) {
if(world.isAirBlock(right) && !world.isAirBlock(right.down()) && BlockKeyboardRight.checkNeighborhood(world, right, pos)) {
world.setBlockState(right, WebDisplays.INSTANCE.blockKbRight.getDefaultState().withProperty(BlockKeyboardRight.facing, f));
return;
} else if(world.isAirBlock(left) && !world.isAirBlock(left.down()) && BlockKeyboardRight.checkNeighborhood(world, left, pos)) {
world.setBlockState(left, state);
world.setBlockState(pos, WebDisplays.INSTANCE.blockKbRight.getDefaultState().withProperty(BlockKeyboardRight.facing, f));
return;
}
}
//Not good; remove this shit...
world.setBlockToAir(pos);
if(!(placer instanceof EntityPlayer) || !((EntityPlayer) placer).isCreative())
dropBlockAsItem(world, pos, state, 0);
} else if(placer instanceof EntityPlayer) {
TileEntity te = world.getTileEntity(pos);
if(te instanceof TileEntityServer)
((TileEntityServer) te).setOwner((EntityPlayer) placer);
else if(te instanceof TileEntityInterfaceBase)
((TileEntityInterfaceBase) te).setOwner((EntityPlayer) placer);
}
}
@Override
@Nonnull
public EnumPushReaction getMobilityFlag(IBlockState state) {
return EnumPushReaction.IGNORE;
}
private void removeRightPiece(World world, BlockPos pos) {
for(EnumFacing nf: EnumFacing.HORIZONTALS) {
BlockPos np = pos.add(nf.getDirectionVec());
if(world.getBlockState(np).getBlock() instanceof BlockKeyboardRight) {
world.setBlockToAir(np);
break;
}
}
}
@Override
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block neighborType, BlockPos neighbor) {
TileEntity te = world.getTileEntity(pos);
if(te != null && te instanceof TileEntityPeripheralBase)
((TileEntityPeripheralBase) te).onNeighborChange(neighborType, neighbor);
if(world.isRemote || state.getValue(type) != DefaultPeripheral.KEYBOARD)
return;
if(neighbor.getX() == pos.getX() && neighbor.getY() == pos.getY() - 1 && neighbor.getZ() == pos.getZ() && world.isAirBlock(neighbor)) {
removeRightPiece(world, pos);
world.setBlockToAir(pos);
dropBlockAsItem(world, pos, state, 0);
WebDisplays.NET_HANDLER.sendToAllAround(new CMessageCloseGui(pos), point(world, pos));
}
}
@Override
public void onBlockDestroyedByPlayer(World world, BlockPos pos, IBlockState state) {
if(!world.isRemote) {
if(state.getBlock() == this && state.getValue(type) == DefaultPeripheral.KEYBOARD)
removeRightPiece(world, pos);
WebDisplays.NET_HANDLER.sendToAllAround(new CMessageCloseGui(pos), point(world, pos));
}
}
@Override
public void onBlockDestroyedByExplosion(World world, BlockPos pos, Explosion explosion) {
onBlockDestroyedByPlayer(world, pos, world.getBlockState(pos));
}
@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
if(!world.isRemote && world.getBlockState(pos).getValue(type) == DefaultPeripheral.KEYBOARD) {
double rpos = (entity.posY - ((double) pos.getY())) * 16.0;
if(rpos >= 1.0 && rpos <= 2.0 && Math.random() < 0.25) {
TileEntity te = world.getTileEntity(pos);
if(te != null && te instanceof TileEntityKeyboard)
((TileEntityKeyboard) te).simulateCat(entity);
}
}
}
private static NetworkRegistry.TargetPoint point(World world, BlockPos bp) {
return new NetworkRegistry.TargetPoint(world.provider.getDimension(), (double) bp.getX(), (double) bp.getY(), (double) bp.getZ(), 64.0);
}
}

View File

@@ -0,0 +1,400 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.block;
import net.minecraft.block.Block;
import net.minecraft.block.material.EnumPushReaction;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.property.ExtendedBlockState;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import net.minecraftforge.common.property.Properties;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.core.IUpgrade;
import net.montoyo.wd.data.SetURLData;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.item.WDItem;
import net.montoyo.wd.utilities.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class BlockScreen extends WDBlockContainer {
public static final PropertyBool hasTE = PropertyBool.create("haste");
public static final PropertyBool emitting = PropertyBool.create("emitting");
private static final IProperty[] properties = new IProperty[] { hasTE, emitting };
public static final IUnlistedProperty<Integer>[] sideFlags = new IUnlistedProperty[6];
static {
for(int i = 0; i < sideFlags.length; i++)
sideFlags[i] = Properties.toUnlisted(PropertyInteger.create("neighbor" + i, 0, 15));
}
private static final int BAR_BOT = 1;
private static final int BAR_RIGHT = 2;
private static final int BAR_TOP = 4;
private static final int BAR_LEFT = 8;
public BlockScreen() {
super(Material.ROCK);
setHardness(1.5f);
setResistance(10.f);
setCreativeTab(WebDisplays.CREATIVE_TAB);
setName("screen");
setDefaultState(blockState.getBaseState().withProperty(hasTE, false).withProperty(emitting, false));
}
@Override
@Nonnull
public EnumBlockRenderType getRenderType(IBlockState state) {
return EnumBlockRenderType.MODEL;
}
@Override
@Nonnull
protected BlockStateContainer createBlockState() {
return new ExtendedBlockState(this, properties, sideFlags);
}
public static boolean isntScreenBlock(IBlockAccess world, Vector3i pos) {
return world.getBlockState(pos.toBlock()).getBlock() != WebDisplays.INSTANCE.blockScreen;
}
@Override
@Nonnull
public IBlockState getExtendedState(@Nonnull IBlockState state, IBlockAccess world, BlockPos bpos) {
IExtendedBlockState ret = (IExtendedBlockState) blockState.getBaseState();
Vector3i pos = new Vector3i(bpos);
for(BlockSide side : BlockSide.values()) {
int icon = 0;
if(isntScreenBlock(world, side.up.clone().add(pos))) icon |= BAR_TOP;
if(isntScreenBlock(world, side.down.clone().add(pos))) icon |= BAR_BOT;
if(isntScreenBlock(world, side.left.clone().add(pos))) icon |= BAR_LEFT;
if(isntScreenBlock(world, side.right.clone().add(pos))) icon |= BAR_RIGHT;
ret = ret.withProperty(sideFlags[side.ordinal()], icon);
}
return ret;
}
@Override
@Nonnull
public IBlockState getStateFromMeta(int meta) {
return getDefaultState().withProperty(hasTE, (meta & 1) != 0).withProperty(emitting, (meta & 2) != 0);
}
@Override
public int getMetaFromState(IBlockState state) {
int ret = 0;
if(state.getValue(hasTE))
ret |= 1;
if(state.getValue(emitting))
ret |= 2;
return ret;
}
@Override
public boolean onBlockActivated(World world, BlockPos bpos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
ItemStack heldItem = player.getHeldItem(hand);
if(heldItem.isEmpty())
heldItem = null; //Easier to work with
else if(!(heldItem.getItem() instanceof IUpgrade))
return false;
if(world.isRemote)
return true;
boolean sneaking = player.isSneaking();
Vector3i pos = new Vector3i(bpos);
BlockSide side = BlockSide.values()[facing.ordinal()];
Multiblock.findOrigin(world, pos, side, null);
TileEntityScreen te = (TileEntityScreen) world.getTileEntity(pos.toBlock());
if(te != null && te.getScreen(side) != null) {
TileEntityScreen.Screen scr = te.getScreen(side);
if(sneaking) { //Set URL
if((scr.rightsFor(player) & ScreenRights.CHANGE_URL) == 0)
Util.toast(player, "restrictions");
else
(new SetURLData(pos, scr.side, scr.url)).sendTo((EntityPlayerMP) player);
return true;
} else if(heldItem != null && !te.hasUpgrade(side, heldItem)) { //Add upgrade
if((scr.rightsFor(player) & ScreenRights.MANAGE_UPGRADES) == 0) {
Util.toast(player, "restrictions");
return true;
}
if(te.addUpgrade(side, heldItem, player, false)) {
if(!player.isCreative())
heldItem.shrink(1);
Util.toast(player, TextFormatting.AQUA, "upgradeOk");
if(player instanceof EntityPlayerMP)
WebDisplays.INSTANCE.criterionUpgradeScreen.trigger(((EntityPlayerMP) player).getAdvancements());
} else
Util.toast(player, "upgradeError");
return true;
} else { //Click
if((scr.rightsFor(player) & ScreenRights.CLICK) == 0) {
Util.toast(player, "restrictions");
return true;
}
Vector2i tmp = new Vector2i();
if(hit2pixels(side, bpos, pos, scr, hitX, hitY, hitZ, tmp))
te.click(side, tmp);
return true;
}
} else if(sneaking) {
Util.toast(player, "turnOn");
return true;
}
Vector2i size = Multiblock.measure(world, pos, side);
if(size.x < 2 || size.y < 2) {
Util.toast(player, "tooSmall");
return true;
}
if(size.x > WebDisplays.INSTANCE.maxScreenX || size.y > WebDisplays.INSTANCE.maxScreenY) {
Util.toast(player, "tooBig", WebDisplays.INSTANCE.maxScreenX, WebDisplays.INSTANCE.maxScreenY);
return true;
}
Vector3i err = Multiblock.check(world, pos, size, side);
if(err != null) {
Util.toast(player, "invalid", err.toString());
return true;
}
boolean created = false;
Log.info("Player %s (UUID %s) created a screen at %s of size %dx%d", player.getName(), player.getGameProfile().getId().toString(), pos.toString(), size.x, size.y);
if(te == null) {
BlockPos bp = pos.toBlock();
world.setBlockState(bp, world.getBlockState(bp).withProperty(hasTE, true));
te = (TileEntityScreen) world.getTileEntity(bp);
created = true;
}
te.addScreen(side, size, null, player, !created);
return true;
}
@Override
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos source) {
if(block != this && !world.isRemote && !state.getValue(emitting)) {
for(BlockSide side: BlockSide.values()) {
Vector3i vec = new Vector3i(pos);
Multiblock.findOrigin(world, vec, side, null);
TileEntityScreen tes = (TileEntityScreen) world.getTileEntity(vec.toBlock());
if(tes != null && tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_INPUT)) {
EnumFacing facing = EnumFacing.VALUES[side.reverse().ordinal()]; //Opposite face
vec.sub(pos.getX(), pos.getY(), pos.getZ()).neg();
tes.updateJSRedstone(side, new Vector2i(vec.dot(side.right), vec.dot(side.up)), world.getRedstonePower(pos, facing));
}
}
}
}
public static boolean hit2pixels(BlockSide side, BlockPos bpos, Vector3i pos, TileEntityScreen.Screen scr, float hitX, float hitY, float hitZ, Vector2i dst) {
if(side.right.x < 0)
hitX -= 1.f;
if(side.right.z < 0 || side == BlockSide.TOP || side == BlockSide.BOTTOM)
hitZ -= 1.f;
Vector3f rel = new Vector3f(bpos.getX(), bpos.getY(), bpos.getZ());
rel.sub((float) pos.x, (float) pos.y, (float) pos.z);
rel.add(hitX, hitY, hitZ);
float cx = rel.dot(side.right.toFloat()) - 2.f / 16.f;
float cy = rel.dot(side.up.toFloat()) - 2.f / 16.f;
float sw = ((float) scr.size.x) - 4.f / 16.f;
float sh = ((float) scr.size.y) - 4.f / 16.f;
cx /= sw;
cy /= sh;
if(cx >= 0.f && cx <= 1.0 && cy >= 0.f && cy <= 1.f) {
if(side != BlockSide.BOTTOM)
cy = 1.f - cy;
switch(scr.rotation) {
case ROT_90:
cy = 1.0f - cy;
break;
case ROT_180:
cx = 1.0f - cx;
cy = 1.0f - cy;
break;
case ROT_270:
cx = 1.0f - cx;
break;
default:
break;
}
cx *= (float) scr.resolution.x;
cy *= (float) scr.resolution.y;
if(scr.rotation.isVertical) {
dst.x = (int) cy;
dst.y = (int) cx;
} else {
dst.x = (int) cx;
dst.y = (int) cy;
}
return true;
}
return false;
}
@Nullable
@Override
public TileEntity createNewTileEntity(@Nonnull World world, int meta) {
if((meta & 1) == 0)
return null;
return ((meta & 1) == 0) ? null : new TileEntityScreen();
}
/************************************************* DESTRUCTION HANDLING *************************************************/
private void onDestroy(World world, BlockPos pos, EntityPlayer ply) {
if(!world.isRemote) {
Vector3i bp = new Vector3i(pos);
Multiblock.BlockOverride override = new Multiblock.BlockOverride(bp, Multiblock.OverrideAction.SIMULATE);
for(BlockSide bs: BlockSide.values())
destroySide(world, bp.clone(), bs, override, ply);
}
}
private void destroySide(World world, Vector3i pos, BlockSide side, Multiblock.BlockOverride override, EntityPlayer source) {
Multiblock.findOrigin(world, pos, side, override);
BlockPos bp = pos.toBlock();
TileEntity te = world.getTileEntity(bp);
if(te != null && te instanceof TileEntityScreen) {
((TileEntityScreen) te).onDestroy(source);
world.setBlockState(bp, world.getBlockState(bp).withProperty(hasTE, false)); //Destroy tile entity.
}
}
@Override
public boolean removedByPlayer(@Nonnull IBlockState state, World world, @Nonnull BlockPos pos, @Nonnull EntityPlayer ply, boolean willHarvest) {
onDestroy(world, pos, ply);
return super.removedByPlayer(state, world, pos, ply, willHarvest);
}
@Override
public void onBlockDestroyedByExplosion(World world, BlockPos pos, Explosion explosion) {
onDestroy(world, pos, null);
}
@Override
public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase whoDidThisShit, ItemStack stack) {
if(world.isRemote)
return;
Multiblock.BlockOverride override = new Multiblock.BlockOverride(new Vector3i(pos), Multiblock.OverrideAction.IGNORE);
Vector3i[] neighbors = new Vector3i[6];
neighbors[0] = new Vector3i(pos.getX() + 1, pos.getY(), pos.getZ());
neighbors[1] = new Vector3i(pos.getX() - 1, pos.getY(), pos.getZ());
neighbors[2] = new Vector3i(pos.getX(), pos.getY() + 1, pos.getZ());
neighbors[3] = new Vector3i(pos.getX(), pos.getY() - 1, pos.getZ());
neighbors[4] = new Vector3i(pos.getX(), pos.getY(), pos.getZ() + 1);
neighbors[5] = new Vector3i(pos.getX(), pos.getY(), pos.getZ() - 1);
for(Vector3i neighbor: neighbors) {
if(world.getBlockState(neighbor.toBlock()).getBlock() instanceof BlockScreen) {
for(BlockSide bs: BlockSide.values())
destroySide(world, neighbor.clone(), bs, override, (whoDidThisShit instanceof EntityPlayer) ? ((EntityPlayer) whoDidThisShit) : null);
}
}
}
@Override
@Nonnull
public EnumPushReaction getMobilityFlag(IBlockState state) {
return EnumPushReaction.IGNORE;
}
@Override
public int getWeakPower(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing side) {
return state.getValue(emitting) ? 15 : 0;
}
@Override
public boolean canProvidePower(IBlockState state) {
return state.getValue(emitting);
}
@Override
protected ItemBlock createItemBlock() {
return new ItemBlockScreen(this);
}
private static class ItemBlockScreen extends ItemBlock implements WDItem {
public ItemBlockScreen(BlockScreen screen) {
super(screen);
}
@Nullable
@Override
public String getWikiName(@Nonnull ItemStack is) {
return "Screen";
}
@Override
public void addInformation(@Nullable ItemStack is, @Nullable World world, @Nullable List<String> tt, @Nullable ITooltipFlag ttFlags) {
super.addInformation(is, world, tt, ttFlags);
WDItem.addInformation(tt);
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.block;
import net.minecraft.block.Block;
import net.minecraft.block.material.MapColor;
import net.minecraft.block.material.Material;
import net.minecraft.item.ItemBlock;
public abstract class WDBlock extends Block {
protected ItemBlock itemBlock;
public WDBlock(Material mat, MapColor color) {
super(mat, color);
}
public WDBlock(Material material) {
super(material);
}
protected void setName(String name) {
setUnlocalizedName("webdisplays." + name);
setRegistryName(name);
}
public void makeItemBlock() {
if(itemBlock != null)
throw new RuntimeException("WDBlock.makeItemBlock() called twice!");
itemBlock = new ItemBlock(this);
itemBlock.setUnlocalizedName(getUnlocalizedName());
itemBlock.setRegistryName(getRegistryName());
}
public ItemBlock getItem() {
return itemBlock;
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.MapColor;
import net.minecraft.block.material.Material;
import net.minecraft.item.ItemBlock;
public abstract class WDBlockContainer extends BlockContainer {
protected ItemBlock itemBlock;
public WDBlockContainer(Material material) {
super(material);
}
protected void setName(String name) {
setUnlocalizedName("webdisplays." + name);
setRegistryName(name);
}
protected abstract ItemBlock createItemBlock();
public void makeItemBlock() {
if(itemBlock != null)
throw new RuntimeException("WDBlockContainer.makeItemBlock() called twice!");
itemBlock = createItemBlock();
itemBlock.setUnlocalizedName(getUnlocalizedName());
itemBlock.setRegistryName(getRegistryName());
}
public ItemBlock getItem() {
return itemBlock;
}
}

View File

@@ -0,0 +1,790 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.client;
import com.mojang.authlib.GameProfile;
import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.AdvancementProgress;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.multiplayer.ClientAdvancementManager;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.SimpleReloadableResourceManager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumHandSide;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.client.event.*;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.resource.IResourceType;
import net.minecraftforge.client.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.montoyo.mcef.api.*;
import net.montoyo.wd.SharedProxy;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.client.gui.*;
import net.montoyo.wd.client.gui.loading.GuiLoader;
import net.montoyo.wd.client.renderers.*;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.HasAdvancement;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.data.GuiData;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.item.ItemMulti;
import net.montoyo.wd.item.WDItem;
import net.montoyo.wd.miniserv.client.Client;
import net.montoyo.wd.net.server.SMessagePadCtrl;
import net.montoyo.wd.net.server.SMessageScreenCtrl;
import net.montoyo.wd.utilities.*;
import org.lwjgl.input.Keyboard;
import paulscode.sound.SoundSystemConfig;
import javax.annotation.Nonnull;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.*;
import java.util.function.Predicate;
public class ClientProxy extends SharedProxy implements ISelectiveResourceReloadListener, IDisplayHandler, IJSQueryHandler {
public class PadData {
public IBrowser view;
private boolean isInHotbar;
private final int id;
private long lastURLSent;
private PadData(String url, int id) {
view = mcef.createBrowser(WebDisplays.applyBlacklist(url));
view.resize((int) WebDisplays.INSTANCE.padResX, (int) WebDisplays.INSTANCE.padResY);
isInHotbar = true;
this.id = id;
}
}
private Minecraft mc;
private final ArrayList<ResourceModelPair> modelBakers = new ArrayList<>();
private net.montoyo.mcef.api.API mcef;
private MinePadRenderer minePadRenderer;
private JSQueryDispatcher jsDispatcher;
private LaserPointerRenderer laserPointerRenderer;
private GuiScreen nextScreen;
private boolean isF1Down;
//Miniserv handling
private int miniservPort;
private boolean msClientStarted;
//Client-side advancement hack
private final Field advancementToProgressField = findAdvancementToProgressField();
private ClientAdvancementManager lastAdvMgr;
private Map advancementToProgress;
//Laser pointer
private TileEntityScreen pointedScreen;
private BlockSide pointedScreenSide;
private long lastPointPacket;
//Tracking
private final ArrayList<TileEntityScreen> screenTracking = new ArrayList<>();
private int lastTracked = 0;
//MinePads Management
private final HashMap<Integer, PadData> padMap = new HashMap<>();
private final ArrayList<PadData> padList = new ArrayList<>();
private int minePadTickCounter = 0;
/**************************************** INHERITED METHODS ****************************************/
@Override
public void preInit() {
mc = Minecraft.getMinecraft();
MinecraftForge.EVENT_BUS.register(this);
registerCustomBlockBaker(new ScreenBaker(), WebDisplays.INSTANCE.blockScreen);
mcef = MCEFApi.getAPI();
if(mcef != null)
mcef.registerScheme("wd", WDScheme.class, true, false, false, true, true, false, false);
}
@Override
public void init() {
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityScreen.class, new ScreenRenderer());
jsDispatcher = new JSQueryDispatcher(this);
minePadRenderer = new MinePadRenderer();
laserPointerRenderer = new LaserPointerRenderer();
}
@Override
public void postInit() {
((SimpleReloadableResourceManager) mc.getResourceManager()).registerReloadListener(this);
if(mcef == null)
throw new RuntimeException("MCEF is missing");
mcef.registerDisplayHandler(this);
mcef.registerJSQueryHandler(this);
findAdvancementToProgressField();
}
@Override
public World getWorld(int dim) {
World ret = mc.world;
if(dim == CURRENT_DIMENSION)
return ret;
if(ret.provider.getDimension() != dim)
throw new RuntimeException("Can't get non-current dimension " + dim + " from client.");
return ret;
}
@Override
public void enqueue(Runnable r) {
mc.addScheduledTask(r);
}
@Override
public void displayGui(GuiData data) {
GuiScreen gui = data.createGui(mc.currentScreen, mc.world);
if(gui != null)
mc.displayGuiScreen(gui);
}
@Override
public void trackScreen(TileEntityScreen tes, boolean track) {
int idx = -1;
for(int i = 0; i < screenTracking.size(); i++) {
if(screenTracking.get(i) == tes) {
idx = i;
break;
}
}
if(track) {
if(idx < 0)
screenTracking.add(tes);
} else if(idx >= 0)
screenTracking.remove(idx);
}
@Override
public void onAutocompleteResult(NameUUIDPair[] pairs) {
if(mc.currentScreen != null && mc.currentScreen instanceof WDScreen) {
if(pairs.length == 0)
((WDScreen) mc.currentScreen).onAutocompleteFailure();
else
((WDScreen) mc.currentScreen).onAutocompleteResult(pairs);
}
}
@Override
public GameProfile[] getOnlineGameProfiles() {
return new GameProfile[] { mc.player.getGameProfile() };
}
@Override
public void screenUpdateResolutionInGui(Vector3i pos, BlockSide side, Vector2i res) {
if(mc.currentScreen != null && mc.currentScreen instanceof GuiScreenConfig) {
GuiScreenConfig gsc = (GuiScreenConfig) mc.currentScreen;
if(gsc.isForBlock(pos.toBlock(), side))
gsc.updateResolution(res);
}
}
@Override
public void screenUpdateRotationInGui(Vector3i pos, BlockSide side, Rotation rot) {
if(mc.currentScreen != null && mc.currentScreen instanceof GuiScreenConfig) {
GuiScreenConfig gsc = (GuiScreenConfig) mc.currentScreen;
if(gsc.isForBlock(pos.toBlock(), side))
gsc.updateRotation(rot);
}
}
@Override
public void screenUpdateAutoVolumeInGui(Vector3i pos, BlockSide side, boolean av) {
if(mc.currentScreen != null && mc.currentScreen instanceof GuiScreenConfig) {
GuiScreenConfig gsc = (GuiScreenConfig) mc.currentScreen;
if(gsc.isForBlock(pos.toBlock(), side))
gsc.updateAutoVolume(av);
}
}
@Override
public void displaySetPadURLGui(String padURL) {
mc.displayGuiScreen(new GuiSetURL2(padURL));
}
@Override
public void openMinePadGui(int padId) {
PadData pd = padMap.get(padId);
if(pd != null && pd.view != null)
mc.displayGuiScreen(new GuiMinePad(pd));
}
@Override
@Nonnull
public HasAdvancement hasClientPlayerAdvancement(@Nonnull ResourceLocation rl) {
if(advancementToProgressField != null && mc.player != null && mc.player.connection != null) {
ClientAdvancementManager cam = mc.player.connection.getAdvancementManager();
Advancement adv = cam.getAdvancementList().getAdvancement(rl);
if(adv == null)
return HasAdvancement.DONT_KNOW;
if(lastAdvMgr != cam) {
lastAdvMgr = cam;
try {
advancementToProgress = (Map) advancementToProgressField.get(cam);
} catch(Throwable t) {
Log.warningEx("Could not get ClientAdvancementManager.advancementToProgress field", t);
advancementToProgress = null;
return HasAdvancement.DONT_KNOW;
}
}
if(advancementToProgress == null)
return HasAdvancement.DONT_KNOW;
Object progress = advancementToProgress.get(adv);
if(progress == null)
return HasAdvancement.NO;
if(!(progress instanceof AdvancementProgress)) {
Log.warning("The ClientAdvancementManager.advancementToProgress map does not contain AdvancementProgress instances");
advancementToProgress = null; //Invalidate this: it's wrong
return HasAdvancement.DONT_KNOW;
}
return ((AdvancementProgress) progress).isDone() ? HasAdvancement.YES : HasAdvancement.NO;
}
return HasAdvancement.DONT_KNOW;
}
@Override
public MinecraftServer getServer() {
return mc.getIntegratedServer();
}
@Override
public void handleJSResponseSuccess(int reqId, JSServerRequest type, byte[] data) {
JSQueryDispatcher.ServerQuery q = jsDispatcher.fulfillQuery(reqId);
if(q == null)
Log.warning("Received success response for invalid query ID %d of type %s", reqId, type.toString());
else {
if(type == JSServerRequest.CLEAR_REDSTONE || type == JSServerRequest.SET_REDSTONE_AT)
q.success("{\"status\":\"success\"}");
else
Log.warning("Received success response for query ID %d, but type is invalid", reqId);
}
}
@Override
public void handleJSResponseError(int reqId, JSServerRequest type, int errCode, String err) {
JSQueryDispatcher.ServerQuery q = jsDispatcher.fulfillQuery(reqId);
if(q == null)
Log.warning("Received error response for invalid query ID %d of type %s", reqId, type.toString());
else
q.error(errCode, err);
}
@Override
public void setMiniservClientPort(int port) {
miniservPort = port;
}
@Override
public void startMiniservClient() {
if(miniservPort <= 0) {
Log.warning("Can't start miniserv client: miniserv is disabled");
return;
}
if(mc.player == null) {
Log.warning("Can't start miniserv client: player is null");
return;
}
SocketAddress saddr = mc.player.connection.getNetworkManager().channel().remoteAddress();
if(saddr == null || !(saddr instanceof InetSocketAddress)) {
Log.warning("Miniserv client: remote address is not inet, assuming local address");
saddr = new InetSocketAddress("127.0.0.1", 1234);
}
InetSocketAddress msAddr = new InetSocketAddress(((InetSocketAddress) saddr).getAddress(), miniservPort);
Client.getInstance().start(msAddr);
msClientStarted = true;
}
@Override
public boolean isMiniservDisabled() {
return miniservPort <= 0;
}
@Override
public void closeGui(BlockPos bp, BlockSide bs) {
if(mc.currentScreen instanceof WDScreen) {
WDScreen scr = (WDScreen) mc.currentScreen;
if(scr.isForBlock(bp, bs))
mc.displayGuiScreen(null);
}
}
@Override
public void renderRecipes() {
nextScreen = new RenderRecipe();
}
@Override
public boolean isShiftDown() {
return Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT);
}
/**************************************** RESOURCE MANAGER METHODS ****************************************/
@Override
public void onResourceManagerReload(IResourceManager resourceManager, Predicate<IResourceType> resourcePredicate) {
Log.info("Resource manager reload: clearing GUI cache...");
GuiLoader.clearCache();
}
/**************************************** DISPLAY HANDLER METHODS ****************************************/
@Override
public void onAddressChange(IBrowser browser, String url) {
if(browser != null) {
long t = System.currentTimeMillis();
for(PadData pd: padList) {
if(pd.view == browser && t - pd.lastURLSent >= 1000) {
if(WebDisplays.isSiteBlacklisted(url))
pd.view.loadURL(WebDisplays.BLACKLIST_URL);
else {
pd.lastURLSent = t; //Avoid spamming the server with porn URLs
WebDisplays.NET_HANDLER.sendToServer(new SMessagePadCtrl(pd.id, url));
}
break;
}
}
for(TileEntityScreen tes: screenTracking)
tes.updateClientSideURL(browser, url);
}
}
@Override
public void onTitleChange(IBrowser browser, String title) {
}
@Override
public void onTooltip(IBrowser browser, String text) {
}
@Override
public void onStatusMessage(IBrowser browser, String value) {
}
/**************************************** JS HANDLER METHODS ****************************************/
@Override
public boolean handleQuery(IBrowser browser, long queryId, String query, boolean persistent, IJSQueryCallback cb) {
if(browser != null && persistent && query != null && cb != null) {
query = query.toLowerCase();
if(query.startsWith("webdisplays_")) {
query = query.substring(12);
String args;
int parenthesis = query.indexOf('(');
if(parenthesis < 0)
args = null;
else {
if(query.indexOf(')') != query.length() - 1) {
cb.failure(400, "Malformed request");
return true;
}
args = query.substring(parenthesis + 1, query.length() - 1);
query = query.substring(0, parenthesis);
}
if(jsDispatcher.canHandleQuery(query))
jsDispatcher.enqueueQuery(browser, query, args, cb);
else
cb.failure(404, "Unknown WebDisplays query");
return true;
}
}
return false;
}
@Override
public void cancelQuery(IBrowser browser, long queryId) {
}
/**************************************** EVENT METHODS ****************************************/
@SubscribeEvent
public void onStitchTextures(TextureStitchEvent.Pre ev) {
TextureMap texMap = ev.getMap();
if(texMap == mc.getTextureMapBlocks()) {
for(ResourceModelPair pair : modelBakers)
pair.getModel().loadTextures(texMap);
}
}
@SubscribeEvent
public void onBakeModel(ModelBakeEvent ev) {
for(ResourceModelPair pair : modelBakers)
ev.getModelRegistry().putObject(pair.getResourceLocation(), pair.getModel());
}
@SubscribeEvent
public void onRegisterModels(ModelRegistryEvent ev) {
final WebDisplays wd = WebDisplays.INSTANCE;
//I hope I'm doing this right because it doesn't seem like it...
registerItemModel(wd.blockScreen.getItem(), 0, "inventory");
ModelLoader.setCustomModelResourceLocation(wd.blockPeripheral.getItem(), 0, new ModelResourceLocation("webdisplays:kb_inv", "normal"));
registerItemModel(wd.blockPeripheral.getItem(), 1, "facing=2,type=ccinterface");
registerItemModel(wd.blockPeripheral.getItem(), 2, "facing=2,type=cointerface");
registerItemModel(wd.blockPeripheral.getItem(), 3, "facing=0,type=remotectrl");
registerItemModel(wd.blockPeripheral.getItem(), 7, "facing=0,type=redstonectrl");
registerItemModel(wd.blockPeripheral.getItem(), 11, "facing=0,type=server");
registerItemModel(wd.itemScreenCfg, 0, "normal");
registerItemModel(wd.itemOwnerThief, 0, "normal");
registerItemModel(wd.itemLinker, 0, "normal");
registerItemModel(wd.itemMinePad, 0, "normal");
registerItemModel(wd.itemMinePad, 1, "normal");
registerItemModel(wd.itemLaserPointer, 0, "normal");
registerItemMultiModels(wd.itemUpgrade);
registerItemMultiModels(wd.itemCraftComp);
registerItemMultiModels(wd.itemAdvIcon);
}
@SubscribeEvent
public void onTick(TickEvent.ClientTickEvent ev) {
if(ev.phase == TickEvent.Phase.END) {
//Help
if(Keyboard.isKeyDown(Keyboard.KEY_F1)) {
if(!isF1Down) {
isF1Down = true;
String wikiName = null;
if(mc.currentScreen instanceof WDScreen)
wikiName = ((WDScreen) mc.currentScreen).getWikiPageName();
else if(mc.currentScreen instanceof GuiContainer) {
Slot slot = ((GuiContainer) mc.currentScreen).getSlotUnderMouse();
if(slot != null && slot.getHasStack() && slot.getStack().getItem() instanceof WDItem)
wikiName = ((WDItem) slot.getStack().getItem()).getWikiName(slot.getStack());
}
if(wikiName != null)
mcef.openExampleBrowser("https://montoyo.net/wdwiki/index.php/" + wikiName);
}
} else if(isF1Down)
isF1Down = false;
//Workaround cuz chat sux
if(nextScreen != null && mc.currentScreen == null) {
mc.displayGuiScreen(nextScreen);
nextScreen = null;
}
//Unload/load screens depending on client player distance
if(mc.player != null && !screenTracking.isEmpty()) {
int id = lastTracked % screenTracking.size();
lastTracked++;
TileEntityScreen tes = screenTracking.get(id);
double dist2 = mc.player.getDistanceSq(tes.getPos());
if(tes.isLoaded()) {
if(dist2 > WebDisplays.INSTANCE.unloadDistance2)
tes.unload();
else if(WebDisplays.INSTANCE.enableSoundDistance)
tes.updateTrackDistance(dist2, SoundSystemConfig.getMasterGain());
} else if(dist2 <= WebDisplays.INSTANCE.loadDistance2)
tes.load();
}
//Load/unload minePads depending on which item is in the player's hand
if(++minePadTickCounter >= 10) {
minePadTickCounter = 0;
EntityPlayer ep = mc.player;
for(PadData pd: padList)
pd.isInHotbar = false;
if(ep != null) {
updateInventory(ep.inventory.mainInventory, ep.getHeldItem(EnumHand.MAIN_HAND), 9);
updateInventory(ep.inventory.offHandInventory, ep.getHeldItem(EnumHand.OFF_HAND), 1); //Is this okay?
}
//TODO: Check for GuiContainer.draggedStack
for(int i = padList.size() - 1; i >= 0; i--) {
PadData pd = padList.get(i);
if(!pd.isInHotbar) {
pd.view.close();
pd.view = null; //This is for GuiMinePad, in case the player dies with the GUI open
padList.remove(i);
padMap.remove(pd.id);
}
}
}
//Laser pointer raycast
boolean raycastHit = false;
if(mc.player != null && mc.world != null && mc.player.getHeldItem(EnumHand.MAIN_HAND).getItem() == WebDisplays.INSTANCE.itemLaserPointer
&& mc.gameSettings.keyBindUseItem.isKeyDown()
&& (mc.objectMouseOver == null || mc.objectMouseOver.typeOfHit != RayTraceResult.Type.BLOCK)) {
laserPointerRenderer.isOn = true;
RayTraceResult result = raycast(64.0); //TODO: Make that distance configurable
if(result != null) {
BlockPos bpos = result.getBlockPos();
if(result.typeOfHit == RayTraceResult.Type.BLOCK && mc.world.getBlockState(bpos).getBlock() == WebDisplays.INSTANCE.blockScreen) {
Vector3i pos = new Vector3i(result.getBlockPos());
BlockSide side = BlockSide.values()[result.sideHit.ordinal()];
Multiblock.findOrigin(mc.world, pos, side, null);
TileEntityScreen te = (TileEntityScreen) mc.world.getTileEntity(pos.toBlock());
if(te != null && te.hasUpgrade(side, DefaultUpgrade.LASER_MOUSE)) { //hasUpgrade returns false is there's no screen on side 'side'
//Since rights aren't synchronized, let the server check them for us...
TileEntityScreen.Screen scr = te.getScreen(side);
if(scr.browser != null) {
float hitX = ((float) result.hitVec.x) - (float) bpos.getX();
float hitY = ((float) result.hitVec.y) - (float) bpos.getY();
float hitZ = ((float) result.hitVec.z) - (float) bpos.getZ();
Vector2i tmp = new Vector2i();
if(BlockScreen.hit2pixels(side, bpos, pos, scr, hitX, hitY, hitZ, tmp)) {
laserClick(te, side, scr, tmp);
raycastHit = true;
}
}
}
}
}
} else
laserPointerRenderer.isOn = false;
if(!raycastHit)
deselectScreen();
//Handle JS queries
jsDispatcher.handleQueries();
//Miniserv
if(msClientStarted && mc.player == null) {
msClientStarted = false;
Client.getInstance().stop();
}
}
}
@SubscribeEvent
public void onRenderPlayerHand(RenderSpecificHandEvent ev) {
Item item = ev.getItemStack().getItem();
IItemRenderer renderer;
if(item == WebDisplays.INSTANCE.itemMinePad)
renderer = minePadRenderer;
else if(item == WebDisplays.INSTANCE.itemLaserPointer)
renderer = laserPointerRenderer;
else
return;
EnumHandSide handSide = mc.player.getPrimaryHand();
if(ev.getHand() == EnumHand.OFF_HAND)
handSide = handSide.opposite();
renderer.render(ev.getItemStack(), (handSide == EnumHandSide.RIGHT) ? 1.0f : -1.0f, ev.getSwingProgress(), ev.getEquipProgress());
ev.setCanceled(true);
}
@SubscribeEvent
public void onWorldUnload(WorldEvent.Unload ev) {
Log.info("World unloaded; killing screens...");
int dim = ev.getWorld().provider.getDimension();
for(int i = screenTracking.size() - 1; i >= 0; i--) {
if(screenTracking.get(i).getWorld().provider.getDimension() == dim) //Could be world == ev.getWorld()
screenTracking.remove(i).unload();
}
}
/**************************************** OTHER METHODS ****************************************/
private void laserClick(TileEntityScreen tes, BlockSide side, TileEntityScreen.Screen scr, Vector2i hit) {
if(pointedScreen == tes && pointedScreenSide == side) {
long t = System.currentTimeMillis();
if(t - lastPointPacket >= 100) {
lastPointPacket = t;
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.vec2(tes, side, SMessageScreenCtrl.CTRL_LASER_MOVE, hit));
}
} else {
deselectScreen();
pointedScreen = tes;
pointedScreenSide = side;
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.vec2(tes, side, SMessageScreenCtrl.CTRL_LASER_DOWN, hit));
}
}
private void deselectScreen() {
if(pointedScreen != null && pointedScreenSide != null) {
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.laserUp(pointedScreen, pointedScreenSide));
pointedScreen = null;
pointedScreenSide = null;
}
}
private RayTraceResult raycast(double dist) {
Vec3d start = mc.player.getPositionEyes(1.0f);
Vec3d lookVec = mc.player.getLook(1.0f);
Vec3d end = start.addVector(lookVec.x * dist, lookVec.y * dist, lookVec.z * dist);
return mc.world.rayTraceBlocks(start, end, true, true, false);
}
private void updateInventory(NonNullList<ItemStack> inv, ItemStack heldStack, int cnt) {
for(int i = 0; i < cnt; i++) {
ItemStack item = inv.get(i);
if(item.getItem() == WebDisplays.INSTANCE.itemMinePad) {
NBTTagCompound tag = item.getTagCompound();
if(tag != null && tag.hasKey("PadID"))
updatePad(tag.getInteger("PadID"), tag, item == heldStack);
}
}
}
private void registerCustomBlockBaker(IModelBaker baker, Block block0) {
ModelResourceLocation normalLoc = new ModelResourceLocation(block0.getRegistryName(), "normal");
ResourceModelPair pair = new ResourceModelPair(normalLoc, baker);
modelBakers.add(pair);
ModelLoader.setCustomStateMapper(block0, new StaticStateMapper(normalLoc));
}
private void registerItemModel(Item item, int meta, String variant) {
ModelLoader.setCustomModelResourceLocation(item, meta, new ModelResourceLocation(item.getRegistryName(), variant));
}
private void registerItemMultiModels(ItemMulti item) {
Enum[] values = item.getEnumValues();
for(int i = 0; i < values.length; i++)
ModelLoader.setCustomModelResourceLocation(item, i, new ModelResourceLocation(item.getRegistryName().toString() + '_' + values[i], "normal"));
}
private void updatePad(int id, NBTTagCompound tag, boolean isSelected) {
PadData pd = padMap.get(id);
if(pd != null)
pd.isInHotbar = true;
else if(isSelected && tag.hasKey("PadURL")) {
pd = new PadData(tag.getString("PadURL"), id);
padMap.put(id, pd);
padList.add(pd);
}
}
public MinePadRenderer getMinePadRenderer() {
return minePadRenderer;
}
public PadData getPadByID(int id) {
return padMap.get(id);
}
public net.montoyo.mcef.api.API getMCEF() {
return mcef;
}
public static final class ScreenSidePair {
public TileEntityScreen tes;
public BlockSide side;
}
public boolean findScreenFromBrowser(IBrowser browser, ScreenSidePair pair) {
for(TileEntityScreen tes: screenTracking) {
for(int i = 0; i < tes.screenCount(); i++) {
TileEntityScreen.Screen scr = tes.getScreen(i);
if(scr.browser == browser) {
pair.tes = tes;
pair.side = scr.side;
return true;
}
}
}
return false;
}
private static Field findAdvancementToProgressField() {
Field[] fields = ClientAdvancementManager.class.getDeclaredFields();
Optional<Field> result = Arrays.stream(fields).filter(f -> f.getType() == Map.class).findAny();
if(result.isPresent()) {
try {
Field ret = result.get();
ret.setAccessible(true);
return ret;
} catch(Throwable t) {
t.printStackTrace();
}
}
Log.warning("ClientAdvancementManager.advancementToProgress field could not be found");
return null;
}
}

View File

@@ -0,0 +1,370 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client;
import net.minecraft.client.Minecraft;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.mcef.api.IBrowser;
import net.montoyo.mcef.api.IJSQueryCallback;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.IScreenQueryHandler;
import net.montoyo.wd.core.IUpgrade;
import net.montoyo.wd.core.JSServerRequest;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.net.server.SMessageScreenCtrl;
import net.montoyo.wd.utilities.*;
import java.util.*;
@SideOnly(Side.CLIENT)
public final class JSQueryDispatcher {
private static final class QueryData {
private final IBrowser browser;
private final String query;
private final String args;
private final IJSQueryCallback callback;
private QueryData(IBrowser b, String q, String a, IJSQueryCallback cb) {
browser = b;
query = q;
args = a;
callback = cb;
}
}
public static final class ServerQuery {
private static int lastId = 0;
private final TileEntityScreen tes;
private final BlockSide side;
private final IJSQueryCallback callback;
private final int id;
private ServerQuery(TileEntityScreen t, BlockSide s, IJSQueryCallback cb) {
tes = t;
side = s;
callback = cb;
id = lastId++;
}
public TileEntityScreen getTileEntity() {
return tes;
}
public BlockSide getSide() {
return side;
}
public TileEntityScreen.Screen getScreen() {
return tes.getScreen(side);
}
public void success(String resp) {
callback.success(resp);
}
public void error(int errId, String errStr) {
callback.failure(errId, errStr);
}
}
private final ClientProxy proxy;
private final ArrayDeque<QueryData> queue = new ArrayDeque<>();
private final ClientProxy.ScreenSidePair lookupResult = new ClientProxy.ScreenSidePair();
private final HashMap<String, IScreenQueryHandler> handlers = new HashMap<>();
private final ArrayList<ServerQuery> serverQueries = new ArrayList<>();
private final Minecraft mc = Minecraft.getMinecraft();
public JSQueryDispatcher(ClientProxy proxy) {
this.proxy = proxy;
registerDefaults();
}
public void enqueueQuery(IBrowser b, String q, String a, IJSQueryCallback cb) {
synchronized(queue) {
queue.offer(new QueryData(b, q, a, cb));
}
}
public void handleQueries() {
while(true) {
QueryData next;
synchronized(queue) {
next = queue.poll();
}
if(next == null)
break;
if(proxy.findScreenFromBrowser(next.browser, lookupResult)) {
Object[] args = (next.args == null) ? new Object[0] : parseArgs(next.args);
if(args == null)
next.callback.failure(400, "Malformed request parameters");
else {
try {
handlers.get(next.query).handleQuery(next.callback, lookupResult.tes, lookupResult.side, args);
} catch(Throwable t) {
Log.warningEx("Could not execute JS query %s(%s)", t, next.query, (next.args == null) ? "" : next.args);
next.callback.failure(500, "Internal error");
}
}
} else
next.callback.failure(403, "A screen is required");
}
}
public boolean canHandleQuery(String q) {
return handlers.containsKey(q);
}
private static Object[] parseArgs(String args) {
ArrayList<String> array = new ArrayList<>();
int lastIdx = 0;
boolean inString = false;
boolean escape = false;
boolean hadString = false;
for(int i = 0; i < args.length(); i++) {
char chr = args.charAt(i);
if(inString) {
if(escape)
escape = false;
else {
if(chr == '\"')
inString = false;
else if(chr == '\\')
escape = true;
}
} else if(chr == '\"') {
if(hadString)
return null;
inString = true;
hadString = true;
} else if(chr == ',') {
array.add(args.substring(lastIdx, i).trim());
lastIdx = i + 1;
hadString = false;
}
}
if(inString)
return null; //Non terminated string
array.add(args.substring(lastIdx).trim());
Object[] ret = new Object[array.size()];
for(int i = 0; i < ret.length; i++) {
String str = array.get(i);
if(str.isEmpty())
return null; //Nah...
if(str.charAt(0) == '\"') //String
ret[i] = str.substring(1, str.length() - 1);
else {
try {
ret[i] = Double.parseDouble(str);
} catch(NumberFormatException ex) {
return null;
}
}
}
return ret;
}
public void register(String query, IScreenQueryHandler handler) {
handlers.put(query.toLowerCase(), handler);
}
public ServerQuery fulfillQuery(int id) {
int toRemove = -1;
for(int i = 0; i < serverQueries.size(); i++) {
ServerQuery sq = serverQueries.get(i);
if(sq.id == id) {
toRemove = i;
break;
}
}
if(toRemove < 0)
return null;
else
return serverQueries.remove(toRemove);
}
private void makeServerQuery(TileEntityScreen tes, BlockSide side, IJSQueryCallback cb, JSServerRequest type, Object ... data) {
ServerQuery ret = new ServerQuery(tes, side, cb);
serverQueries.add(ret);
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.jsRequest(tes, side, ret.id, type, data));
}
private void registerDefaults() {
register("GetSize", (cb, tes, side, args) -> {
Vector2i size = tes.getScreen(side).size;
cb.success("{\"x\":" + size.x + ",\"y\":" + size.y + "}");
});
register("GetRedstoneAt", (cb, tes, side, args) -> {
if(!tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_INPUT)) {
cb.failure(403, "Missing upgrade");
return;
}
if(args.length == 2 && args[0] instanceof Double && args[1] instanceof Double) {
TileEntityScreen.Screen scr = tes.getScreen(side);
int x = ((Double) args[0]).intValue();
int y = ((Double) args[1]).intValue();
if(x < 0 || x >= scr.size.x || y < 0 || y >= scr.size.y)
cb.failure(403, "Out of range");
else {
BlockPos bpos = (new Vector3i(tes.getPos())).addMul(side.right, x).addMul(side.up, y).toBlock();
int level = tes.getWorld().getBlockState(bpos).getValue(BlockScreen.emitting) ? 0 : tes.getWorld().getRedstonePower(bpos, EnumFacing.VALUES[side.reverse().ordinal()]);
cb.success("{\"level\":" + level + "}");
}
} else
cb.failure(400, "Wrong arguments");
});
register("GetRedstoneArray", (cb, tes, side, args) -> {
if(tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_INPUT)) {
final EnumFacing facing = EnumFacing.VALUES[side.reverse().ordinal()];
final StringJoiner resp = new StringJoiner(",", "{\"levels\":[", "]}");
tes.forEachScreenBlocks(side, bp -> {
if(tes.getWorld().getBlockState(bp).getValue(BlockScreen.emitting))
resp.add("0");
else
resp.add("" + tes.getWorld().getRedstonePower(bp, facing));
});
cb.success(resp.toString());
} else
cb.failure(403, "Missing upgrade");
});
register("ClearRedstone", (cb, tes, side, args) -> {
if(tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_OUTPUT)) {
if(tes.getScreen(side).owner.uuid.equals(mc.player.getGameProfile().getId()))
makeServerQuery(tes, side, cb, JSServerRequest.CLEAR_REDSTONE);
else
cb.success("{\"status\":\"notOwner\"}");
} else
cb.failure(403, "Missing upgrade");
});
register("SetRedstoneAt", (cb, tes, side, args) -> {
if(args.length != 3 || !Arrays.stream(args).allMatch((obj) -> obj instanceof Double)) {
cb.failure(400, "Wrong arguments");
return;
}
if(!tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_OUTPUT)) {
cb.failure(403, "Missing upgrade");
return;
}
if(!tes.getScreen(side).owner.uuid.equals(mc.player.getGameProfile().getId())) {
cb.success("{\"status\":\"notOwner\"}");
return;
}
int x = ((Double) args[0]).intValue();
int y = ((Double) args[1]).intValue();
boolean state = ((Double) args[2]) > 0.0;
Vector2i size = tes.getScreen(side).size;
if(x < 0 || x >= size.x || y < 0 || y >= size.y) {
cb.failure(403, "Out of range");
return;
}
makeServerQuery(tes, side, cb, JSServerRequest.SET_REDSTONE_AT, x, y, state);
});
register("IsEmitting", (cb, tes, side, args) -> {
if(!tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_OUTPUT)) {
cb.failure(403, "Missing upgrade");
return;
}
if(args.length == 2 && args[0] instanceof Double && args[1] instanceof Double) {
TileEntityScreen.Screen scr = tes.getScreen(side);
int x = ((Double) args[0]).intValue();
int y = ((Double) args[1]).intValue();
if(x < 0 || x >= scr.size.x || y < 0 || y >= scr.size.y)
cb.failure(403, "Out of range");
else {
BlockPos bpos = (new Vector3i(tes.getPos())).addMul(side.right, x).addMul(side.up, y).toBlock();
boolean e = tes.getWorld().getBlockState(bpos).getValue(BlockScreen.emitting);
cb.success("{\"emitting\":" + (e ? "true" : "false") + "}");
}
} else
cb.failure(400, "Wrong arguments");
});
register("GetEmissionArray", (cb, tes, side, args) -> {
if(tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_OUTPUT)) {
final StringJoiner resp = new StringJoiner(",", "{\"emission\":[", "]}");
tes.forEachScreenBlocks(side, bp -> resp.add(tes.getWorld().getBlockState(bp).getValue(BlockScreen.emitting) ? "1" : "0"));
cb.success(resp.toString());
} else
cb.failure(403, "Missing upgrade");
});
register("GetLocation", (cb, tes, side, args) -> {
if(!tes.hasUpgrade(side, DefaultUpgrade.GPS)) {
cb.failure(403, "Missing upgrade");
return;
}
BlockPos bp = tes.getPos();
cb.success("{\"x\":" + bp.getX() + ",\"y\":" + bp.getY() + ",\"z\":" + bp.getZ() + ",\"side\":\"" + side + "\"}");
});
register("GetUpgrades", (cb, tes, side, args) -> {
final StringBuilder sb = new StringBuilder("{\"upgrades\":[");
final ArrayList<ItemStack> upgrades = tes.getScreen(side).upgrades;
for(int i = 0; i < upgrades.size(); i++) {
if(i > 0)
sb.append(',');
sb.append('\"');
sb.append(Util.addSlashes(((IUpgrade) upgrades.get(i).getItem()).getJSName(upgrades.get(i))));
sb.append('\"');
}
cb.success(sb.append("]}").toString());
});
register("IsOwner", (cb, tes, side, args) -> {
boolean res = (tes.getScreen(side).owner != null && tes.getScreen(side).owner.uuid.equals(mc.player.getGameProfile().getId()));
cb.success("{\"isOwner\":" + (res ? "true}" : "false}"));
});
register("GetRotation", (cb, tes, side, args) -> cb.success("{\"rotation\":" + tes.getScreen(side).rotation.ordinal() + "}"));
register("GetSide", (cb, tes, side, args) -> cb.success("{\"side\":" + tes.getScreen(side).side.ordinal() + "}"));
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.montoyo.wd.client.renderers.IModelBaker;
public class ResourceModelPair {
private final ModelResourceLocation resLoc;
private final IModelBaker model;
public ResourceModelPair(ModelResourceLocation rl, IModelBaker m) {
resLoc = rl;
model = m;
}
public ModelResourceLocation getResourceLocation() {
return resLoc;
}
public IModelBaker getModel() {
return model;
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.block.statemap.StateMapperBase;
import javax.annotation.Nonnull;
public class StaticStateMapper extends StateMapperBase {
private final ModelResourceLocation resLoc;
public StaticStateMapper(ModelResourceLocation rl) {
resLoc = rl;
}
@Override
@Nonnull
protected ModelResourceLocation getModelResourceLocation(@Nonnull IBlockState state) {
return resLoc;
}
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client;
import net.montoyo.mcef.api.IScheme;
import net.montoyo.mcef.api.ISchemeResponseData;
import net.montoyo.mcef.api.ISchemeResponseHeaders;
import net.montoyo.mcef.api.SchemePreResponse;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.miniserv.Constants;
import net.montoyo.wd.miniserv.client.Client;
import net.montoyo.wd.miniserv.client.ClientTaskGetFile;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Util;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.UUID;
public class WDScheme implements IScheme {
private static final String ERROR_PAGE = "<!DOCTYPE html><html><head></head><body><h1>%d %s</h1><hr /><i>Miniserv powered by WebDisplays</i></body></html>";
private ClientTaskGetFile task;
private boolean isErrorPage;
@Override
public SchemePreResponse processRequest(String url) {
url = url.substring("wd://".length());
int pos = url.indexOf('/');
if(pos < 0)
return SchemePreResponse.NOT_HANDLED;
String uuidStr = url.substring(0, pos);
String fileStr = url.substring(pos + 1);
try {
fileStr = URLDecoder.decode(fileStr, "UTF-8");
} catch(UnsupportedEncodingException ex) {
Log.warningEx("UTF-8 isn't supported... yeah... and I'm a billionaire...", ex);
}
if(uuidStr.isEmpty() || Util.isFileNameInvalid(fileStr))
return SchemePreResponse.NOT_HANDLED;
UUID uuid;
try {
uuid = UUID.fromString(uuidStr);
} catch(IllegalArgumentException ex) {
return SchemePreResponse.NOT_HANDLED; //Invalid UUID
}
task = new ClientTaskGetFile(uuid, fileStr);
return Client.getInstance().addTask(task) ? SchemePreResponse.HANDLED_CONTINUE : SchemePreResponse.NOT_HANDLED;
}
@Override
public void getResponseHeaders(ISchemeResponseHeaders resp) {
Log.info("Waiting for response...");
int status = task.waitForResponse();
Log.info("Got response %d", status);
if(status == 0) {
//OK
int extPos = task.getFileName().lastIndexOf('.');
if(extPos >= 0) {
String mime = ((ClientProxy) WebDisplays.PROXY).getMCEF().mimeTypeFromExtension(task.getFileName().substring(extPos + 1));
if(mime != null)
resp.setMimeType(mime);
}
resp.setStatus(200);
resp.setStatusText("OK");
resp.setResponseLength(-1);
return;
}
int errCode;
String errStr;
if(status == Constants.GETF_STATUS_NOT_FOUND) {
errCode = 404;
errStr = "Not Found";
} else {
errCode = 500;
errStr = "Internal Server Error";
}
resp.setStatus(errCode);
resp.setStatusText(errStr);
try {
dataToWrite = String.format(ERROR_PAGE, errCode, errStr).getBytes("UTF-8");
dataOffset = 0;
amountToWrite = dataToWrite.length;
isErrorPage = true;
resp.setResponseLength(amountToWrite);
} catch(UnsupportedEncodingException ex) {
resp.setResponseLength(0);
}
}
private byte[] dataToWrite;
private int dataOffset;
private int amountToWrite;
@Override
public boolean readResponse(ISchemeResponseData data) {
if(dataToWrite == null) {
if(isErrorPage) {
data.setAmountRead(0);
return false;
}
dataToWrite = task.waitForData();
dataOffset = 3; //packet ID + size
amountToWrite = task.getDataLength();
if(amountToWrite <= 0) {
dataToWrite = null;
data.setAmountRead(0);
return false;
}
}
int toWrite = data.getBytesToRead();
if(toWrite > amountToWrite)
toWrite = amountToWrite;
System.arraycopy(dataToWrite, dataOffset, data.getDataArray(), 0, toWrite);
data.setAmountRead(toWrite);
dataOffset += toWrite;
amountToWrite -= toWrite;
if(amountToWrite <= 0) {
if(!isErrorPage)
task.nextData();
dataToWrite = null;
}
return true;
}
}

View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandHandler {
String value();
}

View File

@@ -0,0 +1,204 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.gui.controls.Button;
import net.montoyo.wd.client.gui.controls.Control;
import net.montoyo.wd.client.gui.controls.Label;
import net.montoyo.wd.client.gui.loading.FillControl;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.net.server.SMessageScreenCtrl;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.TypeData;
import net.montoyo.wd.utilities.Util;
import org.lwjgl.input.Keyboard;
import java.io.*;
import java.util.ArrayList;
import java.util.Map;
@SideOnly(Side.CLIENT)
public class GuiKeyboard extends WDScreen {
private static final String WARNING_FNAME = "wd_keyboard_warning.txt";
private TileEntityScreen tes;
private BlockSide side;
private final ArrayList<TypeData> evStack = new ArrayList<>();
private BlockPos kbPos;
private boolean showWarning = true;
@FillControl
private Label lblInfo;
@FillControl
private Button btnOk;
public GuiKeyboard() {
}
public GuiKeyboard(TileEntityScreen tes, BlockSide side, BlockPos kbPos) {
this.tes = tes;
this.side = side;
this.kbPos = kbPos;
}
@Override
protected void addLoadCustomVariables(Map<String, Double> vars) {
vars.put("showWarning", showWarning ? 1.0 : 0.0);
}
@Override
public void initGui() {
super.initGui();
if(mc.isIntegratedServerRunning() && mc.getIntegratedServer() != null && !mc.getIntegratedServer().getPublic())
showWarning = false; //NO NEED
else
showWarning = !hasUserReadWarning();
loadFrom(new ResourceLocation("webdisplays", "gui/keyboard.json"));
if(showWarning) {
int maxLabelW = 0;
int totalH = 0;
for(Control ctrl : controls) {
if(ctrl != lblInfo && ctrl instanceof Label) {
if(ctrl.getWidth() > maxLabelW)
maxLabelW = ctrl.getWidth();
totalH += ctrl.getHeight();
ctrl.setPos((width - ctrl.getWidth()) / 2, 0);
}
}
btnOk.setWidth(maxLabelW);
btnOk.setPos((width - maxLabelW) / 2, 0);
totalH += btnOk.getHeight();
int y = (height - totalH) / 2;
for(Control ctrl : controls) {
if(ctrl != lblInfo) {
ctrl.setPos(ctrl.getX(), y);
y += ctrl.getHeight();
}
}
} else {
mc.inGameHasFocus = true;
mc.mouseHelper.grabMouseCursor();
}
defaultBackground = showWarning;
syncTicks = 5;
}
@Override
public void handleInput() {
if(showWarning) {
try {
super.handleInput();
} catch(IOException ex) {
Log.warningEx("Caught exception while handling screen input", ex);
}
return;
}
if(Keyboard.isCreated()) {
while(Keyboard.next()) {
if(Keyboard.getEventKey() == Keyboard.KEY_ESCAPE)
mc.displayGuiScreen(null);
else {
char chr = Keyboard.getEventCharacter();
if(Keyboard.getEventKeyState()) {
int kc = Keyboard.getEventKey();
evStack.add(new TypeData(TypeData.Action.PRESS, kc, chr));
evStack.add(new TypeData(TypeData.Action.RELEASE, kc, chr));
}
if(chr != 0)
evStack.add(new TypeData(TypeData.Action.TYPE, 0, chr));
}
}
if(!evStack.isEmpty() && !syncRequested())
requestSync();
}
}
@Override
protected void sync() {
if(!evStack.isEmpty()) {
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.type(tes, side, WebDisplays.GSON.toJson(evStack), kbPos));
evStack.clear();
}
}
@GuiSubscribe
public void onClick(Button.ClickEvent ev) {
if(showWarning && ev.getSource() == btnOk) {
writeUserAcknowledge();
for(Control ctrl: controls) {
if(ctrl instanceof Label) {
Label lbl = (Label) ctrl;
lbl.setVisible(!lbl.isVisible());
}
}
btnOk.setDisabled(true);
btnOk.setVisible(false);
showWarning = false;
defaultBackground = false;
mc.inGameHasFocus = true;
mc.mouseHelper.grabMouseCursor();
}
}
private boolean hasUserReadWarning() {
try {
File f = new File(mc.mcDataDir, WARNING_FNAME);
if(f.exists()) {
BufferedReader br = new BufferedReader(new FileReader(f));
String str = br.readLine();
Util.silentClose(br);
return str != null && str.trim().equalsIgnoreCase("read");
}
} catch(Throwable t) {
Log.warningEx("Can't know if user has already read the warning", t);
}
return false;
}
private void writeUserAcknowledge() {
try {
File f = new File(mc.mcDataDir, WARNING_FNAME);
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
bw.write("read\n");
Util.silentClose(bw);
} catch(Throwable t) {
Log.warningEx("Can't write that the user read the warning", t);
}
}
@Override
public boolean isForBlock(BlockPos bp, BlockSide side) {
return bp.equals(kbPos) || (bp.equals(tes.getPos()) && side == this.side);
}
}

View File

@@ -0,0 +1,143 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.ClientProxy;
import net.montoyo.wd.utilities.BlockSide;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import static org.lwjgl.opengl.GL11.*;
@SideOnly(Side.CLIENT)
public class GuiMinePad extends WDScreen {
private ClientProxy.PadData pad;
private double vx;
private double vy;
private double vw;
private double vh;
public GuiMinePad() {
}
public GuiMinePad(ClientProxy.PadData pad) {
this.pad = pad;
}
@Override
public void initGui() {
super.initGui();
vw = ((double) width) - 32.0f;
vh = vw / WebDisplays.PAD_RATIO;
vx = 16.0f;
vy = (((double) height) - vh) / 2.0f;
}
private static void addRect(BufferBuilder bb, double x, double y, double w, double h) {
bb.pos(x, y, 0.0).endVertex();
bb.pos(x + w, y, 0.0).endVertex();
bb.pos(x + w, y + h, 0.0).endVertex();
bb.pos(x, y + h, 0.0).endVertex();
}
@Override
public void drawScreen(int mouseX, int mouseY, float ptt) {
drawDefaultBackground();
glDisable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
glColor4f(0.73f, 0.73f, 0.73f, 1.0f);
Tessellator t = Tessellator.getInstance();
BufferBuilder bb = t.getBuffer();
bb.begin(GL_QUADS, DefaultVertexFormats.POSITION);
addRect(bb, vx, vy - 16, vw, 16);
addRect(bb, vx, vy + vh, vw, 16);
addRect(bb, vx - 16, vy, 16, vh);
addRect(bb, vx + vw, vy, 16, vh);
t.draw();
glEnable(GL_TEXTURE_2D);
if(pad.view != null) {
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
pad.view.draw(vx, vy + vh, vx + vw, vy);
}
glEnable(GL_CULL_FACE);
}
@Override
public void handleInput() {
while(Keyboard.next()) {
char key = Keyboard.getEventCharacter();
int keycode = Keyboard.getEventKey();
boolean pressed = Keyboard.getEventKeyState();
if(Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) {
mc.displayGuiScreen(null);
return;
}
if(pad.view != null) {
if(pressed)
pad.view.injectKeyPressedByKeyCode(keycode, key, 0);
else
pad.view.injectKeyReleasedByKeyCode(keycode, key, 0);
if(key != 0)
pad.view.injectKeyTyped(key, 0);
}
}
int vx = screen2DisplayX((int) this.vx);
int vy = screen2DisplayY((int) this.vy);
int vh = screen2DisplayX((int) this.vh);
int vw = screen2DisplayY((int) this.vw);
while(Mouse.next()) {
int btn = Mouse.getEventButton();
boolean pressed = Mouse.getEventButtonState();
int sx = Mouse.getEventX();
int sy = Mouse.getEventY();
if(pad.view != null && sx >= vx && sx <= vx + vw && sy >= vy && sy <= vy + vh) {
sx -= vx;
sy -= vy;
sy = vh - sy;
//Scale again according to the webview
sx = (int) (((double) sx) / ((double) vw) * WebDisplays.INSTANCE.padResX);
sy = (int) (((double) sy) / ((double) vh) * WebDisplays.INSTANCE.padResY);
if(btn == -1)
pad.view.injectMouseMove(sx, sy, 0, false);
else
pad.view.injectMouseButton(sx, sy, 0, btn + 1, pressed, 1);
}
}
}
@Override
public void updateScreen() {
if(pad.view == null)
mc.displayGuiScreen(null); //In case the user dies with the pad in the hand
}
@Override
public boolean isForBlock(BlockPos bp, BlockSide side) {
return false;
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.montoyo.mcef.api.API;
import net.montoyo.wd.client.ClientProxy;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.gui.controls.Button;
import net.montoyo.wd.client.gui.controls.TextField;
import net.montoyo.wd.client.gui.loading.FillControl;
import net.montoyo.wd.net.server.SMessageRedstoneCtrl;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Util;
import net.montoyo.wd.utilities.Vector3i;
import javax.annotation.Nullable;
public class GuiRedstoneCtrl extends WDScreen {
private int dimension;
private Vector3i pos;
private String risingEdgeURL;
private String fallingEdgeURL;
@FillControl
private TextField tfRisingEdge;
@FillControl
private TextField tfFallingEdge;
@FillControl
private Button btnOk;
public GuiRedstoneCtrl() {
}
public GuiRedstoneCtrl(int d, Vector3i p, String r, String f) {
dimension = d;
pos = p;
risingEdgeURL = r;
fallingEdgeURL = f;
}
@Override
public void initGui() {
super.initGui();
loadFrom(new ResourceLocation("webdisplays", "gui/redstonectrl.json"));
tfRisingEdge.setText(risingEdgeURL);
tfFallingEdge.setText(fallingEdgeURL);
}
@GuiSubscribe
public void onClick(Button.ClickEvent ev) {
if(ev.getSource() == btnOk) {
API mcef = ((ClientProxy) WebDisplays.PROXY).getMCEF();
String rising = mcef.punycode(Util.addProtocol(tfRisingEdge.getText()));
String falling = mcef.punycode(Util.addProtocol(tfFallingEdge.getText()));
WebDisplays.NET_HANDLER.sendToServer(new SMessageRedstoneCtrl(dimension, pos, rising, falling));
}
mc.displayGuiScreen(null);
}
@Override
public boolean isForBlock(BlockPos bp, BlockSide side) {
return pos.equalsBlockPos(bp);
}
@Nullable
@Override
public String getWikiPageName() {
return "Redstone_Controller";
}
}

View File

@@ -0,0 +1,503 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.resources.I18n;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.gui.controls.*;
import net.montoyo.wd.client.gui.loading.FillControl;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.item.WDItem;
import net.montoyo.wd.net.server.SMessageScreenCtrl;
import net.montoyo.wd.utilities.*;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.UUID;
public class GuiScreenConfig extends WDScreen {
//Screen data
private final TileEntityScreen tes;
private final BlockSide side;
private NameUUIDPair owner;
private NameUUIDPair[] friends;
private int friendRights;
private int otherRights;
private Rotation rotation = Rotation.ROT_0;
private float aspectRatio;
//Autocomplete handling
private boolean waitingAC;
private int acFailTicks = -1;
private final ArrayList<NameUUIDPair> acResults = new ArrayList<>();
private boolean adding;
//Controls
@FillControl
private Label lblOwner;
@FillControl
private List lstFriends;
@FillControl
private Button btnAdd;
@FillControl
private TextField tfFriend;
@FillControl
private TextField tfResX;
@FillControl
private TextField tfResY;
@FillControl
private ControlGroup grpFriends;
@FillControl
private ControlGroup grpOthers;
@FillControl
private CheckBox boxFSetUrl;
@FillControl
private CheckBox boxFClick;
@FillControl
private CheckBox boxFFriends;
@FillControl
private CheckBox boxFOthers;
@FillControl
private CheckBox boxFUpgrades;
@FillControl
private CheckBox boxFResolution;
@FillControl
private CheckBox boxOSetUrl;
@FillControl
private CheckBox boxOClick;
@FillControl
private CheckBox boxOUpgrades;
@FillControl
private CheckBox boxOResolution;
@FillControl
private Button btnSetRes;
@FillControl
private UpgradeGroup ugUpgrades;
@FillControl
private Button btnChangeRot;
@FillControl
private CheckBox cbLockRatio;
@FillControl
private CheckBox cbAutoVolume;
private CheckBox[] friendBoxes;
private CheckBox[] otherBoxes;
public GuiScreenConfig(TileEntityScreen tes, BlockSide side, NameUUIDPair[] friends, int fr, int or) {
this.tes = tes;
this.side = side;
this.friends = friends;
friendRights = fr;
otherRights = or;
}
@Override
public void initGui() {
super.initGui();
loadFrom(new ResourceLocation("webdisplays", "gui/screencfg.json"));
friendBoxes = new CheckBox[] { boxFResolution, boxFUpgrades, boxFOthers, boxFFriends, boxFClick, boxFSetUrl };
boxFResolution.setUserdata(ScreenRights.CHANGE_RESOLUTION);
boxFUpgrades.setUserdata(ScreenRights.MANAGE_UPGRADES);
boxFOthers.setUserdata(ScreenRights.MANAGE_OTHER_RIGHTS);
boxFFriends.setUserdata(ScreenRights.MANAGE_FRIEND_LIST);
boxFClick.setUserdata(ScreenRights.CLICK);
boxFSetUrl.setUserdata(ScreenRights.CHANGE_URL);
otherBoxes = new CheckBox[] { boxOResolution, boxOUpgrades, boxOClick, boxOSetUrl };
boxOResolution.setUserdata(ScreenRights.CHANGE_RESOLUTION);
boxOUpgrades.setUserdata(ScreenRights.MANAGE_UPGRADES);
boxOClick.setUserdata(ScreenRights.CLICK);
boxOSetUrl.setUserdata(ScreenRights.CHANGE_URL);
TileEntityScreen.Screen scr = tes.getScreen(side);
if(scr != null) {
owner = scr.owner;
rotation = scr.rotation;
tfResX.setText("" + scr.resolution.x);
tfResY.setText("" + scr.resolution.y);
aspectRatio = ((float) scr.resolution.x) / ((float) scr.resolution.y);
//Hopefully upgrades have been synchronized...
ugUpgrades.setUpgrades(scr.upgrades);
cbAutoVolume.setChecked(scr.autoVolume);
}
if(owner == null)
owner = new NameUUIDPair("???", UUID.randomUUID());
lblOwner.setLabel(lblOwner.getLabel() + ' ' + owner.name);
for(NameUUIDPair f : friends)
lstFriends.addElementRaw(f.name, f);
lstFriends.updateContent();
updateRights(friendRights, friendRights, friendBoxes, true);
updateRights(otherRights, otherRights, otherBoxes, true);
updateMyRights();
updateRotationStr();
mc.getSoundHandler().playSound(PositionedSoundRecord.getRecord(WebDisplays.INSTANCE.soundScreenCfg, 1.0f, 1.0f));
}
private void updateRotationStr() {
btnChangeRot.setLabel(I18n.format("webdisplays.gui.screencfg.rot" + rotation.getAngleAsInt()));
}
private void addFriend(String name) {
if(!name.isEmpty()) {
requestAutocomplete(name, true);
tfFriend.setDisabled(true);
adding = true;
waitingAC = true;
}
}
private void clickSetRes() {
TileEntityScreen.Screen scr = tes.getScreen(side);
if(scr == null)
return; //WHATDAFUQ?
try {
int x = Integer.parseInt(tfResX.getText());
int y = Integer.parseInt(tfResY.getText());
if(x < 1 || y < 1)
throw new NumberFormatException(); //I'm lazy
if(x != scr.resolution.x || y != scr.resolution.y)
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.vec2(tes, side, SMessageScreenCtrl.CTRL_SET_RESOLUTION, new Vector2i(x, y)));
} catch(NumberFormatException ex) {
//Roll back
tfResX.setText("" + scr.resolution.x);
tfResY.setText("" + scr.resolution.y);
}
btnSetRes.setDisabled(true);
}
@GuiSubscribe
public void onClick(Button.ClickEvent ev) {
if(ev.getSource() == btnAdd && !waitingAC)
addFriend(tfFriend.getText().trim());
else if(ev.getSource() == btnSetRes)
clickSetRes();
else if(ev.getSource() == btnChangeRot) {
Rotation[] rots = Rotation.values();
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tes, side, rots[(rotation.ordinal() + 1) % rots.length]));
}
}
@GuiSubscribe
public void onEnterPressed(TextField.EnterPressedEvent ev) {
if(ev.getSource() == tfFriend && !waitingAC)
addFriend(ev.getText().trim());
else if((ev.getSource() == tfResX || ev.getSource() == tfResY) && !btnSetRes.isDisabled())
clickSetRes();
}
@GuiSubscribe
public void onAutocomplete(TextField.TabPressedEvent ev) {
if(ev.getSource() == tfFriend && !waitingAC && !ev.getBeginning().isEmpty()) {
if(acResults.isEmpty()) {
waitingAC = true;
requestAutocomplete(ev.getBeginning(), false);
} else {
NameUUIDPair pair = acResults.remove(0);
tfFriend.setText(pair.name);
}
} else if(ev.getSource() == tfResX) {
tfResX.setFocused(false);
tfResY.focus();
tfResY.getMcField().setCursorPositionZero();
tfResY.getMcField().setSelectionPos(tfResY.getText().length());
}
}
@GuiSubscribe
public void onTextChanged(TextField.TextChangedEvent ev) {
if(ev.getSource() == tfResX || ev.getSource() == tfResY) {
for(int i = 0; i < ev.getNewContent().length(); i++) {
if(!Character.isDigit(ev.getNewContent().charAt(i))) {
ev.getSource().setText(ev.getOldContent());
return;
}
}
if(cbLockRatio.isChecked()) {
if(ev.getSource() == tfResX) {
try {
float val = (float) Integer.parseInt(ev.getNewContent());
val /= aspectRatio;
tfResY.setText("" + ((int) val));
} catch(NumberFormatException ex) {}
} else {
try {
float val = (float) Integer.parseInt(ev.getNewContent());
val *= aspectRatio;
tfResX.setText("" + ((int) val));
} catch(NumberFormatException ex) {}
}
}
btnSetRes.setDisabled(false);
}
}
@GuiSubscribe
public void onRemovePlayer(List.EntryClick ev) {
if(ev.getSource() == lstFriends)
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tes, side, (NameUUIDPair) ev.getUserdata(), true));
}
@GuiSubscribe
public void onCheckboxChanged(CheckBox.CheckedEvent ev) {
if(isFriendCheckbox(ev.getSource())) {
int flag = (Integer) ev.getSource().getUserdata();
if(ev.isChecked())
friendRights |= flag;
else
friendRights &= ~flag;
requestSync();
} else if(isOtherCheckbox(ev.getSource())) {
int flag = (Integer) ev.getSource().getUserdata();
if(ev.isChecked())
otherRights |= flag;
else
otherRights &= ~flag;
requestSync();
} else if(ev.getSource() == cbLockRatio && ev.isChecked()) {
try {
int x = Integer.parseInt(tfResX.getText());
int y = Integer.parseInt(tfResY.getText());
aspectRatio = ((float) x) / ((float) y);
} catch(NumberFormatException ex) {
cbLockRatio.setChecked(false);
}
} else if(ev.getSource() == cbAutoVolume)
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.autoVol(tes, side, ev.isChecked()));
}
@GuiSubscribe
public void onRemoveUpgrade(UpgradeGroup.ClickEvent ev) {
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tes, side, ev.getMouseOverStack()));
}
public boolean isFriendCheckbox(CheckBox cb) {
return Arrays.stream(friendBoxes).anyMatch(fb -> cb == fb);
}
public boolean isOtherCheckbox(CheckBox cb) {
return Arrays.stream(otherBoxes).anyMatch(ob -> cb == ob);
}
public boolean hasFriend(NameUUIDPair f) {
return Arrays.stream(friends).anyMatch(f::equals);
}
@Override
public void onAutocompleteResult(NameUUIDPair pairs[]) {
waitingAC = false;
if(adding) {
if(!hasFriend(pairs[0]))
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tes, side, pairs[0], false));
tfFriend.setDisabled(false);
tfFriend.clear();
tfFriend.focus();
adding = false;
} else {
acResults.clear();
acResults.addAll(Arrays.asList(pairs));
NameUUIDPair pair = acResults.remove(0);
tfFriend.setText(pair.name);
}
}
@Override
public void onAutocompleteFailure() {
waitingAC = false;
acResults.clear();
acFailTicks = 0;
tfFriend.setTextColor(Control.COLOR_RED);
if(adding) {
tfFriend.setDisabled(false);
adding = false;
}
}
@Override
public void updateScreen() {
super.updateScreen();
if(acFailTicks >= 0) {
if(++acFailTicks >= 10) {
acFailTicks = -1;
tfFriend.setTextColor(TextField.DEFAULT_TEXT_COLOR);
}
}
}
public void updateFriends(NameUUIDPair[] friends) {
boolean diff = false;
if(friends.length != this.friends.length)
diff = true;
else {
for(NameUUIDPair pair : friends) {
if(!hasFriend(pair)) {
diff = true;
break;
}
}
}
if(diff) {
this.friends = friends;
lstFriends.clearRaw();
for(NameUUIDPair pair : friends)
lstFriends.addElementRaw(pair.name, pair);
lstFriends.updateContent();
}
}
private int updateRights(int current, int newVal, CheckBox[] boxes, boolean force) {
if(force || current != newVal) {
for(CheckBox box : boxes) {
int flag = (Integer) box.getUserdata();
box.setChecked((newVal & flag) != 0);
}
if(!force) {
Log.info("Screen check boxes were updated");
abortSync(); //Value changed by another user, abort modifications by local user
}
}
return newVal;
}
public void updateFriendRights(int rights) {
friendRights = updateRights(friendRights, rights, friendBoxes, false);
}
public void updateOtherRights(int rights) {
otherRights = updateRights(otherRights, rights, otherBoxes, false);
}
@Override
protected void sync() {
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tes, side, friendRights, otherRights));
Log.info("Sent sync packet");
}
public void updateMyRights() {
NameUUIDPair me = new NameUUIDPair(mc.player.getGameProfile());
int myRights;
boolean clientIsOwner = false;
if(me.equals(owner)) {
myRights = ScreenRights.ALL;
clientIsOwner = true;
} else if(hasFriend(me))
myRights = friendRights;
else
myRights = otherRights;
//Disable components according to client rights
grpFriends.setDisabled(!clientIsOwner);
boolean flag = (myRights & ScreenRights.MANAGE_FRIEND_LIST) == 0;
lstFriends.setDisabled(flag);
tfFriend.setDisabled(flag);
btnAdd.setDisabled(flag);
flag = (myRights & ScreenRights.MANAGE_OTHER_RIGHTS) == 0;
grpOthers.setDisabled(flag);
flag = (myRights & ScreenRights.CHANGE_RESOLUTION) == 0;
tfResX.setDisabled(flag);
tfResY.setDisabled(flag);
btnChangeRot.setDisabled(flag);
if(flag)
btnSetRes.setDisabled(true);
flag = (myRights & ScreenRights.MANAGE_UPGRADES) == 0;
ugUpgrades.setDisabled(flag);
cbAutoVolume.setDisabled(flag);
}
public void updateResolution(Vector2i res) {
aspectRatio = ((float) res.x) / ((float) res.y);
tfResX.setText("" + res.x);
tfResY.setText("" + res.y);
btnSetRes.setDisabled(true);
}
public void updateRotation(Rotation rot) {
rotation = rot;
updateRotationStr();
}
public void updateAutoVolume(boolean av) {
cbAutoVolume.setChecked(av);
}
@Override
public boolean isForBlock(BlockPos bp, BlockSide side) {
return bp.equals(tes.getPos()) && side == this.side;
}
@Nullable
@Override
public String getWikiPageName() {
ItemStack is = ugUpgrades.getMouseOverUpgrade();
if(is != null) {
if(is.getItem() instanceof WDItem)
return ((WDItem) is.getItem()).getWikiName(is);
else
return null;
}
return "Screen_Configurator";
}
}

View File

@@ -0,0 +1,711 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import net.minecraft.client.audio.ISound;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.BlockPos;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.miniserv.Constants;
import net.montoyo.wd.miniserv.client.*;
import net.montoyo.wd.utilities.*;
import org.lwjgl.input.Keyboard;
import javax.annotation.Nullable;
import javax.swing.filechooser.FileSystemView;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import static org.lwjgl.opengl.GL11.*;
public class GuiServer extends WDScreen {
private static final ResourceLocation BG_IMAGE = new ResourceLocation("webdisplays", "textures/gui/server_bg.png");
private static final ResourceLocation FG_IMAGE = new ResourceLocation("webdisplays", "textures/gui/server_fg.png");
private static final HashMap<String, Method> COMMAND_MAP = new HashMap<>();
private static final int MAX_LINE_LEN = 32;
private static final int MAX_LINES = 12;
private final Vector3i serverPos;
private final NameUUIDPair owner;
private final ArrayList<String> lines = new ArrayList<>();
private String prompt = "";
private String userPrompt;
private int blinkTime;
private String lastCmd;
private boolean promptLocked;
private volatile long queryTime;
private ClientTask<?> currentTask;
private int selectedLine = -1;
//Access command
private int accessTrials;
private int accessTime;
private int accessState = -1;
private PositionedSoundRecord accessSound;
//Upload wizard
private boolean uploadWizard;
private File uploadDir;
private final ArrayList<File> uploadFiles = new ArrayList<>();
private int uploadOffset;
private boolean uploadFirstIsParent;
private String uploadFilter = "";
private long uploadFilterTime;
public GuiServer(Vector3i vec, NameUUIDPair owner) {
serverPos = vec;
this.owner = owner;
//userPrompt = owner.name + "@miniserv$ ";
userPrompt = "> ";
if(COMMAND_MAP.isEmpty())
buildCommandMap();
lines.add("MiniServ 1.0");
lines.add(tr("info"));
uploadCD(FileSystemView.getFileSystemView().getDefaultDirectory());
}
private static String tr(String key, Object ... args) {
return I18n.format("webdisplays.server." + key, args);
}
@Override
public void drawScreen(int mouseX, int mouseY, float ptt) {
super.drawScreen(mouseX, mouseY, ptt);
int x = (width - 256) / 2;
int y = (height - 176) / 2;
GlStateManager.enableTexture2D();
mc.renderEngine.bindTexture(BG_IMAGE);
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
drawTexturedModalRect(x, y, 0, 0, 256, 176);
x += 18;
y += 18;
for(int i = 0; i < lines.size(); i++) {
if(selectedLine == i) {
drawWhiteQuad(x - 1, y - 2, fontRenderer.getStringWidth(lines.get(i)) + 1, 12);
fontRenderer.drawString(lines.get(i), x, y, 0xFF129700, false);
} else
fontRenderer.drawString(lines.get(i), x, y, 0xFFFFFFFF, false);
y += 12;
}
if(!promptLocked) {
x = fontRenderer.drawString(userPrompt, x, y, 0xFFFFFFFF, false);
x = fontRenderer.drawString(prompt, x, y, 0xFFFFFFFF, false);
}
if(!uploadWizard && blinkTime < 5)
drawWhiteQuad(x + 1, y, 6, 8);
GlStateManager.disableAlpha();
GlStateManager.enableTexture2D();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
mc.renderEngine.bindTexture(FG_IMAGE);
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
drawTexturedModalRect((width - 256) / 2, (height - 176) / 2, 0, 0, 256, 176);
GlStateManager.enableAlpha();
}
private void drawWhiteQuad(int x, int y, int w, int h) {
double xd = (double) x;
double xd2 = (double) (x + w);
double yd = (double) y;
double yd2 = (double) (y + h);
double zd = (double) zLevel;
GlStateManager.disableTexture2D();
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
Tessellator t = Tessellator.getInstance();
BufferBuilder bb = t.getBuffer();
bb.begin(GL_QUADS, DefaultVertexFormats.POSITION);
bb.pos(xd, yd2, zd).endVertex();
bb.pos(xd2, yd2, zd).endVertex();
bb.pos(xd2, yd, zd).endVertex();
bb.pos(xd, yd, zd).endVertex();
t.draw();
GlStateManager.enableTexture2D();
}
@Override
public void updateScreen() {
super.updateScreen();
if(accessState >= 0) {
if(--accessTime <= 0) {
accessState++;
if(accessState == 1) {
if(lines.size() > 0)
lines.remove(lines.size() - 1);
lines.add("access: PERMISSION DENIED....and...");
accessTime = 20;
} else {
if(accessSound == null) {
accessSound = new PositionedSoundRecord(WebDisplays.INSTANCE.soundServer.getSoundName(), SoundCategory.MASTER, 1.0f, 1.0f, true, 0, ISound.AttenuationType.NONE, 0.0f, 0.0f, 0.0f);
mc.getSoundHandler().playSound(accessSound);
}
writeLine("YOU DIDN'T SAY THE MAGIC WORD!");
accessTime = 2;
}
}
} else {
blinkTime = (blinkTime + 1) % 10;
if(currentTask != null) {
long queryTime;
synchronized(this) {
queryTime = this.queryTime;
}
if(System.currentTimeMillis() - queryTime >= 10000) {
writeLine(tr("timeout"));
currentTask.cancel();
clearTask();
}
}
if(!uploadFilter.isEmpty() && System.currentTimeMillis() - uploadFilterTime >= 1000) {
Log.info("Upload filter cleared");
uploadFilter = "";
}
}
}
@Override
public void handleKeyboardInput() throws IOException {
boolean keyState = Keyboard.getEventKeyState();
int keyCode = Keyboard.getEventKey();
if(uploadWizard) {
if(keyState) {
if(keyCode == Keyboard.KEY_UP) {
if(selectedLine > 3)
selectedLine--;
else if(uploadOffset > 0) {
uploadOffset--;
updateUploadScreen();
}
} else if(keyCode == Keyboard.KEY_DOWN) {
if(selectedLine < MAX_LINES - 1)
selectedLine++;
else if(uploadOffset + selectedLine - 2 < uploadFiles.size()) {
uploadOffset++;
updateUploadScreen();
}
} else if(keyCode == Keyboard.KEY_PRIOR) {
selectedLine = 3;
int dst = uploadOffset - (MAX_LINES - 3);
if(dst < 0)
dst = 0;
selectFile(dst);
} else if(keyCode == Keyboard.KEY_NEXT) {
selectedLine = 3;
int dst = uploadOffset + (MAX_LINES - 3);
if(dst >= uploadFiles.size())
dst = uploadFiles.size() - 1;
selectFile(dst);
} else if(keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER) {
File file = uploadFiles.get(uploadOffset + selectedLine - 3);
if(file.isDirectory()) {
uploadCD(file);
updateUploadScreen();
} else
startFileUpload(file, true);
} else if(keyCode == Keyboard.KEY_F5) {
uploadCD(uploadDir);
updateUploadScreen();
}
}
if(keyCode == Keyboard.KEY_ESCAPE) {
quitUploadWizard();
return; //Don't let the screen handle this
}
super.handleKeyboardInput();
} else {
super.handleKeyboardInput();
if(keyState) {
boolean ctrl = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL);
if(keyCode == Keyboard.KEY_L && ctrl)
lines.clear();
else if(keyCode == Keyboard.KEY_V && ctrl) {
prompt += getClipboardString();
if(prompt.length() > MAX_LINE_LEN)
prompt = prompt.substring(0, MAX_LINE_LEN);
} else if(keyCode == Keyboard.KEY_UP) {
if(lastCmd != null) {
String tmp = prompt;
prompt = lastCmd;
lastCmd = tmp;
}
}
}
}
}
@Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
super.keyTyped(typedChar, keyCode);
if(uploadWizard) {
boolean found = false;
uploadFilter += Character.toLowerCase(typedChar);
uploadFilterTime = System.currentTimeMillis();
for(int i = uploadFirstIsParent ? 1 : 0; i < uploadFiles.size(); i++) {
if(uploadFiles.get(i).getName().toLowerCase().startsWith(uploadFilter)) {
selectFile(i);
found = true;
break;
}
}
if(!found && uploadFilter.length() == 1)
uploadFilter = "";
return;
} else if(promptLocked)
return;
if(keyCode == Keyboard.KEY_BACK) {
if(prompt.length() > 0)
prompt = prompt.substring(0, prompt.length() - 1);
} else if(keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER) {
if(prompt.length() > 0) {
writeLine(userPrompt + prompt);
evaluateCommand(prompt);
lastCmd = prompt;
prompt = "";
} else
writeLine(userPrompt);
} else if(prompt.length() + 1 < MAX_LINE_LEN && typedChar >= 32 && typedChar <= 126)
prompt = prompt + typedChar;
blinkTime = 0;
}
private void evaluateCommand(String str) {
String[] args = str.trim().split("\\s+");
Method handler = COMMAND_MAP.get(args[0].toLowerCase());
if(handler == null) {
writeLine(tr("unknowncmd"));
return;
}
Object[] params;
if(handler.getParameterCount() == 0)
params = new Object[0];
else {
String[] args2 = new String[args.length - 1];
System.arraycopy(args, 1, args2, 0, args2.length);
params = new Object[] { args2 };
}
try {
handler.invoke(this, params);
} catch(IllegalAccessException | InvocationTargetException e) {
Log.errorEx("Caught exception while running command \"%s\"", e, str);
writeLine(tr("error"));
}
}
private void writeLine(String line) {
final int maxl = uploadWizard ? MAX_LINES : (MAX_LINES - 1); //Cuz prompt is hidden
while(lines.size() >= maxl)
lines.remove(0);
lines.add(line);
}
private static void buildCommandMap() {
COMMAND_MAP.clear();
Method[] methods = GuiServer.class.getMethods();
for(Method m: methods) {
CommandHandler cmd = m.getAnnotation(CommandHandler.class);
if(cmd != null && Modifier.isPublic(m.getModifiers())) {
if(m.getParameterCount() == 0 || (m.getParameterCount() == 1 && m.getParameterTypes()[0] == String[].class))
COMMAND_MAP.put(cmd.value().toLowerCase(), m);
}
}
}
private void quitUploadWizard() {
lines.clear();
promptLocked = false;
uploadWizard = false;
selectedLine = -1;
}
@Override
public void onGuiClosed() {
super.onGuiClosed();
if(accessSound != null)
mc.getSoundHandler().stopSound(accessSound);
}
private boolean queueTask(ClientTask<?> task) {
if(Client.getInstance().addTask(task)) {
promptLocked = true;
queryTime = System.currentTimeMillis(); //No task is running so it's okay to have an unsynchronized access here
currentTask = task;
return true;
} else {
writeLine(tr("queryerr"));
return false;
}
}
private void clearTask() {
promptLocked = false;
currentTask = null;
}
private static String trimStringL(String str) {
int delta = str.length() - MAX_LINE_LEN;
if(delta <= 0)
return str;
return "..." + str.substring(delta + 3);
}
private static String trimStringR(String str) {
return (str.length() <= MAX_LINE_LEN) ? str : (str.substring(0, MAX_LINE_LEN - 3) + "...");
}
@CommandHandler("clear")
public void commandClear() {
lines.clear();
}
@CommandHandler("help")
public void commandHelp(String[] args) {
if(args.length > 0) {
String cmd = args[0].toLowerCase();
if(COMMAND_MAP.containsKey(cmd))
writeLine(tr("help." + cmd));
else
writeLine(tr("unknowncmd"));
} else {
for(String c : COMMAND_MAP.keySet())
writeLine(c + " - " + tr("help." + c));
}
}
@CommandHandler("exit")
public void commandExit() {
mc.displayGuiScreen(null);
}
@CommandHandler("access")
public void commandAccess(String[] args) {
boolean handled = false;
if(args.length >= 1 && args[0].equalsIgnoreCase("security")) {
if(args.length == 1 || (args.length == 2 && args[1].equalsIgnoreCase("grid")))
handled = true;
} else if(args.length == 3 && args[0].equalsIgnoreCase("main") && args[1].equalsIgnoreCase("security") && args[2].equalsIgnoreCase("grid"))
handled = true;
if(handled) {
writeLine("access: PERMISSION DENIED.");
if(++accessTrials >= 3) {
promptLocked = true;
accessState = 0;
accessTime = 20;
}
} else
writeLine(tr("argerror"));
}
@CommandHandler("owner")
public void commandOwner() {
writeLine(tr("ownername", owner.name));
writeLine(tr("owneruuid"));
writeLine(owner.uuid.toString());
}
@CommandHandler("quota")
public void commandQuota() {
if(!mc.player.getGameProfile().getId().equals(owner.uuid)) {
writeLine(tr("errowner"));
return;
}
ClientTaskGetQuota task = new ClientTaskGetQuota();
task.setFinishCallback((t) -> {
writeLine(tr("quota", Util.sizeString(t.getQuota()), Util.sizeString(t.getMaxQuota())));
clearTask();
});
queueTask(task);
}
@CommandHandler("ls")
public void commandList() {
ClientTaskGetFileList task = new ClientTaskGetFileList(owner.uuid);
task.setFinishCallback((t) -> {
String[] files = t.getFileList();
if(files != null)
Arrays.stream(files).forEach(this::writeLine);
clearTask();
});
queueTask(task);
}
@CommandHandler("url")
public void commandURL(String[] args) {
if(args.length < 1) {
writeLine(tr("fnamearg"));
return;
}
String fname = Util.join(args, " ");
if(Util.isFileNameInvalid(fname)) {
writeLine(tr("nameerr"));
return;
}
ClientTaskCheckFile task = new ClientTaskCheckFile(owner.uuid, fname);
task.setFinishCallback((t) -> {
int status = t.getStatus();
if(status == 0) {
writeLine(tr("urlcopied"));
setClipboardString(t.getURL());
} else if(status == Constants.GETF_STATUS_NOT_FOUND)
writeLine(tr("notfound"));
else
writeLine(tr("error2", status));
clearTask();
});
queueTask(task);
}
private void uploadCD(File newDir) {
try {
uploadDir = newDir.getCanonicalFile();
} catch(IOException ex) {
uploadDir = newDir;
}
uploadFiles.clear();
File parent = uploadDir.getParentFile();
if(parent != null && parent.exists()) {
uploadFiles.add(parent);
uploadFirstIsParent = true;
} else
uploadFirstIsParent = false;
File[] children = uploadDir.listFiles();
if(children != null) {
Collator c = Collator.getInstance();
c.setStrength(Collator.SECONDARY);
c.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
Arrays.stream(children).filter(f -> !f.isHidden() && (f.isDirectory() || f.isFile())).sorted((a, b) -> c.compare(a.getName(), b.getName())).forEach(uploadFiles::add);
}
uploadOffset = 0;
uploadFilter = "";
if(uploadWizard)
selectedLine = 3;
}
private void updateUploadScreen() {
lines.clear();
lines.add(tr("upload.info"));
lines.add(trimStringL(uploadDir.getPath()));
lines.add("");
for(int i = uploadOffset; i < uploadFiles.size() && lines.size() < MAX_LINES; i++) {
if(i == 0 && uploadFirstIsParent)
lines.add(tr("upload.parent"));
else
lines.add(trimStringR(uploadFiles.get(i).getName()));
}
}
private void selectFile(int i) {
int pos = 3 + i - uploadOffset;
if(pos >= 3 && pos < MAX_LINES) {
selectedLine = pos;
return;
}
uploadOffset = i;
if(uploadOffset + MAX_LINES - 3 > uploadFiles.size())
uploadOffset = uploadFiles.size() - MAX_LINES + 3;
updateUploadScreen();
selectedLine = 3 + i - uploadOffset;
}
@CommandHandler("upload")
public void commandUpload(String[] args) {
if(!mc.player.getGameProfile().getId().equals(owner.uuid)) {
writeLine(tr("errowner"));
return;
}
if(args.length > 0) {
File fle = new File(Util.join(args, " "));
if(!fle.exists()) {
writeLine(tr("notfound"));
return;
}
if(fle.isDirectory())
uploadCD(fle);
else if(fle.isFile()) {
startFileUpload(fle, false);
return;
} else {
writeLine(tr("notfound"));
return;
}
}
uploadWizard = true;
promptLocked = true;
uploadOffset = 0;
selectedLine = 3;
updateUploadScreen();
}
@CommandHandler("rm")
public void commandDelete(String[] args) {
if(!mc.player.getGameProfile().getId().equals(owner.uuid)) {
writeLine(tr("errowner"));
return;
}
if(args.length < 1) {
writeLine(tr("fnamearg"));
return;
}
String fname = Util.join(args, " ");
if(Util.isFileNameInvalid(fname)) {
writeLine(tr("nameerr"));
return;
}
ClientTaskDeleteFile task = new ClientTaskDeleteFile(fname);
task.setFinishCallback((t) -> {
int status = t.getStatus();
if(status == 1)
writeLine(tr("notfound"));
else if(status != 0)
writeLine(tr("error"));
clearTask();
});
queueTask(task);
}
@CommandHandler("reconnect")
public void commandReconnect() {
Client.getInstance().stop();
WebDisplays.NET_HANDLER.sendToServer(Client.getInstance().beginConnection());
}
private void startFileUpload(File f, boolean quit) {
if(quit)
quitUploadWizard();
if(Util.isFileNameInvalid(f.getName()) || f.getName().length() >= MAX_LINE_LEN - 3) {
writeLine(tr("nameerr"));
return;
}
ClientTaskUploadFile task;
try {
task = new ClientTaskUploadFile(f);
} catch(IOException ex) {
writeLine(tr("error"));
ex.printStackTrace();
return;
}
task.setProgressCallback((cur, total) -> {
synchronized(GuiServer.this) {
queryTime = System.currentTimeMillis();
}
});
task.setFinishCallback(t -> {
int status = t.getUploadStatus();
if(status == 0)
writeLine(tr("upload.done"));
else if(status == Constants.FUPA_STATUS_FILE_EXISTS)
writeLine(tr("upload.exists"));
else if(status == Constants.FUPA_STATUS_EXCEEDS_QUOTA)
writeLine(tr("upload.quota"));
else
writeLine(tr("error2", status));
clearTask();
});
if(queueTask(task))
writeLine(tr("upload.uploading"));
}
@Override
public boolean isForBlock(BlockPos bp, BlockSide side) {
return serverPos.equalsBlockPos(bp);
}
@Nullable
@Override
public String getWikiPageName() {
return "Server";
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.ClientProxy;
import net.montoyo.wd.client.gui.controls.Button;
import net.montoyo.wd.client.gui.controls.TextField;
import net.montoyo.wd.client.gui.loading.FillControl;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.net.server.SMessagePadCtrl;
import net.montoyo.wd.net.server.SMessageScreenCtrl;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Util;
import net.montoyo.wd.utilities.Vector3i;
import java.util.Map;
public class GuiSetURL2 extends WDScreen {
//Screen data
private TileEntityScreen tileEntity;
private BlockSide screenSide;
private Vector3i remoteLocation;
//Pad data
private final boolean isPad;
//Common
private final String screenURL;
@FillControl
private TextField tfURL;
@FillControl
private Button btnShutDown;
@FillControl
private Button btnCancel;
@FillControl
private Button btnOk;
public GuiSetURL2(TileEntityScreen tes, BlockSide side, String url, Vector3i rl) {
tileEntity = tes;
screenSide = side;
remoteLocation = rl;
isPad = false;
screenURL = url;
}
public GuiSetURL2(String url) {
isPad = true;
screenURL = url;
}
@Override
public void initGui() {
super.initGui();
loadFrom(new ResourceLocation("webdisplays", "gui/seturl.json"));
tfURL.setText(screenURL);
}
@Override
protected void addLoadCustomVariables(Map<String, Double> vars) {
vars.put("isPad", isPad ? 1.0 : 0.0);
}
@GuiSubscribe
public void onButtonClicked(Button.ClickEvent ev) {
if(ev.getSource() == btnCancel)
mc.displayGuiScreen(null);
else if(ev.getSource() == btnOk)
validate(tfURL.getText());
else if(ev.getSource() == btnShutDown) {
if(isPad)
WebDisplays.NET_HANDLER.sendToServer(new SMessagePadCtrl(""));
mc.displayGuiScreen(null);
}
}
@GuiSubscribe
public void onEnterPressed(TextField.EnterPressedEvent ev) {
validate(ev.getText());
}
private void validate(String url) {
if(!url.isEmpty()) {
url = Util.addProtocol(url);
url = ((ClientProxy) WebDisplays.PROXY).getMCEF().punycode(url);
if(isPad) {
WebDisplays.NET_HANDLER.sendToServer(new SMessagePadCtrl(url));
ItemStack held = mc.player.getHeldItem(EnumHand.MAIN_HAND);
if(held.getItem() == WebDisplays.INSTANCE.itemMinePad && held.getTagCompound() != null && held.getTagCompound().hasKey("PadID")) {
ClientProxy.PadData pd = ((ClientProxy) WebDisplays.PROXY).getPadByID(held.getTagCompound().getInteger("PadID"));
if(pd != null && pd.view != null)
pd.view.loadURL(WebDisplays.applyBlacklist(url));
}
} else
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.setURL(tileEntity, screenSide, url, remoteLocation));
}
mc.displayGuiScreen(null);
}
@Override
public boolean isForBlock(BlockPos bp, BlockSide side) {
return (remoteLocation != null && remoteLocation.equalsBlockPos(bp)) || (bp.equals(tileEntity.getPos()) && side == screenSide);
}
}

View File

@@ -0,0 +1,15 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GuiSubscribe {
}

View File

@@ -0,0 +1,203 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.RenderItem;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.client.resources.I18n;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.item.crafting.ShapedRecipes;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.utilities.Log;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.EXTBgra;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.stream.IntStream;
import static org.lwjgl.opengl.GL11.*;
@SideOnly(Side.CLIENT)
public class RenderRecipe extends GuiScreen {
private static class NameRecipePair {
private final String name;
private final ShapedRecipes recipe;
private NameRecipePair(String n, ShapedRecipes r) {
this.name = n;
this.recipe = r;
}
}
private static final ResourceLocation CRAFTING_TABLE_GUI_TEXTURES = new ResourceLocation("textures/gui/container/crafting_table.png");
private static final int SIZE_X = 176;
private static final int SIZE_Y = 166;
private int x;
private int y;
private RenderItem renderItem;
private final ItemStack[] recipe = new ItemStack[3 * 3];
private ItemStack recipeResult;
private String recipeName;
private final ArrayList<NameRecipePair> recipes = new ArrayList<>();
private IntBuffer buffer;
private int[] array;
@Override
public void initGui() {
x = (width - SIZE_X) / 2;
y = (height - SIZE_Y) / 2;
renderItem = mc.getRenderItem();
for(IRecipe recipe: CraftingManager.REGISTRY) {
ResourceLocation regName = recipe.getRegistryName();
if(regName != null && regName.getResourceDomain().equals("webdisplays")) {
if(recipe instanceof ShapedRecipes)
recipes.add(new NameRecipePair(regName.getResourcePath(), (ShapedRecipes) recipe));
else
Log.warning("Found non-shaped recipe %s", regName.toString());
}
}
Log.info("Loaded %d recipes", recipes.size());
nextRecipe();
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
drawDefaultBackground();
GlStateManager.color(1.0f, 1.0f, 1.0f);
mc.getTextureManager().bindTexture(CRAFTING_TABLE_GUI_TEXTURES);
drawTexturedModalRect(x, y, 0, 0, SIZE_X, SIZE_Y);
fontRenderer.drawString(I18n.format("container.crafting"), x + 28, y + 6, 0x404040);
RenderHelper.enableGUIStandardItemLighting();
GlStateManager.disableLighting();
for(int sy = 0; sy < 3; sy++) {
for(int sx = 0; sx < 3; sx++) {
ItemStack is = recipe[sy * 3 + sx];
if(is != null) {
int x = this.x + 30 + sx * 18;
int y = this.y + 17 + sy * 18;
renderItem.renderItemAndEffectIntoGUI(mc.player, is, x, y);
renderItem.renderItemOverlayIntoGUI(fontRenderer, is, x, y, null);
}
}
}
if(recipeResult != null) {
renderItem.renderItemAndEffectIntoGUI(mc.player, recipeResult, x + 124, y + 35);
renderItem.renderItemOverlayIntoGUI(fontRenderer, recipeResult, x + 124, y + 35, null);
}
GlStateManager.enableLighting();
RenderHelper.disableStandardItemLighting();
}
private void setRecipe(ShapedRecipes recipe) {
IntStream.range(0, this.recipe.length).forEach(i -> this.recipe[i] = null);
NonNullList<Ingredient> ingredients = recipe.getIngredients();
int pos = 0;
for(int y = 0; y < recipe.getRecipeHeight(); y++) {
for(int x = 0; x < recipe.getRecipeWidth(); x++) {
ItemStack[] stacks = ingredients.get(pos++).getMatchingStacks();
if(stacks.length > 0)
this.recipe[y * 3 + x] = stacks[0];
}
}
recipeResult = recipe.getRecipeOutput();
}
private void nextRecipe() {
if(recipes.isEmpty())
mc.displayGuiScreen(null);
else {
NameRecipePair pair = recipes.remove(0);
setRecipe(pair.recipe);
recipeName = pair.name;
}
}
private int screen2DisplayX(int x) {
double ret = ((double) x) / ((double) width) * ((double) mc.displayWidth);
return (int) ret;
}
private int screen2DisplayY(int y) {
double ret = ((double) y) / ((double) height) * ((double) mc.displayHeight);
return (int) ret;
}
private void takeScreenshot() throws Throwable {
int x = screen2DisplayX(this.x + 27);
int y = mc.displayHeight - screen2DisplayY(this.y + 4);
int w = screen2DisplayX(120);
int h = screen2DisplayY(68);
y -= h;
if(buffer == null)
buffer = BufferUtils.createIntBuffer(w * h);
int oldPack = glGetInteger(GL_PACK_ALIGNMENT);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
buffer.clear();
glReadPixels(x, y, w, h, EXTBgra.GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer);
glPixelStorei(GL_PACK_ALIGNMENT, oldPack);
if(array == null)
array = new int[w * h];
buffer.clear();
buffer.get(array);
TextureUtil.processPixelValues(array, w, h);
File f = new File(mc.mcDataDir, "wd_recipes");
if(!f.exists())
f.mkdir();
f = new File(f, recipeName + ".png");
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
bi.setRGB(0, 0, w, h, array, 0, w);
ImageIO.write(bi, "PNG", f);
}
@Override
public void updateScreen() {
if(recipeName != null) {
try {
takeScreenshot();
nextRecipe();
} catch(Throwable t) {
t.printStackTrace();
mc.displayGuiScreen(null);
}
}
}
}

View File

@@ -0,0 +1,367 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.gui.controls.Container;
import net.montoyo.wd.client.gui.controls.Control;
import net.montoyo.wd.client.gui.controls.Event;
import net.montoyo.wd.client.gui.controls.List;
import net.montoyo.wd.client.gui.loading.FillControl;
import net.montoyo.wd.client.gui.loading.GuiLoader;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import net.montoyo.wd.net.server.SMessageACQuery;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Bounds;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.NameUUIDPair;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public abstract class WDScreen extends GuiScreen {
public static WDScreen CURRENT_SCREEN = null;
protected final ArrayList<Control> controls = new ArrayList<>();
protected final ArrayList<Control> postDrawList = new ArrayList<>();
private final HashMap<Class<? extends Event>, Method> eventMap = new HashMap<>();
protected boolean quitOnEscape = true;
protected boolean defaultBackground = true;
protected int syncTicks = 40;
private int syncTicksLeft = -1;
public WDScreen() {
Method[] methods = getClass().getMethods();
for(Method m : methods) {
if(m.getAnnotation(GuiSubscribe.class) != null) {
if(!Modifier.isPublic(m.getModifiers()))
throw new RuntimeException("Found non public @GuiSubscribe");
Class<?> params[] = m.getParameterTypes();
if(params.length != 1 || !Event.class.isAssignableFrom(params[0]))
throw new RuntimeException("Invalid parameters for @GuiSubscribe");
eventMap.put((Class<? extends Event>) params[0], m);
}
}
}
protected <T extends Control> T addControl(T ctrl) {
controls.add(ctrl);
return ctrl;
}
public int screen2DisplayX(int x) {
double ret = ((double) x) / ((double) width) * ((double) mc.displayWidth);
return (int) ret;
}
public int screen2DisplayY(int y) {
double ret = ((double) y) / ((double) height) * ((double) mc.displayHeight);
return (int) ret;
}
public int display2ScreenX(int x) {
double ret = ((double) x) / ((double) mc.displayWidth) * ((double) width);
return (int) ret;
}
public int display2ScreenY(int y) {
double ret = ((double) y) / ((double) mc.displayHeight) * ((double) height);
return (int) ret;
}
protected void centerControls() {
//Determine bounding box
Bounds bounds = Control.findBounds(controls);
//Translation vector
int diffX = (width - bounds.maxX - bounds.minX) / 2;
int diffY = (height - bounds.maxY - bounds.minY) / 2;
//Translate controls
for(Control ctrl : controls) {
int x = ctrl.getX();
int y = ctrl.getY();
ctrl.setPos(x + diffX, y + diffY);
}
}
@Override
public void drawScreen(int mouseX, int mouseY, float ptt) {
if(defaultBackground)
drawDefaultBackground();
for(Control ctrl: controls)
ctrl.draw(mouseX, mouseY, ptt);
for(Control ctrl: postDrawList)
ctrl.postDraw(mouseX, mouseY, ptt);
}
@Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
if(quitOnEscape && keyCode == Keyboard.KEY_ESCAPE) {
mc.displayGuiScreen(null);
return;
}
for(Control ctrl: controls)
ctrl.keyTyped(typedChar, keyCode);
}
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
for(Control ctrl: controls)
ctrl.mouseClicked(mouseX, mouseY, mouseButton);
}
@Override
protected void mouseReleased(int mouseX, int mouseY, int state) {
for(Control ctrl: controls)
ctrl.mouseReleased(mouseX, mouseY, state);
}
@Override
protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
for(Control ctrl: controls)
ctrl.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick);
}
@Override
public void initGui() {
CURRENT_SCREEN = this;
Keyboard.enableRepeatEvents(true);
}
@Override
public void onGuiClosed() {
if(syncTicksLeft >= 0) {
sync();
syncTicksLeft = -1;
}
for(Control ctrl : controls)
ctrl.destroy();
Keyboard.enableRepeatEvents(false);
CURRENT_SCREEN = null;
}
@Override
public void handleMouseInput() throws IOException {
super.handleMouseInput();
int x = Mouse.getEventX() * width / mc.displayWidth;
int y = height - Mouse.getEventY() * height / mc.displayHeight - 1;
int dw = Mouse.getEventDWheel();
if(dw != 0)
onMouseScroll(x, y, dw);
else if(Mouse.getEventButton() == -1)
onMouseMove(x, y);
}
@Override
public void handleKeyboardInput() throws IOException {
super.handleKeyboardInput();
int key = Keyboard.getEventKey();
if(key != Keyboard.KEY_NONE) {
if(Keyboard.getEventKeyState()) {
for(Control ctrl : controls)
ctrl.keyDown(key);
} else {
for(Control ctrl : controls)
ctrl.keyUp(key);
}
}
}
public void onMouseScroll(int mouseX, int mouseY, int amount) {
for(Control ctrl : controls)
ctrl.mouseScroll(mouseX, mouseY, amount);
}
public void onMouseMove(int mouseX, int mouseY) {
for(Control ctrl : controls)
ctrl.mouseMove(mouseX, mouseY);
}
public Object actionPerformed(Event ev) {
Method m = eventMap.get(ev.getClass());
if(m != null) {
try {
return m.invoke(this, ev);
} catch(IllegalAccessException e) {
Log.errorEx("Access to event %s of screen %s is denied", e, ev.getClass().getSimpleName(), getClass().getSimpleName());
} catch(InvocationTargetException e) {
Log.errorEx("Event %s of screen %s failed", e, ev.getClass().getSimpleName(), getClass().getSimpleName());
}
}
return null;
}
public <T extends Control> T getControlByName(String name) {
for(Control ctrl : controls) {
if(name.equals(ctrl.getName()))
return (T) ctrl;
if(ctrl instanceof Container) {
Control ret = ((Container) ctrl).getByName(name);
if(ret != null)
return (T) ret;
}
}
return null;
}
protected void addLoadCustomVariables(Map<String, Double> vars) {
}
public void loadFrom(ResourceLocation resLoc) {
JsonObject root = GuiLoader.getJson(resLoc);
if(root == null)
throw new RuntimeException("Could not load GUI file " + resLoc.toString());
if(!root.has("controls") || !root.get("controls").isJsonArray())
throw new RuntimeException("In GUI file " + resLoc.toString() + ": missing root 'controls' object.");
HashMap<String, Double> vars = new HashMap<>();
vars.put("width", (double) width);
vars.put("height", (double) height);
vars.put("displayWidth", (double) mc.displayWidth);
vars.put("displayHeight", (double) mc.displayHeight);
addLoadCustomVariables(vars);
JsonArray content = root.get("controls").getAsJsonArray();
for(JsonElement elem: content)
controls.add(GuiLoader.create(new JsonOWrapper(elem.getAsJsonObject(), vars)));
Field[] fields = getClass().getDeclaredFields();
for(Field f: fields) {
f.setAccessible(true);
FillControl fc = f.getAnnotation(FillControl.class);
if(fc != null) {
String name = fc.name().isEmpty() ? f.getName() : fc.name();
Control ctrl = getControlByName(name);
if(ctrl == null) {
if(fc.required())
throw new RuntimeException("In GUI file " + resLoc.toString() + ": missing required control " + name);
continue;
}
if(!f.getType().isAssignableFrom(ctrl.getClass()))
throw new RuntimeException("In GUI file " + resLoc.toString() + ": invalid type for control " + name);
try {
f.set(this, ctrl);
} catch(IllegalAccessException e) {
if(fc.required())
throw new RuntimeException(e);
}
}
}
if(root.has("center") && root.get("center").getAsBoolean())
centerControls();
}
@Override
public void onResize(@Nonnull Minecraft mcIn, int w, int h) {
for(Control ctrl : controls)
ctrl.destroy();
controls.clear();
super.onResize(mcIn, w, h);
}
protected void requestAutocomplete(String beginning, boolean matchExact) {
WebDisplays.NET_HANDLER.sendToServer(new SMessageACQuery(beginning, matchExact));
}
public void onAutocompleteResult(NameUUIDPair pairs[]) {
}
public void onAutocompleteFailure() {
}
protected void requestSync() {
syncTicksLeft = syncTicks - 1;
}
protected boolean syncRequested() {
return syncTicksLeft >= 0;
}
protected void abortSync() {
syncTicksLeft = -1;
}
protected void sync() {
}
@Override
public void updateScreen() {
if(syncTicksLeft >= 0) {
if(--syncTicksLeft < 0)
sync();
}
}
public void drawItemStackTooltip(ItemStack is, int x, int y) {
renderToolTip(is, x, y); //Since it's protected...
}
public void drawTooltip(java.util.List<String> lines, int x, int y) {
drawHoveringText(lines, x, y, fontRenderer); //This is also protected...
}
public void requirePostDraw(Control ctrl) {
if(!postDrawList.contains(ctrl))
postDrawList.add(ctrl);
}
@Override
public boolean doesGuiPauseGame() {
return false;
}
public abstract boolean isForBlock(BlockPos bp, BlockSide side);
@Nullable
public String getWikiPageName() {
return null;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
public abstract class BasicControl extends Control {
protected int x;
protected int y;
protected boolean visible = true;
protected boolean disabled = false;
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
@Override
public void setPos(int x, int y) {
this.x = x;
this.y = y;
}
public boolean isDisabled() {
return disabled;
}
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
public void enable() {
disabled = false;
}
public void disable() {
disabled = true;
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public void show() {
visible = true;
}
public void hide() {
visible = false;
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
x = json.getInt("x", 0);
y = json.getInt("y", 0);
disabled = json.getBool("disabled", false);
visible = json.getBool("visible", true);
}
}

View File

@@ -0,0 +1,203 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.minecraft.client.gui.GuiButton;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import org.lwjgl.input.Keyboard;
public class Button extends Control {
protected final GuiButton btn;
protected boolean selected = false;
protected boolean shiftDown = false;
protected int originalColor = 0;
protected int shiftColor = 0;
public static class ClickEvent extends Event<Button> {
private final boolean shiftDown;
private ClickEvent(Button btn) {
source = btn;
shiftDown = btn.shiftDown;
}
public boolean isShiftDown() {
return shiftDown;
}
}
public Button() {
btn = new GuiButton(0, 0, 0, "");
}
public Button(String text, int x, int y, int width) {
btn = new GuiButton(0, x, y, width, 20, text);
}
public Button(String text, int x, int y) {
btn = new GuiButton(0, x, y, text);
}
@Override
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
if(mouseButton == 0 && btn.mousePressed(mc, mouseX, mouseY)) {
selected = true;
btn.playPressSound(mc.getSoundHandler());
if(!onClick())
parent.actionPerformed(new ClickEvent(this));
}
}
@Override
public void mouseReleased(int mouseX, int mouseY, int state) {
if(selected && state == 0) {
btn.mouseReleased(mouseX, mouseY);
selected = false;
}
}
@Override
public void draw(int mouseX, int mouseY, float ptt) {
btn.drawButton(mc, mouseX, mouseY, ptt);
}
public void setLabel(String label) {
btn.displayString = label;
}
public String getLabel() {
return btn.displayString;
}
public void setWidth(int width) {
btn.setWidth(width);
}
@Override
public int getWidth() {
return btn.getButtonWidth();
}
@Override
public int getHeight() {
return 20;
}
@Override
public void setPos(int x, int y) {
btn.x = x;
btn.y = y;
}
@Override
public int getX() {
return btn.x;
}
@Override
public int getY() {
return btn.y;
}
public GuiButton getMcButton() {
return btn;
}
public void setDisabled(boolean dis) {
btn.enabled = !dis;
}
public boolean isDisabled() {
return !btn.enabled;
}
public void enable() {
btn.enabled = true;
}
public void disable() {
btn.enabled = false;
}
public void setVisible(boolean visible) {
btn.visible = visible;
}
public boolean isVisible() {
return btn.visible;
}
public void show() {
btn.visible = true;
}
public void hide() {
btn.visible = false;
}
public boolean isShiftDown() {
return shiftDown;
}
@Override
public void keyUp(int key) {
if(key == Keyboard.KEY_LSHIFT || key == Keyboard.KEY_RSHIFT) {
shiftDown = false;
btn.packedFGColour = originalColor;
}
}
@Override
public void keyDown(int key) {
if(key == Keyboard.KEY_LSHIFT || key == Keyboard.KEY_RSHIFT) {
shiftDown = true;
btn.packedFGColour = shiftColor;
}
}
public void setTextColor(int color) {
originalColor = color;
if(!shiftDown)
btn.packedFGColour = color;
}
public int getTextColor() {
return btn.packedFGColour;
}
public void setShiftTextColor(int shiftColor) {
this.shiftColor = shiftColor;
if(shiftDown)
btn.packedFGColour = shiftColor;
}
public int getShiftTextColor() {
return shiftColor;
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
btn.x = json.getInt("x", 0);
btn.y = json.getInt("y", 0);
btn.width = json.getInt("width", 200);
btn.displayString = tr(json.getString("label", btn.displayString));
btn.enabled = !json.getBool("disabled", !btn.enabled);
btn.visible = json.getBool("visible", btn.visible);
originalColor = json.getColor("color", originalColor);
shiftColor = json.getColor("shiftColor", shiftColor);
btn.packedFGColour = originalColor;
}
protected boolean onClick() {
return false;
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.init.SoundEvents;
import net.minecraft.util.ResourceLocation;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import java.util.Arrays;
public class CheckBox extends BasicControl {
private static final ResourceLocation texUnchecked = new ResourceLocation("webdisplays", "textures/gui/checkbox.png");
private static final ResourceLocation texChecked = new ResourceLocation("webdisplays", "textures/gui/checkbox_checked.png");
public static final int WIDTH = 16;
public static final int HEIGHT = 16;
public static class CheckedEvent extends Event<CheckBox> {
private final boolean checked;
private CheckedEvent(CheckBox cb) {
source = cb;
checked = cb.checked;
}
public boolean isChecked() {
return checked;
}
}
private String label;
private int labelW;
private boolean checked;
private java.util.List<String> tooltip;
public CheckBox() {
label = "";
}
public CheckBox(int x, int y, String label) {
this.label = label;
labelW = font.getStringWidth(label);
checked = false;
this.x = x;
this.y = y;
}
public CheckBox(int x, int y, String label, boolean val) {
this.label = label;
labelW = font.getStringWidth(label);
checked = val;
this.x = x;
this.y = y;
}
@Override
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
if(mouseButton == 0 && !disabled) {
if(mouseX >= x && mouseX <= x + WIDTH + 2 + labelW && mouseY >= y && mouseY < y + HEIGHT) {
checked = !checked;
mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(SoundEvents.UI_BUTTON_CLICK, 1.0F));
parent.actionPerformed(new CheckedEvent(this));
}
}
}
@Override
public void draw(int mouseX, int mouseY, float ptt) {
if(visible) {
GlStateManager.disableAlpha();
bindTexture(checked ? texChecked : texUnchecked);
blend(true);
fillTexturedRect(x, y, WIDTH, HEIGHT, 0.0, 0.0, 1.0, 1.0);
blend(false);
bindTexture(null);
boolean inside = (!disabled && mouseX >= x && mouseX <= x + WIDTH + 2 + labelW && mouseY >= y && mouseY < y + HEIGHT);
font.drawString(label, x + WIDTH + 2, y + 4, inside ? 0xFF0080FF : COLOR_WHITE);
}
}
public void setLabel(String label) {
this.label = label;
labelW = font.getStringWidth(label);
}
public String getLabel() {
return label;
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
@Override
public int getWidth() {
return WIDTH + 2 + labelW;
}
@Override
public int getHeight() {
return HEIGHT;
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
label = tr(json.getString("label", ""));
labelW = font.getStringWidth(label);
checked = json.getBool("checked", false);
String tt = tr(json.getString("tooltip", ""));
if(!tt.isEmpty()) {
tooltip = Arrays.asList(tt.split("\\\\n"));
parent.requirePostDraw(this);
}
}
@Override
public void postDraw(int mouseX, int mouseY, float ptt) {
if(tooltip != null && !disabled && mouseX >= x && mouseX <= x + WIDTH + 2 + labelW && mouseY >= y && mouseY < y + HEIGHT)
parent.drawTooltip(tooltip, mouseX, mouseY);
}
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.montoyo.wd.client.gui.loading.GuiLoader;
import net.montoyo.wd.client.gui.loading.JsonAWrapper;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import org.lwjgl.opengl.GL11;
import java.io.IOException;
import java.util.ArrayList;
public abstract class Container extends BasicControl {
protected int paddingX = 0;
protected int paddingY = 0;
protected final ArrayList<Control> childs = new ArrayList<>();
public <T extends Control> T addControl(T ctrl) {
childs.add(ctrl);
return ctrl;
}
@Override
public void keyTyped(char typedChar, int keyCode) throws IOException {
if(!disabled) {
for(Control ctrl : childs)
ctrl.keyTyped(typedChar, keyCode);
}
}
@Override
public void keyUp(int key) {
if(!disabled) {
for(Control ctrl : childs)
ctrl.keyUp(key);
}
}
@Override
public void keyDown(int key) {
if(!disabled) {
for(Control ctrl : childs)
ctrl.keyDown(key);
}
}
@Override
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
if(!disabled) {
mouseX -= x + paddingX;
mouseY -= y + paddingY;
for(Control ctrl : childs)
ctrl.mouseClicked(mouseX, mouseY, mouseButton);
}
}
@Override
public void mouseReleased(int mouseX, int mouseY, int state) {
if(!disabled) {
mouseX -= x + paddingX;
mouseY -= y + paddingY;
for(Control ctrl : childs)
ctrl.mouseReleased(mouseX, mouseY, state);
}
}
@Override
public void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
if(!disabled) {
mouseX -= x + paddingX;
mouseY -= y + paddingY;
for(Control ctrl : childs)
ctrl.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick);
}
}
@Override
public void mouseMove(int mouseX, int mouseY) {
if(!disabled) {
mouseX -= x + paddingX;
mouseY -= y + paddingY;
for(Control ctrl : childs)
ctrl.mouseMove(mouseX, mouseY);
}
}
@Override
public void mouseScroll(int mouseX, int mouseY, int amount) {
if(!disabled) {
mouseX -= x + paddingX;
mouseY -= y + paddingY;
for(Control ctrl : childs)
ctrl.mouseScroll(mouseX, mouseY, amount);
}
}
@Override
public void draw(int mouseX, int mouseY, float ptt) {
if(visible) {
mouseX -= x + paddingX;
mouseY -= y + paddingY;
GL11.glPushMatrix();
GL11.glTranslated((double) (x + paddingX), (double) (y + paddingY), 0.0);
if(disabled) {
for(Control ctrl : childs)
ctrl.draw(-1, -1, ptt);
} else {
for(Control ctrl : childs)
ctrl.draw(mouseX, mouseY, ptt);
}
GL11.glPopMatrix();
}
}
@Override
public void destroy() {
for(Control ctrl : childs)
ctrl.destroy();
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
JsonAWrapper objs = json.getArray("childs");
for(int i = 0; i < objs.size(); i++)
childs.add(GuiLoader.create(objs.getObject(i)));
}
public Control getByName(String name) {
for(Control ctrl : childs) {
if(name.equals(ctrl.name))
return ctrl;
if(ctrl instanceof Container) {
Control ret = ((Container) ctrl).getByName(name);
if(ret != null)
return ret;
}
}
return null;
}
}

View File

@@ -0,0 +1,282 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.shader.Framebuffer;
import net.minecraft.util.ResourceLocation;
import net.montoyo.wd.client.gui.WDScreen;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import net.montoyo.wd.utilities.Bounds;
import java.io.IOException;
import static org.lwjgl.opengl.GL11.*;
public abstract class Control {
public static final int COLOR_BLACK = 0xFF000000;
public static final int COLOR_WHITE = 0xFFFFFFFF;
public static final int COLOR_RED = 0xFFFF0000;
public static final int COLOR_GREEN = 0xFF00FF00;
public static final int COLOR_BLUE = 0xFF0000FF;
public static final int COLOR_CYAN = 0xFF00FFFF;
public static final int COLOR_MANGENTA = 0xFFFF00FF;
public static final int COLOR_YELLOW = 0xFFFFFF00;
protected final Minecraft mc;
protected final FontRenderer font;
protected final Tessellator tessellator;
protected final BufferBuilder vBuffer;
protected final WDScreen parent;
protected String name;
protected Object userdata;
public Control() {
mc = Minecraft.getMinecraft();
font = mc.fontRenderer;
tessellator = Tessellator.getInstance();
vBuffer = tessellator.getBuffer();
parent = WDScreen.CURRENT_SCREEN;
}
public Object getUserdata() {
return userdata;
}
public void setUserdata(Object userdata) {
this.userdata = userdata;
}
public void keyTyped(char typedChar, int keyCode) throws IOException {
}
public void keyUp(int key) {
}
public void keyDown(int key) {
}
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
}
public void mouseReleased(int mouseX, int mouseY, int state) {
}
public void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
}
public void mouseMove(int mouseX, int mouseY) {
}
public void mouseScroll(int mouseX, int mouseY, int amount) {
}
public void draw(int mouseX, int mouseY, float ptt) {
}
public void postDraw(int mouseX, int mouseY, float ptt) {
}
public void destroy() {
}
public WDScreen getParent() {
return parent;
}
public abstract int getX();
public abstract int getY();
public abstract int getWidth();
public abstract int getHeight();
public abstract void setPos(int x, int y);
public void fillRect(int x, int y, int w, int h, int color) {
double x1 = (double) x;
double y1 = (double) y;
double x2 = (double) (x + w);
double y2 = (double) (y + h);
int a = (color >> 24) & 0xFF;
int r = (color >> 16) & 0xFF;
int g = (color >> 8 ) & 0xFF;
int b = color & 0xFF;
glColor4f(((float) r) / 255.f, ((float) g) / 255.f, ((float) b) / 255.f, ((float) a) / 255.f);
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
vBuffer.begin(GL_QUADS, DefaultVertexFormats.POSITION);
vBuffer.pos(x1, y2, 0.0).endVertex();
vBuffer.pos(x2, y2, 0.0).endVertex();
vBuffer.pos(x2, y1, 0.0).endVertex();
vBuffer.pos(x1, y1, 0.0).endVertex();
tessellator.draw();
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
}
public void fillTexturedRect(int x, int y, int w, int h, double u1, double v1, double u2, double v2) {
double x1 = (double) x;
double y1 = (double) y;
double x2 = (double) (x + w);
double y2 = (double) (y + h);
vBuffer.begin(GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
vBuffer.pos(x1, y2, 0.0).tex(u1, v2).color(255, 255, 255, 255).endVertex();
vBuffer.pos(x2, y2, 0.0).tex(u2, v2).color(255, 255, 255, 255).endVertex();
vBuffer.pos(x2, y1, 0.0).tex(u2, v1).color(255, 255, 255, 255).endVertex();
vBuffer.pos(x1, y1, 0.0).tex(u1, v1).color(255, 255, 255, 255).endVertex();
tessellator.draw();
}
public static void blend(boolean enable) {
if(enable) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} else
glDisable(GL_BLEND);
}
public void bindTexture(ResourceLocation resLoc) {
if(resLoc == null)
GlStateManager.bindTexture(0); //Damn state manager
else
mc.renderEngine.bindTexture(resLoc);
}
public void drawBorder(int x, int y, int w, int h, int color) {
drawBorder(x, y, w, h, color, 1.0);
}
public void drawBorder(int x, int y, int w, int h, int color, double sz) {
double x1 = (double) x;
double y1 = (double) y;
double x2 = (double) (x + w);
double y2 = (double) (y + h);
int a = (color >> 24) & 0xFF;
int r = (color >> 16) & 0xFF;
int g = (color >> 8 ) & 0xFF;
int b = color & 0xFF;
glColor4f(((float) r) / 255.f, ((float) g) / 255.f, ((float) b) / 255.f, ((float) a) / 255.f);
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
vBuffer.begin(GL_QUADS, DefaultVertexFormats.POSITION);
//Top edge (y = y1)
vBuffer.pos(x1, y1 + sz, 0.0).endVertex();
vBuffer.pos(x2, y1 + sz, 0.0).endVertex();
vBuffer.pos(x2, y1, 0.0).endVertex();
vBuffer.pos(x1, y1, 0.0).endVertex();
//Bottom edge (y = y2)
vBuffer.pos(x1, y2, 0.0).endVertex();
vBuffer.pos(x2, y2, 0.0).endVertex();
vBuffer.pos(x2, y2 - sz, 0.0).endVertex();
vBuffer.pos(x1, y2 - sz, 0.0).endVertex();
//Left edge (x = x1)
vBuffer.pos(x1, y2, 0.0).endVertex();
vBuffer.pos(x1 + sz, y2, 0.0).endVertex();
vBuffer.pos(x1 + sz, y1, 0.0).endVertex();
vBuffer.pos(x1, y1, 0.0).endVertex();
//Right edge (x = x2)
vBuffer.pos(x2 - sz, y2, 0.0).endVertex();
vBuffer.pos(x2, y2, 0.0).endVertex();
vBuffer.pos(x2, y1, 0.0).endVertex();
vBuffer.pos(x2 - sz, y1, 0.0).endVertex();
tessellator.draw();
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
}
public void beginFramebuffer(Framebuffer fbo, int vpW, int vpH) {
fbo.bindFramebuffer(true);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, (double) vpW, (double) vpH, 0.0, -1.0,1.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
if(!fbo.useDepth)
glDisable(GL_DEPTH_TEST);
}
public void endFramebuffer(Framebuffer fbo) {
if(!fbo.useDepth)
glEnable(GL_DEPTH_TEST);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
fbo.unbindFramebuffer();
mc.getFramebuffer().bindFramebuffer(true);
}
public static String tr(String text) {
if(text.length() >= 2 && text.charAt(0) == '$') {
if(text.charAt(1) == '$')
return text.substring(1);
else
return I18n.format(text.substring(1));
} else
return text;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void load(JsonOWrapper json) {
name = json.getString("name", "");
}
public static Bounds findBounds(java.util.List<Control> controlList) {
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int maxY = Integer.MIN_VALUE;
for(Control ctrl : controlList) {
int x = ctrl.getX();
int y = ctrl.getY();
if(x < minX)
minX = x;
if(y < minY)
minY = y;
x += ctrl.getWidth();
y += ctrl.getHeight();
if(x > maxX)
maxX = x;
if(y >= maxY)
maxY = y;
}
return new Bounds(minX, minY, maxX, maxY);
}
}

View File

@@ -0,0 +1,187 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import net.montoyo.wd.utilities.Bounds;
import static org.lwjgl.opengl.GL11.*;
public class ControlGroup extends Container {
private int width;
private int height;
private String label;
private int labelW;
private int labelColor = COLOR_WHITE;
private boolean labelShadowed = true;
public ControlGroup() {
width = 100;
height = 100;
label = "";
paddingX = 8;
paddingY = 8;
}
public ControlGroup(int x, int y, int w, int h) {
this.x = x;
this.y = y;
width = w;
height = h;
paddingX = 8;
paddingY = 8;
label = "";
labelW = 0;
}
public ControlGroup(int x, int y, int w, int h, String label) {
this.x = x;
this.y = y;
width = w;
height = h;
this.label = label;
this.labelW = font.getStringWidth(label);
paddingX = 8;
paddingY = 8;
}
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
public void setSize(int w, int h) {
width = w;
height = h;
}
public void setLabel(String label) {
this.label = label;
labelW = font.getStringWidth(label);
}
public String getLabel() {
return label;
}
public int getLabelColor() {
return labelColor;
}
public void setLabelColor(int labelColor) {
this.labelColor = labelColor;
}
public boolean isLabelShadowed() {
return labelShadowed;
}
public void setLabelShadowed(boolean labelShadowed) {
this.labelShadowed = labelShadowed;
}
@Override
public void draw(int mouseX, int mouseY, float ptt) {
super.draw(mouseX, mouseY, ptt);
if(visible) {
glColor4f(0.5f, 0.5f, 0.5f, 1.f);
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
double x1 = (double) x;
double y1 = (double) y;
double x2 = (double) (x + width);
double y2 = (double) (y + height);
double bp = 4.0;
double lw = (double) labelW;
x1 += bp;
y1 += bp;
x2 -= bp;
y2 -= bp;
lw += 12.0;
vBuffer.begin(GL_QUADS, DefaultVertexFormats.POSITION);
//Top edge (y = y1)
if(labelW == 0) {
vBuffer.pos(x1, y1 + 1.0, 0.0).endVertex();
vBuffer.pos(x2, y1 + 1.0, 0.0).endVertex();
vBuffer.pos(x2, y1, 0.0).endVertex();
vBuffer.pos(x1, y1, 0.0).endVertex();
} else {
//Left
vBuffer.pos(x1, y1 + 1.0, 0.0).endVertex();
vBuffer.pos(x1 + 8.0, y1 + 1.0, 0.0).endVertex();
vBuffer.pos(x1 + 8.0, y1, 0.0).endVertex();
vBuffer.pos(x1, y1, 0.0).endVertex();
//Right
vBuffer.pos(x1 + lw, y1 + 1.0, 0.0).endVertex();
vBuffer.pos(x2, y1 + 1.0, 0.0).endVertex();
vBuffer.pos(x2, y1, 0.0).endVertex();
vBuffer.pos(x1 + lw, y1, 0.0).endVertex();
}
//Bottom edge (y = y2)
vBuffer.pos(x1, y2, 0.0).endVertex();
vBuffer.pos(x2, y2, 0.0).endVertex();
vBuffer.pos(x2, y2 - 1.0, 0.0).endVertex();
vBuffer.pos(x1, y2 - 1.0, 0.0).endVertex();
//Left edge (x = x1)
vBuffer.pos(x1, y2, 0.0).endVertex();
vBuffer.pos(x1 + 1.0, y2, 0.0).endVertex();
vBuffer.pos(x1 + 1.0, y1, 0.0).endVertex();
vBuffer.pos(x1, y1, 0.0).endVertex();
//Right edge (x = x2)
vBuffer.pos(x2 - 1.0, y2, 0.0).endVertex();
vBuffer.pos(x2, y2, 0.0).endVertex();
vBuffer.pos(x2, y1, 0.0).endVertex();
vBuffer.pos(x2 - 1.0, y1, 0.0).endVertex();
tessellator.draw();
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
if(labelW != 0)
font.drawString(label, x + 10 + ((int) bp), y, labelColor, labelShadowed);
}
}
public void pack() {
Bounds bounds = findBounds(childs);
for(Control ctrl : childs)
ctrl.setPos(ctrl.getX() - bounds.minX, ctrl.getY() - bounds.minY);
width = bounds.getWidth() + paddingX * 2;
height = bounds.getHeight() + paddingY * 2;
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
width = json.getInt("width", 100);
height = json.getInt("height", 100);
label = tr(json.getString("label", ""));
labelW = font.getStringWidth(label);
labelColor = json.getColor("labelColor", COLOR_WHITE);
labelShadowed = json.getBool("labelShadowed", true);
if(json.getBool("pack", false))
pack();
}
}

View File

@@ -0,0 +1,15 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
public abstract class Event<T extends Control> {
protected T source;
public T getSource() {
return source;
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.minecraft.util.ResourceLocation;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import org.lwjgl.opengl.GL11;
public class Icon extends BasicControl {
protected int width;
protected int height;
protected double u1;
protected double v1;
protected double u2;
protected double v2;
protected ResourceLocation texture;
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
width = json.getInt("width", 16);
height = json.getInt("height", 16);
u1 = json.getDouble("u1", 0.0);
v1 = json.getDouble("v1", 0.0);
u2 = json.getDouble("u2", 1.0);
v2 = json.getDouble("v2", 1.0);
texture = new ResourceLocation(json.getString("resourceLocation", ""));
}
@Override
public void draw(int mouseX, int mouseY, float ptt) {
if(texture != null) {
GL11.glEnable(GL11.GL_TEXTURE_2D);
bindTexture(texture);
blend(true);
fillTexturedRect(x, y, width, height, u1, v1, u2, v2);
blend(false);
bindTexture(null);
}
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public void setTextureCoordinates(double u1, double v1, double u2, double v2) {
this.u1 = u1;
this.v1 = v1;
this.u2 = u2;
this.v2 = v2;
}
public void setTexture(ResourceLocation texture) {
this.texture = texture;
}
public double getU1() {
return u1;
}
public double getV1() {
return v1;
}
public double getU2() {
return u2;
}
public double getV2() {
return v2;
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
public class Label extends BasicControl {
private String label;
private int labelW;
private int color;
private boolean shadowed;
public Label() {
label = "";
color = COLOR_WHITE;
}
public Label(int x, int y, String str) {
this.x = x;
this.y = y;
label = str;
labelW = font.getStringWidth(str);
color = COLOR_WHITE;
shadowed = false;
}
public Label(int x, int y, String str, int color) {
this.x = x;
this.y = y;
label = str;
labelW = font.getStringWidth(str);
this.color = color;
shadowed = false;
}
public Label(int x, int y, String str, int color, boolean shadowed) {
this.x = x;
this.y = y;
label = str;
labelW = font.getStringWidth(str);
this.color = color;
this.shadowed = shadowed;
}
public void setLabel(String label) {
this.label = label;
labelW = font.getStringWidth(label);
}
public String getLabel() {
return label;
}
public void setColor(int color) {
this.color = color;
}
public int getColor() {
return color;
}
public void setShadowed(boolean shadowed) {
this.shadowed = shadowed;
}
public boolean isShadowed() {
return shadowed;
}
@Override
public void draw(int mouseX, int mouseY, float ptt) {
if(visible)
font.drawString(label, x, y, color, shadowed);
}
@Override
public int getWidth() {
return labelW;
}
@Override
public int getHeight() {
return 12;
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
label = tr(json.getString("label", ""));
labelW = font.getStringWidth(label);
color = json.getColor("color", COLOR_WHITE);
shadowed = json.getBool("shadowed", false);
}
}

View File

@@ -0,0 +1,383 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.minecraft.client.shader.Framebuffer;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import java.util.ArrayList;
import static org.lwjgl.opengl.GL11.*;
public class List extends BasicControl {
private static class Entry {
public final String text;
public final Object userdata;
public Entry(String t, Object o) {
text = t;
userdata = o;
}
}
public static class EntryClick extends Event<List> {
private final int id;
private final Entry entry;
private EntryClick(List lst) {
source = lst;
id = lst.selected;
entry = lst.content.get(lst.selected);
}
public int getId() {
return id;
}
public String getLabel() {
return entry.text;
}
public Object getUserdata() {
return entry.userdata;
}
}
private int width;
private int height;
private final ArrayList<Entry> content = new ArrayList<>();
private Framebuffer fbo;
private int selected = -1;
private boolean update;
private int selColor = 0xFF0080FF;
//Scroll handling
private int contentH = 0;
private int scrollSize;
private int scrollPos = 0;
private boolean scrolling = false;
private int scrollGrab;
public List() {
}
public List(int x, int y, int w, int h) {
this.x = x;
this.y = y;
width = w;
height = h;
scrollSize = h - 2;
createFBO();
}
private int getYOffset() {
double amount = ((double) scrollPos) / ((double) (height - 2 - scrollSize)) * ((double) (contentH - height));
return (int) amount;
}
private boolean isInScrollbar(int mouseX, int mouseY) {
return mouseX >= x + width - 5 && mouseX <= x + width - 1 && mouseY >= y + 1 + scrollPos && mouseY <= y + 1 + scrollPos + scrollSize;
}
private void createFBO() {
if(fbo != null)
fbo.deleteFramebuffer();
fbo = new Framebuffer(parent.screen2DisplayX(width), parent.screen2DisplayY(height), false);
fbo.setFramebufferFilter(GL_NEAREST);
fbo.bindFramebuffer(false);
glClearColor(0.0f, 0.0f, 0.0f, 1.f); //Set alpha to 1
glClear(GL_COLOR_BUFFER_BIT);
fbo.unbindFramebuffer();
update = true;
}
private void renderToFBO() {
beginFramebuffer(fbo, width, height);
fillRect(0, 0, width, height, COLOR_BLACK);
glColor4f(1.f, 1.f, 1.f, 1.f);
int offset = 4 - getYOffset();
for(int i = 0; i < content.size(); i++) {
int pos = i * 12 + offset;
if(pos + 12 >= 1) {
if(pos >= height - 1)
break;
int color = (i == selected) ? selColor : COLOR_WHITE;
font.drawString(content.get(i).text, 4, i * 12 + offset, color);
}
}
drawBorder(0, 0, width, height, 0xFF808080);
endFramebuffer(fbo);
}
@Override
public void destroy() {
if(fbo != null)
fbo.deleteFramebuffer();
}
public void setSize(int w, int h) {
width = w;
height = h;
createFBO();
}
public void setWidth(int width) {
this.width = width;
createFBO();
}
public void setHeight(int height) {
this.height = height;
createFBO();
}
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
public void updateContent() {
contentH = content.size() * 12 + 4;
int h2 = height - 2;
if(contentH <= h2) {
scrollSize = h2;
scrollPos = 0;
} else {
scrollSize = h2 * h2 / contentH;
if(scrollSize < 4)
scrollSize = 4;
}
update = true;
}
public int addElement(String str) {
return addElement(str, null);
}
public int addElement(String str, Object ud) {
content.add(new Entry(str, ud));
updateContent();
return content.size() - 1;
}
public int addElementRaw(String str) {
return addElement(str, null);
}
public int addElementRaw(String str, Object ud) {
content.add(new Entry(str, ud));
return content.size() - 1;
}
@Override
public void setDisabled(boolean dis) {
disabled = dis;
if(dis) {
selected = -1;
update = true;
}
}
@Override
public void disable() {
disabled = true;
selected = -1;
update = true;
}
@Override
public void mouseMove(int mouseX, int mouseY) {
int sel = -1;
if(!disabled && mouseX >= x + 1 && mouseX <= x + width - 6 && mouseY >= y + 2 && mouseY <= y + height - 2) {
int offset = y + 4 - getYOffset();
sel = (mouseY - offset) / 12;
if(sel < 0 || sel >= content.size())
sel = -1;
}
if(selected != sel) {
selected = sel;
update = true;
}
}
@Override
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
if(!disabled && mouseButton == 0) {
if(isInScrollbar(mouseX, mouseY)) {
scrolling = true;
scrollGrab = mouseY - (y + 1 + scrollPos);
} else if(selected >= 0)
parent.actionPerformed(new EntryClick(this));
}
}
@Override
public void mouseReleased(int mouseX, int mouseY, int state) {
if(!disabled && scrolling)
scrolling = false;
}
@Override
public void mouseScroll(int mouseX, int mouseY, int amount) {
if(!disabled && !scrolling && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height) {
double disp = 12.d * ((double) (height - 2 - scrollSize)) / ((double) (contentH - height));
int sp = scrollPos;
if(amount < 0)
sp += (int) disp;
else
sp -= (int) disp;
if(sp < 0)
sp = 0;
else if(sp > height - 2 - scrollSize)
sp = height - 2 - scrollSize;
if(sp != scrollPos) {
scrollPos = sp;
update = true;
}
}
}
@Override
public void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
if(!disabled && scrolling) {
int sp = mouseY - scrollGrab - y - 1;
if(sp < 0)
sp = 0;
else if(sp > height - 2 - scrollSize)
sp = height - 2 - scrollSize;
if(scrollPos != sp) {
scrollPos = sp;
update = true;
}
}
}
@Override
public void draw(int mouseX, int mouseY, float ptt) {
if(visible) {
if(update) {
renderToFBO();
update = false;
}
fbo.bindFramebufferTexture();
glColor4f(1.f, 1.f, 1.f, 1.f);
fillTexturedRect(x, y, width, height, 0.0, 1.0, 1.0, 0.0);
fbo.unbindFramebufferTexture();
fillRect(x + width - 5, y + 1 + scrollPos, 4, scrollSize, (scrolling || isInScrollbar(mouseX, mouseY)) ? 0xFF202020 : 0xFF404040);
}
}
public String getEntryLabel(int id) {
return content.get(id).text;
}
public Object getEntryUserdata(int id) {
return content.get(id).userdata;
}
public int findEntryByLabel(String label) {
for(int i = 0; i < content.size(); i++) {
if(content.get(i).text.equals(label))
return i;
}
return -1;
}
public int findEntryByUserdata(Object o) {
if(o == null) {
for(int i = 0; i < content.size(); i++) {
if(content.get(i).userdata == null)
return i;
}
} else {
for(int i = 0; i < content.size(); i++) {
if(content.get(i).userdata != null && content.get(i).userdata.equals(o))
return i;
}
}
return -1;
}
public void setSelectionColor(int selColor) {
this.selColor = selColor;
}
public int getSelectionColor() {
return selColor;
}
public int getElementCount() {
return content.size();
}
public void removeElement(int id) {
if(selected != -1 && id == content.size() - 1)
selected = -1;
content.remove(id);
updateContent();
}
public void removeElementRaw(int id) {
if(selected != -1 && id == content.size() - 1)
selected = -1;
content.remove(id);
}
public void clear() {
content.clear();
scrollPos = 0;
scrolling = false;
scrollSize = height - 2;
selected = -1;
update = true;
}
public void clearRaw() {
content.clear();
scrollPos = 0;
scrolling = false;
selected = -1;
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
width = json.getInt("width", 100);
height = json.getInt("height", 100);
selColor = json.getColor("selectionColor", 0xFF0080FF);
createFBO();
}
}

View File

@@ -0,0 +1,307 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.minecraft.client.gui.GuiTextField;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import org.lwjgl.input.Keyboard;
import java.util.ArrayList;
public class TextField extends Control {
public static class EnterPressedEvent extends Event<TextField> {
private final String text;
private EnterPressedEvent(TextField field) {
source = field;
text = field.field.getText();
}
public String getText() {
return text;
}
}
public static class TabPressedEvent extends Event<TextField> {
private final String beginning;
private TabPressedEvent(TextField field) {
source = field;
String text = field.field.getText();
int max = field.field.getCursorPosition();
int spacePos = 0;
for(int i = max - 1; i >= 0; i--) {
if(Character.isSpaceChar(text.charAt(i))) {
spacePos = i;
break;
}
}
beginning = text.substring(spacePos, max).trim();
}
public String getBeginning() {
return beginning;
}
}
public static class TextChangedEvent extends Event<TextField> {
private final String oldContent;
private final String newContent;
private TextChangedEvent(TextField tf, String old) {
source = tf;
oldContent = old;
newContent = tf.field.getText();
}
public String getOldContent() {
return oldContent;
}
public String getNewContent() {
return newContent;
}
}
public interface TextChangeListener {
void onTextChange(TextField tf, String oldContent, String newContent);
}
public static final int DEFAULT_TEXT_COLOR = 14737632;
public static final int DEFAULT_DISABLED_COLOR = 7368816;
private final GuiTextField field;
private boolean enabled = true;
private int textColor = DEFAULT_TEXT_COLOR;
private int disabledColor = DEFAULT_DISABLED_COLOR;
private final ArrayList<TextChangeListener> listeners = new ArrayList<>();
public TextField() {
field = new GuiTextField(0, font, 1, 1, 198, 20);
}
public TextField(int x, int y, int width, int height) {
field = new GuiTextField(0, font, x + 1, y + 1, width - 2, height - 2);
}
public TextField(int x, int y, int width, int height, String text) {
field = new GuiTextField(0, font, x + 1, y + 1, width - 2, height - 2);
field.setText(text);
}
@Override
public void keyTyped(char typedChar, int keyCode) {
if(keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER)
parent.actionPerformed(new EnterPressedEvent(this));
else if(keyCode == Keyboard.KEY_TAB)
parent.actionPerformed(new TabPressedEvent(this));
else {
String old;
if(enabled && field.isFocused())
old = field.getText();
else
old = null;
field.textboxKeyTyped(typedChar, keyCode);
if(enabled && field.isFocused() && !field.getText().equals(old)) {
for(TextChangeListener tcl : listeners)
tcl.onTextChange(this, old, field.getText());
parent.actionPerformed(new TextChangedEvent(this, old));
}
}
}
@Override
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
field.mouseClicked(mouseX, mouseY, mouseButton);
}
@Override
public void draw(int mouseX, int mouseY, float ptt) {
field.drawTextBox();
}
public void setText(String text) {
String old = field.getText();
field.setText(text);
if(!old.equals(text)) {
for(TextChangeListener tcl : listeners)
tcl.onTextChange(this, old, text);
}
}
public void clear() {
field.setText("");
}
public String getText() {
return field.getText();
}
public String getSelectedText() {
return field.getSelectedText();
}
public void setWidth(int width) {
field.width = width - 2;
}
@Override
public int getWidth() {
return field.width + 2;
}
public void setHeight(int height) {
field.height = height - 2;
}
@Override
public int getHeight() {
return field.height + 2;
}
public void setSize(int w, int h) {
field.width = w - 2;
field.height = h - 2;
}
@Override
public void setPos(int x, int y) {
field.x = x + 1;
field.y = y + 1;
}
@Override
public int getX() {
return field.x - 1;
}
@Override
public int getY() {
return field.y - 1;
}
public void setDisabled(boolean en) {
enabled = !en;
field.setEnabled(enabled);
}
public boolean isDisabled() {
return !enabled;
}
public void enable() {
field.setEnabled(true);
enabled = true;
}
public void disable() {
field.setEnabled(false);
enabled = false;
}
public void setVisible(boolean vi) {
field.setVisible(vi);
}
public boolean isVisible() {
return field.getVisible();
}
public void show() {
field.setVisible(true);
}
public void hide() {
field.setVisible(false);
}
public void setFocused(boolean val) {
field.setFocused(val);
}
public boolean hasFocus() {
return field.isFocused();
}
public void focus() {
field.setFocused(true);
}
public void setMaxLength(int len) {
field.setMaxStringLength(len);
}
public int getMaxLength() {
return field.getMaxStringLength();
}
public void setTextColor(int color) {
field.setTextColor(color);
textColor = color;
}
public int getTextColor() {
return textColor;
}
public void setDisabledTextColor(int color) {
field.setDisabledTextColour(color);
disabledColor = color;
}
public int getDisabledTextColor() {
return disabledColor;
}
public GuiTextField getMcField() {
return field;
}
public void addTextChangeListener(TextChangeListener l) {
if(l != null && !listeners.contains(l))
listeners.add(l);
}
public void removeTextChangeListener(TextChangeListener l) {
listeners.remove(l);
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
field.x = json.getInt("x", 0) + 1;
field.y = json.getInt("y", 0) + 1;
field.width = json.getInt("width", 200) - 2;
field.height = json.getInt("height", 22) - 2;
field.setText(tr(json.getString("text", "")));
field.setVisible(json.getBool("visible", true));
field.setMaxStringLength(json.getInt("maxLength", 32));
enabled = !json.getBool("disabled", false);
textColor = json.getColor("textColor", DEFAULT_TEXT_COLOR);
disabledColor = json.getColor("disabledColor", DEFAULT_DISABLED_COLOR);
field.setTextColor(textColor);
field.setDisabledTextColour(disabledColor);
field.setEnabled(enabled);
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderItem;
import net.minecraft.item.ItemStack;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import java.util.ArrayList;
public class UpgradeGroup extends BasicControl {
private int width;
private int height;
private ArrayList<ItemStack> upgrades;
private ItemStack overStack;
private ItemStack clickStack;
private final RenderItem renderItem = Minecraft.getMinecraft().getRenderItem();
public UpgradeGroup() {
parent.requirePostDraw(this);
}
@Override
public void draw(int mouseX, int mouseY, float ptt) {
if(upgrades != null) {
int x = this.x;
for(ItemStack is: upgrades) {
if(is == overStack && !disabled)
fillRect(x, y, 16, 16, 0x80FF0000);
renderItem.renderItemAndEffectIntoGUI(mc.player, is, x, y);
renderItem.renderItemOverlayIntoGUI(font, is, x, y, null);
x += 18;
}
}
}
@Override
public void postDraw(int mouseX, int mouseY, float ptt) {
if(overStack != null)
parent.drawItemStackTooltip(overStack, mouseX, mouseY);
}
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
public void setWidth(int w) {
width = w;
}
public void setHeight(int h) {
height = h;
}
public void setUpgrades(ArrayList<ItemStack> upgrades) {
this.upgrades = upgrades;
}
public ArrayList<ItemStack> getUpgrades() {
return upgrades;
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
width = json.getInt("width", 0);
height = json.getInt("height", 16);
}
@Override
public void mouseMove(int mouseX, int mouseY) {
if(upgrades != null) {
overStack = null;
if(mouseY >= y && mouseY <= y + 16 && mouseX >= x) {
mouseX -= x;
int sel = mouseX / 18;
if(sel < upgrades.size() && mouseX % 18 <= 16)
overStack = upgrades.get(sel);
}
}
}
@Override
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
if(mouseButton == 0)
clickStack = overStack;
}
@Override
public void mouseReleased(int mouseX, int mouseY, int state) {
if(state == 0 && clickStack != null) {
if(clickStack == overStack && !disabled && upgrades.contains(clickStack)) //HOTFIX: Make sure it's actually in the list :p
parent.actionPerformed(new ClickEvent(this));
clickStack = null;
}
}
public ItemStack getMouseOverUpgrade() {
return overStack;
}
public static class ClickEvent extends Event<UpgradeGroup> {
private final ItemStack clickStack;
private ClickEvent(UpgradeGroup src) {
source = src;
clickStack = src.clickStack;
}
public ItemStack getMouseOverStack() {
return clickStack;
}
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import net.montoyo.wd.utilities.Util;
import net.montoyo.wd.utilities.VideoType;
import java.net.MalformedURLException;
import java.net.URL;
public class YTButton extends Button implements TextField.TextChangeListener {
private TextField urlField;
public YTButton() {
btn.displayString = "YT";
btn.enabled = false;
shiftColor = 0xFFFF6464;
}
@Override
protected boolean onClick() {
if(urlField != null) {
String urlStr = Util.addProtocol(urlField.getText());
URL url;
try {
url = new URL(urlStr);
} catch(MalformedURLException ex) {
return true;
}
VideoType vt = VideoType.getTypeFromURL(url);
if(vt == VideoType.YOUTUBE)
urlField.setText(VideoType.YOUTUBE_EMBED.getURLFromID(vt.getVideoIDFromURL(url), shiftDown));
}
return true;
}
public void setURLField(TextField tf) {
if(urlField != null)
tf.removeTextChangeListener(this);
urlField = tf;
if(urlField != null)
tf.addTextChangeListener(this);
}
public TextField getURLField() {
return urlField;
}
@Override
public void load(JsonOWrapper json) {
super.load(json);
String tfName = json.getString("urlField", null);
if(tfName != null) {
Control ctrl = parent.getControlByName(tfName);
if(ctrl != null && ctrl instanceof TextField) {
urlField = (TextField) ctrl;
urlField.addTextChangeListener(this);
}
}
}
@Override
public void onTextChange(TextField tf, String oldContent, String newContent) {
btn.enabled = (VideoType.getTypeFromURL(Util.addProtocol(newContent)) == VideoType.YOUTUBE);
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.loading;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FillControl {
String name() default "";
boolean required() default true;
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.loading;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource;
import net.minecraft.util.ResourceLocation;
import net.montoyo.wd.client.gui.controls.*;
import net.montoyo.wd.utilities.Log;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Modifier;
import java.util.HashMap;
public class GuiLoader {
private static final HashMap<String, Class<? extends Control>> CONTROLS = new HashMap<>();
private static final HashMap<ResourceLocation, JsonObject> RESOURCES = new HashMap<>();
public static void register(Class<? extends Control> cls) {
if(Modifier.isAbstract(cls.getModifiers()))
throw new RuntimeException("GG retard, you just registered an abstract class...");
String name = cls.getSimpleName();
if(CONTROLS.containsKey(name))
throw new RuntimeException("Control class already registered or name taken!");
CONTROLS.put(name, cls);
}
static {
register(Button.class);
register(CheckBox.class);
register(ControlGroup.class);
register(Label.class);
register(List.class);
register(TextField.class);
register(Icon.class);
register(UpgradeGroup.class);
register(YTButton.class);
}
public static Control create(JsonOWrapper json) {
Control ret;
try {
ret = CONTROLS.get(json.getString("type", null)).newInstance();
} catch(InstantiationException e) {
Log.errorEx("Could not create control from JSON: instantiation exception", e);
throw new RuntimeException(e);
} catch(IllegalAccessException e) {
Log.errorEx("Could not create control from JSON: access denied", e);
throw new RuntimeException(e);
}
ret.load(json);
return ret;
}
public static JsonObject getJson(ResourceLocation resLoc) {
JsonObject ret = RESOURCES.get(resLoc);
if(ret == null) {
IResource resource;
try {
resource = Minecraft.getMinecraft().getResourceManager().getResource(resLoc);
} catch(IOException e) {
Log.errorEx("Couldn't load JSON UI from file", e);
throw new RuntimeException(e);
}
JsonParser parser = new JsonParser();
ret = parser.parse(new InputStreamReader(resource.getInputStream())).getAsJsonObject();
try {
resource.close();
} catch(IOException e) {}
RESOURCES.put(resLoc, ret);
}
return ret;
}
public static void clearCache() {
RESOURCES.clear();
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.loading;
import com.google.gson.JsonArray;
import java.util.Map;
public class JsonAWrapper {
private final JsonArray array;
private final Map<String, Double> variables;
public JsonAWrapper(JsonArray a, Map<String, Double> vars) {
array = a;
variables = vars;
}
public int size() {
return array.size();
}
public String getString(int i) {
return array.get(i).getAsString();
}
public int getInt(int i) {
return array.get(i).getAsInt();
}
public long getLong(int i) {
return array.get(i).getAsLong();
}
public float getFloat(int i) {
return array.get(i).getAsFloat();
}
public double getDouble(int i) {
return array.get(i).getAsDouble();
}
public boolean getBool(int i) {
return array.get(i).getAsBoolean();
}
public JsonOWrapper getObject(int i) {
return new JsonOWrapper(array.get(i).getAsJsonObject(), variables);
}
public JsonAWrapper getArray(int i) {
return new JsonAWrapper(array.get(i).getAsJsonArray(), variables);
}
public JsonArray getArray() {
return array;
}
}

View File

@@ -0,0 +1,311 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.loading;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import net.montoyo.wd.client.gui.controls.Control;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JsonOWrapper {
private static final HashMap<String, Integer> defaultColors = new HashMap<>();
static {
defaultColors.put("black", Control.COLOR_BLACK);
defaultColors.put("white", Control.COLOR_WHITE);
defaultColors.put("red", Control.COLOR_RED);
defaultColors.put("green", Control.COLOR_GREEN);
defaultColors.put("blue", Control.COLOR_BLUE);
defaultColors.put("magenta", Control.COLOR_MANGENTA);
defaultColors.put("cyan", Control.COLOR_CYAN);
defaultColors.put("yellow", Control.COLOR_YELLOW);
}
private final JsonObject object;
private final Map<String, Double> variables;
public JsonOWrapper(JsonObject obj, Map<String, Double> vars) {
object = obj;
variables = vars;
}
public String getString(String key, String def) {
return object.has(key) ? object.get(key).getAsString() : def;
}
public long getLong(String key, long def) {
return object.has(key) ? object.get(key).getAsLong() : def;
}
public int getInt(String key, int def) {
if(!object.has(key))
return def;
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
if(prim.isNumber())
return prim.getAsInt();
return (int) evalExpr(prim.getAsString(), variables);
}
public float getFloat(String key, float def) {
if(!object.has(key))
return def;
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
if(prim.isNumber())
return prim.getAsFloat();
return (float) evalExpr(prim.getAsString(), variables);
}
public double getDouble(String key, double def) {
if(!object.has(key))
return def;
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
if(prim.isNumber())
return prim.getAsDouble();
return evalExpr(prim.getAsString(), variables);
}
public boolean getBool(String key, boolean def) {
if(!object.has(key))
return def;
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
if(prim.isBoolean())
return prim.getAsBoolean();
else if(prim.isNumber())
return prim.getAsInt() != 0;
return evalExpr(prim.getAsString(), variables) != 0.0;
}
public JsonOWrapper getObject(String key) {
return new JsonOWrapper(object.has(key) ? object.get(key).getAsJsonObject() : (new JsonObject()), variables);
}
public JsonAWrapper getArray(String key) {
return new JsonAWrapper(object.has(key) ? object.get(key).getAsJsonArray() : (new JsonArray()), variables);
}
public JsonObject getObject() {
return object;
}
public int getColor(String key, int def) {
if(!object.has(key))
return def;
JsonElement c = object.get(key);
if(c.isJsonPrimitive()) {
JsonPrimitive prim = c.getAsJsonPrimitive();
if(prim.isNumber())
return (int) prim.getAsLong();
else if(prim.isString()) {
String str = prim.getAsString();
Integer dc = defaultColors.get(str.toLowerCase());
if(dc != null)
return dc;
if(!str.isEmpty() && str.charAt(0) == '#')
str = str.substring(1);
long ret = Long.parseLong(str, 16);
if(str.length() <= 6)
ret |= 0xFF000000L;
return (int) ret;
} else
return def;
}
int r, g, b, a;
if(c.isJsonArray()) {
JsonArray array = c.getAsJsonArray();
r = array.get(0).getAsInt();
g = array.get(1).getAsInt();
b = array.get(2).getAsInt();
a = (array.size() >= 4) ? array.get(3).getAsInt() : 255;
} else if(c.isJsonObject()) {
JsonObject obj = c.getAsJsonObject();
r = obj.get("r").getAsInt();
g = obj.get("g").getAsInt();
b = obj.get("b").getAsInt();
a = obj.has("a") ? obj.get("a").getAsInt() : 255;
} else
return def;
return (a << 24) | (r << 16) | (g << 8) | b;
}
private static final String OPS = "+*/%&|"; //The - sign is an exception, don't add it here
private static final String[] OPS_PRIORITY = new String[] { "*/%", "+-", "&|" };
private static class VarOpPair {
double var;
char op;
void setVar(String str, boolean isNumber, String expr, Map<String, Double> variables) {
if(isNumber)
var = Double.parseDouble(str);
else {
boolean neg = (str.charAt(0) == '-');
String varName = neg ? str.substring(1) : str;
Double d = variables.get(varName);
if(d == null)
throw new RuntimeException("Unknown variable \"" + varName + "\" in expression \"" + expr + "\"");
var = neg ? -d : d;
}
}
void setOp(char op) {
this.op = op;
}
}
private static int findPair(List<VarOpPair> list, String ops) {
for(int i = 0; i < list.size(); i++) {
if(ops.indexOf(list.get(i).op) >= 0)
return i;
}
return -1;
}
private static double evalExpr(String expr, Map<String, Double> variables) {
//Apply parenthesis
while(true) {
int pos = expr.indexOf('(');
if(pos < 0)
break;
int end = ++pos;
int lvl = 0;
for(; end < expr.length(); end++) {
char chr = expr.charAt(end);
if(chr == '(')
lvl++;
else if(chr == ')') {
if(lvl == 0)
break;
lvl--;
}
}
if(end >= expr.length())
throw new RuntimeException("Unclosed parenthesis in expression \"" + expr + "\"");
double val = evalExpr(expr.substring(pos, end), variables);
expr = expr.substring(0, pos - 1) + val + expr.substring(end + 1);
}
//Parse into ops
ArrayList<VarOpPair> ops = new ArrayList<>();
StringBuilder str = new StringBuilder();
boolean negIsPartOfStr = true;
boolean strIsNumber = true;
for(int i = 0; i < expr.length(); i++) {
char chr = expr.charAt(i);
if(Character.isSpaceChar(chr))
continue;
if((chr == '-' && !negIsPartOfStr) || OPS.indexOf(chr) >= 0) {
//Parse
VarOpPair pair = new VarOpPair();
pair.setVar(str.toString(), strIsNumber, expr, variables);
pair.setOp(chr);
ops.add(pair);
//Reset
str.setLength(0);
negIsPartOfStr = true;
strIsNumber = true;
} else {
if(strIsNumber && chr != '-' && chr != '.' && !Character.isDigit(chr))
strIsNumber = false;
if(negIsPartOfStr)
negIsPartOfStr = false;
str.append(chr);
}
}
if(str.length() > 0) {
VarOpPair pair = new VarOpPair();
pair.setVar(str.toString(), strIsNumber, expr, variables);
pair.setOp((char) 0);
ops.add(pair);
}
//Compute
while(true) {
int pairId = -1;
for(String opList : OPS_PRIORITY) {
pairId = findPair(ops, opList);
if(pairId >= 0)
break;
}
if(pairId < 0)
break;
VarOpPair a = ops.get(pairId);
VarOpPair b = ops.get(pairId + 1);
if(a.op == '*')
b.var = a.var * b.var;
else if(a.op == '/')
b.var = a.var / b.var;
else if(a.op == '%')
b.var = a.var % b.var;
else if(a.op == '+')
b.var = a.var + b.var;
else if(a.op == '-')
b.var = a.var - b.var;
else if(a.op == '&') {
if(a.var == 0.0)
b.var = 0.0;
//if b.var == 0, b.var stays 0
//if a.var != 0, b.var keeps its value
} else if(a.op == '|') {
if(a.var != 0.0)
b.var = a.var;
//if a.var == 0, b.var keeps its value
//if a.var != 0, b.var takes the value of a
}
ops.remove(pairId);
}
//Check
if(ops.size() != 1 || ops.get(0).op != (char) 0)
throw new RuntimeException("Error while parsing evaluating \"" + expr + "\"");
return ops.get(0).var;
}
}

View File

@@ -0,0 +1,13 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.renderers;
import net.minecraft.item.ItemStack;
public interface IItemRenderer {
void render(ItemStack is, float handSideSign, float swingProgress, float equipProgress);
}

View File

@@ -0,0 +1,14 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.renderers;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.texture.TextureMap;
public interface IModelBaker extends IBakedModel {
void loadTextures(TextureMap texMap);
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.renderers;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.BufferUtils;
import java.nio.FloatBuffer;
import static org.lwjgl.opengl.GL11.*;
@SideOnly(Side.CLIENT)
public final class LaserPointerRenderer implements IItemRenderer {
private static final float PI = (float) Math.PI;
private final Tessellator t = Tessellator.getInstance();
private final BufferBuilder bb = t.getBuffer();
private final FloatBuffer matrix1 = BufferUtils.createFloatBuffer(16);
private final FloatBuffer renderBuffer = BufferUtils.createFloatBuffer(8);
public boolean isOn = false;
public LaserPointerRenderer() {
for(int i = 0; i < 8; i++)
renderBuffer.put(0.0f);
renderBuffer.position(0);
}
@Override
public final void render(ItemStack is, float handSideSign, float swingProgress, float equipProgress) {
//This whole method is a fucking hack
float sqrtSwingProg = (float) Math.sqrt((double) swingProgress);
float sinSqrtSwingProg1 = MathHelper.sin(sqrtSwingProg * PI);
GlStateManager.disableCull();
GlStateManager.disableTexture2D();
GlStateManager.enableRescaleNormal();
//Laser pointer
glPushMatrix();
glTranslatef(handSideSign * -0.4f * sinSqrtSwingProg1, 0.2f * MathHelper.sin(sqrtSwingProg * PI * 2.0f), -0.2f * MathHelper.sin(swingProgress * PI));
glTranslatef(handSideSign * 0.56f, -0.52f - equipProgress * 0.6f, -0.72f);
glRotatef(handSideSign * (45.0f - MathHelper.sin(swingProgress * swingProgress * PI) * 20.0f), 0.0f, 1.0f, 0.0f);
glRotatef(handSideSign * sinSqrtSwingProg1 * -20.0f, 0.0f, 0.0f, 1.0f);
glRotatef(sinSqrtSwingProg1 * -80.0f, 1.0f, 0.0f, 0.0f);
glRotatef(handSideSign * -30.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.2f, 0.0f);
glRotatef(10.0f, 1.0f, 0.0f, 0.0f);
glScalef(1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f);
glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
bb.begin(GL_QUADS, DefaultVertexFormats.POSITION_NORMAL);
bb.pos(0.0, 0.0, 0.0).normal(0.0f, 1.0f, 0.0f).endVertex();
bb.pos(1.0, 0.0, 0.0).normal(0.0f, 1.0f, 0.0f).endVertex();
bb.pos(1.0, 0.0, 4.0).normal(0.0f, 1.0f, 0.0f).endVertex();
bb.pos(0.0, 0.0, 4.0).normal(0.0f, 1.0f, 0.0f).endVertex();
bb.pos(0.0, 0.0, 0.0).normal(-1.0f, 0.0f, 0.0f).endVertex();
bb.pos(0.0, -1.0, 0.0).normal(-1.0f, 0.0f, 0.0f).endVertex();
bb.pos(0.0, -1.0, 4.0).normal(-1.0f, 0.0f, 0.0f).endVertex();
bb.pos(0.0, 0.0, 4.0).normal(-1.0f, 0.0f, 0.0f).endVertex();
bb.pos(1.0, 0.0, 0.0).normal(1.0f, 0.0f, 0.0f).endVertex();
bb.pos(1.0, -1.0, 0.0).normal(1.0f, 0.0f, 0.0f).endVertex();
bb.pos(1.0, -1.0, 4.0).normal(1.0f, 0.0f, 0.0f).endVertex();
bb.pos(1.0, 0.0, 4.0).normal(1.0f, 0.0f, 0.0f).endVertex();
bb.pos(0.0, -1.0, 4.0).normal(0.0f, 0.0f, 1.0f).endVertex();
bb.pos(1.0, -1.0, 4.0).normal(0.0f, 0.0f, 1.0f).endVertex();
bb.pos(1.0, 0.0, 4.0).normal(0.0f, 0.0f, 1.0f).endVertex();
bb.pos(0.0, 0.0, 4.0).normal(0.0f, 0.0f, 1.0f).endVertex();
t.draw();
if(isOn) {
glTranslatef(0.5f, -0.5f, 0.0f);
matrix1.position(0);
glGetFloat(GL_MODELVIEW_MATRIX, matrix1); //Hax to get that damn position
}
glPopMatrix();
if(isOn) {
RenderHelper.disableStandardItemLighting();
GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit);
GlStateManager.disableTexture2D();
GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
//Actual laser
glPushMatrix();
glLoadIdentity();
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.DST_ALPHA);
glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
GlStateManager.glLineWidth(3.0f);
matrix1.position(12);
renderBuffer.put(matrix1.get());
renderBuffer.put(matrix1.get());
renderBuffer.put(matrix1.get() - 0.02f); //I know this is stupid, but it's the only thing that worked...
renderBuffer.put(matrix1.get());
renderBuffer.position(0);
glVertexPointer(4, 0, renderBuffer);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_LINES, 0, 2);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
GlStateManager.enableTexture2D(); //Fix for shitty minecraft fire
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.renderers;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.entity.RenderPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.ClientProxy;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.GL_RESCALE_NORMAL;
@SideOnly(Side.CLIENT)
public final class MinePadRenderer implements IItemRenderer {
private static final float PI = (float) Math.PI;
private final Minecraft mc = Minecraft.getMinecraft();
private final ResourceLocation tex = new ResourceLocation("webdisplays", "textures/models/minepad.png");
private final ModelMinePad model = new ModelMinePad();
private final ClientProxy clientProxy = (ClientProxy) WebDisplays.PROXY;
private float sinSqrtSwingProg1;
private float sinSqrtSwingProg2;
private float sinSwingProg1;
private float sinSwingProg2;
public static void drawAxis() {
glDisable(GL_TEXTURE_2D);
glBegin(GL_LINES);
glColor4f(1.f, 0.f, 0.f, 1.f); glVertex3d(0.0, 0.0, 0.0);
glColor4f(1.f, 0.f, 0.f, 1.f); glVertex3d(5.0, 0.0, 0.0);
glColor4f(0.f, 1.f, 0.f, 1.f); glVertex3d(0.0, 0.0, 0.0);
glColor4f(0.f, 1.f, 0.f, 1.f); glVertex3d(0.0, 5.0, 0.0);
glColor4f(0.f, 0.f, 1.f, 1.f); glVertex3d(0.0, 0.0, 0.0);
glColor4f(0.f, 0.f, 1.f, 1.f); glVertex3d(0.0, 0.0, 5.0);
glEnd();
glEnable(GL_TEXTURE_2D);
}
@Override
public final void render(ItemStack is, float handSideSign, float swingProgress, float equipProgress) {
//Pre-compute values
float sqrtSwingProg = (float) Math.sqrt((double) swingProgress);
sinSqrtSwingProg1 = MathHelper.sin(sqrtSwingProg * PI);
sinSqrtSwingProg2 = MathHelper.sin(sqrtSwingProg * PI * 2.0f);
sinSwingProg1 = MathHelper.sin(swingProgress * PI);
sinSwingProg2 = MathHelper.sin(swingProgress * swingProgress * PI);
glDisable(GL_CULL_FACE);
glEnable(GL_RESCALE_NORMAL);
//Render arm
glPushMatrix();
renderArmFirstPerson(equipProgress, handSideSign);
glPopMatrix();
//Prepare minePad transform
glPushMatrix();
glTranslatef(handSideSign * -0.4f * sinSqrtSwingProg1, 0.2f * sinSqrtSwingProg2, -0.2f * sinSwingProg1);
glTranslatef(handSideSign * 0.56f, -0.52f - equipProgress * 0.6f, -0.72f);
glRotatef(handSideSign * (45.0f - sinSwingProg2 * 20.0f), 0.0f, 1.0f, 0.0f);
glRotatef(handSideSign * sinSqrtSwingProg1 * -20.0f, 0.0f, 0.0f, 1.0f);
glRotatef(sinSqrtSwingProg1 * -80.0f, 1.0f, 0.0f, 0.0f);
glRotatef(handSideSign * -45.0f, 0.0f, 1.0f, 0.0f);
if(handSideSign >= 0.0f)
glTranslatef(-1.065f, 0.0f, 0.0f);
else {
glTranslatef(0.0f, 0.0f, -0.2f);
glRotatef(20.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(-0.475f, -0.1f, 0.0f);
glRotatef(1.0f, 0.0f, 0.0f, 1.0f);
}
//Render model
glPushMatrix();
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
mc.renderEngine.bindTexture(tex);
model.render(1.f / 16.f);
glPopMatrix();
//Render web view
if(is.getTagCompound() != null && is.getTagCompound().hasKey("PadID")) {
ClientProxy.PadData pd = clientProxy.getPadByID(is.getTagCompound().getInteger("PadID"));
if(pd != null) {
glTranslatef(0.063f, 0.28f, 0.001f);
RenderHelper.disableStandardItemLighting();
OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit);
glDisable(GL_TEXTURE_2D);
OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit);
pd.view.draw(0.0, 0.0, 27.65 / 32.0 + 0.01, 14.0 / 32.0 + 0.002);
}
}
glPopMatrix();
glDisable(GL_RESCALE_NORMAL);
glEnable(GL_CULL_FACE);
}
private void renderArmFirstPerson(float equipProgress, float handSideSign) {
float tx = -0.3f * sinSqrtSwingProg1;
float ty = 0.4f * sinSqrtSwingProg2;
float tz = -0.4f * sinSwingProg1;
glTranslatef(handSideSign * (tx + 0.64000005f), ty - 0.6f - equipProgress * 0.6f, tz - 0.71999997f);
glRotatef(handSideSign * 45.0f, 0.0f, 1.0f, 0.0f);
glRotatef(handSideSign * sinSqrtSwingProg1 * 70.0f, 0.0f, 1.0f, 0.0f);
glRotatef(handSideSign * sinSwingProg2 * -20.0f, 0.0f, 0.0f, 1.0f);
glTranslatef(-handSideSign, 3.6f, 3.5f);
glRotatef(handSideSign * 120.0f, 0.0f, 0.0f, 1.0f);
glRotatef(200.0f, 1.0f, 0.0f, 0.0f);
glRotatef(handSideSign * -135.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(handSideSign * 5.6f, 0.0f, 0.0f);
RenderPlayer playerRenderer = (RenderPlayer) mc.getRenderManager().<AbstractClientPlayer>getEntityRenderObject(mc.player);
mc.getTextureManager().bindTexture(mc.player.getLocationSkin());
if(handSideSign >= 0.0f)
playerRenderer.renderRightArm(mc.player);
else
playerRenderer.renderLeftArm(mc.player);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.renderers;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public final class ModelMinePad extends ModelBase {
// fields
private final ModelRenderer base;
private final ModelRenderer left;
private final ModelRenderer right;
public ModelMinePad() {
textureWidth = 64;
textureHeight = 32;
base = new ModelRenderer(this, 0, 0);
base.addBox(0F, 0F, 0F, 14, 1, 9);
base.setRotationPoint(1F, 0F, 3.5F);
base.setTextureSize(64, 32);
base.mirror = true;
clearRotation(base);
left = new ModelRenderer(this, 0, 10);
left.addBox(0F, 0F, 0F, 1, 1, 7);
left.setRotationPoint(0F, 0F, 4.5F);
left.setTextureSize(64, 32);
left.mirror = true;
clearRotation(left);
right = new ModelRenderer(this, 30, 10);
right.addBox(0F, 0F, 0F, 1, 1, 7);
right.setRotationPoint(15F, 0F, 4.5F);
right.setTextureSize(64, 32);
right.mirror = true;
clearRotation(right);
}
public final void render(float f5) {
base.render(f5);
left.render(f5);
right.render(f5);
}
private void clearRotation(ModelRenderer model) {
model.rotateAngleX = 0.0f;
model.rotateAngleY = 0.0f;
model.rotateAngleZ = 0.0f;
}
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.renderers;
import com.google.common.collect.ImmutableList;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.block.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Vector3f;
import net.montoyo.wd.utilities.Vector3i;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class ScreenBaker implements IModelBaker {
private static final List<BakedQuad> noQuads = ImmutableList.of();
private final TextureAtlasSprite[] texs = new TextureAtlasSprite[16];
private final BlockSide[] blockSides = BlockSide.values();
private final EnumFacing[] blockFacings = EnumFacing.values();
@Override
public void loadTextures(TextureMap texMap) {
for(int i = 0; i < texs.length; i++)
texs[i] = texMap.registerSprite(new ResourceLocation("webdisplays", "blocks/screen" + i));
}
private void putVertex(int[] buf, int pos, Vector3f vpos, TextureAtlasSprite tex, Vector3f uv, Vector3i normal) {
buf[pos * 7 + 0] = Float.floatToRawIntBits(vpos.x);
buf[pos * 7 + 1] = Float.floatToRawIntBits(vpos.y);
buf[pos * 7 + 2] = Float.floatToRawIntBits(vpos.z);
buf[pos * 7 + 3] = 0xFFFFFFFF; //Color, let this white...
buf[pos * 7 + 4] = Float.floatToRawIntBits(tex.getInterpolatedU(uv.x));
buf[pos * 7 + 5] = Float.floatToRawIntBits(tex.getInterpolatedV(uv.y));
int nx = (normal.x * 127) & 0xFF;
int ny = (normal.y * 127) & 0xFF;
int nz = (normal.z * 127) & 0xFF;
buf[pos * 7 + 6] = nx | (ny << 8) | (nz << 16);
}
private Vector3f rotateVec(Vector3f vec, BlockSide side) {
switch(side) {
case BOTTOM: return new Vector3f(vec.x, 1.0f, 1.0f - vec.z);
case TOP: return new Vector3f(vec.x, 0.0f, vec.z);
case NORTH: return new Vector3f(vec.x, vec.z, 1.0f);
case SOUTH: return new Vector3f(vec.x, 1.0f - vec.z, 0.0f);
case WEST: return new Vector3f(1.f , vec.x, vec.z);
case EAST: return new Vector3f(0.0f, 1.0f - vec.x, vec.z);
}
throw new RuntimeException("Unknown block side " + side);
}
private Vector3f rotateTex(BlockSide side, float u, float v) {
switch(side) {
case BOTTOM: return new Vector3f(u, 16.f - v, 0.0f);
case TOP: return new Vector3f(u, v, 0.0f);
case NORTH: return new Vector3f(16.f - u, 16.f - v, 0.0f);
case SOUTH: return new Vector3f(u, v, 0.0f);
case WEST: return new Vector3f(v, 16.f - u, 0.0f);
case EAST: return new Vector3f(16.f - v, u, 0.0f);
}
throw new RuntimeException("Unknown block side " + side);
}
private BakedQuad bakeSide(BlockSide side, TextureAtlasSprite tex) {
int[] data = new int[7 * 4];
putVertex(data, 3, rotateVec(new Vector3f(0.0f, 0.0f, 0.0f), side), tex, rotateTex(side, 0.0f, 0.0f ), side.backward);
putVertex(data, 2, rotateVec(new Vector3f(0.0f, 0.0f, 1.0f), side), tex, rotateTex(side, 0.0f, 16.0f ), side.backward);
putVertex(data, 1, rotateVec(new Vector3f(1.0f, 0.0f, 1.0f), side), tex, rotateTex(side, 16.0f, 16.0f), side.backward);
putVertex(data, 0, rotateVec(new Vector3f(1.0f, 0.0f, 0.0f), side), tex, rotateTex(side, 16.0f, 0.0f ), side.backward);
return new BakedQuad(data, 0xFFFFFFFF, blockFacings[side.ordinal()], tex, true, DefaultVertexFormats.ITEM);
}
@Override
@Nonnull
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) {
if(side == null)
return noQuads;
IExtendedBlockState bs = (IExtendedBlockState) state;
List<BakedQuad> ret = new ArrayList<>();
int sid = BlockSide.reverse(side.ordinal());
BlockSide s = blockSides[sid];
TextureAtlasSprite tex = texs[15];
if(bs != null)
tex = texs[bs.getValue(BlockScreen.sideFlags[sid])];
ret.add(bakeSide(s, tex));
return ret;
}
@Override
public boolean isAmbientOcclusion() {
return true;
}
@Override
public boolean isGui3d() {
return true;
}
@Override
public boolean isBuiltInRenderer() {
return false;
}
@Override
@Nonnull
public TextureAtlasSprite getParticleTexture() {
return texs[15];
}
@Override
@Nonnull
public ItemCameraTransforms getItemCameraTransforms() {
return ItemCameraTransforms.DEFAULT;
}
@Override
@Nonnull
public ItemOverrideList getOverrides() {
return ItemOverrideList.NONE;
}
}

View File

@@ -0,0 +1,206 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.renderers;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.AxisAlignedBB;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.ClientProxy;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.Vector3f;
import net.montoyo.wd.utilities.Vector3i;
import static org.lwjgl.opengl.GL11.*;
public class ScreenRenderer extends TileEntitySpecialRenderer<TileEntityScreen> {
private final Vector3f mid = new Vector3f();
private final Vector3i tmpi = new Vector3i();
private final Vector3f tmpf = new Vector3f();
@Override
public void render(TileEntityScreen te, double x, double y, double z, float partialTicks, int destroyStage, float alpha) {
if(!te.isLoaded())
return;
//Disable lighting
RenderHelper.disableStandardItemLighting();
setLightmapDisabled(true);
glEnable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
for(int i = 0; i < te.screenCount(); i++) {
TileEntityScreen.Screen scr = te.getScreen(i);
if(scr.browser == null) {
scr.browser = ((ClientProxy) WebDisplays.PROXY).getMCEF().createBrowser(WebDisplays.applyBlacklist(scr.url));
if(scr.rotation.isVertical)
scr.browser.resize(scr.resolution.y, scr.resolution.x);
else
scr.browser.resize(scr.resolution.x, scr.resolution.y);
scr.doTurnOnAnim = true;
scr.turnOnTime = System.currentTimeMillis();
}
tmpi.set(scr.side.right);
tmpi.mul(scr.size.x);
tmpi.addMul(scr.side.up, scr.size.y);
tmpf.set(tmpi);
mid.set(x + 0.5, y + 0.5, z + 0.5);
mid.addMul(tmpf, 0.5f);
tmpf.set(scr.side.left);
mid.addMul(tmpf, 0.5f);
tmpf.set(scr.side.down);
mid.addMul(tmpf, 0.5f);
glPushMatrix();
glTranslatef(mid.x, mid.y, mid.z);
switch(scr.side) {
case BOTTOM:
glRotatef(90.f, 1.f, 0.f, 0.f);
break;
case TOP:
glRotatef(-90.f, 1.f, 0.f, 0.f);
break;
case NORTH:
glRotatef(180.f, 0.f, 1.f, 0.f);
break;
case SOUTH:
break;
case WEST:
glRotatef(-90.f, 0.f, 1.f, 0.f);
break;
case EAST:
glRotatef(90.f, 0.f, 1.f, 0.f);
break;
}
if(scr.doTurnOnAnim) {
long lt = System.currentTimeMillis() - scr.turnOnTime;
float ft = ((float) lt) / 100.0f;
if(ft >= 1.0f) {
ft = 1.0f;
scr.doTurnOnAnim = false;
}
glScalef(ft, ft, 1.0f);
}
if(!scr.rotation.isNull)
glRotatef(scr.rotation.angle, 0.0f, 0.0f, 1.0f);
float sw = ((float) scr.size.x) * 0.5f - 2.f / 16.f;
float sh = ((float) scr.size.y) * 0.5f - 2.f / 16.f;
if(scr.rotation.isVertical) {
float tmp = sw;
sw = sh;
sh = tmp;
}
//TODO: Use tesselator
glBindTexture(GL_TEXTURE_2D, scr.browser.getTextureID());
glBegin(GL_QUADS);
glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(0.f, 1.f); glVertex3f(-sw, -sh, 0.505f);
glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(1.f, 1.f); glVertex3f( sw, -sh, 0.505f);
glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(1.f, 0.f); glVertex3f( sw, sh, 0.505f);
glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(0.f, 0.f); glVertex3f(-sw, sh, 0.505f);
glEnd();
GlStateManager.bindTexture(0); //Minecraft does shit with mah texture otherwise...
glPopMatrix();
}
/*
//Bounding box debugging
glPushMatrix();
glTranslated(-rendererDispatcher.entityX, -rendererDispatcher.entityY, -rendererDispatcher.entityZ);
renderAABB(te.getRenderBoundingBox());
glPopMatrix();
*/
//Re-enable lighting
RenderHelper.enableStandardItemLighting();
setLightmapDisabled(false);
glEnable(GL_CULL_FACE);
}
public void renderAABB(AxisAlignedBB bb) {
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glColor4f(0.f, 0.5f, 1.f, 0.75f);
glDepthMask(false);
Tessellator t = Tessellator.getInstance();
BufferBuilder vb = t.getBuffer();
vb.begin(GL_QUADS, DefaultVertexFormats.POSITION);
//Bottom
vb.pos(bb.minX, bb.minY, bb.minZ).endVertex();
vb.pos(bb.maxX, bb.minY, bb.minZ).endVertex();
vb.pos(bb.maxX, bb.minY, bb.maxZ).endVertex();
vb.pos(bb.minX, bb.minY, bb.maxZ).endVertex();
//Top
vb.pos(bb.minX, bb.maxY, bb.minZ).endVertex();
vb.pos(bb.maxX, bb.maxY, bb.minZ).endVertex();
vb.pos(bb.maxX, bb.maxY, bb.maxZ).endVertex();
vb.pos(bb.minX, bb.maxY, bb.maxZ).endVertex();
//Left
vb.pos(bb.minX, bb.minY, bb.minZ).endVertex();
vb.pos(bb.minX, bb.minY, bb.maxZ).endVertex();
vb.pos(bb.minX, bb.maxY, bb.maxZ).endVertex();
vb.pos(bb.minX, bb.maxY, bb.minZ).endVertex();
//Right
vb.pos(bb.maxX, bb.minY, bb.minZ).endVertex();
vb.pos(bb.maxX, bb.minY, bb.maxZ).endVertex();
vb.pos(bb.maxX, bb.maxY, bb.maxZ).endVertex();
vb.pos(bb.maxX, bb.maxY, bb.minZ).endVertex();
//Front
vb.pos(bb.minX, bb.minY, bb.minZ).endVertex();
vb.pos(bb.maxX, bb.minY, bb.minZ).endVertex();
vb.pos(bb.maxX, bb.maxY, bb.minZ).endVertex();
vb.pos(bb.minX, bb.maxY, bb.minZ).endVertex();
//Back
vb.pos(bb.minX, bb.minY, bb.maxZ).endVertex();
vb.pos(bb.maxX, bb.minY, bb.maxZ).endVertex();
vb.pos(bb.maxX, bb.maxY, bb.maxZ).endVertex();
vb.pos(bb.minX, bb.maxY, bb.maxZ).endVertex();
t.draw();
glDepthMask(true);
glEnable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
@Override
public boolean isGlobalRenderer(TileEntityScreen te) {
//I don't like making it a global renderer for performance reasons,
//but Minecraft's AABB-in-view-frustum checking is crappy as hell.
return te.isLoaded();
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
public enum AdvancementIcon {
WEB_DISPLAYS("wd"),
BROKEN_PAD("brokenpad"),
PIGEON("pigeon");
private final String name;
AdvancementIcon(String n) {
name = n;
}
@Override
public String toString() {
return name;
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import java.util.List;
import java.util.Map;
public class CCArguments implements IComputerArgs {
private final Object[] args;
public CCArguments(Object[] args) {
this.args = args;
}
@Override
public String checkString(int i) {
checkIndex(i, "string");
Object obj = args[i];
if(!(obj instanceof String))
throw typeError(i, "string", obj);
return (String) obj;
}
@Override
public int checkInteger(int i) {
checkIndex(i, "number");
Object obj = args[i];
int ret;
if(obj instanceof Integer)
ret = (int) obj;
else if(obj instanceof Double)
ret = ((Double) obj).intValue();
else if(obj instanceof Float)
ret = ((Float) obj).intValue();
else
throw typeError(i, "number", obj);
return ret;
}
@Override
public Map checkTable(int i) {
checkIndex(i, "table");
Object obj = args[i];
if(!(obj instanceof Map))
throw typeError(i, "table", args[i]);
return (Map) obj;
}
private void checkIndex(int idx, String want) {
if(idx < 0 || idx >= args.length)
typeError(idx, want, null);
}
private static IllegalArgumentException typeError(int idx, String want, Object got) {
return new IllegalArgumentException("bad argument #" + (idx + 1) + " (" + want + " expected, got " + luaTypeName(got) + ")");
}
private static String luaTypeName(Object obj) {
if(obj == null)
return "nil";
Class<?> cls = obj.getClass();
if(cls == Boolean.class || cls == Boolean.TYPE)
return "boolean";
else if(cls == Integer.class || cls == Integer.TYPE || cls == Double.class || cls == Double.TYPE || cls == Float.class || cls == Float.TYPE)
return "number";
else if(cls == String.class)
return "string";
else if(Map.class.isAssignableFrom(cls))
return "table";
else
return cls.getSimpleName();
}
@Override
public int count() {
return args.length;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.Optional;
import net.montoyo.wd.entity.TileEntityCCInterface;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheralProvider", modid = "computercraft")
public class CCPeripheralProvider implements IPeripheralProvider {
private CCPeripheralProvider() {
}
@Optional.Method(modid = "computercraft")
@Nullable
@Override
public IPeripheral getPeripheral(@Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing f) {
TileEntity te = world.getTileEntity(pos);
return (te instanceof TileEntityCCInterface) ? ((TileEntityCCInterface) te) : null;
}
@Optional.Method(modid = "computercraft")
public static void register() {
ComputerCraftAPI.registerPeripheralProvider(new CCPeripheralProvider());
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.minecraft.item.ItemStack;
import net.montoyo.wd.WebDisplays;
public enum CraftComponent {
STONE_KEY("stonekey", "Stone_Key"),
BLANK_UPGRADE("upgrade", "Blank_Upgrade"),
PERIPHERAL_BASE("peripheral", "Peripheral_Base"),
BATTERY_CELL("batcell", "Battery_Cell"),
BATTERY_PACK("batpack", "Battery_Pack"),
LASER_DIODE("laserdiode", "Laser_Diode"),
BACKLIGHT("backlight", "Backlight"),
EXTENSION_CARD("extcard", "Blank_Upgrade"),
BAD_EXTENSION_CARD("badextcard", "Bad_Extension_Card");
private final String name;
private final String wikiName;
CraftComponent(String n, String wikiName) {
name = n;
this.wikiName = wikiName;
}
@Override
public String toString() {
return name;
}
public static String getWikiName(int meta) {
CraftComponent[] values = values();
return (meta >= 0 && meta < values.length) ? values[meta].wikiName : null;
}
public ItemStack makeItemStack() {
return new ItemStack(WebDisplays.INSTANCE.itemCraftComp, 1, ordinal());
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import net.minecraft.advancements.ICriterionTrigger;
import net.minecraft.advancements.PlayerAdvancements;
import net.minecraft.advancements.critereon.AbstractCriterionInstance;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
public class Criterion implements ICriterionTrigger<Criterion.Instance> {
public static class Instance extends AbstractCriterionInstance {
public Instance(ResourceLocation id) {
super(id);
}
}
private final ResourceLocation id;
private final HashMap<PlayerAdvancements, ArrayList<Listener<Instance>>> map = new HashMap<>();
public Criterion(@Nonnull String name) {
id = new ResourceLocation("webdisplays", name);
}
@Override
@Nonnull
public ResourceLocation getId() {
return id;
}
@Override
public void addListener(@Nonnull PlayerAdvancements adv, @Nonnull Listener<Instance> l) {
map.computeIfAbsent(adv, k -> new ArrayList<>()).add(l);
}
@Override
public void removeListener(@Nonnull PlayerAdvancements adv, @Nonnull Listener<Instance> l) {
map.computeIfPresent(adv, (k, v) -> {
v.remove(l);
return v.isEmpty() ? null : v;
});
}
@Override
public void removeAllListeners(@Nonnull PlayerAdvancements adv) {
map.remove(adv);
}
@Override
@Nonnull
public Instance deserializeInstance(@Nonnull JsonObject json, @Nonnull JsonDeserializationContext ctx) {
return new Instance(id);
}
public void trigger(PlayerAdvancements ply) {
ArrayList<Listener<Instance>> listeners = map.get(ply);
if(listeners != null) {
Listener[] copy = listeners.toArray(new Listener[0]); //We need to make a copy, otherwise we get a ConcurrentModificationException
Arrays.stream(copy).forEach(l -> l.grantCriterion(ply));
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.IStringSerializable;
import net.montoyo.wd.entity.*;
import javax.annotation.Nonnull;
public enum DefaultPeripheral implements IStringSerializable {
KEYBOARD("keyboard", "Keyboard", TileEntityKeyboard.class), //WITH FACING (< 3)
CC_INTERFACE("ccinterface", "ComputerCraft_Interface", TileEntityCCInterface.class),
OC_INTERFACE("cointerface", "OpenComputers_Interface", TileEntityOCInterface.class),
REMOTE_CONTROLLER("remotectrl", "Remote_Controller", TileEntityRCtrl.class), //WITHOUT FACING (>= 3)
REDSTONE_CONTROLLER("redstonectrl", "Redstone_Controller", TileEntityRedCtrl.class),
SERVER("server", "Server", TileEntityServer.class);
private final String name;
private final String wikiName;
private final Class<? extends TileEntity> teClass;
DefaultPeripheral(String name, String wname, Class<? extends TileEntity> te) {
this.name = name;
wikiName = wname;
teClass = te;
}
public static DefaultPeripheral fromMetadata(int meta) {
if((meta & 3) == 3)
return values()[(((meta >> 2) & 3) | 4) - 1]; //Without facing
else
return values()[meta & 3]; //With facing
}
@Override
@Nonnull
public String getName() {
return name;
}
public Class<? extends TileEntity> getTEClass() {
return teClass;
}
public boolean hasFacing() {
return ordinal() < 3;
}
public int toMetadata(int facing) {
int ret = ordinal();
if(ret < 3) //With facing
ret |= facing << 2;
else //Without facing
ret = (((ret + 1) & 3) << 2) | 3;
return ret;
}
public String getWikiName() {
return wikiName;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.minecraft.item.ItemStack;
import net.montoyo.wd.WebDisplays;
public enum DefaultUpgrade {
LASER_MOUSE("lasermouse", "Laser_Sensor"),
REDSTONE_INPUT("redinput", "Redstone_Input_Port"),
REDSTONE_OUTPUT("redoutput", "Redstone_Output_Port"),
GPS("gps", "GPS_Module");
private final String name;
private final String wikiName;
DefaultUpgrade(String n, String wn) {
name = n;
wikiName = wn;
}
@Override
public String toString() {
return name;
}
public boolean matches(ItemStack is) {
return is.getItem() == WebDisplays.INSTANCE.itemUpgrade && is.getMetadata() == ordinal();
}
public static String getWikiName(int meta) {
DefaultUpgrade[] values = values();
return (meta >= 0 && meta < values.length) ? values[meta].wikiName : null;
}
}

View File

@@ -0,0 +1,13 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
public enum HasAdvancement {
DONT_KNOW,
YES,
NO
}

View File

@@ -0,0 +1,16 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import java.util.Map;
public interface IComputerArgs {
String checkString(int i);
int checkInteger(int i);
Map checkTable(int i);
int count();
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Vector3i;
public interface IPeripheral {
boolean connect(World world, BlockPos blockPos, IBlockState blockState, Vector3i screenPos, BlockSide screenSide);
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.montoyo.mcef.api.IJSQueryCallback;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import javax.annotation.Nonnull;
public interface IScreenQueryHandler {
//args is an array of Doubles or Strings
//The screen DOES exist, so scr.getScreen(side) is never null
void handleQuery(@Nonnull IJSQueryCallback cb, @Nonnull TileEntityScreen scr, @Nonnull BlockSide side, @Nonnull Object[] args);
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface IUpgrade {
void onInstall(@Nonnull TileEntityScreen tes, @Nonnull BlockSide screenSide, @Nullable EntityPlayer player, @Nonnull ItemStack is);
boolean onRemove(@Nonnull TileEntityScreen tes, @Nonnull BlockSide screenSide, @Nullable EntityPlayer player, @Nonnull ItemStack is); //Return true to prevent dropping
boolean isSameUpgrade(@Nonnull ItemStack myStack, @Nonnull ItemStack otherStack); //myStack.getItem() is an instance of this class
String getJSName(@Nonnull ItemStack is); //modname:upgradename
}

View File

@@ -0,0 +1,13 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
public interface IWDDCapability {
boolean isFirstRun();
void clearFirstRun();
void cloneTo(IWDDCapability dst);
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import io.netty.buffer.ByteBuf;
import net.montoyo.wd.utilities.Util;
public enum JSServerRequest {
CLEAR_REDSTONE,
SET_REDSTONE_AT(Integer.class, Integer.class, Boolean.class);
private final Class[] requestTypes;
JSServerRequest(Class<?> ... requestTypes) {
this.requestTypes = requestTypes;
}
public static JSServerRequest fromID(int id) {
JSServerRequest[] values = values();
return (id >= 0 && id < values.length) ? values[id] : null;
}
public boolean serialize(ByteBuf buf, Object[] data) {
if(data.length != requestTypes.length)
return false;
for(int i = 0; i < data.length; i++) {
if(data[i].getClass() != requestTypes[i])
return false;
Util.serialize(buf, data[i]);
}
return true;
}
public Object[] deserialize(ByteBuf buf) {
Object[] ret = new Object[requestTypes.length];
try {
for(int i = 0; i < requestTypes.length; i++)
ret[i] = Util.unserialize(buf, requestTypes[i]);
} catch(Throwable t) {
t.printStackTrace();
return null;
}
return ret;
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.minecraft.entity.player.EntityPlayerMP;
public class MissingPermissionException extends Exception {
private final int permission;
private final EntityPlayerMP player;
public MissingPermissionException(int p, EntityPlayerMP ply) {
super("Player " + ply.getName() + " is missing permission " + p);
permission = p;
player = ply;
}
public int getPermission() {
return permission;
}
public EntityPlayerMP getPlayer() {
return player;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import li.cil.oc.api.machine.Arguments;
import net.minecraftforge.fml.common.Optional;
import java.util.Map;
@Optional.Interface(iface = "net.montoyo.wd.core.IComputerArgs", modid = "opencomputers")
public class OCArguments implements IComputerArgs {
//Keep this as an "Object" so that it doesn't crash if OC is absent
private final Object args;
public OCArguments(Object a) {
args = a;
}
@Optional.Method(modid = "opencomputers")
@Override
public String checkString(int i) {
return ((Arguments) args).checkString(i);
}
@Optional.Method(modid = "opencomputers")
@Override
public int checkInteger(int i) {
return ((Arguments) args).checkInteger(i);
}
@Optional.Method(modid = "opencomputers")
@Override
public Map checkTable(int i) {
return ((Arguments) args).checkTable(i);
}
@Optional.Method(modid = "opencomputers")
@Override
public int count() {
return ((Arguments) args).count();
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
public abstract class ScreenRights {
public static final int CHANGE_URL = 1; //Change URL AND run JavaScript
public static final int CLICK = 2; //Click AND type
public static final int MANAGE_FRIEND_LIST = 4;
public static final int MANAGE_OTHER_RIGHTS = 8;
public static final int MANAGE_UPGRADES = 16; //Manage upgrades AND peripherals AND autoVolume
public static final int CHANGE_RESOLUTION = 32; //Change resolution AND rotation
public static final int NONE = 0;
public static final int ALL = 0xFF;
public static final int DEFAULTS = CHANGE_URL | CLICK | MANAGE_UPGRADES | CHANGE_RESOLUTION;
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemStack;
import net.montoyo.wd.WebDisplays;
import javax.annotation.Nonnull;
public class WDCreativeTab extends CreativeTabs {
public WDCreativeTab() {
super("webdisplays");
}
@Override
@Nonnull
public ItemStack getTabIconItem() {
return new ItemStack(WebDisplays.INSTANCE.blockScreen);
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagByte;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.concurrent.Callable;
public class WDDCapability implements IWDDCapability {
@CapabilityInject(IWDDCapability.class)
public static final Capability<IWDDCapability> INSTANCE = null;
public static class Storage implements Capability.IStorage<IWDDCapability> {
@Nullable
@Override
public NBTBase writeNBT(Capability<IWDDCapability> cap, IWDDCapability inst, EnumFacing side) {
NBTTagCompound tag = new NBTTagCompound();
tag.setBoolean("FirstRun", inst.isFirstRun());
return tag;
}
@Override
public void readNBT(Capability<IWDDCapability> cap, IWDDCapability inst, EnumFacing side, NBTBase nbt) {
if(nbt instanceof NBTTagCompound) {
NBTTagCompound tag = (NBTTagCompound) nbt;
if(tag.hasKey("FirstRun") && tag.getTag("FirstRun") instanceof NBTTagByte && !tag.getBoolean("FirstRun"))
inst.clearFirstRun();
}
}
}
public static class Factory implements Callable<IWDDCapability> {
@Override
public IWDDCapability call() throws Exception {
return new WDDCapability();
}
}
public static class Provider implements ICapabilitySerializable<NBTBase> {
private IWDDCapability cap = INSTANCE.getDefaultInstance();
@Override
public boolean hasCapability(@Nonnull Capability<?> cap, @Nullable EnumFacing f) {
return cap == INSTANCE;
}
@Nullable
@Override
public <T> T getCapability(@Nonnull Capability<T> cap, @Nullable EnumFacing f) {
return cap == INSTANCE ? INSTANCE.cast(this.cap) : null;
}
@Override
public NBTBase serializeNBT() {
return INSTANCE.getStorage().writeNBT(INSTANCE, cap, null);
}
@Override
public void deserializeNBT(NBTBase nbt) {
INSTANCE.getStorage().readNBT(INSTANCE, cap, null, nbt);
}
}
private boolean firstRun = true;
private WDDCapability() {
}
@Override
public boolean isFirstRun() {
return firstRun;
}
@Override
public void clearFirstRun() {
firstRun = false;
}
@Override
public void cloneTo(IWDDCapability dst) {
if(!isFirstRun())
dst.clearFirstRun();
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.data;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.net.client.CMessageOpenGui;
import java.util.HashMap;
public abstract class GuiData {
private static final HashMap<String, Class<? extends GuiData>> dataTable = new HashMap<>();
static {
dataTable.put("SetURL", SetURLData.class);
dataTable.put("ScreenConfig", ScreenConfigData.class);
dataTable.put("Keyboard", KeyboardData.class);
dataTable.put("RedstoneCtrl", RedstoneCtrlData.class);
dataTable.put("Server", ServerData.class);
}
public static Class<? extends GuiData> classOf(String name) {
return dataTable.get(name);
}
@SideOnly(Side.CLIENT)
public abstract GuiScreen createGui(GuiScreen old, World world);
public abstract String getName();
public void sendTo(EntityPlayerMP player) {
WebDisplays.NET_HANDLER.sendTo(new CMessageOpenGui(this), player);
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.data;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.client.gui.GuiKeyboard;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Vector3i;
public class KeyboardData extends GuiData {
public Vector3i pos;
public BlockSide side;
public int kbX;
public int kbY;
public int kbZ;
public KeyboardData() {
}
public KeyboardData(TileEntityScreen tes, BlockSide side, BlockPos kbPos) {
pos = new Vector3i(tes.getPos());
this.side = side;
kbX = kbPos.getX();
kbY = kbPos.getY();
kbZ = kbPos.getZ();
}
@SideOnly(Side.CLIENT)
@Override
public GuiScreen createGui(GuiScreen old, World world) {
TileEntity te = world.getTileEntity(pos.toBlock());
if(te == null || !(te instanceof TileEntityScreen)) {
Log.error("TileEntity at %s is not a screen; can't open keyboard!", pos.toString());
return null;
}
return new GuiKeyboard((TileEntityScreen) te, side, new BlockPos(kbX, kbY, kbZ));
}
@Override
public String getName() {
return "Keyboard";
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.data;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.client.gui.GuiRedstoneCtrl;
import net.montoyo.wd.utilities.Vector3i;
public class RedstoneCtrlData extends GuiData {
public int dimension;
public Vector3i pos;
public String risingEdgeURL;
public String fallingEdgeURL;
public RedstoneCtrlData() {
}
public RedstoneCtrlData(int d, BlockPos p, String r, String f) {
dimension = d;
pos = new Vector3i(p);
risingEdgeURL = r;
fallingEdgeURL = f;
}
@SideOnly(Side.CLIENT)
@Override
public GuiScreen createGui(GuiScreen old, World world) {
return new GuiRedstoneCtrl(dimension, pos, risingEdgeURL, fallingEdgeURL);
}
@Override
public String getName() {
return "RedstoneCtrl";
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.data;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.gui.GuiScreenConfig;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.net.client.CMessageOpenGui;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.NameUUIDPair;
import net.montoyo.wd.utilities.Vector3i;
public class ScreenConfigData extends GuiData {
public boolean onlyUpdate;
public Vector3i pos;
public BlockSide side;
public NameUUIDPair[] friends;
public int friendRights;
public int otherRights;
public ScreenConfigData() {
}
public ScreenConfigData(Vector3i pos, BlockSide side, TileEntityScreen.Screen scr) {
this.pos = pos;
this.side = side;
friends = scr.friends.toArray(new NameUUIDPair[0]);
friendRights = scr.friendRights;
otherRights = scr.otherRights;
onlyUpdate = false;
}
@SideOnly(Side.CLIENT)
@Override
public GuiScreen createGui(GuiScreen old, World world) {
if(old != null && old instanceof GuiScreenConfig) {
GuiScreenConfig gsc = (GuiScreenConfig) old;
if(gsc.isForBlock(pos.toBlock(), side)) {
gsc.updateFriends(friends);
gsc.updateFriendRights(friendRights);
gsc.updateOtherRights(otherRights);
gsc.updateMyRights();
return null;
}
}
if(onlyUpdate)
return null;
TileEntity te = world.getTileEntity(pos.toBlock());
if(te == null || !(te instanceof TileEntityScreen)) {
Log.error("TileEntity at %s is not a screen; can't open gui!", pos.toString());
return null;
}
return new GuiScreenConfig((TileEntityScreen) te, side, friends, friendRights, otherRights);
}
@Override
public String getName() {
return "ScreenConfig";
}
public ScreenConfigData updateOnly() {
onlyUpdate = true;
return this;
}
public void sendTo(NetworkRegistry.TargetPoint tp) {
WebDisplays.NET_HANDLER.sendToAllAround(new CMessageOpenGui(this), tp);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.data;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.client.gui.GuiServer;
import net.montoyo.wd.utilities.NameUUIDPair;
import net.montoyo.wd.utilities.Vector3i;
public class ServerData extends GuiData {
public Vector3i pos;
public NameUUIDPair owner;
public ServerData() {
}
public ServerData(BlockPos bp, NameUUIDPair owner) {
pos = new Vector3i(bp);
this.owner = owner;
}
@SideOnly(Side.CLIENT)
@Override
public GuiScreen createGui(GuiScreen old, World world) {
return new GuiServer(pos, owner);
}
@Override
public String getName() {
return "Server";
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.data;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.client.gui.GuiSetURL2;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Vector3i;
public class SetURLData extends GuiData {
public Vector3i pos;
public BlockSide side;
public String url;
public boolean isRemote;
public Vector3i remoteLocation;
public SetURLData() {
}
public SetURLData(Vector3i pos, BlockSide side, String url) {
this.pos = pos;
this.side = side;
this.url = url;
isRemote = false;
remoteLocation = new Vector3i();
}
public SetURLData(Vector3i pos, BlockSide side, String url, BlockPos rl) {
this.pos = pos;
this.side = side;
this.url = url;
isRemote = true;
remoteLocation = new Vector3i(rl);
}
@SideOnly(Side.CLIENT)
@Override
public GuiScreen createGui(GuiScreen old, World world) {
TileEntity te = world.getTileEntity(pos.toBlock());
if(te == null || !(te instanceof TileEntityScreen)) {
Log.error("TileEntity at %s is not a screen; can't open gui!", pos.toString());
return null;
}
return new GuiSetURL2((TileEntityScreen) te, side, url, isRemote ? remoteLocation : null);
}
@Override
public String getName() {
return "SetURL";
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.entity;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraftforge.fml.common.Optional;
import net.montoyo.wd.core.CCArguments;
import net.montoyo.wd.core.IComputerArgs;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
@Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheral", modid = "computercraft")
public class TileEntityCCInterface extends TileEntityInterfaceBase implements IPeripheral {
private static final String[] METHOD_NAMES;
private static final Method[] METHODS;
static {
ArrayList<String> names = new ArrayList<>();
ArrayList<Method> methods = new ArrayList<>();
Method[] src = TileEntityInterfaceBase.class.getMethods();
for(Method m: src) {
if(m.getAnnotation(TileEntityInterfaceBase.ComputerFunc.class) != null) {
if(m.getParameterCount() != 1 || m.getParameterTypes()[0] != IComputerArgs.class)
throw new RuntimeException("Found @ComputerFunc method with invalid arguments");
if(m.getReturnType() != Object[].class)
throw new RuntimeException("Found @ComputerFunc method with invalid return type");
names.add(m.getName());
methods.add(m);
}
}
METHOD_NAMES = names.toArray(new String[0]);
METHODS = methods.toArray(new Method[0]);
}
@Nonnull
@Override
public String getType() {
return "webdisplays";
}
@Nonnull
@Override
public String[] getMethodNames() {
return METHOD_NAMES;
}
@Optional.Method(modid = "computercraft")
@Nullable
@Override
public Object[] callMethod(@Nonnull IComputerAccess ca, @Nonnull ILuaContext ctx, int mid, @Nonnull Object[] args) throws LuaException, InterruptedException {
try {
return (Object[]) METHODS[mid].invoke(this, new CCArguments(args));
} catch(IllegalAccessException e) {
throw new RuntimeException(e);
} catch(InvocationTargetException e) {
if(e.getCause() instanceof IllegalArgumentException)
throw new LuaException(e.getCause().getMessage());
else
throw new RuntimeException(e.getCause());
}
}
@Optional.Method(modid = "computercraft")
@Override
public boolean equals(@Nullable IPeripheral periph) {
return periph == this;
}
}

View File

@@ -0,0 +1,401 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.IComputerArgs;
import net.montoyo.wd.core.IUpgrade;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.net.client.CMessageScreenUpdate;
import net.montoyo.wd.utilities.*;
import javax.annotation.Nonnull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Map;
public abstract class TileEntityInterfaceBase extends TileEntityPeripheralBase {
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComputerFunc {}
private NameUUIDPair owner;
private static final Object[] TRUE = new Object[] { true };
private static final Object[] FALSE = new Object[] { false };
@Override
public void readFromNBT(NBTTagCompound tag) {
super.readFromNBT(tag);
owner = Util.readOwnerFromNBT(tag);
}
@Override
@Nonnull
public NBTTagCompound writeToNBT(NBTTagCompound tag) {
super.writeToNBT(tag);
return Util.writeOwnerToNBT(tag, owner);
}
public void setOwner(EntityPlayer ep) {
owner = new NameUUIDPair(ep.getGameProfile());
markDirty();
}
@ComputerFunc
public Object[] isLinked(IComputerArgs args) {
return new Object[] { isLinked() };
}
@ComputerFunc
public Object[] isScreenChunkLoaded(IComputerArgs args) {
return new Object[] { isScreenChunkLoaded() };
}
@ComputerFunc
public Object[] getScreenPos(IComputerArgs args) {
return isLinked() ? new Object[] { screenPos.x, screenPos.y, screenPos.z } : null;
}
@ComputerFunc
public Object[] getScreenSide(IComputerArgs args) {
return isLinked() ? new Object[] { screenSide.toString().toLowerCase() } : null;
}
@ComputerFunc
public Object[] getOwner(IComputerArgs args) {
if(owner == null)
return null;
else
return new Object[] { owner.name, owner.uuid.toString() };
}
@ComputerFunc
public Object[] can(IComputerArgs args) {
String what = args.checkString(0).toLowerCase();
int right;
switch(what) {
case "click":
case "type":
right = ScreenRights.CLICK;
break;
case "seturl":
case "js":
case "javascript":
case "runjs":
right = ScreenRights.CHANGE_URL;
break;
case "setresolution":
case "setrotation":
right = ScreenRights.CHANGE_RESOLUTION;
break;
default:
throw new IllegalArgumentException("invalid right name");
}
TileEntityScreen tes = getConnectedScreenEx();
if(owner == null || tes == null)
return null;
else
return ((tes.getScreen(screenSide).rightsFor(owner.uuid) & right) == 0) ? FALSE : TRUE;
}
@ComputerFunc
public Object[] hasUpgrade(IComputerArgs args) {
String name = args.checkString(0);
TileEntityScreen tes = getConnectedScreenEx();
if(owner == null || tes == null)
return null;
else
return tes.getScreen(screenSide).upgrades.stream().anyMatch(is -> ((IUpgrade) is.getItem()).getJSName(is).equalsIgnoreCase(name)) ? TRUE : FALSE;
}
@ComputerFunc
public Object[] getSize(IComputerArgs args) {
TileEntityScreen tes = getConnectedScreenEx();
if(owner == null || tes == null)
return null;
else {
Vector2i sz = tes.getScreen(screenSide).size;
return new Object[] { sz.x, sz.y };
}
}
@ComputerFunc
public Object[] getResolution(IComputerArgs args) {
TileEntityScreen tes = getConnectedScreenEx();
if(owner == null || tes == null)
return null;
else {
Vector2i res = tes.getScreen(screenSide).resolution;
return new Object[] { res.x, res.y };
}
}
@ComputerFunc
public Object[] getRotation(IComputerArgs args) {
TileEntityScreen tes = getConnectedScreenEx();
if(owner == null || tes == null)
return null;
else
return new Object[] { tes.getScreen(screenSide).rotation.getAngleAsInt() };
}
@ComputerFunc
public Object[] getURL(IComputerArgs args) {
TileEntityScreen tes = getConnectedScreenEx();
if(owner == null || tes == null)
return null;
else
return new Object[] { tes.getScreen(screenSide).url };
}
private static Object[] err(String str) {
return new Object[] { false, str };
}
@ComputerFunc
public Object[] click(IComputerArgs args) {
int x = args.checkInteger(0);
int y = args.checkInteger(1);
String action = "click";
if(args.count() > 2)
action = args.checkString(2).toLowerCase();
int actionId;
switch(action) {
case "click":
actionId = CMessageScreenUpdate.MOUSE_CLICK;
break;
case "up":
case "release":
actionId = CMessageScreenUpdate.MOUSE_UP;
break;
case "down":
case "press":
actionId = CMessageScreenUpdate.MOUSE_DOWN;
break;
case "move":
actionId = CMessageScreenUpdate.MOUSE_MOVE;
break;
default:
throw new IllegalArgumentException("bad action name");
}
TileEntityScreen scr = getConnectedScreenEx();
if(owner == null || scr == null)
return err("notlinked");
else {
TileEntityScreen.Screen scrscr = scr.getScreen(screenSide);
if((scrscr.rightsFor(owner.uuid) & ScreenRights.CLICK) == 0)
return err("restrictions");
else {
switch(scrscr.rotation) {
case ROT_90:
y = scrscr.resolution.y - y;
break;
case ROT_180:
x = scrscr.resolution.x - x;
y = scrscr.resolution.y - y;
break;
case ROT_270:
x = scrscr.resolution.x - x;
break;
default:
break;
}
if(scrscr.rotation.isVertical)
scr.clickUnsafe(screenSide, actionId, y, x);
else
scr.clickUnsafe(screenSide, actionId, x, y);
return TRUE;
}
}
}
private Object[] realType(String what) {
TileEntityScreen scr = getConnectedScreenEx();
if(owner == null || scr == null)
return err("notlinked");
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.CLICK) == 0)
return err("restrictions");
else {
scr.type(screenSide, what, null);
return TRUE;
}
}
@ComputerFunc
public Object[] type(IComputerArgs args) {
String text = args.checkString(0);
if(text.length() > 64)
return err("toolong");
if(text.indexOf((char) 1) >= 0)
return err("badchar");
return realType("t" + text);
}
@ComputerFunc
public Object[] typeAdvanced(IComputerArgs args) {
ArrayList<TypeData> data = new ArrayList<>();
Map map = args.checkTable(0);
int maxEvents = 0;
for(Object o: map.values()) {
if(!(o instanceof Map))
return err("badinput");
if(++maxEvents >= 16)
return err("toomany");
Map event = (Map) o;
Object action = event.get("action");
Object chr = event.get("char");
int code = 0;
if(!(action instanceof String))
return err("badaction");
if(!(chr instanceof String))
return err("badchar");
String strAction = (String) action;
String strChr = (String) chr;
TypeData.Action dataAction;
if(strAction.equalsIgnoreCase("press"))
dataAction = TypeData.Action.PRESS;
else if(strAction.equalsIgnoreCase("release"))
dataAction = TypeData.Action.RELEASE;
else if(strAction.equalsIgnoreCase("type"))
dataAction = TypeData.Action.TYPE;
else
return err("unknownaction");
if(strChr.isEmpty())
return err("emptychar");
if(dataAction != TypeData.Action.TYPE) {
Object oCode = event.get("code");
if(!(oCode instanceof Double))
return err("badcode");
code = ((Double) oCode).intValue();
}
data.add(new TypeData(dataAction, code, strChr.charAt(0)));
}
return realType(WebDisplays.GSON.toJson(data));
}
@ComputerFunc
public Object[] setURL(IComputerArgs args) {
String url = args.checkString(0);
TileEntityScreen scr = getConnectedScreenEx();
if(owner == null || scr == null)
return err("notlinked");
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.CHANGE_URL) == 0)
return err("restrictions");
else {
scr.setScreenURL(screenSide, url);
return TRUE;
}
}
@ComputerFunc
public Object[] setResolution(IComputerArgs args) {
int rx = args.checkInteger(0);
int ry = args.checkInteger(1);
TileEntityScreen scr = getConnectedScreenEx();
if(owner == null || scr == null)
return err("notlinked");
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.CHANGE_RESOLUTION) == 0)
return err("restrictions");
else {
scr.setResolution(screenSide, new Vector2i(rx, ry));
return TRUE;
}
}
@ComputerFunc
public Object[] setRotation(IComputerArgs args) {
int rot = args.checkInteger(0);
if(rot < 0) {
int toAdd = (rot / -360) + 1;
rot += toAdd * 360;
}
rot /= 90;
rot &= 3;
TileEntityScreen scr = getConnectedScreenEx();
if(owner == null || scr == null)
return err("notlinked");
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.CHANGE_RESOLUTION) == 0)
return err("restrictions");
else {
scr.setRotation(screenSide, Rotation.values()[rot]);
return TRUE;
}
}
@ComputerFunc
public Object[] runJS(IComputerArgs args) {
String code = args.checkString(0);
TileEntityScreen scr = getConnectedScreenEx();
if(owner == null || scr == null)
return err("notlinked");
else if((scr.getScreen(screenSide).rightsFor(owner.uuid) & ScreenRights.CHANGE_URL) == 0)
return err("restrictions");
else {
scr.evalJS(screenSide, code);
return TRUE;
}
}
@ComputerFunc
public Object[] unlink(IComputerArgs args) {
if(isLinked()) {
screenPos = null;
screenSide = null;
markDirty();
}
return null;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.entity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.passive.EntityOcelot;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.EnumHand;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.data.KeyboardData;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Util;
public class TileEntityKeyboard extends TileEntityPeripheralBase {
private static final String RANDOM_CHARS = "AZERTYUIOPQSDFGHJKLMWXCVBNazertyuiopqsdfghjklmwxcvbn0123456789"; //Yes I have an AZERTY keyboard, u care?
@Override
public boolean onRightClick(EntityPlayer player, EnumHand hand, BlockSide side) {
if(world.isRemote)
return true;
if(!isScreenChunkLoaded()) {
Util.toast(player, "chunkUnloaded");
return true;
}
TileEntityScreen tes = getConnectedScreen();
if(tes == null) {
Util.toast(player, "notLinked");
return true;
}
TileEntityScreen.Screen scr = tes.getScreen(screenSide);
if((scr.rightsFor(player) & ScreenRights.CLICK) == 0) {
Util.toast(player, "restrictions");
return true;
}
(new KeyboardData(tes, screenSide, pos)).sendTo((EntityPlayerMP) player);
return true;
}
public void simulateCat(Entity ent) {
if(isScreenChunkLoaded()) {
TileEntityScreen tes = getConnectedScreen();
if(tes != null) {
TileEntityScreen.Screen scr = tes.getScreen(screenSide);
boolean ok;
if(ent instanceof EntityPlayer)
ok = (scr.rightsFor((EntityPlayer) ent) & ScreenRights.CLICK) != 0;
else
ok = (scr.otherRights & ScreenRights.CLICK) != 0;
if(ok) {
char rnd = RANDOM_CHARS.charAt((int) (Math.random() * ((double) RANDOM_CHARS.length())));
tes.type(screenSide, "t" + rnd, pos);
EntityPlayer owner = world.getPlayerEntityByUUID(scr.owner.uuid);
if(owner != null && owner instanceof EntityPlayerMP && ent instanceof EntityOcelot)
WebDisplays.INSTANCE.criterionKeyboardCat.trigger(((EntityPlayerMP) owner).getAdvancements());
}
}
}
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.entity;
import li.cil.oc.api.machine.Arguments;
import li.cil.oc.api.machine.Callback;
import li.cil.oc.api.machine.Context;
import li.cil.oc.api.network.SimpleComponent;
import net.minecraftforge.fml.common.Optional;
import net.montoyo.wd.core.OCArguments;
@Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "opencomputers")
public class TileEntityOCInterface extends TileEntityInterfaceBase implements SimpleComponent {
@Override
public String getComponentName() {
return "webdisplays";
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] isLinked(Context ctx, Arguments args) {
return isLinked(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] isScreenChunkLoaded(Context ctx, Arguments args) {
return isScreenChunkLoaded(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] getScreenPos(Context ctx, Arguments args) {
return getScreenPos(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] getScreenSide(Context ctx, Arguments args) {
return getScreenSide(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] getOwner(Context ctx, Arguments args) {
return getOwner(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] can(Context ctx, Arguments args) {
return can(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] hasUpgrade(Context ctx, Arguments args) {
return hasUpgrade(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] getSize(Context ctx, Arguments args) {
return getSize(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] getResolution(Context ctx, Arguments args) {
return getResolution(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] getRotation(Context ctx, Arguments args) {
return getRotation(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] getURL(Context ctx, Arguments args) {
return getURL(new OCArguments(args));
}
@Callback(limit = 4)
@Optional.Method(modid = "opencomputers")
public Object[] click(Context ctx, Arguments args) {
return click(new OCArguments(args));
}
@Callback(limit = 4)
@Optional.Method(modid = "opencomputers")
public Object[] type(Context ctx, Arguments args) {
return type(new OCArguments(args));
}
@Callback(limit = 4)
@Optional.Method(modid = "opencomputers")
public Object[] typeAdvanced(Context ctx, Arguments args) {
return typeAdvanced(new OCArguments(args));
}
@Callback(limit = 1)
@Optional.Method(modid = "opencomputers")
public Object[] setURL(Context ctx, Arguments args) {
return setURL(new OCArguments(args));
}
@Callback(limit = 1)
@Optional.Method(modid = "opencomputers")
public Object[] setResolution(Context ctx, Arguments args) {
return setResolution(new OCArguments(args));
}
@Callback(limit = 1)
@Optional.Method(modid = "opencomputers")
public Object[] setRotation(Context ctx, Arguments args) {
return setRotation(new OCArguments(args));
}
@Callback(limit = 4)
@Optional.Method(modid = "opencomputers")
public Object[] runJS(Context ctx, Arguments args) {
return runJS(new OCArguments(args));
}
@Callback
@Optional.Method(modid = "opencomputers")
public Object[] unlink(Context ctx, Arguments args) {
return unlink(new OCArguments(args));
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.entity;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.montoyo.wd.core.IPeripheral;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Vector3i;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class TileEntityPeripheralBase extends TileEntity implements IPeripheral {
protected Vector3i screenPos;
protected BlockSide screenSide;
@Override
public void readFromNBT(NBTTagCompound tag) {
super.readFromNBT(tag);
if(tag.hasKey("WDScreen", 10)) {
NBTTagCompound scr = tag.getCompoundTag("WDScreen");
screenPos = new Vector3i(scr.getInteger("X"), scr.getInteger("Y"), scr.getInteger("Z"));
screenSide = BlockSide.values()[scr.getByte("Side")];
} else {
screenPos = null;
screenSide = null;
}
}
@Override
@Nonnull
public NBTTagCompound writeToNBT(NBTTagCompound tag) {
super.writeToNBT(tag);
if(screenPos != null && screenSide != null) {
NBTTagCompound scr = new NBTTagCompound();
scr.setInteger("X", screenPos.x);
scr.setInteger("Y", screenPos.y);
scr.setInteger("Z", screenPos.z);
scr.setByte("Side", (byte) screenSide.ordinal());
tag.setTag("WDScreen", scr);
}
return tag;
}
@Override
public boolean connect(World world_, BlockPos blockPos, IBlockState blockState, Vector3i pos, BlockSide side) {
TileEntity te = world.getTileEntity(pos.toBlock());
if(te == null || !(te instanceof TileEntityScreen)) {
Log.error("TileEntityPeripheralBase.connect(): Tile entity at %s is not a screen!", pos.toString());
return false;
}
if(((TileEntityScreen) te).getScreen(side) == null) {
Log.error("TileEntityPeripheralBase.connect(): There is no screen at %s on side %s!", pos.toString(), side.toString());
return false;
}
screenPos = pos;
screenSide = side;
markDirty();
return true;
}
public boolean isLinked() {
return screenPos != null && screenSide != null;
}
public boolean isScreenChunkLoaded() {
if(screenPos == null || screenSide == null)
return true;
Chunk chunk = world.getChunkProvider().getLoadedChunk(screenPos.x >> 4, screenPos.z >> 4);
return chunk != null && !chunk.isEmpty();
}
@Nullable
public TileEntityScreen getConnectedScreen() {
if(screenPos == null || screenSide == null)
return null;
TileEntity te = world.getTileEntity(screenPos.toBlock());
if(te == null || !(te instanceof TileEntityScreen) || ((TileEntityScreen) te).getScreen(screenSide) == null) {
screenPos = null;
screenSide = null;
markDirty();
return null;
}
return (TileEntityScreen) te;
}
@Nullable
public TileEntityScreen getConnectedScreenEx() {
if(screenPos == null || screenSide == null)
return null;
TileEntity te = world.getTileEntity(screenPos.toBlock());
if(te == null || !(te instanceof TileEntityScreen) || ((TileEntityScreen) te).getScreen(screenSide) == null)
return null;
return (TileEntityScreen) te;
}
@Nullable
public Vector3i getScreenPos() {
return screenPos;
}
@Nullable
public BlockSide getScreenSide() {
return screenSide;
}
public boolean onRightClick(EntityPlayer player, EnumHand hand, BlockSide side) {
return false;
}
public void onNeighborChange(Block neighborType, BlockPos neighborPos) {
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.EnumHand;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.data.SetURLData;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Util;
public class TileEntityRCtrl extends TileEntityPeripheralBase {
@Override
public boolean onRightClick(EntityPlayer player, EnumHand hand, BlockSide side) {
if(world.isRemote)
return true;
if(!isScreenChunkLoaded()) {
Util.toast(player, "chunkUnloaded");
return true;
}
TileEntityScreen tes = getConnectedScreen();
if(tes == null) {
Util.toast(player, "notLinked");
return true;
}
TileEntityScreen.Screen scr = tes.getScreen(screenSide);
if((scr.rightsFor(player) & ScreenRights.CHANGE_URL) == 0) {
Util.toast(player, "restrictions");
return true;
}
(new SetURLData(screenPos, screenSide, scr.url, pos)).sendTo((EntityPlayerMP) player);
return true;
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.entity;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.data.RedstoneCtrlData;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Util;
import javax.annotation.Nonnull;
public class TileEntityRedCtrl extends TileEntityPeripheralBase {
private String risingEdgeURL = "";
private String fallingEdgeURL = "";
private boolean state = false;
@Override
public void readFromNBT(NBTTagCompound tag) {
super.readFromNBT(tag);
risingEdgeURL = tag.getString("RisingEdgeURL");
fallingEdgeURL = tag.getString("FallingEdgeURL");
state = tag.getBoolean("Powered");
}
@Override
@Nonnull
public NBTTagCompound writeToNBT(NBTTagCompound tag) {
super.writeToNBT(tag);
tag.setString("RisingEdgeURL", risingEdgeURL);
tag.setString("FallingEdgeURL", fallingEdgeURL);
tag.setBoolean("Powered", state);
return tag;
}
@Override
public boolean onRightClick(EntityPlayer player, EnumHand hand, BlockSide side) {
if(world.isRemote)
return true;
if(!isScreenChunkLoaded()) {
Util.toast(player, "chunkUnloaded");
return true;
}
TileEntityScreen tes = getConnectedScreen();
if(tes == null) {
Util.toast(player, "notLinked");
return true;
}
TileEntityScreen.Screen scr = tes.getScreen(screenSide);
if((scr.rightsFor(player) & ScreenRights.CHANGE_URL) == 0) {
Util.toast(player, "restrictions");
return true;
}
(new RedstoneCtrlData(world.provider.getDimension(), pos, risingEdgeURL, fallingEdgeURL)).sendTo((EntityPlayerMP) player);
return true;
}
@Override
public void onNeighborChange(Block neighborType, BlockPos neighborPos) {
boolean hasPower = (world.isBlockPowered(pos) || world.isBlockPowered(pos.up())); //Same as dispenser
if(hasPower != state) {
state = hasPower;
if(state) //Rising edge
changeURL(risingEdgeURL);
else //Falling edge
changeURL(fallingEdgeURL);
}
}
public void setURLs(String r, String f) {
risingEdgeURL = r.trim();
fallingEdgeURL = f.trim();
markDirty();
}
private void changeURL(String url) {
if(world.isRemote || url.isEmpty())
return;
if(isScreenChunkLoaded()) {
TileEntityScreen tes = getConnectedScreen();
if(tes != null)
tes.setScreenURL(screenSide, url);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.data.ServerData;
import net.montoyo.wd.utilities.NameUUIDPair;
import net.montoyo.wd.utilities.Util;
import javax.annotation.Nonnull;
public class TileEntityServer extends TileEntity {
private NameUUIDPair owner;
@Override
public void readFromNBT(NBTTagCompound tag) {
super.readFromNBT(tag);
owner = Util.readOwnerFromNBT(tag);
}
@Override
@Nonnull
public NBTTagCompound writeToNBT(NBTTagCompound tag) {
super.writeToNBT(tag);
return Util.writeOwnerToNBT(tag, owner);
}
public void setOwner(EntityPlayer ep) {
owner = new NameUUIDPair(ep.getGameProfile());
markDirty();
}
public void onPlayerRightClick(EntityPlayer ply) {
if(world.isRemote)
return;
if(WebDisplays.INSTANCE.miniservPort == 0)
Util.toast(ply, "noMiniserv");
else if(owner != null && ply instanceof EntityPlayerMP)
(new ServerData(pos, owner)).sendTo((EntityPlayerMP) ply);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import com.mojang.realmsclient.gui.ChatFormatting;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.CraftComponent;
import net.montoyo.wd.core.HasAdvancement;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ItemCraftComponent extends ItemMulti implements WDItem {
public ItemCraftComponent() {
super(CraftComponent.class);
setUnlocalizedName("webdisplays.craftcomp");
setRegistryName("craftcomp");
setCreativeTab(WebDisplays.CREATIVE_TAB);
//Hide the bad extension card from the creative tab
creativeTabItems.clear(CraftComponent.BAD_EXTENSION_CARD.ordinal());
}
@Override
public void addInformation(ItemStack is, @Nullable World world, List<String> tt, ITooltipFlag ttFlags) {
if(WebDisplays.INSTANCE.doHardRecipe && is.getMetadata() == CraftComponent.EXTENSION_CARD.ordinal() && WebDisplays.PROXY.hasClientPlayerAdvancement(WebDisplays.ADV_PAD_BREAK) != HasAdvancement.YES) {
tt.add("" + ChatFormatting.RED + I18n.format("webdisplays.extcard.cantcraft1"));
tt.add("" + ChatFormatting.RED + I18n.format("webdisplays.extcard.cantcraft2"));
} else if(is.getMetadata() == CraftComponent.BAD_EXTENSION_CARD.ordinal())
tt.add("" + ChatFormatting.RED + I18n.format("webdisplays.extcard.bad"));
else
tt.add("" + ChatFormatting.ITALIC + I18n.format("item.webdisplays.craftcomp.name"));
WDItem.addInformation(tt);
}
@Nullable
@Override
public String getWikiName(@Nonnull ItemStack is) {
return CraftComponent.getWikiName(is.getMetadata());
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.montoyo.wd.WebDisplays;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ItemLaserPointer extends Item implements WDItem {
public ItemLaserPointer() {
setUnlocalizedName("webdisplays.laserpointer");
setRegistryName("laserpointer");
setMaxStackSize(1);
setCreativeTab(WebDisplays.CREATIVE_TAB);
}
@Override
public void addInformation(ItemStack is, @Nullable World world, List<String> tt, ITooltipFlag ttFlags) {
WDItem.addInformation(tt);
}
@Nullable
@Override
public String getWikiName(@Nonnull ItemStack is) {
return "Laser_Pointer";
}
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.core.IPeripheral;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Multiblock;
import net.montoyo.wd.utilities.Util;
import net.montoyo.wd.utilities.Vector3i;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ItemLinker extends Item implements WDItem {
public ItemLinker() {
setUnlocalizedName("webdisplays.linker");
setRegistryName("linker");
setMaxStackSize(1);
setCreativeTab(WebDisplays.CREATIVE_TAB);
}
@Override
@Nonnull
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos_, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
if(world.isRemote)
return EnumActionResult.SUCCESS;
ItemStack stack = player.getHeldItem(hand);
NBTTagCompound tag = stack.getTagCompound();
if(tag != null) {
if(tag.hasKey("ScreenX") && tag.hasKey("ScreenY") && tag.hasKey("ScreenZ") && tag.hasKey("ScreenSide")) {
IBlockState state = world.getBlockState(pos_);
IPeripheral target;
if(state.getBlock() instanceof IPeripheral)
target = (IPeripheral) state.getBlock();
else {
TileEntity te = world.getTileEntity(pos_);
if(te == null || !(te instanceof IPeripheral)) {
if(player.isSneaking()) {
Util.toast(player, TextFormatting.GOLD, "linkAbort");
stack.setTagCompound(null);
} else
Util.toast(player, "peripheral");
return EnumActionResult.SUCCESS;
}
target = (IPeripheral) te;
}
Vector3i tePos = new Vector3i(tag.getInteger("ScreenX"), tag.getInteger("ScreenY"), tag.getInteger("ScreenZ"));
BlockSide scrSide = BlockSide.values()[tag.getByte("ScreenSide")];
if(target.connect(world, pos_, state, tePos, scrSide)) {
Util.toast(player, TextFormatting.AQUA, "linked");
if(player instanceof EntityPlayerMP)
WebDisplays.INSTANCE.criterionLinkPeripheral.trigger(((EntityPlayerMP) player).getAdvancements());
} else
Util.toast(player, "linkError");
stack.setTagCompound(null);
return EnumActionResult.SUCCESS;
}
}
if(!(world.getBlockState(pos_).getBlock() instanceof BlockScreen)) {
Util.toast(player, "notAScreen");
return EnumActionResult.SUCCESS;
}
Vector3i pos = new Vector3i(pos_);
BlockSide side = BlockSide.values()[facing.ordinal()];
Multiblock.findOrigin(world, pos, side, null);
TileEntity te = world.getTileEntity(pos.toBlock());
if(te == null || !(te instanceof TileEntityScreen)) {
Util.toast(player, "turnOn");
return EnumActionResult.SUCCESS;
}
TileEntityScreen.Screen scr = ((TileEntityScreen) te).getScreen(side);
if(scr == null)
Util.toast(player, "turnOn");
else if((scr.rightsFor(player) & ScreenRights.MANAGE_UPGRADES) == 0)
Util.toast(player, "restrictions");
else {
tag = new NBTTagCompound();
tag.setInteger("ScreenX", pos.x);
tag.setInteger("ScreenY", pos.y);
tag.setInteger("ScreenZ", pos.z);
tag.setByte("ScreenSide", (byte) side.ordinal());
stack.setTagCompound(tag);
Util.toast(player, TextFormatting.AQUA, "screenSet2");
}
return EnumActionResult.SUCCESS;
}
@SideOnly(Side.CLIENT)
@Override
public void addInformation(ItemStack stack, @Nullable World world, List<String> tt, ITooltipFlag ttFlag) {
NBTTagCompound tag = stack.getTagCompound();
if(tag != null) {
if(tag.hasKey("ScreenX") && tag.hasKey("ScreenY") && tag.hasKey("ScreenZ") && tag.hasKey("ScreenSide")) {
BlockSide side = BlockSide.fromInt(tag.getByte("ScreenSide"));
if(side == null)
side = BlockSide.BOTTOM;
tt.add(I18n.format("webdisplays.linker.selectPeripheral"));
tt.add(I18n.format("webdisplays.linker.posInfo", tag.getInteger("ScreenX"), tag.getInteger("ScreenY"), tag.getInteger("ScreenZ")));
tt.add(I18n.format("webdisplays.linker.sideInfo", I18n.format("webdisplays.side." + side.toString().toLowerCase())));
WDItem.addInformation(tt);
return;
}
}
tt.add(I18n.format("webdisplays.linker.selectScreen"));
WDItem.addInformation(tt);
}
@Nullable
@Override
public String getWikiName(@Nonnull ItemStack is) {
return "Linking_Tool";
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import com.mojang.realmsclient.gui.ChatFormatting;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundCategory;
import net.minecraft.world.World;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.CraftComponent;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.UUID;
public class ItemMinePad2 extends Item implements WDItem {
public ItemMinePad2() {
setUnlocalizedName("webdisplays.minepad");
setRegistryName("minepad");
setMaxStackSize(1);
setFull3D();
setMaxDamage(0);
setCreativeTab(WebDisplays.CREATIVE_TAB);
}
private static String getURL(ItemStack is) {
if(is.getTagCompound() == null || !is.getTagCompound().hasKey("PadURL"))
return WebDisplays.INSTANCE.homePage;
else
return is.getTagCompound().getString("PadURL");
}
@Override
@Nonnull
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer ply, @Nonnull EnumHand hand) {
ItemStack is = ply.getHeldItem(hand);
boolean ok;
if(ply.isSneaking()) {
if(world.isRemote)
WebDisplays.PROXY.displaySetPadURLGui(getURL(is));
ok = true;
} else if(is.getTagCompound() != null && is.getTagCompound().hasKey("PadID")) {
if(world.isRemote)
WebDisplays.PROXY.openMinePadGui(is.getTagCompound().getInteger("PadID"));
ok = true;
} else
ok = false;
return ActionResult.newResult(ok ? EnumActionResult.SUCCESS : EnumActionResult.PASS, is);
}
@Override
public void addInformation(ItemStack is, @Nullable World world, List<String> tt, ITooltipFlag ttFlags) {
if(is.getTagCompound() == null || !is.getTagCompound().hasKey("PadID"))
tt.add("" + ChatFormatting.ITALIC + ChatFormatting.GRAY + I18n.format("webdisplays.minepad.turnon"));
if(is.getMetadata() > 0)
tt.add("" + ChatFormatting.RED + I18n.format("webdisplays.minepad2.info"));
WDItem.addInformation(tt);
}
@Override
public boolean onEntityItemUpdate(EntityItem ent) {
if(ent.onGround && !ent.world.isRemote) {
NBTTagCompound tag = ent.getItem().getTagCompound();
if(tag != null && tag.hasKey("ThrowHeight")) {
//Delete it, it touched the ground
double height = tag.getDouble("ThrowHeight");
UUID thrower = null;
if(tag.hasKey("ThrowerMSB") && tag.hasKey("ThrowerLSB"))
thrower = new UUID(tag.getLong("ThrowerMSB"), tag.getLong("ThrowerLSB"));
if(tag.hasKey("PadID") || tag.hasKey("PadURL")) {
tag.removeTag("ThrowerMSB");
tag.removeTag("ThrowerLSB");
tag.removeTag("ThrowHeight");
} else //We can delete the whole tag
ent.getItem().setTagCompound(null);
if(thrower != null && height - ent.posY >= 20.0) {
ent.world.playSound(null, ent.posX, ent.posY, ent.posZ, SoundEvents.BLOCK_GLASS_BREAK, SoundCategory.BLOCKS, 4.0f, 1.0f);
ent.world.spawnEntity(new EntityItem(ent.world, ent.posX, ent.posY, ent.posZ, CraftComponent.EXTENSION_CARD.makeItemStack()));
ent.setDead();
EntityPlayer ply = ent.world.getPlayerEntityByUUID(thrower);
if(ply != null && ply instanceof EntityPlayerMP)
WebDisplays.INSTANCE.criterionPadBreak.trigger(((EntityPlayerMP) ply).getAdvancements());
}
}
}
return false;
}
@Override
@Nonnull
public String getUnlocalizedName(ItemStack stack) {
String ret = getUnlocalizedName();
if(stack.getMetadata() > 0)
ret += "2";
return ret;
}
@Nullable
@Override
public String getWikiName(@Nonnull ItemStack is) {
return "Mine_Pad";
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList;
import javax.annotation.Nonnull;
import java.util.BitSet;
public class ItemMulti extends Item {
protected final Enum[] values;
protected final BitSet creativeTabItems;
public ItemMulti(Class<? extends Enum> cls) {
values = cls.getEnumConstants();
creativeTabItems = new BitSet(values.length);
creativeTabItems.set(0, values.length);
setHasSubtypes(true);
setMaxDamage(0);
}
@Override
@Nonnull
public String getUnlocalizedName(ItemStack stack) {
int meta = stack.getMetadata();
String ret = getUnlocalizedName();
if(meta >= 0 && meta < values.length)
return ret + '.' + values[meta];
else
return ret;
}
@Override
public void getSubItems(@Nonnull CreativeTabs tab, @Nonnull NonNullList<ItemStack> items) {
if(isInCreativeTab(tab)) {
for(int i = 0; i < values.length; i++) {
if(creativeTabItems.get(i))
items.add(new ItemStack(this, 1, i));
}
}
}
public Enum[] getEnumValues() {
return values;
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ItemOwnershipThief extends Item implements WDItem {
public ItemOwnershipThief() {
setUnlocalizedName("webdisplays.ownerthief");
setRegistryName("ownerthief");
setMaxStackSize(1);
setCreativeTab(WebDisplays.CREATIVE_TAB);
}
@Override
@Nonnull
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos_, EnumHand hand, EnumFacing side_, float hitX, float hitY, float hitZ) {
if(player.isSneaking())
return EnumActionResult.PASS;
if(world.isRemote)
return EnumActionResult.SUCCESS;
if(WebDisplays.INSTANCE.disableOwnershipThief) {
Util.toast(player, "otDisabled");
return EnumActionResult.SUCCESS;
}
ItemStack stack = player.getHeldItem(hand);
if(stack.hasTagCompound()) {
NBTTagCompound tag = stack.getTagCompound();
if(tag.hasKey("PosX") && tag.hasKey("PosY") && tag.hasKey("PosZ") && tag.hasKey("Side")) {
BlockPos bp = new BlockPos(tag.getInteger("PosX"), tag.getInteger("PosY"), tag.getInteger("PosZ"));
BlockSide side = BlockSide.values()[tag.getByte("Side")];
if(!(world.getBlockState(bp).getBlock() instanceof BlockScreen))
return EnumActionResult.SUCCESS;
TileEntity te = world.getTileEntity(bp);
if(te == null || !(te instanceof TileEntityScreen))
return EnumActionResult.SUCCESS;
TileEntityScreen tes = (TileEntityScreen) te;
TileEntityScreen.Screen scr = tes.getScreen(side);
if(scr == null)
return EnumActionResult.SUCCESS;
Log.warning("Owner of screen at %d %d %d, side %s was changed from %s (UUID %s) to %s (UUID %s)", bp.getX(), bp.getY(), bp.getZ(), side.toString(), scr.owner.name, scr.owner.uuid.toString(), player.getName(), player.getGameProfile().getId().toString());
player.setHeldItem(hand, ItemStack.EMPTY);
tes.setOwner(side, player);
Util.toast(player, TextFormatting.AQUA, "newOwner");
return EnumActionResult.SUCCESS;
}
}
if(!(world.getBlockState(pos_).getBlock() instanceof BlockScreen))
return EnumActionResult.SUCCESS;
Vector3i pos = new Vector3i(pos_);
BlockSide side = BlockSide.values()[side_.ordinal()];
Multiblock.findOrigin(world, pos, side, null);
TileEntity te = world.getTileEntity(pos.toBlock());
if(te == null || !(te instanceof TileEntityScreen)) {
Util.toast(player, "turnOn");
return EnumActionResult.SUCCESS;
}
if(((TileEntityScreen) te).getScreen(side) == null)
Util.toast(player, "turnOn");
else {
NBTTagCompound tag = new NBTTagCompound();
tag.setInteger("PosX", pos.x);
tag.setInteger("PosY", pos.y);
tag.setInteger("PosZ", pos.z);
tag.setByte("Side", (byte) side.ordinal());
stack.setTagCompound(tag);
Util.toast(player, TextFormatting.AQUA, "screenSet");
Log.warning("Player %s (UUID %s) created an Ownership Thief item for screen at %d %d %d, side %s!", player.getName(), player.getGameProfile().getId().toString(), pos.x, pos.y, pos.z, side.toString());
}
return EnumActionResult.SUCCESS;
}
@SideOnly(Side.CLIENT)
@Override
public void addInformation(ItemStack stack, @Nullable World world, List<String> tt, ITooltipFlag ttFlags) {
if(stack.hasTagCompound()) {
NBTTagCompound tag = stack.getTagCompound();
if(tag.hasKey("PosX") && tag.hasKey("PosY") && tag.hasKey("PosZ") && tag.hasKey("Side")) {
tt.add("Screen pos: " + tag.getInteger("PosX") + ", " + tag.getInteger("PosY") + ", " + tag.getInteger("PosZ"));
tt.add("Screen side: " + BlockSide.values()[tag.getByte("Side")].toString());
WDItem.addInformation(tt);
return;
}
}
tt.add("" + TextFormatting.RED + "WARNING: Admin tool");
tt.add("Right click on screen");
tt.add("and give to new owner.");
WDItem.addInformation(tt);
}
@Nullable
@Override
public String getWikiName(@Nonnull ItemStack is) {
return "Ownership_Thief";
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2019 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import com.mojang.realmsclient.gui.ChatFormatting;
import net.minecraft.block.Block;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemMultiTexture;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockKeyboardRight;
import net.montoyo.wd.core.DefaultPeripheral;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ItemPeripheral extends ItemMultiTexture implements WDItem {
public ItemPeripheral(Block block) {
super(block, block, (is) -> DefaultPeripheral.fromMetadata(is.getMetadata()).getName());
}
@Override
public boolean canPlaceBlockOnSide(World world, @Nonnull BlockPos pos_, @Nonnull EnumFacing side, EntityPlayer player, ItemStack stack) {
if(stack.getMetadata() != 0) //Keyboard
return true;
//Special checks for the keyboard
BlockPos pos = pos_.add(side.getDirectionVec());
if(world.isAirBlock(pos.down()) || !BlockKeyboardRight.checkNeighborhood(world, pos, null))
return false;
int f = MathHelper.floor(((double) (player.rotationYaw * 4.0f / 360.0f)) + 2.5) & 3;
Vec3i dir = EnumFacing.getHorizontal(f).rotateY().getDirectionVec();
BlockPos left = pos.add(dir);
BlockPos right = pos.subtract(dir);
if(world.isAirBlock(right) && !world.isAirBlock(right.down()) && BlockKeyboardRight.checkNeighborhood(world, right, null))
return true;
else
return world.isAirBlock(left) && !world.isAirBlock(left.down()) && BlockKeyboardRight.checkNeighborhood(world, left, null);
}
@Override
public void addInformation(@Nullable ItemStack is, @Nullable World world, @Nullable List<String> tt, @Nullable ITooltipFlag ttFlags) {
super.addInformation(is, world, tt, ttFlags);
if(is != null && tt != null) {
if(is.getMetadata() == 1 && !WebDisplays.isComputerCraftAvailable()) //CC Interface
tt.add("" + ChatFormatting.RED + I18n.format("webdisplays.message.missingCC"));
else if(is.getMetadata() == 2 && !WebDisplays.isOpenComputersAvailable()) //OC Interface
tt.add("" + ChatFormatting.RED + I18n.format("webdisplays.message.missingOC"));
else if(is.getMetadata() == 11 && WebDisplays.PROXY.isMiniservDisabled()) //Server
tt.add("" + ChatFormatting.RED + I18n.format("webdisplays.message.noMiniserv"));
}
WDItem.addInformation(tt);
}
@Nullable
@Override
public String getWikiName(@Nonnull ItemStack is) {
return DefaultPeripheral.fromMetadata(is.getMetadata()).getWikiName();
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.data.ScreenConfigData;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Multiblock;
import net.montoyo.wd.utilities.Util;
import net.montoyo.wd.utilities.Vector3i;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ItemScreenConfigurator extends Item implements WDItem {
public ItemScreenConfigurator() {
setUnlocalizedName("webdisplays.screencfg");
setRegistryName("screencfg");
setMaxStackSize(1);
setCreativeTab(WebDisplays.CREATIVE_TAB);
}
@Override
@Nonnull
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing side_, float hitX, float hitY, float hitZ) {
if(player.isSneaking() || !(world.getBlockState(pos).getBlock() instanceof BlockScreen))
return EnumActionResult.PASS;
if(world.isRemote)
return EnumActionResult.SUCCESS;
Vector3i origin = new Vector3i(pos);
BlockSide side = BlockSide.values()[side_.ordinal()];
Multiblock.findOrigin(world, origin, side, null);
TileEntity te = world.getTileEntity(origin.toBlock());
if(te == null || !(te instanceof TileEntityScreen)) {
Util.toast(player, "turnOn");
return EnumActionResult.SUCCESS;
}
TileEntityScreen.Screen scr = ((TileEntityScreen) te).getScreen(side);
if(scr == null)
Util.toast(player, "turnOn");
else
(new ScreenConfigData(origin, side, scr)).sendTo((EntityPlayerMP) player);
return EnumActionResult.SUCCESS;
}
@Override
public void addInformation(ItemStack is, @Nullable World world, List<String> tt, ITooltipFlag ttFlags) {
WDItem.addInformation(tt);
}
@Nullable
@Override
public String getWikiName(@Nonnull ItemStack is) {
return "Screen_Configurator";
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import com.mojang.realmsclient.gui.ChatFormatting;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.DefaultUpgrade;
import net.montoyo.wd.core.IUpgrade;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ItemUpgrade extends ItemMulti implements IUpgrade, WDItem {
public ItemUpgrade() {
super(DefaultUpgrade.class);
setUnlocalizedName("webdisplays.upgrade");
setRegistryName("upgrade");
setCreativeTab(WebDisplays.CREATIVE_TAB);
}
@Override
public void onInstall(@Nonnull TileEntityScreen tes, @Nonnull BlockSide screenSide, @Nullable EntityPlayer player, @Nonnull ItemStack is) {
}
@Override
public boolean onRemove(@Nonnull TileEntityScreen tes, @Nonnull BlockSide screenSide, @Nullable EntityPlayer player, @Nonnull ItemStack is) {
if(is.getMetadata() == DefaultUpgrade.LASER_MOUSE.ordinal())
tes.clearLaserUser(screenSide);
return false;
}
@Override
public boolean isSameUpgrade(@Nonnull ItemStack myStack, @Nonnull ItemStack otherStack) {
return otherStack.getItem() == this && otherStack.getMetadata() == myStack.getMetadata();
}
@Override
public void addInformation(ItemStack is, @Nullable World world, List<String> tt, ITooltipFlag ttFlags) {
tt.add("" + ChatFormatting.ITALIC + I18n.format("item.webdisplays.upgrade.name"));
WDItem.addInformation(tt);
}
@Override
public String getJSName(@Nonnull ItemStack is) {
int meta = is.getMetadata();
DefaultUpgrade[] upgrades = DefaultUpgrade.values();
if(meta < 0 || meta >= upgrades.length)
return "webdisplays:wtf";
else
return "webdisplays:" + upgrades[meta];
}
@Nullable
@Override
public String getWikiName(@Nonnull ItemStack is) {
return DefaultUpgrade.getWikiName(is.getMetadata());
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import com.mojang.realmsclient.gui.ChatFormatting;
import net.minecraft.client.resources.I18n;
import net.minecraft.item.ItemStack;
import net.montoyo.wd.WebDisplays;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public interface WDItem {
@Nullable
String getWikiName(@Nonnull ItemStack is);
static void addInformation(@Nullable List<String> tt) {
if(tt != null && WebDisplays.PROXY.isShiftDown())
tt.add("" + ChatFormatting.GRAY + I18n.format("item.webdisplays.wiki"));
}
}

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