+ Added base files

This commit is contained in:
Nicolas BARBOTIN 2018-01-26 18:03:02 +01:00
commit 2d29747888
154 changed files with 12796 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

56
build.gradle Normal file
View File

@ -0,0 +1,56 @@
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.0"
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.1.2555"
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.
}
dependencies {
}
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

Binary file not shown.

View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd;
import com.mojang.authlib.GameProfile;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.fml.server.FMLServerHandler;
import net.montoyo.mcef.utilities.Log;
import net.montoyo.wd.data.GuiData;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.NameUUIDPair;
import net.montoyo.wd.utilities.Vector2i;
import net.montoyo.wd.utilities.Vector3i;
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 displaySetPadURLGui(String padURL) {
Log.error("Called SharedProxy.displaySetPadURLGui() on server side...");
}
public void openMinePadGui(int padId) {
Log.error("Called SharedProxy.openMinePadGui() on server side...");
}
}

View File

@ -0,0 +1,193 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
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.DefaultPeripheral;
import net.montoyo.wd.core.WDCreativeTab;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.item.ItemLinker;
import net.montoyo.wd.item.ItemMinePad2;
import net.montoyo.wd.item.ItemOwnershipThief;
import net.montoyo.wd.item.ItemScreenConfigurator;
import net.montoyo.wd.net.Messages;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Util;
import java.io.*;
@Mod(modid = "webdisplays", version = WebDisplays.MOD_VERSION, dependencies = "required-after:mcef;")
public class WebDisplays {
public static final String MOD_VERSION = "1.0";
@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;
//Blocks
public BlockScreen blockScreen;
public BlockPeripheral blockPeripheral;
public BlockKeyboardRight blockKbRight;
//Items
public ItemScreenConfigurator itemScreenCfg;
public ItemOwnershipThief itemOwnerThief;
public ItemLinker itemLinker;
public Item itemStoneKey;
public ItemMinePad2 itemMinePad;
//Sounds
public SoundEvent soundTyping;
//Config
public static final double PAD_RATIO = 59.0 / 30.0;
public String homePage = "https://google.com"; //TODO: Read from config
public double padResX;
public double padResY;
private int lastPadId = 0;
@Mod.EventHandler
public void onPreInit(FMLPreInitializationEvent ev) {
CREATIVE_TAB = new WDCreativeTab();
//TODO: Read configuration
final int padHeight = 480;
padResY = (double) padHeight;
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();
itemStoneKey = new Item();
itemStoneKey.setCreativeTab(CREATIVE_TAB);
itemStoneKey.setUnlocalizedName("webdisplays.stonekey");
itemStoneKey.setRegistryName("stonekey");
PROXY.preInit();
MinecraftForge.EVENT_BUS.register(this);
}
@Mod.EventHandler
public void onInit(FMLInitializationEvent ev) {
//Register tile entities
GameRegistry.registerTileEntity(TileEntityScreen.class, "webdisplays:screen");
for(DefaultPeripheral dp: DefaultPeripheral.values()) {
if(dp.getTEClass() != null)
GameRegistry.registerTileEntity(dp.getTEClass(), "webdisplays:" + dp.getName());
}
//Other things
PROXY.init();
NET_HANDLER = NetworkRegistry.INSTANCE.newSimpleChannel("webdisplays");
Messages.registerAll(NET_HANDLER);
}
@Mod.EventHandler
public void onPostInit(FMLPostInitializationEvent ev) {
PROXY.postInit();
}
@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, itemStoneKey, itemMinePad);
}
@SubscribeEvent
public void onRegisterSounds(RegistryEvent.Register<SoundEvent> ev) {
soundTyping = new SoundEvent(new ResourceLocation("webdisplays", "keyboardType"));
soundTyping.setRegistryName(soundTyping.getSoundName());
ev.getRegistry().register(soundTyping);
}
@SubscribeEvent
public void onWorldLoad(WorldEvent.Load ev) {
if(ev.getWorld().isRemote || ev.getWorld().provider.getDimension() != 0)
return;
File f = new File(ev.getWorld().getSaveHandler().getWorldDirectory(), "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());
}
}
}
@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());
}
}
public static int getNextAvailablePadID() {
return INSTANCE.lastPadId++;
}
}

View File

@ -0,0 +1,218 @@
/*
* 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 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
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
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
return KEYBOARD_AABB;
}
@Override
public IBlockState getStateFromMeta(int meta) {
return getDefaultState().withProperty(facing, meta);
}
@Override
public int getMetaFromState(IBlockState state) {
return state.getValue(facing);
}
@Override
public ItemStack getPickBlock(IBlockState state, RayTraceResult target, World world, BlockPos pos, EntityPlayer player) {
return new ItemStack(WebDisplays.INSTANCE.blockPeripheral, 1, 0);
}
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
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(IBlockState state, World world, BlockPos pos, 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,243 @@
/*
* 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.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.montoyo.wd.WebDisplays;
import net.montoyo.wd.core.DefaultPeripheral;
import net.montoyo.wd.entity.TileEntityKeyboard;
import net.montoyo.wd.entity.TileEntityPeripheralBase;
import net.montoyo.wd.item.ItemLinker;
import net.montoyo.wd.item.ItemPeripheral;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import javax.annotation.Nullable;
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
protected BlockStateContainer createBlockState() {
return new BlockStateContainer(this, properties);
}
@Override
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing rrezozei, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer, EnumHand hand) {
int rot = MathHelper.floor(((double) (placer.rotationYaw * 4.0f / 360.0f)) + 2.5) & 3;
return getDefaultState().withProperty(type, DefaultPeripheral.values()[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.ordinal()));
}
@Override
public IBlockState getStateFromMeta(int meta) {
return getDefaultState().withProperty(type, DefaultPeripheral.values()[meta & 3]).withProperty(facing, (meta >> 2) & 3);
}
@Override
public int getMetaFromState(IBlockState state) {
return state.getValue(type).ordinal() | (state.getValue(facing) << 2);
}
@Nullable
@Override
public TileEntity createNewTileEntity(World world, int meta) {
Class<? extends TileEntityPeripheralBase> cls = DefaultPeripheral.values()[meta & 3].getTEClass();
if(cls == null)
return null;
try {
return cls.newInstance();
} catch(Throwable t) {
Log.errorEx("Couldn't instantiate peripheral TileEntity:", t);
}
return null;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state) {
return EnumBlockRenderType.MODEL;
}
@Override
public int damageDropped(IBlockState state) {
return state.getValue(type).ordinal();
}
@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 == null || !(te instanceof TileEntityPeripheralBase))
return false;
return ((TileEntityPeripheralBase) te).onRightClick(player, hand, BlockSide.values()[facing.ordinal()]);
}
@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
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 || state.getValue(type) != DefaultPeripheral.KEYBOARD)
return;
//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);
}
@Override
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) {
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);
}
}
@Override
public void onBlockDestroyedByPlayer(World world, BlockPos pos, IBlockState state) {
if(!world.isRemote && state.getValue(type) == DefaultPeripheral.KEYBOARD)
removeRightPiece(world, pos);
}
@Override
public void onBlockDestroyedByExplosion(World world, BlockPos pos, Explosion explosion) {
if(!world.isRemote && world.getBlockState(pos).getValue(type) == DefaultPeripheral.KEYBOARD)
removeRightPiece(world, 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);
}
}
}
}

View File

@ -0,0 +1,253 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.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.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
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.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.ScreenRights;
import net.montoyo.wd.data.SetURLData;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.*;
import javax.annotation.Nullable;
public class BlockScreen extends WDBlockContainer {
public static final PropertyBool hasTE = PropertyBool.create("haste");
private static final IProperty[] properties = new IProperty[] { hasTE };
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));
}
public static final int BAR_BOT = 1;
public static final int BAR_RIGHT = 2;
public static final int BAR_TOP = 4;
public static final int BAR_LEFT = 8;
public BlockScreen() {
super(Material.ROCK);
setHardness(1.5f);
setResistance(10.f);
setCreativeTab(WebDisplays.CREATIVE_TAB);
setName("screen");
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state) {
return EnumBlockRenderType.MODEL;
}
@Override
protected BlockStateContainer createBlockState() {
return new ExtendedBlockState(this, properties, sideFlags);
}
public static boolean isScreenBlock(IBlockAccess world, Vector3i pos) {
return world.getBlockState(pos.toBlock()).getBlock() instanceof BlockScreen;
}
@Override
public IBlockState getExtendedState(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(!isScreenBlock(world, side.up.clone().add(pos))) icon |= BAR_TOP;
if(!isScreenBlock(world, side.down.clone().add(pos))) icon |= BAR_BOT;
if(!isScreenBlock(world, side.left.clone().add(pos))) icon |= BAR_LEFT;
if(!isScreenBlock(world, side.right.clone().add(pos))) icon |= BAR_RIGHT;
ret = ret.withProperty(sideFlags[side.ordinal()], icon);
}
return ret;
}
@Override
public IBlockState getStateFromMeta(int meta) {
return getDefaultState().withProperty(hasTE, meta != 0);
}
@Override
public int getMetaFromState(IBlockState state) {
return state.getValue(hasTE) ? 1 : 0;
}
@Override
public boolean onBlockActivated(World world, BlockPos bpos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
if(!player.getHeldItem(hand).isEmpty())
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((scr.rightsFor(player) & ScreenRights.CLICK) == 0) {
Util.toast(player, "restrictions");
return true;
}
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;
cx *= (float) scr.resolution.x;
cy *= (float) scr.resolution.y;
te.click(side, new Vector2i((int) cx, (int) cy));
}
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;
}
Vector3i err = Multiblock.check(world, pos, size, side);
if(err != null) {
Util.toast(player, "invalid", err.toString());
return true;
}
boolean created = false;
Log.info("Structure at %s of size %dx%d", pos.toString(), size.x, size.y);
if(te == null) {
BlockPos bp = pos.toBlock();
world.setBlockState(bp, getDefaultState().withProperty(hasTE, true));
te = (TileEntityScreen) world.getTileEntity(bp);
created = true;
}
te.addScreen(side, size, null, !created).setOwner(player);
return true;
}
@Nullable
@Override
public TileEntity createNewTileEntity(World world, int meta) {
return meta == 0 ? null : new TileEntityScreen();
}
@Override
public void onBlockDestroyedByPlayer(World world, BlockPos pos, IBlockState dontCare) {
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);
}
}
private void destroySide(World world, Vector3i pos, BlockSide side, Multiblock.BlockOverride override) {
Multiblock.findOrigin(world, pos, side, override);
BlockPos bp = pos.toBlock();
TileEntity te = world.getTileEntity(bp);
if(te != null && te instanceof TileEntityScreen)
world.setBlockState(bp, getDefaultState().withProperty(hasTE, false)); //Destroy tile entity
}
@Override
public EnumPushReaction getMobilityFlag(IBlockState state) {
return EnumPushReaction.IGNORE;
}
@Override
public void onBlockDestroyedByExplosion(World world, BlockPos pos, Explosion explosion) {
onBlockDestroyedByPlayer(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);
}
}
}
}

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,46 @@
/*
* 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 mat, MapColor color) {
super(mat, color);
}
public WDBlockContainer(Material material) {
super(material);
}
protected void setName(String name) {
setUnlocalizedName("webdisplays." + name);
setRegistryName(name);
}
protected ItemBlock createItemBlock() {
return new ItemBlock(this);
}
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,376 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client;
import com.mojang.authlib.GameProfile;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
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.IResourceManagerReloadListener;
import net.minecraft.client.resources.SimpleReloadableResourceManager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumHandSide;
import net.minecraft.util.NonNullList;
import net.minecraft.world.World;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.MinecraftForge;
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.IBrowser;
import net.montoyo.mcef.api.IDisplayHandler;
import net.montoyo.mcef.api.MCEFApi;
import net.montoyo.wd.SharedProxy;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.gui.GuiMinePad;
import net.montoyo.wd.client.gui.GuiScreenConfig;
import net.montoyo.wd.client.gui.GuiSetURL2;
import net.montoyo.wd.client.gui.WDScreen;
import net.montoyo.wd.client.gui.loading.GuiLoader;
import net.montoyo.wd.client.renderers.IModelBaker;
import net.montoyo.wd.client.renderers.MinePadRenderer;
import net.montoyo.wd.client.renderers.ScreenBaker;
import net.montoyo.wd.client.renderers.ScreenRenderer;
import net.montoyo.wd.data.GuiData;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.net.SMessagePadCtrl;
import net.montoyo.wd.utilities.*;
import java.util.ArrayList;
import java.util.HashMap;
public class ClientProxy extends SharedProxy implements IResourceManagerReloadListener, IDisplayHandler {
public class PadData {
public IBrowser view;
private boolean isInHotbar;
private int id;
private long lastURLSent;
private PadData(String url, int id) {
view = mcef.createBrowser(url);
view.resize((int) WebDisplays.INSTANCE.padResX, (int) WebDisplays.INSTANCE.padResY);
isInHotbar = true;
this.id = id;
}
}
private Minecraft mc;
private ArrayList<ResourceModelPair> modelBakers = new ArrayList<>();
private net.montoyo.mcef.api.API mcef;
private MinePadRenderer minePadRenderer;
//Tracking
private ArrayList<TileEntityScreen> screenTracking = new ArrayList<>();
private double unloadDistance2 = 32.0 * 32.0;
private double loadDistance2 = 30.0 * 30.0;
private int lastTracked = 0;
//MinePads Management
private HashMap<Integer, PadData> padMap = new HashMap<>();
private 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);
}
@Override
public void init() {
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityScreen.class, new ScreenRenderer());
mcef = MCEFApi.getAPI();
minePadRenderer = new MinePadRenderer();
}
@Override
public void postInit() {
((SimpleReloadableResourceManager) mc.getResourceManager()).registerReloadListener(this);
if(mcef == null)
throw new RuntimeException("MCEF is missing");
mcef.registerDisplayHandler(this);
}
@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
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.isScreen(pos, side))
gsc.updateResolution(res);
}
}
@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));
}
/**************************************** RESOURCE MANAGER METHODS ****************************************/
@Override
public void onResourceManagerReload(IResourceManager rm) {
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) {
pd.lastURLSent = t; //Avoid spamming the server with porn URLs
WebDisplays.NET_HANDLER.sendToServer(new SMessagePadCtrl(pd.id, url));
break;
}
}
}
}
@Override
public void onTitleChange(IBrowser browser, String title) {
}
@Override
public void onTooltip(IBrowser browser, String text) {
}
@Override
public void onStatusMessage(IBrowser browser, String value) {
}
/**************************************** 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;
registerItemModel(wd.blockScreen.getItem(), 0, "inventory");
ModelLoader.setCustomModelResourceLocation(wd.blockPeripheral.getItem(), 0, new ModelResourceLocation("webdisplays:kb_inv", "normal"));
registerItemModel(wd.blockPeripheral.getItem(), 1, "facing=0,type=remotectrl");
registerItemModel(wd.blockPeripheral.getItem(), 2, "facing=0,type=ccinterface"); //TODO: This doesn't work...
registerItemModel(wd.blockPeripheral.getItem(), 3, "facing=0,type=cointerface");
registerItemModel(wd.itemScreenCfg, 0, "normal");
registerItemModel(wd.itemOwnerThief, 0, "normal");
registerItemModel(wd.itemLinker, 0, "normal");
registerItemModel(wd.itemStoneKey, 0, "normal");
registerItemModel(wd.itemMinePad, 0, "normal");
}
@SubscribeEvent
public void onTick(TickEvent.ClientTickEvent ev) {
if(ev.phase == TickEvent.Phase.END) {
//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 > unloadDistance2)
tes.unload();
else
tes.updateTrackDistance(dist2);
} else if(dist2 <= 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);
}
}
}
}
}
@SubscribeEvent
public void onRenderPlayerHand(RenderSpecificHandEvent ev) {
if(ev.getItemStack().getItem() == WebDisplays.INSTANCE.itemMinePad) {
EnumHandSide handSide = mc.player.getPrimaryHand();
if(ev.getHand() == EnumHand.OFF_HAND)
handSide = handSide.opposite();
minePadRenderer.render(ev.getItemStack(), (handSide == EnumHandSide.RIGHT) ? 1.0f : -1.0f, ev.getSwingProgress(), ev.getEquipProgress());
ev.setCanceled(true);
}
}
/**************************************** OTHER METHODS ****************************************/
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 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;
}
}

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 ModelResourceLocation resLoc;
private 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,24 @@
/*
* 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;
public class StaticStateMapper extends StateMapperBase {
private ModelResourceLocation resLoc;
public StaticStateMapper(ModelResourceLocation rl) {
resLoc = rl;
}
@Override
protected ModelResourceLocation getModelResourceLocation(IBlockState state) {
return resLoc;
}
}

View File

@ -0,0 +1,219 @@
/*
* Copyright (C) 2018 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.SMessageScreenCtrl;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Util;
import org.lwjgl.input.Keyboard;
import java.io.*;
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 String eventStack = "";
private boolean lastIsType = false;
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(chr == '\n' || chr == '\r' || chr == '\b') {
if(lastIsType)
lastIsType = false;
if(!eventStack.isEmpty())
eventStack += (char) 1;
if(Keyboard.getEventKeyState())
eventStack += 'p';
else
eventStack += 'r';
eventStack += chr;
} else if(chr != 0) {
if(!lastIsType) {
if(!eventStack.isEmpty())
eventStack += (char) 1;
eventStack += 't';
lastIsType = true;
}
eventStack += chr;
}
}
}
if(!eventStack.isEmpty() && !syncRequested())
requestSync();
}
}
@Override
public boolean doesGuiPauseGame() {
return false;
}
@Override
protected void sync() {
if(!eventStack.isEmpty()) {
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.type(tes, side, eventStack, kbPos));
eventStack = "";
lastIsType = false;
}
}
@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);
}
}
}

View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2018 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.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.client.ClientProxy;
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();
boolean pressed = Keyboard.getEventKeyState();
if(Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) {
mc.displayGuiScreen(null);
return;
}
if(pad.view != null) {
if(key != '.' && key != ';' && key != ',') {
if(pressed)
pad.view.injectKeyPressed(key, 0);
else
pad.view.injectKeyReleased(key, 0);
}
if(key != Keyboard.CHAR_NONE)
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 doesGuiPauseGame() {
//TODO: Is this necessary??
return false;
}
}

View File

@ -0,0 +1,415 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import net.minecraft.util.ResourceLocation;
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.net.SMessageScreenCtrl;
import net.montoyo.wd.utilities.*;
import java.util.ArrayList;
import java.util.Arrays;
public class GuiScreenConfig extends WDScreen {
//Screen data
private TileEntityScreen tes;
private BlockSide side;
private NameUUIDPair owner;
private NameUUIDPair[] friends;
private int friendRights;
private int otherRights;
//Autocomplete handling
private boolean waitingAC;
private int acFailTicks = -1;
private ArrayList<NameUUIDPair> acResults = new ArrayList<NameUUIDPair>();
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;
private CheckBox[] friendBoxes;
private CheckBox[] otherBoxes;
public GuiScreenConfig(TileEntityScreen tes, BlockSide side, NameUUIDPair owner, NameUUIDPair[] friends, int fr, int or) {
this.tes = tes;
this.side = side;
this.owner = owner;
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) {
tfResX.setText("" + scr.resolution.x);
tfResY.setText("" + scr.resolution.y);
}
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();
}
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(new SMessageScreenCtrl(tes, side, 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();
}
@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;
}
}
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();
}
}
public boolean isFriendCheckbox(CheckBox cb) {
for(CheckBox box : friendBoxes) {
if(box == cb)
return true;
}
return false;
}
public boolean isOtherCheckbox(CheckBox cb) {
for(CheckBox box : otherBoxes) {
if(box == cb)
return true;
}
return false;
}
public boolean hasFriend(NameUUIDPair f) {
for(NameUUIDPair pair : friends) {
if(pair.equals(f))
return true;
}
return false;
}
@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);
}
public boolean isScreen(Vector3i pos, BlockSide side) {
return pos.x == tes.getPos().getX() && pos.y == tes.getPos().getY() && pos.z == tes.getPos().getZ() && side == this.side;
}
@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 = 0;
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);
if(flag)
btnSetRes.setDisabled(true);
}
public void updateResolution(Vector2i res) {
tfResX.setText("" + res.x);
tfResY.setText("" + res.y);
btnSetRes.setDisabled(true);
}
}

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import net.minecraft.util.ResourceLocation;
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.entity.TileEntityScreen;
import net.montoyo.wd.net.SMessagePadCtrl;
import net.montoyo.wd.net.SMessageScreenCtrl;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import java.util.Map;
public class GuiSetURL2 extends WDScreen {
//Screen data
private TileEntityScreen tileEntity;
private BlockSide screenSide;
//Pad data
private boolean isPad;
//Common
private String screenURL;
@FillControl
private TextField tfURL;
@FillControl
private Button btnShutDown;
@FillControl
private Button btnCancel;
@FillControl
private Button btnOk;
@FillControl
private Button btnYT;
public GuiSetURL2(TileEntityScreen tes, BlockSide side, String url) {
tileEntity = tes;
screenSide = side;
screenURL = url;
isPad = false;
}
public GuiSetURL2(String url) {
screenURL = url;
isPad = true;
}
@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);
} else
Log.info("GuiSetURL2: TODO"); //TODO
}
@GuiSubscribe
public void onEnterPressed(TextField.EnterPressedEvent ev) {
validate(ev.getText());
}
private void validate(String url) {
if(!url.isEmpty()) {
if(isPad)
WebDisplays.NET_HANDLER.sendToServer(new SMessagePadCtrl(url));
else
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tileEntity, screenSide, url));
}
mc.displayGuiScreen(null);
}
}

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,353 @@
/*
* 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.util.ResourceLocation;
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.loading.FillControl;
import net.montoyo.wd.client.gui.loading.GuiLoader;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import net.montoyo.wd.net.SMessageACQuery;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.NameUUIDPair;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
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 ArrayList<Control> controls = new ArrayList<Control>();
private HashMap<Class<? extends Event>, Method> eventMap = new HashMap<Class<? extends Event>, Method>();
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
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int maxY = Integer.MIN_VALUE;
for(Control ctrl : controls) {
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;
}
//Translation vector
int diffX = (width - maxX - minX) / 2;
int diffY = (height - maxY - 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);
}
@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) throws IOException {
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<String, Double>();
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(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();
}
}
}

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,199 @@
/*
* 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;
import java.io.IOException;
public class Button extends Control {
private final GuiButton btn;
private boolean selected = false;
private boolean shiftDown = false;
private int originalColor = 0;
private int shiftColor = 0;
public static class ClickEvent extends Event<Button> {
private 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) throws IOException {
if(mouseButton == 0 && btn.mousePressed(mc, mouseX, mouseY)) {
selected = true;
btn.playPressSound(mc.getSoundHandler());
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.enabled = !json.getBool("disabled", false);
btn.visible = json.getBool("visible", true);
originalColor = json.getColor("color", 0);
shiftColor = json.getColor("shiftColor", 0);
btn.packedFGColour = originalColor;
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.controls;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.init.SoundEvents;
import net.minecraft.util.ResourceLocation;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
import java.io.IOException;
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 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;
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) throws IOException {
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) {
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);
}
}

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 ArrayList<Control> childs = new ArrayList<Control>();
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) throws IOException {
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,249 @@
/*
* 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.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 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) throws IOException {
}
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 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)
glBindTexture(GL_TEXTURE_2D, 0);
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", "");
}
}

View File

@ -0,0 +1,211 @@
/*
* 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 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() {
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int maxY = Integer.MIN_VALUE;
for(Control ctrl : childs) {
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;
}
for(Control ctrl : childs)
ctrl.setPos(ctrl.getX() - minX, ctrl.getY() - minY);
maxX -= minX;
maxY -= minY;
width = maxX + paddingX * 2;
height = maxY + 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,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,384 @@
/*
* 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.io.IOException;
import java.util.ArrayList;
import static org.lwjgl.opengl.GL11.*;
public class List extends BasicControl {
private static class Entry {
public String text;
public Object userdata;
public Entry(String t, Object o) {
text = t;
userdata = o;
}
}
public static class EntryClick extends Event<List> {
private int id;
private 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 ArrayList<Entry> content = new ArrayList<Entry>();
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) throws IOException {
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,281 @@
/*
* 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.io.IOException;
public class TextField extends Control {
public static class EnterPressedEvent extends Event<TextField> {
private 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 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 String oldContent;
private 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 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;
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) throws IOException {
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))
parent.actionPerformed(new TextChangedEvent(this, old));
}
}
@Override
public void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
field.mouseClicked(mouseX, mouseY, mouseButton);
}
@Override
public void draw(int mouseX, int mouseY, float ptt) {
field.drawTextBox();
}
public void setText(String text) {
field.setText(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;
}
@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,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,92 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui.loading;
import com.google.common.base.Throwables;
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 HashMap<String, Class<? extends Control>> controls = new HashMap<String, Class<? extends Control>>();
private static HashMap<ResourceLocation, JsonObject> resources = new HashMap<ResourceLocation, JsonObject>();
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);
}
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 Throwables.propagate(e);
} catch(IllegalAccessException e) {
Log.errorEx("Could not create control from JSON: access denied", e);
throw Throwables.propagate(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 Throwables.propagate(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<String, Integer>();
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<VarOpPair>();
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,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,135 @@
/*
* 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 {
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;
private 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);
}
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
ModelRenderer base;
ModelRenderer left;
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;
setRotation(base, 0F, 0F, 0F);
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;
setRotation(left, 0F, 0F, 0F);
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;
setRotation(right, 0F, 0F, 0F);
}
public final void render(float f5) {
base.render(f5);
left.render(f5);
right.render(f5);
}
private void setRotation(ModelRenderer model, float x, float y, float z) {
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
}

View File

@ -0,0 +1,139 @@
/*
* 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.Nullable;
import java.util.ArrayList;
import java.util.List;
public class ScreenBaker implements IModelBaker {
private static final List<BakedQuad> noQuads = ImmutableList.of();
private TextureAtlasSprite[] texs = new TextureAtlasSprite[16];
private BlockSide[] blockSides = BlockSide.values();
private 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
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<BakedQuad>();
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
public TextureAtlasSprite getParticleTexture() {
return texs[15];
}
@Override
public ItemCameraTransforms getItemCameraTransforms() {
return ItemCameraTransforms.DEFAULT;
}
@Override
public ItemOverrideList getOverrides() {
return ItemOverrideList.NONE;
}
}

View File

@ -0,0 +1,177 @@
/*
* 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(scr.url);
scr.browser.resize(scr.resolution.x, scr.resolution.y);
}
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;
}
float sw = ((float) scr.size.x) * 0.5f - 2.f / 16.f;
float sh = ((float) scr.size.y) * 0.5f - 2.f / 16.f;
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();
}
if(false) {
//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,36 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
import net.minecraft.util.IStringSerializable;
import net.montoyo.wd.entity.TileEntityKeyboard;
import net.montoyo.wd.entity.TileEntityPeripheralBase;
import net.montoyo.wd.entity.TileEntityRCtrl;
public enum DefaultPeripheral implements IStringSerializable {
KEYBOARD("keyboard", TileEntityKeyboard.class),
REMOTE_CONTROLLER("remotectrl", TileEntityRCtrl.class),
CC_INTERFACE("ccinterface", null),
OC_INTERFACE("cointerface", null);
private final String name;
private final Class<? extends TileEntityPeripheralBase> teClass;
DefaultPeripheral(String name, Class<? extends TileEntityPeripheralBase> te) {
this.name = name;
teClass = te;
}
@Override
public String getName() {
return name;
}
public Class<? extends TileEntityPeripheralBase> getTEClass() {
return teClass;
}
}

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,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,20 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.core;
public class ScreenRights {
public static final int CHANGE_URL = 1;
public static final int CLICK = 2;
public static final int MANAGE_FRIEND_LIST = 4;
public static final int MANAGE_OTHER_RIGHTS = 8;
public static final int MANAGE_UPGRADES = 16;
public static final int CHANGE_RESOLUTION = 32;
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,22 @@
/*
* 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;
public class WDCreativeTab extends CreativeTabs {
public WDCreativeTab() {
super("webdisplays");
}
@Override
public ItemStack getTabIconItem() {
return new ItemStack(WebDisplays.INSTANCE.blockScreen);
}
}

View File

@ -0,0 +1,38 @@
/*
* 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.CMessageOpenGui;
import java.util.HashMap;
public abstract class GuiData {
private static final HashMap<String, Class<? extends GuiData>> dataTable = new HashMap<String, Class<? extends GuiData>>();
static {
dataTable.put("SetURL", SetURLData.class);
dataTable.put("ScreenConfig", ScreenConfigData.class);
dataTable.put("Keyboard", KeyboardData.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,87 @@
/*
* 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.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 owner;
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;
owner = scr.owner;
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.isScreen(pos, 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, owner, 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,50 @@
/*
* 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.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 SetURLData() {
}
public SetURLData(Vector3i pos, BlockSide side, String url) {
this.pos = pos;
this.side = side;
this.url = url;
}
@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);
}
@Override
public String getName() {
return "SetURL";
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.entity;
import net.minecraft.entity.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.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);
}
}
}
}
}

View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.entity;
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.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
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 Vector3i getScreenPos() {
return screenPos;
}
@Nullable
public BlockSide getScreenSide() {
return screenSide;
}
public boolean onRightClick(EntityPlayer player, EnumHand hand, BlockSide side) {
return false;
}
}

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)).sendTo((EntityPlayerMP) player);
return true;
}
}

View File

@ -0,0 +1,539 @@
/*
* 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.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.montoyo.mcef.api.IBrowser;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockScreen;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.data.ScreenConfigData;
import net.montoyo.wd.net.CMessageAddScreen;
import net.montoyo.wd.net.CMessageScreenUpdate;
import net.montoyo.wd.net.SMessageRequestTEData;
import net.montoyo.wd.utilities.*;
import java.util.ArrayList;
import java.util.UUID;
public class TileEntityScreen extends TileEntity {
public static class Screen {
private static final String YT_REGEX1 = "^https?\\://(?:www\\.)?youtube\\.com/watch.+$"; //TODO: Fix embedded videos sound/distance
private static final String YT_REGEX2 = "^https?\\://(?:www\\.)?youtu\\.be/[a-zA-Z0-9_\\-]+.*$";
public BlockSide side;
public Vector2i size;
public Vector2i resolution;
public String url;
public boolean isYouTube = false;
public NameUUIDPair owner;
public ArrayList<NameUUIDPair> friends;
public int friendRights;
public int otherRights;
public IBrowser browser;
public static boolean isYouTubeURL(String url) {
return url.matches(YT_REGEX1) || url.matches(YT_REGEX2);
}
public static Screen deserialize(NBTTagCompound tag) {
Screen ret = new Screen();
ret.side = BlockSide.values()[tag.getByte("Side")];
ret.size = new Vector2i(tag.getInteger("Width"), tag.getInteger("Height"));
ret.resolution = new Vector2i(tag.getInteger("ResolutionX"), tag.getInteger("ResolutionY"));
ret.url = tag.getString("URL");
ret.isYouTube = isYouTubeURL(ret.url);
if(ret.resolution.x <= 0 || ret.resolution.y <= 0) {
float psx = ((float) ret.size.x) * 16.f - 4.f;
float psy = ((float) ret.size.y) * 16.f - 4.f;
psx *= 8.f; //TODO: Use ratio in config file
psy *= 8.f;
ret.resolution.x = (int) psx;
ret.resolution.y = (int) psy;
}
if(tag.hasKey("OwnerName")) {
String name = tag.getString("OwnerName");
UUID uuid = tag.getUniqueId("OwnerUUID");
ret.owner = new NameUUIDPair(name, uuid);
}
NBTTagList friends = tag.getTagList("Friends", 10);
ret.friends = new ArrayList<NameUUIDPair>(friends.tagCount());
for(int i = 0; i < friends.tagCount(); i++) {
NBTTagCompound nf = friends.getCompoundTagAt(i);
NameUUIDPair pair = new NameUUIDPair(nf.getString("Name"), nf.getUniqueId("UUID"));
ret.friends.add(pair);
}
ret.friendRights = tag.getByte("FriendRights");
ret.otherRights = tag.getByte("OtherRights");
return ret;
}
public NBTTagCompound serialize() {
NBTTagCompound tag = new NBTTagCompound();
tag.setByte("Side", (byte) side.ordinal());
tag.setInteger("Width", size.x);
tag.setInteger("Height", size.y);
tag.setInteger("ResolutionX", resolution.x);
tag.setInteger("ResolutionY", resolution.y);
tag.setString("URL", url);
if(owner == null)
Log.warning("Found TES with NO OWNER!!");
else {
tag.setString("OwnerName", owner.name);
tag.setUniqueId("OwnerUUID", owner.uuid);
}
NBTTagList list = new NBTTagList();
for(NameUUIDPair f: friends) {
NBTTagCompound nf = new NBTTagCompound();
nf.setString("Name", f.name);
nf.setUniqueId("UUID", f.uuid);
list.appendTag(nf);
}
tag.setTag("Friends", list);
tag.setByte("FriendRights", (byte) friendRights);
tag.setByte("OtherRights", (byte) otherRights);
return tag;
}
public void setOwner(EntityPlayer ply) {
owner = new NameUUIDPair(ply.getGameProfile());
}
public int rightsFor(EntityPlayer ply) {
UUID uuid = ply.getGameProfile().getId();
if(owner.uuid.equals(uuid))
return ScreenRights.ALL;
for(NameUUIDPair f: friends) {
if(f.uuid.equals(uuid))
return friendRights;
}
return otherRights;
}
}
private ArrayList<Screen> screens = new ArrayList<Screen>();
private AxisAlignedBB renderBB = new AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 1.0, 1.0);
private boolean loaded = true;
public float ytVolume = 100.0f;
public boolean isLoaded() {
return loaded;
}
public void load() {
loaded = true;
}
public void unload() {
for(Screen scr: screens) {
if(scr.browser != null) {
scr.browser.close();
scr.browser = null;
}
}
loaded = false;
}
@Override
public void readFromNBT(NBTTagCompound tag) {
super.readFromNBT(tag);
NBTTagList list = tag.getTagList("WDScreens", 10);
if(list.hasNoTags())
return;
screens.clear();
for(int i = 0; i < list.tagCount(); i++)
screens.add(Screen.deserialize(list.getCompoundTagAt(i)));
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound tag) {
super.writeToNBT(tag);
NBTTagList list = new NBTTagList();
for(Screen scr: screens)
list.appendTag(scr.serialize());
tag.setTag("WDScreens", list);
return tag;
}
public NetworkRegistry.TargetPoint point() {
return new NetworkRegistry.TargetPoint(world.provider.getDimension(), (double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), 64.0);
}
public Screen addScreen(BlockSide side, Vector2i size, Vector2i resolution, boolean sendUpdate) {
for(Screen scr: screens) {
if(scr.side == side)
return scr;
}
Screen ret = new Screen();
ret.side = side;
ret.size = size;
ret.url = WebDisplays.INSTANCE.homePage;
ret.friends = new ArrayList<NameUUIDPair>();
ret.friendRights = ScreenRights.DEFAULTS;
ret.otherRights = ScreenRights.DEFAULTS;
if(resolution == null || resolution.x < 1 || resolution.y < 1) {
float psx = ((float) size.x) * 16.f - 4.f;
float psy = ((float) size.y) * 16.f - 4.f;
psx *= 8.f; //TODO: Use ratio in config file
psy *= 8.f;
ret.resolution = new Vector2i((int) psx, (int) psy);
} else
ret.resolution = resolution;
if(sendUpdate && !world.isRemote) {
CMessageAddScreen msg = new CMessageAddScreen(this, ret);
WebDisplays.NET_HANDLER.sendToAllAround(msg, point());
}
screens.add(ret);
if(world.isRemote)
updateAABB();
else
markDirty();
return ret;
}
public Screen getScreen(BlockSide side) {
for(Screen scr: screens) {
if(scr.side == side)
return scr;
}
return null;
}
public int screenCount() {
return screens.size();
}
public Screen getScreen(int idx) {
return screens.get(idx);
}
public void clear() {
screens.clear();
if(!world.isRemote)
markDirty();
}
public void requestData(EntityPlayerMP ep) {
if(!world.isRemote)
WebDisplays.NET_HANDLER.sendTo(new CMessageAddScreen(this), ep);
}
public void setScreenURL(BlockSide side, String url) {
Screen scr = getScreen(side);
if(scr == null) {
Log.error("Attempt to change URL of non-existing screen on side %s", side.toString());
return;
}
scr.url = url;
scr.isYouTube = Screen.isYouTubeURL(url);
if(world.isRemote) {
if(scr.browser != null)
scr.browser.loadURL(url);
} else {
WebDisplays.NET_HANDLER.sendToAllAround(CMessageScreenUpdate.setURL(this, side, url), point());
markDirty();
}
}
public void removeScreen(BlockSide side) {
int idx = -1;
for(int i = 0; i < screens.size(); i++) {
if(screens.get(i).side == side) {
idx = i;
break;
}
}
if(idx < 0) {
Log.error("Tried to delete non-existing screen on side %s", side.toString());
return;
}
if(world.isRemote) {
if(screens.get(idx).browser != null) {
screens.get(idx).browser.close();
screens.get(idx).browser = null;
}
} else
WebDisplays.NET_HANDLER.sendToAllAround(new CMessageScreenUpdate(this, side), point()); //Delete the screen
screens.remove(idx);
if(!world.isRemote) {
if(screens.isEmpty()) //No more screens: remove tile entity
world.setBlockState(getPos(), WebDisplays.INSTANCE.blockScreen.getDefaultState().withProperty(BlockScreen.hasTE, false));
else
markDirty();
}
}
public void setResolution(BlockSide side, Vector2i res) {
if(res.x < 1 || res.y < 1) {
Log.warning("Call to TileEntityScreen.setResolution(%s) with suspicious values X=%d and Y=%d", side.toString(), res.x, res.y);
return;
}
Screen scr = getScreen(side);
if(scr == null) {
Log.error("Tried to change resolution of non-existing screen on side %s", side.toString());
return;
}
scr.resolution = res;
if(world.isRemote) {
WebDisplays.PROXY.screenUpdateResolutionInGui(new Vector3i(getPos()), side, res);
if(scr.browser != null) {
scr.browser.close();
scr.browser = null; //Will be re-created by renderer
}
} else {
WebDisplays.NET_HANDLER.sendToAllAround(CMessageScreenUpdate.setResolution(this, side, res), point());
markDirty();
}
}
public void click(BlockSide side, Vector2i vec) {
Screen scr = getScreen(side);
if(scr == null) {
Log.error("Attempt click non-existing screen of side %s", side.toString());
return;
}
if(world.isRemote) {
if(scr.browser != null) {
scr.browser.injectMouseMove(vec.x, vec.y, 0, false);
scr.browser.injectMouseButton(vec.x, vec.y, 0, 1, true, 1);
scr.browser.injectMouseButton(vec.x, vec.y, 0, 1, false, 1);
}
} else
WebDisplays.NET_HANDLER.sendToAllAround(CMessageScreenUpdate.click(this, side, vec), point());
}
@Override
public void onLoad() {
if(world.isRemote) {
WebDisplays.NET_HANDLER.sendToServer(new SMessageRequestTEData(this));
WebDisplays.PROXY.trackScreen(this, true);
}
}
@Override
public void onChunkUnload() {
if(world.isRemote) {
WebDisplays.PROXY.trackScreen(this, false);
for(Screen scr: screens) {
if(scr.browser != null) {
scr.browser.close();
scr.browser = null;
}
}
}
}
private void updateAABB() {
Vector3i origin = new Vector3i(pos);
Vector3i tmp = new Vector3i();
AABB aabb = new AABB(origin);
for(Screen scr: screens) {
tmp.set(origin);
tmp.addMul(scr.side.right, scr.size.x);
tmp.addMul(scr.side.up, scr.size.y);
tmp.add(scr.side.forward);
aabb.expand(tmp);
}
renderBB = aabb.toMc().expand(0.1, 0.1, 0.1);
}
@Override
public AxisAlignedBB getRenderBoundingBox() {
return renderBB;
}
public void updateTrackDistance(double d) {
boolean needsComputation = true;
float vol = -1.f;
String jsCode = null;
for(Screen scr: screens) {
if(scr.isYouTube && scr.browser != null && !scr.browser.isPageLoading()) {
if(needsComputation) {
float dist = (float) Math.sqrt(d);
if(dist <= 10.f)
vol = 100.f;
else if(dist >= 30.f)
vol = 0.f;
else
vol = (1.f - (dist - 10.f) / 20.f) * 100.f;
if(Math.abs(ytVolume - vol) < 0.5f)
return; //Delta is too small
ytVolume = vol;
int intPart = (int) vol; //Manually convert to string, probably faster in that case...
int fracPart = ((int) (vol * 100.f)) - intPart * 100;
//jsCode = "yt.player.getPlayerByElement(document.getElementById(\"movie_player\")).setVolume(" + intPart + '.' + fracPart + ')';
//jsCode = "console.log(document.getElementById(\"movie_player\"))";
jsCode = "document.getElementById(\"movie_player\").setVolume(" + intPart + '.' + fracPart + ')';
//Log.info(jsCode);
needsComputation = false;
}
scr.browser.runJS(jsCode, "");
}
}
}
/*@Override
public void validate() {
super.validate();
if(world.isRemote)
Log.info("===> TES( VALIDATE) %s", getPos().toString());
}*/
@Override
public void invalidate() {
super.invalidate();
if(world.isRemote) {
Log.info("===> TES(INVALIDATE) %s", getPos().toString());
onChunkUnload();
}
}
public void addFriend(EntityPlayerMP ply, BlockSide side, NameUUIDPair pair) {
if(!world.isRemote) {
Screen scr = getScreen(side);
if(scr == null) {
Log.error("Tried to add friend to invalid screen side %s", side.toString());
return;
}
if(!scr.friends.contains(pair)) {
scr.friends.add(pair);
(new ScreenConfigData(new Vector3i(pos), side, scr)).updateOnly().sendTo(point());
markDirty();
}
}
}
public void removeFriend(EntityPlayerMP ply, BlockSide side, NameUUIDPair pair) {
if(!world.isRemote) {
Screen scr = getScreen(side);
if(scr == null) {
Log.error("Tried to remove friend from invalid screen side %s", side.toString());
return;
}
if(scr.friends.remove(pair)) {
(new ScreenConfigData(new Vector3i(pos), side, scr)).updateOnly().sendTo(point());
markDirty();
}
}
}
public void setRights(EntityPlayerMP ply, BlockSide side, int fr, int or) {
if(!world.isRemote) {
Screen scr = getScreen(side);
if(scr == null) {
Log.error("Tried to change rights of invalid screen on side %s", side.toString());
return;
}
scr.friendRights = fr;
scr.otherRights = or;
(new ScreenConfigData(new Vector3i(pos), side, scr)).updateOnly().sendTo(point());
markDirty();
}
}
public void type(BlockSide side, String text, BlockPos soundPos) {
Screen scr = getScreen(side);
if(scr == null) {
Log.error("Tried to type on invalid screen on side %s", side.toString());
return;
}
if(world.isRemote) {
if(scr.browser != null) {
try {
String[] events = text.split("" + ((char) 1));
for(String ev: events) {
char action = ev.charAt(0);
if(action == 'p')
scr.browser.injectKeyPressed(ev.charAt(1), 0);
else if(action == 'r')
scr.browser.injectKeyReleased(ev.charAt(1), 0);
else if(action == 't') {
for(int i = 1; i < ev.length(); i++)
scr.browser.injectKeyTyped(ev.charAt(i), 0);
} else
throw new RuntimeException("Invalid control key '" + action + '\'');
}
} catch(Throwable t) {
Log.warningEx("Suspicious keyboard type packet received...", t);
}
}
} else {
WebDisplays.NET_HANDLER.sendToAllAround(CMessageScreenUpdate.type(this, side, text), point());
if(soundPos != null) {
double x = (double) soundPos.getX();
double y = (double) soundPos.getY();
double z = (double) soundPos.getZ();
world.playSound(null, x + 0.5, y + 0.5, z + 0.5, WebDisplays.INSTANCE.soundTyping, SoundCategory.BLOCKS, 0.25f, 1.f);
}
}
}
}

View File

@ -0,0 +1,137 @@
/*
* 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.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.Nullable;
import java.util.List;
public class ItemLinker extends Item {
public ItemLinker() {
setUnlocalizedName("webdisplays.linker");
setRegistryName("linker");
setMaxStackSize(1);
setCreativeTab(WebDisplays.CREATIVE_TAB);
}
@Override
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos_, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
if(player.isSneaking())
return EnumActionResult.PASS;
if(world.isRemote)
return EnumActionResult.SUCCESS;
ItemStack stack = player.getHeldItem(hand);
if(stack.hasTagCompound()) {
NBTTagCompound tag = stack.getTagCompound();
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)) {
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");
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 {
NBTTagCompound 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) {
if(stack.hasTagCompound()) {
NBTTagCompound tag = stack.getTagCompound();
if(tag.hasKey("ScreenX") && tag.hasKey("ScreenY") && tag.hasKey("ScreenZ") && tag.hasKey("ScreenSide")) {
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", BlockSide.values()[tag.getByte("ScreenSide")].toString()));
return;
}
}
tt.add(I18n.format("webdisplays.linker.selectScreen"));
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.world.World;
import net.montoyo.wd.WebDisplays;
import javax.annotation.Nullable;
import java.util.List;
public class ItemMinePad2 extends Item {
public ItemMinePad2() {
setUnlocalizedName("webdisplays.minepad");
setRegistryName("minepad");
setMaxStackSize(1);
setFull3D();
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
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer ply, EnumHand hand) {
ItemStack is = ply.getHeldItem(hand);
if(world.isRemote) {
if(ply.isSneaking())
WebDisplays.PROXY.displaySetPadURLGui(getURL(is));
else if(is.getTagCompound() != null && is.getTagCompound().hasKey("PadID"))
WebDisplays.PROXY.openMinePadGui(is.getTagCompound().getInteger("PadID"));
}
return ActionResult.newResult(EnumActionResult.SUCCESS, is);
}
@Override
public void addInformation(ItemStack is, @Nullable World world, List<String> tt, ITooltipFlag ttFlags) {
if(is == null || is.getTagCompound() == null || !is.getTagCompound().hasKey("PadID"))
tt.add("" + ChatFormatting.ITALIC + ChatFormatting.GRAY + I18n.format("webdisplays.minepad.turnon"));
}
}

View File

@ -0,0 +1,121 @@
/*
* 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.Nullable;
import java.util.List;
public class ItemOwnershipThief extends Item {
public ItemOwnershipThief() {
setUnlocalizedName("webdisplays.ownerthief");
setRegistryName("ownerthief");
setMaxStackSize(1);
setCreativeTab(WebDisplays.CREATIVE_TAB);
}
@Override
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;
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.Screen scr = ((TileEntityScreen) te).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());
scr.setOwner(player);
player.setHeldItem(hand, ItemStack.EMPTY);
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());
return;
}
}
tt.add("" + TextFormatting.RED + "WARNING: Admin tool");
tt.add("Right click on screen");
tt.add("and give to new owner.");
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import net.minecraft.block.Block;
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.block.BlockKeyboardRight;
import net.montoyo.wd.core.DefaultPeripheral;
public class ItemPeripheral extends ItemMultiTexture {
public ItemPeripheral(Block block) {
super(block, block, new ItemMultiTexture.Mapper() {
@Override
public String apply(ItemStack is) {
return DefaultPeripheral.values()[is.getMetadata()].getName();
}
});
}
@Override
public boolean canPlaceBlockOnSide(World world, BlockPos pos_, EnumFacing side, EntityPlayer player, ItemStack stack) {
if(stack.getMetadata() != 0)
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);
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.item;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
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;
public class ItemScreenConfigurator extends Item {
public ItemScreenConfigurator() {
setUnlocalizedName("webdisplays.screencfg");
setRegistryName("screencfg");
setMaxStackSize(1);
setCreativeTab(WebDisplays.CREATIVE_TAB);
}
@Override
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;
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import com.mojang.authlib.GameProfile;
import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.utilities.NameUUIDPair;
@Message(messageId = 6, side = Side.CLIENT)
public class CMessageACResult implements IMessage, Runnable {
private NameUUIDPair[] result;
public CMessageACResult() {
}
public CMessageACResult(GameProfile gp) {
result = new NameUUIDPair[] { new NameUUIDPair(gp) };
}
public CMessageACResult(GameProfile[] gps) {
result = new NameUUIDPair[gps.length];
for(int i = 0; i < gps.length; i++)
result[i] = new NameUUIDPair(gps[i]);
}
public CMessageACResult(NameUUIDPair[] pairs) {
result = pairs;
}
@Override
public void fromBytes(ByteBuf buf) {
int cnt = buf.readByte();
result = new NameUUIDPair[cnt];
for(int i = 0; i < cnt; i++)
result[i] = new NameUUIDPair(buf);
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeByte(result.length);
for(int i = 0; i < result.length; i++)
result[i].writeTo(buf);
}
@Override
public void run() {
WebDisplays.PROXY.onAutocompleteResult(result);
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import io.netty.buffer.ByteBuf;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
import net.montoyo.wd.SharedProxy;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Vector2i;
import net.montoyo.wd.utilities.Vector3i;
@Message(messageId = 0, side = Side.CLIENT)
public class CMessageAddScreen implements IMessage, Runnable {
private boolean clear;
private Vector3i pos;
private TileEntityScreen.Screen[] screens;
public CMessageAddScreen() {
}
public CMessageAddScreen(TileEntityScreen tes) {
clear = true;
pos = new Vector3i(tes.getPos());
screens = new TileEntityScreen.Screen[tes.screenCount()];
for(int i = 0; i < tes.screenCount(); i++)
screens[i] = tes.getScreen(i);
}
public CMessageAddScreen(TileEntityScreen tes, TileEntityScreen.Screen ... toSend) {
clear = false;
pos = new Vector3i(tes.getPos());
screens = toSend;
}
@Override
public void fromBytes(ByteBuf buf) {
clear = buf.readBoolean();
pos = new Vector3i(buf);
int cnt = buf.readByte() & 7;
screens = new TileEntityScreen.Screen[cnt];
for(int i = 0; i < cnt; i++) {
screens[i] = new TileEntityScreen.Screen();
screens[i].side = BlockSide.values()[buf.readByte()];
screens[i].size = new Vector2i(buf);
screens[i].url = ByteBufUtils.readUTF8String(buf);
screens[i].resolution = new Vector2i(buf);
}
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeBoolean(clear);
pos.writeTo(buf);
buf.writeByte(screens.length);
for(TileEntityScreen.Screen scr: screens) {
buf.writeByte(scr.side.ordinal());
scr.size.writeTo(buf);
ByteBufUtils.writeUTF8String(buf, scr.url);
scr.resolution.writeTo(buf);
}
}
@Override
public void run() {
TileEntity te = WebDisplays.PROXY.getWorld(SharedProxy.CURRENT_DIMENSION).getTileEntity(pos.toBlock());
if(te == null || !(te instanceof TileEntityScreen)) {
if(clear)
Log.error("CMessageAddScreen: Can't add screen to invalid tile entity at %s", pos.toString());
return;
}
TileEntityScreen tes = (TileEntityScreen) te;
if(clear)
tes.clear();
for(TileEntityScreen.Screen entry: screens) {
TileEntityScreen.Screen scr = tes.addScreen(entry.side, entry.size, entry.resolution, false);
scr.url = entry.url;
if(scr.browser != null)
scr.browser.loadURL(entry.url);
}
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
import net.montoyo.mcef.utilities.Log;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.data.GuiData;
import net.montoyo.wd.utilities.Util;
@Message(messageId = 3, side = Side.CLIENT)
public class CMessageOpenGui implements IMessage, Runnable {
private GuiData data;
public CMessageOpenGui() {
}
public CMessageOpenGui(GuiData data) {
this.data = data;
}
@Override
public void fromBytes(ByteBuf buf) {
String name = ByteBufUtils.readUTF8String(buf);
Class<? extends GuiData> cls = GuiData.classOf(name);
if(cls == null) {
Log.error("Could not create GuiData of type %s because it doesn't exist!", name);
return;
}
data = (GuiData) Util.unserialize(buf, cls);
}
@Override
public void toBytes(ByteBuf buf) {
ByteBufUtils.writeUTF8String(buf, data.getName());
Util.serialize(buf, data);
}
@Override
public void run() {
WebDisplays.PROXY.displayGui(data);
}
}

View File

@ -0,0 +1,147 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import io.netty.buffer.ByteBuf;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
import net.montoyo.wd.SharedProxy;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.BlockSide;
import net.montoyo.wd.utilities.Log;
import net.montoyo.wd.utilities.Vector2i;
import net.montoyo.wd.utilities.Vector3i;
@Message(messageId = 4, side = Side.CLIENT)
public class CMessageScreenUpdate implements IMessage, Runnable {
public static final int UPDATE_URL = 0;
public static final int UPDATE_RESOLUTION = 1;
public static final int UPDATE_DELETE = 2;
public static final int UPDATE_CLICK = 3;
public static final int UPDATE_TYPE = 4;
private Vector3i pos;
private BlockSide side;
private int action;
private String url;
private Vector2i resolution;
private Vector2i click;
private String text;
public CMessageScreenUpdate() {
}
public static CMessageScreenUpdate setURL(TileEntityScreen tes, BlockSide side, String url) {
CMessageScreenUpdate ret = new CMessageScreenUpdate();
ret.pos = new Vector3i(tes.getPos());
ret.side = side;
ret.action = UPDATE_URL;
ret.url = url;
return ret;
}
public static CMessageScreenUpdate setResolution(TileEntityScreen tes, BlockSide side, Vector2i res) {
CMessageScreenUpdate ret = new CMessageScreenUpdate();
ret.pos = new Vector3i(tes.getPos());
ret.side = side;
ret.action = UPDATE_RESOLUTION;
ret.resolution = res;
return ret;
}
public static CMessageScreenUpdate click(TileEntityScreen tes, BlockSide side, Vector2i pos) {
CMessageScreenUpdate ret = new CMessageScreenUpdate();
ret.pos = new Vector3i(tes.getPos());
ret.side = side;
ret.action = UPDATE_CLICK;
ret.click = pos;
return ret;
}
public CMessageScreenUpdate(TileEntityScreen tes, BlockSide side) {
pos = new Vector3i(tes.getPos());
this.side = side;
action = UPDATE_DELETE;
}
public static CMessageScreenUpdate type(TileEntityScreen tes, BlockSide side, String text) {
CMessageScreenUpdate ret = new CMessageScreenUpdate();
ret.pos = new Vector3i(tes.getPos());
ret.side = side;
ret.text = text;
ret.action = UPDATE_TYPE;
return ret;
}
@Override
public void fromBytes(ByteBuf buf) {
pos = new Vector3i(buf);
side = BlockSide.values()[buf.readByte()];
action = buf.readByte();
if(action == UPDATE_URL)
url = ByteBufUtils.readUTF8String(buf);
else if(action == UPDATE_CLICK)
click = new Vector2i(buf);
else if(action == UPDATE_RESOLUTION)
resolution = new Vector2i(buf);
else if(action == UPDATE_TYPE)
text = ByteBufUtils.readUTF8String(buf);
}
@Override
public void toBytes(ByteBuf buf) {
pos.writeTo(buf);
buf.writeByte(side.ordinal());
buf.writeByte(action);
if(action == UPDATE_URL)
ByteBufUtils.writeUTF8String(buf, url);
else if(action == UPDATE_CLICK)
click.writeTo(buf);
else if(action == UPDATE_RESOLUTION)
resolution.writeTo(buf);
else if(action == UPDATE_TYPE)
ByteBufUtils.writeUTF8String(buf, text);
}
@Override
public void run() {
TileEntity te = WebDisplays.PROXY.getWorld(SharedProxy.CURRENT_DIMENSION).getTileEntity(pos.toBlock());
if(te == null || !(te instanceof TileEntityScreen)) {
Log.error("CMessageScreenUpdate: TileEntity at %s is not a screen!", pos.toString());
return;
}
TileEntityScreen tes = (TileEntityScreen) te;
/*TileEntityScreen.Screen scr = tes.getScreen(side);
if(scr == null) {
Log.error("CMessageScreenUpdate: No screen on side %s at %s", side.toString(), pos.toString());
return;
}*/
if(action == UPDATE_URL)
tes.setScreenURL(side, url);
else if(action == UPDATE_CLICK)
tes.click(side, click);
else if(action == UPDATE_DELETE)
tes.removeScreen(side);
else if(action == UPDATE_RESOLUTION)
tes.setResolution(side, resolution);
else if(action == UPDATE_TYPE)
tes.type(side, text, null);
else
Log.warning("===> TODO"); //TODO
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.montoyo.wd.WebDisplays;
public class DefaultHandler implements IMessageHandler<IMessage, IMessage> {
@Override
public IMessage onMessage(IMessage message, MessageContext ctx) {
WebDisplays.PROXY.enqueue((Runnable) message);
return null;
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import net.minecraftforge.fml.relauncher.Side;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Message {
int messageId();
Side side();
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
public class Messages {
private static DefaultHandler DEFAULT_HANDLER = new DefaultHandler();
private static Class<? extends IMessage>[] messages;
static {
ArrayList<Class<? extends IMessage>> l = new ArrayList<Class<? extends IMessage>>();
l.add(CMessageAddScreen.class);
l.add(SMessageRequestTEData.class);
l.add(SMessageScreenCtrl.class);
l.add(CMessageOpenGui.class);
l.add(CMessageScreenUpdate.class);
l.add(SMessageACQuery.class);
l.add(CMessageACResult.class);
l.add(SMessagePadCtrl.class);
messages = l.toArray(new Class[0]);
}
public static void registerAll(SimpleNetworkWrapper wrapper) {
for(Class<? extends IMessage> md: messages) {
Message data = md.getAnnotation(Message.class);
if(data == null)
throw new RuntimeException("Missing @Message annotation for message class " + md.getSimpleName());
Class<?>[] classes = md.getClasses();
Class<? extends IMessageHandler> handler = null;
for(Class<?> cls: classes) {
if(cls.getSimpleName().equals("Handler") && Modifier.isStatic(cls.getModifiers()) && IMessageHandler.class.isAssignableFrom(cls)) {
handler = (Class<? extends IMessageHandler>) cls;
break;
}
}
IMessageHandler handlerInst;
if(handler == null) {
if(Runnable.class.isAssignableFrom(md))
handlerInst = DEFAULT_HANDLER;
else
throw new RuntimeException("Could not find message handler for message " + md.getSimpleName());
} else {
try {
handlerInst = handler.newInstance();
} catch(Throwable t) {
throw new RuntimeException("Could not instantiate message handler for message " + md.getSimpleName());
}
}
wrapper.registerMessage(handlerInst, md, data.messageId(), data.side());
}
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import com.mojang.authlib.GameProfile;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.utilities.NameUUIDPair;
import java.util.ArrayList;
@Message(messageId = 5, side = Side.SERVER)
public class SMessageACQuery implements IMessage, Runnable {
private EntityPlayerMP player;
private String beginning;
private boolean matchExact;
public SMessageACQuery() {
}
public SMessageACQuery(String beg, boolean exact) {
beginning = beg;
matchExact = exact;
}
@Override
public void fromBytes(ByteBuf buf) {
beginning = ByteBufUtils.readUTF8String(buf);
matchExact = buf.readBoolean();
if(!matchExact)
beginning = beginning.toLowerCase();
}
@Override
public void toBytes(ByteBuf buf) {
ByteBufUtils.writeUTF8String(buf, beginning);
buf.writeBoolean(matchExact);
}
@Override
public void run() {
GameProfile[] profiles = WebDisplays.PROXY.getOnlineGameProfiles();
if(matchExact) {
for(GameProfile gp : profiles) {
if(gp.getName().equals(beginning)) {
WebDisplays.NET_HANDLER.sendTo(new CMessageACResult(gp), player);
return;
}
WebDisplays.NET_HANDLER.sendTo(new CMessageACResult(new NameUUIDPair[0]), player);
}
} else {
ArrayList<NameUUIDPair> results = new ArrayList<NameUUIDPair>();
for(GameProfile gp : profiles) {
if(gp.getName().toLowerCase().startsWith(beginning)) {
results.add(new NameUUIDPair(gp));
break;
}
}
WebDisplays.NET_HANDLER.sendTo(new CMessageACResult(results.toArray(new NameUUIDPair[0])), player);
}
}
public static class Handler implements IMessageHandler<SMessageACQuery, IMessage> {
@Override
public IMessage onMessage(SMessageACQuery msg, MessageContext ctx) {
msg.player = ctx.getServerHandler().player;
((WorldServer) msg.player.world).addScheduledTask(msg);
return null;
}
}
}

View File

@ -0,0 +1,106 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.montoyo.wd.WebDisplays;
@Message(messageId = 7, side = Side.SERVER)
public class SMessagePadCtrl implements IMessage, Runnable {
private int id;
private String url;
private EntityPlayer player;
public SMessagePadCtrl() {
}
public SMessagePadCtrl(String url) {
id = -1;
this.url = url;
}
public SMessagePadCtrl(int id, String url) {
this.id = id;
this.url = url;
}
private boolean matchesMinePadID(ItemStack is) {
return is.getItem() == WebDisplays.INSTANCE.itemMinePad && is.getTagCompound() != null && is.getTagCompound().hasKey("PadID") && is.getTagCompound().getInteger("PadID") == id;
}
@Override
public void run() {
if(id < 0) {
ItemStack is = player.getHeldItem(EnumHand.MAIN_HAND);
if(is.getItem() == WebDisplays.INSTANCE.itemMinePad) {
if(url.isEmpty())
is.setTagCompound(null); //Shutdown
else {
//TODO: Check if site is not blacklisted
if(is.getTagCompound() == null)
is.setTagCompound(new NBTTagCompound());
if(!is.getTagCompound().hasKey("PadID"))
is.getTagCompound().setInteger("PadID", WebDisplays.getNextAvailablePadID());
is.getTagCompound().setString("PadURL", url);
}
}
} else {
NonNullList<ItemStack> inv = player.inventory.mainInventory;
ItemStack target = null;
for(int i = 0; i < 9; i++) {
if(matchesMinePadID(inv.get(i))) {
target = inv.get(i);
break;
}
}
if(target == null && matchesMinePadID(player.inventory.offHandInventory.get(0)))
target = player.inventory.offHandInventory.get(0);
if(target != null)
target.getTagCompound().setString("PadURL", url);
}
}
@Override
public void fromBytes(ByteBuf buf) {
id = buf.readInt();
url = ByteBufUtils.readUTF8String(buf);
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(id);
ByteBufUtils.writeUTF8String(buf, url);
}
public static class Handler implements IMessageHandler<SMessagePadCtrl, IMessage> {
@Override
public IMessage onMessage(SMessagePadCtrl msg, MessageContext ctx) {
msg.player = ctx.getServerHandler().player;
((WorldServer) msg.player.world).addScheduledTask(msg);
return null;
}
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.montoyo.mcef.utilities.Log;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.Vector3i;
@Message(messageId = 1, side = Side.SERVER)
public class SMessageRequestTEData implements IMessage, Runnable {
private int dim;
private Vector3i pos;
private EntityPlayerMP player;
public SMessageRequestTEData() {
}
public SMessageRequestTEData(TileEntity te) {
dim = te.getWorld().provider.getDimension();
pos = new Vector3i(te.getPos());
}
@Override
public void fromBytes(ByteBuf buf) {
dim = buf.readInt();
pos = new Vector3i(buf);
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(dim);
pos.writeTo(buf);
}
@Override
public void run() {
if(player.world.provider.getDimension() != dim)
return;
BlockPos bp = pos.toBlock();
if(player.getDistanceSq(bp) > 512.0 * 512.0)
return;
TileEntity te = player.world.getTileEntity(bp);
if(te == null) {
Log.error("MesageRequestTEData: Can't request data of null tile entity at %s", pos.toString());
return;
}
if(te instanceof TileEntityScreen)
((TileEntityScreen) te).requestData(player);
}
public static class Handler implements IMessageHandler<SMessageRequestTEData, IMessage> {
@Override
public IMessage onMessage(SMessageRequestTEData message, MessageContext ctx) {
message.player = ctx.getServerHandler().player;
((WorldServer) message.player.world).addScheduledTask(message);
return null;
}
}
}

View File

@ -0,0 +1,223 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.net;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.montoyo.wd.core.MissingPermissionException;
import net.montoyo.wd.core.ScreenRights;
import net.montoyo.wd.entity.TileEntityScreen;
import net.montoyo.wd.utilities.*;
@Message(messageId = 2, side = Side.SERVER)
public class SMessageScreenCtrl implements IMessage, Runnable {
public static final int CTRL_SET_URL = 0;
public static final int CTRL_SHUT_DOWN = 1;
public static final int CTRL_ADD_FRIEND = 2;
public static final int CTRL_REMOVE_FRIEND = 3;
public static final int CTRL_SET_RIGHTS = 4;
public static final int CTRL_SET_RESOLUTION = 5;
public static final int CTRL_TYPE = 6;
private int ctrl;
private int dim;
private Vector3i pos;
private BlockSide side;
private String url;
private NameUUIDPair friend;
private EntityPlayerMP player;
private int friendRights;
private int otherRights;
private Vector2i resolution;
private String text;
private BlockPos soundPos;
public SMessageScreenCtrl() {
}
public SMessageScreenCtrl(TileEntityScreen tes, BlockSide side, String url) {
ctrl = CTRL_SET_URL;
dim = tes.getWorld().provider.getDimension();
pos = new Vector3i(tes.getPos());
this.side = side;
this.url = url;
}
public SMessageScreenCtrl(TileEntityScreen tes, BlockSide side) {
ctrl = CTRL_SHUT_DOWN;
dim = tes.getWorld().provider.getDimension();
pos = new Vector3i(tes.getPos());
this.side = side;
this.url = url;
}
public SMessageScreenCtrl(TileEntityScreen tes, BlockSide side, NameUUIDPair friend, boolean del) {
ctrl = del ? CTRL_REMOVE_FRIEND : CTRL_ADD_FRIEND;
dim = tes.getWorld().provider.getDimension();
pos = new Vector3i(tes.getPos());
this.side = side;
this.friend = friend;
}
public SMessageScreenCtrl(TileEntityScreen tes, BlockSide side, int fr, int or) {
ctrl = CTRL_SET_RIGHTS;
dim = tes.getWorld().provider.getDimension();
pos = new Vector3i(tes.getPos());
this.side = side;
friendRights = fr;
otherRights = or;
}
public SMessageScreenCtrl(TileEntityScreen tes, BlockSide side, Vector2i res) {
ctrl = CTRL_SET_RESOLUTION;
dim = tes.getWorld().provider.getDimension();
pos = new Vector3i(tes.getPos());
this.side = side;
resolution = res;
}
public static SMessageScreenCtrl type(TileEntityScreen tes, BlockSide side, String text, BlockPos soundPos) {
SMessageScreenCtrl ret = new SMessageScreenCtrl();
ret.ctrl = CTRL_TYPE;
ret.pos = new Vector3i(tes.getPos());
ret.dim = tes.getWorld().provider.getDimension();
ret.side = side;
ret.text = text;
ret.soundPos = soundPos;
return ret;
}
@Override
public void fromBytes(ByteBuf buf) {
ctrl = buf.readByte();
dim = buf.readInt();
pos = new Vector3i(buf);
side = BlockSide.values()[buf.readByte()];
if(ctrl == CTRL_SET_URL)
url = ByteBufUtils.readUTF8String(buf);
else if(ctrl == CTRL_ADD_FRIEND || ctrl == CTRL_REMOVE_FRIEND)
friend = new NameUUIDPair(buf);
else if(ctrl == CTRL_SET_RIGHTS) {
friendRights = buf.readByte();
otherRights = buf.readByte();
} else if(ctrl == CTRL_SET_RESOLUTION)
resolution = new Vector2i(buf);
else if(ctrl == CTRL_TYPE) {
text = ByteBufUtils.readUTF8String(buf);
int sx = buf.readInt();
int sy = buf.readInt();
int sz = buf.readInt();
soundPos = new BlockPos(sx, sy, sz);
}
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeByte(ctrl);
buf.writeInt(dim);
pos.writeTo(buf);
buf.writeByte(side.ordinal());
if(ctrl == CTRL_SET_URL)
ByteBufUtils.writeUTF8String(buf, url);
else if(ctrl == CTRL_ADD_FRIEND || ctrl == CTRL_REMOVE_FRIEND)
friend.writeTo(buf);
else if(ctrl == CTRL_SET_RIGHTS) {
buf.writeByte(friendRights);
buf.writeByte(otherRights);
} else if(ctrl == CTRL_SET_RESOLUTION)
resolution.writeTo(buf);
else if(ctrl == CTRL_TYPE) {
ByteBufUtils.writeUTF8String(buf, text);
buf.writeInt(soundPos.getX());
buf.writeInt(soundPos.getY());
buf.writeInt(soundPos.getZ());
}
}
@Override
public void run() {
try {
runUnsafe();
} catch(MissingPermissionException e) {
Log.errorEx("I have reasons to believe %s (UUID %s) is a hacker, but don't take my word for it...", e, e.getPlayer().getName(), e.getPlayer().getGameProfile().getId().toString());
}
}
private void checkPermission(TileEntityScreen scr, int right) throws MissingPermissionException {
int prights = scr.getScreen(side).rightsFor(player);
if((prights & right) == 0)
throw new MissingPermissionException(right, player);
}
private void runUnsafe() throws MissingPermissionException {
World world = player.world;
BlockPos bp = pos.toBlock();
if(world.provider.getDimension() != dim || player.getDistanceSq(bp) > 512.0 * 512.0)
return; //Out of range
TileEntity te = world.getTileEntity(bp);
if(te == null || !(te instanceof TileEntityScreen)) {
Log.error("TileEntity at %s is not a screen; can't change url!", pos.toString());
return;
}
TileEntityScreen tes = (TileEntityScreen) te;
if(ctrl == CTRL_SET_URL) {
checkPermission(tes, ScreenRights.CHANGE_URL);
tes.setScreenURL(side, url);
} else if(ctrl == CTRL_SHUT_DOWN) {
checkPermission(tes, ScreenRights.CHANGE_URL);
tes.removeScreen(side);
} else if(ctrl == CTRL_ADD_FRIEND) {
checkPermission(tes, ScreenRights.MANAGE_FRIEND_LIST);
tes.addFriend(player, side, friend);
} else if(ctrl == CTRL_REMOVE_FRIEND) {
checkPermission(tes, ScreenRights.MANAGE_FRIEND_LIST);
tes.removeFriend(player, side, friend);
} else if(ctrl == CTRL_SET_RIGHTS) {
TileEntityScreen.Screen scr = tes.getScreen(side);
int fr = scr.owner.uuid.equals(player.getGameProfile().getId()) ? friendRights : scr.friendRights;
int or = (scr.rightsFor(player) & ScreenRights.MANAGE_OTHER_RIGHTS) == 0 ? scr.otherRights : otherRights;
if(scr.friendRights != fr || scr.otherRights != or)
tes.setRights(player, side, fr, or);
} else if(ctrl == CTRL_SET_RESOLUTION) {
checkPermission(tes, ScreenRights.CHANGE_RESOLUTION);
tes.setResolution(side, resolution);
} else if(ctrl == CTRL_TYPE) {
checkPermission(tes, ScreenRights.CLICK);
tes.type(side, text, soundPos);
} else
Log.info("SMessageScreenCtrl: TODO"); //TODO: other ctrl messages
}
public static class Handler implements IMessageHandler<SMessageScreenCtrl, IMessage> {
@Override
public IMessage onMessage(SMessageScreenCtrl message, MessageContext ctx) {
message.player = ctx.getServerHandler().player;
((WorldServer) message.player.world).addScheduledTask(message);
return null;
}
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
import net.minecraft.util.math.AxisAlignedBB;
public class AABB {
public final Vector3i start;
public final Vector3i end;
public AABB() {
start = new Vector3i();
end = new Vector3i();
}
public AABB(Vector3i pos) {
start = pos.clone();
end = pos.clone();
}
public AABB(Vector3i a, Vector3i b) {
start = new Vector3i();
end = new Vector3i();
start.x = Math.min(a.x, b.x);
start.y = Math.min(a.y, b.y);
start.z = Math.min(a.z, b.z);
end.x = Math.max(a.x, b.x);
end.y = Math.max(a.y, b.y);
end.z = Math.max(a.z, b.z);
}
public AABB(AxisAlignedBB bb) {
start = new Vector3i();
end = new Vector3i();
start.x = (int) bb.minX;
start.y = (int) bb.minY;
start.z = (int) bb.minZ;
end.x = (int) Math.ceil(bb.maxX);
end.y = (int) Math.ceil(bb.maxY);
end.z = (int) Math.ceil(bb.maxZ);
}
public AABB expand(Vector3i vec) {
if(vec.x > end.x)
end.x = vec.x;
else if(vec.x < start.x)
start.x = vec.x;
if(vec.y > end.y)
end.y = vec.y;
else if(vec.y < start.y)
start.y = vec.y;
if(vec.z > end.z)
end.z = vec.z;
else if(vec.z < start.z)
start.z = vec.z;
return this;
}
public AABB move(Vector3i start) {
end.sub(this.start).add(start);
this.start.set(start);
return this;
}
public AxisAlignedBB toMc() {
return new AxisAlignedBB((double) start.x, (double) start.y, (double) start.z, (double) end.x, (double) end.y, (double) end.z);
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
public enum BlockSide {
BOTTOM(new Vector3i( 0, 0, -1), new Vector3i( 1, 0, 0), new Vector3i( 0, -1, 0)),
TOP (new Vector3i( 0, 0, -1), new Vector3i( 1, 0, 0), new Vector3i( 0, 1, 0)),
NORTH (new Vector3i( 0, 1, 0), new Vector3i(-1, 0, 0), new Vector3i( 0, 0, -1)),
SOUTH (new Vector3i( 0, 1, 0), new Vector3i( 1, 0, 0), new Vector3i( 0, 0, 1)),
WEST (new Vector3i( 0, 1, 0), new Vector3i( 0, 0, 1), new Vector3i(-1, 0, 0)),
EAST (new Vector3i( 0, 1, 0), new Vector3i( 0, 0, -1), new Vector3i( 1, 0, 0));
public final Vector3i up;
public final Vector3i right;
public final Vector3i forward;
public final Vector3i down;
public final Vector3i left;
public final Vector3i backward;
BlockSide(Vector3i u, Vector3i r, Vector3i f) {
up = u;
right = r;
forward = f;
down = u.clone().neg();
left = r.clone().neg();
backward = f.clone().neg();
}
public BlockSide reverse()
{
int side = ordinal();
int div = side / 2;
int rest = 1 - side % 2;
return values()[div * 2 + rest];
}
public static int reverse(int side) {
int div = side / 2;
int rest = 1 - side % 2;
return div * 2 + rest;
}
}

View File

@ -0,0 +1,15 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
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 DontSerialize {
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
import net.minecraftforge.fml.common.FMLLog;
import org.apache.logging.log4j.Level;
public class Log {
public static void info(String what, Object ... data) {
FMLLog.log("WebDisplays", Level.INFO, what, data);
}
public static void warning(String what, Object ... data) {
FMLLog.log("WebDisplays", Level.WARN, what, data);
}
public static void error(String what, Object ... data) {
FMLLog.log("WebDisplays", Level.ERROR, what, data);
}
public static void infoEx(String what, Throwable e, Object ... data) {
FMLLog.log("WebDisplays", Level.INFO, e, what, data);
}
public static void warningEx(String what, Throwable e, Object ... data) {
FMLLog.log("WebDisplays", Level.WARN, e, what, data);
}
public static void errorEx(String what, Throwable e, Object ... data) {
FMLLog.log("WebDisplays", Level.ERROR, e, what, data);
}
}

View File

@ -0,0 +1,178 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.montoyo.wd.block.BlockScreen;
public class Multiblock {
public static enum OverrideAction {
NONE,
SIMULATE,
IGNORE;
}
public static class BlockOverride {
final Vector3i pos;
final OverrideAction action;
public BlockOverride(Vector3i p, OverrideAction act) {
pos = p;
action = act;
}
public boolean apply(Vector3i bp, boolean originalResult) {
if(action == OverrideAction.NONE || !bp.equals(pos))
return originalResult;
else if(action == OverrideAction.SIMULATE)
return true;
else //action == OverrideAction.IGNORE
return false;
}
}
public static final BlockOverride NULL_OVERRIDE = new BlockOverride(null, OverrideAction.NONE);
//Modifies pos
public static void findOrigin(IBlockAccess world, Vector3i pos, BlockSide side, BlockOverride override)
{
if(override == null)
override = NULL_OVERRIDE;
BlockPos.MutableBlockPos bp = new BlockPos.MutableBlockPos();
//Go left
do {
pos.add(side.left);
pos.toBlock(bp);
} while(override.apply(pos, world.getBlockState(bp).getBlock() instanceof BlockScreen));
pos.add(side.right);
//Go down
do {
pos.add(side.down);
pos.toBlock(bp);
} while(override.apply(pos, world.getBlockState(bp).getBlock() instanceof BlockScreen));
pos.add(side.up);
}
//Origin stays constant
public static Vector2i measure(IBlockAccess world, Vector3i origin, BlockSide side)
{
Vector2i ret = new Vector2i();
Vector3i pos = origin.clone();
BlockPos.MutableBlockPos bp = new BlockPos.MutableBlockPos();
pos.toBlock(bp);
//Go up
do {
pos.add(side.up);
pos.toBlock(bp);
ret.y++;
} while(world.getBlockState(bp).getBlock() instanceof BlockScreen);
pos.add(side.down);
//Go right
do {
pos.add(side.right);
pos.toBlock(bp);
ret.x++;
} while(world.getBlockState(bp).getBlock() instanceof BlockScreen);
return ret;
}
//Origin and size stays constant.
//Returns null if structure is okay, otherwise the erroring block pos.
public static Vector3i check(IBlockAccess world, Vector3i origin, Vector2i size, BlockSide side)
{
Vector3i pos = origin.clone();
BlockPos.MutableBlockPos bp = new BlockPos.MutableBlockPos();
//Check inner
for(int y = 0; y < size.y; y++) {
for(int x = 0; x < size.x; x++) {
pos.toBlock(bp);
if(!(world.getBlockState(bp).getBlock() instanceof BlockScreen))
return pos; //Hole
pos.add(side.forward);
pos.toBlock(bp);
if(world.getBlockState(bp).getBlock() instanceof BlockScreen)
return pos; //Back should be empty
pos.addMul(side.backward, 2);
pos.toBlock(bp);
if(world.getBlockState(bp).getBlock() instanceof BlockScreen)
return pos; //Front should be empty
pos.add(side.forward);
pos.add(side.right);
}
pos.addMul(side.left, size.x);
pos.add(side.up);
}
//Check left edge
pos.set(origin);
pos.add(side.left);
for(int y = 0; y < size.y; y++) {
pos.toBlock(bp);
if(world.getBlockState(bp).getBlock() instanceof BlockScreen)
return pos; //Left edge should be empty
pos.add(side.up);
}
//Check right edge
pos.set(origin);
pos.addMul(side.right, size.x);
for(int y = 0; y < size.y; y++) {
pos.toBlock(bp);
if(world.getBlockState(bp).getBlock() instanceof BlockScreen)
return pos; //Left edge should be empty
pos.add(side.up);
}
//Check bottom edge
pos.set(origin);
pos.add(side.down);
for(int x = 0; x < size.x; x++) {
pos.toBlock(bp);
if(world.getBlockState(bp).getBlock() instanceof BlockScreen)
return pos; //Left edge should be empty
pos.add(side.right);
}
//Check top edge
pos.set(origin);
pos.addMul(side.up, size.y);
for(int x = 0; x < size.x; x++) {
pos.toBlock(bp);
if(world.getBlockState(bp).getBlock() instanceof BlockScreen)
return pos; //Left edge should be empty
pos.add(side.right);
}
//All good.
return null;
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
import com.mojang.authlib.GameProfile;
import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import java.util.UUID;
public class NameUUIDPair {
public final String name;
public final UUID uuid;
public NameUUIDPair() {
name = "";
uuid = new UUID(0L, 0L);
}
public NameUUIDPair(String name, UUID uuid) {
this.name = name;
this.uuid = uuid;
}
public NameUUIDPair(GameProfile profile) {
name = profile.getName();
uuid = profile.getId();
}
public NameUUIDPair(ByteBuf bb) {
name = ByteBufUtils.readUTF8String(bb);
long msb = bb.readLong();
long lsb = bb.readLong();
uuid = new UUID(msb, lsb);
}
public String getName() {
return name;
}
public UUID getUUID() {
return uuid;
}
@Override
public boolean equals(Object obj) {
if(obj == null || !(obj instanceof NameUUIDPair))
return false;
return ((NameUUIDPair) obj).uuid.equals(uuid);
}
@Override
public int hashCode() {
return uuid.hashCode();
}
public boolean isBlank() {
return name.isEmpty() && uuid.getMostSignificantBits() == 0L && uuid.getLeastSignificantBits() == 0L;
}
public void writeTo(ByteBuf bb) {
ByteBufUtils.writeUTF8String(bb, name);
bb.writeLong(uuid.getMostSignificantBits());
bb.writeLong(uuid.getLeastSignificantBits());
}
}

View File

@ -0,0 +1,224 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.*;
import net.minecraft.util.text.*;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
public class Util {
public static void serialize(ByteBuf bb, Object f) {
Class<?> cls = f.getClass();
if(cls == Integer.class || cls == Integer.TYPE)
bb.writeInt((Integer) f);
else if(cls == Float.class || cls == Float.TYPE)
bb.writeFloat((Float) f);
else if(cls == Double.class || cls == Double.TYPE)
bb.writeDouble((Double) f);
else if(cls == Boolean.class || cls == Boolean.TYPE)
bb.writeBoolean((Boolean) f);
else if(cls == String.class)
ByteBufUtils.writeUTF8String(bb, (String) f);
else if(cls == NameUUIDPair.class)
((NameUUIDPair) f).writeTo(bb);
else if(cls.isEnum())
bb.writeByte(((Enum<?>) f).ordinal());
else if(cls.isArray()) {
Object[] ray = (Object[]) f;
bb.writeInt(ray.length);
for (int i = 0; i < ray.length; i++)
serialize(bb, ray[i]);
} else if(!cls.isPrimitive()) {
Field[] fields = cls.getFields();
for(int i = 0; i < fields.length; i++) {
try {
if(fields[i].getAnnotation(DontSerialize.class) == null && !Modifier.isStatic(fields[i].getModifiers()))
serialize(bb, fields[i].get(f));
} catch(IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(String.format("Caught IllegalAccessException for %s.%s", cls.getName(), fields[i].getName()));
}
}
} else
throw new RuntimeException(String.format("Cannot transmit class %s over network!", cls.getName()));
}
public static Object unserialize(ByteBuf bb, Class cls) {
if(cls == Integer.class || cls == Integer.TYPE)
return bb.readInt();
else if(cls == Float.class || cls == Float.TYPE)
return bb.readFloat();
else if(cls == Double.class || cls == Double.TYPE)
return bb.readDouble();
else if(cls == Boolean.class || cls == Boolean.TYPE)
return bb.readBoolean();
else if(cls == String.class)
return ByteBufUtils.readUTF8String(bb);
else if(cls == NameUUIDPair.class)
return new NameUUIDPair(bb);
else if(cls.isEnum())
return cls.getEnumConstants()[bb.readByte()];
else if(cls.isArray()) {
Object[] ray = new Object[bb.readInt()];
for(int i = 0; i < ray.length; i++)
ray[i] = unserialize(bb, cls.getComponentType());
return Arrays.copyOf(ray, ray.length, cls);
} else if(!cls.isPrimitive()) {
Object ret;
Field[] fields = cls.getFields();
try {
ret = cls.newInstance();
} catch(InstantiationException e) {
e.printStackTrace();
throw new RuntimeException(String.format("Caught InstantiationException for class %s", cls.getName()));
} catch(IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(String.format("Caught IllegalAccessException for class %s", cls.getName()));
}
for(int i = 0; i < fields.length; i++) {
try {
if(fields[i].getAnnotation(DontSerialize.class) == null && !Modifier.isStatic(fields[i].getModifiers()))
fields[i].set(ret, unserialize(bb, fields[i].getType()));
} catch(IllegalAccessException e) {
throw new RuntimeException(String.format("Caught IllegalAccessException for %s.%s", cls.getName(), fields[i].getName()));
}
}
return ret;
} else
throw new RuntimeException(String.format("Cannot unserialize class %s!", cls.getName()));
}
public static NBTBase serialize(Object f) {
Class<?> cls = f.getClass();
if(cls == Integer.class)
return new NBTTagInt((Integer) f);
else if(cls == Float.class)
return new NBTTagFloat((Float) f);
else if(cls == Double.class)
return new NBTTagDouble((Double) f);
else if(cls == String.class)
return new NBTTagString((String) f);
else if(cls.isEnum())
return new NBTTagInt(((Enum<?>) f).ordinal());
else if(cls.isArray()) {
Object[] ray = (Object[]) f;
NBTTagList ret = new NBTTagList();
for(int i = 0; i < ray.length; i++)
ret.appendTag(serialize(ray[i]));
return ret;
} else
throw new RuntimeException(String.format("Cannot save class %s as NBT!", cls.getName()));
}
public static Object unserialize(NBTBase nbt, Class cls) {
if(cls == Integer.class || cls == Integer.TYPE)
return ((NBTTagInt) nbt).getInt();
else if(cls == Float.class || cls == Float.TYPE)
return ((NBTTagFloat) nbt).getFloat();
else if(cls == Double.class || cls == Double.TYPE)
return ((NBTTagDouble) nbt).getDouble();
else if(cls == String.class)
return ((NBTTagString) nbt).getString();
else if(cls.isEnum())
return cls.getEnumConstants()[((NBTTagInt) nbt).getInt()];
else if(cls.isArray()) {
NBTTagList lst = (NBTTagList) nbt;
Object[] ray = new Object[lst.tagCount()];
for(int i = 0; lst.tagCount() > 0; i++)
ray[i] = unserialize(lst.removeTag(0), cls.getComponentType());
return Arrays.copyOf(ray, ray.length, cls);
} else
throw new RuntimeException(String.format("Cannot load class %s from NBT!", cls.getName()));
}
public static String[] commaSplit(String str) {
ArrayList<String> lst = new ArrayList<String>();
String out = "";
boolean escape = false;
for(int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if(c == '\\' && !escape) {
escape = true;
continue; //Otherwise it'll set escape back to false
} else if(c == ',' && !escape) {
lst.add(out);
out = "";
} else
out += c;
if(escape)
escape = false;
}
lst.add(out);
String[] ret = new String[lst.size()];
return lst.toArray(ret);
}
public static String addSlashes(String str) {
String out = "";
for(int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if(c == '\\')
out += "\\\\";
else if(c == '\"')
out += "\\\"";
else
out += c;
}
return out;
}
public static int scrambleKey(int idx)
{
idx = idx * 0x9E3779B9;
return idx ^ (idx >> 16);
}
public static void toast(EntityPlayer player, String key, Object ... data) {
toast(player, TextFormatting.RED, key, data);
}
public static void toast(EntityPlayer player, TextFormatting color, String key, Object ... data) {
ITextComponent root = new TextComponentString("[WebDisplays] ");
root.setStyle((new Style()).setColor(color));
root.appendSibling(new TextComponentTranslation("webdisplays.message." + key, data));
player.sendMessage(root);
}
public static void silentClose(Object obj) {
try {
obj.getClass().getMethod("close").invoke(obj);
} catch(Throwable t) {}
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
import io.netty.buffer.ByteBuf;
public class Vector2i {
public int x;
public int y;
public Vector2i()
{
x = 0;
y = 0;
}
public Vector2i(int val)
{
x = val;
y = val;
}
public Vector2i(int x, int y)
{
this.x = x;
this.y = y;
}
public Vector2i(ByteBuf bb)
{
x = bb.readInt();
y = bb.readInt();
}
public void writeTo(ByteBuf bb)
{
bb.writeInt(x);
bb.writeInt(y);
}
}

View File

@ -0,0 +1,186 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
public class Vector3f {
public float x;
public float y;
public float z;
public Vector3f() {
x = 0.f;
y = 0.f;
z = 0.f;
}
public Vector3f(float val) {
x = val;
y = val;
z = val;
}
public Vector3f(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public Vector3f clone() {
return new Vector3f(x, y, z);
}
@Override
public int hashCode() {
return ((37 + Float.floatToRawIntBits(x)) * 31 + Float.floatToRawIntBits(y)) * 43 + Float.floatToRawIntBits(z);
}
@Override
public boolean equals(Object o) {
if(o instanceof Vector3f) {
Vector3f src = (Vector3f) o;
return (src.x == x && src.y == y && src.z == z);
} else
return false;
}
//Add
public Vector3f add(Vector3f src) {
x += src.x;
y += src.y;
z += src.z;
return this;
}
public Vector3f addMul(Vector3f src, float m) {
x += src.x * m;
y += src.y * m;
z += src.z * m;
return this;
}
public Vector3f add(float x, float y, float z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public Vector3f add(float xyz) {
x += xyz;
y += xyz;
z += xyz;
return this;
}
//Sub
public Vector3f sub(Vector3f src) {
x -= src.x;
y -= src.y;
z -= src.z;
return this;
}
public Vector3f sub(float x, float y, float z) {
this.x -= x;
this.y -= y;
this.z -= z;
return this;
}
public Vector3f sub(float xyz) {
x -= xyz;
y -= xyz;
z -= xyz;
return this;
}
//Mul
public Vector3f neg() {
x = -x;
y = -y;
z = -z;
return this;
}
public Vector3f mul(float val) {
x *= val;
y *= val;
z *= val;
return this;
}
public Vector3f div(float val) {
x /= val;
y /= val;
z /= val;
return this;
}
public Vector3f set(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
return this;
}
public Vector3f set(float xyz) {
x = xyz;
y = xyz;
z = xyz;
return this;
}
public float dot(Vector3f vec) {
return x * vec.x + y * vec.y + z * vec.z;
}
public Vector3f set(double x, double y, double z) {
this.x = (float) x;
this.y = (float) y;
this.z = (float) z;
return this;
}
public Vector3f set(int x, int y, int z) {
this.x = (float) x;
this.y = (float) y;
this.z = (float) z;
return this;
}
public Vector3f set(Vector3f vec) {
x = vec.x;
y = vec.y;
z = vec.z;
return this;
}
public Vector3f set(Vector3i vec) {
x = (float) vec.x;
y = (float) vec.y;
z = (float) vec.z;
return this;
}
}

View File

@ -0,0 +1,228 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
import io.netty.buffer.ByteBuf;
import net.minecraft.util.math.BlockPos;
public class Vector3i {
public int x;
public int y;
public int z;
public Vector3i() {
x = 0;
y = 0;
z = 0;
}
public Vector3i(int val) {
x = val;
y = val;
z = val;
}
public Vector3i(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector3i(BlockPos bp) {
x = bp.getX();
y = bp.getY();
z = bp.getZ();
}
public Vector3i(ByteBuf bb) {
x = bb.readInt();
y = bb.readInt();
z = bb.readInt();
}
@Override
public Vector3i clone() {
return new Vector3i(x, y, z);
}
@Override
public int hashCode() {
return ((37 + x) * 31 + y) * 43 + z;
}
@Override
public boolean equals(Object o) {
if(o instanceof Vector3i) {
Vector3i src = (Vector3i) o;
return (src.x == x && src.y == y && src.z == z);
} else
return false;
}
@Override
public String toString() {
return "X: " + x + ", Y: " + y + ", Z: " + z;
}
//Add
public Vector3i add(Vector3i src) {
x += src.x;
y += src.y;
z += src.z;
return this;
}
public Vector3i addMul(Vector3i src, int mul) {
x += src.x * mul;
y += src.y * mul;
z += src.z * mul;
return this;
}
public Vector3i add(int x, int y, int z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public Vector3i add(int xyz) {
x += xyz;
y += xyz;
z += xyz;
return this;
}
//Sub
public Vector3i sub(Vector3i src) {
x -= src.x;
y -= src.y;
z -= src.z;
return this;
}
public Vector3i sub(int x, int y, int z) {
this.x -= x;
this.y -= y;
this.z -= z;
return this;
}
public Vector3i sub(int xyz) {
x -= xyz;
y -= xyz;
z -= xyz;
return this;
}
//Mul
public Vector3i neg() {
x = -x;
y = -y;
z = -z;
return this;
}
public Vector3i mul(int val) {
x *= val;
y *= val;
z *= val;
return this;
}
public Vector3i div(int val) {
x /= val;
y /= val;
z /= val;
return this;
}
public Vector3i set(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
return this;
}
public Vector3i set(double x, double y, double z)
{
this.x = (int) x;
this.y = (int) y;
this.z = (int) z;
return this;
}
public Vector3i set(float x, float y, float z)
{
this.x = (int) x;
this.y = (int) y;
this.z = (int) z;
return this;
}
public Vector3i set(int val)
{
x = val;
y = val;
z = val;
return this;
}
public Vector3i set(Vector3i val)
{
x = val.x;
y = val.y;
z = val.z;
return this;
}
public Vector3i set(Vector3f vec)
{
this.x = (int) vec.x;
this.y = (int) vec.y;
this.z = (int) vec.z;
return this;
}
public Vector3f toFloat() {
return new Vector3f((float) x, (float) y, (float) z);
}
public BlockPos toBlock() {
return new BlockPos(x, y, z);
}
public void toBlock(BlockPos.MutableBlockPos bp) {
bp.setPos(x, y, z);
}
public int getChunkLocalPos()
{
int lx = x & 15;
int ly = y & 255;
int lz = z & 15;
return (ly << 8) | (lz << 4) | lx;
}
public void writeTo(ByteBuf bb) {
bb.writeInt(x);
bb.writeInt(y);
bb.writeInt(z);
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.utilities;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.net.URL;
public enum VideoType {
YOUTUBE("document.getElementById(\"movie_player\").setVolume(", ")"),
YOUTUBE_EMBED("", "");
private final String volumePrefix;
private final String volumeSuffix;
private final int volumeCap;
VideoType(String prefix, String suffix) {
volumePrefix = prefix;
volumeSuffix = suffix;
volumeCap = prefix.length() + 5 + suffix.length();
}
@Nullable
public static VideoType getTypeFromURL(@Nonnull URL url) {
String loHost = url.getHost().toLowerCase();
if(loHost.equals("youtu.be"))
return url.getPath().length() > 1 ? YOUTUBE : null;
else if(!loHost.equals("www.youtube.com") && !loHost.equals("youtube.com"))
return null;
String loPath = url.getPath().toLowerCase();
if(loPath.equals("/watch")) {
if(url.getQuery() != null && (url.getQuery().startsWith("v=") || url.getQuery().contains("&v=")))
return YOUTUBE;
} else if(loPath.startsWith("/embed/"))
return loPath.length() > 7 ? YOUTUBE_EMBED : null;
return null;
}
@Nonnull
public String getVideoIDFromURL(@Nonnull URL url) {
if(this == YOUTUBE) {
if(url.getHost().equalsIgnoreCase("youtu.be"))
return url.getPath().substring(1);
String args[] = url.getQuery().split("&");
for(String arg : args) {
if(arg.startsWith("v="))
return arg.substring(2);
}
} else if(this == YOUTUBE_EMBED)
return url.getPath().substring(7);
return "";
}
@Nonnull
public String getURLFromID(@Nonnull String vid, boolean autoplay) {
String format;
if(this == YOUTUBE)
format = autoplay ? "https://www.youtube.com/watch?v=%s&autoplay=1" : "https://www.youtube.com/watch?v=%s";
else if(this == YOUTUBE_EMBED)
format = autoplay ? "https://www.youtube.com/embed/%s?autoplay=1" : "https://www.youtube.com/embed/%s";
else
return "";
return String.format(format, vid);
}
@Nonnull
public String getVolumeJSQuery(int volInt, int volFrac) {
return (new StringBuilder(volumeCap)).append(volumePrefix).append(volInt).append('.').append(volFrac).append(volumeSuffix).toString();
}
}

View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<link href="http://fonts.googleapis.com/css?family=Roboto+Slab:400,700" rel="stylesheet" type="text/css">
<style type="text/css">
body {
font-family: "Roboto Slab", serif;
background-color: #405FFF;
color: white;
margin: 0;
padding: 5px;
}
a {
text-decoration: none;
color: white;
font-weight: 700;
padding: 10px;
border: 1px solid white;
font-size: 16pt;
border-radius: 5px;
}
a:hover {
background-color: white;
color: #405FFF;
}
#pic {
margin: 0;
padding: 0;
float: right;
}
</style>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(function() {
window.mcefQuery({
"request": "username",
"persistent": false,
"onSuccess": function(msg) {
$("#username").html(msg);
$("#pic").html("<img src=\"https://minotar.net/avatar/" + msg + "/70.png\" />");
},
"onFailure": function(err, msg) {
}
});
});
</script>
</head>
<body>
Hello, <span id="username">?</span>!&nbsp;<div id="pic"></div><br /><br /><br /><br />
<center><a href="http://google.com">Google!</a>&nbsp;&nbsp;<a href="http://youtube.com">YouTube!</a></center>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.tube.js"></script>
<script type="text/javascript">
$(function() {
$("#example_video").player({video: "iP6XpLQM2Cs"});
});
</script>
</head>
<body>
<div id="example_video">Loading, please wait...</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
{
"variants": {
"facing=0": { "model": "webdisplays:kb_right" },
"facing=1": { "model": "webdisplays:kb_right", "y": 90.0 },
"facing=2": { "model": "webdisplays:kb_right", "y": 180.0 },
"facing=3": { "model": "webdisplays:kb_right", "y": 270.0 }
}
}

View File

@ -0,0 +1,23 @@
{
"variants": {
"facing=0,type=keyboard": { "model": "webdisplays:kb_left" },
"facing=1,type=keyboard": { "model": "webdisplays:kb_left", "y": 90.0 },
"facing=2,type=keyboard": { "model": "webdisplays:kb_left", "y": 180.0 },
"facing=3,type=keyboard": { "model": "webdisplays:kb_left", "y": 270.0 },
"facing=0,type=remotectrl": { "model": "webdisplays:peripheral" },
"facing=1,type=remotectrl": { "model": "webdisplays:peripheral" },
"facing=2,type=remotectrl": { "model": "webdisplays:peripheral" },
"facing=3,type=remotectrl": { "model": "webdisplays:peripheral" },
"facing=0,type=ccinterface": { "model": "webdisplays:peripheral" },
"facing=1,type=ccinterface": { "model": "webdisplays:peripheral" },
"facing=2,type=ccinterface": { "model": "webdisplays:peripheral" },
"facing=3,type=ccinterface": { "model": "webdisplays:peripheral" },
"facing=0,type=cointerface": { "model": "webdisplays:peripheral" },
"facing=1,type=cointerface": { "model": "webdisplays:peripheral" },
"facing=2,type=cointerface": { "model": "webdisplays:peripheral" },
"facing=3,type=cointerface": { "model": "webdisplays:peripheral" }
}
}

View File

@ -0,0 +1,6 @@
{
"variants": {
"normal": { "model": "webdisplays:screen" },
"inventory": { "model": "webdisplays:screen_item" }
}
}

View File

@ -0,0 +1,38 @@
{
"controls": [
{
"type": "Label",
"x": 5,
"y": 5,
"label": "$webdisplays.gui.keyboard.hooked",
"color": "yellow",
"name": "lblInfo",
"visible": "1 - showWarning"
},
{
"type": "Label",
"label": "$webdisplays.gui.keyboard.warning1",
"color": "red",
"visible": "showWarning"
},
{
"type": "Label",
"label": "$webdisplays.gui.keyboard.warning2",
"color": "red",
"visible": "showWarning"
},
{
"type": "Label",
"label": "$webdisplays.gui.keyboard.warning3",
"color": "red",
"visible": "showWarning"
},
{
"type": "Button",
"name": "btnOk",
"label": "$webdisplays.gui.keyboard.gotcha",
"visible": "showWarning",
"disabled": "1 - showWarning"
}
]
}

View File

@ -0,0 +1,180 @@
{
"controls": [
{
"type": "Label",
"name": "lblOwner",
"label": "$webdisplays.gui.screencfg.owner",
"x": 0,
"y": 0,
"shadowed": true
},
{
"type": "Label",
"label": "$webdisplays.gui.screencfg.friends",
"x": 0,
"y": 12
},
{
"type": "List",
"name": "lstFriends",
"x": 0,
"y": 24,
"width": 100,
"height": 170,
"selectionColor": "red"
},
{
"type": "TextField",
"name": "tfFriend",
"x": 0,
"y": 198,
"width": 76,
"maxLength": 128
},
{
"type": "Button",
"name": "btnAdd",
"x": 80,
"y": 199,
"width": 20,
"label": "+"
},
{
"type": "Label",
"x": 104,
"y": 12,
"label": "$webdisplays.gui.screencfg.permissions"
},
{
"type": "ControlGroup",
"name": "grpFriends",
"x": 104,
"y": 24,
"label": "$webdisplays.gui.screencfg.friends",
"width": 150,
"height": 112,
"childs": [
{
"type": "CheckBox",
"name": "boxFSetUrl",
"x": 0,
"y": 0,
"label": "$webdisplays.gui.screencfg.seturl"
},
{
"type": "CheckBox",
"name": "boxFClick",
"x": 0,
"y": 16,
"label": "$webdisplays.gui.screencfg.click"
},
{
"type": "CheckBox",
"name": "boxFFriends",
"x": 0,
"y": 32,
"label": "$webdisplays.gui.screencfg.friendlist"
},
{
"type": "CheckBox",
"name": "boxFOthers",
"x": 0,
"y": 48,
"label": "$webdisplays.gui.screencfg.otherrights"
},
{
"type": "CheckBox",
"name": "boxFUpgrades",
"x": 0,
"y": 64,
"label": "$webdisplays.gui.screencfg.mupgrades"
},
{
"type": "CheckBox",
"name": "boxFResolution",
"x": 0,
"y": 80,
"label": "$webdisplays.gui.screencfg.mres"
}
]
},
{
"type": "ControlGroup",
"name": "grpOthers",
"x": 104,
"y": 140,
"label": "$webdisplays.gui.screencfg.others",
"width": 150,
"height": 80,
"childs": [
{
"type": "CheckBox",
"name": "boxOSetUrl",
"x": 0,
"y": 0,
"label": "$webdisplays.gui.screencfg.seturl"
},
{
"type": "CheckBox",
"name": "boxOClick",
"x": 0,
"y": 16,
"label": "$webdisplays.gui.screencfg.click"
},
{
"type": "CheckBox",
"name": "boxOUpgrades",
"x": 0,
"y": 32,
"label": "$webdisplays.gui.screencfg.mupgrades"
},
{
"type": "CheckBox",
"name": "boxOResolution",
"x": 0,
"y": 48,
"label": "$webdisplays.gui.screencfg.mres"
}
]
},
{
"type": "Label",
"x": 258,
"y": 12,
"label": "$webdisplays.gui.screencfg.upgrades"
},
{
"type": "Label",
"x": 258,
"y": 40,
"label": "$webdisplays.gui.screencfg.resolution"
},
{
"type": "TextField",
"name": "tfResX",
"x": 260,
"y": 52,
"width": 40,
"maxLength": 4
},
{
"type": "TextField",
"name": "tfResY",
"x": 304,
"y": 52,
"width": 40,
"maxLength": 4
},
{
"type": "Button",
"name": "btnSetRes",
"x": 260,
"y": 78,
"width": 84,
"label": "$webdisplays.gui.screencfg.setres",
"disabled": true
}
],
"center": true
}

View File

@ -0,0 +1,56 @@
{
"controls": [
{
"type": "Label",
"label": "$webdisplays.gui.seturl.url",
"x": 0,
"y": 0,
"shadowed": true
},
{
"type": "TextField",
"name": "tfURL",
"x": 0,
"y": 12,
"width": 272,
"maxLength": 65535
},
{
"type": "Button",
"name": "btnYT",
"label": "YT",
"x": 276,
"y": 13,
"width": 20,
"shiftColor": [ 255, 100, 100 ]
},
{
"type": "Button",
"name": "btnShutDown",
"label": "$webdisplays.gui.seturl.shutdown",
"x": 0,
"y": 38,
"width": 96,
"visible": "isPad",
"disabled": "1 - isPad"
},
{
"type": "Button",
"name": "btnCancel",
"label": "$webdisplays.gui.seturl.cancel",
"x": "isPad & 100 | 0",
"y": 38,
"width": "isPad & 96 | 146"
},
{
"type": "Button",
"name": "btnOk",
"label": "$webdisplays.gui.seturl.ok",
"x": "isPad & 200 | 150",
"y": 38,
"width": "isPad & 96 | 146"
}
],
"center": true
}

View File

@ -0,0 +1,51 @@
itemGroup.webdisplays=§5Web Displays
tile.webdisplays.screen.name=Web Screen
tile.webdisplays.peripheral.keyboard.name=Keyboard
tile.webdisplays.peripheral.remotectrl.name=Remote Controller
tile.webdisplays.peripheral.ccinterface.name=ComputerCraft Interface
tile.webdisplays.peripheral.cointerface.name=OpenComputers Interface
item.webdisplays.screencfg.name=Screen Configurator
item.webdisplays.ownerthief.name=Ownership Thief [ADMIN]
item.webdisplays.linker.name=Linking Tool
item.webdisplays.stonekey.name=Stone Key
item.webdisplays.minepad.name=minePad
webdisplays.message.tooSmall=Too small! Minimum size is 2x2.
webdisplays.message.invalid=Structure is invalid; look at %s.
webdisplays.message.turnOn=You need to turn the screen on first!
webdisplays.message.screenSet=Screen set! Now give the item to the new owner...
webdisplays.message.newOwner=You are now the owner of this screen!
webdisplays.message.restrictions=You are not allowed to do this :(
webdisplays.message.peripheral=This is not a peripheral!
webdisplays.message.linked=Linked!
webdisplays.message.linkError=Link error :( Check logs...
webdisplays.message.notAScreen=Please right click on the screen first...
webdisplays.message.screenSet2=Screen set! Now right click on the peripheral...
webdisplays.message.chunkUnloaded=The chunk the screen in placed it is not loaded!
webdisplays.message.notLinked=This peripheral has not been linked yet.
webdisplays.gui.screencfg.owner=Screen owner:
webdisplays.gui.screencfg.friends=Friends:
webdisplays.gui.screencfg.permissions=Permissions:
webdisplays.gui.screencfg.seturl=Change URL
webdisplays.gui.screencfg.click=Click & type
webdisplays.gui.screencfg.friendlist=Manage friends
webdisplays.gui.screencfg.otherrights=Manage others
webdisplays.gui.screencfg.mupgrades=Upgrade & link
webdisplays.gui.screencfg.mres=Change resolution
webdisplays.gui.screencfg.others=Others
webdisplays.gui.screencfg.upgrades=Upgrades:
webdisplays.gui.screencfg.resolution=Resolution:
webdisplays.gui.screencfg.setres=Set Resolution
webdisplays.linker.selectScreen=Right click on a screen
webdisplays.linker.selectPeripheral=Right click on a peripheral
webdisplays.linker.posInfo=Screen pos: %d %d %d
webdisplays.linker.sideInfo=Side: %s
webdisplays.gui.seturl.url=URL:
webdisplays.gui.seturl.ok=OK
webdisplays.gui.seturl.cancel=Cancel
webdisplays.gui.seturl.shutdown=Shut down
webdisplays.minepad.turnon=Sneak and right-click to turn on
webdisplays.gui.keyboard.hooked=Keyboard hooked. Press escape to leave.
webdisplays.gui.keyboard.warning1=WARNING! Typed data are sent in PLAIN TEXT to the server.
webdisplays.gui.keyboard.warning2=This means anyone can know what you're up to.
webdisplays.gui.keyboard.warning3=NEVER write one of your passwords using this keyboard.
webdisplays.gui.keyboard.gotcha=Got ya

View File

@ -0,0 +1,503 @@
{
"__comment": "Model absolutely not generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)",
"textures": {
"particle": "webdisplays:blocks/kb_key",
"0": "webdisplays:blocks/kb_base",
"1": "webdisplays:blocks/kb_key"
},
"elements": [
{
"name": "Base",
"from": [ 0.0, 0.0, 3.0 ],
"to": [ 16.0, 1.0, 16.0 ],
"faces": {
"north": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"east": { "texture": "#0", "uv": [ 0.0, 0.0, 13.0, 1.0 ] },
"south": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"west": { "texture": "#0", "uv": [ 0.0, 0.0, 13.0, 1.0 ] },
"up": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 13.0 ] },
"down": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 13.0 ], "cullface": "down" }
}
},
{
"name": "Key1",
"from": [ 1.0, 1.0, 4.0 ],
"to": [ 2.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key2",
"from": [ 4.0, 1.0, 4.0 ],
"to": [ 5.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key3",
"from": [ 6.0, 1.0, 4.0 ],
"to": [ 7.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key4",
"from": [ 8.0, 1.0, 4.0 ],
"to": [ 9.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key5",
"from": [ 10.0, 1.0, 4.0 ],
"to": [ 11.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key6",
"from": [ 13.0, 1.0, 4.0 ],
"to": [ 14.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key7",
"from": [ 15.0, 1.0, 4.0 ],
"to": [ 16.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key8",
"from": [ 1.0, 1.0, 6.0 ],
"to": [ 2.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key9",
"from": [ 3.0, 1.0, 6.0 ],
"to": [ 4.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key10",
"from": [ 5.0, 1.0, 6.0 ],
"to": [ 6.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key11",
"from": [ 7.0, 1.0, 6.0 ],
"to": [ 8.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key12",
"from": [ 9.0, 1.0, 6.0 ],
"to": [ 10.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key13",
"from": [ 11.0, 1.0, 6.0 ],
"to": [ 12.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key14",
"from": [ 13.0, 1.0, 6.0 ],
"to": [ 14.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key15",
"from": [ 15.0, 1.0, 6.0 ],
"to": [ 16.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key16",
"from": [ 1.0, 1.0, 8.0 ],
"to": [ 3.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }
}
},
{
"name": "Key17",
"from": [ 4.0, 1.0, 8.0 ],
"to": [ 5.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key18",
"from": [ 6.0, 1.0, 8.0 ],
"to": [ 7.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key19",
"from": [ 8.0, 1.0, 8.0 ],
"to": [ 9.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key20",
"from": [ 10.0, 1.0, 8.0 ],
"to": [ 11.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key21",
"from": [ 12.0, 1.0, 8.0 ],
"to": [ 13.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key22",
"from": [ 14.0, 1.0, 8.0 ],
"to": [ 15.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key23",
"from": [ 1.0, 1.0, 10.0 ],
"to": [ 4.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] }
}
},
{
"name": "Key24",
"from": [ 5.0, 1.0, 10.0 ],
"to": [ 6.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key25",
"from": [ 7.0, 1.0, 10.0 ],
"to": [ 8.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key26",
"from": [ 9.0, 1.0, 10.0 ],
"to": [ 10.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key27",
"from": [ 11.0, 1.0, 10.0 ],
"to": [ 12.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key28",
"from": [ 13.0, 1.0, 10.0 ],
"to": [ 14.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key29",
"from": [ 15.0, 1.0, 10.0 ],
"to": [ 16.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key30",
"from": [ 1.0, 1.0, 12.0 ],
"to": [ 3.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }
}
},
{
"name": "Key31",
"from": [ 4.0, 1.0, 12.0 ],
"to": [ 5.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key32",
"from": [ 6.0, 1.0, 12.0 ],
"to": [ 7.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key33",
"from": [ 8.0, 1.0, 12.0 ],
"to": [ 9.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key34",
"from": [ 10.0, 1.0, 12.0 ],
"to": [ 11.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key35",
"from": [ 12.0, 1.0, 12.0 ],
"to": [ 13.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key36",
"from": [ 14.0, 1.0, 12.0 ],
"to": [ 15.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key37",
"from": [ 1.0, 1.0, 14.0 ],
"to": [ 3.0, 2.0, 15.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }
}
},
{
"name": "Key38",
"from": [ 4.0, 1.0, 14.0 ],
"to": [ 6.0, 2.0, 15.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }
}
},
{
"name": "Key39",
"from": [ 7.0, 1.0, 14.0 ],
"to": [ 9.0, 2.0, 15.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }
}
},
{
"name": "Key40",
"from": [ 10.0, 1.0, 14.0 ],
"to": [ 16.0, 2.0, 15.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 6.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 6.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 6.0, 1.0 ] }
}
}
]
}

View File

@ -0,0 +1,477 @@
{
"__comment": "Model absolutely not generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)",
"textures": {
"particle": "webdisplays:blocks/kb_key",
"0": "webdisplays:blocks/kb_base",
"1": "webdisplays:blocks/kb_key"
},
"elements": [
{
"name": "Base",
"from": [ 0.0, 0.0, 3.0 ],
"to": [ 16.0, 1.0, 16.0 ],
"faces": {
"north": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"east": { "texture": "#0", "uv": [ 0.0, 0.0, 13.0, 1.0 ] },
"south": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 1.0 ] },
"west": { "texture": "#0", "uv": [ 0.0, 0.0, 13.0, 1.0 ] },
"up": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 13.0 ] },
"down": { "texture": "#0", "uv": [ 0.0, 0.0, 16.0, 13.0 ], "cullface": "down" }
}
},
{
"name": "Key1",
"from": [ 1.0, 1.0, 4.0 ],
"to": [ 2.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key2",
"from": [ 3.0, 1.0, 4.0 ],
"to": [ 4.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key3",
"from": [ 6.0, 1.0, 4.0 ],
"to": [ 7.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key4",
"from": [ 8.0, 1.0, 4.0 ],
"to": [ 9.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key5",
"from": [ 10.0, 1.0, 4.0 ],
"to": [ 11.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key6",
"from": [ 12.0, 1.0, 4.0 ],
"to": [ 13.0, 2.0, 5.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key7",
"from": [ 1.0, 1.0, 6.0 ],
"to": [ 2.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key8",
"from": [ 3.0, 1.0, 6.0 ],
"to": [ 4.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key9",
"from": [ 5.0, 1.0, 6.0 ],
"to": [ 6.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key10",
"from": [ 7.0, 1.0, 6.0 ],
"to": [ 8.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key11",
"from": [ 9.0, 1.0, 6.0 ],
"to": [ 11.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }
}
},
{
"name": "Key12",
"from": [ 12.0, 1.0, 6.0 ],
"to": [ 13.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key13",
"from": [ 14.0, 1.0, 6.0 ],
"to": [ 15.0, 2.0, 7.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key14",
"from": [ 0.0, 1.0, 8.0 ],
"to": [ 1.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key15",
"from": [ 2.0, 1.0, 8.0 ],
"to": [ 3.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key16",
"from": [ 4.0, 1.0, 8.0 ],
"to": [ 5.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key17",
"from": [ 6.0, 1.0, 8.0 ],
"to": [ 7.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key18",
"from": [ 8.0, 1.0, 8.0 ],
"to": [ 11.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] }
}
},
{
"name": "Key19",
"from": [ 12.0, 1.0, 8.0 ],
"to": [ 13.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key20",
"from": [ 14.0, 1.0, 8.0 ],
"to": [ 15.0, 2.0, 9.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key21",
"from": [ 1.0, 1.0, 10.0 ],
"to": [ 2.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key22",
"from": [ 3.0, 1.0, 10.0 ],
"to": [ 4.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key23",
"from": [ 5.0, 1.0, 10.0 ],
"to": [ 6.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key24",
"from": [ 7.0, 1.0, 10.0 ],
"to": [ 8.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key25",
"from": [ 9.0, 1.0, 9.0 ],
"to": [ 11.0, 2.0, 11.0 ],
"faces": {
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 0.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }
}
},
{
"name": "Key26",
"from": [ 12.0, 1.0, 10.0 ],
"to": [ 13.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key27",
"from": [ 14.0, 1.0, 10.0 ],
"to": [ 15.0, 2.0, 11.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key29",
"from": [ 0.0, 1.0, 12.0 ],
"to": [ 1.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key30",
"from": [ 2.0, 1.0, 12.0 ],
"to": [ 3.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key31",
"from": [ 4.0, 1.0, 12.0 ],
"to": [ 5.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key32",
"from": [ 6.0, 1.0, 12.0 ],
"to": [ 7.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key33",
"from": [ 8.0, 1.0, 12.0 ],
"to": [ 11.0, 2.0, 13.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] }
}
},
{
"name": "Key34",
"from": [ 13.0, 1.0, 13.0 ],
"to": [ 14.0, 2.0, 14.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }
}
},
{
"name": "Key35",
"from": [ 0.0, 1.0, 14.0 ],
"to": [ 2.0, 2.0, 15.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }
}
},
{
"name": "Key36",
"from": [ 3.0, 1.0, 14.0 ],
"to": [ 5.0, 2.0, 15.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }
}
},
{
"name": "Key37",
"from": [ 6.0, 1.0, 14.0 ],
"to": [ 8.0, 2.0, 15.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }
}
},
{
"name": "Key38",
"from": [ 9.0, 1.0, 14.0 ],
"to": [ 11.0, 2.0, 15.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 2.0, 1.0 ] }
}
},
{
"name": "Key39",
"from": [ 12.0, 1.0, 14.0 ],
"to": [ 15.0, 2.0, 15.0 ],
"faces": {
"north": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] },
"east": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"south": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] },
"west": { "texture": "#1", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
"up": { "texture": "#1", "uv": [ 0.0, 0.0, 3.0, 1.0 ] }
}
}
]
}

View File

@ -0,0 +1,6 @@
{
"parent": "block/cube_all",
"textures": {
"all": "webdisplays:blocks/rctrl"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "block/cube_all",
"textures": {
"all": "webdisplays:blocks/screen15"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "webdisplays:items/kb_inv"
}
}

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