├── .github ├── no-response.yml ├── config.yml └── ISSUE_TEMPLATE.md ├── example-listener-json ├── serverinfo.json ├── chat-singlemessage.json ├── playerinfo.json └── worlinfo.json ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── dev.gradle ├── versioning.gradle ├── forge.gradle └── deploy.gradle ├── src ├── api │ └── java │ │ └── org │ │ ├── java_websocket │ │ ├── exceptions │ │ │ ├── WebsocketNotConnectedException.java │ │ │ ├── LimitExedeedException.java │ │ │ ├── IncompleteHandshakeException.java │ │ │ ├── NotSendableException.java │ │ │ ├── InvalidFrameException.java │ │ │ ├── InvalidHandshakeException.java │ │ │ └── InvalidDataException.java │ │ ├── handshake │ │ │ ├── ServerHandshake.java │ │ │ ├── ClientHandshakeBuilder.java │ │ │ ├── HandshakeBuilder.java │ │ │ ├── ServerHandshakeBuilder.java │ │ │ ├── ClientHandshake.java │ │ │ ├── Handshakedata.java │ │ │ ├── HandshakeImpl1Client.java │ │ │ ├── HandshakeImpl1Server.java │ │ │ └── HandshakedataImpl1.java │ │ ├── WebSocketFactory.java │ │ ├── framing │ │ │ ├── FrameBuilder.java │ │ │ ├── Framedata.java │ │ │ ├── FramedataImpl1.java │ │ │ ├── CloseFrameBuilder.java │ │ │ └── CloseFrame.java │ │ ├── server │ │ │ ├── DefaultWebSocketServerFactory.java │ │ │ └── DefaultSSLWebSocketServerFactory.java │ │ ├── drafts │ │ │ └── Draft_17.java │ │ ├── WrappedByteChannel.java │ │ ├── client │ │ │ └── AbstractClientProxyChannel.java │ │ ├── LICENCE │ │ ├── AbstractWrappedByteChannel.java │ │ ├── SocketChannelIOHelper.java │ │ ├── util │ │ │ └── Charsetfunctions.java │ │ ├── WebSocketAdapter.java │ │ ├── WebSocket.java │ │ └── WebSocketListener.java │ │ └── json │ │ ├── JSONString.java │ │ ├── JSONException.java │ │ └── JSONStringer.java ├── main │ ├── java │ │ └── de │ │ │ └── maxgb │ │ │ └── minecraft │ │ │ └── second_screen │ │ │ ├── util │ │ │ ├── ForceUpdateEvent.java │ │ │ ├── Constants.java │ │ │ ├── Logger.java │ │ │ ├── User.java │ │ │ └── Helper.java │ │ │ ├── commands │ │ │ ├── BaseCommand.java │ │ │ ├── TestCommand.java │ │ │ ├── GetMSSPortCommand.java │ │ │ ├── GetIPCommand.java │ │ │ ├── mss_sub │ │ │ │ ├── RegisterUserCommand.java │ │ │ │ ├── MssCommand.java │ │ │ │ ├── RegisterRedstoneInfoCommand.java │ │ │ │ └── RegisterObserverCommand.java │ │ │ └── ListInterfacesCommand.java │ │ │ ├── client │ │ │ └── gui │ │ │ │ ├── ModGuiFactory.java │ │ │ │ └── ModConfigGui.java │ │ │ ├── info_listener │ │ │ ├── ServerInfoListener.java │ │ │ ├── PlayerInfoListener.java │ │ │ ├── WorldInfoListener.java │ │ │ ├── PlayerInventoryListener.java │ │ │ └── ChatListener.java │ │ │ ├── StandardListener.java │ │ │ ├── actions │ │ │ ├── GetLastChatAction.java │ │ │ ├── ChatMessageAction.java │ │ │ ├── ActionManager.java │ │ │ └── RedstoneControlAction.java │ │ │ ├── MSSEventHandler.java │ │ │ ├── world_observer │ │ │ ├── NodeObserver.java │ │ │ ├── InventoryObserver.java │ │ │ ├── RFEnergyStorageObserver.java │ │ │ ├── RedstoneObserver.java │ │ │ ├── FluidTankObserver.java │ │ │ └── ObservedBlock.java │ │ │ ├── data │ │ │ ├── DataStorageDriver.java │ │ │ ├── UserManager.java │ │ │ └── ObservingManager.java │ │ │ ├── Configs.java │ │ │ ├── SecondScreenMod.java │ │ │ └── WebSocketListener.java │ └── resources │ │ └── mcmod.info └── shared │ └── java │ └── de │ └── maxgb │ └── minecraft │ └── second_screen │ └── shared │ ├── ClientVersion.java │ ├── ModVersion.java │ └── PROTOKOLL.java ├── .gitattributes ├── README.md ├── gradlew.bat ├── .gitignore └── gradlew /.github/no-response.yml: -------------------------------------------------------------------------------- 1 | daysUntilClose: 21 2 | 3 | responseRequiredLabel: "Needs Info" -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | todo: 2 | keyword: "@TODO-issue" 3 | 4 | reminders: 5 | label: reminder -------------------------------------------------------------------------------- /example-listener-json/serverinfo.json: -------------------------------------------------------------------------------- 1 | {"usernames":["maxanier"],"playercount":1,"motd":"maxanier - 1.7.10","maxplayer":8} -------------------------------------------------------------------------------- /example-listener-json/chat-singlemessage.json: -------------------------------------------------------------------------------- 1 | {"success":1,"messages":[{"sender":"mss~maxanier","time":"16:30","msg":"asdf"}]} -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxanier/MinecraftSecondScreenMod/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example-listener-json/playerinfo.json: -------------------------------------------------------------------------------- 1 | {"foodlevel":20,"posz":-7,"posy":68,"potions":[],"posx":138,"eplevel":0,"health":20,"success":1,"ping":0} -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/exceptions/WebsocketNotConnectedException.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.exceptions; 2 | 3 | public class WebsocketNotConnectedException extends RuntimeException { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | *.bat text eol=crlf 3 | *.patch text eol=lf 4 | *.java text eol=lf 5 | *.gradle text eol=crlf 6 | *.png binary 7 | *.jar binary 8 | *.zip binary 9 | *.cfg text eol=lf 10 | *.psd binary 11 | *.bdc3D binary -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/handshake/ServerHandshake.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.handshake; 2 | 3 | public interface ServerHandshake extends Handshakedata { 4 | public short getHttpStatus(); 5 | 6 | public String getHttpStatusMessage(); 7 | } 8 | -------------------------------------------------------------------------------- /gradle/dev.gradle: -------------------------------------------------------------------------------- 1 | task devJar(type: Jar, dependsOn: 'classes') { 2 | from(sourceSets.main.output) { 3 | include '**' 4 | } 5 | 6 | extension = 'jar' 7 | classifier = 'dev' 8 | } 9 | 10 | artifacts { 11 | archives devJar 12 | } -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/handshake/ClientHandshakeBuilder.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.handshake; 2 | 3 | public interface ClientHandshakeBuilder extends HandshakeBuilder, 4 | ClientHandshake { 5 | public void setResourceDescriptor(String resourceDescriptor); 6 | } 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jan 12 21:55:52 GMT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip 7 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/handshake/HandshakeBuilder.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.handshake; 2 | 3 | public interface HandshakeBuilder extends Handshakedata { 4 | public abstract void put(String name, String value); 5 | 6 | public abstract void setContent(byte[] content); 7 | } 8 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/handshake/ServerHandshakeBuilder.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.handshake; 2 | 3 | public interface ServerHandshakeBuilder extends HandshakeBuilder, 4 | ServerHandshake { 5 | public void setHttpStatus(short status); 6 | 7 | public void setHttpStatusMessage(String message); 8 | } 9 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/handshake/ClientHandshake.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.handshake; 2 | 3 | public interface ClientHandshake extends Handshakedata { 4 | /** 5 | * returns the HTTP Request-URI as defined by 6 | * http://tools.ietf.org/html/rfc2616#section-5.1.2 7 | */ 8 | public String getResourceDescriptor(); 9 | } 10 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/handshake/Handshakedata.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.handshake; 2 | 3 | import java.util.Iterator; 4 | 5 | public interface Handshakedata { 6 | public byte[] getContent(); 7 | 8 | public String getFieldValue(String name); 9 | 10 | public boolean hasFieldValue(String name); 11 | 12 | public Iterator iterateHttpFields(); 13 | } 14 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/WebSocketFactory.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket; 2 | 3 | import java.net.Socket; 4 | import java.util.List; 5 | 6 | import org.java_websocket.drafts.Draft; 7 | 8 | public interface WebSocketFactory { 9 | public WebSocket createWebSocket(WebSocketAdapter a, Draft d, Socket s); 10 | 11 | public WebSocket createWebSocket(WebSocketAdapter a, List drafts, 12 | Socket s); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /example-listener-json/worlinfo.json: -------------------------------------------------------------------------------- 1 | {"rf_es":[["s2",20000,20000],["s",400000,400000]],"overworld":{"time":"12 h 08 min ","name":"1.7.10","timetillrain":"08 h 50 min ","rain":false},"fluidtank":[{"Nothing":[0,0],"label":"tank"}],"th_node":[{"aspects":{"Perditio":11,"Ordo":12,"Ignis":17},"label":"nod"},{"aspects":{"Ignis":9},"label":"node"},{"aspects":{"Terra":22,"Ignis":31},"label":"nodes"},{"aspects":{"Ignis":9},"label":"node"}],"redstone":[["sadfasdf",false,false]],"inv":{"chest":[["Portable Tank",1],["Tank",1]]}} 2 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/exceptions/LimitExedeedException.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.exceptions; 2 | 3 | import org.java_websocket.framing.CloseFrame; 4 | 5 | public class LimitExedeedException extends InvalidDataException { 6 | 7 | /** 8 | * Serializable 9 | */ 10 | private static final long serialVersionUID = 6908339749836826785L; 11 | 12 | public LimitExedeedException() { 13 | super(CloseFrame.TOOBIG); 14 | } 15 | 16 | public LimitExedeedException(String s) { 17 | super(CloseFrame.TOOBIG, s); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/framing/FrameBuilder.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.framing; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import org.java_websocket.exceptions.InvalidDataException; 6 | 7 | public interface FrameBuilder extends Framedata { 8 | 9 | public abstract void setFin(boolean fin); 10 | 11 | public abstract void setOptcode(Opcode optcode); 12 | 13 | public abstract void setPayload(ByteBuffer payload) 14 | throws InvalidDataException; 15 | 16 | public abstract void setTransferemasked(boolean transferemasked); 17 | 18 | } -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/util/ForceUpdateEvent.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.util; 2 | 3 | import net.minecraftforge.fml.common.eventhandler.Event; 4 | 5 | 6 | /** 7 | * Event which forces an update of the listener corrosponding to the referred class 8 | * @author Max 9 | * 10 | */ 11 | @SuppressWarnings("rawtypes") 12 | public class ForceUpdateEvent extends Event { 13 | public final Class listener; 14 | 15 | public ForceUpdateEvent(Class updateListener) { 16 | listener = updateListener; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/exceptions/IncompleteHandshakeException.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.exceptions; 2 | 3 | public class IncompleteHandshakeException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 7906596804233893092L; 6 | private int newsize; 7 | 8 | public IncompleteHandshakeException() { 9 | this.newsize = 0; 10 | } 11 | 12 | public IncompleteHandshakeException(int newsize) { 13 | this.newsize = newsize; 14 | } 15 | 16 | public int getPreferedSize() { 17 | return newsize; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/mcmod.info: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "modid": "maxanier_secondscreenmod", 4 | "name": "Second Screen Mod", 5 | "description": "Allows you to show your android device as second screen, which displays serveral informations", 6 | "version": "${m_version}", 7 | "mcversion": "${mc_version}", 8 | "url": "http://maxgb.de/minecraftsecondscreen", 9 | "updateUrl": "", 10 | "authors": [ 11 | "maxanier" 12 | ], 13 | "credits": "By maxanier", 14 | "logoFile": "", 15 | "screenshots": [ 16 | ], 17 | "parent":"", 18 | "dependencies": [ 19 | ] 20 | } 21 | ] -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/exceptions/NotSendableException.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.exceptions; 2 | 3 | public class NotSendableException extends RuntimeException { 4 | 5 | /** 6 | * Serializable 7 | */ 8 | private static final long serialVersionUID = -6468967874576651628L; 9 | 10 | public NotSendableException() { 11 | } 12 | 13 | public NotSendableException(String message) { 14 | super(message); 15 | } 16 | 17 | public NotSendableException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public NotSendableException(Throwable cause) { 22 | super(cause); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/commands/BaseCommand.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.commands; 2 | 3 | import net.minecraft.command.ICommand; 4 | import net.minecraft.command.ICommandSender; 5 | import net.minecraft.util.text.TextComponentString; 6 | 7 | /** 8 | * Basic command on which all other commands should depend on 9 | * @author Max 10 | * 11 | */ 12 | public abstract class BaseCommand implements ICommand { 13 | public static void sendMessage(ICommandSender target, String message) { 14 | String[] lines = message.split("\\n"); 15 | for (String line : lines) { 16 | target.sendMessage(new TextComponentString(line)); 17 | } 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/framing/Framedata.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.framing; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import org.java_websocket.exceptions.InvalidFrameException; 6 | 7 | public interface Framedata { 8 | public enum Opcode { 9 | CONTINUOUS, TEXT, BINARY, PING, PONG, CLOSING 10 | // more to come 11 | } 12 | 13 | public abstract void append(Framedata nextframe) 14 | throws InvalidFrameException; 15 | 16 | public Opcode getOpcode(); 17 | 18 | public ByteBuffer getPayloadData();// TODO the separation of the application 19 | // data and the extension data is yet to 20 | // be done 21 | 22 | public boolean getTransfereMasked(); 23 | 24 | public boolean isFin(); 25 | } 26 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/handshake/HandshakeImpl1Client.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.handshake; 2 | 3 | public class HandshakeImpl1Client extends HandshakedataImpl1 implements 4 | ClientHandshakeBuilder { 5 | private String resourceDescriptor = "*"; 6 | 7 | public HandshakeImpl1Client() { 8 | } 9 | 10 | @Override 11 | public String getResourceDescriptor() { 12 | return resourceDescriptor; 13 | } 14 | 15 | @Override 16 | public void setResourceDescriptor(String resourceDescriptor) 17 | throws IllegalArgumentException { 18 | if (resourceDescriptor == null) 19 | throw new IllegalArgumentException( 20 | "http resource descriptor must not be null"); 21 | this.resourceDescriptor = resourceDescriptor; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/handshake/HandshakeImpl1Server.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.handshake; 2 | 3 | public class HandshakeImpl1Server extends HandshakedataImpl1 implements 4 | ServerHandshakeBuilder { 5 | private short httpstatus; 6 | private String httpstatusmessage; 7 | 8 | public HandshakeImpl1Server() { 9 | } 10 | 11 | @Override 12 | public short getHttpStatus() { 13 | return httpstatus; 14 | } 15 | 16 | @Override 17 | public String getHttpStatusMessage() { 18 | return httpstatusmessage; 19 | } 20 | 21 | @Override 22 | public void setHttpStatus(short status) { 23 | httpstatus = status; 24 | } 25 | 26 | @Override 27 | public void setHttpStatusMessage(String message) { 28 | this.httpstatusmessage = message; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/api/java/org/json/JSONString.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /** 4 | * The JSONString interface allows a toJSONString() 5 | * method so that a class can change the behavior of 6 | * JSONObject.toString(), JSONArray.toString(), and 7 | * JSONWriter.value(Object). The 8 | * toJSONString method will be used instead of the default behavior 9 | * of using the Object's toString() method and quoting the result. 10 | */ 11 | public interface JSONString { 12 | /** 13 | * The toJSONString method allows a class to produce its own 14 | * JSON serialization. 15 | * 16 | * @return A strictly syntactically correct JSON text. 17 | */ 18 | public String toJSONString(); 19 | } 20 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/exceptions/InvalidFrameException.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.exceptions; 2 | 3 | import org.java_websocket.framing.CloseFrame; 4 | 5 | public class InvalidFrameException extends InvalidDataException { 6 | 7 | /** 8 | * Serializable 9 | */ 10 | private static final long serialVersionUID = -9016496369828887591L; 11 | 12 | public InvalidFrameException() { 13 | super(CloseFrame.PROTOCOL_ERROR); 14 | } 15 | 16 | public InvalidFrameException(String arg0) { 17 | super(CloseFrame.PROTOCOL_ERROR, arg0); 18 | } 19 | 20 | public InvalidFrameException(String arg0, Throwable arg1) { 21 | super(CloseFrame.PROTOCOL_ERROR, arg0, arg1); 22 | } 23 | 24 | public InvalidFrameException(Throwable arg0) { 25 | super(CloseFrame.PROTOCOL_ERROR, arg0); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/exceptions/InvalidHandshakeException.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.exceptions; 2 | 3 | import org.java_websocket.framing.CloseFrame; 4 | 5 | public class InvalidHandshakeException extends InvalidDataException { 6 | 7 | /** 8 | * Serializable 9 | */ 10 | private static final long serialVersionUID = -1426533877490484964L; 11 | 12 | public InvalidHandshakeException() { 13 | super(CloseFrame.PROTOCOL_ERROR); 14 | } 15 | 16 | public InvalidHandshakeException(String arg0) { 17 | super(CloseFrame.PROTOCOL_ERROR, arg0); 18 | } 19 | 20 | public InvalidHandshakeException(String arg0, Throwable arg1) { 21 | super(CloseFrame.PROTOCOL_ERROR, arg0, arg1); 22 | } 23 | 24 | public InvalidHandshakeException(Throwable arg0) { 25 | super(CloseFrame.PROTOCOL_ERROR, arg0); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/client/gui/ModGuiFactory.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.client.gui; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.GuiScreen; 5 | import net.minecraftforge.fml.client.IModGuiFactory; 6 | 7 | import java.util.Set; 8 | 9 | 10 | public class ModGuiFactory implements IModGuiFactory { 11 | 12 | 13 | 14 | @Override 15 | public void initialize(Minecraft minecraftInstance) { 16 | 17 | } 18 | 19 | @Override 20 | public boolean hasConfigGui() { 21 | return true; 22 | } 23 | 24 | @Override 25 | public GuiScreen createConfigGui(GuiScreen parentScreen) { 26 | return new ModConfigGui(parentScreen); 27 | } 28 | 29 | @Override 30 | public Set runtimeGuiCategories() { 31 | return null; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/exceptions/InvalidDataException.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.exceptions; 2 | 3 | public class InvalidDataException extends Exception { 4 | /** 5 | * Serializable 6 | */ 7 | private static final long serialVersionUID = 3731842424390998726L; 8 | 9 | private int closecode; 10 | 11 | public InvalidDataException(int closecode) { 12 | this.closecode = closecode; 13 | } 14 | 15 | public InvalidDataException(int closecode, String s) { 16 | super(s); 17 | this.closecode = closecode; 18 | } 19 | 20 | public InvalidDataException(int closecode, String s, Throwable t) { 21 | super(s, t); 22 | this.closecode = closecode; 23 | } 24 | 25 | public InvalidDataException(int closecode, Throwable t) { 26 | super(t); 27 | this.closecode = closecode; 28 | } 29 | 30 | public int getCloseCode() { 31 | return closecode; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/util/Constants.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.util; 2 | 3 | public class Constants { 4 | 5 | public static final String MOD_ID = "maxanier_secondscreenmod"; 6 | public static final String VERSION = "@VERSION@"; 7 | public static final String MINECRAFT_VERSION = "@MVERSION@"; 8 | public static final String NAME = "Second Screen Mod"; 9 | public static final String UPDATE_FILE_LINK = "http://maxgb.de/minecraftsecondscreen/modversion.json"; 10 | 11 | /** 12 | * Feature version for the client to know what feautures the modversion 13 | * supports 14 | */ 15 | public static final int FEATURE_VERSION = 6; 16 | 17 | public static final String USER_SAVE_DIR = "mss-users"; 18 | 19 | public static final String OBSERVER_FILE_NAME = "observer.json"; 20 | 21 | public static final String GUI_FACTORY_CLASS = "de.maxgb.minecraft.second_screen.client.gui.ModGuiFactory"; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ## Versions 6 | - Minecraft: 7 | - Forge: 8 | - MinecraftSecondScreen: 9 | 10 | 11 | ## Issue Description 12 | 13 | 14 | 15 | ## Reproduce Steps 16 | 17 | 18 | 19 | ## Additional Information 20 | 21 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/server/DefaultWebSocketServerFactory.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.server; 2 | 3 | import java.net.Socket; 4 | import java.nio.channels.SelectionKey; 5 | import java.nio.channels.SocketChannel; 6 | import java.util.List; 7 | 8 | import org.java_websocket.WebSocketAdapter; 9 | import org.java_websocket.WebSocketImpl; 10 | import org.java_websocket.drafts.Draft; 11 | import org.java_websocket.server.WebSocketServer.WebSocketServerFactory; 12 | 13 | public class DefaultWebSocketServerFactory implements WebSocketServerFactory { 14 | @Override 15 | public WebSocketImpl createWebSocket(WebSocketAdapter a, Draft d, Socket s) { 16 | return new WebSocketImpl(a, d); 17 | } 18 | 19 | @Override 20 | public WebSocketImpl createWebSocket(WebSocketAdapter a, List d, 21 | Socket s) { 22 | return new WebSocketImpl(a, d); 23 | } 24 | 25 | @Override 26 | public SocketChannel wrapChannel(SocketChannel channel, SelectionKey key) { 27 | return channel; 28 | } 29 | } -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/drafts/Draft_17.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.drafts; 2 | 3 | import org.java_websocket.exceptions.InvalidHandshakeException; 4 | import org.java_websocket.handshake.ClientHandshake; 5 | import org.java_websocket.handshake.ClientHandshakeBuilder; 6 | 7 | public class Draft_17 extends Draft_10 { 8 | @Override 9 | public HandshakeState acceptHandshakeAsServer(ClientHandshake handshakedata) 10 | throws InvalidHandshakeException { 11 | int v = readVersion(handshakedata); 12 | if (v == 13) 13 | return HandshakeState.MATCHED; 14 | return HandshakeState.NOT_MATCHED; 15 | } 16 | 17 | @Override 18 | public Draft copyInstance() { 19 | return new Draft_17(); 20 | } 21 | 22 | @Override 23 | public ClientHandshakeBuilder postProcessHandshakeRequestAsClient( 24 | ClientHandshakeBuilder request) { 25 | super.postProcessHandshakeRequestAsClient(request); 26 | request.put("Sec-WebSocket-Version", "13");// overwriting the previous 27 | return request; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /gradle/versioning.gradle: -------------------------------------------------------------------------------- 1 | project.mod_version = "${config.main_version}.${config.major_version}.${config.minor_version}" 2 | if (hasProperty("beta")) { 3 | project.mod_version = project.mod_version + "-beta." + beta 4 | config.type = "beta" 5 | } else if (hasProperty("release")) { 6 | config.type = "release" 7 | } else if (System.getenv().CI) { 8 | project.mod_version = project.mod_version + "-test+" + System.getenv().GIT_BRANCH + "." + System.getenv().GIT_COMMIT 9 | writeVersion() 10 | config.type = "test" 11 | } else { 12 | project.mod_version = project.mod_version + "-alpha+" + getDate() 13 | config.type = "alpha" 14 | } 15 | 16 | version = config.minecraft_version + "-" + project.mod_version 17 | 18 | logger.lifecycle "Version " + project.mod_version 19 | 20 | 21 | def writeVersion() { 22 | def file = new File("version.txt") 23 | file.text = project.mod_version 24 | } 25 | 26 | def getDate() { 27 | def date = new Date() 28 | def formattedDate = date.format('MM-dd-HH-mm') 29 | return formattedDate 30 | } 31 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/WrappedByteChannel.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket; 2 | 3 | import java.io.IOException; 4 | import java.nio.ByteBuffer; 5 | import java.nio.channels.ByteChannel; 6 | 7 | import javax.net.ssl.SSLException; 8 | 9 | public interface WrappedByteChannel extends ByteChannel { 10 | public boolean isBlocking(); 11 | 12 | /** 13 | * returns whether readMore should be called to fetch data which has been 14 | * decoded but not yet been returned. 15 | * 16 | * @see #read(ByteBuffer) 17 | * @see #readMore(ByteBuffer) 18 | **/ 19 | public boolean isNeedRead(); 20 | 21 | public boolean isNeedWrite(); 22 | 23 | /** 24 | * This function does not read data from the underlying channel at all. It 25 | * is just a way to fetch data which has already be received or decoded but 26 | * was but was not yet returned to the user. This could be the case when the 27 | * decoded data did not fit into the buffer the user passed to 28 | * {@link #read(ByteBuffer)}. 29 | **/ 30 | public int readMore(ByteBuffer dst) throws SSLException; 31 | 32 | public void writeMore() throws IOException; 33 | } 34 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/client/AbstractClientProxyChannel.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.client; 2 | 3 | import java.io.IOException; 4 | import java.io.UnsupportedEncodingException; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.ByteChannel; 7 | 8 | import org.java_websocket.AbstractWrappedByteChannel; 9 | 10 | public abstract class AbstractClientProxyChannel extends 11 | AbstractWrappedByteChannel { 12 | protected final ByteBuffer proxyHandshake; 13 | 14 | /** 15 | * @param towrap 16 | * The channel to the proxy server 17 | **/ 18 | public AbstractClientProxyChannel(ByteChannel towrap) { 19 | super(towrap); 20 | try { 21 | proxyHandshake = ByteBuffer 22 | .wrap(buildHandShake().getBytes("ASCII")); 23 | } catch (UnsupportedEncodingException e) { 24 | throw new RuntimeException(e); 25 | } 26 | } 27 | 28 | public abstract String buildHandShake(); 29 | 30 | @Override 31 | public int write(ByteBuffer src) throws IOException { 32 | if (!proxyHandshake.hasRemaining()) { 33 | return super.write(src); 34 | } else { 35 | return super.write(proxyHandshake); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/api/java/org/json/JSONException.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /** 4 | * The JSONException is thrown by the JSON.org classes when things are amiss. 5 | * 6 | * @author JSON.org 7 | * @version 2013-02-10 8 | */ 9 | public class JSONException extends RuntimeException { 10 | private static final long serialVersionUID = 0; 11 | private Throwable cause; 12 | 13 | /** 14 | * Constructs a JSONException with an explanatory message. 15 | * 16 | * @param message 17 | * Detail about the reason for the exception. 18 | */ 19 | public JSONException(String message) { 20 | super(message); 21 | } 22 | 23 | /** 24 | * Constructs a new JSONException with the specified cause. 25 | */ 26 | public JSONException(Throwable cause) { 27 | super(cause.getMessage()); 28 | this.cause = cause; 29 | } 30 | 31 | /** 32 | * Returns the cause of this exception or null if the cause is nonexistent 33 | * or unknown. 34 | * 35 | * @returns the cause of this exception or null if the cause is nonexistent 36 | * or unknown. 37 | */ 38 | @Override 39 | public Throwable getCause() { 40 | return this.cause; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /gradle/forge.gradle: -------------------------------------------------------------------------------- 1 | minecraft { 2 | version = config.minecraft_version + "-" + config.forge_version 3 | mappings = config.mappings 4 | runDir = "run" 5 | replaceIn "util/REFERENCE.java" 6 | replace "@VERSION@", "${project.mod_version}" 7 | replace "@MVERSION@", "${config.minecraft_version}" 8 | replace "@FVERSION@", "${config.forge_version}" 9 | makeObfSourceJar = false // an Srg named sources jar is made if enabled 10 | useDepAts = true 11 | } 12 | 13 | processResources { 14 | // this will ensure that this task is redone when the versions change. 15 | inputs.property "m_version", project.mod_version 16 | inputs.property "mc_version", project.config.minecraft_version 17 | 18 | // replace stuff in mcmod.info, nothing else 19 | from(sourceSets.main.resources.srcDirs) { 20 | include '*.info', "*.mcmeta", "META_INF/**" 21 | // replace version and mcversion 22 | expand 'm_version': project.mod_version, 'mc_version': project.config.minecraft_version 23 | } 24 | // copy everything else, thats not the mcmod.info 25 | from(sourceSets.main.resources.srcDirs) { 26 | exclude '**/*.info' 27 | } 28 | 29 | exclude '**/Thumbs.db' 30 | } 31 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/LICENCE: -------------------------------------------------------------------------------- 1 | This package org.java_websocket.* was created by Nathan Rajlich and published under the following licence: 2 | 3 | Copyright (c) 2010-2012 Nathan Rajlich 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/info_listener/ServerInfoListener.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.info_listener; 2 | 3 | import de.maxgb.minecraft.second_screen.Configs; 4 | import de.maxgb.minecraft.second_screen.SecondScreenMod; 5 | import de.maxgb.minecraft.second_screen.StandardListener; 6 | import de.maxgb.minecraft.second_screen.shared.PROTOKOLL; 7 | import de.maxgb.minecraft.second_screen.util.User; 8 | import org.json.JSONObject; 9 | 10 | /** 11 | * Listener which listens to server informations like online players 12 | * @author Max 13 | * 14 | */ 15 | public class ServerInfoListener extends StandardListener { 16 | 17 | public ServerInfoListener(User user) { 18 | super(user); 19 | everyTick = Configs.server_info_update_time; 20 | } 21 | 22 | @Override 23 | public String update() { 24 | JSONObject info = new JSONObject(); 25 | info.put("motd", server.getMOTD()); 26 | info.put("maxplayer", server.getMaxPlayers()); 27 | info.put("usernames", server.getOnlinePlayerNames()); 28 | if (server.getOnlinePlayerNames().length == 0) { 29 | info.put("lastonline", SecondScreenMod.instance.latestOnlinePlayer); 30 | } 31 | info.put("playercount", server.getCurrentPlayerCount()); 32 | return PROTOKOLL.SERVER_INFO_LISTENER + "-" + info.toString(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/client/gui/ModConfigGui.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.client.gui; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import net.minecraft.client.gui.GuiScreen; 7 | import net.minecraftforge.common.config.ConfigElement; 8 | import net.minecraftforge.fml.client.config.GuiConfig; 9 | import net.minecraftforge.fml.client.config.IConfigElement; 10 | import de.maxgb.minecraft.second_screen.Configs; 11 | import de.maxgb.minecraft.second_screen.util.Constants; 12 | 13 | /** 14 | * Gui for the modconfigs menu added by forge 15 | * @author Max 16 | * 17 | */ 18 | public class ModConfigGui extends GuiConfig { 19 | 20 | @SuppressWarnings({ "rawtypes", "unchecked" }) 21 | private static List getConfigElements() { 22 | List elements = new ArrayList(); 23 | elements.addAll(new ConfigElement(Configs.config.getCategory(Configs.CATEGORY_GENERAL)).getChildElements()); 24 | elements.addAll(new ConfigElement(Configs.config.getCategory(Configs.CATEGORY_CONNECTION_SETTINGS)) 25 | .getChildElements()); 26 | elements.addAll(new ConfigElement(Configs.config.getCategory(Configs.CATEGORY_UPDATE_TIMES)).getChildElements()); 27 | return elements; 28 | } 29 | 30 | public ModConfigGui(GuiScreen guiScreen) { 31 | super(guiScreen, getConfigElements(), Constants.MOD_ID, true, false, GuiConfig 32 | .getAbridgedConfigPath(Configs.config.toString())); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/shared/java/de/maxgb/minecraft/second_screen/shared/ClientVersion.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.shared; 2 | 3 | /** 4 | * Class which contains client version informations 5 | * @author Max 6 | * 7 | */ 8 | public class ClientVersion { 9 | 10 | public static class ClientInfo { 11 | public final String id; 12 | public final int version; 13 | 14 | public ClientInfo(String id, int version) { 15 | this.id = id; 16 | this.version = version; 17 | } 18 | } 19 | 20 | /** 21 | * Returns if a update is available 22 | * @param id client app id 23 | * @param version client app version 24 | * @return 25 | */ 26 | public static boolean isUpdateAvailable(String id, int version) { 27 | if (id.endsWith("ANDROID4")) { 28 | if (version < 26) { 29 | return true; 30 | } 31 | } 32 | if(id.endsWith("universal")){ 33 | if(version<1){ 34 | return true; 35 | } 36 | } 37 | return false; 38 | } 39 | 40 | /** 41 | * Returns if a update is necessary 42 | * @param id client app id 43 | * @param version client app version 44 | * @return 45 | */ 46 | public static boolean isUpdateNecessary(String id, int version) { 47 | if (id.equals("ANDROID4")) { 48 | if (version < 18) { 49 | return true; 50 | } 51 | } 52 | if(id.endsWith("universal")){ 53 | if(version<1){ 54 | return true; 55 | } 56 | } 57 | return false; 58 | } 59 | 60 | public static boolean isUpdateAvailable(ClientInfo info) { 61 | return isUpdateAvailable(info.id, info.version); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Second Screen for Minecraft 1.12 - Latest branch [![](http://cf.way2muchnoise.eu/versions/For%20MC_second-screen_all.svg)](https://minecraft.curseforge.com/projects/second-screen/files) 2 | ============================================ 3 | [![forthebadge](https://forthebadge.com/images/badges/for-sharks.svg)](https://maxanier.de) 4 | ## Mod Description 5 | A Minecraft mod which allows you to use your mobile device as a second screen. 6 | This mod provides an "api" for the clientapps. 7 | There is client for Android 4.0+ (https://play.google.com/store/apps/details?id=de.maxgb.android.minecraft_second_screen) and a Webapp which can be used on almost any device (http://maxanier.de/projects/mcss/app) 8 | 9 | ## Downloads 10 | https://minecraft.curseforge.com/projects/second-screen/files 11 | 12 | *More informations can be found here: http://maxanier.de/projects/mcss* 13 | 14 | 15 | ## Credits and Licence 16 | Author: maxanier 17 | 18 | Uses the Java-Websocket implementation by TooTallNate/Nathan Rajlich https://github.com/TooTallNate/Java-WebSocket, the JSON-java by douglascrockford/Douglas Crockford https://github.com/douglascrockford/JSON-java 19 | and multiple apis from other mods. They can be found in the api folder together with the corresponding licences. 20 | 21 | Everything else is published under the Licence LGPL v3. 22 | Feel free to make pull request or suggestions what could be improved. 23 | 24 | You also may create clients which use this mod respectivly its web "api", you also may earn money with you clients. 25 | If you have any questions feel free to contact me. 26 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/handshake/HandshakedataImpl1.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.handshake; 2 | 3 | import java.util.Collections; 4 | import java.util.Iterator; 5 | import java.util.TreeMap; 6 | 7 | public class HandshakedataImpl1 implements HandshakeBuilder { 8 | private byte[] content; 9 | private TreeMap map; 10 | 11 | public HandshakedataImpl1() { 12 | map = new TreeMap(String.CASE_INSENSITIVE_ORDER); 13 | } 14 | 15 | /* 16 | * public HandshakedataImpl1( Handshakedata h ) { httpstatusmessage = 17 | * h.getHttpStatusMessage(); resourcedescriptor = h.getResourceDescriptor(); 18 | * content = h.getContent(); map = new LinkedHashMap(); 19 | * Iterator it = h.iterateHttpFields(); while ( it.hasNext() ) { 20 | * String key = (String) it.next(); map.put( key, h.getFieldValue( key ) ); 21 | * } } 22 | */ 23 | 24 | @Override 25 | public byte[] getContent() { 26 | return content; 27 | } 28 | 29 | @Override 30 | public String getFieldValue(String name) { 31 | String s = map.get(name); 32 | if (s == null) { 33 | return ""; 34 | } 35 | return s; 36 | } 37 | 38 | @Override 39 | public boolean hasFieldValue(String name) { 40 | return map.containsKey(name); 41 | } 42 | 43 | @Override 44 | public Iterator iterateHttpFields() { 45 | return Collections.unmodifiableSet(map.keySet()).iterator();// Safety 46 | // first 47 | } 48 | 49 | @Override 50 | public void put(String name, String value) { 51 | map.put(name, value); 52 | } 53 | 54 | @Override 55 | public void setContent(byte[] content) { 56 | this.content = content; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/util/Logger.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.util; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.PrintStream; 5 | 6 | import net.minecraftforge.fml.common.FMLLog; 7 | 8 | import org.apache.logging.log4j.Level; 9 | 10 | import de.maxgb.minecraft.second_screen.Configs; 11 | 12 | 13 | /** 14 | * Logging class, which provides different methods for different log levels and always adds a tag which states to what the log is related 15 | * @author Max 16 | * 17 | */ 18 | public class Logger { 19 | 20 | public static void d(String tag, String msg) { 21 | if(Configs.debug_mode){ 22 | log(Level.INFO, "[" + tag + "]" + msg); 23 | } 24 | 25 | } 26 | 27 | public static void e(String tag, String msg) { 28 | log(Level.ERROR, "[" + tag + "]" + msg); 29 | } 30 | 31 | public static void e(String tag, String msg, Throwable t) { 32 | String stacktrace = ""; 33 | 34 | PrintStream p; 35 | try { 36 | p = new PrintStream(stacktrace); 37 | t.printStackTrace(p); 38 | } catch (FileNotFoundException e1) { 39 | stacktrace = t.getMessage(); 40 | } 41 | log(Level.ERROR, "[" + tag + "]" + msg + "\nThrowable: "+t.getClass().getCanonicalName()+"\nStacktrace: " + stacktrace+"\nMessage: "+t.getMessage()); 42 | } 43 | 44 | 45 | public static void i(String tag, String msg) { 46 | log(Level.INFO, "[" + tag + "]" + msg); 47 | } 48 | 49 | 50 | private static void log(Level level, String msg) { 51 | FMLLog.log(Constants.MOD_ID, level, msg); 52 | } 53 | 54 | public static void w(String tag, String msg) { 55 | log(Level.WARN, "[" + tag + "]" + msg); 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/commands/TestCommand.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.commands; 2 | 3 | import net.minecraft.command.CommandException; 4 | import net.minecraft.command.ICommand; 5 | import net.minecraft.command.ICommandSender; 6 | import net.minecraft.server.MinecraftServer; 7 | import net.minecraft.util.math.BlockPos; 8 | 9 | import javax.annotation.Nullable; 10 | import java.util.ArrayList; 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | /** 15 | * Test command for development purpose 16 | * @author Max 17 | * 18 | */ 19 | @SuppressWarnings({ "rawtypes" }) 20 | public class TestCommand extends BaseCommand { 21 | 22 | private List aliases; 23 | 24 | public TestCommand() { 25 | this.aliases = new ArrayList(); 26 | } 27 | 28 | 29 | @Override 30 | public int compareTo(ICommand arg0) { 31 | 32 | return 0; 33 | } 34 | 35 | 36 | @Override 37 | public String getUsage(ICommandSender var1) { 38 | return "/msstest"; 39 | } 40 | 41 | @Override 42 | public boolean isUsernameIndex(String[] var1, int var2) { 43 | return false; 44 | } 45 | 46 | 47 | @Override 48 | public String getName() { 49 | return "msstest"; 50 | } 51 | 52 | @Override 53 | public List getAliases() { 54 | return aliases; 55 | } 56 | 57 | @Override 58 | public void execute(MinecraftServer server, ICommandSender sender, String[] args) 59 | throws CommandException { 60 | 61 | } 62 | 63 | @Override 64 | public boolean checkPermission(MinecraftServer server, ICommandSender sender) { 65 | return true; 66 | } 67 | 68 | @Override 69 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { 70 | return Collections.emptyList(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/server/DefaultSSLWebSocketServerFactory.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.server; 2 | 3 | import java.io.IOException; 4 | import java.net.Socket; 5 | import java.nio.channels.ByteChannel; 6 | import java.nio.channels.SelectionKey; 7 | import java.nio.channels.SocketChannel; 8 | import java.util.List; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | 12 | import javax.net.ssl.SSLContext; 13 | import javax.net.ssl.SSLEngine; 14 | 15 | import org.java_websocket.SSLSocketChannel2; 16 | import org.java_websocket.WebSocketAdapter; 17 | import org.java_websocket.WebSocketImpl; 18 | import org.java_websocket.drafts.Draft; 19 | 20 | public class DefaultSSLWebSocketServerFactory implements 21 | WebSocketServer.WebSocketServerFactory { 22 | protected SSLContext sslcontext; 23 | protected ExecutorService exec; 24 | 25 | public DefaultSSLWebSocketServerFactory(SSLContext sslContext) { 26 | this(sslContext, Executors.newSingleThreadScheduledExecutor()); 27 | } 28 | 29 | public DefaultSSLWebSocketServerFactory(SSLContext sslContext, 30 | ExecutorService exec) { 31 | if (sslContext == null || exec == null) 32 | throw new IllegalArgumentException(); 33 | this.sslcontext = sslContext; 34 | this.exec = exec; 35 | } 36 | 37 | @Override 38 | public WebSocketImpl createWebSocket(WebSocketAdapter a, Draft d, Socket c) { 39 | return new WebSocketImpl(a, d); 40 | } 41 | 42 | @Override 43 | public WebSocketImpl createWebSocket(WebSocketAdapter a, List d, 44 | Socket s) { 45 | return new WebSocketImpl(a, d); 46 | } 47 | 48 | @Override 49 | public ByteChannel wrapChannel(SocketChannel channel, SelectionKey key) 50 | throws IOException { 51 | SSLEngine e = sslcontext.createSSLEngine(); 52 | e.setUseClientMode(false); 53 | return new SSLSocketChannel2(channel, e, exec, key); 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/StandardListener.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen; 2 | 3 | import net.minecraft.server.MinecraftServer; 4 | import net.minecraftforge.fml.common.FMLCommonHandler; 5 | import de.maxgb.minecraft.second_screen.util.User; 6 | 7 | /** 8 | * Abstract class which all Listeners have to extend 9 | * @author Max 10 | * 11 | */ 12 | public abstract class StandardListener { 13 | 14 | protected User user; 15 | protected MinecraftServer server; 16 | protected int everyTick = 0; 17 | private int tick; 18 | private String lastMessage; 19 | 20 | public StandardListener(User user) { 21 | this.user = user; 22 | server = FMLCommonHandler.instance().getMinecraftServerInstance(); 23 | tick = 0; 24 | } 25 | 26 | /** 27 | * Is called every tick 28 | * 29 | * @param force 30 | * Whether to force an update or to only update if its time this 31 | * tick 32 | * @return Message which should be sent, null if none 33 | */ 34 | public String tick(boolean force) { 35 | if (tick < 1 || force) { 36 | tick = everyTick; 37 | String newMessage = update(); 38 | if (newMessage == null) { 39 | return null; 40 | } 41 | if (!newMessage.equals(lastMessage)) { 42 | lastMessage = newMessage; 43 | return newMessage; 44 | } 45 | } 46 | tick--; 47 | return null; 48 | } 49 | 50 | /** 51 | * Is called every {@link everyTick} tick. Should check if there are any 52 | * updates which need to be sent to the client. The message is only sent if 53 | * it is not the same as last time. 54 | * 55 | * @return Null if there is no update, otherwise a String which is sent to 56 | * the client listener 57 | */ 58 | public abstract String update(); 59 | 60 | /** 61 | * Is called when the listener is removed. 62 | * There might be a few situations where this fails. 63 | */ 64 | public void onUnregister(){ 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/actions/GetLastChatAction.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.actions; 2 | 3 | import de.maxgb.minecraft.second_screen.actions.ActionManager.ActionResultListener; 4 | import de.maxgb.minecraft.second_screen.actions.ActionManager.IAction; 5 | import de.maxgb.minecraft.second_screen.info_listener.ChatListener.RemoteChatMessageEvent; 6 | import de.maxgb.minecraft.second_screen.shared.PROTOKOLL; 7 | import de.maxgb.minecraft.second_screen.util.Helper; 8 | import de.maxgb.minecraft.second_screen.util.User; 9 | import net.minecraftforge.common.MinecraftForge; 10 | import net.minecraftforge.event.ServerChatEvent; 11 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 12 | import org.json.JSONArray; 13 | import org.json.JSONObject; 14 | 15 | import java.util.ArrayList; 16 | 17 | public class GetLastChatAction implements IAction{ 18 | 19 | private ArrayList messages; 20 | 21 | public GetLastChatAction(){ 22 | messages=new ArrayList(); 23 | MinecraftForge.EVENT_BUS.register(this); 24 | } 25 | 26 | @Override 27 | public void doAction(JSONObject param, User user, ActionResultListener listener) { 28 | JSONArray msgs=new JSONArray(); 29 | for(JSONObject j:messages){ 30 | msgs.put(j); 31 | } 32 | listener.onActionResult(PROTOKOLL.A_GET_CHAT, new JSONObject().put("messages", msgs).put("success", 1) ); 33 | 34 | } 35 | 36 | private void addMessage(String message,String username){ 37 | JSONObject msg = new JSONObject(); 38 | msg.put("sender", username); 39 | msg.put("msg", message); 40 | 41 | msg.put("time", Helper.getCurrentTimeString()); 42 | 43 | if(messages.size()>50){ 44 | messages.subList(0, 10).clear(); 45 | } 46 | 47 | messages.add(msg); 48 | } 49 | 50 | 51 | @SubscribeEvent 52 | public void onChatMessage(ServerChatEvent e){ 53 | addMessage(e.getMessage(), e.getUsername()); 54 | } 55 | 56 | @SubscribeEvent 57 | public void onRemoteMessage(RemoteChatMessageEvent e){ 58 | addMessage(e.msg,"mss~"+e.username); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/AbstractWrappedByteChannel.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket; 2 | 3 | import java.io.IOException; 4 | import java.nio.ByteBuffer; 5 | import java.nio.channels.ByteChannel; 6 | import java.nio.channels.SocketChannel; 7 | 8 | import javax.net.ssl.SSLException; 9 | 10 | public class AbstractWrappedByteChannel implements WrappedByteChannel { 11 | 12 | private final ByteChannel channel; 13 | 14 | public AbstractWrappedByteChannel(ByteChannel towrap) { 15 | this.channel = towrap; 16 | } 17 | 18 | public AbstractWrappedByteChannel(WrappedByteChannel towrap) { 19 | this.channel = towrap; 20 | } 21 | 22 | @Override 23 | public void close() throws IOException { 24 | channel.close(); 25 | } 26 | 27 | @Override 28 | public boolean isBlocking() { 29 | if (channel instanceof SocketChannel) 30 | return ((SocketChannel) channel).isBlocking(); 31 | else if (channel instanceof WrappedByteChannel) 32 | return ((WrappedByteChannel) channel).isBlocking(); 33 | return false; 34 | } 35 | 36 | @Override 37 | public boolean isNeedRead() { 38 | return channel instanceof WrappedByteChannel ? ((WrappedByteChannel) channel) 39 | .isNeedRead() : false; 40 | 41 | } 42 | 43 | @Override 44 | public boolean isNeedWrite() { 45 | return channel instanceof WrappedByteChannel ? ((WrappedByteChannel) channel) 46 | .isNeedWrite() : false; 47 | } 48 | 49 | @Override 50 | public boolean isOpen() { 51 | return channel.isOpen(); 52 | } 53 | 54 | @Override 55 | public int read(ByteBuffer dst) throws IOException { 56 | return channel.read(dst); 57 | } 58 | 59 | @Override 60 | public int readMore(ByteBuffer dst) throws SSLException { 61 | return channel instanceof WrappedByteChannel ? ((WrappedByteChannel) channel) 62 | .readMore(dst) : 0; 63 | } 64 | 65 | @Override 66 | public int write(ByteBuffer src) throws IOException { 67 | return channel.write(src); 68 | } 69 | 70 | @Override 71 | public void writeMore() throws IOException { 72 | if (channel instanceof WrappedByteChannel) 73 | ((WrappedByteChannel) channel).writeMore(); 74 | 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/MSSEventHandler.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen; 2 | 3 | import de.maxgb.minecraft.second_screen.util.Helper; 4 | import de.maxgb.minecraft.second_screen.util.Logger; 5 | import net.minecraft.entity.player.EntityPlayer; 6 | import net.minecraft.init.Items; 7 | import net.minecraft.item.ItemStack; 8 | import net.minecraftforge.event.entity.EntityJoinWorldEvent; 9 | import net.minecraftforge.event.world.WorldEvent; 10 | import net.minecraftforge.fml.common.eventhandler.EventPriority; 11 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 12 | import net.minecraftforge.fml.common.gameevent.PlayerEvent; 13 | 14 | public class MSSEventHandler { 15 | 16 | private final static String TAG="EventHandler"; 17 | 18 | @SubscribeEvent 19 | public void onWorldSave(WorldEvent.Save e){ 20 | if (e.getWorld().provider.getDimension() == 0 && !e.getWorld().isRemote) { 21 | Logger.i(TAG, "Saving data"); 22 | SecondScreenMod.instance.saveData(); 23 | } 24 | } 25 | 26 | @SubscribeEvent 27 | public void onPlayerLoggedOut(PlayerEvent.PlayerLoggedOutEvent e){ 28 | SecondScreenMod.instance.latestOnlinePlayer=e.player.getDisplayName().getFormattedText(); 29 | } 30 | 31 | @SubscribeEvent(priority=EventPriority.LOWEST) 32 | public void onPlayerJoinWorld(EntityJoinWorldEvent e){ 33 | if (e.getEntity() instanceof EntityPlayer && !e.getWorld().isRemote) { 34 | EntityPlayer p = (EntityPlayer) e.getEntity(); 35 | if(!p.getEntityData().getBoolean("mss_book")){ 36 | ItemStack book=Helper.createTutorialBook(); 37 | Helper.dropItemStackInWorld(e.getWorld(), p.posX, p.posY, p.posZ, new ItemStack(Items.APPLE)); 38 | if(!p.inventory.addItemStackToInventory(book)){ 39 | Logger.i("EntityJoinWorld-Main","Playerinventory full, dropping manual to the ground"); 40 | Helper.dropItemStackInWorld(e.getWorld(), p.posX, p.posY, p.posZ, book); 41 | } 42 | 43 | p.getEntityData().setBoolean("mss_book", true); 44 | } 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/actions/ChatMessageAction.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.actions; 2 | 3 | 4 | import net.minecraftforge.common.MinecraftForge; 5 | 6 | import org.json.JSONObject; 7 | 8 | import de.maxgb.minecraft.second_screen.actions.ActionManager.ActionResultListener; 9 | import de.maxgb.minecraft.second_screen.actions.ActionManager.IAction; 10 | import de.maxgb.minecraft.second_screen.info_listener.ChatListener.RemoteChatMessageEvent; 11 | import de.maxgb.minecraft.second_screen.shared.PROTOKOLL; 12 | import de.maxgb.minecraft.second_screen.util.Helper; 13 | import de.maxgb.minecraft.second_screen.util.Logger; 14 | import de.maxgb.minecraft.second_screen.util.User; 15 | 16 | /** 17 | * Action which can show a chat message ingame 18 | * @author Max 19 | * 20 | */ 21 | public class ChatMessageAction implements IAction { 22 | 23 | private static final String TAG = "ChatMessage"; 24 | private static final String PERMISSION = "send_chat_message"; 25 | 26 | @Override 27 | public void doAction(JSONObject param, User user, ActionResultListener listener) { 28 | if (!param.has("msg")) { 29 | Logger.w(TAG, "Params did not include message"); 30 | JSONObject result = new JSONObject(); 31 | result.put("success", 0); 32 | result.put("error", "Params did not include message"); 33 | 34 | listener.onActionResult(PROTOKOLL.A_CHAT_MSG, result); 35 | return; 36 | } 37 | if (!user.isAllowedTo(PERMISSION, true)) { 38 | Logger.w(TAG, "User " + user.username + " is not allowed to execute this command"); 39 | JSONObject result = new JSONObject(); 40 | result.put("success", 0); 41 | result.put("allowed", false); 42 | 43 | listener.onActionResult(PROTOKOLL.A_CHAT_MSG, result); 44 | return; 45 | } 46 | String msg = param.getString("msg"); 47 | 48 | Helper.sendChatMessage("[MSS] <" + user.username + "> " + msg); 49 | 50 | MinecraftForge.EVENT_BUS.post(new RemoteChatMessageEvent(user.username, msg)); 51 | 52 | JSONObject result = new JSONObject(); 53 | result.put("success", 1); 54 | result.put("allowed", true); 55 | 56 | listener.onActionResult(PROTOKOLL.A_CHAT_MSG, result); 57 | return; 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/SocketChannelIOHelper.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket; 2 | 3 | import java.io.IOException; 4 | import java.nio.ByteBuffer; 5 | import java.nio.channels.ByteChannel; 6 | 7 | import org.java_websocket.WebSocket.Role; 8 | 9 | public class SocketChannelIOHelper { 10 | 11 | /** Returns whether the whole outQueue has been flushed */ 12 | public static boolean batch(WebSocketImpl ws, ByteChannel sockchannel) 13 | throws IOException { 14 | ByteBuffer buffer = ws.outQueue.peek(); 15 | WrappedByteChannel c = null; 16 | 17 | if (buffer == null) { 18 | if (sockchannel instanceof WrappedByteChannel) { 19 | c = (WrappedByteChannel) sockchannel; 20 | if (c.isNeedWrite()) { 21 | c.writeMore(); 22 | } 23 | } 24 | } else { 25 | do {// FIXME writing as much as possible is unfair!! 26 | /* int written = */sockchannel.write(buffer); 27 | if (buffer.remaining() > 0) { 28 | return false; 29 | } else { 30 | ws.outQueue.poll(); // Buffer finished. Remove it. 31 | buffer = ws.outQueue.peek(); 32 | } 33 | } while (buffer != null); 34 | } 35 | 36 | if (ws.outQueue.isEmpty() && ws.isFlushAndClose() 37 | && ws.getDraft().getRole() == Role.SERVER) {// 38 | synchronized (ws) { 39 | ws.closeConnection(); 40 | } 41 | } 42 | return c != null ? !((WrappedByteChannel) sockchannel).isNeedWrite() 43 | : true; 44 | } 45 | 46 | public static boolean read(final ByteBuffer buf, WebSocketImpl ws, 47 | ByteChannel channel) throws IOException { 48 | buf.clear(); 49 | int read = channel.read(buf); 50 | buf.flip(); 51 | 52 | if (read == -1) { 53 | ws.eot(); 54 | return false; 55 | } 56 | return read != 0; 57 | } 58 | 59 | /** 60 | * @see WrappedByteChannel#readMore(ByteBuffer) 61 | * @return returns whether there is more data left which can be obtained via 62 | * {@link #readMore(ByteBuffer, WebSocketImpl, WrappedByteChannel)} 63 | **/ 64 | public static boolean readMore(final ByteBuffer buf, WebSocketImpl ws, 65 | WrappedByteChannel channel) throws IOException { 66 | buf.clear(); 67 | int read = channel.readMore(buf); 68 | buf.flip(); 69 | 70 | if (read == -1) { 71 | ws.eot(); 72 | return false; 73 | } 74 | return channel.isNeedRead(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/commands/GetMSSPortCommand.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.commands; 2 | 3 | import de.maxgb.minecraft.second_screen.SecondScreenMod; 4 | import net.minecraft.command.CommandException; 5 | import net.minecraft.command.ICommand; 6 | import net.minecraft.command.ICommandSender; 7 | import net.minecraft.server.MinecraftServer; 8 | import net.minecraft.util.math.BlockPos; 9 | 10 | import javax.annotation.Nullable; 11 | import java.util.ArrayList; 12 | import java.util.Collections; 13 | import java.util.List; 14 | 15 | /** 16 | * Returns the port the mod listens to 17 | * @author Max 18 | * 19 | */ 20 | @SuppressWarnings({ "rawtypes", "unchecked" }) 21 | public class GetMSSPortCommand extends BaseCommand { 22 | 23 | private List aliase; 24 | 25 | public GetMSSPortCommand() { 26 | aliase = new ArrayList(); 27 | aliase.add("getmssport"); 28 | aliase.add("getMSSPort"); 29 | aliase.add("getmssPort"); 30 | } 31 | 32 | @Override 33 | public int compareTo(ICommand o) { 34 | 35 | return 0; 36 | } 37 | 38 | 39 | @Override 40 | public String getUsage(ICommandSender var1) { 41 | return "/getMssPort"; 42 | } 43 | 44 | @Override 45 | public boolean isUsernameIndex(String[] var1, int var2) { 46 | 47 | return false; 48 | } 49 | 50 | @Override 51 | public String getName() { 52 | return "getMssPort"; 53 | } 54 | 55 | @Override 56 | public List getAliases() { 57 | return aliase; 58 | } 59 | 60 | @Override 61 | public void execute(MinecraftServer server, ICommandSender sender, String[] args) 62 | throws CommandException { 63 | if (SecondScreenMod.instance.webSocketListener.isRunning()) { 64 | sendMessage(sender, "Minecraft Second Screen Port: " + SecondScreenMod.instance.port); 65 | } else { 66 | 67 | sendMessage(sender, "Minecraft Second Screen Port: " + SecondScreenMod.instance.port 68 | + ". But the mod isnt running. Error: " + SecondScreenMod.instance.webSocketListener.getError()); 69 | } 70 | 71 | } 72 | 73 | @Override 74 | public boolean checkPermission(MinecraftServer server, ICommandSender sender) { 75 | return true; 76 | } 77 | 78 | @Override 79 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { 80 | return Collections.emptyList(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/shared/java/de/maxgb/minecraft/second_screen/shared/ModVersion.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.shared; 2 | 3 | /** 4 | * Version class which should be used in the clients to determine which features 5 | * are available with the mod feature id which is sent on connect 6 | * 7 | * @author Max 8 | * 9 | */ 10 | public class ModVersion { 11 | public static ModVersion getVersion(int feature_id) { 12 | 13 | ModVersion v = new ModVersion(); 14 | 15 | // Set Features 16 | if(feature_id>=6){ 17 | v.extendedplayer=true; 18 | } 19 | if(feature_id>=5){ 20 | v.getchat=true; 21 | } 22 | if (feature_id >= 4) { 23 | v.sendchat = true; 24 | v.controlRed = true; 25 | v.newest = true; 26 | 27 | } 28 | if (feature_id >= 3) { 29 | v.chat = true; 30 | 31 | } 32 | if (feature_id >= 2) { 33 | v.inventoryinfo_simple = true; 34 | 35 | } 36 | if (feature_id >= 1) { 37 | v.versionid = feature_id; 38 | v.playerinfo = true; 39 | v.serverinfo = true; 40 | v.worldinfo = true; 41 | } 42 | return v; 43 | } 44 | 45 | private boolean playerinfo = false; 46 | private boolean serverinfo = false; 47 | private boolean worldinfo = false; 48 | private boolean inventoryinfo_simple = false; 49 | private boolean chat = false; 50 | private int versionid = 0; 51 | private boolean newest = false; 52 | private boolean sendchat = false; 53 | private boolean controlRed = false; 54 | private boolean getchat=false; 55 | private boolean extendedplayer=false; 56 | 57 | public int getVersionId() { 58 | return versionid; 59 | } 60 | 61 | public boolean isInventoryinfo() { 62 | return inventoryinfo_simple; 63 | } 64 | 65 | public boolean isNewest() { 66 | return newest; 67 | } 68 | 69 | public boolean isPlayerinfo() { 70 | return playerinfo; 71 | } 72 | 73 | public boolean isServerinfo() { 74 | return serverinfo; 75 | } 76 | 77 | public boolean isWorldinfo() { 78 | return worldinfo; 79 | } 80 | 81 | public boolean isChat() { 82 | return chat; 83 | } 84 | 85 | public boolean isSendChat() { 86 | return sendchat; 87 | } 88 | 89 | public boolean isControlRed() { 90 | return this.controlRed; 91 | } 92 | 93 | public boolean isGetChat(){ 94 | return this.getchat; 95 | } 96 | public boolean isExtendendPlayer(){ 97 | return this.extendedplayer; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/commands/GetIPCommand.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.commands; 2 | 3 | import de.maxgb.minecraft.second_screen.SecondScreenMod; 4 | import net.minecraft.command.CommandException; 5 | import net.minecraft.command.ICommand; 6 | import net.minecraft.command.ICommandSender; 7 | import net.minecraft.server.MinecraftServer; 8 | import net.minecraft.util.math.BlockPos; 9 | 10 | import javax.annotation.Nullable; 11 | import java.util.ArrayList; 12 | import java.util.Collections; 13 | import java.util.List; 14 | 15 | /** 16 | * Returns the IP the mod is running on or if not running the error message 17 | * @author Max 18 | * 19 | */ 20 | @SuppressWarnings({ "rawtypes", "unchecked" }) 21 | public class GetIPCommand extends BaseCommand { 22 | 23 | private List aliases; 24 | 25 | 26 | public GetIPCommand() { 27 | this.aliases = new ArrayList(); 28 | this.aliases.add("getIP"); 29 | this.aliases.add("getip"); 30 | this.aliases.add("getIp"); 31 | this.aliases.add("gethostname"); 32 | } 33 | 34 | 35 | 36 | @Override 37 | public int compareTo(ICommand arg0) { 38 | 39 | return 0; 40 | } 41 | 42 | 43 | @Override 44 | public String getUsage(ICommandSender var1) { 45 | return "/getIP"; 46 | } 47 | 48 | @Override 49 | public boolean isUsernameIndex(String[] var1, int var2) { 50 | return false; 51 | } 52 | 53 | @Override 54 | public String getName() { 55 | return "getIP"; 56 | } 57 | 58 | @Override 59 | public List getAliases() { 60 | return aliases; 61 | } 62 | 63 | 64 | @Override 65 | public void execute(MinecraftServer server, ICommandSender sender, String[] args) 66 | throws CommandException { 67 | if (SecondScreenMod.instance.webSocketListener.isRunning()) { 68 | sendMessage(sender, "IP: " + SecondScreenMod.instance.hostname); 69 | } else { 70 | 71 | sendMessage(sender, "IP: " + SecondScreenMod.instance.hostname + ". But the mod isnt running. Error: " 72 | + SecondScreenMod.instance.webSocketListener.getError()); 73 | } 74 | 75 | } 76 | 77 | @Override 78 | public boolean checkPermission(MinecraftServer server, ICommandSender sender) { 79 | return true; 80 | } 81 | 82 | @Override 83 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { 84 | return Collections.emptyList(); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/world_observer/NodeObserver.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.world_observer; 2 | 3 | /* 4 | import net.minecraft.block.Block; 5 | import net.minecraft.tileentity.TileEntity; 6 | import net.minecraft.world.World; 7 | 8 | import org.json.JSONArray; 9 | import org.json.JSONObject; 10 | 11 | import scala.collection.concurrent.INode; 12 | import de.maxgb.minecraft.second_screen.util.Logger; 13 | 14 | //@formatter:off 15 | /* JSONStructure: 16 | * <"th_node":JSONArray> 17 | * which contains one JSONObject for each block 18 | * JSONObject contains: 19 | * <"label":String> 20 | * <"aspects":JSONObject> 21 | * which contains multiple 22 | * 0) { 73 | parent.put("th_node", info); 74 | info = null; 75 | } 76 | 77 | } 78 | 79 | @Override 80 | public int getId() { 81 | return ID; 82 | } 83 | 84 | @Override 85 | public String getIdentifier() { 86 | return "Thaumcraft_Node"; 87 | } 88 | 89 | @Override 90 | public String getShortIndentifier() { 91 | return "node"; 92 | } 93 | 94 | } 95 | */ 96 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/commands/mss_sub/RegisterUserCommand.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.commands.mss_sub; 2 | 3 | import net.minecraft.command.ICommandSender; 4 | import net.minecraft.entity.player.EntityPlayer; 5 | import de.maxgb.minecraft.second_screen.commands.BaseCommand; 6 | import de.maxgb.minecraft.second_screen.data.UserManager; 7 | import de.maxgb.minecraft.second_screen.util.Logger; 8 | 9 | /** 10 | * Command to register a second screen user 11 | * Only used if auth_required is enabled 12 | * User can set a pass for his username 13 | * Server or Rcon can set pass for any username 14 | * @author Max 15 | * 16 | */ 17 | public class RegisterUserCommand implements MssCommand.MssSubCommand { 18 | 19 | private static final String TAG = "RegisterUserCommand"; 20 | 21 | @Override 22 | public boolean canCommandSenderUseCommand(ICommandSender var1) { 23 | 24 | return false; 25 | } 26 | 27 | @Override 28 | public String getCommandName() { 29 | return "register"; 30 | } 31 | 32 | @Override 33 | public void sendCommandUsage(ICommandSender var1) { 34 | if (var1.getName().equals("Rcon") || var1.getName().equals("Server")) { 35 | sendMessage(var1, "register "); 36 | } 37 | else{ 38 | sendMessage(var1,"register "); 39 | } 40 | } 41 | 42 | @Override 43 | public void processCommand(ICommandSender var1, String[] var2) { 44 | if (var2 == null || var2.length == 0) { 45 | sendMessage(var1, "Missing arguments. Usage:"); 46 | sendCommandUsage(var1); 47 | return; 48 | } 49 | if (var1 instanceof EntityPlayer) { 50 | if (var2.length != 1) { 51 | sendMessage(var1, "Wrong arguments. Usage:"); 52 | sendCommandUsage(var1); 53 | return; 54 | } 55 | 56 | int hash = var2[0].hashCode(); 57 | UserManager.addUser(var1.getName(), hash); 58 | BaseCommand.sendMessage(var1, "Added user " + var1.getName()); 59 | Logger.i(TAG, "Added user " + var1.getName() + " with pass: " + hash); 60 | 61 | return; 62 | 63 | } else if (var1.getName().equals("Rcon") || var1.getName().equals("Server")) { 64 | if (var2.length != 2) { 65 | sendMessage(var1, "Wrong arguments. Usage:"); 66 | sendCommandUsage(var1); 67 | return; 68 | } 69 | int hash = var2[1].hashCode(); 70 | UserManager.addUser(var2[0], hash); 71 | BaseCommand.sendMessage(var1, "Added user " + var2[0]); 72 | Logger.i(TAG, "Added user " + var2[0] + " with pass: " + hash); 73 | 74 | return; 75 | } else { 76 | Logger.w(TAG, var1.getName() + " tried to add a user, but what is he?"); 77 | } 78 | 79 | } 80 | 81 | private void sendMessage(ICommandSender var1,String msg){ 82 | BaseCommand.sendMessage(var1, msg); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/world_observer/InventoryObserver.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.world_observer; 2 | 3 | import de.maxgb.minecraft.second_screen.util.Logger; 4 | import net.minecraft.block.state.IBlockState; 5 | import net.minecraft.inventory.IInventory; 6 | import net.minecraft.item.ItemStack; 7 | import net.minecraft.tileentity.TileEntity; 8 | import net.minecraft.world.World; 9 | import org.json.JSONArray; 10 | import org.json.JSONObject; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map.Entry; 14 | 15 | //@formatter:off 16 | /*JSONStructure: 17 | * <"inv":JSONObject> 18 | * which contains for each block: 19 | * 20 | * which contains JSONArrays with 21 | * <0=displayname:String> 22 | * <1=stacksize:int> 23 | */ 24 | //@formatter:on 25 | 26 | /** 27 | * Observer which is designed to observe any inventory which implements IInventory 28 | * @author Max 29 | * 30 | */ 31 | public class InventoryObserver implements ObservedBlock.ObservingType { 32 | 33 | private final int ID = 3; 34 | private JSONObject info; 35 | 36 | @Override 37 | public boolean addInfoForBlock(World world, ObservedBlock block) { 38 | if (info == null) { 39 | info = new JSONObject(); 40 | } 41 | try { 42 | JSONArray inv = new JSONArray(); 43 | IInventory chest = (IInventory) world.getTileEntity(block.pos); 44 | HashMap items=new HashMap(); 45 | for (int i = 0; i < chest.getSizeInventory(); i++) { 46 | ItemStack s = chest.getStackInSlot(i); 47 | if (s != null) { 48 | String name=s.getDisplayName(); 49 | if(items.containsKey(name)){ 50 | items.put(name, items.get(name) + s.getCount()); 51 | } 52 | else{ 53 | items.put(name, s.getCount()); 54 | } 55 | 56 | } 57 | } 58 | for(Entry e:items.entrySet()){ 59 | inv.put(new JSONArray().put(e.getKey()).put(e.getValue())); 60 | } 61 | info.put(block.label, inv); 62 | return true; 63 | } catch (Exception e) { 64 | Logger.e("Inventory Observer", "Failed to gather block info -> remove", e); 65 | return false; 66 | } 67 | } 68 | 69 | @Override 70 | public boolean canObserve(IBlockState block, TileEntity tile) { 71 | return tile != null && tile instanceof IInventory; 72 | } 73 | 74 | @Override 75 | public void finishInfoCreation(JSONObject parent) { 76 | if (info != null && info.length() > 0) { 77 | parent.put("inv", info); 78 | info = null; 79 | } 80 | 81 | } 82 | 83 | @Override 84 | public int getId() { 85 | return ID; 86 | } 87 | 88 | @Override 89 | public String getIdentifier() { 90 | return "Inventory"; 91 | } 92 | 93 | @Override 94 | public String getShortIndentifier() { 95 | return "i"; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/world_observer/RFEnergyStorageObserver.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.world_observer; 2 | 3 | /* 4 | import net.minecraft.block.Block; 5 | import net.minecraft.tileentity.TileEntity; 6 | import net.minecraft.world.World; 7 | 8 | import org.json.JSONArray; 9 | import org.json.JSONObject; 10 | 11 | import de.maxgb.minecraft.second_screen.util.Logger; 12 | 13 | //@formatter:off 14 | /* 15 | * JSONStructure: 16 | * <"rf_es":JSONArray> 17 | * contains one JSONArray for each block 18 | * Array contains: 19 | * <0=label:String> 20 | * <1=energystored:int> 21 | * <2=maxenergystored:int> 22 | * 23 | //@formatter:on 24 | 25 | /** 26 | * Observer class which is designed to observe redstone flux energy storage container which implement IEnergyStorage or IEngeryHandler 27 | * @author Max 28 | * 29 | * 30 | public class RFEnergyStorageObserver implements ObservedBlock.ObservingType { 31 | 32 | private final int ID = 4; 33 | private JSONArray info; 34 | 35 | @Override 36 | public boolean addInfoForBlock(World world, ObservedBlock block) { 37 | if (info == null) { 38 | info = new JSONArray(); 39 | } 40 | if (block.side == -1) { 41 | return false; 42 | } 43 | JSONArray es = new JSONArray(); 44 | es.put(block.label); 45 | 46 | TileEntity storage = world.getTileEntity(block.x, block.y, block.z); 47 | if (storage != null && storage instanceof IEnergyHandler) { 48 | IEnergyHandler s = (IEnergyHandler) storage; 49 | es.put(s.getEnergyStored(ForgeDirection.getOrientation(block.side))).put( 50 | s.getMaxEnergyStored(ForgeDirection.getOrientation(block.side))); 51 | info.put(es); 52 | return true; 53 | } else if (storage != null && storage instanceof IEnergyStorage) { 54 | IEnergyStorage s = (IEnergyStorage) storage; 55 | es.put(s.getEnergyStored()).put(s.getMaxEnergyStored()); 56 | info.put(es); 57 | return true; 58 | } else { 59 | Logger.w("RF_Energy_Storage Observer", "Observed Block is no energy storage"); 60 | return false; 61 | } 62 | } 63 | 64 | @Override 65 | public boolean canObserve(Block block, TileEntity tile) { 66 | if (tile != null && (tile instanceof IEnergyHandler || tile instanceof IEnergyStorage)) { 67 | 68 | return true; 69 | } 70 | return false; 71 | } 72 | 73 | @Override 74 | public void finishInfoCreation(JSONObject parent) { 75 | if (info != null && info.length() > 0) { 76 | parent.put("rf_es", info); 77 | info = null; 78 | } 79 | 80 | } 81 | 82 | @Override 83 | public int getId() { 84 | return ID; 85 | } 86 | 87 | @Override 88 | public String getIdentifier() { 89 | return "RF_energy_storage"; 90 | } 91 | 92 | @Override 93 | public String getShortIndentifier() { 94 | return "rf_es"; 95 | } 96 | 97 | } 98 | */ 99 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/util/Charsetfunctions.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.nio.ByteBuffer; 5 | import java.nio.charset.CharacterCodingException; 6 | import java.nio.charset.Charset; 7 | import java.nio.charset.CharsetDecoder; 8 | import java.nio.charset.CodingErrorAction; 9 | 10 | import org.java_websocket.exceptions.InvalidDataException; 11 | import org.java_websocket.framing.CloseFrame; 12 | 13 | public class Charsetfunctions { 14 | 15 | public static CodingErrorAction codingErrorAction = CodingErrorAction.REPORT; 16 | 17 | /* 18 | * @return ASCII encoding in bytes 19 | */ 20 | public static byte[] asciiBytes(String s) { 21 | try { 22 | return s.getBytes("ASCII"); 23 | } catch (UnsupportedEncodingException e) { 24 | throw new RuntimeException(e); 25 | } 26 | } 27 | 28 | public static void main(String[] args) throws InvalidDataException { 29 | stringUtf8(utf8Bytes("\0")); 30 | stringAscii(asciiBytes("\0")); 31 | } 32 | 33 | public static String stringAscii(byte[] bytes) { 34 | return stringAscii(bytes, 0, bytes.length); 35 | } 36 | 37 | public static String stringAscii(byte[] bytes, int offset, int length) { 38 | try { 39 | return new String(bytes, offset, length, "ASCII"); 40 | } catch (UnsupportedEncodingException e) { 41 | throw new RuntimeException(e); 42 | } 43 | } 44 | 45 | public static String stringUtf8(byte[] bytes) throws InvalidDataException { 46 | return stringUtf8(ByteBuffer.wrap(bytes)); 47 | } 48 | 49 | /* 50 | * public static String stringUtf8( byte[] bytes, int off, int length ) 51 | * throws InvalidDataException { CharsetDecoder decode = Charset.forName( 52 | * "UTF8" ).newDecoder(); decode.onMalformedInput( codingErrorAction ); 53 | * decode.onUnmappableCharacter( codingErrorAction ); //decode.replaceWith( 54 | * "X" ); String s; try { s = decode.decode( ByteBuffer.wrap( bytes, off, 55 | * length ) ).toString(); } catch ( CharacterCodingException e ) { throw new 56 | * InvalidDataException( CloseFrame.NO_UTF8, e ); } return s; } 57 | */ 58 | 59 | public static String stringUtf8(ByteBuffer bytes) 60 | throws InvalidDataException { 61 | CharsetDecoder decode = Charset.forName("UTF8").newDecoder(); 62 | decode.onMalformedInput(codingErrorAction); 63 | decode.onUnmappableCharacter(codingErrorAction); 64 | // decode.replaceWith( "X" ); 65 | String s; 66 | try { 67 | bytes.mark(); 68 | s = decode.decode(bytes).toString(); 69 | bytes.reset(); 70 | } catch (CharacterCodingException e) { 71 | throw new InvalidDataException(CloseFrame.NO_UTF8, e); 72 | } 73 | return s; 74 | } 75 | 76 | /* 77 | * @return UTF-8 encoding in bytes 78 | */ 79 | public static byte[] utf8Bytes(String s) { 80 | try { 81 | return s.getBytes("UTF8"); 82 | } catch (UnsupportedEncodingException e) { 83 | throw new RuntimeException(e); 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Minecraft Forge Template 2 | 3 | # Minecraft 4 | crash-reports/ 5 | /.metadata/ 6 | /libs/ 7 | /saves/ 8 | /resourcepacks/ 9 | /logs/ 10 | /mods/ 11 | /screenshots/ 12 | /classes/ 13 | options.txt 14 | usernamecache.json 15 | banned-ips.json 16 | banned-players.json 17 | eula.txt 18 | ops.json 19 | server.properties 20 | usercache.json 21 | whitelist.json 22 | 23 | # Other 24 | /run/ 25 | Thumbs.db 26 | .directory 27 | ### Eclipse template 28 | 29 | .metadata 30 | bin/ 31 | tmp/ 32 | *.tmp 33 | *.bak 34 | *.swp 35 | *~.nib 36 | local.properties 37 | .settings/ 38 | .loadpath 39 | .recommenders 40 | 41 | # Eclipse Core 42 | .project 43 | 44 | # External tool builders 45 | .externalToolBuilders/ 46 | 47 | # Locally stored "Eclipse launch configurations" 48 | *.launch 49 | 50 | # PyDev specific (Python IDE for Eclipse) 51 | *.pydevproject 52 | 53 | # CDT-specific (C/C++ Development Tooling) 54 | .cproject 55 | 56 | # JDT-specific (Eclipse Java Development Tools) 57 | .classpath 58 | 59 | # Java annotation processor (APT) 60 | .factorypath 61 | 62 | # PDT-specific (PHP Development Tools) 63 | .buildpath 64 | 65 | # sbteclipse plugin 66 | .target 67 | 68 | # Tern plugin 69 | .tern-project 70 | 71 | # TeXlipse plugin 72 | .texlipse 73 | 74 | # STS (Spring Tool Suite) 75 | .springBeans 76 | 77 | # Code Recommenders 78 | .recommenders/ 79 | 80 | # Scala IDE specific (Scala & Java development for Eclipse) 81 | .cache-main 82 | .scala_dependencies 83 | .worksheet 84 | ### JetBrains template 85 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 86 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 87 | 88 | .idea 89 | 90 | ## File-based project format: 91 | *.iws 92 | 93 | ## Plugin-specific files: 94 | 95 | # IntelliJ 96 | /out/ 97 | *.iml 98 | *.ipr 99 | 100 | # mpeltonen/sbt-idea plugin 101 | .idea_modules/ 102 | 103 | # JIRA plugin 104 | atlassian-ide-plugin.xml 105 | 106 | # Crashlytics plugin (for Android Studio and IntelliJ) 107 | com_crashlytics_export_strings.xml 108 | crashlytics.properties 109 | crashlytics-build.properties 110 | fabric.properties 111 | ### Java template 112 | # Compiled class file 113 | *.class 114 | 115 | # Log file 116 | *.log 117 | 118 | # BlueJ files 119 | *.ctxt 120 | 121 | # Mobile Tools for Java (J2ME) 122 | .mtj.tmp/ 123 | 124 | # Package Files # 125 | *.jar 126 | *.war 127 | *.ear 128 | *.zip 129 | *.tar.gz 130 | *.rar 131 | 132 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 133 | hs_err_pid* 134 | ### Gradle template 135 | .gradle 136 | /build/ 137 | 138 | # Ignore Gradle GUI config 139 | gradle-app.setting 140 | 141 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 142 | !gradle-wrapper.jar 143 | 144 | # Cache of project 145 | .gradletasknamecache 146 | 147 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 148 | # gradle/wrapper/gradle-wrapper.properties -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/data/DataStorageDriver.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.data; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileNotFoundException; 7 | import java.io.FileReader; 8 | import java.io.FileWriter; 9 | import java.io.IOException; 10 | import java.util.ArrayList; 11 | 12 | import net.minecraftforge.common.DimensionManager; 13 | import de.maxgb.minecraft.second_screen.util.Logger; 14 | 15 | /** 16 | * Class which should manage all file related operations 17 | * @author Max 18 | * 19 | */ 20 | public class DataStorageDriver { 21 | private final static String TAG = "DataStorageDriver"; 22 | 23 | public static File getSaveDir() { 24 | return new File(DimensionManager.getCurrentSaveRootDirectory(), "secondscreen"); 25 | } 26 | 27 | /** 28 | * Reads lines from given file 29 | * @param file 30 | * @return lines, null if exception 31 | */ 32 | private static ArrayList readFromFile(File file) { 33 | 34 | if (!file.exists()) { 35 | Logger.i(TAG, "File: " + file.getPath() + " does not exist"); 36 | return null; 37 | } 38 | ArrayList lines = new ArrayList(); 39 | 40 | try { 41 | BufferedReader reader = new BufferedReader(new FileReader(file)); 42 | String line = reader.readLine(); 43 | while (line != null) { 44 | lines.add(line); 45 | line = reader.readLine(); 46 | } 47 | reader.close(); 48 | return lines; 49 | 50 | } catch (FileNotFoundException e) { 51 | Logger.w(TAG, "File: " + file.getAbsolutePath() + " not found"); 52 | return null; 53 | } catch (IOException e) { 54 | Logger.e(TAG, "Failed to read from file: " + file.getAbsolutePath(), e); 55 | return null; 56 | } 57 | } 58 | 59 | /** 60 | * Reads from a file in the world folder 61 | * @param filename 62 | * @return lines of file, null if error 63 | */ 64 | public static ArrayList readFromWorldFile(String filename) { 65 | File f = new File(getSaveDir(), filename); 66 | 67 | return readFromFile(f); 68 | 69 | } 70 | 71 | 72 | private static void writeToFile(File file, ArrayList lines) { 73 | try { 74 | getSaveDir().mkdirs(); 75 | file.createNewFile(); 76 | file.setReadable(true); 77 | file.setWritable(true); 78 | BufferedWriter writer = new BufferedWriter(new FileWriter(file)); 79 | for (String line : lines) { 80 | writer.append(line); 81 | writer.newLine(); 82 | } 83 | writer.flush(); 84 | writer.close(); 85 | 86 | } catch (IOException e) { 87 | e.printStackTrace(); 88 | Logger.e(TAG, "Failed writing the String Array to the file: " + file.getAbsolutePath(), e); 89 | } 90 | } 91 | 92 | /** 93 | * Writes to a file in the world folder 94 | * @param filename 95 | * @param lines 96 | */ 97 | public static void writeToWorldFile(String filename, ArrayList lines) { 98 | File f = new File(getSaveDir(), filename); 99 | writeToFile(f, lines); 100 | 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/shared/java/de/maxgb/minecraft/second_screen/shared/PROTOKOLL.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.shared; 2 | 3 | /** 4 | * Protokoll constant class for the communication 5 | * @author Max 6 | * 7 | */ 8 | public class PROTOKOLL { 9 | 10 | // Listener managment commands 11 | public static final String REGISTER_COMMAND_BEGIN = "r-"; 12 | public static final String UNREGISTER_COMMAND_BEGIN = "ur-"; 13 | 14 | // Listeners 15 | public static final String S_PLAYERINFO_LISTENER = "spil"; 16 | public static final String PLAYER_INVENTORY_LISTENER = "pil"; 17 | public static final String SERVER_INFO_LISTENER = "sil"; 18 | public static final String WORLD_INFO_LISTENER = "wil"; 19 | public static final String CHAT_LISTENER = "cl"; 20 | public static final String ALL_LISTENERS = "all"; 21 | 22 | // Action commands 23 | public static final String ACTION_COMMAND_BEGIN = "do-"; 24 | public static final String ACTION_RESULT_BEGIN = "doresult-"; 25 | 26 | /** 27 | * Chat message action. Followed by Json string containing "msg"(String) 28 | */ 29 | public static final String A_CHAT_MSG = "cm"; 30 | /** 31 | * Switch lever state action. Followed by Json string containing 32 | * "label"(String),"state"(Boolean) 33 | */ 34 | public static final String A_RED_CONTROL = "rc"; 35 | 36 | /** 37 | * Asks for the latest chat messages. No params 38 | */ 39 | public static final String A_GET_CHAT = "gc"; 40 | 41 | // Connection 42 | 43 | /** 44 | * Connect message Connection procedure: C-S: CONNECT S-C: CONNECT_RESULT 45 | * C-S: LOGIN (if auth is required, with password hash) S-C: LOGIN_RESULT 46 | * S-C or C-S DISCONNECT or SERVER_STOPPING All messages which contain 47 | * success=0 should contain an "error" field with an error message 48 | */ 49 | public static final String CONNECT = "connecting"; 50 | 51 | /** 52 | * Connect result send to the client. Followed by Json string containing: 53 | * "versionid"(int),"minecraftversion"(String),"login_required"(boolean) 54 | */ 55 | public static final String CONNECT_RESULT = "conncted";//!!!typing mistake 56 | /** 57 | * Login message send to the server. Followed by Json string containing: 58 | * "username"(String),"password"(md5 hash of password as 59 | * String),"clientid"(String),"clientversion"(int) 60 | */ 61 | public static final String LOGIN = "login"; 62 | /** 63 | * Login result message send to the client. Followed by Json string 64 | * containing: "success"(int 65 | * [0/1]),"clientupdate"(boolean),"clientupdatenecessary"(boolean) 66 | */ 67 | public static final String LOGIN_RESULT = "login_result"; 68 | 69 | public static final String SERVER_STOPPING = "server_stopping"; 70 | public static final String DISCONNECT = "disconnect"; 71 | 72 | 73 | 74 | // Etc 75 | /** 76 | * If the message is unknown. Followed by " ["+orginalmessage+"]" 77 | */ 78 | public static final String UNKNOWN = "unknown"; 79 | 80 | /** 81 | * If an error occured, while processing a message. Followed by error 82 | * message and by " ["+orginalmessage+"]" 83 | */ 84 | public static final String ERROR = "error"; 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/actions/ActionManager.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.actions; 2 | 3 | import java.util.HashMap; 4 | 5 | import org.json.JSONObject; 6 | 7 | import de.maxgb.minecraft.second_screen.shared.PROTOKOLL; 8 | import de.maxgb.minecraft.second_screen.util.Logger; 9 | import de.maxgb.minecraft.second_screen.util.User; 10 | 11 | /** 12 | * Manages all possible actions 13 | * @author Max 14 | * 15 | */ 16 | public class ActionManager { 17 | 18 | public interface ActionResultListener { 19 | public void onActionResult(String command, JSONObject r); 20 | } 21 | 22 | /** 23 | * Interface for actions, which can be executed by the client 24 | * 25 | * @author Max 26 | * 27 | */ 28 | public interface IAction { 29 | /** 30 | * Should execute the action 31 | * 32 | * @param param 33 | * Params 34 | * @param listener 35 | * Listener which should get the action result 36 | * @return 37 | */ 38 | public void doAction(JSONObject param, User user, ActionResultListener listener); 39 | } 40 | 41 | private static HashMap actions; 42 | private static final String TAG = "ActionManager"; 43 | 44 | /** 45 | * Executes an action with the given params. Actionresult is send to the 46 | * listener 47 | * 48 | * @param command 49 | * Command which corrosponds to the action 50 | * @param params 51 | * Params 52 | * @param listener 53 | * Listener to receive the action result 54 | * @return whether the action was found or not 55 | */ 56 | public static boolean doAction(String command, final JSONObject params, final User user, 57 | final ActionResultListener listener) { 58 | if (!actions.containsKey(command)) { 59 | Logger.w(TAG, "No action fitting: " + command + " found"); 60 | return false; 61 | } 62 | final IAction a = actions.get(command); 63 | Thread action = new Thread(new Runnable() { 64 | 65 | @Override 66 | public void run() { 67 | a.doAction(params, user, listener); 68 | 69 | } 70 | 71 | }); 72 | action.start(); 73 | 74 | return true; 75 | } 76 | 77 | /** 78 | * Registers a action, which can then be executed 79 | * 80 | * @param command 81 | * The command which represents the action 82 | * @param action 83 | * The action 84 | */ 85 | public static void registerAction(String command, IAction action) { 86 | if (actions == null) { 87 | actions = new HashMap(); 88 | } 89 | actions.put(command, action); 90 | } 91 | 92 | /** 93 | * Registers all standard actions 94 | */ 95 | public static void registerStandardActions() { 96 | registerAction(PROTOKOLL.A_CHAT_MSG, new ChatMessageAction()); 97 | registerAction(PROTOKOLL.A_RED_CONTROL, new RedstoneControlAction()); 98 | registerAction(PROTOKOLL.A_GET_CHAT, new GetLastChatAction()); 99 | } 100 | 101 | public static void removeAllActions() { 102 | actions = new HashMap(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/world_observer/RedstoneObserver.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.world_observer; 2 | 3 | import net.minecraft.block.BlockLever; 4 | import net.minecraft.block.state.IBlockState; 5 | import net.minecraft.tileentity.TileEntity; 6 | import net.minecraft.util.EnumFacing; 7 | import net.minecraft.util.EnumParticleTypes; 8 | import net.minecraft.world.World; 9 | import net.minecraftforge.fml.common.FMLCommonHandler; 10 | import org.json.JSONArray; 11 | import org.json.JSONObject; 12 | 13 | public class RedstoneObserver implements ObservedBlock.ObservingType { 14 | 15 | public final static int ID = 1; 16 | 17 | public static boolean canObserve(IBlockState block) { 18 | if (block != null && block.getBlock() instanceof BlockLever) { 19 | return true; 20 | } else if (block != null && block.isNormalCube()) { 21 | return true; 22 | } 23 | return false; 24 | } 25 | 26 | /** 27 | * Sets the state of a lever 28 | * 29 | * @param b 30 | * Block 31 | * @param state 32 | * State 33 | * @return Whether the block is a lever or not 34 | */ 35 | public static boolean setLeverState(ObservedBlock b, boolean state) { 36 | if (b.type == ID) { 37 | World w = FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(b.dimensionId); 38 | 39 | if (w.getBlockState(b.pos).getBlock() instanceof BlockLever) { 40 | IBlockState st = w.getBlockState(b.pos); 41 | 42 | if (!st.getValue(BlockLever.POWERED).equals(state)) { 43 | st = st.withProperty(BlockLever.POWERED, state); 44 | w.setBlockState(b.pos, st, 3); 45 | w.notifyNeighborsOfStateChange(b.pos, w.getBlockState(b.pos).getBlock(), true); 46 | EnumFacing enumfacing1 = st.getValue(BlockLever.FACING).getFacing(); 47 | w.notifyNeighborsOfStateChange(b.pos.offset(enumfacing1.getOpposite()), w.getBlockState(b.pos).getBlock(), true); 48 | } 49 | 50 | 51 | w.spawnParticle(EnumParticleTypes.REDSTONE, b.pos.getX(), b.pos.getY() + 1, b.pos.getZ(), 0.0D, 255.0D, 0.0D); 52 | 53 | return true; 54 | } 55 | } 56 | return false; 57 | } 58 | 59 | private JSONArray info; 60 | 61 | @Override 62 | public boolean addInfoForBlock(World world, ObservedBlock block) { 63 | if (info == null) { 64 | info = new JSONArray(); 65 | } 66 | JSONArray in = new JSONArray(); 67 | in.put(block.label).put((world.isBlockIndirectlyGettingPowered(block.pos)>0)) 68 | .put(block.getBlock(world) instanceof BlockLever); 69 | 70 | info.put(in); 71 | return true; 72 | } 73 | 74 | @Override 75 | public boolean canObserve(IBlockState block, TileEntity tile) { 76 | return RedstoneObserver.canObserve(block); 77 | } 78 | 79 | @Override 80 | public void finishInfoCreation(JSONObject parent) { 81 | if (info != null && info.length() > 0) { 82 | parent.put("redstone", info); 83 | info = null; 84 | } 85 | 86 | } 87 | 88 | @Override 89 | public int getId() { 90 | return RedstoneObserver.ID; 91 | } 92 | 93 | @Override 94 | public String getIdentifier() { 95 | return "redstone"; 96 | } 97 | 98 | @Override 99 | public String getShortIndentifier() { 100 | return "r"; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/actions/RedstoneControlAction.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.actions; 2 | 3 | import net.minecraftforge.fml.common.FMLCommonHandler; 4 | 5 | import org.json.JSONObject; 6 | 7 | import de.maxgb.minecraft.second_screen.actions.ActionManager.ActionResultListener; 8 | import de.maxgb.minecraft.second_screen.actions.ActionManager.IAction; 9 | import de.maxgb.minecraft.second_screen.data.ObservingManager; 10 | import de.maxgb.minecraft.second_screen.info_listener.WorldInfoListener; 11 | import de.maxgb.minecraft.second_screen.shared.PROTOKOLL; 12 | import de.maxgb.minecraft.second_screen.util.ForceUpdateEvent; 13 | import de.maxgb.minecraft.second_screen.util.Logger; 14 | import de.maxgb.minecraft.second_screen.util.User; 15 | import de.maxgb.minecraft.second_screen.world_observer.ObservedBlock; 16 | import de.maxgb.minecraft.second_screen.world_observer.RedstoneObserver; 17 | 18 | /** 19 | * Action which can change levers ingame 20 | * @author Max 21 | * 22 | */ 23 | public class RedstoneControlAction implements IAction { 24 | 25 | private static final String TAG = "RedstoneControlAction"; 26 | private static final String PERMISSION = "control_redstone"; 27 | 28 | @Override 29 | public void doAction(JSONObject param, User user, ActionResultListener listener) { 30 | if (!param.has("label")) { 31 | Logger.w(TAG, "Params did not include label"); 32 | JSONObject result = new JSONObject(); 33 | result.put("success", 0); 34 | result.put("error", "Params did not include label"); 35 | 36 | listener.onActionResult(PROTOKOLL.A_RED_CONTROL, result); 37 | return; 38 | } 39 | if (!param.has("state")) { 40 | Logger.w(TAG, "Params did not include state"); 41 | JSONObject result = new JSONObject(); 42 | result.put("success", 0); 43 | result.put("error", "Params did not include state"); 44 | 45 | listener.onActionResult(PROTOKOLL.A_RED_CONTROL, result); 46 | return; 47 | } 48 | if (!user.isAllowedTo(PERMISSION, true)) { 49 | Logger.w(TAG, "User " + user.username + " is not allowed to execute this command"); 50 | JSONObject result = new JSONObject(); 51 | result.put("success", 0); 52 | result.put("allowed", false); 53 | 54 | listener.onActionResult(PROTOKOLL.A_RED_CONTROL, result); 55 | return; 56 | } 57 | String label = param.getString("label"); 58 | boolean state = param.getBoolean("state"); 59 | for (ObservedBlock o : ObservingManager.getObservedBlocks(user.username, true)) { 60 | if (o.getLabel().equals(label)) { 61 | 62 | if (RedstoneObserver.setLeverState(o, state)) { 63 | JSONObject result = new JSONObject(); 64 | result.put("success", 1); 65 | result.put("allowed", true); 66 | 67 | listener.onActionResult(PROTOKOLL.A_RED_CONTROL, result); 68 | FMLCommonHandler.instance().bus().post(new ForceUpdateEvent(WorldInfoListener.class)); 69 | return; 70 | } else { 71 | Logger.w(TAG, "Block connected with this label is not a lever"); 72 | JSONObject result = new JSONObject(); 73 | result.put("success", 0); 74 | result.put("error", "Block connected with this label is not a lever"); 75 | 76 | listener.onActionResult(PROTOKOLL.A_RED_CONTROL, result); 77 | 78 | return; 79 | } 80 | } 81 | } 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/commands/ListInterfacesCommand.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.commands; 2 | 3 | import de.maxgb.minecraft.second_screen.util.Helper; 4 | import net.minecraft.block.Block; 5 | import net.minecraft.command.CommandException; 6 | import net.minecraft.command.ICommand; 7 | import net.minecraft.command.ICommandSender; 8 | import net.minecraft.entity.player.EntityPlayer; 9 | import net.minecraft.server.MinecraftServer; 10 | import net.minecraft.tileentity.TileEntity; 11 | import net.minecraft.util.math.BlockPos; 12 | import net.minecraft.util.math.RayTraceResult; 13 | import org.apache.commons.lang3.ClassUtils; 14 | 15 | import javax.annotation.Nullable; 16 | import java.util.ArrayList; 17 | import java.util.Collections; 18 | import java.util.List; 19 | 20 | /** 21 | * Command for development purpose 22 | * Returns all classes and interfaces the looked at block extends/implements 23 | * @author Max 24 | * 25 | */ 26 | @SuppressWarnings({ "rawtypes" }) 27 | public class ListInterfacesCommand extends BaseCommand { 28 | 29 | private List aliases; 30 | 31 | public ListInterfacesCommand() { 32 | this.aliases = new ArrayList(); 33 | aliases.add("liint"); 34 | } 35 | 36 | 37 | 38 | 39 | @Override 40 | public int compareTo(ICommand arg0) { 41 | 42 | return 0; 43 | } 44 | 45 | 46 | @Override 47 | public String getUsage(ICommandSender var1) { 48 | return "/listinterfaces"; 49 | } 50 | 51 | @Override 52 | public boolean isUsernameIndex(String[] var1, int var2) { 53 | return false; 54 | } 55 | 56 | @Override 57 | public String getName() { 58 | return "listinterfaces"; 59 | } 60 | 61 | @Override 62 | public List getAliases() { 63 | return aliases; 64 | } 65 | 66 | @Override 67 | public void execute(MinecraftServer server, ICommandSender var1, String[] var2) 68 | throws CommandException { 69 | EntityPlayer player; 70 | 71 | if (var1 instanceof EntityPlayer) { 72 | player = (EntityPlayer) var1; 73 | } else { 74 | sendMessage(var1, "Player only command"); 75 | return; 76 | } 77 | 78 | RayTraceResult p = Helper.getPlayerLookingSpot(player, true); 79 | if (p == null) { 80 | sendMessage(var1, "You have to look at a block"); 81 | return; 82 | } 83 | 84 | 85 | Block block = player.getEntityWorld().getBlockState(p.getBlockPos()).getBlock(); 86 | TileEntity tile = player.getEntityWorld().getTileEntity(p.getBlockPos()); 87 | 88 | if(block!=null){ 89 | sendMessage(var1,block.getClass().getName()); 90 | for(Class c : ClassUtils.getAllInterfaces(block.getClass())){ 91 | sendMessage(var1,c.getName()); 92 | } 93 | } 94 | if(tile!=null){ 95 | sendMessage(var1,tile.getClass().getName()); 96 | for(Class c : ClassUtils.getAllInterfaces(tile.getClass())){ 97 | sendMessage(var1,c.getName()); 98 | } 99 | } 100 | 101 | 102 | } 103 | 104 | @Override 105 | public boolean checkPermission(MinecraftServer server, ICommandSender sender) { 106 | return true; 107 | } 108 | 109 | @Override 110 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { 111 | return Collections.emptyList(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/api/java/org/json/JSONStringer.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2006 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.io.StringWriter; 28 | 29 | /** 30 | * JSONStringer provides a quick and convenient way of producing JSON text. The 31 | * texts produced strictly conform to JSON syntax rules. No whitespace is added, 32 | * so the results are ready for transmission or storage. Each instance of 33 | * JSONStringer can produce one JSON text. 34 | *

35 | * A JSONStringer instance provides a value method for appending 36 | * values to the text, and a key method for adding keys before 37 | * values in objects. There are array and endArray 38 | * methods that make and bound array values, and object and 39 | * endObject methods which make and bound object values. All of 40 | * these methods return the JSONWriter instance, permitting cascade style. For 41 | * example, 42 | * 43 | *

44 |  * myString = new JSONStringer().object().key("JSON").value("Hello, World!")
45 |  * 		.endObject().toString();
46 |  * 
47 | * 48 | * which produces the string 49 | * 50 | *
51 |  * {"JSON":"Hello, World!"}
52 |  * 
53 | *

54 | * The first method called must be array or object. 55 | * There are no methods for adding commas or colons. JSONStringer adds them for 56 | * you. Objects and arrays can be nested up to 20 levels deep. 57 | *

58 | * This can sometimes be easier than using a JSONObject to build a string. 59 | * 60 | * @author JSON.org 61 | * @version 2008-09-18 62 | */ 63 | public class JSONStringer extends JSONWriter { 64 | /** 65 | * Make a fresh JSONStringer. It can be used to build one JSON text. 66 | */ 67 | public JSONStringer() { 68 | super(new StringWriter()); 69 | } 70 | 71 | /** 72 | * Return the JSON text. This method is used to obtain the product of the 73 | * JSONStringer instance. It will return null if there was a 74 | * problem in the construction of the JSON text (such as the calls to 75 | * array were not properly balanced with calls to 76 | * endArray). 77 | * 78 | * @return The JSON text. 79 | */ 80 | @Override 81 | public String toString() { 82 | return this.mode == 'd' ? this.writer.toString() : null; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/framing/FramedataImpl1.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.framing; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.util.Arrays; 5 | 6 | import org.java_websocket.exceptions.InvalidDataException; 7 | import org.java_websocket.exceptions.InvalidFrameException; 8 | import org.java_websocket.util.Charsetfunctions; 9 | 10 | public class FramedataImpl1 implements FrameBuilder { 11 | protected static byte[] emptyarray = {}; 12 | protected boolean fin; 13 | protected Opcode optcode; 14 | private ByteBuffer unmaskedpayload; 15 | protected boolean transferemasked; 16 | 17 | public FramedataImpl1() { 18 | } 19 | 20 | /** 21 | * Helper constructor which helps to create "echo" frames. The new object 22 | * will use the same underlying payload data. 23 | **/ 24 | public FramedataImpl1(Framedata f) { 25 | fin = f.isFin(); 26 | optcode = f.getOpcode(); 27 | unmaskedpayload = f.getPayloadData(); 28 | transferemasked = f.getTransfereMasked(); 29 | } 30 | 31 | public FramedataImpl1(Opcode op) { 32 | this.optcode = op; 33 | unmaskedpayload = ByteBuffer.wrap(emptyarray); 34 | } 35 | 36 | @Override 37 | public void append(Framedata nextframe) throws InvalidFrameException { 38 | ByteBuffer b = nextframe.getPayloadData(); 39 | if (unmaskedpayload == null) { 40 | unmaskedpayload = ByteBuffer.allocate(b.remaining()); 41 | b.mark(); 42 | unmaskedpayload.put(b); 43 | b.reset(); 44 | } else { 45 | b.mark(); 46 | unmaskedpayload.position(unmaskedpayload.limit()); 47 | unmaskedpayload.limit(unmaskedpayload.capacity()); 48 | 49 | if (b.remaining() > unmaskedpayload.remaining()) { 50 | ByteBuffer tmp = ByteBuffer.allocate(b.remaining() 51 | + unmaskedpayload.capacity()); 52 | unmaskedpayload.flip(); 53 | tmp.put(unmaskedpayload); 54 | tmp.put(b); 55 | unmaskedpayload = tmp; 56 | 57 | } else { 58 | unmaskedpayload.put(b); 59 | } 60 | unmaskedpayload.rewind(); 61 | b.reset(); 62 | } 63 | fin = nextframe.isFin(); 64 | } 65 | 66 | @Override 67 | public Opcode getOpcode() { 68 | return optcode; 69 | } 70 | 71 | @Override 72 | public ByteBuffer getPayloadData() { 73 | return unmaskedpayload; 74 | } 75 | 76 | @Override 77 | public boolean getTransfereMasked() { 78 | return transferemasked; 79 | } 80 | 81 | @Override 82 | public boolean isFin() { 83 | return fin; 84 | } 85 | 86 | @Override 87 | public void setFin(boolean fin) { 88 | this.fin = fin; 89 | } 90 | 91 | @Override 92 | public void setOptcode(Opcode optcode) { 93 | this.optcode = optcode; 94 | } 95 | 96 | @Override 97 | public void setPayload(ByteBuffer payload) throws InvalidDataException { 98 | unmaskedpayload = payload; 99 | } 100 | 101 | @Override 102 | public void setTransferemasked(boolean transferemasked) { 103 | this.transferemasked = transferemasked; 104 | } 105 | 106 | @Override 107 | public String toString() { 108 | return "Framedata{ optcode:" 109 | + getOpcode() 110 | + ", fin:" 111 | + isFin() 112 | + ", payloadlength:[pos:" 113 | + unmaskedpayload.position() 114 | + ", len:" 115 | + unmaskedpayload.remaining() 116 | + "], payload:" 117 | + Arrays.toString(Charsetfunctions.utf8Bytes(new String( 118 | unmaskedpayload.array()))) + "/"+new String( 119 | unmaskedpayload.array())+"}"; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/info_listener/PlayerInfoListener.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.info_listener; 2 | 3 | import de.maxgb.minecraft.second_screen.Configs; 4 | import de.maxgb.minecraft.second_screen.StandardListener; 5 | import de.maxgb.minecraft.second_screen.shared.PROTOKOLL; 6 | import de.maxgb.minecraft.second_screen.util.User; 7 | import net.minecraft.entity.player.EntityPlayerMP; 8 | import net.minecraft.potion.PotionEffect; 9 | import net.minecraft.util.EnumFacing; 10 | import net.minecraft.util.math.MathHelper; 11 | import net.minecraft.util.text.translation.I18n; 12 | import net.minecraft.world.EnumSkyBlock; 13 | import net.minecraft.world.chunk.Chunk; 14 | import org.json.JSONArray; 15 | import org.json.JSONObject; 16 | 17 | import java.util.Collection; 18 | 19 | /** 20 | * Listener which listens to player information like health or position 21 | * @author Max 22 | * 23 | */ 24 | public class PlayerInfoListener extends StandardListener { 25 | 26 | @SuppressWarnings("unused") 27 | private final String TAG = "PlayerInfoListener"; 28 | 29 | public PlayerInfoListener(User user) { 30 | super(user); 31 | everyTick = Configs.player_info_update_time; 32 | 33 | } 34 | 35 | @Override 36 | public String update() { 37 | JSONObject response = new JSONObject(); 38 | 39 | EntityPlayerMP player = user.getPlayer(server); 40 | 41 | 42 | if (player == null) { 43 | response.put("success", 0).put("error", "User " + user.username + " not online"); 44 | } else { 45 | int x = MathHelper.floor(player.posX); 46 | int y = MathHelper.floor(player.posY); 47 | int z = MathHelper.floor(player.posZ); 48 | 49 | response.put("health", player.getHealth()); 50 | response.put("foodlevel", player.getFoodStats().getFoodLevel()); 51 | response.put("eplevel", player.experienceLevel); 52 | response.put("posx", Integer.valueOf(x)); 53 | response.put("posy", Integer.valueOf(y)); 54 | response.put("posz", Integer.valueOf(z)); 55 | response.put("posxc", Integer.valueOf(x & 15)); 56 | response.put("poszc", Integer.valueOf(z & 15)); 57 | response.put("ping", player.ping); 58 | 59 | //Get direction, @see GUIIngame 60 | 61 | EnumFacing enumfacing = player.getHorizontalFacing(); 62 | response.put("direction", enumfacing.getName()); 63 | 64 | if (player.getEntityWorld() != null && player.getEntityWorld().isBlockLoaded(player.getPosition())) 65 | { 66 | Chunk chunk = player.getEntityWorld().getChunkFromBlockCoords(player.getPosition()); 67 | response.put("lc", (chunk.getTopFilledSegment()+15)); 68 | response.put("biome", chunk.getBiome(player.getPosition(), player.getEntityWorld().getBiomeProvider()).getBiomeName()); 69 | response.put("light", chunk.getLightSubtracted(player.getPosition(), 0) + " (" + chunk.getLightFor(EnumSkyBlock.SKY, player.getPosition()) + " sky, " + chunk.getLightFor(EnumSkyBlock.BLOCK, player.getPosition()) + " block)"); 70 | 71 | 72 | } 73 | 74 | JSONArray potions = new JSONArray(); 75 | Collection pot = player.getActivePotionEffects(); 76 | for (PotionEffect i : pot) { 77 | JSONArray p = new JSONArray(); 78 | p.put(I18n.translateToLocal(i.getEffectName())); 79 | p.put(i.getDuration() / 20); 80 | potions.put(p); 81 | } 82 | response.put("potions", potions); 83 | 84 | response.put("success", 1); 85 | } 86 | 87 | return PROTOKOLL.S_PLAYERINFO_LISTENER + "-" + response.toString(); 88 | 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/world_observer/FluidTankObserver.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.world_observer; 2 | 3 | import de.maxgb.minecraft.second_screen.util.Logger; 4 | import net.minecraft.block.state.IBlockState; 5 | import net.minecraft.tileentity.TileEntity; 6 | import net.minecraft.world.World; 7 | import net.minecraftforge.fluids.FluidTankInfo; 8 | import net.minecraftforge.fluids.IFluidTank; 9 | import net.minecraftforge.fluids.capability.IFluidHandler; 10 | import net.minecraftforge.fluids.capability.IFluidTankProperties; 11 | import org.json.JSONArray; 12 | import org.json.JSONObject; 13 | 14 | //@formatter:off 15 | /*JSONStructure: 16 | * <"fluidtank":JSONArray> 17 | * contains one JSONObject foreach block 18 | * JSONObject each contain: 19 | * <"label":String> 20 | * 21 | * each JSONArray contains 22 | * <0=fluidamount;int> 23 | * <1=fluidcapacity:int> 24 | */ 25 | //@formatter:on 26 | 27 | /** 28 | * Observer class which is desinged to observe tanks which implement the 29 | * IFluidHandler or IFluidTank interface 30 | * 31 | * 32 | * @author Max 33 | * 34 | * 35 | */ 36 | public class FluidTankObserver implements ObservedBlock.ObservingType { 37 | 38 | private final int ID = 5; 39 | private JSONArray info; 40 | 41 | @Override 42 | public boolean addInfoForBlock(World world, ObservedBlock block) { 43 | if (info == null) { 44 | info = new JSONArray(); 45 | } 46 | 47 | JSONObject ti = new JSONObject(); 48 | 49 | TileEntity t = world.getTileEntity(block.pos); 50 | 51 | if (t != null && (t instanceof IFluidHandler)) { 52 | IFluidHandler tank = (IFluidHandler) t; 53 | try { 54 | for (IFluidTankProperties tinfo : tank.getTankProperties()) { 55 | addTankInfo(ti, tinfo); 56 | } 57 | } catch (NullPointerException e) { 58 | } 59 | 60 | } else if (t != null && t instanceof IFluidTank) { 61 | addTankInfo(ti, ((IFluidTank) t).getInfo()); 62 | } else { 63 | Logger.w("TankObserver", "No tank found -> remove"); 64 | return false; 65 | } 66 | if (ti.length() == 0) { 67 | ti.put("Nothing", new JSONArray().put(0).put(0)); 68 | } 69 | ti.put("label", block.label); 70 | info.put(ti); 71 | return true; 72 | 73 | } 74 | 75 | private void addTankInfo(JSONObject parent, FluidTankInfo tank) { 76 | try { 77 | parent.put(tank.fluid.getFluid().getLocalizedName(tank.fluid), 78 | new JSONArray().put(tank.fluid.amount).put(tank.capacity)); 79 | } catch (NullPointerException e) { 80 | } 81 | } 82 | 83 | private void addTankInfo(JSONObject parent, IFluidTankProperties tank) { 84 | try { 85 | parent.put(tank.getContents().getFluid().getLocalizedName(tank.getContents()), 86 | new JSONArray().put(tank.getContents().amount).put(tank.getCapacity())); 87 | } catch (NullPointerException e) { 88 | } 89 | } 90 | 91 | @Override 92 | public boolean canObserve(IBlockState block, TileEntity tile) { 93 | return tile != null && (tile instanceof IFluidHandler || tile instanceof IFluidTank); 94 | } 95 | 96 | @Override 97 | public void finishInfoCreation(JSONObject parent) { 98 | if (info != null && info.length() > 0) { 99 | parent.put("fluidtank", info); 100 | info = null; 101 | } 102 | 103 | } 104 | 105 | @Override 106 | public int getId() { 107 | return ID; 108 | } 109 | 110 | @Override 111 | public String getIdentifier() { 112 | return "fluid_tank"; 113 | } 114 | 115 | @Override 116 | public String getShortIndentifier() { 117 | return "t"; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/data/UserManager.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.data; 2 | 3 | import de.maxgb.minecraft.second_screen.Configs; 4 | import de.maxgb.minecraft.second_screen.util.Constants; 5 | import de.maxgb.minecraft.second_screen.util.Helper; 6 | import de.maxgb.minecraft.second_screen.util.Logger; 7 | import de.maxgb.minecraft.second_screen.util.User; 8 | import net.minecraftforge.common.config.Configuration; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | 14 | /** 15 | * Manages the second screen users 16 | * @author Max 17 | * 18 | */ 19 | public class UserManager { 20 | private static final String TAG = "UserManager"; 21 | private static ArrayList auth_users = new ArrayList(); 22 | private static ArrayList temp_users = new ArrayList(); 23 | 24 | public static void addUser(String username, int pass) { 25 | if (username != null && !username.equals("")) { 26 | for (User u : auth_users) { 27 | if (u.username.equals(username)) { 28 | u.setPassword(pass); 29 | return; 30 | } 31 | } 32 | auth_users.add(new User(username, pass)); 33 | } 34 | 35 | } 36 | 37 | /** 38 | * Returns if the username password combination is correct 39 | * 40 | * @param username 41 | * Username 42 | * @param pass 43 | * Passwordhash 44 | * @return 45 | */ 46 | public static boolean auth(String username, int pass) { 47 | User u = getUser(username); 48 | if (u == null) { 49 | return false; 50 | } 51 | return u.getPassword() == pass; 52 | 53 | } 54 | 55 | /** 56 | * Gets the user with the given username 57 | * 58 | * @param username 59 | * @return 60 | */ 61 | public static User getUser(String username) { 62 | if (Configs.auth_required) { 63 | for (User u : auth_users) { 64 | if (u.username.equals(username)) { 65 | if (Helper.isPlayerOpped(u.username)) { 66 | u.setAllAllowed(true); 67 | } 68 | return u; 69 | } 70 | } 71 | return null; 72 | } 73 | 74 | User u = new User(username, 0); 75 | u.setAllAllowed(true); 76 | temp_users.add(u); 77 | return u; 78 | 79 | } 80 | 81 | private static File getUsersDir() { 82 | File dir = new File(DataStorageDriver.getSaveDir(), Constants.USER_SAVE_DIR); 83 | dir.mkdirs(); 84 | return dir; 85 | } 86 | 87 | /** 88 | * Loads a user from file 89 | * 90 | * @param f 91 | * @return User or null if unsuccesfull 92 | */ 93 | private static User loadUser(File f) { 94 | Configuration config = new Configuration(f); 95 | 96 | return User.readFromConfig(config); 97 | } 98 | 99 | public static void loadUsers() { 100 | auth_users = new ArrayList(); 101 | File dir = getUsersDir(); 102 | File[] files = dir.listFiles(); 103 | for (File f : files) { 104 | if (f.isFile()) { 105 | User u = loadUser(f); 106 | if (u != null) { 107 | auth_users.add(u); 108 | } 109 | } 110 | } 111 | Logger.i(TAG, "Loaded " + auth_users.size() + " users"); 112 | 113 | } 114 | 115 | private static void saveUser(File f, User u) { 116 | 117 | try { 118 | f.createNewFile(); 119 | Configuration config = new Configuration(f); 120 | u.saveToConfig(config); 121 | 122 | } catch (IOException e) { 123 | Logger.e(TAG, "Failed to create user config for " + u.username); 124 | } 125 | } 126 | 127 | public static void saveUsers() { 128 | for (User u : auth_users) { 129 | File uf = new File(getUsersDir(), u.username); 130 | saveUser(uf, u); 131 | } 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/info_listener/WorldInfoListener.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.info_listener; 2 | 3 | import de.maxgb.minecraft.second_screen.Configs; 4 | import de.maxgb.minecraft.second_screen.StandardListener; 5 | import de.maxgb.minecraft.second_screen.shared.PROTOKOLL; 6 | import de.maxgb.minecraft.second_screen.util.Logger; 7 | import de.maxgb.minecraft.second_screen.util.User; 8 | import de.maxgb.minecraft.second_screen.world_observer.ObservedBlock; 9 | import net.minecraft.world.WorldServer; 10 | import net.minecraft.world.storage.WorldInfo; 11 | import org.json.JSONObject; 12 | 13 | import java.util.HashMap; 14 | 15 | /** 16 | * Listens to world related informations like world time, also adds informations from all observed blocks 17 | * @author Max 18 | * 19 | */ 20 | public class WorldInfoListener extends StandardListener { 21 | /** 22 | * MinecraftTime Gets a string with only needed elements. Max time is weeks 23 | * 24 | * @param timeInTicks 25 | * @return Time in string format 26 | */ 27 | public static String parseTime(int timeInTicks) { 28 | String time = ""; 29 | // int weeks = timeInTicks / (168000); 30 | int remainder = timeInTicks % (168000); 31 | // int days = remainder / 24000; 32 | remainder = timeInTicks % 24000; 33 | int hours = remainder / 1000; 34 | remainder = timeInTicks % 1000; 35 | int minutes = remainder / 17; 36 | 37 | // Not interesting 38 | // if (weeks != 0) { 39 | // time += weeks + " weeks "; 40 | // } 41 | // 42 | // if (days != 0) { 43 | // time += (days < 10 ? "0" : "") + days + " days "; 44 | // } 45 | 46 | if (hours != 0) { 47 | time += (hours < 10 ? "0" : "") + hours + " h "; 48 | } 49 | 50 | if (minutes != 0) { 51 | time += (minutes < 10 ? "0" : "") + minutes + " min "; 52 | } 53 | 54 | return time; 55 | } 56 | 57 | HashMap worlds; 58 | 59 | private final String TAG = "WorldInfoListener"; 60 | 61 | public WorldInfoListener(User user) { 62 | super(user); 63 | everyTick = Configs.world_info_update_time; 64 | worlds = new HashMap(); 65 | 66 | for (WorldServer s : server.worlds) { 67 | worlds.put(s.provider.getDimension(), s); 68 | } 69 | Logger.i(TAG, "Worlds: " + worlds.toString()); 70 | } 71 | 72 | @Override 73 | public String update() { 74 | JSONObject info = new JSONObject(); 75 | 76 | // General Overworldinfo 77 | JSONObject ow = new JSONObject(); 78 | 79 | for (WorldServer w : server.worlds) { 80 | if (w.provider.getDimension() == 0) { 81 | WorldInfo i = w.getWorldInfo(); 82 | ow.put("name", i.getWorldName()); 83 | ow.put("time", parseTime((int) i.getWorldTime() + 6000)); 84 | ow.put("rain", i.isRaining()); 85 | ow.put("timetillrain", parseTime(i.getRainTime())); 86 | break; 87 | } 88 | } 89 | info.put("overworld", ow); 90 | 91 | // Observing Info 92 | ObservedBlock.addObservingInfo(info, worlds, user.username); 93 | 94 | // TestMessage 95 | // return PROTOKOLL.WORLD_INFO_LISTENER + "-" + 96 | // "{\"overworld\":{\"time\":\"17 h 31 min \",\"name\":\"New World\",\"timetillrain\":\"09 h 01 min \",\"rain\":false},\"th_node\":[{\"aspects\":{\"Perditio\":11,\"Ordo\":12,\"Ignis\":17},\"label\":\"nod\"},{\"aspects\":{\"Ignis\":9},\"label\":\"node\"},{\"aspects\":{\"Terra\":22,\"Ignis\":31},\"label\":\"nodes\"},{\"aspects\":{\"Ignis\":9},\"label\":\"node\"}],\"redstone\":[[\"label\",true,false],[\"lever\",true,true]]}"; 97 | return PROTOKOLL.WORLD_INFO_LISTENER + "-" + info.toString(); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /gradle/deploy.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven' 2 | 3 | curseforge { 4 | if (project.hasProperty("CURSEFORGE_API")) { 5 | apiKey = project.CURSEFORGE_API 6 | } else { 7 | apiKey = "DUMMY" 8 | } 9 | project { 10 | id = "235268" 11 | 12 | if (config.type == "beta") { 13 | releaseType = 'beta' 14 | //changelog = new File("resources/changelog/${project.version}.txt").text 15 | } else if (config.type == "release") { 16 | releaseType = 'release' 17 | } else { 18 | releaseType = 'alpha' 19 | changelog = "This version should not be used in your 'productive' world. It contains the latest features, but also the latest bugs.\n Probably not all features are finished.\n To see what might have changed visit our Github page and browse the latest commits." 20 | } 21 | addGameVersion config.minecraft_version 22 | 23 | mainArtifact(jar) { 24 | displayName = "Vampirism-${config.minecraft_version}-${project.mod_version}" 25 | } 26 | 27 | relations { 28 | optionalLibrary 'jei' 29 | optionalLibrary 'guide-api' 30 | } 31 | 32 | } 33 | 34 | 35 | } 36 | 37 | configurations { 38 | deployerJars 39 | } 40 | 41 | dependencies { 42 | deployerJars "org.apache.maven.wagon:wagon-ftp:2.9" 43 | } 44 | 45 | uploadArchives { 46 | repositories { 47 | add getProject().repositories.mavenLocal() 48 | } 49 | repositories.mavenDeployer { 50 | configuration = configurations.deployerJars 51 | 52 | if (project.hasProperty("filesmaven_url")) { 53 | logger.info('Publishing to files server') 54 | repository(url: project.filesmaven_url) { 55 | authentication(userName: project.filesmaven_username, password: project.filesmaven_key) 56 | } 57 | } else if (System.getenv().MAVEN_URL) { 58 | logger.info('Publishing to files server') 59 | repository(url: System.getenv().MAVEN_URL) { 60 | authentication(userName: System.getenv().MAVEN_USERNAME, password: System.getenv().MAVEN_KEY) 61 | } 62 | } else { 63 | logger.info('Publishing to repo folder') 64 | repository(url: 'file://localhost/' + project.file('~/.m2/repository').getAbsolutePath()) 65 | } 66 | 67 | pom { 68 | groupId = project.group 69 | version = project.version 70 | artifactId = project.archivesBaseName 71 | } 72 | pom.project { 73 | name project.archivesBaseName 74 | packaging 'jar' 75 | description 'An Minecraft mod that allows you to become a vampire' 76 | url 'https://maxanier.de/projects/vampirism' 77 | 78 | scm { 79 | url 'https://github.com/TeamLapen/Vampirism' 80 | connection 'scm:git:git://github.com/maxanier/MinecraftSecondScreenMod.git' 81 | developerConnection 'scm:git:git@github.com:maxanier/MinecraftSecondScreenMod.git' 82 | } 83 | 84 | issueManagement { 85 | system 'github' 86 | url 'https://github.com/maxanier/MinecraftSecondScreenMod/issues' 87 | } 88 | 89 | developers { 90 | developer { 91 | id 'maxanier' 92 | name 'maxanier' 93 | roles { role 'developer' } 94 | } 95 | } 96 | } 97 | 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/commands/mss_sub/MssCommand.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.commands.mss_sub; 2 | 3 | import de.maxgb.minecraft.second_screen.commands.BaseCommand; 4 | import net.minecraft.command.CommandException; 5 | import net.minecraft.command.ICommand; 6 | import net.minecraft.command.ICommandSender; 7 | import net.minecraft.server.MinecraftServer; 8 | import net.minecraft.util.math.BlockPos; 9 | 10 | import javax.annotation.Nullable; 11 | import java.util.ArrayList; 12 | import java.util.Collections; 13 | import java.util.List; 14 | 15 | /** 16 | * Manages all commands which start with mss 17 | * @author Max 18 | * 19 | */ 20 | @SuppressWarnings({ "rawtypes", "unchecked" }) 21 | public class MssCommand extends BaseCommand { 22 | private List aliases; 23 | private ArrayList commands; 24 | 25 | public MssCommand() { 26 | this.aliases = new ArrayList(); 27 | this.aliases.add("mss"); 28 | this.aliases.add("minecraftsecondscreen"); 29 | this.aliases.add("secondscreen"); 30 | commands = new ArrayList(); 31 | } 32 | 33 | @Override 34 | public int compareTo(ICommand o) { 35 | return 0; 36 | } 37 | 38 | public void addSubCommand(MssSubCommand c) { 39 | commands.add(c); 40 | } 41 | 42 | @Override 43 | public String getName() { 44 | return "mss"; 45 | } 46 | 47 | @Override 48 | public String getUsage(ICommandSender var1) { 49 | 50 | return "/mss "; 51 | 52 | } 53 | 54 | @Override 55 | public List getAliases() { 56 | return aliases; 57 | } 58 | 59 | @Override 60 | public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { 61 | if (args == null || args.length == 0) { 62 | BaseCommand.sendMessage(sender, "Usage: " + getUsage(sender)); 63 | return; 64 | } 65 | //Tests for the corrosponding subcommand and calls it with the reduced amount of params 66 | for (MssSubCommand c : commands) { 67 | if (args[0].equals(c.getCommandName())) { 68 | String[] var; 69 | if (args.length == 1) { 70 | var = null; 71 | } else { 72 | var = new String[args.length - 1]; 73 | for (int i = 1; i < args.length; i++) { 74 | var[i - 1] = args[i]; 75 | } 76 | } 77 | 78 | c.processCommand(sender, var); 79 | return; 80 | } 81 | } 82 | if (!args[0].equals("help")) { 83 | BaseCommand.sendMessage(sender, "Action not found."); 84 | } 85 | sendActions(sender); 86 | } 87 | 88 | @Override 89 | public boolean checkPermission(MinecraftServer server, ICommandSender sender) { 90 | return true; 91 | } 92 | 93 | @Override 94 | public boolean isUsernameIndex(String[] var1, int var2) { 95 | 96 | return false; 97 | } 98 | 99 | /** 100 | * Prints the available actions/subcommands to the command sender 101 | * @param var1 102 | */ 103 | private void sendActions(ICommandSender var1) { 104 | sendMessage(var1, getUsage(var1)); 105 | sendMessage(var1, "Actions:"); 106 | for (MssSubCommand c : commands) { 107 | c.sendCommandUsage(var1); 108 | } 109 | } 110 | 111 | @Override 112 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { 113 | return Collections.emptyList(); 114 | } 115 | 116 | protected interface MssSubCommand { 117 | boolean canCommandSenderUseCommand(ICommandSender var1); 118 | 119 | String getCommandName(); 120 | 121 | void processCommand(ICommandSender var1, String[] var2); 122 | 123 | void sendCommandUsage(ICommandSender var1); 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/api/java/org/java_websocket/framing/CloseFrameBuilder.java: -------------------------------------------------------------------------------- 1 | package org.java_websocket.framing; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import org.java_websocket.exceptions.InvalidDataException; 6 | import org.java_websocket.exceptions.InvalidFrameException; 7 | import org.java_websocket.util.Charsetfunctions; 8 | 9 | public class CloseFrameBuilder extends FramedataImpl1 implements CloseFrame { 10 | 11 | static final ByteBuffer emptybytebuffer = ByteBuffer.allocate(0); 12 | 13 | private int code; 14 | private String reason; 15 | 16 | public CloseFrameBuilder() { 17 | super(Opcode.CLOSING); 18 | setFin(true); 19 | } 20 | 21 | public CloseFrameBuilder(int code) throws InvalidDataException { 22 | super(Opcode.CLOSING); 23 | setFin(true); 24 | setCodeAndMessage(code, ""); 25 | } 26 | 27 | public CloseFrameBuilder(int code, String m) throws InvalidDataException { 28 | super(Opcode.CLOSING); 29 | setFin(true); 30 | setCodeAndMessage(code, m); 31 | } 32 | 33 | @Override 34 | public int getCloseCode() { 35 | return code; 36 | } 37 | 38 | @Override 39 | public String getMessage() { 40 | return reason; 41 | } 42 | 43 | @Override 44 | public ByteBuffer getPayloadData() { 45 | if (code == NOCODE) 46 | return emptybytebuffer; 47 | return super.getPayloadData(); 48 | } 49 | 50 | private void initCloseCode() throws InvalidFrameException { 51 | code = CloseFrame.NOCODE; 52 | ByteBuffer payload = super.getPayloadData(); 53 | payload.mark(); 54 | if (payload.remaining() >= 2) { 55 | ByteBuffer bb = ByteBuffer.allocate(4); 56 | bb.position(2); 57 | bb.putShort(payload.getShort()); 58 | bb.position(0); 59 | code = bb.getInt(); 60 | 61 | if (code == CloseFrame.ABNORMAL_CLOSE 62 | || code == CloseFrame.TLS_ERROR 63 | || code == CloseFrame.NOCODE || code > 4999 || code < 1000 64 | || code == 1004) { 65 | throw new InvalidFrameException( 66 | "closecode must not be sent over the wire: " + code); 67 | } 68 | } 69 | payload.reset(); 70 | } 71 | 72 | private void initMessage() throws InvalidDataException { 73 | if (code == CloseFrame.NOCODE) { 74 | reason = Charsetfunctions.stringUtf8(super.getPayloadData()); 75 | } else { 76 | ByteBuffer b = super.getPayloadData(); 77 | int mark = b.position();// because stringUtf8 also creates a mark 78 | try { 79 | b.position(b.position() + 2); 80 | reason = Charsetfunctions.stringUtf8(b); 81 | } catch (IllegalArgumentException e) { 82 | throw new InvalidFrameException(e); 83 | } finally { 84 | b.position(mark); 85 | } 86 | } 87 | } 88 | 89 | private void setCodeAndMessage(int code, String m) 90 | throws InvalidDataException { 91 | if (m == null) { 92 | m = ""; 93 | } 94 | // CloseFrame.TLS_ERROR is not allowed to be transfered over the wire 95 | if (code == CloseFrame.TLS_ERROR) { 96 | code = CloseFrame.NOCODE; 97 | m = ""; 98 | } 99 | if (code == CloseFrame.NOCODE) { 100 | if (0 < m.length()) { 101 | throw new InvalidDataException(PROTOCOL_ERROR, 102 | "A close frame must have a closecode if it has a reason"); 103 | } 104 | return;// empty payload 105 | } 106 | 107 | byte[] by = Charsetfunctions.utf8Bytes(m); 108 | ByteBuffer buf = ByteBuffer.allocate(4); 109 | buf.putInt(code); 110 | buf.position(2); 111 | ByteBuffer pay = ByteBuffer.allocate(2 + by.length); 112 | pay.put(buf); 113 | pay.put(by); 114 | pay.rewind(); 115 | setPayload(pay); 116 | } 117 | 118 | @Override 119 | public void setPayload(ByteBuffer payload) throws InvalidDataException { 120 | super.setPayload(payload); 121 | initCloseCode(); 122 | initMessage(); 123 | } 124 | 125 | @Override 126 | public String toString() { 127 | return super.toString() + "code: " + code; 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/de/maxgb/minecraft/second_screen/commands/mss_sub/RegisterRedstoneInfoCommand.java: -------------------------------------------------------------------------------- 1 | package de.maxgb.minecraft.second_screen.commands.mss_sub; 2 | 3 | import de.maxgb.minecraft.second_screen.commands.BaseCommand; 4 | import de.maxgb.minecraft.second_screen.data.ObservingManager; 5 | import de.maxgb.minecraft.second_screen.util.Helper; 6 | import de.maxgb.minecraft.second_screen.world_observer.ObservedBlock; 7 | import de.maxgb.minecraft.second_screen.world_observer.RedstoneObserver; 8 | import net.minecraft.block.state.IBlockState; 9 | import net.minecraft.command.ICommandSender; 10 | import net.minecraft.entity.player.EntityPlayer; 11 | import net.minecraft.util.EnumFacing; 12 | import net.minecraft.util.math.RayTraceResult; 13 | 14 | public class RegisterRedstoneInfoCommand implements MssCommand.MssSubCommand { 15 | 16 | private static final String TAG = "RegisterRedstoneCommand"; 17 | 18 | public RegisterRedstoneInfoCommand() { 19 | 20 | } 21 | 22 | @Override 23 | public boolean canCommandSenderUseCommand(ICommandSender var1) { 24 | return var1 instanceof EntityPlayer; 25 | } 26 | 27 | @Override 28 | public String getCommandName() { 29 | return "redinfo"; 30 | } 31 | 32 | @Override 33 | public void processCommand(ICommandSender var1, String[] var2) { 34 | 35 | if (var2 == null || var2.length < 2) { 36 | sendMessage(var1, "Invalid arguments. Usage:"); 37 | sendCommandUsage(var1); 38 | return; 39 | } 40 | 41 | if (var2[0].equals("add")) { 42 | 43 | // Get player 44 | EntityPlayer player; 45 | 46 | if (var1 instanceof EntityPlayer) { 47 | player = (EntityPlayer) var1; 48 | } else { 49 | sendMessage(var1, "Player only command"); 50 | return; 51 | } 52 | 53 | // If the block should be observed publicly 54 | boolean publ = false; 55 | if (var2.length >= 3) { 56 | if (var2[2].equals("public")) { 57 | publ = true; 58 | } 59 | } 60 | 61 | // Get Block 62 | RayTraceResult p = Helper.getPlayerLookingSpot(player, true); 63 | if (p == null) { 64 | sendMessage(var1, "You have to look at a block"); 65 | return; 66 | } 67 | IBlockState b = player.getEntityWorld().getBlockState(p.getBlockPos()); 68 | 69 | sendMessage(var1, 70 | "You are looking at: " + p.getBlockPos().toString() + " " + b.getBlock().getUnlocalizedName()); 71 | 72 | if (!RedstoneObserver.canObserve(b)) { 73 | sendMessage(var1, "You can only observe solid blocks and levers"); 74 | } 75 | 76 | if (ObservingManager.observeBlock(var1.getName(), publ, new ObservedBlock(var2[1], p.getBlockPos(), player.getEntityWorld().provider.getDimension(), RedstoneObserver.ID, EnumFacing.UP))) { 77 | sendMessage(var1, "Successfully added block to observer list."); 78 | } else { 79 | sendMessage(var1, 80 | "Successfully added block to observer list, but overrode another block with the same label"); 81 | } 82 | // var1.addChatMessage(new 83 | // ChatComponentText(""+player.worldObj.isBlockIndirectlyGettingPowered(p.blockX, 84 | // p.blockY, p.blockZ))); 85 | } else if (var2[0].equals("remove")) { 86 | if (ObservingManager.removeObservedBlock(var1.getName(), var2[1])) { 87 | sendMessage(var1, "Successfully removed block from observer list"); 88 | } else { 89 | sendMessage(var1, "Failed to remove block from observer list. There is no block with this label"); 90 | } 91 | } else { 92 | sendMessage(var1, "Invalid arguments. Usage:"); 93 | sendCommandUsage(var1); 94 | return; 95 | 96 | } 97 | 98 | } 99 | 100 | @Override 101 | public void sendCommandUsage(ICommandSender var1) { 102 | sendMessage(var1, "redinfo add