Upload base
This commit is contained in:
790
src/main/java/net/montoyo/wd/client/ClientProxy.java
Normal file
790
src/main/java/net/montoyo/wd/client/ClientProxy.java
Normal file
@@ -0,0 +1,790 @@
|
||||
/*
|
||||
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.advancements.Advancement;
|
||||
import net.minecraft.advancements.AdvancementProgress;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.multiplayer.ClientAdvancementManager;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.SimpleReloadableResourceManager;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.EnumHandSide;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.*;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.client.resource.IResourceType;
|
||||
import net.minecraftforge.client.resource.ISelectiveResourceReloadListener;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import net.minecraftforge.fml.client.registry.ClientRegistry;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import net.montoyo.mcef.api.*;
|
||||
import net.montoyo.wd.SharedProxy;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.block.BlockScreen;
|
||||
import net.montoyo.wd.client.gui.*;
|
||||
import net.montoyo.wd.client.gui.loading.GuiLoader;
|
||||
import net.montoyo.wd.client.renderers.*;
|
||||
import net.montoyo.wd.core.DefaultUpgrade;
|
||||
import net.montoyo.wd.core.HasAdvancement;
|
||||
import net.montoyo.wd.core.JSServerRequest;
|
||||
import net.montoyo.wd.data.GuiData;
|
||||
import net.montoyo.wd.entity.TileEntityScreen;
|
||||
import net.montoyo.wd.item.ItemMulti;
|
||||
import net.montoyo.wd.item.WDItem;
|
||||
import net.montoyo.wd.miniserv.client.Client;
|
||||
import net.montoyo.wd.net.server.SMessagePadCtrl;
|
||||
import net.montoyo.wd.net.server.SMessageScreenCtrl;
|
||||
import net.montoyo.wd.utilities.*;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import paulscode.sound.SoundSystemConfig;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ClientProxy extends SharedProxy implements ISelectiveResourceReloadListener, IDisplayHandler, IJSQueryHandler {
|
||||
|
||||
public class PadData {
|
||||
|
||||
public IBrowser view;
|
||||
private boolean isInHotbar;
|
||||
private final int id;
|
||||
private long lastURLSent;
|
||||
|
||||
private PadData(String url, int id) {
|
||||
view = mcef.createBrowser(WebDisplays.applyBlacklist(url));
|
||||
view.resize((int) WebDisplays.INSTANCE.padResX, (int) WebDisplays.INSTANCE.padResY);
|
||||
isInHotbar = true;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Minecraft mc;
|
||||
private final ArrayList<ResourceModelPair> modelBakers = new ArrayList<>();
|
||||
private net.montoyo.mcef.api.API mcef;
|
||||
private MinePadRenderer minePadRenderer;
|
||||
private JSQueryDispatcher jsDispatcher;
|
||||
private LaserPointerRenderer laserPointerRenderer;
|
||||
private GuiScreen nextScreen;
|
||||
private boolean isF1Down;
|
||||
|
||||
//Miniserv handling
|
||||
private int miniservPort;
|
||||
private boolean msClientStarted;
|
||||
|
||||
//Client-side advancement hack
|
||||
private final Field advancementToProgressField = findAdvancementToProgressField();
|
||||
private ClientAdvancementManager lastAdvMgr;
|
||||
private Map advancementToProgress;
|
||||
|
||||
//Laser pointer
|
||||
private TileEntityScreen pointedScreen;
|
||||
private BlockSide pointedScreenSide;
|
||||
private long lastPointPacket;
|
||||
|
||||
//Tracking
|
||||
private final ArrayList<TileEntityScreen> screenTracking = new ArrayList<>();
|
||||
private int lastTracked = 0;
|
||||
|
||||
//MinePads Management
|
||||
private final HashMap<Integer, PadData> padMap = new HashMap<>();
|
||||
private final ArrayList<PadData> padList = new ArrayList<>();
|
||||
private int minePadTickCounter = 0;
|
||||
|
||||
/**************************************** INHERITED METHODS ****************************************/
|
||||
|
||||
@Override
|
||||
public void preInit() {
|
||||
mc = Minecraft.getMinecraft();
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
registerCustomBlockBaker(new ScreenBaker(), WebDisplays.INSTANCE.blockScreen);
|
||||
|
||||
mcef = MCEFApi.getAPI();
|
||||
if(mcef != null)
|
||||
mcef.registerScheme("wd", WDScheme.class, true, false, false, true, true, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityScreen.class, new ScreenRenderer());
|
||||
jsDispatcher = new JSQueryDispatcher(this);
|
||||
minePadRenderer = new MinePadRenderer();
|
||||
laserPointerRenderer = new LaserPointerRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit() {
|
||||
((SimpleReloadableResourceManager) mc.getResourceManager()).registerReloadListener(this);
|
||||
|
||||
if(mcef == null)
|
||||
throw new RuntimeException("MCEF is missing");
|
||||
|
||||
mcef.registerDisplayHandler(this);
|
||||
mcef.registerJSQueryHandler(this);
|
||||
findAdvancementToProgressField();
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld(int dim) {
|
||||
World ret = mc.world;
|
||||
if(dim == CURRENT_DIMENSION)
|
||||
return ret;
|
||||
|
||||
if(ret.provider.getDimension() != dim)
|
||||
throw new RuntimeException("Can't get non-current dimension " + dim + " from client.");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enqueue(Runnable r) {
|
||||
mc.addScheduledTask(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayGui(GuiData data) {
|
||||
GuiScreen gui = data.createGui(mc.currentScreen, mc.world);
|
||||
if(gui != null)
|
||||
mc.displayGuiScreen(gui);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trackScreen(TileEntityScreen tes, boolean track) {
|
||||
int idx = -1;
|
||||
for(int i = 0; i < screenTracking.size(); i++) {
|
||||
if(screenTracking.get(i) == tes) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(track) {
|
||||
if(idx < 0)
|
||||
screenTracking.add(tes);
|
||||
} else if(idx >= 0)
|
||||
screenTracking.remove(idx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAutocompleteResult(NameUUIDPair[] pairs) {
|
||||
if(mc.currentScreen != null && mc.currentScreen instanceof WDScreen) {
|
||||
if(pairs.length == 0)
|
||||
((WDScreen) mc.currentScreen).onAutocompleteFailure();
|
||||
else
|
||||
((WDScreen) mc.currentScreen).onAutocompleteResult(pairs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameProfile[] getOnlineGameProfiles() {
|
||||
return new GameProfile[] { mc.player.getGameProfile() };
|
||||
}
|
||||
|
||||
@Override
|
||||
public void screenUpdateResolutionInGui(Vector3i pos, BlockSide side, Vector2i res) {
|
||||
if(mc.currentScreen != null && mc.currentScreen instanceof GuiScreenConfig) {
|
||||
GuiScreenConfig gsc = (GuiScreenConfig) mc.currentScreen;
|
||||
|
||||
if(gsc.isForBlock(pos.toBlock(), side))
|
||||
gsc.updateResolution(res);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void screenUpdateRotationInGui(Vector3i pos, BlockSide side, Rotation rot) {
|
||||
if(mc.currentScreen != null && mc.currentScreen instanceof GuiScreenConfig) {
|
||||
GuiScreenConfig gsc = (GuiScreenConfig) mc.currentScreen;
|
||||
|
||||
if(gsc.isForBlock(pos.toBlock(), side))
|
||||
gsc.updateRotation(rot);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void screenUpdateAutoVolumeInGui(Vector3i pos, BlockSide side, boolean av) {
|
||||
if(mc.currentScreen != null && mc.currentScreen instanceof GuiScreenConfig) {
|
||||
GuiScreenConfig gsc = (GuiScreenConfig) mc.currentScreen;
|
||||
|
||||
if(gsc.isForBlock(pos.toBlock(), side))
|
||||
gsc.updateAutoVolume(av);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displaySetPadURLGui(String padURL) {
|
||||
mc.displayGuiScreen(new GuiSetURL2(padURL));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openMinePadGui(int padId) {
|
||||
PadData pd = padMap.get(padId);
|
||||
|
||||
if(pd != null && pd.view != null)
|
||||
mc.displayGuiScreen(new GuiMinePad(pd));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public HasAdvancement hasClientPlayerAdvancement(@Nonnull ResourceLocation rl) {
|
||||
if(advancementToProgressField != null && mc.player != null && mc.player.connection != null) {
|
||||
ClientAdvancementManager cam = mc.player.connection.getAdvancementManager();
|
||||
Advancement adv = cam.getAdvancementList().getAdvancement(rl);
|
||||
|
||||
if(adv == null)
|
||||
return HasAdvancement.DONT_KNOW;
|
||||
|
||||
if(lastAdvMgr != cam) {
|
||||
lastAdvMgr = cam;
|
||||
|
||||
try {
|
||||
advancementToProgress = (Map) advancementToProgressField.get(cam);
|
||||
} catch(Throwable t) {
|
||||
Log.warningEx("Could not get ClientAdvancementManager.advancementToProgress field", t);
|
||||
advancementToProgress = null;
|
||||
return HasAdvancement.DONT_KNOW;
|
||||
}
|
||||
}
|
||||
|
||||
if(advancementToProgress == null)
|
||||
return HasAdvancement.DONT_KNOW;
|
||||
|
||||
Object progress = advancementToProgress.get(adv);
|
||||
if(progress == null)
|
||||
return HasAdvancement.NO;
|
||||
|
||||
if(!(progress instanceof AdvancementProgress)) {
|
||||
Log.warning("The ClientAdvancementManager.advancementToProgress map does not contain AdvancementProgress instances");
|
||||
advancementToProgress = null; //Invalidate this: it's wrong
|
||||
return HasAdvancement.DONT_KNOW;
|
||||
}
|
||||
|
||||
return ((AdvancementProgress) progress).isDone() ? HasAdvancement.YES : HasAdvancement.NO;
|
||||
}
|
||||
|
||||
return HasAdvancement.DONT_KNOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftServer getServer() {
|
||||
return mc.getIntegratedServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleJSResponseSuccess(int reqId, JSServerRequest type, byte[] data) {
|
||||
JSQueryDispatcher.ServerQuery q = jsDispatcher.fulfillQuery(reqId);
|
||||
|
||||
if(q == null)
|
||||
Log.warning("Received success response for invalid query ID %d of type %s", reqId, type.toString());
|
||||
else {
|
||||
if(type == JSServerRequest.CLEAR_REDSTONE || type == JSServerRequest.SET_REDSTONE_AT)
|
||||
q.success("{\"status\":\"success\"}");
|
||||
else
|
||||
Log.warning("Received success response for query ID %d, but type is invalid", reqId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleJSResponseError(int reqId, JSServerRequest type, int errCode, String err) {
|
||||
JSQueryDispatcher.ServerQuery q = jsDispatcher.fulfillQuery(reqId);
|
||||
|
||||
if(q == null)
|
||||
Log.warning("Received error response for invalid query ID %d of type %s", reqId, type.toString());
|
||||
else
|
||||
q.error(errCode, err);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMiniservClientPort(int port) {
|
||||
miniservPort = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startMiniservClient() {
|
||||
if(miniservPort <= 0) {
|
||||
Log.warning("Can't start miniserv client: miniserv is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
if(mc.player == null) {
|
||||
Log.warning("Can't start miniserv client: player is null");
|
||||
return;
|
||||
}
|
||||
|
||||
SocketAddress saddr = mc.player.connection.getNetworkManager().channel().remoteAddress();
|
||||
if(saddr == null || !(saddr instanceof InetSocketAddress)) {
|
||||
Log.warning("Miniserv client: remote address is not inet, assuming local address");
|
||||
saddr = new InetSocketAddress("127.0.0.1", 1234);
|
||||
}
|
||||
|
||||
InetSocketAddress msAddr = new InetSocketAddress(((InetSocketAddress) saddr).getAddress(), miniservPort);
|
||||
Client.getInstance().start(msAddr);
|
||||
msClientStarted = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMiniservDisabled() {
|
||||
return miniservPort <= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeGui(BlockPos bp, BlockSide bs) {
|
||||
if(mc.currentScreen instanceof WDScreen) {
|
||||
WDScreen scr = (WDScreen) mc.currentScreen;
|
||||
|
||||
if(scr.isForBlock(bp, bs))
|
||||
mc.displayGuiScreen(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderRecipes() {
|
||||
nextScreen = new RenderRecipe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShiftDown() {
|
||||
return Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT);
|
||||
}
|
||||
|
||||
/**************************************** RESOURCE MANAGER METHODS ****************************************/
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager, Predicate<IResourceType> resourcePredicate) {
|
||||
Log.info("Resource manager reload: clearing GUI cache...");
|
||||
GuiLoader.clearCache();
|
||||
}
|
||||
|
||||
/**************************************** DISPLAY HANDLER METHODS ****************************************/
|
||||
|
||||
@Override
|
||||
public void onAddressChange(IBrowser browser, String url) {
|
||||
if(browser != null) {
|
||||
long t = System.currentTimeMillis();
|
||||
|
||||
for(PadData pd: padList) {
|
||||
if(pd.view == browser && t - pd.lastURLSent >= 1000) {
|
||||
if(WebDisplays.isSiteBlacklisted(url))
|
||||
pd.view.loadURL(WebDisplays.BLACKLIST_URL);
|
||||
else {
|
||||
pd.lastURLSent = t; //Avoid spamming the server with porn URLs
|
||||
WebDisplays.NET_HANDLER.sendToServer(new SMessagePadCtrl(pd.id, url));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(TileEntityScreen tes: screenTracking)
|
||||
tes.updateClientSideURL(browser, url);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTitleChange(IBrowser browser, String title) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTooltip(IBrowser browser, String text) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusMessage(IBrowser browser, String value) {
|
||||
}
|
||||
|
||||
/**************************************** JS HANDLER METHODS ****************************************/
|
||||
|
||||
@Override
|
||||
public boolean handleQuery(IBrowser browser, long queryId, String query, boolean persistent, IJSQueryCallback cb) {
|
||||
if(browser != null && persistent && query != null && cb != null) {
|
||||
query = query.toLowerCase();
|
||||
|
||||
if(query.startsWith("webdisplays_")) {
|
||||
query = query.substring(12);
|
||||
|
||||
String args;
|
||||
int parenthesis = query.indexOf('(');
|
||||
if(parenthesis < 0)
|
||||
args = null;
|
||||
else {
|
||||
if(query.indexOf(')') != query.length() - 1) {
|
||||
cb.failure(400, "Malformed request");
|
||||
return true;
|
||||
}
|
||||
|
||||
args = query.substring(parenthesis + 1, query.length() - 1);
|
||||
query = query.substring(0, parenthesis);
|
||||
}
|
||||
|
||||
if(jsDispatcher.canHandleQuery(query))
|
||||
jsDispatcher.enqueueQuery(browser, query, args, cb);
|
||||
else
|
||||
cb.failure(404, "Unknown WebDisplays query");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelQuery(IBrowser browser, long queryId) {
|
||||
}
|
||||
|
||||
/**************************************** EVENT METHODS ****************************************/
|
||||
|
||||
@SubscribeEvent
|
||||
public void onStitchTextures(TextureStitchEvent.Pre ev) {
|
||||
TextureMap texMap = ev.getMap();
|
||||
|
||||
if(texMap == mc.getTextureMapBlocks()) {
|
||||
for(ResourceModelPair pair : modelBakers)
|
||||
pair.getModel().loadTextures(texMap);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onBakeModel(ModelBakeEvent ev) {
|
||||
for(ResourceModelPair pair : modelBakers)
|
||||
ev.getModelRegistry().putObject(pair.getResourceLocation(), pair.getModel());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onRegisterModels(ModelRegistryEvent ev) {
|
||||
final WebDisplays wd = WebDisplays.INSTANCE;
|
||||
|
||||
//I hope I'm doing this right because it doesn't seem like it...
|
||||
registerItemModel(wd.blockScreen.getItem(), 0, "inventory");
|
||||
ModelLoader.setCustomModelResourceLocation(wd.blockPeripheral.getItem(), 0, new ModelResourceLocation("webdisplays:kb_inv", "normal"));
|
||||
registerItemModel(wd.blockPeripheral.getItem(), 1, "facing=2,type=ccinterface");
|
||||
registerItemModel(wd.blockPeripheral.getItem(), 2, "facing=2,type=cointerface");
|
||||
registerItemModel(wd.blockPeripheral.getItem(), 3, "facing=0,type=remotectrl");
|
||||
registerItemModel(wd.blockPeripheral.getItem(), 7, "facing=0,type=redstonectrl");
|
||||
registerItemModel(wd.blockPeripheral.getItem(), 11, "facing=0,type=server");
|
||||
registerItemModel(wd.itemScreenCfg, 0, "normal");
|
||||
registerItemModel(wd.itemOwnerThief, 0, "normal");
|
||||
registerItemModel(wd.itemLinker, 0, "normal");
|
||||
registerItemModel(wd.itemMinePad, 0, "normal");
|
||||
registerItemModel(wd.itemMinePad, 1, "normal");
|
||||
registerItemModel(wd.itemLaserPointer, 0, "normal");
|
||||
registerItemMultiModels(wd.itemUpgrade);
|
||||
registerItemMultiModels(wd.itemCraftComp);
|
||||
registerItemMultiModels(wd.itemAdvIcon);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onTick(TickEvent.ClientTickEvent ev) {
|
||||
if(ev.phase == TickEvent.Phase.END) {
|
||||
//Help
|
||||
if(Keyboard.isKeyDown(Keyboard.KEY_F1)) {
|
||||
if(!isF1Down) {
|
||||
isF1Down = true;
|
||||
|
||||
String wikiName = null;
|
||||
if(mc.currentScreen instanceof WDScreen)
|
||||
wikiName = ((WDScreen) mc.currentScreen).getWikiPageName();
|
||||
else if(mc.currentScreen instanceof GuiContainer) {
|
||||
Slot slot = ((GuiContainer) mc.currentScreen).getSlotUnderMouse();
|
||||
|
||||
if(slot != null && slot.getHasStack() && slot.getStack().getItem() instanceof WDItem)
|
||||
wikiName = ((WDItem) slot.getStack().getItem()).getWikiName(slot.getStack());
|
||||
}
|
||||
|
||||
if(wikiName != null)
|
||||
mcef.openExampleBrowser("https://montoyo.net/wdwiki/index.php/" + wikiName);
|
||||
}
|
||||
} else if(isF1Down)
|
||||
isF1Down = false;
|
||||
|
||||
//Workaround cuz chat sux
|
||||
if(nextScreen != null && mc.currentScreen == null) {
|
||||
mc.displayGuiScreen(nextScreen);
|
||||
nextScreen = null;
|
||||
}
|
||||
|
||||
//Unload/load screens depending on client player distance
|
||||
if(mc.player != null && !screenTracking.isEmpty()) {
|
||||
int id = lastTracked % screenTracking.size();
|
||||
lastTracked++;
|
||||
|
||||
TileEntityScreen tes = screenTracking.get(id);
|
||||
double dist2 = mc.player.getDistanceSq(tes.getPos());
|
||||
|
||||
if(tes.isLoaded()) {
|
||||
if(dist2 > WebDisplays.INSTANCE.unloadDistance2)
|
||||
tes.unload();
|
||||
else if(WebDisplays.INSTANCE.enableSoundDistance)
|
||||
tes.updateTrackDistance(dist2, SoundSystemConfig.getMasterGain());
|
||||
} else if(dist2 <= WebDisplays.INSTANCE.loadDistance2)
|
||||
tes.load();
|
||||
}
|
||||
|
||||
//Load/unload minePads depending on which item is in the player's hand
|
||||
if(++minePadTickCounter >= 10) {
|
||||
minePadTickCounter = 0;
|
||||
EntityPlayer ep = mc.player;
|
||||
|
||||
for(PadData pd: padList)
|
||||
pd.isInHotbar = false;
|
||||
|
||||
if(ep != null) {
|
||||
updateInventory(ep.inventory.mainInventory, ep.getHeldItem(EnumHand.MAIN_HAND), 9);
|
||||
updateInventory(ep.inventory.offHandInventory, ep.getHeldItem(EnumHand.OFF_HAND), 1); //Is this okay?
|
||||
}
|
||||
|
||||
//TODO: Check for GuiContainer.draggedStack
|
||||
|
||||
for(int i = padList.size() - 1; i >= 0; i--) {
|
||||
PadData pd = padList.get(i);
|
||||
|
||||
if(!pd.isInHotbar) {
|
||||
pd.view.close();
|
||||
pd.view = null; //This is for GuiMinePad, in case the player dies with the GUI open
|
||||
padList.remove(i);
|
||||
padMap.remove(pd.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Laser pointer raycast
|
||||
boolean raycastHit = false;
|
||||
|
||||
if(mc.player != null && mc.world != null && mc.player.getHeldItem(EnumHand.MAIN_HAND).getItem() == WebDisplays.INSTANCE.itemLaserPointer
|
||||
&& mc.gameSettings.keyBindUseItem.isKeyDown()
|
||||
&& (mc.objectMouseOver == null || mc.objectMouseOver.typeOfHit != RayTraceResult.Type.BLOCK)) {
|
||||
laserPointerRenderer.isOn = true;
|
||||
RayTraceResult result = raycast(64.0); //TODO: Make that distance configurable
|
||||
|
||||
if(result != null) {
|
||||
BlockPos bpos = result.getBlockPos();
|
||||
|
||||
if(result.typeOfHit == RayTraceResult.Type.BLOCK && mc.world.getBlockState(bpos).getBlock() == WebDisplays.INSTANCE.blockScreen) {
|
||||
Vector3i pos = new Vector3i(result.getBlockPos());
|
||||
BlockSide side = BlockSide.values()[result.sideHit.ordinal()];
|
||||
|
||||
Multiblock.findOrigin(mc.world, pos, side, null);
|
||||
TileEntityScreen te = (TileEntityScreen) mc.world.getTileEntity(pos.toBlock());
|
||||
|
||||
if(te != null && te.hasUpgrade(side, DefaultUpgrade.LASER_MOUSE)) { //hasUpgrade returns false is there's no screen on side 'side'
|
||||
//Since rights aren't synchronized, let the server check them for us...
|
||||
TileEntityScreen.Screen scr = te.getScreen(side);
|
||||
|
||||
if(scr.browser != null) {
|
||||
float hitX = ((float) result.hitVec.x) - (float) bpos.getX();
|
||||
float hitY = ((float) result.hitVec.y) - (float) bpos.getY();
|
||||
float hitZ = ((float) result.hitVec.z) - (float) bpos.getZ();
|
||||
Vector2i tmp = new Vector2i();
|
||||
|
||||
if(BlockScreen.hit2pixels(side, bpos, pos, scr, hitX, hitY, hitZ, tmp)) {
|
||||
laserClick(te, side, scr, tmp);
|
||||
raycastHit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
laserPointerRenderer.isOn = false;
|
||||
|
||||
if(!raycastHit)
|
||||
deselectScreen();
|
||||
|
||||
//Handle JS queries
|
||||
jsDispatcher.handleQueries();
|
||||
|
||||
//Miniserv
|
||||
if(msClientStarted && mc.player == null) {
|
||||
msClientStarted = false;
|
||||
Client.getInstance().stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onRenderPlayerHand(RenderSpecificHandEvent ev) {
|
||||
Item item = ev.getItemStack().getItem();
|
||||
IItemRenderer renderer;
|
||||
|
||||
if(item == WebDisplays.INSTANCE.itemMinePad)
|
||||
renderer = minePadRenderer;
|
||||
else if(item == WebDisplays.INSTANCE.itemLaserPointer)
|
||||
renderer = laserPointerRenderer;
|
||||
else
|
||||
return;
|
||||
|
||||
EnumHandSide handSide = mc.player.getPrimaryHand();
|
||||
if(ev.getHand() == EnumHand.OFF_HAND)
|
||||
handSide = handSide.opposite();
|
||||
|
||||
renderer.render(ev.getItemStack(), (handSide == EnumHandSide.RIGHT) ? 1.0f : -1.0f, ev.getSwingProgress(), ev.getEquipProgress());
|
||||
ev.setCanceled(true);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onWorldUnload(WorldEvent.Unload ev) {
|
||||
Log.info("World unloaded; killing screens...");
|
||||
int dim = ev.getWorld().provider.getDimension();
|
||||
|
||||
for(int i = screenTracking.size() - 1; i >= 0; i--) {
|
||||
if(screenTracking.get(i).getWorld().provider.getDimension() == dim) //Could be world == ev.getWorld()
|
||||
screenTracking.remove(i).unload();
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************** OTHER METHODS ****************************************/
|
||||
|
||||
private void laserClick(TileEntityScreen tes, BlockSide side, TileEntityScreen.Screen scr, Vector2i hit) {
|
||||
if(pointedScreen == tes && pointedScreenSide == side) {
|
||||
long t = System.currentTimeMillis();
|
||||
|
||||
if(t - lastPointPacket >= 100) {
|
||||
lastPointPacket = t;
|
||||
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.vec2(tes, side, SMessageScreenCtrl.CTRL_LASER_MOVE, hit));
|
||||
}
|
||||
} else {
|
||||
deselectScreen();
|
||||
pointedScreen = tes;
|
||||
pointedScreenSide = side;
|
||||
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.vec2(tes, side, SMessageScreenCtrl.CTRL_LASER_DOWN, hit));
|
||||
}
|
||||
}
|
||||
|
||||
private void deselectScreen() {
|
||||
if(pointedScreen != null && pointedScreenSide != null) {
|
||||
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.laserUp(pointedScreen, pointedScreenSide));
|
||||
pointedScreen = null;
|
||||
pointedScreenSide = null;
|
||||
}
|
||||
}
|
||||
|
||||
private RayTraceResult raycast(double dist) {
|
||||
Vec3d start = mc.player.getPositionEyes(1.0f);
|
||||
Vec3d lookVec = mc.player.getLook(1.0f);
|
||||
Vec3d end = start.addVector(lookVec.x * dist, lookVec.y * dist, lookVec.z * dist);
|
||||
|
||||
return mc.world.rayTraceBlocks(start, end, true, true, false);
|
||||
}
|
||||
|
||||
private void updateInventory(NonNullList<ItemStack> inv, ItemStack heldStack, int cnt) {
|
||||
for(int i = 0; i < cnt; i++) {
|
||||
ItemStack item = inv.get(i);
|
||||
|
||||
if(item.getItem() == WebDisplays.INSTANCE.itemMinePad) {
|
||||
NBTTagCompound tag = item.getTagCompound();
|
||||
|
||||
if(tag != null && tag.hasKey("PadID"))
|
||||
updatePad(tag.getInteger("PadID"), tag, item == heldStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerCustomBlockBaker(IModelBaker baker, Block block0) {
|
||||
ModelResourceLocation normalLoc = new ModelResourceLocation(block0.getRegistryName(), "normal");
|
||||
ResourceModelPair pair = new ResourceModelPair(normalLoc, baker);
|
||||
modelBakers.add(pair);
|
||||
ModelLoader.setCustomStateMapper(block0, new StaticStateMapper(normalLoc));
|
||||
}
|
||||
|
||||
private void registerItemModel(Item item, int meta, String variant) {
|
||||
ModelLoader.setCustomModelResourceLocation(item, meta, new ModelResourceLocation(item.getRegistryName(), variant));
|
||||
}
|
||||
|
||||
private void registerItemMultiModels(ItemMulti item) {
|
||||
Enum[] values = item.getEnumValues();
|
||||
|
||||
for(int i = 0; i < values.length; i++)
|
||||
ModelLoader.setCustomModelResourceLocation(item, i, new ModelResourceLocation(item.getRegistryName().toString() + '_' + values[i], "normal"));
|
||||
}
|
||||
|
||||
private void updatePad(int id, NBTTagCompound tag, boolean isSelected) {
|
||||
PadData pd = padMap.get(id);
|
||||
|
||||
if(pd != null)
|
||||
pd.isInHotbar = true;
|
||||
else if(isSelected && tag.hasKey("PadURL")) {
|
||||
pd = new PadData(tag.getString("PadURL"), id);
|
||||
padMap.put(id, pd);
|
||||
padList.add(pd);
|
||||
}
|
||||
}
|
||||
|
||||
public MinePadRenderer getMinePadRenderer() {
|
||||
return minePadRenderer;
|
||||
}
|
||||
|
||||
public PadData getPadByID(int id) {
|
||||
return padMap.get(id);
|
||||
}
|
||||
|
||||
public net.montoyo.mcef.api.API getMCEF() {
|
||||
return mcef;
|
||||
}
|
||||
|
||||
public static final class ScreenSidePair {
|
||||
|
||||
public TileEntityScreen tes;
|
||||
public BlockSide side;
|
||||
|
||||
}
|
||||
|
||||
public boolean findScreenFromBrowser(IBrowser browser, ScreenSidePair pair) {
|
||||
for(TileEntityScreen tes: screenTracking) {
|
||||
for(int i = 0; i < tes.screenCount(); i++) {
|
||||
TileEntityScreen.Screen scr = tes.getScreen(i);
|
||||
|
||||
if(scr.browser == browser) {
|
||||
pair.tes = tes;
|
||||
pair.side = scr.side;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Field findAdvancementToProgressField() {
|
||||
Field[] fields = ClientAdvancementManager.class.getDeclaredFields();
|
||||
Optional<Field> result = Arrays.stream(fields).filter(f -> f.getType() == Map.class).findAny();
|
||||
|
||||
if(result.isPresent()) {
|
||||
try {
|
||||
Field ret = result.get();
|
||||
ret.setAccessible(true);
|
||||
return ret;
|
||||
} catch(Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Log.warning("ClientAdvancementManager.advancementToProgress field could not be found");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
370
src/main/java/net/montoyo/wd/client/JSQueryDispatcher.java
Normal file
370
src/main/java/net/montoyo/wd/client/JSQueryDispatcher.java
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import net.montoyo.mcef.api.IBrowser;
|
||||
import net.montoyo.mcef.api.IJSQueryCallback;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.block.BlockScreen;
|
||||
import net.montoyo.wd.core.DefaultUpgrade;
|
||||
import net.montoyo.wd.core.IScreenQueryHandler;
|
||||
import net.montoyo.wd.core.IUpgrade;
|
||||
import net.montoyo.wd.core.JSServerRequest;
|
||||
import net.montoyo.wd.entity.TileEntityScreen;
|
||||
import net.montoyo.wd.net.server.SMessageScreenCtrl;
|
||||
import net.montoyo.wd.utilities.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public final class JSQueryDispatcher {
|
||||
|
||||
private static final class QueryData {
|
||||
|
||||
private final IBrowser browser;
|
||||
private final String query;
|
||||
private final String args;
|
||||
private final IJSQueryCallback callback;
|
||||
|
||||
private QueryData(IBrowser b, String q, String a, IJSQueryCallback cb) {
|
||||
browser = b;
|
||||
query = q;
|
||||
args = a;
|
||||
callback = cb;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final class ServerQuery {
|
||||
|
||||
private static int lastId = 0;
|
||||
|
||||
private final TileEntityScreen tes;
|
||||
private final BlockSide side;
|
||||
private final IJSQueryCallback callback;
|
||||
private final int id;
|
||||
|
||||
private ServerQuery(TileEntityScreen t, BlockSide s, IJSQueryCallback cb) {
|
||||
tes = t;
|
||||
side = s;
|
||||
callback = cb;
|
||||
id = lastId++;
|
||||
}
|
||||
|
||||
public TileEntityScreen getTileEntity() {
|
||||
return tes;
|
||||
}
|
||||
|
||||
public BlockSide getSide() {
|
||||
return side;
|
||||
}
|
||||
|
||||
public TileEntityScreen.Screen getScreen() {
|
||||
return tes.getScreen(side);
|
||||
}
|
||||
|
||||
public void success(String resp) {
|
||||
callback.success(resp);
|
||||
}
|
||||
|
||||
public void error(int errId, String errStr) {
|
||||
callback.failure(errId, errStr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final ClientProxy proxy;
|
||||
private final ArrayDeque<QueryData> queue = new ArrayDeque<>();
|
||||
private final ClientProxy.ScreenSidePair lookupResult = new ClientProxy.ScreenSidePair();
|
||||
private final HashMap<String, IScreenQueryHandler> handlers = new HashMap<>();
|
||||
private final ArrayList<ServerQuery> serverQueries = new ArrayList<>();
|
||||
private final Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
public JSQueryDispatcher(ClientProxy proxy) {
|
||||
this.proxy = proxy;
|
||||
registerDefaults();
|
||||
}
|
||||
|
||||
public void enqueueQuery(IBrowser b, String q, String a, IJSQueryCallback cb) {
|
||||
synchronized(queue) {
|
||||
queue.offer(new QueryData(b, q, a, cb));
|
||||
}
|
||||
}
|
||||
|
||||
public void handleQueries() {
|
||||
while(true) {
|
||||
QueryData next;
|
||||
synchronized(queue) {
|
||||
next = queue.poll();
|
||||
}
|
||||
|
||||
if(next == null)
|
||||
break;
|
||||
|
||||
if(proxy.findScreenFromBrowser(next.browser, lookupResult)) {
|
||||
Object[] args = (next.args == null) ? new Object[0] : parseArgs(next.args);
|
||||
|
||||
if(args == null)
|
||||
next.callback.failure(400, "Malformed request parameters");
|
||||
else {
|
||||
try {
|
||||
handlers.get(next.query).handleQuery(next.callback, lookupResult.tes, lookupResult.side, args);
|
||||
} catch(Throwable t) {
|
||||
Log.warningEx("Could not execute JS query %s(%s)", t, next.query, (next.args == null) ? "" : next.args);
|
||||
next.callback.failure(500, "Internal error");
|
||||
}
|
||||
}
|
||||
} else
|
||||
next.callback.failure(403, "A screen is required");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canHandleQuery(String q) {
|
||||
return handlers.containsKey(q);
|
||||
}
|
||||
|
||||
private static Object[] parseArgs(String args) {
|
||||
ArrayList<String> array = new ArrayList<>();
|
||||
int lastIdx = 0;
|
||||
boolean inString = false;
|
||||
boolean escape = false;
|
||||
boolean hadString = false;
|
||||
|
||||
for(int i = 0; i < args.length(); i++) {
|
||||
char chr = args.charAt(i);
|
||||
|
||||
if(inString) {
|
||||
if(escape)
|
||||
escape = false;
|
||||
else {
|
||||
if(chr == '\"')
|
||||
inString = false;
|
||||
else if(chr == '\\')
|
||||
escape = true;
|
||||
}
|
||||
} else if(chr == '\"') {
|
||||
if(hadString)
|
||||
return null;
|
||||
|
||||
inString = true;
|
||||
hadString = true;
|
||||
} else if(chr == ',') {
|
||||
array.add(args.substring(lastIdx, i).trim());
|
||||
lastIdx = i + 1;
|
||||
hadString = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(inString)
|
||||
return null; //Non terminated string
|
||||
|
||||
array.add(args.substring(lastIdx).trim());
|
||||
Object[] ret = new Object[array.size()];
|
||||
|
||||
for(int i = 0; i < ret.length; i++) {
|
||||
String str = array.get(i);
|
||||
if(str.isEmpty())
|
||||
return null; //Nah...
|
||||
|
||||
if(str.charAt(0) == '\"') //String
|
||||
ret[i] = str.substring(1, str.length() - 1);
|
||||
else {
|
||||
try {
|
||||
ret[i] = Double.parseDouble(str);
|
||||
} catch(NumberFormatException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void register(String query, IScreenQueryHandler handler) {
|
||||
handlers.put(query.toLowerCase(), handler);
|
||||
}
|
||||
|
||||
public ServerQuery fulfillQuery(int id) {
|
||||
int toRemove = -1;
|
||||
|
||||
for(int i = 0; i < serverQueries.size(); i++) {
|
||||
ServerQuery sq = serverQueries.get(i);
|
||||
|
||||
if(sq.id == id) {
|
||||
toRemove = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(toRemove < 0)
|
||||
return null;
|
||||
else
|
||||
return serverQueries.remove(toRemove);
|
||||
}
|
||||
|
||||
private void makeServerQuery(TileEntityScreen tes, BlockSide side, IJSQueryCallback cb, JSServerRequest type, Object ... data) {
|
||||
ServerQuery ret = new ServerQuery(tes, side, cb);
|
||||
serverQueries.add(ret);
|
||||
|
||||
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.jsRequest(tes, side, ret.id, type, data));
|
||||
}
|
||||
|
||||
private void registerDefaults() {
|
||||
register("GetSize", (cb, tes, side, args) -> {
|
||||
Vector2i size = tes.getScreen(side).size;
|
||||
cb.success("{\"x\":" + size.x + ",\"y\":" + size.y + "}");
|
||||
});
|
||||
|
||||
register("GetRedstoneAt", (cb, tes, side, args) -> {
|
||||
if(!tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_INPUT)) {
|
||||
cb.failure(403, "Missing upgrade");
|
||||
return;
|
||||
}
|
||||
|
||||
if(args.length == 2 && args[0] instanceof Double && args[1] instanceof Double) {
|
||||
TileEntityScreen.Screen scr = tes.getScreen(side);
|
||||
int x = ((Double) args[0]).intValue();
|
||||
int y = ((Double) args[1]).intValue();
|
||||
|
||||
if(x < 0 || x >= scr.size.x || y < 0 || y >= scr.size.y)
|
||||
cb.failure(403, "Out of range");
|
||||
else {
|
||||
BlockPos bpos = (new Vector3i(tes.getPos())).addMul(side.right, x).addMul(side.up, y).toBlock();
|
||||
int level = tes.getWorld().getBlockState(bpos).getValue(BlockScreen.emitting) ? 0 : tes.getWorld().getRedstonePower(bpos, EnumFacing.VALUES[side.reverse().ordinal()]);
|
||||
cb.success("{\"level\":" + level + "}");
|
||||
}
|
||||
} else
|
||||
cb.failure(400, "Wrong arguments");
|
||||
});
|
||||
|
||||
register("GetRedstoneArray", (cb, tes, side, args) -> {
|
||||
if(tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_INPUT)) {
|
||||
final EnumFacing facing = EnumFacing.VALUES[side.reverse().ordinal()];
|
||||
final StringJoiner resp = new StringJoiner(",", "{\"levels\":[", "]}");
|
||||
|
||||
tes.forEachScreenBlocks(side, bp -> {
|
||||
if(tes.getWorld().getBlockState(bp).getValue(BlockScreen.emitting))
|
||||
resp.add("0");
|
||||
else
|
||||
resp.add("" + tes.getWorld().getRedstonePower(bp, facing));
|
||||
});
|
||||
|
||||
cb.success(resp.toString());
|
||||
} else
|
||||
cb.failure(403, "Missing upgrade");
|
||||
});
|
||||
|
||||
register("ClearRedstone", (cb, tes, side, args) -> {
|
||||
if(tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_OUTPUT)) {
|
||||
if(tes.getScreen(side).owner.uuid.equals(mc.player.getGameProfile().getId()))
|
||||
makeServerQuery(tes, side, cb, JSServerRequest.CLEAR_REDSTONE);
|
||||
else
|
||||
cb.success("{\"status\":\"notOwner\"}");
|
||||
} else
|
||||
cb.failure(403, "Missing upgrade");
|
||||
});
|
||||
|
||||
register("SetRedstoneAt", (cb, tes, side, args) -> {
|
||||
if(args.length != 3 || !Arrays.stream(args).allMatch((obj) -> obj instanceof Double)) {
|
||||
cb.failure(400, "Wrong arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_OUTPUT)) {
|
||||
cb.failure(403, "Missing upgrade");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!tes.getScreen(side).owner.uuid.equals(mc.player.getGameProfile().getId())) {
|
||||
cb.success("{\"status\":\"notOwner\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
int x = ((Double) args[0]).intValue();
|
||||
int y = ((Double) args[1]).intValue();
|
||||
boolean state = ((Double) args[2]) > 0.0;
|
||||
|
||||
Vector2i size = tes.getScreen(side).size;
|
||||
if(x < 0 || x >= size.x || y < 0 || y >= size.y) {
|
||||
cb.failure(403, "Out of range");
|
||||
return;
|
||||
}
|
||||
|
||||
makeServerQuery(tes, side, cb, JSServerRequest.SET_REDSTONE_AT, x, y, state);
|
||||
});
|
||||
|
||||
register("IsEmitting", (cb, tes, side, args) -> {
|
||||
if(!tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_OUTPUT)) {
|
||||
cb.failure(403, "Missing upgrade");
|
||||
return;
|
||||
}
|
||||
|
||||
if(args.length == 2 && args[0] instanceof Double && args[1] instanceof Double) {
|
||||
TileEntityScreen.Screen scr = tes.getScreen(side);
|
||||
int x = ((Double) args[0]).intValue();
|
||||
int y = ((Double) args[1]).intValue();
|
||||
|
||||
if(x < 0 || x >= scr.size.x || y < 0 || y >= scr.size.y)
|
||||
cb.failure(403, "Out of range");
|
||||
else {
|
||||
BlockPos bpos = (new Vector3i(tes.getPos())).addMul(side.right, x).addMul(side.up, y).toBlock();
|
||||
boolean e = tes.getWorld().getBlockState(bpos).getValue(BlockScreen.emitting);
|
||||
cb.success("{\"emitting\":" + (e ? "true" : "false") + "}");
|
||||
}
|
||||
} else
|
||||
cb.failure(400, "Wrong arguments");
|
||||
});
|
||||
|
||||
register("GetEmissionArray", (cb, tes, side, args) -> {
|
||||
if(tes.hasUpgrade(side, DefaultUpgrade.REDSTONE_OUTPUT)) {
|
||||
final StringJoiner resp = new StringJoiner(",", "{\"emission\":[", "]}");
|
||||
tes.forEachScreenBlocks(side, bp -> resp.add(tes.getWorld().getBlockState(bp).getValue(BlockScreen.emitting) ? "1" : "0"));
|
||||
cb.success(resp.toString());
|
||||
} else
|
||||
cb.failure(403, "Missing upgrade");
|
||||
});
|
||||
|
||||
register("GetLocation", (cb, tes, side, args) -> {
|
||||
if(!tes.hasUpgrade(side, DefaultUpgrade.GPS)) {
|
||||
cb.failure(403, "Missing upgrade");
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos bp = tes.getPos();
|
||||
cb.success("{\"x\":" + bp.getX() + ",\"y\":" + bp.getY() + ",\"z\":" + bp.getZ() + ",\"side\":\"" + side + "\"}");
|
||||
});
|
||||
|
||||
register("GetUpgrades", (cb, tes, side, args) -> {
|
||||
final StringBuilder sb = new StringBuilder("{\"upgrades\":[");
|
||||
final ArrayList<ItemStack> upgrades = tes.getScreen(side).upgrades;
|
||||
|
||||
for(int i = 0; i < upgrades.size(); i++) {
|
||||
if(i > 0)
|
||||
sb.append(',');
|
||||
|
||||
sb.append('\"');
|
||||
sb.append(Util.addSlashes(((IUpgrade) upgrades.get(i).getItem()).getJSName(upgrades.get(i))));
|
||||
sb.append('\"');
|
||||
}
|
||||
|
||||
cb.success(sb.append("]}").toString());
|
||||
});
|
||||
|
||||
register("IsOwner", (cb, tes, side, args) -> {
|
||||
boolean res = (tes.getScreen(side).owner != null && tes.getScreen(side).owner.uuid.equals(mc.player.getGameProfile().getId()));
|
||||
cb.success("{\"isOwner\":" + (res ? "true}" : "false}"));
|
||||
});
|
||||
|
||||
register("GetRotation", (cb, tes, side, args) -> cb.success("{\"rotation\":" + tes.getScreen(side).rotation.ordinal() + "}"));
|
||||
register("GetSide", (cb, tes, side, args) -> cb.success("{\"side\":" + tes.getScreen(side).side.ordinal() + "}"));
|
||||
}
|
||||
|
||||
}
|
28
src/main/java/net/montoyo/wd/client/ResourceModelPair.java
Normal file
28
src/main/java/net/montoyo/wd/client/ResourceModelPair.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.montoyo.wd.client.renderers.IModelBaker;
|
||||
|
||||
public class ResourceModelPair {
|
||||
|
||||
private final ModelResourceLocation resLoc;
|
||||
private final IModelBaker model;
|
||||
|
||||
public ResourceModelPair(ModelResourceLocation rl, IModelBaker m) {
|
||||
resLoc = rl;
|
||||
model = m;
|
||||
}
|
||||
|
||||
public ModelResourceLocation getResourceLocation() {
|
||||
return resLoc;
|
||||
}
|
||||
|
||||
public IModelBaker getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
27
src/main/java/net/montoyo/wd/client/StaticStateMapper.java
Normal file
27
src/main/java/net/montoyo/wd/client/StaticStateMapper.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.block.statemap.StateMapperBase;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class StaticStateMapper extends StateMapperBase {
|
||||
|
||||
private final ModelResourceLocation resLoc;
|
||||
|
||||
public StaticStateMapper(ModelResourceLocation rl) {
|
||||
resLoc = rl;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
protected ModelResourceLocation getModelResourceLocation(@Nonnull IBlockState state) {
|
||||
return resLoc;
|
||||
}
|
||||
|
||||
}
|
149
src/main/java/net/montoyo/wd/client/WDScheme.java
Normal file
149
src/main/java/net/montoyo/wd/client/WDScheme.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client;
|
||||
|
||||
import net.montoyo.mcef.api.IScheme;
|
||||
import net.montoyo.mcef.api.ISchemeResponseData;
|
||||
import net.montoyo.mcef.api.ISchemeResponseHeaders;
|
||||
import net.montoyo.mcef.api.SchemePreResponse;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.miniserv.Constants;
|
||||
import net.montoyo.wd.miniserv.client.Client;
|
||||
import net.montoyo.wd.miniserv.client.ClientTaskGetFile;
|
||||
import net.montoyo.wd.utilities.Log;
|
||||
import net.montoyo.wd.utilities.Util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.UUID;
|
||||
|
||||
public class WDScheme implements IScheme {
|
||||
|
||||
private static final String ERROR_PAGE = "<!DOCTYPE html><html><head></head><body><h1>%d %s</h1><hr /><i>Miniserv powered by WebDisplays</i></body></html>";
|
||||
private ClientTaskGetFile task;
|
||||
private boolean isErrorPage;
|
||||
|
||||
@Override
|
||||
public SchemePreResponse processRequest(String url) {
|
||||
url = url.substring("wd://".length());
|
||||
|
||||
int pos = url.indexOf('/');
|
||||
if(pos < 0)
|
||||
return SchemePreResponse.NOT_HANDLED;
|
||||
|
||||
String uuidStr = url.substring(0, pos);
|
||||
String fileStr = url.substring(pos + 1);
|
||||
|
||||
try {
|
||||
fileStr = URLDecoder.decode(fileStr, "UTF-8");
|
||||
} catch(UnsupportedEncodingException ex) {
|
||||
Log.warningEx("UTF-8 isn't supported... yeah... and I'm a billionaire...", ex);
|
||||
}
|
||||
|
||||
if(uuidStr.isEmpty() || Util.isFileNameInvalid(fileStr))
|
||||
return SchemePreResponse.NOT_HANDLED;
|
||||
|
||||
UUID uuid;
|
||||
try {
|
||||
uuid = UUID.fromString(uuidStr);
|
||||
} catch(IllegalArgumentException ex) {
|
||||
return SchemePreResponse.NOT_HANDLED; //Invalid UUID
|
||||
}
|
||||
|
||||
task = new ClientTaskGetFile(uuid, fileStr);
|
||||
return Client.getInstance().addTask(task) ? SchemePreResponse.HANDLED_CONTINUE : SchemePreResponse.NOT_HANDLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getResponseHeaders(ISchemeResponseHeaders resp) {
|
||||
Log.info("Waiting for response...");
|
||||
int status = task.waitForResponse();
|
||||
Log.info("Got response %d", status);
|
||||
|
||||
if(status == 0) {
|
||||
//OK
|
||||
int extPos = task.getFileName().lastIndexOf('.');
|
||||
if(extPos >= 0) {
|
||||
String mime = ((ClientProxy) WebDisplays.PROXY).getMCEF().mimeTypeFromExtension(task.getFileName().substring(extPos + 1));
|
||||
|
||||
if(mime != null)
|
||||
resp.setMimeType(mime);
|
||||
}
|
||||
|
||||
resp.setStatus(200);
|
||||
resp.setStatusText("OK");
|
||||
resp.setResponseLength(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
int errCode;
|
||||
String errStr;
|
||||
|
||||
if(status == Constants.GETF_STATUS_NOT_FOUND) {
|
||||
errCode = 404;
|
||||
errStr = "Not Found";
|
||||
} else {
|
||||
errCode = 500;
|
||||
errStr = "Internal Server Error";
|
||||
}
|
||||
|
||||
resp.setStatus(errCode);
|
||||
resp.setStatusText(errStr);
|
||||
|
||||
try {
|
||||
dataToWrite = String.format(ERROR_PAGE, errCode, errStr).getBytes("UTF-8");
|
||||
dataOffset = 0;
|
||||
amountToWrite = dataToWrite.length;
|
||||
isErrorPage = true;
|
||||
resp.setResponseLength(amountToWrite);
|
||||
} catch(UnsupportedEncodingException ex) {
|
||||
resp.setResponseLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] dataToWrite;
|
||||
private int dataOffset;
|
||||
private int amountToWrite;
|
||||
|
||||
@Override
|
||||
public boolean readResponse(ISchemeResponseData data) {
|
||||
if(dataToWrite == null) {
|
||||
if(isErrorPage) {
|
||||
data.setAmountRead(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
dataToWrite = task.waitForData();
|
||||
dataOffset = 3; //packet ID + size
|
||||
amountToWrite = task.getDataLength();
|
||||
|
||||
if(amountToWrite <= 0) {
|
||||
dataToWrite = null;
|
||||
data.setAmountRead(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int toWrite = data.getBytesToRead();
|
||||
if(toWrite > amountToWrite)
|
||||
toWrite = amountToWrite;
|
||||
|
||||
System.arraycopy(dataToWrite, dataOffset, data.getDataArray(), 0, toWrite);
|
||||
data.setAmountRead(toWrite);
|
||||
|
||||
dataOffset += toWrite;
|
||||
amountToWrite -= toWrite;
|
||||
|
||||
if(amountToWrite <= 0) {
|
||||
if(!isErrorPage)
|
||||
task.nextData();
|
||||
|
||||
dataToWrite = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
18
src/main/java/net/montoyo/wd/client/gui/CommandHandler.java
Normal file
18
src/main/java/net/montoyo/wd/client/gui/CommandHandler.java
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CommandHandler {
|
||||
|
||||
String value();
|
||||
|
||||
}
|
204
src/main/java/net/montoyo/wd/client/gui/GuiKeyboard.java
Normal file
204
src/main/java/net/montoyo/wd/client/gui/GuiKeyboard.java
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.client.gui.controls.Button;
|
||||
import net.montoyo.wd.client.gui.controls.Control;
|
||||
import net.montoyo.wd.client.gui.controls.Label;
|
||||
import net.montoyo.wd.client.gui.loading.FillControl;
|
||||
import net.montoyo.wd.entity.TileEntityScreen;
|
||||
import net.montoyo.wd.net.server.SMessageScreenCtrl;
|
||||
import net.montoyo.wd.utilities.BlockSide;
|
||||
import net.montoyo.wd.utilities.Log;
|
||||
import net.montoyo.wd.utilities.TypeData;
|
||||
import net.montoyo.wd.utilities.Util;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class GuiKeyboard extends WDScreen {
|
||||
|
||||
private static final String WARNING_FNAME = "wd_keyboard_warning.txt";
|
||||
|
||||
private TileEntityScreen tes;
|
||||
private BlockSide side;
|
||||
private final ArrayList<TypeData> evStack = new ArrayList<>();
|
||||
private BlockPos kbPos;
|
||||
private boolean showWarning = true;
|
||||
|
||||
@FillControl
|
||||
private Label lblInfo;
|
||||
|
||||
@FillControl
|
||||
private Button btnOk;
|
||||
|
||||
public GuiKeyboard() {
|
||||
}
|
||||
|
||||
public GuiKeyboard(TileEntityScreen tes, BlockSide side, BlockPos kbPos) {
|
||||
this.tes = tes;
|
||||
this.side = side;
|
||||
this.kbPos = kbPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addLoadCustomVariables(Map<String, Double> vars) {
|
||||
vars.put("showWarning", showWarning ? 1.0 : 0.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
|
||||
if(mc.isIntegratedServerRunning() && mc.getIntegratedServer() != null && !mc.getIntegratedServer().getPublic())
|
||||
showWarning = false; //NO NEED
|
||||
else
|
||||
showWarning = !hasUserReadWarning();
|
||||
|
||||
loadFrom(new ResourceLocation("webdisplays", "gui/keyboard.json"));
|
||||
|
||||
if(showWarning) {
|
||||
int maxLabelW = 0;
|
||||
int totalH = 0;
|
||||
|
||||
for(Control ctrl : controls) {
|
||||
if(ctrl != lblInfo && ctrl instanceof Label) {
|
||||
if(ctrl.getWidth() > maxLabelW)
|
||||
maxLabelW = ctrl.getWidth();
|
||||
|
||||
totalH += ctrl.getHeight();
|
||||
ctrl.setPos((width - ctrl.getWidth()) / 2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
btnOk.setWidth(maxLabelW);
|
||||
btnOk.setPos((width - maxLabelW) / 2, 0);
|
||||
totalH += btnOk.getHeight();
|
||||
|
||||
int y = (height - totalH) / 2;
|
||||
for(Control ctrl : controls) {
|
||||
if(ctrl != lblInfo) {
|
||||
ctrl.setPos(ctrl.getX(), y);
|
||||
y += ctrl.getHeight();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mc.inGameHasFocus = true;
|
||||
mc.mouseHelper.grabMouseCursor();
|
||||
}
|
||||
|
||||
defaultBackground = showWarning;
|
||||
syncTicks = 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInput() {
|
||||
if(showWarning) {
|
||||
try {
|
||||
super.handleInput();
|
||||
} catch(IOException ex) {
|
||||
Log.warningEx("Caught exception while handling screen input", ex);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(Keyboard.isCreated()) {
|
||||
while(Keyboard.next()) {
|
||||
if(Keyboard.getEventKey() == Keyboard.KEY_ESCAPE)
|
||||
mc.displayGuiScreen(null);
|
||||
else {
|
||||
char chr = Keyboard.getEventCharacter();
|
||||
|
||||
if(Keyboard.getEventKeyState()) {
|
||||
int kc = Keyboard.getEventKey();
|
||||
|
||||
evStack.add(new TypeData(TypeData.Action.PRESS, kc, chr));
|
||||
evStack.add(new TypeData(TypeData.Action.RELEASE, kc, chr));
|
||||
}
|
||||
|
||||
if(chr != 0)
|
||||
evStack.add(new TypeData(TypeData.Action.TYPE, 0, chr));
|
||||
}
|
||||
}
|
||||
|
||||
if(!evStack.isEmpty() && !syncRequested())
|
||||
requestSync();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sync() {
|
||||
if(!evStack.isEmpty()) {
|
||||
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.type(tes, side, WebDisplays.GSON.toJson(evStack), kbPos));
|
||||
evStack.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onClick(Button.ClickEvent ev) {
|
||||
if(showWarning && ev.getSource() == btnOk) {
|
||||
writeUserAcknowledge();
|
||||
|
||||
for(Control ctrl: controls) {
|
||||
if(ctrl instanceof Label) {
|
||||
Label lbl = (Label) ctrl;
|
||||
lbl.setVisible(!lbl.isVisible());
|
||||
}
|
||||
}
|
||||
|
||||
btnOk.setDisabled(true);
|
||||
btnOk.setVisible(false);
|
||||
showWarning = false;
|
||||
defaultBackground = false;
|
||||
mc.inGameHasFocus = true;
|
||||
mc.mouseHelper.grabMouseCursor();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasUserReadWarning() {
|
||||
try {
|
||||
File f = new File(mc.mcDataDir, WARNING_FNAME);
|
||||
|
||||
if(f.exists()) {
|
||||
BufferedReader br = new BufferedReader(new FileReader(f));
|
||||
String str = br.readLine();
|
||||
Util.silentClose(br);
|
||||
|
||||
return str != null && str.trim().equalsIgnoreCase("read");
|
||||
}
|
||||
} catch(Throwable t) {
|
||||
Log.warningEx("Can't know if user has already read the warning", t);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void writeUserAcknowledge() {
|
||||
try {
|
||||
File f = new File(mc.mcDataDir, WARNING_FNAME);
|
||||
|
||||
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
|
||||
bw.write("read\n");
|
||||
Util.silentClose(bw);
|
||||
} catch(Throwable t) {
|
||||
Log.warningEx("Can't write that the user read the warning", t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||
return bp.equals(kbPos) || (bp.equals(tes.getPos()) && side == this.side);
|
||||
}
|
||||
|
||||
}
|
143
src/main/java/net/montoyo/wd/client/gui/GuiMinePad.java
Normal file
143
src/main/java/net/montoyo/wd/client/gui/GuiMinePad.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui;
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.client.ClientProxy;
|
||||
import net.montoyo.wd.utilities.BlockSide;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class GuiMinePad extends WDScreen {
|
||||
|
||||
private ClientProxy.PadData pad;
|
||||
private double vx;
|
||||
private double vy;
|
||||
private double vw;
|
||||
private double vh;
|
||||
|
||||
public GuiMinePad() {
|
||||
}
|
||||
|
||||
public GuiMinePad(ClientProxy.PadData pad) {
|
||||
this.pad = pad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
|
||||
vw = ((double) width) - 32.0f;
|
||||
vh = vw / WebDisplays.PAD_RATIO;
|
||||
vx = 16.0f;
|
||||
vy = (((double) height) - vh) / 2.0f;
|
||||
}
|
||||
|
||||
private static void addRect(BufferBuilder bb, double x, double y, double w, double h) {
|
||||
bb.pos(x, y, 0.0).endVertex();
|
||||
bb.pos(x + w, y, 0.0).endVertex();
|
||||
bb.pos(x + w, y + h, 0.0).endVertex();
|
||||
bb.pos(x, y + h, 0.0).endVertex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float ptt) {
|
||||
drawDefaultBackground();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glColor4f(0.73f, 0.73f, 0.73f, 1.0f);
|
||||
|
||||
Tessellator t = Tessellator.getInstance();
|
||||
BufferBuilder bb = t.getBuffer();
|
||||
bb.begin(GL_QUADS, DefaultVertexFormats.POSITION);
|
||||
addRect(bb, vx, vy - 16, vw, 16);
|
||||
addRect(bb, vx, vy + vh, vw, 16);
|
||||
addRect(bb, vx - 16, vy, 16, vh);
|
||||
addRect(bb, vx + vw, vy, 16, vh);
|
||||
t.draw();
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
if(pad.view != null) {
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
pad.view.draw(vx, vy + vh, vx + vw, vy);
|
||||
}
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInput() {
|
||||
while(Keyboard.next()) {
|
||||
char key = Keyboard.getEventCharacter();
|
||||
int keycode = Keyboard.getEventKey();
|
||||
boolean pressed = Keyboard.getEventKeyState();
|
||||
|
||||
if(Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) {
|
||||
mc.displayGuiScreen(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if(pad.view != null) {
|
||||
if(pressed)
|
||||
pad.view.injectKeyPressedByKeyCode(keycode, key, 0);
|
||||
else
|
||||
pad.view.injectKeyReleasedByKeyCode(keycode, key, 0);
|
||||
|
||||
if(key != 0)
|
||||
pad.view.injectKeyTyped(key, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int vx = screen2DisplayX((int) this.vx);
|
||||
int vy = screen2DisplayY((int) this.vy);
|
||||
int vh = screen2DisplayX((int) this.vh);
|
||||
int vw = screen2DisplayY((int) this.vw);
|
||||
|
||||
while(Mouse.next()) {
|
||||
int btn = Mouse.getEventButton();
|
||||
boolean pressed = Mouse.getEventButtonState();
|
||||
int sx = Mouse.getEventX();
|
||||
int sy = Mouse.getEventY();
|
||||
|
||||
if(pad.view != null && sx >= vx && sx <= vx + vw && sy >= vy && sy <= vy + vh) {
|
||||
sx -= vx;
|
||||
sy -= vy;
|
||||
sy = vh - sy;
|
||||
|
||||
//Scale again according to the webview
|
||||
sx = (int) (((double) sx) / ((double) vw) * WebDisplays.INSTANCE.padResX);
|
||||
sy = (int) (((double) sy) / ((double) vh) * WebDisplays.INSTANCE.padResY);
|
||||
|
||||
if(btn == -1)
|
||||
pad.view.injectMouseMove(sx, sy, 0, false);
|
||||
else
|
||||
pad.view.injectMouseButton(sx, sy, 0, btn + 1, pressed, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
if(pad.view == null)
|
||||
mc.displayGuiScreen(null); //In case the user dies with the pad in the hand
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
80
src/main/java/net/montoyo/wd/client/gui/GuiRedstoneCtrl.java
Normal file
80
src/main/java/net/montoyo/wd/client/gui/GuiRedstoneCtrl.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.montoyo.mcef.api.API;
|
||||
import net.montoyo.wd.client.ClientProxy;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.client.gui.controls.Button;
|
||||
import net.montoyo.wd.client.gui.controls.TextField;
|
||||
import net.montoyo.wd.client.gui.loading.FillControl;
|
||||
import net.montoyo.wd.net.server.SMessageRedstoneCtrl;
|
||||
import net.montoyo.wd.utilities.BlockSide;
|
||||
import net.montoyo.wd.utilities.Util;
|
||||
import net.montoyo.wd.utilities.Vector3i;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class GuiRedstoneCtrl extends WDScreen {
|
||||
|
||||
private int dimension;
|
||||
private Vector3i pos;
|
||||
private String risingEdgeURL;
|
||||
private String fallingEdgeURL;
|
||||
|
||||
@FillControl
|
||||
private TextField tfRisingEdge;
|
||||
|
||||
@FillControl
|
||||
private TextField tfFallingEdge;
|
||||
|
||||
@FillControl
|
||||
private Button btnOk;
|
||||
|
||||
public GuiRedstoneCtrl() {
|
||||
}
|
||||
|
||||
public GuiRedstoneCtrl(int d, Vector3i p, String r, String f) {
|
||||
dimension = d;
|
||||
pos = p;
|
||||
risingEdgeURL = r;
|
||||
fallingEdgeURL = f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
loadFrom(new ResourceLocation("webdisplays", "gui/redstonectrl.json"));
|
||||
tfRisingEdge.setText(risingEdgeURL);
|
||||
tfFallingEdge.setText(fallingEdgeURL);
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onClick(Button.ClickEvent ev) {
|
||||
if(ev.getSource() == btnOk) {
|
||||
API mcef = ((ClientProxy) WebDisplays.PROXY).getMCEF();
|
||||
|
||||
String rising = mcef.punycode(Util.addProtocol(tfRisingEdge.getText()));
|
||||
String falling = mcef.punycode(Util.addProtocol(tfFallingEdge.getText()));
|
||||
WebDisplays.NET_HANDLER.sendToServer(new SMessageRedstoneCtrl(dimension, pos, rising, falling));
|
||||
}
|
||||
|
||||
mc.displayGuiScreen(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||
return pos.equalsBlockPos(bp);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getWikiPageName() {
|
||||
return "Redstone_Controller";
|
||||
}
|
||||
|
||||
}
|
503
src/main/java/net/montoyo/wd/client/gui/GuiScreenConfig.java
Normal file
503
src/main/java/net/montoyo/wd/client/gui/GuiScreenConfig.java
Normal file
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui;
|
||||
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.client.gui.controls.*;
|
||||
import net.montoyo.wd.client.gui.loading.FillControl;
|
||||
import net.montoyo.wd.core.ScreenRights;
|
||||
import net.montoyo.wd.entity.TileEntityScreen;
|
||||
import net.montoyo.wd.item.WDItem;
|
||||
import net.montoyo.wd.net.server.SMessageScreenCtrl;
|
||||
import net.montoyo.wd.utilities.*;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GuiScreenConfig extends WDScreen {
|
||||
|
||||
//Screen data
|
||||
private final TileEntityScreen tes;
|
||||
private final BlockSide side;
|
||||
private NameUUIDPair owner;
|
||||
private NameUUIDPair[] friends;
|
||||
private int friendRights;
|
||||
private int otherRights;
|
||||
private Rotation rotation = Rotation.ROT_0;
|
||||
private float aspectRatio;
|
||||
|
||||
//Autocomplete handling
|
||||
private boolean waitingAC;
|
||||
private int acFailTicks = -1;
|
||||
|
||||
private final ArrayList<NameUUIDPair> acResults = new ArrayList<>();
|
||||
private boolean adding;
|
||||
|
||||
//Controls
|
||||
@FillControl
|
||||
private Label lblOwner;
|
||||
|
||||
@FillControl
|
||||
private List lstFriends;
|
||||
|
||||
@FillControl
|
||||
private Button btnAdd;
|
||||
|
||||
@FillControl
|
||||
private TextField tfFriend;
|
||||
|
||||
@FillControl
|
||||
private TextField tfResX;
|
||||
|
||||
@FillControl
|
||||
private TextField tfResY;
|
||||
|
||||
@FillControl
|
||||
private ControlGroup grpFriends;
|
||||
|
||||
@FillControl
|
||||
private ControlGroup grpOthers;
|
||||
|
||||
@FillControl
|
||||
private CheckBox boxFSetUrl;
|
||||
|
||||
@FillControl
|
||||
private CheckBox boxFClick;
|
||||
|
||||
@FillControl
|
||||
private CheckBox boxFFriends;
|
||||
|
||||
@FillControl
|
||||
private CheckBox boxFOthers;
|
||||
|
||||
@FillControl
|
||||
private CheckBox boxFUpgrades;
|
||||
|
||||
@FillControl
|
||||
private CheckBox boxFResolution;
|
||||
|
||||
@FillControl
|
||||
private CheckBox boxOSetUrl;
|
||||
|
||||
@FillControl
|
||||
private CheckBox boxOClick;
|
||||
|
||||
@FillControl
|
||||
private CheckBox boxOUpgrades;
|
||||
|
||||
@FillControl
|
||||
private CheckBox boxOResolution;
|
||||
|
||||
@FillControl
|
||||
private Button btnSetRes;
|
||||
|
||||
@FillControl
|
||||
private UpgradeGroup ugUpgrades;
|
||||
|
||||
@FillControl
|
||||
private Button btnChangeRot;
|
||||
|
||||
@FillControl
|
||||
private CheckBox cbLockRatio;
|
||||
|
||||
@FillControl
|
||||
private CheckBox cbAutoVolume;
|
||||
|
||||
private CheckBox[] friendBoxes;
|
||||
private CheckBox[] otherBoxes;
|
||||
|
||||
public GuiScreenConfig(TileEntityScreen tes, BlockSide side, NameUUIDPair[] friends, int fr, int or) {
|
||||
this.tes = tes;
|
||||
this.side = side;
|
||||
this.friends = friends;
|
||||
friendRights = fr;
|
||||
otherRights = or;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
loadFrom(new ResourceLocation("webdisplays", "gui/screencfg.json"));
|
||||
|
||||
friendBoxes = new CheckBox[] { boxFResolution, boxFUpgrades, boxFOthers, boxFFriends, boxFClick, boxFSetUrl };
|
||||
boxFResolution.setUserdata(ScreenRights.CHANGE_RESOLUTION);
|
||||
boxFUpgrades.setUserdata(ScreenRights.MANAGE_UPGRADES);
|
||||
boxFOthers.setUserdata(ScreenRights.MANAGE_OTHER_RIGHTS);
|
||||
boxFFriends.setUserdata(ScreenRights.MANAGE_FRIEND_LIST);
|
||||
boxFClick.setUserdata(ScreenRights.CLICK);
|
||||
boxFSetUrl.setUserdata(ScreenRights.CHANGE_URL);
|
||||
|
||||
otherBoxes = new CheckBox[] { boxOResolution, boxOUpgrades, boxOClick, boxOSetUrl };
|
||||
boxOResolution.setUserdata(ScreenRights.CHANGE_RESOLUTION);
|
||||
boxOUpgrades.setUserdata(ScreenRights.MANAGE_UPGRADES);
|
||||
boxOClick.setUserdata(ScreenRights.CLICK);
|
||||
boxOSetUrl.setUserdata(ScreenRights.CHANGE_URL);
|
||||
|
||||
TileEntityScreen.Screen scr = tes.getScreen(side);
|
||||
if(scr != null) {
|
||||
owner = scr.owner;
|
||||
rotation = scr.rotation;
|
||||
|
||||
tfResX.setText("" + scr.resolution.x);
|
||||
tfResY.setText("" + scr.resolution.y);
|
||||
aspectRatio = ((float) scr.resolution.x) / ((float) scr.resolution.y);
|
||||
|
||||
//Hopefully upgrades have been synchronized...
|
||||
ugUpgrades.setUpgrades(scr.upgrades);
|
||||
cbAutoVolume.setChecked(scr.autoVolume);
|
||||
}
|
||||
|
||||
if(owner == null)
|
||||
owner = new NameUUIDPair("???", UUID.randomUUID());
|
||||
|
||||
lblOwner.setLabel(lblOwner.getLabel() + ' ' + owner.name);
|
||||
for(NameUUIDPair f : friends)
|
||||
lstFriends.addElementRaw(f.name, f);
|
||||
|
||||
lstFriends.updateContent();
|
||||
updateRights(friendRights, friendRights, friendBoxes, true);
|
||||
updateRights(otherRights, otherRights, otherBoxes, true);
|
||||
updateMyRights();
|
||||
updateRotationStr();
|
||||
|
||||
mc.getSoundHandler().playSound(PositionedSoundRecord.getRecord(WebDisplays.INSTANCE.soundScreenCfg, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
private void updateRotationStr() {
|
||||
btnChangeRot.setLabel(I18n.format("webdisplays.gui.screencfg.rot" + rotation.getAngleAsInt()));
|
||||
}
|
||||
|
||||
private void addFriend(String name) {
|
||||
if(!name.isEmpty()) {
|
||||
requestAutocomplete(name, true);
|
||||
tfFriend.setDisabled(true);
|
||||
adding = true;
|
||||
waitingAC = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void clickSetRes() {
|
||||
TileEntityScreen.Screen scr = tes.getScreen(side);
|
||||
if(scr == null)
|
||||
return; //WHATDAFUQ?
|
||||
|
||||
try {
|
||||
int x = Integer.parseInt(tfResX.getText());
|
||||
int y = Integer.parseInt(tfResY.getText());
|
||||
if(x < 1 || y < 1)
|
||||
throw new NumberFormatException(); //I'm lazy
|
||||
|
||||
if(x != scr.resolution.x || y != scr.resolution.y)
|
||||
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.vec2(tes, side, SMessageScreenCtrl.CTRL_SET_RESOLUTION, new Vector2i(x, y)));
|
||||
} catch(NumberFormatException ex) {
|
||||
//Roll back
|
||||
tfResX.setText("" + scr.resolution.x);
|
||||
tfResY.setText("" + scr.resolution.y);
|
||||
}
|
||||
|
||||
btnSetRes.setDisabled(true);
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onClick(Button.ClickEvent ev) {
|
||||
if(ev.getSource() == btnAdd && !waitingAC)
|
||||
addFriend(tfFriend.getText().trim());
|
||||
else if(ev.getSource() == btnSetRes)
|
||||
clickSetRes();
|
||||
else if(ev.getSource() == btnChangeRot) {
|
||||
Rotation[] rots = Rotation.values();
|
||||
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tes, side, rots[(rotation.ordinal() + 1) % rots.length]));
|
||||
}
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onEnterPressed(TextField.EnterPressedEvent ev) {
|
||||
if(ev.getSource() == tfFriend && !waitingAC)
|
||||
addFriend(ev.getText().trim());
|
||||
else if((ev.getSource() == tfResX || ev.getSource() == tfResY) && !btnSetRes.isDisabled())
|
||||
clickSetRes();
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onAutocomplete(TextField.TabPressedEvent ev) {
|
||||
if(ev.getSource() == tfFriend && !waitingAC && !ev.getBeginning().isEmpty()) {
|
||||
if(acResults.isEmpty()) {
|
||||
waitingAC = true;
|
||||
requestAutocomplete(ev.getBeginning(), false);
|
||||
} else {
|
||||
NameUUIDPair pair = acResults.remove(0);
|
||||
tfFriend.setText(pair.name);
|
||||
}
|
||||
} else if(ev.getSource() == tfResX) {
|
||||
tfResX.setFocused(false);
|
||||
tfResY.focus();
|
||||
tfResY.getMcField().setCursorPositionZero();
|
||||
tfResY.getMcField().setSelectionPos(tfResY.getText().length());
|
||||
}
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onTextChanged(TextField.TextChangedEvent ev) {
|
||||
if(ev.getSource() == tfResX || ev.getSource() == tfResY) {
|
||||
for(int i = 0; i < ev.getNewContent().length(); i++) {
|
||||
if(!Character.isDigit(ev.getNewContent().charAt(i))) {
|
||||
ev.getSource().setText(ev.getOldContent());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(cbLockRatio.isChecked()) {
|
||||
if(ev.getSource() == tfResX) {
|
||||
try {
|
||||
float val = (float) Integer.parseInt(ev.getNewContent());
|
||||
val /= aspectRatio;
|
||||
tfResY.setText("" + ((int) val));
|
||||
} catch(NumberFormatException ex) {}
|
||||
} else {
|
||||
try {
|
||||
float val = (float) Integer.parseInt(ev.getNewContent());
|
||||
val *= aspectRatio;
|
||||
tfResX.setText("" + ((int) val));
|
||||
} catch(NumberFormatException ex) {}
|
||||
}
|
||||
}
|
||||
|
||||
btnSetRes.setDisabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onRemovePlayer(List.EntryClick ev) {
|
||||
if(ev.getSource() == lstFriends)
|
||||
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tes, side, (NameUUIDPair) ev.getUserdata(), true));
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onCheckboxChanged(CheckBox.CheckedEvent ev) {
|
||||
if(isFriendCheckbox(ev.getSource())) {
|
||||
int flag = (Integer) ev.getSource().getUserdata();
|
||||
if(ev.isChecked())
|
||||
friendRights |= flag;
|
||||
else
|
||||
friendRights &= ~flag;
|
||||
|
||||
requestSync();
|
||||
} else if(isOtherCheckbox(ev.getSource())) {
|
||||
int flag = (Integer) ev.getSource().getUserdata();
|
||||
if(ev.isChecked())
|
||||
otherRights |= flag;
|
||||
else
|
||||
otherRights &= ~flag;
|
||||
|
||||
requestSync();
|
||||
} else if(ev.getSource() == cbLockRatio && ev.isChecked()) {
|
||||
try {
|
||||
int x = Integer.parseInt(tfResX.getText());
|
||||
int y = Integer.parseInt(tfResY.getText());
|
||||
|
||||
aspectRatio = ((float) x) / ((float) y);
|
||||
} catch(NumberFormatException ex) {
|
||||
cbLockRatio.setChecked(false);
|
||||
}
|
||||
} else if(ev.getSource() == cbAutoVolume)
|
||||
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.autoVol(tes, side, ev.isChecked()));
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onRemoveUpgrade(UpgradeGroup.ClickEvent ev) {
|
||||
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tes, side, ev.getMouseOverStack()));
|
||||
}
|
||||
|
||||
public boolean isFriendCheckbox(CheckBox cb) {
|
||||
return Arrays.stream(friendBoxes).anyMatch(fb -> cb == fb);
|
||||
}
|
||||
|
||||
public boolean isOtherCheckbox(CheckBox cb) {
|
||||
return Arrays.stream(otherBoxes).anyMatch(ob -> cb == ob);
|
||||
}
|
||||
|
||||
public boolean hasFriend(NameUUIDPair f) {
|
||||
return Arrays.stream(friends).anyMatch(f::equals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAutocompleteResult(NameUUIDPair pairs[]) {
|
||||
waitingAC = false;
|
||||
|
||||
if(adding) {
|
||||
if(!hasFriend(pairs[0]))
|
||||
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tes, side, pairs[0], false));
|
||||
|
||||
tfFriend.setDisabled(false);
|
||||
tfFriend.clear();
|
||||
tfFriend.focus();
|
||||
adding = false;
|
||||
} else {
|
||||
acResults.clear();
|
||||
acResults.addAll(Arrays.asList(pairs));
|
||||
|
||||
NameUUIDPair pair = acResults.remove(0);
|
||||
tfFriend.setText(pair.name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAutocompleteFailure() {
|
||||
waitingAC = false;
|
||||
acResults.clear();
|
||||
acFailTicks = 0;
|
||||
tfFriend.setTextColor(Control.COLOR_RED);
|
||||
|
||||
if(adding) {
|
||||
tfFriend.setDisabled(false);
|
||||
adding = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
super.updateScreen();
|
||||
|
||||
if(acFailTicks >= 0) {
|
||||
if(++acFailTicks >= 10) {
|
||||
acFailTicks = -1;
|
||||
tfFriend.setTextColor(TextField.DEFAULT_TEXT_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateFriends(NameUUIDPair[] friends) {
|
||||
boolean diff = false;
|
||||
if(friends.length != this.friends.length)
|
||||
diff = true;
|
||||
else {
|
||||
for(NameUUIDPair pair : friends) {
|
||||
if(!hasFriend(pair)) {
|
||||
diff = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(diff) {
|
||||
this.friends = friends;
|
||||
lstFriends.clearRaw();
|
||||
for(NameUUIDPair pair : friends)
|
||||
lstFriends.addElementRaw(pair.name, pair);
|
||||
|
||||
lstFriends.updateContent();
|
||||
}
|
||||
}
|
||||
|
||||
private int updateRights(int current, int newVal, CheckBox[] boxes, boolean force) {
|
||||
if(force || current != newVal) {
|
||||
for(CheckBox box : boxes) {
|
||||
int flag = (Integer) box.getUserdata();
|
||||
box.setChecked((newVal & flag) != 0);
|
||||
}
|
||||
|
||||
if(!force) {
|
||||
Log.info("Screen check boxes were updated");
|
||||
abortSync(); //Value changed by another user, abort modifications by local user
|
||||
}
|
||||
}
|
||||
|
||||
return newVal;
|
||||
}
|
||||
|
||||
public void updateFriendRights(int rights) {
|
||||
friendRights = updateRights(friendRights, rights, friendBoxes, false);
|
||||
}
|
||||
|
||||
public void updateOtherRights(int rights) {
|
||||
otherRights = updateRights(otherRights, rights, otherBoxes, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sync() {
|
||||
WebDisplays.NET_HANDLER.sendToServer(new SMessageScreenCtrl(tes, side, friendRights, otherRights));
|
||||
Log.info("Sent sync packet");
|
||||
}
|
||||
|
||||
public void updateMyRights() {
|
||||
NameUUIDPair me = new NameUUIDPair(mc.player.getGameProfile());
|
||||
int myRights;
|
||||
boolean clientIsOwner = false;
|
||||
|
||||
if(me.equals(owner)) {
|
||||
myRights = ScreenRights.ALL;
|
||||
clientIsOwner = true;
|
||||
} else if(hasFriend(me))
|
||||
myRights = friendRights;
|
||||
else
|
||||
myRights = otherRights;
|
||||
|
||||
//Disable components according to client rights
|
||||
grpFriends.setDisabled(!clientIsOwner);
|
||||
|
||||
boolean flag = (myRights & ScreenRights.MANAGE_FRIEND_LIST) == 0;
|
||||
lstFriends.setDisabled(flag);
|
||||
tfFriend.setDisabled(flag);
|
||||
btnAdd.setDisabled(flag);
|
||||
|
||||
flag = (myRights & ScreenRights.MANAGE_OTHER_RIGHTS) == 0;
|
||||
grpOthers.setDisabled(flag);
|
||||
|
||||
flag = (myRights & ScreenRights.CHANGE_RESOLUTION) == 0;
|
||||
tfResX.setDisabled(flag);
|
||||
tfResY.setDisabled(flag);
|
||||
btnChangeRot.setDisabled(flag);
|
||||
|
||||
if(flag)
|
||||
btnSetRes.setDisabled(true);
|
||||
|
||||
flag = (myRights & ScreenRights.MANAGE_UPGRADES) == 0;
|
||||
ugUpgrades.setDisabled(flag);
|
||||
cbAutoVolume.setDisabled(flag);
|
||||
}
|
||||
|
||||
public void updateResolution(Vector2i res) {
|
||||
aspectRatio = ((float) res.x) / ((float) res.y);
|
||||
tfResX.setText("" + res.x);
|
||||
tfResY.setText("" + res.y);
|
||||
btnSetRes.setDisabled(true);
|
||||
}
|
||||
|
||||
public void updateRotation(Rotation rot) {
|
||||
rotation = rot;
|
||||
updateRotationStr();
|
||||
}
|
||||
|
||||
public void updateAutoVolume(boolean av) {
|
||||
cbAutoVolume.setChecked(av);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||
return bp.equals(tes.getPos()) && side == this.side;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getWikiPageName() {
|
||||
ItemStack is = ugUpgrades.getMouseOverUpgrade();
|
||||
if(is != null) {
|
||||
if(is.getItem() instanceof WDItem)
|
||||
return ((WDItem) is.getItem()).getWikiName(is);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
return "Screen_Configurator";
|
||||
}
|
||||
|
||||
}
|
711
src/main/java/net/montoyo/wd/client/gui/GuiServer.java
Normal file
711
src/main/java/net/montoyo/wd/client/gui/GuiServer.java
Normal file
@@ -0,0 +1,711 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui;
|
||||
|
||||
import net.minecraft.client.audio.ISound;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.miniserv.Constants;
|
||||
import net.montoyo.wd.miniserv.client.*;
|
||||
import net.montoyo.wd.utilities.*;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
public class GuiServer extends WDScreen {
|
||||
|
||||
private static final ResourceLocation BG_IMAGE = new ResourceLocation("webdisplays", "textures/gui/server_bg.png");
|
||||
private static final ResourceLocation FG_IMAGE = new ResourceLocation("webdisplays", "textures/gui/server_fg.png");
|
||||
private static final HashMap<String, Method> COMMAND_MAP = new HashMap<>();
|
||||
private static final int MAX_LINE_LEN = 32;
|
||||
private static final int MAX_LINES = 12;
|
||||
|
||||
private final Vector3i serverPos;
|
||||
private final NameUUIDPair owner;
|
||||
private final ArrayList<String> lines = new ArrayList<>();
|
||||
private String prompt = "";
|
||||
private String userPrompt;
|
||||
private int blinkTime;
|
||||
private String lastCmd;
|
||||
private boolean promptLocked;
|
||||
private volatile long queryTime;
|
||||
private ClientTask<?> currentTask;
|
||||
private int selectedLine = -1;
|
||||
|
||||
//Access command
|
||||
private int accessTrials;
|
||||
private int accessTime;
|
||||
private int accessState = -1;
|
||||
private PositionedSoundRecord accessSound;
|
||||
|
||||
//Upload wizard
|
||||
private boolean uploadWizard;
|
||||
private File uploadDir;
|
||||
private final ArrayList<File> uploadFiles = new ArrayList<>();
|
||||
private int uploadOffset;
|
||||
private boolean uploadFirstIsParent;
|
||||
private String uploadFilter = "";
|
||||
private long uploadFilterTime;
|
||||
|
||||
public GuiServer(Vector3i vec, NameUUIDPair owner) {
|
||||
serverPos = vec;
|
||||
this.owner = owner;
|
||||
//userPrompt = owner.name + "@miniserv$ ";
|
||||
userPrompt = "> ";
|
||||
|
||||
if(COMMAND_MAP.isEmpty())
|
||||
buildCommandMap();
|
||||
|
||||
lines.add("MiniServ 1.0");
|
||||
lines.add(tr("info"));
|
||||
uploadCD(FileSystemView.getFileSystemView().getDefaultDirectory());
|
||||
}
|
||||
|
||||
private static String tr(String key, Object ... args) {
|
||||
return I18n.format("webdisplays.server." + key, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float ptt) {
|
||||
super.drawScreen(mouseX, mouseY, ptt);
|
||||
|
||||
int x = (width - 256) / 2;
|
||||
int y = (height - 176) / 2;
|
||||
|
||||
GlStateManager.enableTexture2D();
|
||||
mc.renderEngine.bindTexture(BG_IMAGE);
|
||||
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
drawTexturedModalRect(x, y, 0, 0, 256, 176);
|
||||
|
||||
x += 18;
|
||||
y += 18;
|
||||
|
||||
for(int i = 0; i < lines.size(); i++) {
|
||||
if(selectedLine == i) {
|
||||
drawWhiteQuad(x - 1, y - 2, fontRenderer.getStringWidth(lines.get(i)) + 1, 12);
|
||||
fontRenderer.drawString(lines.get(i), x, y, 0xFF129700, false);
|
||||
} else
|
||||
fontRenderer.drawString(lines.get(i), x, y, 0xFFFFFFFF, false);
|
||||
|
||||
y += 12;
|
||||
}
|
||||
|
||||
if(!promptLocked) {
|
||||
x = fontRenderer.drawString(userPrompt, x, y, 0xFFFFFFFF, false);
|
||||
x = fontRenderer.drawString(prompt, x, y, 0xFFFFFFFF, false);
|
||||
}
|
||||
|
||||
if(!uploadWizard && blinkTime < 5)
|
||||
drawWhiteQuad(x + 1, y, 6, 8);
|
||||
|
||||
GlStateManager.disableAlpha();
|
||||
GlStateManager.enableTexture2D();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
mc.renderEngine.bindTexture(FG_IMAGE);
|
||||
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
drawTexturedModalRect((width - 256) / 2, (height - 176) / 2, 0, 0, 256, 176);
|
||||
GlStateManager.enableAlpha();
|
||||
}
|
||||
|
||||
private void drawWhiteQuad(int x, int y, int w, int h) {
|
||||
double xd = (double) x;
|
||||
double xd2 = (double) (x + w);
|
||||
double yd = (double) y;
|
||||
double yd2 = (double) (y + h);
|
||||
double zd = (double) zLevel;
|
||||
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
Tessellator t = Tessellator.getInstance();
|
||||
BufferBuilder bb = t.getBuffer();
|
||||
bb.begin(GL_QUADS, DefaultVertexFormats.POSITION);
|
||||
bb.pos(xd, yd2, zd).endVertex();
|
||||
bb.pos(xd2, yd2, zd).endVertex();
|
||||
bb.pos(xd2, yd, zd).endVertex();
|
||||
bb.pos(xd, yd, zd).endVertex();
|
||||
t.draw();
|
||||
GlStateManager.enableTexture2D();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
super.updateScreen();
|
||||
|
||||
if(accessState >= 0) {
|
||||
if(--accessTime <= 0) {
|
||||
accessState++;
|
||||
|
||||
if(accessState == 1) {
|
||||
if(lines.size() > 0)
|
||||
lines.remove(lines.size() - 1);
|
||||
|
||||
lines.add("access: PERMISSION DENIED....and...");
|
||||
accessTime = 20;
|
||||
} else {
|
||||
if(accessSound == null) {
|
||||
accessSound = new PositionedSoundRecord(WebDisplays.INSTANCE.soundServer.getSoundName(), SoundCategory.MASTER, 1.0f, 1.0f, true, 0, ISound.AttenuationType.NONE, 0.0f, 0.0f, 0.0f);
|
||||
mc.getSoundHandler().playSound(accessSound);
|
||||
}
|
||||
|
||||
writeLine("YOU DIDN'T SAY THE MAGIC WORD!");
|
||||
accessTime = 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
blinkTime = (blinkTime + 1) % 10;
|
||||
|
||||
if(currentTask != null) {
|
||||
long queryTime;
|
||||
synchronized(this) {
|
||||
queryTime = this.queryTime;
|
||||
}
|
||||
|
||||
if(System.currentTimeMillis() - queryTime >= 10000) {
|
||||
writeLine(tr("timeout"));
|
||||
currentTask.cancel();
|
||||
clearTask();
|
||||
}
|
||||
}
|
||||
|
||||
if(!uploadFilter.isEmpty() && System.currentTimeMillis() - uploadFilterTime >= 1000) {
|
||||
Log.info("Upload filter cleared");
|
||||
uploadFilter = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleKeyboardInput() throws IOException {
|
||||
boolean keyState = Keyboard.getEventKeyState();
|
||||
int keyCode = Keyboard.getEventKey();
|
||||
|
||||
if(uploadWizard) {
|
||||
if(keyState) {
|
||||
if(keyCode == Keyboard.KEY_UP) {
|
||||
if(selectedLine > 3)
|
||||
selectedLine--;
|
||||
else if(uploadOffset > 0) {
|
||||
uploadOffset--;
|
||||
updateUploadScreen();
|
||||
}
|
||||
} else if(keyCode == Keyboard.KEY_DOWN) {
|
||||
if(selectedLine < MAX_LINES - 1)
|
||||
selectedLine++;
|
||||
else if(uploadOffset + selectedLine - 2 < uploadFiles.size()) {
|
||||
uploadOffset++;
|
||||
updateUploadScreen();
|
||||
}
|
||||
} else if(keyCode == Keyboard.KEY_PRIOR) {
|
||||
selectedLine = 3;
|
||||
int dst = uploadOffset - (MAX_LINES - 3);
|
||||
if(dst < 0)
|
||||
dst = 0;
|
||||
|
||||
selectFile(dst);
|
||||
} else if(keyCode == Keyboard.KEY_NEXT) {
|
||||
selectedLine = 3;
|
||||
int dst = uploadOffset + (MAX_LINES - 3);
|
||||
if(dst >= uploadFiles.size())
|
||||
dst = uploadFiles.size() - 1;
|
||||
|
||||
selectFile(dst);
|
||||
} else if(keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER) {
|
||||
File file = uploadFiles.get(uploadOffset + selectedLine - 3);
|
||||
|
||||
if(file.isDirectory()) {
|
||||
uploadCD(file);
|
||||
updateUploadScreen();
|
||||
} else
|
||||
startFileUpload(file, true);
|
||||
} else if(keyCode == Keyboard.KEY_F5) {
|
||||
uploadCD(uploadDir);
|
||||
updateUploadScreen();
|
||||
}
|
||||
}
|
||||
|
||||
if(keyCode == Keyboard.KEY_ESCAPE) {
|
||||
quitUploadWizard();
|
||||
return; //Don't let the screen handle this
|
||||
}
|
||||
|
||||
super.handleKeyboardInput();
|
||||
} else {
|
||||
super.handleKeyboardInput();
|
||||
|
||||
if(keyState) {
|
||||
boolean ctrl = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL);
|
||||
|
||||
if(keyCode == Keyboard.KEY_L && ctrl)
|
||||
lines.clear();
|
||||
else if(keyCode == Keyboard.KEY_V && ctrl) {
|
||||
prompt += getClipboardString();
|
||||
|
||||
if(prompt.length() > MAX_LINE_LEN)
|
||||
prompt = prompt.substring(0, MAX_LINE_LEN);
|
||||
} else if(keyCode == Keyboard.KEY_UP) {
|
||||
if(lastCmd != null) {
|
||||
String tmp = prompt;
|
||||
prompt = lastCmd;
|
||||
lastCmd = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) throws IOException {
|
||||
super.keyTyped(typedChar, keyCode);
|
||||
|
||||
if(uploadWizard) {
|
||||
boolean found = false;
|
||||
uploadFilter += Character.toLowerCase(typedChar);
|
||||
uploadFilterTime = System.currentTimeMillis();
|
||||
|
||||
for(int i = uploadFirstIsParent ? 1 : 0; i < uploadFiles.size(); i++) {
|
||||
if(uploadFiles.get(i).getName().toLowerCase().startsWith(uploadFilter)) {
|
||||
selectFile(i);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found && uploadFilter.length() == 1)
|
||||
uploadFilter = "";
|
||||
|
||||
return;
|
||||
} else if(promptLocked)
|
||||
return;
|
||||
|
||||
if(keyCode == Keyboard.KEY_BACK) {
|
||||
if(prompt.length() > 0)
|
||||
prompt = prompt.substring(0, prompt.length() - 1);
|
||||
} else if(keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER) {
|
||||
if(prompt.length() > 0) {
|
||||
writeLine(userPrompt + prompt);
|
||||
evaluateCommand(prompt);
|
||||
lastCmd = prompt;
|
||||
prompt = "";
|
||||
} else
|
||||
writeLine(userPrompt);
|
||||
} else if(prompt.length() + 1 < MAX_LINE_LEN && typedChar >= 32 && typedChar <= 126)
|
||||
prompt = prompt + typedChar;
|
||||
|
||||
blinkTime = 0;
|
||||
}
|
||||
|
||||
private void evaluateCommand(String str) {
|
||||
String[] args = str.trim().split("\\s+");
|
||||
Method handler = COMMAND_MAP.get(args[0].toLowerCase());
|
||||
|
||||
if(handler == null) {
|
||||
writeLine(tr("unknowncmd"));
|
||||
return;
|
||||
}
|
||||
|
||||
Object[] params;
|
||||
if(handler.getParameterCount() == 0)
|
||||
params = new Object[0];
|
||||
else {
|
||||
String[] args2 = new String[args.length - 1];
|
||||
System.arraycopy(args, 1, args2, 0, args2.length);
|
||||
params = new Object[] { args2 };
|
||||
}
|
||||
|
||||
try {
|
||||
handler.invoke(this, params);
|
||||
} catch(IllegalAccessException | InvocationTargetException e) {
|
||||
Log.errorEx("Caught exception while running command \"%s\"", e, str);
|
||||
writeLine(tr("error"));
|
||||
}
|
||||
}
|
||||
|
||||
private void writeLine(String line) {
|
||||
final int maxl = uploadWizard ? MAX_LINES : (MAX_LINES - 1); //Cuz prompt is hidden
|
||||
while(lines.size() >= maxl)
|
||||
lines.remove(0);
|
||||
|
||||
lines.add(line);
|
||||
}
|
||||
|
||||
private static void buildCommandMap() {
|
||||
COMMAND_MAP.clear();
|
||||
|
||||
Method[] methods = GuiServer.class.getMethods();
|
||||
for(Method m: methods) {
|
||||
CommandHandler cmd = m.getAnnotation(CommandHandler.class);
|
||||
|
||||
if(cmd != null && Modifier.isPublic(m.getModifiers())) {
|
||||
if(m.getParameterCount() == 0 || (m.getParameterCount() == 1 && m.getParameterTypes()[0] == String[].class))
|
||||
COMMAND_MAP.put(cmd.value().toLowerCase(), m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void quitUploadWizard() {
|
||||
lines.clear();
|
||||
promptLocked = false;
|
||||
uploadWizard = false;
|
||||
selectedLine = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
super.onGuiClosed();
|
||||
|
||||
if(accessSound != null)
|
||||
mc.getSoundHandler().stopSound(accessSound);
|
||||
}
|
||||
|
||||
private boolean queueTask(ClientTask<?> task) {
|
||||
if(Client.getInstance().addTask(task)) {
|
||||
promptLocked = true;
|
||||
queryTime = System.currentTimeMillis(); //No task is running so it's okay to have an unsynchronized access here
|
||||
currentTask = task;
|
||||
return true;
|
||||
} else {
|
||||
writeLine(tr("queryerr"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void clearTask() {
|
||||
promptLocked = false;
|
||||
currentTask = null;
|
||||
}
|
||||
|
||||
private static String trimStringL(String str) {
|
||||
int delta = str.length() - MAX_LINE_LEN;
|
||||
if(delta <= 0)
|
||||
return str;
|
||||
|
||||
return "..." + str.substring(delta + 3);
|
||||
}
|
||||
|
||||
private static String trimStringR(String str) {
|
||||
return (str.length() <= MAX_LINE_LEN) ? str : (str.substring(0, MAX_LINE_LEN - 3) + "...");
|
||||
}
|
||||
|
||||
@CommandHandler("clear")
|
||||
public void commandClear() {
|
||||
lines.clear();
|
||||
}
|
||||
|
||||
@CommandHandler("help")
|
||||
public void commandHelp(String[] args) {
|
||||
if(args.length > 0) {
|
||||
String cmd = args[0].toLowerCase();
|
||||
|
||||
if(COMMAND_MAP.containsKey(cmd))
|
||||
writeLine(tr("help." + cmd));
|
||||
else
|
||||
writeLine(tr("unknowncmd"));
|
||||
} else {
|
||||
for(String c : COMMAND_MAP.keySet())
|
||||
writeLine(c + " - " + tr("help." + c));
|
||||
}
|
||||
}
|
||||
|
||||
@CommandHandler("exit")
|
||||
public void commandExit() {
|
||||
mc.displayGuiScreen(null);
|
||||
}
|
||||
|
||||
@CommandHandler("access")
|
||||
public void commandAccess(String[] args) {
|
||||
boolean handled = false;
|
||||
|
||||
if(args.length >= 1 && args[0].equalsIgnoreCase("security")) {
|
||||
if(args.length == 1 || (args.length == 2 && args[1].equalsIgnoreCase("grid")))
|
||||
handled = true;
|
||||
} else if(args.length == 3 && args[0].equalsIgnoreCase("main") && args[1].equalsIgnoreCase("security") && args[2].equalsIgnoreCase("grid"))
|
||||
handled = true;
|
||||
|
||||
if(handled) {
|
||||
writeLine("access: PERMISSION DENIED.");
|
||||
|
||||
if(++accessTrials >= 3) {
|
||||
promptLocked = true;
|
||||
accessState = 0;
|
||||
accessTime = 20;
|
||||
}
|
||||
} else
|
||||
writeLine(tr("argerror"));
|
||||
}
|
||||
|
||||
@CommandHandler("owner")
|
||||
public void commandOwner() {
|
||||
writeLine(tr("ownername", owner.name));
|
||||
writeLine(tr("owneruuid"));
|
||||
writeLine(owner.uuid.toString());
|
||||
}
|
||||
|
||||
@CommandHandler("quota")
|
||||
public void commandQuota() {
|
||||
if(!mc.player.getGameProfile().getId().equals(owner.uuid)) {
|
||||
writeLine(tr("errowner"));
|
||||
return;
|
||||
}
|
||||
|
||||
ClientTaskGetQuota task = new ClientTaskGetQuota();
|
||||
task.setFinishCallback((t) -> {
|
||||
writeLine(tr("quota", Util.sizeString(t.getQuota()), Util.sizeString(t.getMaxQuota())));
|
||||
clearTask();
|
||||
});
|
||||
|
||||
queueTask(task);
|
||||
}
|
||||
|
||||
@CommandHandler("ls")
|
||||
public void commandList() {
|
||||
ClientTaskGetFileList task = new ClientTaskGetFileList(owner.uuid);
|
||||
task.setFinishCallback((t) -> {
|
||||
String[] files = t.getFileList();
|
||||
if(files != null)
|
||||
Arrays.stream(files).forEach(this::writeLine);
|
||||
|
||||
clearTask();
|
||||
});
|
||||
|
||||
queueTask(task);
|
||||
}
|
||||
|
||||
@CommandHandler("url")
|
||||
public void commandURL(String[] args) {
|
||||
if(args.length < 1) {
|
||||
writeLine(tr("fnamearg"));
|
||||
return;
|
||||
}
|
||||
|
||||
String fname = Util.join(args, " ");
|
||||
if(Util.isFileNameInvalid(fname)) {
|
||||
writeLine(tr("nameerr"));
|
||||
return;
|
||||
}
|
||||
|
||||
ClientTaskCheckFile task = new ClientTaskCheckFile(owner.uuid, fname);
|
||||
task.setFinishCallback((t) -> {
|
||||
int status = t.getStatus();
|
||||
if(status == 0) {
|
||||
writeLine(tr("urlcopied"));
|
||||
setClipboardString(t.getURL());
|
||||
} else if(status == Constants.GETF_STATUS_NOT_FOUND)
|
||||
writeLine(tr("notfound"));
|
||||
else
|
||||
writeLine(tr("error2", status));
|
||||
|
||||
clearTask();
|
||||
});
|
||||
|
||||
queueTask(task);
|
||||
}
|
||||
|
||||
private void uploadCD(File newDir) {
|
||||
try {
|
||||
uploadDir = newDir.getCanonicalFile();
|
||||
} catch(IOException ex) {
|
||||
uploadDir = newDir;
|
||||
}
|
||||
|
||||
uploadFiles.clear();
|
||||
File parent = uploadDir.getParentFile();
|
||||
|
||||
if(parent != null && parent.exists()) {
|
||||
uploadFiles.add(parent);
|
||||
uploadFirstIsParent = true;
|
||||
} else
|
||||
uploadFirstIsParent = false;
|
||||
|
||||
File[] children = uploadDir.listFiles();
|
||||
if(children != null) {
|
||||
Collator c = Collator.getInstance();
|
||||
c.setStrength(Collator.SECONDARY);
|
||||
c.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
|
||||
|
||||
Arrays.stream(children).filter(f -> !f.isHidden() && (f.isDirectory() || f.isFile())).sorted((a, b) -> c.compare(a.getName(), b.getName())).forEach(uploadFiles::add);
|
||||
}
|
||||
|
||||
uploadOffset = 0;
|
||||
uploadFilter = "";
|
||||
|
||||
if(uploadWizard)
|
||||
selectedLine = 3;
|
||||
}
|
||||
|
||||
private void updateUploadScreen() {
|
||||
lines.clear();
|
||||
|
||||
lines.add(tr("upload.info"));
|
||||
lines.add(trimStringL(uploadDir.getPath()));
|
||||
lines.add("");
|
||||
|
||||
for(int i = uploadOffset; i < uploadFiles.size() && lines.size() < MAX_LINES; i++) {
|
||||
if(i == 0 && uploadFirstIsParent)
|
||||
lines.add(tr("upload.parent"));
|
||||
else
|
||||
lines.add(trimStringR(uploadFiles.get(i).getName()));
|
||||
}
|
||||
}
|
||||
|
||||
private void selectFile(int i) {
|
||||
int pos = 3 + i - uploadOffset;
|
||||
if(pos >= 3 && pos < MAX_LINES) {
|
||||
selectedLine = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
uploadOffset = i;
|
||||
if(uploadOffset + MAX_LINES - 3 > uploadFiles.size())
|
||||
uploadOffset = uploadFiles.size() - MAX_LINES + 3;
|
||||
|
||||
updateUploadScreen();
|
||||
selectedLine = 3 + i - uploadOffset;
|
||||
}
|
||||
|
||||
@CommandHandler("upload")
|
||||
public void commandUpload(String[] args) {
|
||||
if(!mc.player.getGameProfile().getId().equals(owner.uuid)) {
|
||||
writeLine(tr("errowner"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(args.length > 0) {
|
||||
File fle = new File(Util.join(args, " "));
|
||||
if(!fle.exists()) {
|
||||
writeLine(tr("notfound"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(fle.isDirectory())
|
||||
uploadCD(fle);
|
||||
else if(fle.isFile()) {
|
||||
startFileUpload(fle, false);
|
||||
return;
|
||||
} else {
|
||||
writeLine(tr("notfound"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uploadWizard = true;
|
||||
promptLocked = true;
|
||||
uploadOffset = 0;
|
||||
selectedLine = 3;
|
||||
updateUploadScreen();
|
||||
}
|
||||
|
||||
@CommandHandler("rm")
|
||||
public void commandDelete(String[] args) {
|
||||
if(!mc.player.getGameProfile().getId().equals(owner.uuid)) {
|
||||
writeLine(tr("errowner"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(args.length < 1) {
|
||||
writeLine(tr("fnamearg"));
|
||||
return;
|
||||
}
|
||||
|
||||
String fname = Util.join(args, " ");
|
||||
if(Util.isFileNameInvalid(fname)) {
|
||||
writeLine(tr("nameerr"));
|
||||
return;
|
||||
}
|
||||
|
||||
ClientTaskDeleteFile task = new ClientTaskDeleteFile(fname);
|
||||
task.setFinishCallback((t) -> {
|
||||
int status = t.getStatus();
|
||||
if(status == 1)
|
||||
writeLine(tr("notfound"));
|
||||
else if(status != 0)
|
||||
writeLine(tr("error"));
|
||||
|
||||
clearTask();
|
||||
});
|
||||
|
||||
queueTask(task);
|
||||
}
|
||||
|
||||
@CommandHandler("reconnect")
|
||||
public void commandReconnect() {
|
||||
Client.getInstance().stop();
|
||||
WebDisplays.NET_HANDLER.sendToServer(Client.getInstance().beginConnection());
|
||||
}
|
||||
|
||||
private void startFileUpload(File f, boolean quit) {
|
||||
if(quit)
|
||||
quitUploadWizard();
|
||||
|
||||
if(Util.isFileNameInvalid(f.getName()) || f.getName().length() >= MAX_LINE_LEN - 3) {
|
||||
writeLine(tr("nameerr"));
|
||||
return;
|
||||
}
|
||||
|
||||
ClientTaskUploadFile task;
|
||||
try {
|
||||
task = new ClientTaskUploadFile(f);
|
||||
} catch(IOException ex) {
|
||||
writeLine(tr("error"));
|
||||
ex.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
task.setProgressCallback((cur, total) -> {
|
||||
synchronized(GuiServer.this) {
|
||||
queryTime = System.currentTimeMillis();
|
||||
}
|
||||
});
|
||||
|
||||
task.setFinishCallback(t -> {
|
||||
int status = t.getUploadStatus();
|
||||
if(status == 0)
|
||||
writeLine(tr("upload.done"));
|
||||
else if(status == Constants.FUPA_STATUS_FILE_EXISTS)
|
||||
writeLine(tr("upload.exists"));
|
||||
else if(status == Constants.FUPA_STATUS_EXCEEDS_QUOTA)
|
||||
writeLine(tr("upload.quota"));
|
||||
else
|
||||
writeLine(tr("error2", status));
|
||||
|
||||
clearTask();
|
||||
});
|
||||
|
||||
if(queueTask(task))
|
||||
writeLine(tr("upload.uploading"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||
return serverPos.equalsBlockPos(bp);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getWikiPageName() {
|
||||
return "Server";
|
||||
}
|
||||
|
||||
}
|
121
src/main/java/net/montoyo/wd/client/gui/GuiSetURL2.java
Normal file
121
src/main/java/net/montoyo/wd/client/gui/GuiSetURL2.java
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.client.ClientProxy;
|
||||
import net.montoyo.wd.client.gui.controls.Button;
|
||||
import net.montoyo.wd.client.gui.controls.TextField;
|
||||
import net.montoyo.wd.client.gui.loading.FillControl;
|
||||
import net.montoyo.wd.entity.TileEntityScreen;
|
||||
import net.montoyo.wd.net.server.SMessagePadCtrl;
|
||||
import net.montoyo.wd.net.server.SMessageScreenCtrl;
|
||||
import net.montoyo.wd.utilities.BlockSide;
|
||||
import net.montoyo.wd.utilities.Util;
|
||||
import net.montoyo.wd.utilities.Vector3i;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class GuiSetURL2 extends WDScreen {
|
||||
|
||||
//Screen data
|
||||
private TileEntityScreen tileEntity;
|
||||
private BlockSide screenSide;
|
||||
private Vector3i remoteLocation;
|
||||
|
||||
//Pad data
|
||||
private final boolean isPad;
|
||||
|
||||
//Common
|
||||
private final String screenURL;
|
||||
|
||||
@FillControl
|
||||
private TextField tfURL;
|
||||
|
||||
@FillControl
|
||||
private Button btnShutDown;
|
||||
|
||||
@FillControl
|
||||
private Button btnCancel;
|
||||
|
||||
@FillControl
|
||||
private Button btnOk;
|
||||
|
||||
public GuiSetURL2(TileEntityScreen tes, BlockSide side, String url, Vector3i rl) {
|
||||
tileEntity = tes;
|
||||
screenSide = side;
|
||||
remoteLocation = rl;
|
||||
isPad = false;
|
||||
screenURL = url;
|
||||
}
|
||||
|
||||
public GuiSetURL2(String url) {
|
||||
isPad = true;
|
||||
screenURL = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
loadFrom(new ResourceLocation("webdisplays", "gui/seturl.json"));
|
||||
tfURL.setText(screenURL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addLoadCustomVariables(Map<String, Double> vars) {
|
||||
vars.put("isPad", isPad ? 1.0 : 0.0);
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onButtonClicked(Button.ClickEvent ev) {
|
||||
if(ev.getSource() == btnCancel)
|
||||
mc.displayGuiScreen(null);
|
||||
else if(ev.getSource() == btnOk)
|
||||
validate(tfURL.getText());
|
||||
else if(ev.getSource() == btnShutDown) {
|
||||
if(isPad)
|
||||
WebDisplays.NET_HANDLER.sendToServer(new SMessagePadCtrl(""));
|
||||
|
||||
mc.displayGuiScreen(null);
|
||||
}
|
||||
}
|
||||
|
||||
@GuiSubscribe
|
||||
public void onEnterPressed(TextField.EnterPressedEvent ev) {
|
||||
validate(ev.getText());
|
||||
}
|
||||
|
||||
private void validate(String url) {
|
||||
if(!url.isEmpty()) {
|
||||
url = Util.addProtocol(url);
|
||||
url = ((ClientProxy) WebDisplays.PROXY).getMCEF().punycode(url);
|
||||
|
||||
if(isPad) {
|
||||
WebDisplays.NET_HANDLER.sendToServer(new SMessagePadCtrl(url));
|
||||
ItemStack held = mc.player.getHeldItem(EnumHand.MAIN_HAND);
|
||||
|
||||
if(held.getItem() == WebDisplays.INSTANCE.itemMinePad && held.getTagCompound() != null && held.getTagCompound().hasKey("PadID")) {
|
||||
ClientProxy.PadData pd = ((ClientProxy) WebDisplays.PROXY).getPadByID(held.getTagCompound().getInteger("PadID"));
|
||||
|
||||
if(pd != null && pd.view != null)
|
||||
pd.view.loadURL(WebDisplays.applyBlacklist(url));
|
||||
}
|
||||
} else
|
||||
WebDisplays.NET_HANDLER.sendToServer(SMessageScreenCtrl.setURL(tileEntity, screenSide, url, remoteLocation));
|
||||
}
|
||||
|
||||
mc.displayGuiScreen(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||
return (remoteLocation != null && remoteLocation.equalsBlockPos(bp)) || (bp.equals(tileEntity.getPos()) && side == screenSide);
|
||||
}
|
||||
|
||||
}
|
15
src/main/java/net/montoyo/wd/client/gui/GuiSubscribe.java
Normal file
15
src/main/java/net/montoyo/wd/client/gui/GuiSubscribe.java
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface GuiSubscribe {
|
||||
}
|
203
src/main/java/net/montoyo/wd/client/gui/RenderRecipe.java
Normal file
203
src/main/java/net/montoyo/wd/client/gui/RenderRecipe.java
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.RenderItem;
|
||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.CraftingManager;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.item.crafting.ShapedRecipes;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import net.montoyo.wd.utilities.Log;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.EXTBgra;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderRecipe extends GuiScreen {
|
||||
|
||||
private static class NameRecipePair {
|
||||
|
||||
private final String name;
|
||||
private final ShapedRecipes recipe;
|
||||
|
||||
private NameRecipePair(String n, ShapedRecipes r) {
|
||||
this.name = n;
|
||||
this.recipe = r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final ResourceLocation CRAFTING_TABLE_GUI_TEXTURES = new ResourceLocation("textures/gui/container/crafting_table.png");
|
||||
private static final int SIZE_X = 176;
|
||||
private static final int SIZE_Y = 166;
|
||||
private int x;
|
||||
private int y;
|
||||
private RenderItem renderItem;
|
||||
private final ItemStack[] recipe = new ItemStack[3 * 3];
|
||||
private ItemStack recipeResult;
|
||||
private String recipeName;
|
||||
private final ArrayList<NameRecipePair> recipes = new ArrayList<>();
|
||||
private IntBuffer buffer;
|
||||
private int[] array;
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
x = (width - SIZE_X) / 2;
|
||||
y = (height - SIZE_Y) / 2;
|
||||
renderItem = mc.getRenderItem();
|
||||
|
||||
for(IRecipe recipe: CraftingManager.REGISTRY) {
|
||||
ResourceLocation regName = recipe.getRegistryName();
|
||||
|
||||
if(regName != null && regName.getResourceDomain().equals("webdisplays")) {
|
||||
if(recipe instanceof ShapedRecipes)
|
||||
recipes.add(new NameRecipePair(regName.getResourcePath(), (ShapedRecipes) recipe));
|
||||
else
|
||||
Log.warning("Found non-shaped recipe %s", regName.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Log.info("Loaded %d recipes", recipes.size());
|
||||
nextRecipe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||
drawDefaultBackground();
|
||||
GlStateManager.color(1.0f, 1.0f, 1.0f);
|
||||
mc.getTextureManager().bindTexture(CRAFTING_TABLE_GUI_TEXTURES);
|
||||
drawTexturedModalRect(x, y, 0, 0, SIZE_X, SIZE_Y);
|
||||
fontRenderer.drawString(I18n.format("container.crafting"), x + 28, y + 6, 0x404040);
|
||||
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
GlStateManager.disableLighting();
|
||||
|
||||
for(int sy = 0; sy < 3; sy++) {
|
||||
for(int sx = 0; sx < 3; sx++) {
|
||||
ItemStack is = recipe[sy * 3 + sx];
|
||||
|
||||
if(is != null) {
|
||||
int x = this.x + 30 + sx * 18;
|
||||
int y = this.y + 17 + sy * 18;
|
||||
|
||||
renderItem.renderItemAndEffectIntoGUI(mc.player, is, x, y);
|
||||
renderItem.renderItemOverlayIntoGUI(fontRenderer, is, x, y, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(recipeResult != null) {
|
||||
renderItem.renderItemAndEffectIntoGUI(mc.player, recipeResult, x + 124, y + 35);
|
||||
renderItem.renderItemOverlayIntoGUI(fontRenderer, recipeResult, x + 124, y + 35, null);
|
||||
}
|
||||
|
||||
GlStateManager.enableLighting();
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
}
|
||||
|
||||
private void setRecipe(ShapedRecipes recipe) {
|
||||
IntStream.range(0, this.recipe.length).forEach(i -> this.recipe[i] = null);
|
||||
NonNullList<Ingredient> ingredients = recipe.getIngredients();
|
||||
int pos = 0;
|
||||
|
||||
for(int y = 0; y < recipe.getRecipeHeight(); y++) {
|
||||
for(int x = 0; x < recipe.getRecipeWidth(); x++) {
|
||||
ItemStack[] stacks = ingredients.get(pos++).getMatchingStacks();
|
||||
|
||||
if(stacks.length > 0)
|
||||
this.recipe[y * 3 + x] = stacks[0];
|
||||
}
|
||||
}
|
||||
|
||||
recipeResult = recipe.getRecipeOutput();
|
||||
}
|
||||
|
||||
private void nextRecipe() {
|
||||
if(recipes.isEmpty())
|
||||
mc.displayGuiScreen(null);
|
||||
else {
|
||||
NameRecipePair pair = recipes.remove(0);
|
||||
setRecipe(pair.recipe);
|
||||
recipeName = pair.name;
|
||||
}
|
||||
}
|
||||
|
||||
private int screen2DisplayX(int x) {
|
||||
double ret = ((double) x) / ((double) width) * ((double) mc.displayWidth);
|
||||
return (int) ret;
|
||||
}
|
||||
|
||||
private int screen2DisplayY(int y) {
|
||||
double ret = ((double) y) / ((double) height) * ((double) mc.displayHeight);
|
||||
return (int) ret;
|
||||
}
|
||||
|
||||
private void takeScreenshot() throws Throwable {
|
||||
int x = screen2DisplayX(this.x + 27);
|
||||
int y = mc.displayHeight - screen2DisplayY(this.y + 4);
|
||||
int w = screen2DisplayX(120);
|
||||
int h = screen2DisplayY(68);
|
||||
y -= h;
|
||||
|
||||
if(buffer == null)
|
||||
buffer = BufferUtils.createIntBuffer(w * h);
|
||||
|
||||
int oldPack = glGetInteger(GL_PACK_ALIGNMENT);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
buffer.clear();
|
||||
glReadPixels(x, y, w, h, EXTBgra.GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, oldPack);
|
||||
|
||||
if(array == null)
|
||||
array = new int[w * h];
|
||||
|
||||
buffer.clear();
|
||||
buffer.get(array);
|
||||
TextureUtil.processPixelValues(array, w, h);
|
||||
|
||||
File f = new File(mc.mcDataDir, "wd_recipes");
|
||||
if(!f.exists())
|
||||
f.mkdir();
|
||||
|
||||
f = new File(f, recipeName + ".png");
|
||||
|
||||
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
|
||||
bi.setRGB(0, 0, w, h, array, 0, w);
|
||||
ImageIO.write(bi, "PNG", f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
if(recipeName != null) {
|
||||
try {
|
||||
takeScreenshot();
|
||||
nextRecipe();
|
||||
} catch(Throwable t) {
|
||||
t.printStackTrace();
|
||||
mc.displayGuiScreen(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
367
src/main/java/net/montoyo/wd/client/gui/WDScreen.java
Normal file
367
src/main/java/net/montoyo/wd/client/gui/WDScreen.java
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.client.gui.controls.Container;
|
||||
import net.montoyo.wd.client.gui.controls.Control;
|
||||
import net.montoyo.wd.client.gui.controls.Event;
|
||||
import net.montoyo.wd.client.gui.controls.List;
|
||||
import net.montoyo.wd.client.gui.loading.FillControl;
|
||||
import net.montoyo.wd.client.gui.loading.GuiLoader;
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
import net.montoyo.wd.net.server.SMessageACQuery;
|
||||
import net.montoyo.wd.utilities.BlockSide;
|
||||
import net.montoyo.wd.utilities.Bounds;
|
||||
import net.montoyo.wd.utilities.Log;
|
||||
import net.montoyo.wd.utilities.NameUUIDPair;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class WDScreen extends GuiScreen {
|
||||
|
||||
public static WDScreen CURRENT_SCREEN = null;
|
||||
|
||||
protected final ArrayList<Control> controls = new ArrayList<>();
|
||||
protected final ArrayList<Control> postDrawList = new ArrayList<>();
|
||||
private final HashMap<Class<? extends Event>, Method> eventMap = new HashMap<>();
|
||||
protected boolean quitOnEscape = true;
|
||||
protected boolean defaultBackground = true;
|
||||
protected int syncTicks = 40;
|
||||
private int syncTicksLeft = -1;
|
||||
|
||||
public WDScreen() {
|
||||
Method[] methods = getClass().getMethods();
|
||||
|
||||
for(Method m : methods) {
|
||||
if(m.getAnnotation(GuiSubscribe.class) != null) {
|
||||
if(!Modifier.isPublic(m.getModifiers()))
|
||||
throw new RuntimeException("Found non public @GuiSubscribe");
|
||||
|
||||
Class<?> params[] = m.getParameterTypes();
|
||||
if(params.length != 1 || !Event.class.isAssignableFrom(params[0]))
|
||||
throw new RuntimeException("Invalid parameters for @GuiSubscribe");
|
||||
|
||||
eventMap.put((Class<? extends Event>) params[0], m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected <T extends Control> T addControl(T ctrl) {
|
||||
controls.add(ctrl);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
public int screen2DisplayX(int x) {
|
||||
double ret = ((double) x) / ((double) width) * ((double) mc.displayWidth);
|
||||
return (int) ret;
|
||||
}
|
||||
|
||||
public int screen2DisplayY(int y) {
|
||||
double ret = ((double) y) / ((double) height) * ((double) mc.displayHeight);
|
||||
return (int) ret;
|
||||
}
|
||||
|
||||
public int display2ScreenX(int x) {
|
||||
double ret = ((double) x) / ((double) mc.displayWidth) * ((double) width);
|
||||
return (int) ret;
|
||||
}
|
||||
|
||||
public int display2ScreenY(int y) {
|
||||
double ret = ((double) y) / ((double) mc.displayHeight) * ((double) height);
|
||||
return (int) ret;
|
||||
}
|
||||
|
||||
protected void centerControls() {
|
||||
//Determine bounding box
|
||||
Bounds bounds = Control.findBounds(controls);
|
||||
|
||||
//Translation vector
|
||||
int diffX = (width - bounds.maxX - bounds.minX) / 2;
|
||||
int diffY = (height - bounds.maxY - bounds.minY) / 2;
|
||||
|
||||
//Translate controls
|
||||
for(Control ctrl : controls) {
|
||||
int x = ctrl.getX();
|
||||
int y = ctrl.getY();
|
||||
|
||||
ctrl.setPos(x + diffX, y + diffY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float ptt) {
|
||||
if(defaultBackground)
|
||||
drawDefaultBackground();
|
||||
|
||||
for(Control ctrl: controls)
|
||||
ctrl.draw(mouseX, mouseY, ptt);
|
||||
|
||||
for(Control ctrl: postDrawList)
|
||||
ctrl.postDraw(mouseX, mouseY, ptt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) throws IOException {
|
||||
if(quitOnEscape && keyCode == Keyboard.KEY_ESCAPE) {
|
||||
mc.displayGuiScreen(null);
|
||||
return;
|
||||
}
|
||||
|
||||
for(Control ctrl: controls)
|
||||
ctrl.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
for(Control ctrl: controls)
|
||||
ctrl.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseReleased(int mouseX, int mouseY, int state) {
|
||||
for(Control ctrl: controls)
|
||||
ctrl.mouseReleased(mouseX, mouseY, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
|
||||
for(Control ctrl: controls)
|
||||
ctrl.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
CURRENT_SCREEN = this;
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
if(syncTicksLeft >= 0) {
|
||||
sync();
|
||||
syncTicksLeft = -1;
|
||||
}
|
||||
|
||||
for(Control ctrl : controls)
|
||||
ctrl.destroy();
|
||||
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
CURRENT_SCREEN = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMouseInput() throws IOException {
|
||||
super.handleMouseInput();
|
||||
|
||||
int x = Mouse.getEventX() * width / mc.displayWidth;
|
||||
int y = height - Mouse.getEventY() * height / mc.displayHeight - 1;
|
||||
int dw = Mouse.getEventDWheel();
|
||||
|
||||
if(dw != 0)
|
||||
onMouseScroll(x, y, dw);
|
||||
else if(Mouse.getEventButton() == -1)
|
||||
onMouseMove(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleKeyboardInput() throws IOException {
|
||||
super.handleKeyboardInput();
|
||||
|
||||
int key = Keyboard.getEventKey();
|
||||
if(key != Keyboard.KEY_NONE) {
|
||||
if(Keyboard.getEventKeyState()) {
|
||||
for(Control ctrl : controls)
|
||||
ctrl.keyDown(key);
|
||||
} else {
|
||||
for(Control ctrl : controls)
|
||||
ctrl.keyUp(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onMouseScroll(int mouseX, int mouseY, int amount) {
|
||||
for(Control ctrl : controls)
|
||||
ctrl.mouseScroll(mouseX, mouseY, amount);
|
||||
}
|
||||
|
||||
public void onMouseMove(int mouseX, int mouseY) {
|
||||
for(Control ctrl : controls)
|
||||
ctrl.mouseMove(mouseX, mouseY);
|
||||
}
|
||||
|
||||
public Object actionPerformed(Event ev) {
|
||||
Method m = eventMap.get(ev.getClass());
|
||||
|
||||
if(m != null) {
|
||||
try {
|
||||
return m.invoke(this, ev);
|
||||
} catch(IllegalAccessException e) {
|
||||
Log.errorEx("Access to event %s of screen %s is denied", e, ev.getClass().getSimpleName(), getClass().getSimpleName());
|
||||
} catch(InvocationTargetException e) {
|
||||
Log.errorEx("Event %s of screen %s failed", e, ev.getClass().getSimpleName(), getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T extends Control> T getControlByName(String name) {
|
||||
for(Control ctrl : controls) {
|
||||
if(name.equals(ctrl.getName()))
|
||||
return (T) ctrl;
|
||||
|
||||
if(ctrl instanceof Container) {
|
||||
Control ret = ((Container) ctrl).getByName(name);
|
||||
|
||||
if(ret != null)
|
||||
return (T) ret;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void addLoadCustomVariables(Map<String, Double> vars) {
|
||||
}
|
||||
|
||||
public void loadFrom(ResourceLocation resLoc) {
|
||||
JsonObject root = GuiLoader.getJson(resLoc);
|
||||
if(root == null)
|
||||
throw new RuntimeException("Could not load GUI file " + resLoc.toString());
|
||||
|
||||
if(!root.has("controls") || !root.get("controls").isJsonArray())
|
||||
throw new RuntimeException("In GUI file " + resLoc.toString() + ": missing root 'controls' object.");
|
||||
|
||||
HashMap<String, Double> vars = new HashMap<>();
|
||||
vars.put("width", (double) width);
|
||||
vars.put("height", (double) height);
|
||||
vars.put("displayWidth", (double) mc.displayWidth);
|
||||
vars.put("displayHeight", (double) mc.displayHeight);
|
||||
addLoadCustomVariables(vars);
|
||||
|
||||
JsonArray content = root.get("controls").getAsJsonArray();
|
||||
for(JsonElement elem: content)
|
||||
controls.add(GuiLoader.create(new JsonOWrapper(elem.getAsJsonObject(), vars)));
|
||||
|
||||
Field[] fields = getClass().getDeclaredFields();
|
||||
for(Field f: fields) {
|
||||
f.setAccessible(true);
|
||||
FillControl fc = f.getAnnotation(FillControl.class);
|
||||
|
||||
if(fc != null) {
|
||||
String name = fc.name().isEmpty() ? f.getName() : fc.name();
|
||||
Control ctrl = getControlByName(name);
|
||||
|
||||
if(ctrl == null) {
|
||||
if(fc.required())
|
||||
throw new RuntimeException("In GUI file " + resLoc.toString() + ": missing required control " + name);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!f.getType().isAssignableFrom(ctrl.getClass()))
|
||||
throw new RuntimeException("In GUI file " + resLoc.toString() + ": invalid type for control " + name);
|
||||
|
||||
try {
|
||||
f.set(this, ctrl);
|
||||
} catch(IllegalAccessException e) {
|
||||
if(fc.required())
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(root.has("center") && root.get("center").getAsBoolean())
|
||||
centerControls();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResize(@Nonnull Minecraft mcIn, int w, int h) {
|
||||
for(Control ctrl : controls)
|
||||
ctrl.destroy();
|
||||
|
||||
controls.clear();
|
||||
super.onResize(mcIn, w, h);
|
||||
}
|
||||
|
||||
protected void requestAutocomplete(String beginning, boolean matchExact) {
|
||||
WebDisplays.NET_HANDLER.sendToServer(new SMessageACQuery(beginning, matchExact));
|
||||
}
|
||||
|
||||
public void onAutocompleteResult(NameUUIDPair pairs[]) {
|
||||
}
|
||||
|
||||
public void onAutocompleteFailure() {
|
||||
}
|
||||
|
||||
protected void requestSync() {
|
||||
syncTicksLeft = syncTicks - 1;
|
||||
}
|
||||
|
||||
protected boolean syncRequested() {
|
||||
return syncTicksLeft >= 0;
|
||||
}
|
||||
|
||||
protected void abortSync() {
|
||||
syncTicksLeft = -1;
|
||||
}
|
||||
|
||||
protected void sync() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
if(syncTicksLeft >= 0) {
|
||||
if(--syncTicksLeft < 0)
|
||||
sync();
|
||||
}
|
||||
}
|
||||
|
||||
public void drawItemStackTooltip(ItemStack is, int x, int y) {
|
||||
renderToolTip(is, x, y); //Since it's protected...
|
||||
}
|
||||
|
||||
public void drawTooltip(java.util.List<String> lines, int x, int y) {
|
||||
drawHoveringText(lines, x, y, fontRenderer); //This is also protected...
|
||||
}
|
||||
|
||||
public void requirePostDraw(Control ctrl) {
|
||||
if(!postDrawList.contains(ctrl))
|
||||
postDrawList.add(ctrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesGuiPauseGame() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract boolean isForBlock(BlockPos bp, BlockSide side);
|
||||
|
||||
@Nullable
|
||||
public String getWikiPageName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
|
||||
public abstract class BasicControl extends Control {
|
||||
|
||||
protected int x;
|
||||
protected int y;
|
||||
protected boolean visible = true;
|
||||
protected boolean disabled = false;
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPos(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public boolean isDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
public void setDisabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
disabled = false;
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
visible = true;
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
visible = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
x = json.getInt("x", 0);
|
||||
y = json.getInt("y", 0);
|
||||
disabled = json.getBool("disabled", false);
|
||||
visible = json.getBool("visible", true);
|
||||
}
|
||||
|
||||
}
|
203
src/main/java/net/montoyo/wd/client/gui/controls/Button.java
Normal file
203
src/main/java/net/montoyo/wd/client/gui/controls/Button.java
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
public class Button extends Control {
|
||||
|
||||
protected final GuiButton btn;
|
||||
protected boolean selected = false;
|
||||
protected boolean shiftDown = false;
|
||||
protected int originalColor = 0;
|
||||
protected int shiftColor = 0;
|
||||
|
||||
public static class ClickEvent extends Event<Button> {
|
||||
|
||||
private final boolean shiftDown;
|
||||
|
||||
private ClickEvent(Button btn) {
|
||||
source = btn;
|
||||
shiftDown = btn.shiftDown;
|
||||
}
|
||||
|
||||
public boolean isShiftDown() {
|
||||
return shiftDown;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Button() {
|
||||
btn = new GuiButton(0, 0, 0, "");
|
||||
}
|
||||
|
||||
public Button(String text, int x, int y, int width) {
|
||||
btn = new GuiButton(0, x, y, width, 20, text);
|
||||
}
|
||||
|
||||
public Button(String text, int x, int y) {
|
||||
btn = new GuiButton(0, x, y, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
if(mouseButton == 0 && btn.mousePressed(mc, mouseX, mouseY)) {
|
||||
selected = true;
|
||||
btn.playPressSound(mc.getSoundHandler());
|
||||
|
||||
if(!onClick())
|
||||
parent.actionPerformed(new ClickEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(int mouseX, int mouseY, int state) {
|
||||
if(selected && state == 0) {
|
||||
btn.mouseReleased(mouseX, mouseY);
|
||||
selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mouseX, int mouseY, float ptt) {
|
||||
btn.drawButton(mc, mouseX, mouseY, ptt);
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
btn.displayString = label;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return btn.displayString;
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
btn.setWidth(width);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return btn.getButtonWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPos(int x, int y) {
|
||||
btn.x = x;
|
||||
btn.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return btn.x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return btn.y;
|
||||
}
|
||||
|
||||
public GuiButton getMcButton() {
|
||||
return btn;
|
||||
}
|
||||
|
||||
public void setDisabled(boolean dis) {
|
||||
btn.enabled = !dis;
|
||||
}
|
||||
|
||||
public boolean isDisabled() {
|
||||
return !btn.enabled;
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
btn.enabled = true;
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
btn.enabled = false;
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible) {
|
||||
btn.visible = visible;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return btn.visible;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
btn.visible = true;
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
btn.visible = false;
|
||||
}
|
||||
|
||||
public boolean isShiftDown() {
|
||||
return shiftDown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyUp(int key) {
|
||||
if(key == Keyboard.KEY_LSHIFT || key == Keyboard.KEY_RSHIFT) {
|
||||
shiftDown = false;
|
||||
btn.packedFGColour = originalColor;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyDown(int key) {
|
||||
if(key == Keyboard.KEY_LSHIFT || key == Keyboard.KEY_RSHIFT) {
|
||||
shiftDown = true;
|
||||
btn.packedFGColour = shiftColor;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTextColor(int color) {
|
||||
originalColor = color;
|
||||
if(!shiftDown)
|
||||
btn.packedFGColour = color;
|
||||
}
|
||||
|
||||
public int getTextColor() {
|
||||
return btn.packedFGColour;
|
||||
}
|
||||
|
||||
public void setShiftTextColor(int shiftColor) {
|
||||
this.shiftColor = shiftColor;
|
||||
if(shiftDown)
|
||||
btn.packedFGColour = shiftColor;
|
||||
}
|
||||
|
||||
public int getShiftTextColor() {
|
||||
return shiftColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
btn.x = json.getInt("x", 0);
|
||||
btn.y = json.getInt("y", 0);
|
||||
btn.width = json.getInt("width", 200);
|
||||
btn.displayString = tr(json.getString("label", btn.displayString));
|
||||
btn.enabled = !json.getBool("disabled", !btn.enabled);
|
||||
btn.visible = json.getBool("visible", btn.visible);
|
||||
|
||||
originalColor = json.getColor("color", originalColor);
|
||||
shiftColor = json.getColor("shiftColor", shiftColor);
|
||||
btn.packedFGColour = originalColor;
|
||||
}
|
||||
|
||||
protected boolean onClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
136
src/main/java/net/montoyo/wd/client/gui/controls/CheckBox.java
Normal file
136
src/main/java/net/montoyo/wd/client/gui/controls/CheckBox.java
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class CheckBox extends BasicControl {
|
||||
|
||||
private static final ResourceLocation texUnchecked = new ResourceLocation("webdisplays", "textures/gui/checkbox.png");
|
||||
private static final ResourceLocation texChecked = new ResourceLocation("webdisplays", "textures/gui/checkbox_checked.png");
|
||||
public static final int WIDTH = 16;
|
||||
public static final int HEIGHT = 16;
|
||||
|
||||
public static class CheckedEvent extends Event<CheckBox> {
|
||||
|
||||
private final boolean checked;
|
||||
|
||||
private CheckedEvent(CheckBox cb) {
|
||||
source = cb;
|
||||
checked = cb.checked;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return checked;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String label;
|
||||
private int labelW;
|
||||
private boolean checked;
|
||||
private java.util.List<String> tooltip;
|
||||
|
||||
public CheckBox() {
|
||||
label = "";
|
||||
}
|
||||
|
||||
public CheckBox(int x, int y, String label) {
|
||||
this.label = label;
|
||||
labelW = font.getStringWidth(label);
|
||||
checked = false;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public CheckBox(int x, int y, String label, boolean val) {
|
||||
this.label = label;
|
||||
labelW = font.getStringWidth(label);
|
||||
checked = val;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
if(mouseButton == 0 && !disabled) {
|
||||
if(mouseX >= x && mouseX <= x + WIDTH + 2 + labelW && mouseY >= y && mouseY < y + HEIGHT) {
|
||||
checked = !checked;
|
||||
mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(SoundEvents.UI_BUTTON_CLICK, 1.0F));
|
||||
parent.actionPerformed(new CheckedEvent(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mouseX, int mouseY, float ptt) {
|
||||
if(visible) {
|
||||
GlStateManager.disableAlpha();
|
||||
|
||||
bindTexture(checked ? texChecked : texUnchecked);
|
||||
blend(true);
|
||||
fillTexturedRect(x, y, WIDTH, HEIGHT, 0.0, 0.0, 1.0, 1.0);
|
||||
blend(false);
|
||||
bindTexture(null);
|
||||
|
||||
boolean inside = (!disabled && mouseX >= x && mouseX <= x + WIDTH + 2 + labelW && mouseY >= y && mouseY < y + HEIGHT);
|
||||
font.drawString(label, x + WIDTH + 2, y + 4, inside ? 0xFF0080FF : COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
labelW = font.getStringWidth(label);
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return checked;
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return WIDTH + 2 + labelW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
label = tr(json.getString("label", ""));
|
||||
labelW = font.getStringWidth(label);
|
||||
checked = json.getBool("checked", false);
|
||||
|
||||
String tt = tr(json.getString("tooltip", ""));
|
||||
if(!tt.isEmpty()) {
|
||||
tooltip = Arrays.asList(tt.split("\\\\n"));
|
||||
parent.requirePostDraw(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDraw(int mouseX, int mouseY, float ptt) {
|
||||
if(tooltip != null && !disabled && mouseX >= x && mouseX <= x + WIDTH + 2 + labelW && mouseY >= y && mouseY < y + HEIGHT)
|
||||
parent.drawTooltip(tooltip, mouseX, mouseY);
|
||||
}
|
||||
|
||||
}
|
157
src/main/java/net/montoyo/wd/client/gui/controls/Container.java
Normal file
157
src/main/java/net/montoyo/wd/client/gui/controls/Container.java
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.montoyo.wd.client.gui.loading.GuiLoader;
|
||||
import net.montoyo.wd.client.gui.loading.JsonAWrapper;
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public abstract class Container extends BasicControl {
|
||||
|
||||
protected int paddingX = 0;
|
||||
protected int paddingY = 0;
|
||||
protected final ArrayList<Control> childs = new ArrayList<>();
|
||||
|
||||
public <T extends Control> T addControl(T ctrl) {
|
||||
childs.add(ctrl);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(char typedChar, int keyCode) throws IOException {
|
||||
if(!disabled) {
|
||||
for(Control ctrl : childs)
|
||||
ctrl.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyUp(int key) {
|
||||
if(!disabled) {
|
||||
for(Control ctrl : childs)
|
||||
ctrl.keyUp(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyDown(int key) {
|
||||
if(!disabled) {
|
||||
for(Control ctrl : childs)
|
||||
ctrl.keyDown(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
if(!disabled) {
|
||||
mouseX -= x + paddingX;
|
||||
mouseY -= y + paddingY;
|
||||
|
||||
for(Control ctrl : childs)
|
||||
ctrl.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(int mouseX, int mouseY, int state) {
|
||||
if(!disabled) {
|
||||
mouseX -= x + paddingX;
|
||||
mouseY -= y + paddingY;
|
||||
|
||||
for(Control ctrl : childs)
|
||||
ctrl.mouseReleased(mouseX, mouseY, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
|
||||
if(!disabled) {
|
||||
mouseX -= x + paddingX;
|
||||
mouseY -= y + paddingY;
|
||||
|
||||
for(Control ctrl : childs)
|
||||
ctrl.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMove(int mouseX, int mouseY) {
|
||||
if(!disabled) {
|
||||
mouseX -= x + paddingX;
|
||||
mouseY -= y + paddingY;
|
||||
|
||||
for(Control ctrl : childs)
|
||||
ctrl.mouseMove(mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseScroll(int mouseX, int mouseY, int amount) {
|
||||
if(!disabled) {
|
||||
mouseX -= x + paddingX;
|
||||
mouseY -= y + paddingY;
|
||||
|
||||
for(Control ctrl : childs)
|
||||
ctrl.mouseScroll(mouseX, mouseY, amount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mouseX, int mouseY, float ptt) {
|
||||
if(visible) {
|
||||
mouseX -= x + paddingX;
|
||||
mouseY -= y + paddingY;
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glTranslated((double) (x + paddingX), (double) (y + paddingY), 0.0);
|
||||
|
||||
if(disabled) {
|
||||
for(Control ctrl : childs)
|
||||
ctrl.draw(-1, -1, ptt);
|
||||
} else {
|
||||
for(Control ctrl : childs)
|
||||
ctrl.draw(mouseX, mouseY, ptt);
|
||||
}
|
||||
|
||||
GL11.glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
for(Control ctrl : childs)
|
||||
ctrl.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
|
||||
JsonAWrapper objs = json.getArray("childs");
|
||||
for(int i = 0; i < objs.size(); i++)
|
||||
childs.add(GuiLoader.create(objs.getObject(i)));
|
||||
}
|
||||
|
||||
public Control getByName(String name) {
|
||||
for(Control ctrl : childs) {
|
||||
if(name.equals(ctrl.name))
|
||||
return ctrl;
|
||||
|
||||
if(ctrl instanceof Container) {
|
||||
Control ret = ((Container) ctrl).getByName(name);
|
||||
|
||||
if(ret != null)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
282
src/main/java/net/montoyo/wd/client/gui/controls/Control.java
Normal file
282
src/main/java/net/montoyo/wd/client/gui/controls/Control.java
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.client.shader.Framebuffer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.montoyo.wd.client.gui.WDScreen;
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
import net.montoyo.wd.utilities.Bounds;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
public abstract class Control {
|
||||
|
||||
public static final int COLOR_BLACK = 0xFF000000;
|
||||
public static final int COLOR_WHITE = 0xFFFFFFFF;
|
||||
public static final int COLOR_RED = 0xFFFF0000;
|
||||
public static final int COLOR_GREEN = 0xFF00FF00;
|
||||
public static final int COLOR_BLUE = 0xFF0000FF;
|
||||
public static final int COLOR_CYAN = 0xFF00FFFF;
|
||||
public static final int COLOR_MANGENTA = 0xFFFF00FF;
|
||||
public static final int COLOR_YELLOW = 0xFFFFFF00;
|
||||
|
||||
protected final Minecraft mc;
|
||||
protected final FontRenderer font;
|
||||
protected final Tessellator tessellator;
|
||||
protected final BufferBuilder vBuffer;
|
||||
protected final WDScreen parent;
|
||||
protected String name;
|
||||
protected Object userdata;
|
||||
|
||||
public Control() {
|
||||
mc = Minecraft.getMinecraft();
|
||||
font = mc.fontRenderer;
|
||||
tessellator = Tessellator.getInstance();
|
||||
vBuffer = tessellator.getBuffer();
|
||||
parent = WDScreen.CURRENT_SCREEN;
|
||||
}
|
||||
|
||||
public Object getUserdata() {
|
||||
return userdata;
|
||||
}
|
||||
|
||||
public void setUserdata(Object userdata) {
|
||||
this.userdata = userdata;
|
||||
}
|
||||
|
||||
public void keyTyped(char typedChar, int keyCode) throws IOException {
|
||||
}
|
||||
|
||||
public void keyUp(int key) {
|
||||
}
|
||||
|
||||
public void keyDown(int key) {
|
||||
}
|
||||
|
||||
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
}
|
||||
|
||||
public void mouseReleased(int mouseX, int mouseY, int state) {
|
||||
}
|
||||
|
||||
public void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
|
||||
}
|
||||
|
||||
public void mouseMove(int mouseX, int mouseY) {
|
||||
}
|
||||
|
||||
public void mouseScroll(int mouseX, int mouseY, int amount) {
|
||||
}
|
||||
|
||||
public void draw(int mouseX, int mouseY, float ptt) {
|
||||
}
|
||||
|
||||
public void postDraw(int mouseX, int mouseY, float ptt) {
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
public WDScreen getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public abstract int getX();
|
||||
public abstract int getY();
|
||||
public abstract int getWidth();
|
||||
public abstract int getHeight();
|
||||
public abstract void setPos(int x, int y);
|
||||
|
||||
public void fillRect(int x, int y, int w, int h, int color) {
|
||||
double x1 = (double) x;
|
||||
double y1 = (double) y;
|
||||
double x2 = (double) (x + w);
|
||||
double y2 = (double) (y + h);
|
||||
int a = (color >> 24) & 0xFF;
|
||||
int r = (color >> 16) & 0xFF;
|
||||
int g = (color >> 8 ) & 0xFF;
|
||||
int b = color & 0xFF;
|
||||
|
||||
glColor4f(((float) r) / 255.f, ((float) g) / 255.f, ((float) b) / 255.f, ((float) a) / 255.f);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
vBuffer.begin(GL_QUADS, DefaultVertexFormats.POSITION);
|
||||
vBuffer.pos(x1, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y1, 0.0).endVertex();
|
||||
vBuffer.pos(x1, y1, 0.0).endVertex();
|
||||
tessellator.draw();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
public void fillTexturedRect(int x, int y, int w, int h, double u1, double v1, double u2, double v2) {
|
||||
double x1 = (double) x;
|
||||
double y1 = (double) y;
|
||||
double x2 = (double) (x + w);
|
||||
double y2 = (double) (y + h);
|
||||
|
||||
vBuffer.begin(GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
vBuffer.pos(x1, y2, 0.0).tex(u1, v2).color(255, 255, 255, 255).endVertex();
|
||||
vBuffer.pos(x2, y2, 0.0).tex(u2, v2).color(255, 255, 255, 255).endVertex();
|
||||
vBuffer.pos(x2, y1, 0.0).tex(u2, v1).color(255, 255, 255, 255).endVertex();
|
||||
vBuffer.pos(x1, y1, 0.0).tex(u1, v1).color(255, 255, 255, 255).endVertex();
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
public static void blend(boolean enable) {
|
||||
if(enable) {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
} else
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
public void bindTexture(ResourceLocation resLoc) {
|
||||
if(resLoc == null)
|
||||
GlStateManager.bindTexture(0); //Damn state manager
|
||||
else
|
||||
mc.renderEngine.bindTexture(resLoc);
|
||||
}
|
||||
|
||||
public void drawBorder(int x, int y, int w, int h, int color) {
|
||||
drawBorder(x, y, w, h, color, 1.0);
|
||||
}
|
||||
|
||||
public void drawBorder(int x, int y, int w, int h, int color, double sz) {
|
||||
double x1 = (double) x;
|
||||
double y1 = (double) y;
|
||||
double x2 = (double) (x + w);
|
||||
double y2 = (double) (y + h);
|
||||
int a = (color >> 24) & 0xFF;
|
||||
int r = (color >> 16) & 0xFF;
|
||||
int g = (color >> 8 ) & 0xFF;
|
||||
int b = color & 0xFF;
|
||||
|
||||
glColor4f(((float) r) / 255.f, ((float) g) / 255.f, ((float) b) / 255.f, ((float) a) / 255.f);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
vBuffer.begin(GL_QUADS, DefaultVertexFormats.POSITION);
|
||||
//Top edge (y = y1)
|
||||
vBuffer.pos(x1, y1 + sz, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y1 + sz, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y1, 0.0).endVertex();
|
||||
vBuffer.pos(x1, y1, 0.0).endVertex();
|
||||
|
||||
//Bottom edge (y = y2)
|
||||
vBuffer.pos(x1, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y2 - sz, 0.0).endVertex();
|
||||
vBuffer.pos(x1, y2 - sz, 0.0).endVertex();
|
||||
|
||||
//Left edge (x = x1)
|
||||
vBuffer.pos(x1, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x1 + sz, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x1 + sz, y1, 0.0).endVertex();
|
||||
vBuffer.pos(x1, y1, 0.0).endVertex();
|
||||
|
||||
//Right edge (x = x2)
|
||||
vBuffer.pos(x2 - sz, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y1, 0.0).endVertex();
|
||||
vBuffer.pos(x2 - sz, y1, 0.0).endVertex();
|
||||
tessellator.draw();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
public void beginFramebuffer(Framebuffer fbo, int vpW, int vpH) {
|
||||
fbo.bindFramebuffer(true);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0, (double) vpW, (double) vpH, 0.0, -1.0,1.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
if(!fbo.useDepth)
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
public void endFramebuffer(Framebuffer fbo) {
|
||||
if(!fbo.useDepth)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
fbo.unbindFramebuffer();
|
||||
mc.getFramebuffer().bindFramebuffer(true);
|
||||
}
|
||||
|
||||
public static String tr(String text) {
|
||||
if(text.length() >= 2 && text.charAt(0) == '$') {
|
||||
if(text.charAt(1) == '$')
|
||||
return text.substring(1);
|
||||
else
|
||||
return I18n.format(text.substring(1));
|
||||
} else
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void load(JsonOWrapper json) {
|
||||
name = json.getString("name", "");
|
||||
}
|
||||
|
||||
public static Bounds findBounds(java.util.List<Control> controlList) {
|
||||
int minX = Integer.MAX_VALUE;
|
||||
int minY = Integer.MAX_VALUE;
|
||||
int maxX = Integer.MIN_VALUE;
|
||||
int maxY = Integer.MIN_VALUE;
|
||||
|
||||
for(Control ctrl : controlList) {
|
||||
int x = ctrl.getX();
|
||||
int y = ctrl.getY();
|
||||
if(x < minX)
|
||||
minX = x;
|
||||
|
||||
if(y < minY)
|
||||
minY = y;
|
||||
|
||||
x += ctrl.getWidth();
|
||||
y += ctrl.getHeight();
|
||||
|
||||
if(x > maxX)
|
||||
maxX = x;
|
||||
|
||||
if(y >= maxY)
|
||||
maxY = y;
|
||||
}
|
||||
|
||||
return new Bounds(minX, minY, maxX, maxY);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
import net.montoyo.wd.utilities.Bounds;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
public class ControlGroup extends Container {
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
private String label;
|
||||
private int labelW;
|
||||
private int labelColor = COLOR_WHITE;
|
||||
private boolean labelShadowed = true;
|
||||
|
||||
public ControlGroup() {
|
||||
width = 100;
|
||||
height = 100;
|
||||
label = "";
|
||||
paddingX = 8;
|
||||
paddingY = 8;
|
||||
}
|
||||
|
||||
public ControlGroup(int x, int y, int w, int h) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
width = w;
|
||||
height = h;
|
||||
paddingX = 8;
|
||||
paddingY = 8;
|
||||
label = "";
|
||||
labelW = 0;
|
||||
}
|
||||
|
||||
public ControlGroup(int x, int y, int w, int h, String label) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
width = w;
|
||||
height = h;
|
||||
this.label = label;
|
||||
this.labelW = font.getStringWidth(label);
|
||||
paddingX = 8;
|
||||
paddingY = 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setSize(int w, int h) {
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
labelW = font.getStringWidth(label);
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public int getLabelColor() {
|
||||
return labelColor;
|
||||
}
|
||||
|
||||
public void setLabelColor(int labelColor) {
|
||||
this.labelColor = labelColor;
|
||||
}
|
||||
|
||||
public boolean isLabelShadowed() {
|
||||
return labelShadowed;
|
||||
}
|
||||
|
||||
public void setLabelShadowed(boolean labelShadowed) {
|
||||
this.labelShadowed = labelShadowed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mouseX, int mouseY, float ptt) {
|
||||
super.draw(mouseX, mouseY, ptt);
|
||||
|
||||
if(visible) {
|
||||
glColor4f(0.5f, 0.5f, 0.5f, 1.f);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
double x1 = (double) x;
|
||||
double y1 = (double) y;
|
||||
double x2 = (double) (x + width);
|
||||
double y2 = (double) (y + height);
|
||||
double bp = 4.0;
|
||||
double lw = (double) labelW;
|
||||
|
||||
x1 += bp;
|
||||
y1 += bp;
|
||||
x2 -= bp;
|
||||
y2 -= bp;
|
||||
lw += 12.0;
|
||||
|
||||
vBuffer.begin(GL_QUADS, DefaultVertexFormats.POSITION);
|
||||
|
||||
//Top edge (y = y1)
|
||||
if(labelW == 0) {
|
||||
vBuffer.pos(x1, y1 + 1.0, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y1 + 1.0, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y1, 0.0).endVertex();
|
||||
vBuffer.pos(x1, y1, 0.0).endVertex();
|
||||
} else {
|
||||
//Left
|
||||
vBuffer.pos(x1, y1 + 1.0, 0.0).endVertex();
|
||||
vBuffer.pos(x1 + 8.0, y1 + 1.0, 0.0).endVertex();
|
||||
vBuffer.pos(x1 + 8.0, y1, 0.0).endVertex();
|
||||
vBuffer.pos(x1, y1, 0.0).endVertex();
|
||||
|
||||
//Right
|
||||
vBuffer.pos(x1 + lw, y1 + 1.0, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y1 + 1.0, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y1, 0.0).endVertex();
|
||||
vBuffer.pos(x1 + lw, y1, 0.0).endVertex();
|
||||
}
|
||||
|
||||
//Bottom edge (y = y2)
|
||||
vBuffer.pos(x1, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y2 - 1.0, 0.0).endVertex();
|
||||
vBuffer.pos(x1, y2 - 1.0, 0.0).endVertex();
|
||||
|
||||
//Left edge (x = x1)
|
||||
vBuffer.pos(x1, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x1 + 1.0, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x1 + 1.0, y1, 0.0).endVertex();
|
||||
vBuffer.pos(x1, y1, 0.0).endVertex();
|
||||
|
||||
//Right edge (x = x2)
|
||||
vBuffer.pos(x2 - 1.0, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y2, 0.0).endVertex();
|
||||
vBuffer.pos(x2, y1, 0.0).endVertex();
|
||||
vBuffer.pos(x2 - 1.0, y1, 0.0).endVertex();
|
||||
tessellator.draw();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
if(labelW != 0)
|
||||
font.drawString(label, x + 10 + ((int) bp), y, labelColor, labelShadowed);
|
||||
}
|
||||
}
|
||||
|
||||
public void pack() {
|
||||
Bounds bounds = findBounds(childs);
|
||||
for(Control ctrl : childs)
|
||||
ctrl.setPos(ctrl.getX() - bounds.minX, ctrl.getY() - bounds.minY);
|
||||
|
||||
width = bounds.getWidth() + paddingX * 2;
|
||||
height = bounds.getHeight() + paddingY * 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
width = json.getInt("width", 100);
|
||||
height = json.getInt("height", 100);
|
||||
label = tr(json.getString("label", ""));
|
||||
labelW = font.getStringWidth(label);
|
||||
labelColor = json.getColor("labelColor", COLOR_WHITE);
|
||||
labelShadowed = json.getBool("labelShadowed", true);
|
||||
|
||||
if(json.getBool("pack", false))
|
||||
pack();
|
||||
}
|
||||
|
||||
}
|
15
src/main/java/net/montoyo/wd/client/gui/controls/Event.java
Normal file
15
src/main/java/net/montoyo/wd/client/gui/controls/Event.java
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
public abstract class Event<T extends Control> {
|
||||
|
||||
protected T source;
|
||||
|
||||
public T getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
}
|
91
src/main/java/net/montoyo/wd/client/gui/controls/Icon.java
Normal file
91
src/main/java/net/montoyo/wd/client/gui/controls/Icon.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class Icon extends BasicControl {
|
||||
|
||||
protected int width;
|
||||
protected int height;
|
||||
protected double u1;
|
||||
protected double v1;
|
||||
protected double u2;
|
||||
protected double v2;
|
||||
protected ResourceLocation texture;
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
|
||||
width = json.getInt("width", 16);
|
||||
height = json.getInt("height", 16);
|
||||
u1 = json.getDouble("u1", 0.0);
|
||||
v1 = json.getDouble("v1", 0.0);
|
||||
u2 = json.getDouble("u2", 1.0);
|
||||
v2 = json.getDouble("v2", 1.0);
|
||||
texture = new ResourceLocation(json.getString("resourceLocation", ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mouseX, int mouseY, float ptt) {
|
||||
if(texture != null) {
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
bindTexture(texture);
|
||||
blend(true);
|
||||
fillTexturedRect(x, y, width, height, u1, v1, u2, v2);
|
||||
blend(false);
|
||||
bindTexture(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public void setTextureCoordinates(double u1, double v1, double u2, double v2) {
|
||||
this.u1 = u1;
|
||||
this.v1 = v1;
|
||||
this.u2 = u2;
|
||||
this.v2 = v2;
|
||||
}
|
||||
|
||||
public void setTexture(ResourceLocation texture) {
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
public double getU1() {
|
||||
return u1;
|
||||
}
|
||||
|
||||
public double getV1() {
|
||||
return v1;
|
||||
}
|
||||
|
||||
public double getU2() {
|
||||
return u2;
|
||||
}
|
||||
|
||||
public double getV2() {
|
||||
return v2;
|
||||
}
|
||||
|
||||
}
|
98
src/main/java/net/montoyo/wd/client/gui/controls/Label.java
Normal file
98
src/main/java/net/montoyo/wd/client/gui/controls/Label.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
|
||||
public class Label extends BasicControl {
|
||||
|
||||
private String label;
|
||||
private int labelW;
|
||||
private int color;
|
||||
private boolean shadowed;
|
||||
|
||||
public Label() {
|
||||
label = "";
|
||||
color = COLOR_WHITE;
|
||||
}
|
||||
|
||||
public Label(int x, int y, String str) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
label = str;
|
||||
labelW = font.getStringWidth(str);
|
||||
color = COLOR_WHITE;
|
||||
shadowed = false;
|
||||
}
|
||||
|
||||
public Label(int x, int y, String str, int color) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
label = str;
|
||||
labelW = font.getStringWidth(str);
|
||||
this.color = color;
|
||||
shadowed = false;
|
||||
}
|
||||
|
||||
public Label(int x, int y, String str, int color, boolean shadowed) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
label = str;
|
||||
labelW = font.getStringWidth(str);
|
||||
this.color = color;
|
||||
this.shadowed = shadowed;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
labelW = font.getStringWidth(label);
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setShadowed(boolean shadowed) {
|
||||
this.shadowed = shadowed;
|
||||
}
|
||||
|
||||
public boolean isShadowed() {
|
||||
return shadowed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mouseX, int mouseY, float ptt) {
|
||||
if(visible)
|
||||
font.drawString(label, x, y, color, shadowed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return labelW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
label = tr(json.getString("label", ""));
|
||||
labelW = font.getStringWidth(label);
|
||||
color = json.getColor("color", COLOR_WHITE);
|
||||
shadowed = json.getBool("shadowed", false);
|
||||
}
|
||||
|
||||
}
|
383
src/main/java/net/montoyo/wd/client/gui/controls/List.java
Normal file
383
src/main/java/net/montoyo/wd/client/gui/controls/List.java
Normal file
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.minecraft.client.shader.Framebuffer;
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
public class List extends BasicControl {
|
||||
|
||||
private static class Entry {
|
||||
public final String text;
|
||||
public final Object userdata;
|
||||
|
||||
public Entry(String t, Object o) {
|
||||
text = t;
|
||||
userdata = o;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class EntryClick extends Event<List> {
|
||||
|
||||
private final int id;
|
||||
private final Entry entry;
|
||||
|
||||
private EntryClick(List lst) {
|
||||
source = lst;
|
||||
id = lst.selected;
|
||||
entry = lst.content.get(lst.selected);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return entry.text;
|
||||
}
|
||||
|
||||
public Object getUserdata() {
|
||||
return entry.userdata;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
private final ArrayList<Entry> content = new ArrayList<>();
|
||||
private Framebuffer fbo;
|
||||
private int selected = -1;
|
||||
private boolean update;
|
||||
private int selColor = 0xFF0080FF;
|
||||
|
||||
//Scroll handling
|
||||
private int contentH = 0;
|
||||
private int scrollSize;
|
||||
private int scrollPos = 0;
|
||||
private boolean scrolling = false;
|
||||
private int scrollGrab;
|
||||
|
||||
public List() {
|
||||
}
|
||||
|
||||
public List(int x, int y, int w, int h) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
width = w;
|
||||
height = h;
|
||||
scrollSize = h - 2;
|
||||
createFBO();
|
||||
}
|
||||
|
||||
private int getYOffset() {
|
||||
double amount = ((double) scrollPos) / ((double) (height - 2 - scrollSize)) * ((double) (contentH - height));
|
||||
return (int) amount;
|
||||
}
|
||||
|
||||
private boolean isInScrollbar(int mouseX, int mouseY) {
|
||||
return mouseX >= x + width - 5 && mouseX <= x + width - 1 && mouseY >= y + 1 + scrollPos && mouseY <= y + 1 + scrollPos + scrollSize;
|
||||
}
|
||||
|
||||
private void createFBO() {
|
||||
if(fbo != null)
|
||||
fbo.deleteFramebuffer();
|
||||
|
||||
fbo = new Framebuffer(parent.screen2DisplayX(width), parent.screen2DisplayY(height), false);
|
||||
fbo.setFramebufferFilter(GL_NEAREST);
|
||||
fbo.bindFramebuffer(false);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.f); //Set alpha to 1
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
fbo.unbindFramebuffer();
|
||||
update = true;
|
||||
}
|
||||
|
||||
private void renderToFBO() {
|
||||
beginFramebuffer(fbo, width, height);
|
||||
fillRect(0, 0, width, height, COLOR_BLACK);
|
||||
glColor4f(1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
int offset = 4 - getYOffset();
|
||||
for(int i = 0; i < content.size(); i++) {
|
||||
int pos = i * 12 + offset;
|
||||
|
||||
if(pos + 12 >= 1) {
|
||||
if(pos >= height - 1)
|
||||
break;
|
||||
|
||||
int color = (i == selected) ? selColor : COLOR_WHITE;
|
||||
font.drawString(content.get(i).text, 4, i * 12 + offset, color);
|
||||
}
|
||||
}
|
||||
|
||||
drawBorder(0, 0, width, height, 0xFF808080);
|
||||
endFramebuffer(fbo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if(fbo != null)
|
||||
fbo.deleteFramebuffer();
|
||||
}
|
||||
|
||||
public void setSize(int w, int h) {
|
||||
width = w;
|
||||
height = h;
|
||||
createFBO();
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
createFBO();
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
createFBO();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void updateContent() {
|
||||
contentH = content.size() * 12 + 4;
|
||||
|
||||
int h2 = height - 2;
|
||||
if(contentH <= h2) {
|
||||
scrollSize = h2;
|
||||
scrollPos = 0;
|
||||
} else {
|
||||
scrollSize = h2 * h2 / contentH;
|
||||
|
||||
if(scrollSize < 4)
|
||||
scrollSize = 4;
|
||||
}
|
||||
|
||||
update = true;
|
||||
}
|
||||
|
||||
public int addElement(String str) {
|
||||
return addElement(str, null);
|
||||
}
|
||||
|
||||
public int addElement(String str, Object ud) {
|
||||
content.add(new Entry(str, ud));
|
||||
updateContent();
|
||||
return content.size() - 1;
|
||||
}
|
||||
|
||||
public int addElementRaw(String str) {
|
||||
return addElement(str, null);
|
||||
}
|
||||
|
||||
public int addElementRaw(String str, Object ud) {
|
||||
content.add(new Entry(str, ud));
|
||||
return content.size() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisabled(boolean dis) {
|
||||
disabled = dis;
|
||||
|
||||
if(dis) {
|
||||
selected = -1;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
disabled = true;
|
||||
selected = -1;
|
||||
update = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMove(int mouseX, int mouseY) {
|
||||
int sel = -1;
|
||||
if(!disabled && mouseX >= x + 1 && mouseX <= x + width - 6 && mouseY >= y + 2 && mouseY <= y + height - 2) {
|
||||
int offset = y + 4 - getYOffset();
|
||||
sel = (mouseY - offset) / 12;
|
||||
|
||||
if(sel < 0 || sel >= content.size())
|
||||
sel = -1;
|
||||
}
|
||||
|
||||
if(selected != sel) {
|
||||
selected = sel;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
if(!disabled && mouseButton == 0) {
|
||||
if(isInScrollbar(mouseX, mouseY)) {
|
||||
scrolling = true;
|
||||
scrollGrab = mouseY - (y + 1 + scrollPos);
|
||||
} else if(selected >= 0)
|
||||
parent.actionPerformed(new EntryClick(this));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(int mouseX, int mouseY, int state) {
|
||||
if(!disabled && scrolling)
|
||||
scrolling = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseScroll(int mouseX, int mouseY, int amount) {
|
||||
if(!disabled && !scrolling && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height) {
|
||||
double disp = 12.d * ((double) (height - 2 - scrollSize)) / ((double) (contentH - height));
|
||||
int sp = scrollPos;
|
||||
|
||||
if(amount < 0)
|
||||
sp += (int) disp;
|
||||
else
|
||||
sp -= (int) disp;
|
||||
|
||||
if(sp < 0)
|
||||
sp = 0;
|
||||
else if(sp > height - 2 - scrollSize)
|
||||
sp = height - 2 - scrollSize;
|
||||
|
||||
if(sp != scrollPos) {
|
||||
scrollPos = sp;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
|
||||
if(!disabled && scrolling) {
|
||||
int sp = mouseY - scrollGrab - y - 1;
|
||||
if(sp < 0)
|
||||
sp = 0;
|
||||
else if(sp > height - 2 - scrollSize)
|
||||
sp = height - 2 - scrollSize;
|
||||
|
||||
if(scrollPos != sp) {
|
||||
scrollPos = sp;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mouseX, int mouseY, float ptt) {
|
||||
if(visible) {
|
||||
if(update) {
|
||||
renderToFBO();
|
||||
update = false;
|
||||
}
|
||||
|
||||
fbo.bindFramebufferTexture();
|
||||
glColor4f(1.f, 1.f, 1.f, 1.f);
|
||||
fillTexturedRect(x, y, width, height, 0.0, 1.0, 1.0, 0.0);
|
||||
fbo.unbindFramebufferTexture();
|
||||
|
||||
fillRect(x + width - 5, y + 1 + scrollPos, 4, scrollSize, (scrolling || isInScrollbar(mouseX, mouseY)) ? 0xFF202020 : 0xFF404040);
|
||||
}
|
||||
}
|
||||
|
||||
public String getEntryLabel(int id) {
|
||||
return content.get(id).text;
|
||||
}
|
||||
|
||||
public Object getEntryUserdata(int id) {
|
||||
return content.get(id).userdata;
|
||||
}
|
||||
|
||||
public int findEntryByLabel(String label) {
|
||||
for(int i = 0; i < content.size(); i++) {
|
||||
if(content.get(i).text.equals(label))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int findEntryByUserdata(Object o) {
|
||||
if(o == null) {
|
||||
for(int i = 0; i < content.size(); i++) {
|
||||
if(content.get(i).userdata == null)
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < content.size(); i++) {
|
||||
if(content.get(i).userdata != null && content.get(i).userdata.equals(o))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void setSelectionColor(int selColor) {
|
||||
this.selColor = selColor;
|
||||
}
|
||||
|
||||
public int getSelectionColor() {
|
||||
return selColor;
|
||||
}
|
||||
|
||||
public int getElementCount() {
|
||||
return content.size();
|
||||
}
|
||||
|
||||
public void removeElement(int id) {
|
||||
if(selected != -1 && id == content.size() - 1)
|
||||
selected = -1;
|
||||
|
||||
content.remove(id);
|
||||
updateContent();
|
||||
}
|
||||
|
||||
public void removeElementRaw(int id) {
|
||||
if(selected != -1 && id == content.size() - 1)
|
||||
selected = -1;
|
||||
|
||||
content.remove(id);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
content.clear();
|
||||
scrollPos = 0;
|
||||
scrolling = false;
|
||||
scrollSize = height - 2;
|
||||
selected = -1;
|
||||
update = true;
|
||||
}
|
||||
|
||||
public void clearRaw() {
|
||||
content.clear();
|
||||
scrollPos = 0;
|
||||
scrolling = false;
|
||||
selected = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
width = json.getInt("width", 100);
|
||||
height = json.getInt("height", 100);
|
||||
selColor = json.getColor("selectionColor", 0xFF0080FF);
|
||||
createFBO();
|
||||
}
|
||||
|
||||
}
|
307
src/main/java/net/montoyo/wd/client/gui/controls/TextField.java
Normal file
307
src/main/java/net/montoyo/wd/client/gui/controls/TextField.java
Normal file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.minecraft.client.gui.GuiTextField;
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class TextField extends Control {
|
||||
|
||||
public static class EnterPressedEvent extends Event<TextField> {
|
||||
|
||||
private final String text;
|
||||
|
||||
private EnterPressedEvent(TextField field) {
|
||||
source = field;
|
||||
text = field.field.getText();
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TabPressedEvent extends Event<TextField> {
|
||||
|
||||
private final String beginning;
|
||||
|
||||
private TabPressedEvent(TextField field) {
|
||||
source = field;
|
||||
|
||||
String text = field.field.getText();
|
||||
int max = field.field.getCursorPosition();
|
||||
int spacePos = 0;
|
||||
|
||||
for(int i = max - 1; i >= 0; i--) {
|
||||
if(Character.isSpaceChar(text.charAt(i))) {
|
||||
spacePos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
beginning = text.substring(spacePos, max).trim();
|
||||
}
|
||||
|
||||
public String getBeginning() {
|
||||
return beginning;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TextChangedEvent extends Event<TextField> {
|
||||
|
||||
private final String oldContent;
|
||||
private final String newContent;
|
||||
|
||||
private TextChangedEvent(TextField tf, String old) {
|
||||
source = tf;
|
||||
oldContent = old;
|
||||
newContent = tf.field.getText();
|
||||
}
|
||||
|
||||
public String getOldContent() {
|
||||
return oldContent;
|
||||
}
|
||||
|
||||
public String getNewContent() {
|
||||
return newContent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface TextChangeListener {
|
||||
|
||||
void onTextChange(TextField tf, String oldContent, String newContent);
|
||||
|
||||
}
|
||||
|
||||
public static final int DEFAULT_TEXT_COLOR = 14737632;
|
||||
public static final int DEFAULT_DISABLED_COLOR = 7368816;
|
||||
|
||||
private final GuiTextField field;
|
||||
private boolean enabled = true;
|
||||
private int textColor = DEFAULT_TEXT_COLOR;
|
||||
private int disabledColor = DEFAULT_DISABLED_COLOR;
|
||||
private final ArrayList<TextChangeListener> listeners = new ArrayList<>();
|
||||
|
||||
public TextField() {
|
||||
field = new GuiTextField(0, font, 1, 1, 198, 20);
|
||||
}
|
||||
|
||||
public TextField(int x, int y, int width, int height) {
|
||||
field = new GuiTextField(0, font, x + 1, y + 1, width - 2, height - 2);
|
||||
}
|
||||
|
||||
public TextField(int x, int y, int width, int height, String text) {
|
||||
field = new GuiTextField(0, font, x + 1, y + 1, width - 2, height - 2);
|
||||
field.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(char typedChar, int keyCode) {
|
||||
if(keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER)
|
||||
parent.actionPerformed(new EnterPressedEvent(this));
|
||||
else if(keyCode == Keyboard.KEY_TAB)
|
||||
parent.actionPerformed(new TabPressedEvent(this));
|
||||
else {
|
||||
String old;
|
||||
if(enabled && field.isFocused())
|
||||
old = field.getText();
|
||||
else
|
||||
old = null;
|
||||
|
||||
field.textboxKeyTyped(typedChar, keyCode);
|
||||
|
||||
if(enabled && field.isFocused() && !field.getText().equals(old)) {
|
||||
for(TextChangeListener tcl : listeners)
|
||||
tcl.onTextChange(this, old, field.getText());
|
||||
|
||||
parent.actionPerformed(new TextChangedEvent(this, old));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
field.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mouseX, int mouseY, float ptt) {
|
||||
field.drawTextBox();
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
String old = field.getText();
|
||||
field.setText(text);
|
||||
|
||||
if(!old.equals(text)) {
|
||||
for(TextChangeListener tcl : listeners)
|
||||
tcl.onTextChange(this, old, text);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
field.setText("");
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return field.getText();
|
||||
}
|
||||
|
||||
public String getSelectedText() {
|
||||
return field.getSelectedText();
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
field.width = width - 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return field.width + 2;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
field.height = height - 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return field.height + 2;
|
||||
}
|
||||
|
||||
public void setSize(int w, int h) {
|
||||
field.width = w - 2;
|
||||
field.height = h - 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPos(int x, int y) {
|
||||
field.x = x + 1;
|
||||
field.y = y + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return field.x - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return field.y - 1;
|
||||
}
|
||||
|
||||
public void setDisabled(boolean en) {
|
||||
enabled = !en;
|
||||
field.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public boolean isDisabled() {
|
||||
return !enabled;
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
field.setEnabled(true);
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
field.setEnabled(false);
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
public void setVisible(boolean vi) {
|
||||
field.setVisible(vi);
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return field.getVisible();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
field.setVisible(true);
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
field.setVisible(false);
|
||||
}
|
||||
|
||||
public void setFocused(boolean val) {
|
||||
field.setFocused(val);
|
||||
}
|
||||
|
||||
public boolean hasFocus() {
|
||||
return field.isFocused();
|
||||
}
|
||||
|
||||
public void focus() {
|
||||
field.setFocused(true);
|
||||
}
|
||||
|
||||
public void setMaxLength(int len) {
|
||||
field.setMaxStringLength(len);
|
||||
}
|
||||
|
||||
public int getMaxLength() {
|
||||
return field.getMaxStringLength();
|
||||
}
|
||||
|
||||
public void setTextColor(int color) {
|
||||
field.setTextColor(color);
|
||||
textColor = color;
|
||||
}
|
||||
|
||||
public int getTextColor() {
|
||||
return textColor;
|
||||
}
|
||||
|
||||
public void setDisabledTextColor(int color) {
|
||||
field.setDisabledTextColour(color);
|
||||
disabledColor = color;
|
||||
}
|
||||
|
||||
public int getDisabledTextColor() {
|
||||
return disabledColor;
|
||||
}
|
||||
|
||||
public GuiTextField getMcField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public void addTextChangeListener(TextChangeListener l) {
|
||||
if(l != null && !listeners.contains(l))
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
public void removeTextChangeListener(TextChangeListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
field.x = json.getInt("x", 0) + 1;
|
||||
field.y = json.getInt("y", 0) + 1;
|
||||
field.width = json.getInt("width", 200) - 2;
|
||||
field.height = json.getInt("height", 22) - 2;
|
||||
field.setText(tr(json.getString("text", "")));
|
||||
field.setVisible(json.getBool("visible", true));
|
||||
field.setMaxStringLength(json.getInt("maxLength", 32));
|
||||
|
||||
enabled = !json.getBool("disabled", false);
|
||||
textColor = json.getColor("textColor", DEFAULT_TEXT_COLOR);
|
||||
disabledColor = json.getColor("disabledColor", DEFAULT_DISABLED_COLOR);
|
||||
|
||||
field.setTextColor(textColor);
|
||||
field.setDisabledTextColour(disabledColor);
|
||||
field.setEnabled(enabled);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.RenderItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class UpgradeGroup extends BasicControl {
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
private ArrayList<ItemStack> upgrades;
|
||||
private ItemStack overStack;
|
||||
private ItemStack clickStack;
|
||||
private final RenderItem renderItem = Minecraft.getMinecraft().getRenderItem();
|
||||
|
||||
public UpgradeGroup() {
|
||||
parent.requirePostDraw(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mouseX, int mouseY, float ptt) {
|
||||
if(upgrades != null) {
|
||||
int x = this.x;
|
||||
|
||||
for(ItemStack is: upgrades) {
|
||||
if(is == overStack && !disabled)
|
||||
fillRect(x, y, 16, 16, 0x80FF0000);
|
||||
|
||||
renderItem.renderItemAndEffectIntoGUI(mc.player, is, x, y);
|
||||
renderItem.renderItemOverlayIntoGUI(font, is, x, y, null);
|
||||
x += 18;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDraw(int mouseX, int mouseY, float ptt) {
|
||||
if(overStack != null)
|
||||
parent.drawItemStackTooltip(overStack, mouseX, mouseY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setWidth(int w) {
|
||||
width = w;
|
||||
}
|
||||
|
||||
public void setHeight(int h) {
|
||||
height = h;
|
||||
}
|
||||
|
||||
public void setUpgrades(ArrayList<ItemStack> upgrades) {
|
||||
this.upgrades = upgrades;
|
||||
}
|
||||
|
||||
public ArrayList<ItemStack> getUpgrades() {
|
||||
return upgrades;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
width = json.getInt("width", 0);
|
||||
height = json.getInt("height", 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMove(int mouseX, int mouseY) {
|
||||
if(upgrades != null) {
|
||||
overStack = null;
|
||||
|
||||
if(mouseY >= y && mouseY <= y + 16 && mouseX >= x) {
|
||||
mouseX -= x;
|
||||
int sel = mouseX / 18;
|
||||
|
||||
if(sel < upgrades.size() && mouseX % 18 <= 16)
|
||||
overStack = upgrades.get(sel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
if(mouseButton == 0)
|
||||
clickStack = overStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(int mouseX, int mouseY, int state) {
|
||||
if(state == 0 && clickStack != null) {
|
||||
if(clickStack == overStack && !disabled && upgrades.contains(clickStack)) //HOTFIX: Make sure it's actually in the list :p
|
||||
parent.actionPerformed(new ClickEvent(this));
|
||||
|
||||
clickStack = null;
|
||||
}
|
||||
}
|
||||
|
||||
public ItemStack getMouseOverUpgrade() {
|
||||
return overStack;
|
||||
}
|
||||
|
||||
public static class ClickEvent extends Event<UpgradeGroup> {
|
||||
|
||||
private final ItemStack clickStack;
|
||||
|
||||
private ClickEvent(UpgradeGroup src) {
|
||||
source = src;
|
||||
clickStack = src.clickStack;
|
||||
}
|
||||
|
||||
public ItemStack getMouseOverStack() {
|
||||
return clickStack;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.controls;
|
||||
|
||||
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||
import net.montoyo.wd.utilities.Util;
|
||||
import net.montoyo.wd.utilities.VideoType;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public class YTButton extends Button implements TextField.TextChangeListener {
|
||||
|
||||
private TextField urlField;
|
||||
|
||||
public YTButton() {
|
||||
btn.displayString = "YT";
|
||||
btn.enabled = false;
|
||||
shiftColor = 0xFFFF6464;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onClick() {
|
||||
if(urlField != null) {
|
||||
String urlStr = Util.addProtocol(urlField.getText());
|
||||
URL url;
|
||||
|
||||
try {
|
||||
url = new URL(urlStr);
|
||||
} catch(MalformedURLException ex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
VideoType vt = VideoType.getTypeFromURL(url);
|
||||
if(vt == VideoType.YOUTUBE)
|
||||
urlField.setText(VideoType.YOUTUBE_EMBED.getURLFromID(vt.getVideoIDFromURL(url), shiftDown));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setURLField(TextField tf) {
|
||||
if(urlField != null)
|
||||
tf.removeTextChangeListener(this);
|
||||
|
||||
urlField = tf;
|
||||
|
||||
if(urlField != null)
|
||||
tf.addTextChangeListener(this);
|
||||
}
|
||||
|
||||
public TextField getURLField() {
|
||||
return urlField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(JsonOWrapper json) {
|
||||
super.load(json);
|
||||
|
||||
String tfName = json.getString("urlField", null);
|
||||
if(tfName != null) {
|
||||
Control ctrl = parent.getControlByName(tfName);
|
||||
|
||||
if(ctrl != null && ctrl instanceof TextField) {
|
||||
urlField = (TextField) ctrl;
|
||||
urlField.addTextChangeListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChange(TextField tf, String oldContent, String newContent) {
|
||||
btn.enabled = (VideoType.getTypeFromURL(Util.addProtocol(newContent)) == VideoType.YOUTUBE);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.loading;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface FillControl {
|
||||
|
||||
String name() default "";
|
||||
boolean required() default true;
|
||||
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.loading;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.montoyo.wd.client.gui.controls.*;
|
||||
import net.montoyo.wd.utilities.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class GuiLoader {
|
||||
|
||||
private static final HashMap<String, Class<? extends Control>> CONTROLS = new HashMap<>();
|
||||
private static final HashMap<ResourceLocation, JsonObject> RESOURCES = new HashMap<>();
|
||||
|
||||
public static void register(Class<? extends Control> cls) {
|
||||
if(Modifier.isAbstract(cls.getModifiers()))
|
||||
throw new RuntimeException("GG retard, you just registered an abstract class...");
|
||||
|
||||
String name = cls.getSimpleName();
|
||||
if(CONTROLS.containsKey(name))
|
||||
throw new RuntimeException("Control class already registered or name taken!");
|
||||
|
||||
CONTROLS.put(name, cls);
|
||||
}
|
||||
|
||||
static {
|
||||
register(Button.class);
|
||||
register(CheckBox.class);
|
||||
register(ControlGroup.class);
|
||||
register(Label.class);
|
||||
register(List.class);
|
||||
register(TextField.class);
|
||||
register(Icon.class);
|
||||
register(UpgradeGroup.class);
|
||||
register(YTButton.class);
|
||||
}
|
||||
|
||||
public static Control create(JsonOWrapper json) {
|
||||
Control ret;
|
||||
|
||||
try {
|
||||
ret = CONTROLS.get(json.getString("type", null)).newInstance();
|
||||
} catch(InstantiationException e) {
|
||||
Log.errorEx("Could not create control from JSON: instantiation exception", e);
|
||||
throw new RuntimeException(e);
|
||||
} catch(IllegalAccessException e) {
|
||||
Log.errorEx("Could not create control from JSON: access denied", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
ret.load(json);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static JsonObject getJson(ResourceLocation resLoc) {
|
||||
JsonObject ret = RESOURCES.get(resLoc);
|
||||
if(ret == null) {
|
||||
IResource resource;
|
||||
|
||||
try {
|
||||
resource = Minecraft.getMinecraft().getResourceManager().getResource(resLoc);
|
||||
} catch(IOException e) {
|
||||
Log.errorEx("Couldn't load JSON UI from file", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
JsonParser parser = new JsonParser();
|
||||
ret = parser.parse(new InputStreamReader(resource.getInputStream())).getAsJsonObject();
|
||||
|
||||
try {
|
||||
resource.close();
|
||||
} catch(IOException e) {}
|
||||
|
||||
RESOURCES.put(resLoc, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
RESOURCES.clear();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.loading;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class JsonAWrapper {
|
||||
|
||||
private final JsonArray array;
|
||||
private final Map<String, Double> variables;
|
||||
|
||||
public JsonAWrapper(JsonArray a, Map<String, Double> vars) {
|
||||
array = a;
|
||||
variables = vars;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
public String getString(int i) {
|
||||
return array.get(i).getAsString();
|
||||
}
|
||||
|
||||
public int getInt(int i) {
|
||||
return array.get(i).getAsInt();
|
||||
}
|
||||
|
||||
public long getLong(int i) {
|
||||
return array.get(i).getAsLong();
|
||||
}
|
||||
|
||||
public float getFloat(int i) {
|
||||
return array.get(i).getAsFloat();
|
||||
}
|
||||
|
||||
public double getDouble(int i) {
|
||||
return array.get(i).getAsDouble();
|
||||
}
|
||||
|
||||
public boolean getBool(int i) {
|
||||
return array.get(i).getAsBoolean();
|
||||
}
|
||||
|
||||
public JsonOWrapper getObject(int i) {
|
||||
return new JsonOWrapper(array.get(i).getAsJsonObject(), variables);
|
||||
}
|
||||
|
||||
public JsonAWrapper getArray(int i) {
|
||||
return new JsonAWrapper(array.get(i).getAsJsonArray(), variables);
|
||||
}
|
||||
|
||||
public JsonArray getArray() {
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.gui.loading;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import net.montoyo.wd.client.gui.controls.Control;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class JsonOWrapper {
|
||||
|
||||
private static final HashMap<String, Integer> defaultColors = new HashMap<>();
|
||||
static {
|
||||
defaultColors.put("black", Control.COLOR_BLACK);
|
||||
defaultColors.put("white", Control.COLOR_WHITE);
|
||||
defaultColors.put("red", Control.COLOR_RED);
|
||||
defaultColors.put("green", Control.COLOR_GREEN);
|
||||
defaultColors.put("blue", Control.COLOR_BLUE);
|
||||
defaultColors.put("magenta", Control.COLOR_MANGENTA);
|
||||
defaultColors.put("cyan", Control.COLOR_CYAN);
|
||||
defaultColors.put("yellow", Control.COLOR_YELLOW);
|
||||
}
|
||||
|
||||
private final JsonObject object;
|
||||
private final Map<String, Double> variables;
|
||||
|
||||
public JsonOWrapper(JsonObject obj, Map<String, Double> vars) {
|
||||
object = obj;
|
||||
variables = vars;
|
||||
}
|
||||
|
||||
public String getString(String key, String def) {
|
||||
return object.has(key) ? object.get(key).getAsString() : def;
|
||||
}
|
||||
|
||||
public long getLong(String key, long def) {
|
||||
return object.has(key) ? object.get(key).getAsLong() : def;
|
||||
}
|
||||
|
||||
public int getInt(String key, int def) {
|
||||
if(!object.has(key))
|
||||
return def;
|
||||
|
||||
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
|
||||
if(prim.isNumber())
|
||||
return prim.getAsInt();
|
||||
|
||||
return (int) evalExpr(prim.getAsString(), variables);
|
||||
}
|
||||
|
||||
public float getFloat(String key, float def) {
|
||||
if(!object.has(key))
|
||||
return def;
|
||||
|
||||
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
|
||||
if(prim.isNumber())
|
||||
return prim.getAsFloat();
|
||||
|
||||
return (float) evalExpr(prim.getAsString(), variables);
|
||||
}
|
||||
|
||||
public double getDouble(String key, double def) {
|
||||
if(!object.has(key))
|
||||
return def;
|
||||
|
||||
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
|
||||
if(prim.isNumber())
|
||||
return prim.getAsDouble();
|
||||
|
||||
return evalExpr(prim.getAsString(), variables);
|
||||
}
|
||||
|
||||
public boolean getBool(String key, boolean def) {
|
||||
if(!object.has(key))
|
||||
return def;
|
||||
|
||||
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
|
||||
if(prim.isBoolean())
|
||||
return prim.getAsBoolean();
|
||||
else if(prim.isNumber())
|
||||
return prim.getAsInt() != 0;
|
||||
|
||||
return evalExpr(prim.getAsString(), variables) != 0.0;
|
||||
}
|
||||
|
||||
public JsonOWrapper getObject(String key) {
|
||||
return new JsonOWrapper(object.has(key) ? object.get(key).getAsJsonObject() : (new JsonObject()), variables);
|
||||
}
|
||||
|
||||
public JsonAWrapper getArray(String key) {
|
||||
return new JsonAWrapper(object.has(key) ? object.get(key).getAsJsonArray() : (new JsonArray()), variables);
|
||||
}
|
||||
|
||||
public JsonObject getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
public int getColor(String key, int def) {
|
||||
if(!object.has(key))
|
||||
return def;
|
||||
|
||||
JsonElement c = object.get(key);
|
||||
if(c.isJsonPrimitive()) {
|
||||
JsonPrimitive prim = c.getAsJsonPrimitive();
|
||||
|
||||
if(prim.isNumber())
|
||||
return (int) prim.getAsLong();
|
||||
else if(prim.isString()) {
|
||||
String str = prim.getAsString();
|
||||
Integer dc = defaultColors.get(str.toLowerCase());
|
||||
if(dc != null)
|
||||
return dc;
|
||||
|
||||
if(!str.isEmpty() && str.charAt(0) == '#')
|
||||
str = str.substring(1);
|
||||
|
||||
long ret = Long.parseLong(str, 16);
|
||||
if(str.length() <= 6)
|
||||
ret |= 0xFF000000L;
|
||||
|
||||
return (int) ret;
|
||||
} else
|
||||
return def;
|
||||
}
|
||||
|
||||
int r, g, b, a;
|
||||
if(c.isJsonArray()) {
|
||||
JsonArray array = c.getAsJsonArray();
|
||||
|
||||
r = array.get(0).getAsInt();
|
||||
g = array.get(1).getAsInt();
|
||||
b = array.get(2).getAsInt();
|
||||
a = (array.size() >= 4) ? array.get(3).getAsInt() : 255;
|
||||
} else if(c.isJsonObject()) {
|
||||
JsonObject obj = c.getAsJsonObject();
|
||||
|
||||
r = obj.get("r").getAsInt();
|
||||
g = obj.get("g").getAsInt();
|
||||
b = obj.get("b").getAsInt();
|
||||
a = obj.has("a") ? obj.get("a").getAsInt() : 255;
|
||||
} else
|
||||
return def;
|
||||
|
||||
return (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
private static final String OPS = "+*/%&|"; //The - sign is an exception, don't add it here
|
||||
private static final String[] OPS_PRIORITY = new String[] { "*/%", "+-", "&|" };
|
||||
|
||||
private static class VarOpPair {
|
||||
double var;
|
||||
char op;
|
||||
|
||||
void setVar(String str, boolean isNumber, String expr, Map<String, Double> variables) {
|
||||
if(isNumber)
|
||||
var = Double.parseDouble(str);
|
||||
else {
|
||||
boolean neg = (str.charAt(0) == '-');
|
||||
String varName = neg ? str.substring(1) : str;
|
||||
Double d = variables.get(varName);
|
||||
|
||||
if(d == null)
|
||||
throw new RuntimeException("Unknown variable \"" + varName + "\" in expression \"" + expr + "\"");
|
||||
|
||||
var = neg ? -d : d;
|
||||
}
|
||||
}
|
||||
|
||||
void setOp(char op) {
|
||||
this.op = op;
|
||||
}
|
||||
}
|
||||
|
||||
private static int findPair(List<VarOpPair> list, String ops) {
|
||||
for(int i = 0; i < list.size(); i++) {
|
||||
if(ops.indexOf(list.get(i).op) >= 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static double evalExpr(String expr, Map<String, Double> variables) {
|
||||
//Apply parenthesis
|
||||
while(true) {
|
||||
int pos = expr.indexOf('(');
|
||||
if(pos < 0)
|
||||
break;
|
||||
|
||||
int end = ++pos;
|
||||
int lvl = 0;
|
||||
|
||||
for(; end < expr.length(); end++) {
|
||||
char chr = expr.charAt(end);
|
||||
|
||||
if(chr == '(')
|
||||
lvl++;
|
||||
else if(chr == ')') {
|
||||
if(lvl == 0)
|
||||
break;
|
||||
|
||||
lvl--;
|
||||
}
|
||||
}
|
||||
|
||||
if(end >= expr.length())
|
||||
throw new RuntimeException("Unclosed parenthesis in expression \"" + expr + "\"");
|
||||
|
||||
double val = evalExpr(expr.substring(pos, end), variables);
|
||||
expr = expr.substring(0, pos - 1) + val + expr.substring(end + 1);
|
||||
}
|
||||
|
||||
//Parse into ops
|
||||
ArrayList<VarOpPair> ops = new ArrayList<>();
|
||||
StringBuilder str = new StringBuilder();
|
||||
boolean negIsPartOfStr = true;
|
||||
boolean strIsNumber = true;
|
||||
|
||||
for(int i = 0; i < expr.length(); i++) {
|
||||
char chr = expr.charAt(i);
|
||||
if(Character.isSpaceChar(chr))
|
||||
continue;
|
||||
|
||||
if((chr == '-' && !negIsPartOfStr) || OPS.indexOf(chr) >= 0) {
|
||||
//Parse
|
||||
VarOpPair pair = new VarOpPair();
|
||||
pair.setVar(str.toString(), strIsNumber, expr, variables);
|
||||
pair.setOp(chr);
|
||||
ops.add(pair);
|
||||
|
||||
//Reset
|
||||
str.setLength(0);
|
||||
negIsPartOfStr = true;
|
||||
strIsNumber = true;
|
||||
} else {
|
||||
if(strIsNumber && chr != '-' && chr != '.' && !Character.isDigit(chr))
|
||||
strIsNumber = false;
|
||||
|
||||
if(negIsPartOfStr)
|
||||
negIsPartOfStr = false;
|
||||
|
||||
str.append(chr);
|
||||
}
|
||||
}
|
||||
|
||||
if(str.length() > 0) {
|
||||
VarOpPair pair = new VarOpPair();
|
||||
pair.setVar(str.toString(), strIsNumber, expr, variables);
|
||||
pair.setOp((char) 0);
|
||||
ops.add(pair);
|
||||
}
|
||||
|
||||
//Compute
|
||||
while(true) {
|
||||
int pairId = -1;
|
||||
for(String opList : OPS_PRIORITY) {
|
||||
pairId = findPair(ops, opList);
|
||||
|
||||
if(pairId >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(pairId < 0)
|
||||
break;
|
||||
|
||||
VarOpPair a = ops.get(pairId);
|
||||
VarOpPair b = ops.get(pairId + 1);
|
||||
|
||||
if(a.op == '*')
|
||||
b.var = a.var * b.var;
|
||||
else if(a.op == '/')
|
||||
b.var = a.var / b.var;
|
||||
else if(a.op == '%')
|
||||
b.var = a.var % b.var;
|
||||
else if(a.op == '+')
|
||||
b.var = a.var + b.var;
|
||||
else if(a.op == '-')
|
||||
b.var = a.var - b.var;
|
||||
else if(a.op == '&') {
|
||||
if(a.var == 0.0)
|
||||
b.var = 0.0;
|
||||
|
||||
//if b.var == 0, b.var stays 0
|
||||
//if a.var != 0, b.var keeps its value
|
||||
} else if(a.op == '|') {
|
||||
if(a.var != 0.0)
|
||||
b.var = a.var;
|
||||
|
||||
//if a.var == 0, b.var keeps its value
|
||||
//if a.var != 0, b.var takes the value of a
|
||||
}
|
||||
|
||||
ops.remove(pairId);
|
||||
}
|
||||
|
||||
//Check
|
||||
if(ops.size() != 1 || ops.get(0).op != (char) 0)
|
||||
throw new RuntimeException("Error while parsing evaluating \"" + expr + "\"");
|
||||
|
||||
return ops.get(0).var;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.renderers;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public interface IItemRenderer {
|
||||
|
||||
void render(ItemStack is, float handSideSign, float swingProgress, float equipProgress);
|
||||
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.renderers;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
|
||||
public interface IModelBaker extends IBakedModel {
|
||||
|
||||
void loadTextures(TextureMap texMap);
|
||||
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.renderers;
|
||||
|
||||
import net.minecraft.client.renderer.*;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.lwjgl.BufferUtils;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public final class LaserPointerRenderer implements IItemRenderer {
|
||||
|
||||
private static final float PI = (float) Math.PI;
|
||||
private final Tessellator t = Tessellator.getInstance();
|
||||
private final BufferBuilder bb = t.getBuffer();
|
||||
private final FloatBuffer matrix1 = BufferUtils.createFloatBuffer(16);
|
||||
private final FloatBuffer renderBuffer = BufferUtils.createFloatBuffer(8);
|
||||
|
||||
public boolean isOn = false;
|
||||
|
||||
public LaserPointerRenderer() {
|
||||
for(int i = 0; i < 8; i++)
|
||||
renderBuffer.put(0.0f);
|
||||
|
||||
renderBuffer.position(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void render(ItemStack is, float handSideSign, float swingProgress, float equipProgress) {
|
||||
//This whole method is a fucking hack
|
||||
float sqrtSwingProg = (float) Math.sqrt((double) swingProgress);
|
||||
float sinSqrtSwingProg1 = MathHelper.sin(sqrtSwingProg * PI);
|
||||
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.enableRescaleNormal();
|
||||
|
||||
//Laser pointer
|
||||
glPushMatrix();
|
||||
glTranslatef(handSideSign * -0.4f * sinSqrtSwingProg1, 0.2f * MathHelper.sin(sqrtSwingProg * PI * 2.0f), -0.2f * MathHelper.sin(swingProgress * PI));
|
||||
glTranslatef(handSideSign * 0.56f, -0.52f - equipProgress * 0.6f, -0.72f);
|
||||
glRotatef(handSideSign * (45.0f - MathHelper.sin(swingProgress * swingProgress * PI) * 20.0f), 0.0f, 1.0f, 0.0f);
|
||||
glRotatef(handSideSign * sinSqrtSwingProg1 * -20.0f, 0.0f, 0.0f, 1.0f);
|
||||
glRotatef(sinSqrtSwingProg1 * -80.0f, 1.0f, 0.0f, 0.0f);
|
||||
glRotatef(handSideSign * -30.0f, 0.0f, 1.0f, 0.0f);
|
||||
glTranslatef(0.0f, 0.2f, 0.0f);
|
||||
glRotatef(10.0f, 1.0f, 0.0f, 0.0f);
|
||||
glScalef(1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f);
|
||||
|
||||
glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
bb.begin(GL_QUADS, DefaultVertexFormats.POSITION_NORMAL);
|
||||
bb.pos(0.0, 0.0, 0.0).normal(0.0f, 1.0f, 0.0f).endVertex();
|
||||
bb.pos(1.0, 0.0, 0.0).normal(0.0f, 1.0f, 0.0f).endVertex();
|
||||
bb.pos(1.0, 0.0, 4.0).normal(0.0f, 1.0f, 0.0f).endVertex();
|
||||
bb.pos(0.0, 0.0, 4.0).normal(0.0f, 1.0f, 0.0f).endVertex();
|
||||
|
||||
bb.pos(0.0, 0.0, 0.0).normal(-1.0f, 0.0f, 0.0f).endVertex();
|
||||
bb.pos(0.0, -1.0, 0.0).normal(-1.0f, 0.0f, 0.0f).endVertex();
|
||||
bb.pos(0.0, -1.0, 4.0).normal(-1.0f, 0.0f, 0.0f).endVertex();
|
||||
bb.pos(0.0, 0.0, 4.0).normal(-1.0f, 0.0f, 0.0f).endVertex();
|
||||
|
||||
bb.pos(1.0, 0.0, 0.0).normal(1.0f, 0.0f, 0.0f).endVertex();
|
||||
bb.pos(1.0, -1.0, 0.0).normal(1.0f, 0.0f, 0.0f).endVertex();
|
||||
bb.pos(1.0, -1.0, 4.0).normal(1.0f, 0.0f, 0.0f).endVertex();
|
||||
bb.pos(1.0, 0.0, 4.0).normal(1.0f, 0.0f, 0.0f).endVertex();
|
||||
|
||||
bb.pos(0.0, -1.0, 4.0).normal(0.0f, 0.0f, 1.0f).endVertex();
|
||||
bb.pos(1.0, -1.0, 4.0).normal(0.0f, 0.0f, 1.0f).endVertex();
|
||||
bb.pos(1.0, 0.0, 4.0).normal(0.0f, 0.0f, 1.0f).endVertex();
|
||||
bb.pos(0.0, 0.0, 4.0).normal(0.0f, 0.0f, 1.0f).endVertex();
|
||||
t.draw();
|
||||
|
||||
if(isOn) {
|
||||
glTranslatef(0.5f, -0.5f, 0.0f);
|
||||
matrix1.position(0);
|
||||
glGetFloat(GL_MODELVIEW_MATRIX, matrix1); //Hax to get that damn position
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
if(isOn) {
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit);
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
|
||||
//Actual laser
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.DST_ALPHA);
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
|
||||
GlStateManager.glLineWidth(3.0f);
|
||||
|
||||
matrix1.position(12);
|
||||
renderBuffer.put(matrix1.get());
|
||||
renderBuffer.put(matrix1.get());
|
||||
renderBuffer.put(matrix1.get() - 0.02f); //I know this is stupid, but it's the only thing that worked...
|
||||
renderBuffer.put(matrix1.get());
|
||||
renderBuffer.position(0);
|
||||
glVertexPointer(4, 0, renderBuffer);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
GlStateManager.enableTexture2D(); //Fix for shitty minecraft fire
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.renderers;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.entity.RenderPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.client.ClientProxy;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.opengl.GL12.GL_RESCALE_NORMAL;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public final class MinePadRenderer implements IItemRenderer {
|
||||
|
||||
private static final float PI = (float) Math.PI;
|
||||
private final Minecraft mc = Minecraft.getMinecraft();
|
||||
private final ResourceLocation tex = new ResourceLocation("webdisplays", "textures/models/minepad.png");
|
||||
private final ModelMinePad model = new ModelMinePad();
|
||||
private final ClientProxy clientProxy = (ClientProxy) WebDisplays.PROXY;
|
||||
|
||||
private float sinSqrtSwingProg1;
|
||||
private float sinSqrtSwingProg2;
|
||||
private float sinSwingProg1;
|
||||
private float sinSwingProg2;
|
||||
|
||||
public static void drawAxis() {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBegin(GL_LINES);
|
||||
glColor4f(1.f, 0.f, 0.f, 1.f); glVertex3d(0.0, 0.0, 0.0);
|
||||
glColor4f(1.f, 0.f, 0.f, 1.f); glVertex3d(5.0, 0.0, 0.0);
|
||||
glColor4f(0.f, 1.f, 0.f, 1.f); glVertex3d(0.0, 0.0, 0.0);
|
||||
glColor4f(0.f, 1.f, 0.f, 1.f); glVertex3d(0.0, 5.0, 0.0);
|
||||
glColor4f(0.f, 0.f, 1.f, 1.f); glVertex3d(0.0, 0.0, 0.0);
|
||||
glColor4f(0.f, 0.f, 1.f, 1.f); glVertex3d(0.0, 0.0, 5.0);
|
||||
glEnd();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void render(ItemStack is, float handSideSign, float swingProgress, float equipProgress) {
|
||||
//Pre-compute values
|
||||
float sqrtSwingProg = (float) Math.sqrt((double) swingProgress);
|
||||
sinSqrtSwingProg1 = MathHelper.sin(sqrtSwingProg * PI);
|
||||
sinSqrtSwingProg2 = MathHelper.sin(sqrtSwingProg * PI * 2.0f);
|
||||
sinSwingProg1 = MathHelper.sin(swingProgress * PI);
|
||||
sinSwingProg2 = MathHelper.sin(swingProgress * swingProgress * PI);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_RESCALE_NORMAL);
|
||||
|
||||
//Render arm
|
||||
glPushMatrix();
|
||||
renderArmFirstPerson(equipProgress, handSideSign);
|
||||
glPopMatrix();
|
||||
|
||||
//Prepare minePad transform
|
||||
glPushMatrix();
|
||||
glTranslatef(handSideSign * -0.4f * sinSqrtSwingProg1, 0.2f * sinSqrtSwingProg2, -0.2f * sinSwingProg1);
|
||||
glTranslatef(handSideSign * 0.56f, -0.52f - equipProgress * 0.6f, -0.72f);
|
||||
glRotatef(handSideSign * (45.0f - sinSwingProg2 * 20.0f), 0.0f, 1.0f, 0.0f);
|
||||
glRotatef(handSideSign * sinSqrtSwingProg1 * -20.0f, 0.0f, 0.0f, 1.0f);
|
||||
glRotatef(sinSqrtSwingProg1 * -80.0f, 1.0f, 0.0f, 0.0f);
|
||||
glRotatef(handSideSign * -45.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
if(handSideSign >= 0.0f)
|
||||
glTranslatef(-1.065f, 0.0f, 0.0f);
|
||||
else {
|
||||
glTranslatef(0.0f, 0.0f, -0.2f);
|
||||
glRotatef(20.0f, 0.0f, 1.0f, 0.0f);
|
||||
glTranslatef(-0.475f, -0.1f, 0.0f);
|
||||
glRotatef(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
//Render model
|
||||
glPushMatrix();
|
||||
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
mc.renderEngine.bindTexture(tex);
|
||||
model.render(1.f / 16.f);
|
||||
glPopMatrix();
|
||||
|
||||
//Render web view
|
||||
if(is.getTagCompound() != null && is.getTagCompound().hasKey("PadID")) {
|
||||
ClientProxy.PadData pd = clientProxy.getPadByID(is.getTagCompound().getInteger("PadID"));
|
||||
|
||||
if(pd != null) {
|
||||
glTranslatef(0.063f, 0.28f, 0.001f);
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
pd.view.draw(0.0, 0.0, 27.65 / 32.0 + 0.01, 14.0 / 32.0 + 0.002);
|
||||
}
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
glDisable(GL_RESCALE_NORMAL);
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
private void renderArmFirstPerson(float equipProgress, float handSideSign) {
|
||||
float tx = -0.3f * sinSqrtSwingProg1;
|
||||
float ty = 0.4f * sinSqrtSwingProg2;
|
||||
float tz = -0.4f * sinSwingProg1;
|
||||
|
||||
glTranslatef(handSideSign * (tx + 0.64000005f), ty - 0.6f - equipProgress * 0.6f, tz - 0.71999997f);
|
||||
glRotatef(handSideSign * 45.0f, 0.0f, 1.0f, 0.0f);
|
||||
glRotatef(handSideSign * sinSqrtSwingProg1 * 70.0f, 0.0f, 1.0f, 0.0f);
|
||||
glRotatef(handSideSign * sinSwingProg2 * -20.0f, 0.0f, 0.0f, 1.0f);
|
||||
glTranslatef(-handSideSign, 3.6f, 3.5f);
|
||||
glRotatef(handSideSign * 120.0f, 0.0f, 0.0f, 1.0f);
|
||||
glRotatef(200.0f, 1.0f, 0.0f, 0.0f);
|
||||
glRotatef(handSideSign * -135.0f, 0.0f, 1.0f, 0.0f);
|
||||
glTranslatef(handSideSign * 5.6f, 0.0f, 0.0f);
|
||||
|
||||
RenderPlayer playerRenderer = (RenderPlayer) mc.getRenderManager().<AbstractClientPlayer>getEntityRenderObject(mc.player);
|
||||
mc.getTextureManager().bindTexture(mc.player.getLocationSkin());
|
||||
|
||||
if(handSideSign >= 0.0f)
|
||||
playerRenderer.renderRightArm(mc.player);
|
||||
else
|
||||
playerRenderer.renderLeftArm(mc.player);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.renderers;
|
||||
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public final class ModelMinePad extends ModelBase {
|
||||
|
||||
// fields
|
||||
private final ModelRenderer base;
|
||||
private final ModelRenderer left;
|
||||
private final ModelRenderer right;
|
||||
|
||||
public ModelMinePad() {
|
||||
textureWidth = 64;
|
||||
textureHeight = 32;
|
||||
|
||||
base = new ModelRenderer(this, 0, 0);
|
||||
base.addBox(0F, 0F, 0F, 14, 1, 9);
|
||||
base.setRotationPoint(1F, 0F, 3.5F);
|
||||
base.setTextureSize(64, 32);
|
||||
base.mirror = true;
|
||||
clearRotation(base);
|
||||
left = new ModelRenderer(this, 0, 10);
|
||||
left.addBox(0F, 0F, 0F, 1, 1, 7);
|
||||
left.setRotationPoint(0F, 0F, 4.5F);
|
||||
left.setTextureSize(64, 32);
|
||||
left.mirror = true;
|
||||
clearRotation(left);
|
||||
right = new ModelRenderer(this, 30, 10);
|
||||
right.addBox(0F, 0F, 0F, 1, 1, 7);
|
||||
right.setRotationPoint(15F, 0F, 4.5F);
|
||||
right.setTextureSize(64, 32);
|
||||
right.mirror = true;
|
||||
clearRotation(right);
|
||||
}
|
||||
|
||||
public final void render(float f5) {
|
||||
base.render(f5);
|
||||
left.render(f5);
|
||||
right.render(f5);
|
||||
}
|
||||
|
||||
private void clearRotation(ModelRenderer model) {
|
||||
model.rotateAngleX = 0.0f;
|
||||
model.rotateAngleY = 0.0f;
|
||||
model.rotateAngleZ = 0.0f;
|
||||
}
|
||||
|
||||
}
|
144
src/main/java/net/montoyo/wd/client/renderers/ScreenBaker.java
Normal file
144
src/main/java/net/montoyo/wd/client/renderers/ScreenBaker.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.renderers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.property.IExtendedBlockState;
|
||||
import net.montoyo.wd.block.BlockScreen;
|
||||
import net.montoyo.wd.utilities.BlockSide;
|
||||
import net.montoyo.wd.utilities.Vector3f;
|
||||
import net.montoyo.wd.utilities.Vector3i;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ScreenBaker implements IModelBaker {
|
||||
|
||||
private static final List<BakedQuad> noQuads = ImmutableList.of();
|
||||
private final TextureAtlasSprite[] texs = new TextureAtlasSprite[16];
|
||||
private final BlockSide[] blockSides = BlockSide.values();
|
||||
private final EnumFacing[] blockFacings = EnumFacing.values();
|
||||
|
||||
@Override
|
||||
public void loadTextures(TextureMap texMap) {
|
||||
for(int i = 0; i < texs.length; i++)
|
||||
texs[i] = texMap.registerSprite(new ResourceLocation("webdisplays", "blocks/screen" + i));
|
||||
}
|
||||
|
||||
private void putVertex(int[] buf, int pos, Vector3f vpos, TextureAtlasSprite tex, Vector3f uv, Vector3i normal) {
|
||||
buf[pos * 7 + 0] = Float.floatToRawIntBits(vpos.x);
|
||||
buf[pos * 7 + 1] = Float.floatToRawIntBits(vpos.y);
|
||||
buf[pos * 7 + 2] = Float.floatToRawIntBits(vpos.z);
|
||||
buf[pos * 7 + 3] = 0xFFFFFFFF; //Color, let this white...
|
||||
buf[pos * 7 + 4] = Float.floatToRawIntBits(tex.getInterpolatedU(uv.x));
|
||||
buf[pos * 7 + 5] = Float.floatToRawIntBits(tex.getInterpolatedV(uv.y));
|
||||
|
||||
int nx = (normal.x * 127) & 0xFF;
|
||||
int ny = (normal.y * 127) & 0xFF;
|
||||
int nz = (normal.z * 127) & 0xFF;
|
||||
buf[pos * 7 + 6] = nx | (ny << 8) | (nz << 16);
|
||||
}
|
||||
|
||||
private Vector3f rotateVec(Vector3f vec, BlockSide side) {
|
||||
switch(side) {
|
||||
case BOTTOM: return new Vector3f(vec.x, 1.0f, 1.0f - vec.z);
|
||||
case TOP: return new Vector3f(vec.x, 0.0f, vec.z);
|
||||
case NORTH: return new Vector3f(vec.x, vec.z, 1.0f);
|
||||
case SOUTH: return new Vector3f(vec.x, 1.0f - vec.z, 0.0f);
|
||||
case WEST: return new Vector3f(1.f , vec.x, vec.z);
|
||||
case EAST: return new Vector3f(0.0f, 1.0f - vec.x, vec.z);
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unknown block side " + side);
|
||||
}
|
||||
|
||||
private Vector3f rotateTex(BlockSide side, float u, float v) {
|
||||
switch(side) {
|
||||
case BOTTOM: return new Vector3f(u, 16.f - v, 0.0f);
|
||||
case TOP: return new Vector3f(u, v, 0.0f);
|
||||
case NORTH: return new Vector3f(16.f - u, 16.f - v, 0.0f);
|
||||
case SOUTH: return new Vector3f(u, v, 0.0f);
|
||||
case WEST: return new Vector3f(v, 16.f - u, 0.0f);
|
||||
case EAST: return new Vector3f(16.f - v, u, 0.0f);
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unknown block side " + side);
|
||||
}
|
||||
|
||||
private BakedQuad bakeSide(BlockSide side, TextureAtlasSprite tex) {
|
||||
int[] data = new int[7 * 4];
|
||||
|
||||
putVertex(data, 3, rotateVec(new Vector3f(0.0f, 0.0f, 0.0f), side), tex, rotateTex(side, 0.0f, 0.0f ), side.backward);
|
||||
putVertex(data, 2, rotateVec(new Vector3f(0.0f, 0.0f, 1.0f), side), tex, rotateTex(side, 0.0f, 16.0f ), side.backward);
|
||||
putVertex(data, 1, rotateVec(new Vector3f(1.0f, 0.0f, 1.0f), side), tex, rotateTex(side, 16.0f, 16.0f), side.backward);
|
||||
putVertex(data, 0, rotateVec(new Vector3f(1.0f, 0.0f, 0.0f), side), tex, rotateTex(side, 16.0f, 0.0f ), side.backward);
|
||||
|
||||
return new BakedQuad(data, 0xFFFFFFFF, blockFacings[side.ordinal()], tex, true, DefaultVertexFormats.ITEM);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) {
|
||||
if(side == null)
|
||||
return noQuads;
|
||||
|
||||
IExtendedBlockState bs = (IExtendedBlockState) state;
|
||||
List<BakedQuad> ret = new ArrayList<>();
|
||||
|
||||
int sid = BlockSide.reverse(side.ordinal());
|
||||
BlockSide s = blockSides[sid];
|
||||
TextureAtlasSprite tex = texs[15];
|
||||
if(bs != null)
|
||||
tex = texs[bs.getValue(BlockScreen.sideFlags[sid])];
|
||||
|
||||
ret.add(bakeSide(s, tex));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public TextureAtlasSprite getParticleTexture() {
|
||||
return texs[15];
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public ItemCameraTransforms getItemCameraTransforms() {
|
||||
return ItemCameraTransforms.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public ItemOverrideList getOverrides() {
|
||||
return ItemOverrideList.NONE;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||
*/
|
||||
|
||||
package net.montoyo.wd.client.renderers;
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.montoyo.wd.WebDisplays;
|
||||
import net.montoyo.wd.client.ClientProxy;
|
||||
import net.montoyo.wd.entity.TileEntityScreen;
|
||||
import net.montoyo.wd.utilities.Vector3f;
|
||||
import net.montoyo.wd.utilities.Vector3i;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
public class ScreenRenderer extends TileEntitySpecialRenderer<TileEntityScreen> {
|
||||
|
||||
private final Vector3f mid = new Vector3f();
|
||||
private final Vector3i tmpi = new Vector3i();
|
||||
private final Vector3f tmpf = new Vector3f();
|
||||
|
||||
@Override
|
||||
public void render(TileEntityScreen te, double x, double y, double z, float partialTicks, int destroyStage, float alpha) {
|
||||
if(!te.isLoaded())
|
||||
return;
|
||||
|
||||
//Disable lighting
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
setLightmapDisabled(true);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
for(int i = 0; i < te.screenCount(); i++) {
|
||||
TileEntityScreen.Screen scr = te.getScreen(i);
|
||||
if(scr.browser == null) {
|
||||
scr.browser = ((ClientProxy) WebDisplays.PROXY).getMCEF().createBrowser(WebDisplays.applyBlacklist(scr.url));
|
||||
|
||||
if(scr.rotation.isVertical)
|
||||
scr.browser.resize(scr.resolution.y, scr.resolution.x);
|
||||
else
|
||||
scr.browser.resize(scr.resolution.x, scr.resolution.y);
|
||||
|
||||
scr.doTurnOnAnim = true;
|
||||
scr.turnOnTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
tmpi.set(scr.side.right);
|
||||
tmpi.mul(scr.size.x);
|
||||
tmpi.addMul(scr.side.up, scr.size.y);
|
||||
tmpf.set(tmpi);
|
||||
|
||||
mid.set(x + 0.5, y + 0.5, z + 0.5);
|
||||
mid.addMul(tmpf, 0.5f);
|
||||
tmpf.set(scr.side.left);
|
||||
mid.addMul(tmpf, 0.5f);
|
||||
tmpf.set(scr.side.down);
|
||||
mid.addMul(tmpf, 0.5f);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(mid.x, mid.y, mid.z);
|
||||
|
||||
switch(scr.side) {
|
||||
case BOTTOM:
|
||||
glRotatef(90.f, 1.f, 0.f, 0.f);
|
||||
break;
|
||||
|
||||
case TOP:
|
||||
glRotatef(-90.f, 1.f, 0.f, 0.f);
|
||||
break;
|
||||
|
||||
case NORTH:
|
||||
glRotatef(180.f, 0.f, 1.f, 0.f);
|
||||
break;
|
||||
|
||||
case SOUTH:
|
||||
break;
|
||||
|
||||
case WEST:
|
||||
glRotatef(-90.f, 0.f, 1.f, 0.f);
|
||||
break;
|
||||
|
||||
case EAST:
|
||||
glRotatef(90.f, 0.f, 1.f, 0.f);
|
||||
break;
|
||||
}
|
||||
|
||||
if(scr.doTurnOnAnim) {
|
||||
long lt = System.currentTimeMillis() - scr.turnOnTime;
|
||||
float ft = ((float) lt) / 100.0f;
|
||||
|
||||
if(ft >= 1.0f) {
|
||||
ft = 1.0f;
|
||||
scr.doTurnOnAnim = false;
|
||||
}
|
||||
|
||||
glScalef(ft, ft, 1.0f);
|
||||
}
|
||||
|
||||
if(!scr.rotation.isNull)
|
||||
glRotatef(scr.rotation.angle, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
float sw = ((float) scr.size.x) * 0.5f - 2.f / 16.f;
|
||||
float sh = ((float) scr.size.y) * 0.5f - 2.f / 16.f;
|
||||
|
||||
if(scr.rotation.isVertical) {
|
||||
float tmp = sw;
|
||||
sw = sh;
|
||||
sh = tmp;
|
||||
}
|
||||
|
||||
//TODO: Use tesselator
|
||||
glBindTexture(GL_TEXTURE_2D, scr.browser.getTextureID());
|
||||
glBegin(GL_QUADS);
|
||||
glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(0.f, 1.f); glVertex3f(-sw, -sh, 0.505f);
|
||||
glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(1.f, 1.f); glVertex3f( sw, -sh, 0.505f);
|
||||
glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(1.f, 0.f); glVertex3f( sw, sh, 0.505f);
|
||||
glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(0.f, 0.f); glVertex3f(-sw, sh, 0.505f);
|
||||
glEnd();
|
||||
GlStateManager.bindTexture(0); //Minecraft does shit with mah texture otherwise...
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
/*
|
||||
//Bounding box debugging
|
||||
glPushMatrix();
|
||||
glTranslated(-rendererDispatcher.entityX, -rendererDispatcher.entityY, -rendererDispatcher.entityZ);
|
||||
renderAABB(te.getRenderBoundingBox());
|
||||
glPopMatrix();
|
||||
*/
|
||||
|
||||
//Re-enable lighting
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
setLightmapDisabled(false);
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
public void renderAABB(AxisAlignedBB bb) {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glColor4f(0.f, 0.5f, 1.f, 0.75f);
|
||||
glDepthMask(false);
|
||||
|
||||
Tessellator t = Tessellator.getInstance();
|
||||
BufferBuilder vb = t.getBuffer();
|
||||
vb.begin(GL_QUADS, DefaultVertexFormats.POSITION);
|
||||
|
||||
//Bottom
|
||||
vb.pos(bb.minX, bb.minY, bb.minZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.minY, bb.minZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.minY, bb.maxZ).endVertex();
|
||||
vb.pos(bb.minX, bb.minY, bb.maxZ).endVertex();
|
||||
|
||||
//Top
|
||||
vb.pos(bb.minX, bb.maxY, bb.minZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.maxY, bb.minZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.maxY, bb.maxZ).endVertex();
|
||||
vb.pos(bb.minX, bb.maxY, bb.maxZ).endVertex();
|
||||
|
||||
//Left
|
||||
vb.pos(bb.minX, bb.minY, bb.minZ).endVertex();
|
||||
vb.pos(bb.minX, bb.minY, bb.maxZ).endVertex();
|
||||
vb.pos(bb.minX, bb.maxY, bb.maxZ).endVertex();
|
||||
vb.pos(bb.minX, bb.maxY, bb.minZ).endVertex();
|
||||
|
||||
//Right
|
||||
vb.pos(bb.maxX, bb.minY, bb.minZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.minY, bb.maxZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.maxY, bb.maxZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.maxY, bb.minZ).endVertex();
|
||||
|
||||
//Front
|
||||
vb.pos(bb.minX, bb.minY, bb.minZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.minY, bb.minZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.maxY, bb.minZ).endVertex();
|
||||
vb.pos(bb.minX, bb.maxY, bb.minZ).endVertex();
|
||||
|
||||
//Back
|
||||
vb.pos(bb.minX, bb.minY, bb.maxZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.minY, bb.maxZ).endVertex();
|
||||
vb.pos(bb.maxX, bb.maxY, bb.maxZ).endVertex();
|
||||
vb.pos(bb.minX, bb.maxY, bb.maxZ).endVertex();
|
||||
t.draw();
|
||||
|
||||
glDepthMask(true);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGlobalRenderer(TileEntityScreen te) {
|
||||
//I don't like making it a global renderer for performance reasons,
|
||||
//but Minecraft's AABB-in-view-frustum checking is crappy as hell.
|
||||
return te.isLoaded();
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user