/* * Copyright (C) 2018 BARBOTIN Nicolas */ package net.montoyo.wd.client.gui; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.language.I18n; import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; 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.WDNetworkRegistry; import net.montoyo.wd.net.server_bound.C2SMessageScreenCtrl; import net.montoyo.wd.utilities.*; import org.lwjgl.glfw.GLFW; 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 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(Component component, TileEntityScreen tes, BlockSide side, NameUUIDPair[] friends, int fr, int or) { super(component); this.tes = tes; this.side = side; this.friends = friends; friendRights = fr; otherRights = or; } @Override public void init() { super.init(); loadFrom(new ResourceLocation("webdisplays", "gui/screencfg.json")); friendBoxes = new CheckBox[] { boxFResolution, boxFUpgrades, boxFOthers, boxFFriends, boxFClick, boxFSetUrl }; boxFResolution.setUserdata(ScreenRights.MODIFY_SCREEN); boxFUpgrades.setUserdata(ScreenRights.MANAGE_UPGRADES); boxFOthers.setUserdata(ScreenRights.MANAGE_OTHER_RIGHTS); boxFFriends.setUserdata(ScreenRights.MANAGE_FRIEND_LIST); boxFClick.setUserdata(ScreenRights.INTERACT); boxFSetUrl.setUserdata(ScreenRights.CHANGE_URL); otherBoxes = new CheckBox[] { boxOResolution, boxOUpgrades, boxOClick, boxOSetUrl }; boxOResolution.setUserdata(ScreenRights.MODIFY_SCREEN); boxOUpgrades.setUserdata(ScreenRights.MANAGE_UPGRADES); boxOClick.setUserdata(ScreenRights.INTERACT); 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(); Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI( WebDisplays.INSTANCE.soundScreenCfg, 1.0f, 1.0f)); } private void updateRotationStr() { btnChangeRot.setLabel(I18n.get("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) WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.resolution(tes, side, new Vector2i(x, y))); } catch(NumberFormatException ex) { //Roll back tfResX.setText("" + scr.resolution.x); tfResY.setText("" + scr.resolution.y); } btnSetRes.setDisabled(true); } @GuiSubscribe public void onClick(Button.ClickEvent ev) { if(ev.getSource() == btnAdd && !waitingAC) addFriend(tfFriend.getText().trim()); else if(ev.getSource() == btnSetRes) clickSetRes(); else if(ev.getSource() == btnChangeRot) { Rotation[] rots = Rotation.values(); WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageScreenCtrl(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().setCursorPosition(0); tfResY.getMcField().setHighlightPos(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) WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageScreenCtrl(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) WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.autoVol(tes, side, ev.isChecked())); } @GuiSubscribe public void onRemoveUpgrade(UpgradeGroup.ClickEvent ev) { WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageScreenCtrl(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])) WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageScreenCtrl(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 tick() { super.tick(); 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() { WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageScreenCtrl(tes, side, friendRights, otherRights)); Log.info("Sent sync packet"); } public void updateMyRights() { NameUUIDPair me = new NameUUIDPair(minecraft.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.MODIFY_SCREEN) == 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.getBlockPos()) && 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"; } // reason: allow closing the UI, lol @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (keyCode == GLFW.GLFW_KEY_ESCAPE) { Minecraft.getInstance().setScreen(null); return true; } return super.keyPressed(keyCode, scanCode, modifiers); } }