diff --git a/scripts/radial/terminal/bank.js b/scripts/radial/terminal/bank.js index 70c936c41..312e8d5b1 100644 --- a/scripts/radial/terminal/bank.js +++ b/scripts/radial/terminal/bank.js @@ -23,27 +23,18 @@ var handleSelection = function(player, target, selection) { case RadialItem.ITEM_USE: case RadialItem.BANK_TRANSFER: { creature = player.getCreatureObject(); - SuiWindow = Java.type("resources.sui.SuiWindow"); - Trigger = Java.type("resources.sui.SuiWindow.Trigger"); - window = new SuiWindow("Script.transfer", player); - window.setProperty('transaction.txtInputFrom:Text', 'From'); - window.setProperty('transaction.txtInputFrom:Text', 'From'); - window.setProperty('bg.caption.lblTitle:Text', '@base_player:bank_title'); - window.setProperty('Prompt.lblPrompt:Text', '@base_player:bank_prompt'); - window.setProperty('transaction.txtInputTo:Text', 'To'); - window.setProperty('transaction.lblFrom:Text', 'Cash'); - window.setProperty('transaction.lblTo:Text', 'Bank'); - window.setProperty('transaction.lblStartingFrom:Text', creature.getCashBalance()); - window.setProperty('transaction.lblStartingTo:Text', creature.getBankBalance()); - window.setProperty('transaction.txtInputFrom:Text', creature.getCashBalance()); - window.setProperty('transaction.txtInputTo:Text', creature.getBankBalance()); - window.setProperty('transaction:ConversionRatioFrom', '1'); - window.setProperty('transaction:ConversionRatioTo', '1'); - returnParams = new java.util.ArrayList(); - returnParams.add('transaction.txtInputFrom:Text'); - returnParams.add('transaction.txtInputTo:Text'); - window.addCallback(0, '', Trigger.OK, returnParams, "radial/terminal/bank"); - window.addCallback(1, '', Trigger.CANCEL, returnParams, "radial/terminal/bank"); + window = new SuiWindow("Script.transfer", player, SuiButtons.OK_CANCEL, '@base_player:bank_title', '@base_player:bank_prompt'); + window.setPropertyText('transaction.lblFrom', 'Cash'); + window.setPropertyText('transaction.lblTo', 'Bank'); + window.setPropertyText('transaction.lblStartingFrom', creature.getCashBalance()); + window.setPropertyText('transaction.lblStartingTo', creature.getBankBalance()); + window.setPropertyText('transaction.txtInputFrom', creature.getCashBalance()); + window.setPropertyText('transaction.txtInputTo', creature.getBankBalance()); + window.setProperty('transaction', 'ConversionRatioFrom', '1'); + window.setProperty('transaction', 'ConversionRatioTo', '1'); + window.addReturnableProperty('transaction.txtInputFrom', 'Text'); + window.addReturnableProperty('transaction.txtInputTo', 'Text'); + window.addCallback("radial/terminal/bank", "handleBankTransfer"); window.display(); break; } @@ -81,7 +72,7 @@ var handleSelection = function(player, target, selection) { if (amount > 1E9) amount = 1E9; if (creature.getReserveBalance() + amount > 3E9 || amount == 0) { - intentFactory.sendSystemMessage(player, '@error_message:bank_deposit') + intentFactory.sendSystemMessage(player, '@error_message:bank_deposit'); break; } creature.setBankBalance(creature.getBankBalance() - amount); @@ -94,7 +85,7 @@ var handleSelection = function(player, target, selection) { if (amount > 1E9) amount = 1E9; if (creature.getBankBalance() + amount > 2E9 || amount == 0) { - intentFactory.sendSystemMessage(player, '@error_message:bank_withdraw') + intentFactory.sendSystemMessage(player, '@error_message:bank_withdraw'); break; } creature.setBankBalance(creature.getBankBalance() + amount); @@ -103,12 +94,12 @@ var handleSelection = function(player, target, selection) { } } }; -var callback = function(player, creature, eventId, dataStrings) { - switch (eventId) { - case 0: - creature.setCashBalance(Number(dataStrings[0])); - creature.setBankBalance(Number(dataStrings[1])); - intentFactory.sendSystemMessage(player, '@base_player:bank_success') +var handleBankTransfer = function(player, creature, eventType, parameters) { + switch (eventType) { + case SuiEvent.OK_PRESSED: + creature.setCashBalance(Number(parameters.get('transaction.txtInputFrom.Text'))); + creature.setBankBalance(Number(parameters.get('transaction.txtInputTo.Text'))); + intentFactory.sendSystemMessage(player, '@base_player:bank_success'); break; } }; \ No newline at end of file diff --git a/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java b/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java index a2c64d635..dd348bbc1 100644 --- a/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java +++ b/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java @@ -63,4 +63,8 @@ public class SuiCreatePageMessage extends SWGPacket { addData(data, windowData); return data; } + + public SuiWindow getWindow() { + return window; + } } diff --git a/src/network/packets/swg/zone/server_ui/SuiEventNotification.java b/src/network/packets/swg/zone/server_ui/SuiEventNotification.java index 3f0032d52..89ee79347 100644 --- a/src/network/packets/swg/zone/server_ui/SuiEventNotification.java +++ b/src/network/packets/swg/zone/server_ui/SuiEventNotification.java @@ -37,12 +37,12 @@ public class SuiEventNotification extends SWGPacket { public static final int CRC = getCrc("SuiEventNotification"); private int windowId; - private int eventId; + private int eventIndex; private int updateCount; - private List dataStrings; + private List subscribedToProperties; public SuiEventNotification() { - dataStrings = new ArrayList(); + subscribedToProperties = new ArrayList<>(); } public SuiEventNotification(ByteBuffer data) { @@ -54,20 +54,33 @@ public class SuiEventNotification extends SWGPacket { if (!super.decode(data, CRC)) return; windowId = getInt(data); - eventId = getInt(data); + eventIndex = getInt(data); int size = getInt(data); updateCount = getInt(data); for (int i = 0; i < size; i++) { - dataStrings.add(getUnicode(data)); + subscribedToProperties.add(getUnicode(data)); } } public ByteBuffer encode() { - return null; + int size = 0; + for (String property : subscribedToProperties) { + size += 4 + (property.length() * 2); + } + + ByteBuffer bb = ByteBuffer.allocate(size + 16); + addInt(bb, windowId); + addInt(bb, eventIndex); + addInt(bb, subscribedToProperties.size()); + addInt(bb, updateCount); + for (String property : subscribedToProperties) { + addUnicode(bb, property); + } + return bb; } public int getWindowId() { return this.windowId; } - public List getDataStrings() { return this.dataStrings; } - public int getEventId() { return this.eventId; } + public List getSubscribedToProperties() { return this.subscribedToProperties; } + public int getEventIndex() { return this.eventIndex; } public int getUpdateCount() { return this.updateCount; } } diff --git a/src/resources/commands/callbacks/ServerCmdCallback.java b/src/resources/commands/callbacks/ServerCmdCallback.java index 3e413e1bc..ca2743602 100644 --- a/src/resources/commands/callbacks/ServerCmdCallback.java +++ b/src/resources/commands/callbacks/ServerCmdCallback.java @@ -29,41 +29,39 @@ package resources.commands.callbacks; import intents.server.ServerManagementIntent; import intents.server.ServerManagementIntent.ServerManagementEvent; - -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - import resources.commands.ICmdCallback; import resources.objects.SWGObject; import resources.player.Player; import resources.sui.ISuiCallback; +import resources.sui.SuiButtons; +import resources.sui.SuiEvent; import resources.sui.SuiInputBox; -import resources.sui.SuiInputBox.InputBoxType; import resources.sui.SuiListBox; -import resources.sui.SuiListBox.ListBoxType; import resources.sui.SuiMessageBox; -import resources.sui.SuiMessageBox.MessageBoxType; import utilities.Scripts; import services.galaxy.GalacticManager; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + public class ServerCmdCallback implements ICmdCallback { @Override public void execute(GalacticManager galacticManager, Player player, SWGObject target, String args) { - if (args.equals("debug") || args.startsWith("debug ")) { + if (args.startsWith("debug")) { debug(galacticManager, player, target, args); return; } - SuiListBox listBox = new SuiListBox(player, ListBoxType.OK_CANCEL, "Server Management", "Select the management function you wish to perform from the list."); + SuiListBox listBox = new SuiListBox(player, SuiButtons.OK_CANCEL, "Server Management", "Select the management function you wish to perform from the list."); - listBox.addListItem("Kick Player", 0); - listBox.addListItem("Ban Player", 1); - listBox.addListItem("Unban Player", 2); - listBox.addListItem("Shutdown Server - 15 Minutes", 3); + listBox.addListItem("Kick Player"); + listBox.addListItem("Ban Player"); + listBox.addListItem("Unban Player"); + listBox.addListItem("Shutdown Server - 15 Minutes"); listBox.addListItem("Shutdown Server - Custom Time"); - - listBox.addItemSelectionCallback(0, new ServerSuiCallback()); + + listBox.addOkButtonCallback("handleSelectedItem", new ServerSuiCallback()); listBox.display(); } @@ -72,9 +70,9 @@ public class ServerCmdCallback implements ICmdCallback { } private static class ServerSuiCallback implements ISuiCallback { - - public void handleEvent(Player player, SWGObject actor, int eventType, List returnParams) { - int selection = SuiListBox.getSelectedIndex(returnParams); + @Override + public void handleEvent(Player player, SWGObject actor, SuiEvent event, Map parameters) { + int selection = SuiListBox.getSelectedRow(parameters); switch(selection) { case 0: handleKickPlayer(player); break; @@ -82,60 +80,48 @@ public class ServerCmdCallback implements ICmdCallback { case 2: handleUnbanPlayer(player); break; case 3: handleShutdownServer(player); break; case 4: handleCustomShutdownServer(player); break; - default: break; + default: System.out.println("Nothing for selection " + selection); break; } } private void handleKickPlayer(Player actor) { - SuiInputBox window = new SuiInputBox(actor, InputBoxType.OK_CANCEL, "Kick Player", "Enter the name of the player that you wish to KICK from the server."); - window.addInputTextCallback(0, new ISuiCallback() { - public void handleEvent(Player player, SWGObject actor, int eventType, List returnParams) { - String name = returnParams.get(0); // input - new ServerManagementIntent(player, name, ServerManagementEvent.KICK).broadcast(); - } + SuiInputBox window = new SuiInputBox(actor, SuiButtons.OK_CANCEL, "Kick Player", "Enter the name of the player that you wish to KICK from the server."); + window.addOkButtonCallback("handleKickPlayer", (player, actor1, event, parameters) -> { + String name = SuiInputBox.getEnteredText(parameters); + new ServerManagementIntent(player, name, ServerManagementEvent.KICK).broadcast(); }); - window.display(); } private void handleBanPlayer(Player actor) { - SuiInputBox window = new SuiInputBox(actor, InputBoxType.OK_CANCEL, "Ban Player", "Enter the name of the player that you wish to BAN from the server."); - window.addInputTextCallback(0, new ISuiCallback() { - public void handleEvent(Player player, SWGObject actor, int eventType, List returnParams) { - String name = returnParams.get(0); // input - new ServerManagementIntent(player, name, ServerManagementEvent.BAN).broadcast(); - } + SuiInputBox window = new SuiInputBox(actor, SuiButtons.OK_CANCEL, "Ban Player", "Enter the name of the player that you wish to BAN from the server."); + window.addOkButtonCallback("handleBanPlayer", (player, actor1, event, parameters) -> { + String name = SuiInputBox.getEnteredText(parameters); + new ServerManagementIntent(player, name, ServerManagementEvent.BAN).broadcast(); }); - window.display(); } private void handleUnbanPlayer(Player actor) { - SuiInputBox window = new SuiInputBox(actor, InputBoxType.OK_CANCEL, "Unban Player", "Enter the name of the player that you wish to UNBAN from the server."); - window.addInputTextCallback(0, new ISuiCallback() { - public void handleEvent(Player player, SWGObject actor, int eventType, List returnParams) { - String name = returnParams.get(0); - new ServerManagementIntent(player, name, ServerManagementEvent.UNBAN).broadcast(); - } + SuiInputBox window = new SuiInputBox(actor, SuiButtons.OK_CANCEL, "Unban Player", "Enter the name of the player that you wish to UNBAN from the server."); + window.addOkButtonCallback("handleUnbanPlayer", (player, actor1, event, parameters) -> { + String name = SuiInputBox.getEnteredText(parameters); + new ServerManagementIntent(player, name, ServerManagementEvent.UNBAN).broadcast(); }); - window.display(); } private void handleShutdownServer(Player actor) { - SuiMessageBox window = new SuiMessageBox(actor, MessageBoxType.YES_NO, "Shutdown Server", "Are you sure you wish to begin the shutdown sequence?"); - window.addOkButtonCallback(0, new ISuiCallback() { - public void handleEvent(Player player, SWGObject actor, int eventType, List returnParams) { - new ServerManagementIntent(15, TimeUnit.MINUTES, ServerManagementEvent.SHUTDOWN).broadcast(); - } + SuiMessageBox window = new SuiMessageBox(actor, SuiButtons.YES_NO, "Shutdown Server", "Are you sure you wish to begin the shutdown sequence?"); + window.addOkButtonCallback("handleShutdownServer", (player, actor1, event, parameters) -> { + new ServerManagementIntent(15, TimeUnit.MINUTES, ServerManagementEvent.SHUTDOWN).broadcast(); }); - window.display(); } private void handleCustomShutdownServer(Player actor) { - final SuiListBox unitWindow = new SuiListBox(actor, ListBoxType.OK_CANCEL, "Shutdown Server", "Select the time unit that the time will be specified in. "); - final SuiInputBox timeWindow = new SuiInputBox(actor, InputBoxType.OK_CANCEL, "Shutdown Server", "Enter the time until the server shuts down. The shutdown sequence " + final SuiListBox unitWindow = new SuiListBox(actor, SuiButtons.OK_CANCEL, "Shutdown Server", "Select the time unit that the time will be specified in. "); + final SuiInputBox timeWindow = new SuiInputBox(actor, SuiButtons.OK_CANCEL, "Shutdown Server", "Enter the time until the server shuts down. The shutdown sequence " + "will begin upon hitting OK."); final AtomicReference timeUnitReference = new AtomicReference<>(); final TimeUnit[] unitValues = TimeUnit.values(); @@ -145,22 +131,18 @@ public class ServerCmdCallback implements ICmdCallback { // Ziggy: Add all the TimeUnit values as options for(byte i = 0; i < unitValues.length; i++) unitWindow.addListItem(unitValues[i].toString(), i); - - unitWindow.addItemSelectionCallback(0, new ISuiCallback() { - public void handleEvent(Player player, SWGObject actor, int eventType, List returnParams) { - int index = SuiListBox.getSelectedIndex(returnParams); - if (index < 0 || index >= unitValues.length) - return; - timeUnitReference.set(unitValues[index]); - timeWindow.display(); // Ziggy: Display the next window - } + + unitWindow.addOkButtonCallback("handleCustomShutdownTime", (player, actor1, event, parameters) -> { + int index = SuiListBox.getSelectedRow(parameters); + if (index < 0 || index >= unitValues.length) + return; + timeUnitReference.set(unitValues[index]); + timeWindow.display(); // Ziggy: Display the next window }); - timeWindow.addInputTextCallback(0, new ISuiCallback() { - public void handleEvent(Player player, SWGObject actor, int eventType, List returnParams) { - long countdown = Long.parseLong(returnParams.get(0)); - new ServerManagementIntent(countdown, timeUnitReference.get(), ServerManagementEvent.SHUTDOWN).broadcast(); - } + timeWindow.addOkButtonCallback("handleCustomShutdownCountdown", (player, actor1, event, parameters) -> { + long countdown = Long.valueOf(SuiInputBox.getEnteredText(parameters)); + new ServerManagementIntent(countdown, timeUnitReference.get(), ServerManagementEvent.SHUTDOWN).broadcast(); }); unitWindow.display(); diff --git a/src/resources/sui/ISuiCallback.java b/src/resources/sui/ISuiCallback.java index c1b0635aa..c51887680 100644 --- a/src/resources/sui/ISuiCallback.java +++ b/src/resources/sui/ISuiCallback.java @@ -27,11 +27,11 @@ ***********************************************************************************/ package resources.sui; -import java.util.List; +import java.util.Map; import resources.objects.SWGObject; import resources.player.Player; public interface ISuiCallback { - public void handleEvent(Player player, SWGObject actor, int eventType, List returnParams); + void handleEvent(Player player, SWGObject actor, SuiEvent event, Map parameters); } diff --git a/src/resources/sui/SuiBaseWindow.java b/src/resources/sui/SuiBaseWindow.java index eb8c5c64f..440896c8b 100644 --- a/src/resources/sui/SuiBaseWindow.java +++ b/src/resources/sui/SuiBaseWindow.java @@ -30,26 +30,118 @@ package resources.sui; import resources.player.Player; public class SuiBaseWindow extends SuiWindow { - private String windowType; - - public SuiBaseWindow(String script, Player owner, String title, String prompt) { + + public SuiBaseWindow(String script, Player owner, SuiButtons buttons, String title, String prompt) { super(script, owner); - windowType = script.replace("Script.", ""); setTitle(title); setPrompt(prompt); + setButtons(buttons); } - public void setSize(int x, int z) { - setProperty(windowType + ":Size", String.valueOf(x) + "," + String.valueOf(z)); + public SuiBaseWindow(String script, Player owner, SuiButtons buttons, String title, String prompt, String callbackScript, String function) { + this(script, owner, buttons, title, prompt); + + addOkButtonCallback(callbackScript, function); + addCancelButtonCallback(callbackScript, function); } - + + public SuiBaseWindow(String script, Player owner, SuiButtons buttons, String title, String prompt, String callback, ISuiCallback suiCallback) { + this(script, owner, buttons, title, prompt); + + addOkButtonCallback(callback, suiCallback); + addCancelButtonCallback(callback, suiCallback); + } + + public SuiBaseWindow(String script, Player owner, String title, String prompt) { + this(script, owner, SuiButtons.DEFAULT, title, prompt); + } + public void setTitle(String title) { if (title != null) - setProperty("bg.caption.lblTitle:Text", title); + setPropertyText("bg.caption.lblTitle", title); } public void setPrompt(String prompt) { if (prompt != null) - setProperty("Prompt.lblPrompt:Text", prompt); + setPropertyText("Prompt.lblPrompt", prompt); + } + + public void setPropertyText(String widget, String value) { + setProperty(widget, "Text", value); + } + + public void setAutosave(boolean autosave) { + setProperty("this", "autosave", String.valueOf(autosave)); + } + + public void setLocation(int x, int y) { + setProperty("this", "Location", String.valueOf(x) + "," + String.valueOf(y)); + } + + public void setSize(int width, int height) { + setProperty("this", "Size", String.valueOf(width) + "," + String.valueOf(height)); + } + + protected void setOkButtonText() { + setOkButtonText("@ok"); + } + + protected void setOkButtonText(String text) { + setProperty("btnOk", "Text", text); + } + + protected void setCancelButtonText() { + setCancelButtonText("@cancel"); + } + + protected void setCancelButtonText(String text) { + setProperty("btnCancel", "Text", text); + } + + protected void setShowOtherButton(boolean display, String text) { + setProperty("btnOther", "Visible", String.valueOf(display)); + if (display) { + setProperty("btnOther", "Text", text); + addOtherButtonReturnable(); + } + } + + protected void setShowCancelButton(boolean display) { + String value = String.valueOf(display); + setProperty("btnCancel", "Enabled", value); + setProperty("btnCancel", "Visible", value); + } + + public void addOkButtonCallback(String callback, ISuiCallback suiCallback) { + addCallback(SuiEvent.OK_PRESSED, callback, suiCallback); + } + + public void addOkButtonCallback(String script, String function) { + addCallback(SuiEvent.OK_PRESSED, script, function); + } + + public void addCancelButtonCallback(String callback, ISuiCallback suiCallback) { + addCallback(SuiEvent.CANCEL_PRESSED, callback, suiCallback); + } + + public void addCancelButtonCallback(String script, String function) { + addCallback(SuiEvent.CANCEL_PRESSED, script, function); + } + + public void addOtherButtonReturnable() { + addReturnableProperty(SuiEvent.OK_PRESSED, "this", "otherPressed"); + } + + protected void setButtons(SuiButtons buttons) { + switch(buttons) { + case OK_CANCEL: + setOkButtonText(); + setCancelButtonText(); + break; + case OK: + default: + setOkButtonText(); + break; + } } } diff --git a/src/resources/sui/SuiButtons.java b/src/resources/sui/SuiButtons.java new file mode 100644 index 000000000..b486bdd33 --- /dev/null +++ b/src/resources/sui/SuiButtons.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package resources.sui; + +/** + * Created by Waverunner on 8/15/2015 + */ +public enum SuiButtons { + OK, + CANCEL, + OK_CANCEL, + YES_NO, + OK_REFRESH_CANCEL, + YES_NO_CANCEL, + YES_NO_MAYBE, + YES_NO_ABSTAIN, + RETRY_CANCEL, + RETRY_ABORT_CANCEL, + OK_REFRESH, + OK_CANCEL_REFRESH, + REFRESH, + REFRESH_CANCEL, + OK_CANCEL_ALL, + MOVEUP_MOVEDOWN_DONE, + REMOVE_CANCEL, + BET_MAX_BET_ONE_SPIN, + DEFAULT, + COMBO_OK, + COMBO_OK_CANCEL; + + public static SuiButtons valueOf(int index) { + switch(index) { + case 0: return SuiButtons.OK; + case 1: return SuiButtons.CANCEL; + case 3: return SuiButtons.REFRESH; + default: break; + } + return DEFAULT; + } +} diff --git a/src/resources/sui/SuiComponent.java b/src/resources/sui/SuiComponent.java index 2e2834ecb..fbc592bb3 100644 --- a/src/resources/sui/SuiComponent.java +++ b/src/resources/sui/SuiComponent.java @@ -29,6 +29,7 @@ package resources.sui; import network.packets.Packet; import resources.encodables.Encodable; +import resources.server_info.Log; import utilities.Encoder; import java.nio.ByteBuffer; @@ -40,41 +41,103 @@ import java.util.List; */ public class SuiComponent implements Encodable { - public SuiComponent() {} + private Type type; + private List wideParams; + private List narrowParams; - public SuiComponent(Type type) { - this.type = type; + public SuiComponent() { + type = Type.NONE; + wideParams = new ArrayList<>(); + narrowParams = new ArrayList<>(); } - private Type type; - private List wideParams = new ArrayList<>(); - private List narrowParams = new ArrayList<>(); + public SuiComponent(Type type, String widget) { + this.type = type; + this.wideParams = new ArrayList<>(3); + this.narrowParams = new ArrayList<>(3); + + narrowParams.add(widget); + } public Type getType() { return type; } - public void setType(Type type) { - this.type = type; - } public List getNarrowParams() { return narrowParams; } - public void setNarrowParams(List narrowParams) { - this.narrowParams = narrowParams; - } public List getWideParams() { return wideParams; } - public void setWideParams(List wideParams) { - this.wideParams = wideParams; + + /** + * Retrieve the base widget that this component targets + * @return Base widget this component targets + */ + public String getTarget() { + return narrowParams.get(0); } + public void addNarrowParam(String param) { narrowParams.add(param); } + public void addWideParam(String param) { wideParams.add(param); } + public List getSubscribedProperties() { + if (type != Type.SUBSCRIBE_TO_EVENT) + return null; + + int size = narrowParams.size(); + if (size < 3) { + Log.i("SuiComponent", "Tried to get subscribed properties when there are none for target %s", getTarget()); + } else { + List subscribedProperties = new ArrayList<>(); + + for (int i = 3; i < size;) { + String property = narrowParams.get(i++) + "." + narrowParams.get(i++); + subscribedProperties.add(property); + } + + return subscribedProperties; + } + return null; + } + + public String getSubscribeToEventCallback() { + if (type != Type.SUBSCRIBE_TO_EVENT) + return null; + + int size = narrowParams.size(); + if (size < 3) { + Log.i("SuiComponent", "Tried to get subscribed callback when there is none for target %s", getTarget()); + } else { + + return narrowParams.get(2); + } + return null; + } + + public int getSubscribedToEventType() { + if (type != Type.SUBSCRIBE_TO_EVENT) + return -1; + + int size = narrowParams.size(); + if (size < 3) { + Log.i("SuiComponent", "Tried to get subscribed event type when there is none for target %s", getTarget()); + } else { + byte[] bytes = narrowParams.get(1).getBytes(); + if (bytes.length > 1) { + Log.i("SuiComponent", "Tried to get event tyep but narrowparams string byte array length is more than 1"); + return -1; + } + + return (int) bytes[0]; + } + return -1; + } + @Override public byte[] encode() { int size = 9; diff --git a/src/resources/sui/SuiEvent.java b/src/resources/sui/SuiEvent.java new file mode 100644 index 000000000..7e2c0dc8a --- /dev/null +++ b/src/resources/sui/SuiEvent.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package resources.sui; + +/** + * Created by Waverunner on 8/14/2015 + */ +public enum SuiEvent { + NONE(0), + BUTTON(1), + CHECKBOX(2), + ENABLE_DISABLE(3), + GENERIC(4), + SLIDER(5), + TAB_PANE(6), + TEXTBOX(7), + VISIBILITY_CHANGED(8), + OK_PRESSED(9), + CANCEL_PRESSED(10); + + private int value; + + SuiEvent(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static SuiEvent valueOf(int value) { + switch(value) { + case 0: return NONE; + case 1: return BUTTON; + case 2: return CHECKBOX; + case 3: return ENABLE_DISABLE; + case 4: return GENERIC; + case 5: return SLIDER; + case 6: return TAB_PANE; + case 7: return TEXTBOX; + case 8: return VISIBILITY_CHANGED; + case 9: return OK_PRESSED; + case 10: return CANCEL_PRESSED; + default: return NONE; + } + } +} diff --git a/src/resources/sui/SuiInputBox.java b/src/resources/sui/SuiInputBox.java index 8504abba1..fb2d6e608 100644 --- a/src/resources/sui/SuiInputBox.java +++ b/src/resources/sui/SuiInputBox.java @@ -27,53 +27,89 @@ ***********************************************************************************/ package resources.sui; -import java.util.ArrayList; -import java.util.List; - import resources.player.Player; +import java.util.Map; + public class SuiInputBox extends SuiBaseWindow { - public SuiInputBox(Player owner, InputBoxType type, String title, String prompt) { - super("Script.inputBox", owner, title, prompt); - switch(type){ - case OK: - setProperty("btnOk:visible", "True"); - setProperty("btnOk:Text", "@ok"); - setProperty("btnCancel:visible", "False"); - setProperty("cmbInput:visible", "False"); - break; - case OK_CANCEL: - setProperty("btnOk:visible", "True"); - setProperty("btnCancel:visible", "True"); - setProperty("btnCancel:Text", "@cancel"); - setProperty("btnOk:Text", "@ok"); - setProperty("cmbInput:visible", "False"); - break; - default: break; - } + public SuiInputBox(Player owner, SuiButtons buttons, String title, String prompt) { + super("Script.inputBox", owner, buttons, title, prompt); } public SuiInputBox(Player owner, String title, String prompt) { - this(owner, InputBoxType.OK_CANCEL, title, prompt); + this(owner, SuiButtons.OK_CANCEL, title, prompt); } - - public void addInputTextCallback(int eventType, ISuiCallback callback) { - List returnParams = new ArrayList(); - returnParams.add("txtInput:LocalText"); - addCallback(eventType, "", Trigger.OK, returnParams, callback); + + public static String getEnteredText(Map parameters) { + return parameters.get("txtInput.Text"); } - + + public static String getSelectedComboText(Map parameters) { + return parameters.get("cmbInput.SelectedText"); + } + + @Override + protected void setButtons(SuiButtons buttons) { + switch(buttons) { + case OK_CANCEL: + setProperty("btnOk", "Visible", "True"); + setProperty("btnCancel", "Visible", "True"); + setCancelButtonText("@cancel"); + setOkButtonText("@ok"); + displayComboBox(false); + break; + case COMBO_OK: + setProperty("btnOk", "Visible", "True"); + setProperty("btnCancel", "Visible", "False"); + setOkButtonText("@ok"); + displayComboBox(true); + break; + case COMBO_OK_CANCEL: + setProperty("btnOk", "Visible", "True"); + setProperty("btnCancel", "Visible", "True"); + setOkButtonText("@ok"); + setCancelButtonText("@cancel"); + displayComboBox(true); + break; + case OK: + default: + setProperty("btnOk", "Visible", "True"); + setProperty("btnCancel", "Visible", "False"); + setOkButtonText("@ok"); + displayComboBox(false); + break; + } + } + + @Override + protected void onDisplayRequest() { + addReturnableProperty("txtInput", "Text"); + addReturnableProperty("cmbInput", "SelectedText"); + addReturnableProperty("txtInput", "MaxLength"); + } + + private void displayComboBox(boolean show) { + if (show) { + setProperty("cmbInput", "Visible", "True"); + setProperty("cmbInput", "Visible", "True"); + + setProperty("txtInput", "Enabled", "False"); + setProperty("txtInput", "Visible", "False"); + } else { + setProperty("cmbInput", "Visible", "False"); + setProperty("cmbInput", "Visible", "False"); + + setProperty("txtInput", "Enabled", "True"); + setProperty("txtInput", "Visible", "True"); + } + } + public void allowStringCharacters(boolean stringCharacters) { - setProperty("txtInput:NumericInteger", String.valueOf(stringCharacters)); + setProperty("txtInput", "NumericInteger", String.valueOf(stringCharacters)); } - - public void setMaxInputLength(int maxLength) { - setProperty("txtInput:MaxLength", String.valueOf(maxLength)); - } - - public enum InputBoxType { - OK, - OK_CANCEL; + + public void setMaxLength(int maxLength) { + setProperty("txtInput", "MaxLength", String.valueOf(maxLength)); } } diff --git a/src/resources/sui/SuiListBox.java b/src/resources/sui/SuiListBox.java index 7cd7859e8..58ab2ef44 100644 --- a/src/resources/sui/SuiListBox.java +++ b/src/resources/sui/SuiListBox.java @@ -29,89 +29,130 @@ package resources.sui; import java.util.ArrayList; import java.util.List; +import java.util.Map; import resources.player.Player; public class SuiListBox extends SuiBaseWindow { private List list; - public SuiListBox(Player owner, ListBoxType type, String title, String prompt) { - super("Script.listBox", owner, title, prompt); - list = new ArrayList(); - switch(type) { - case OK: - setProperty("btnOk:visible", "True"); - setProperty("btnOk:Text", "@ok"); - setProperty("btnCancel:visible", "False"); - break; - case OK_CANCEL: - setProperty("btnOk:visible", "True"); - setProperty("btnCancel:visible", "True"); - setProperty("btnOk:Text", "@ok"); - setProperty("btnCancel:Text", "@cancel"); - break; - default: break; - } + public SuiListBox(Player owner, SuiButtons buttons, String title, String prompt) { + super("Script.listBox", owner, buttons, title, prompt); clearDataSource("List.dataList"); + + list = new ArrayList<>(); } public SuiListBox(Player owner, String title, String prompt) { - this(owner, ListBoxType.OK_CANCEL, title, prompt); + this(owner, SuiButtons.OK_CANCEL, title, prompt); } - - public void addListItem(String name, long id) { - SuiListBoxItem item = new SuiListBoxItem(name, id); + + public static int getSelectedRow(Map parameters) { + String selectedIndex = parameters.get("List.lstList.SelectedRow"); + if (selectedIndex != null) return Integer.parseInt(selectedIndex); + return -1; + } + + @Override + protected void setButtons(SuiButtons buttons) { + switch(buttons) { + case OK_CANCEL: + setOkButtonText("@ok"); + setCancelButtonText("@cancel"); + break; + case YES_NO: + setOkButtonText("@yes"); + setCancelButtonText("@no"); + break; + case OK_REFRESH: + setOkButtonText("@ok"); + setCancelButtonText("@refresh"); + break; + case OK_CANCEL_REFRESH: + setOkButtonText("@ok"); + setCancelButtonText("@cancel"); + setShowOtherButton(true, "@refresh"); + break; + case OK_CANCEL_ALL: + setOkButtonText("@ok"); + setCancelButtonText("@cancel"); + setShowOtherButton(true, "@all"); + break; + case REFRESH: + setOkButtonText("@refresh"); + setShowCancelButton(false); + break; + case REFRESH_CANCEL: + setOkButtonText("@refresh"); + setCancelButtonText("@cancel"); + break; + case REMOVE_CANCEL: + setOkButtonText("@remove"); + setCancelButtonText("@cancel"); + break; + case MOVEUP_MOVEDOWN_DONE: + setOkButtonText("@moveup"); + setCancelButtonText("@done"); + setShowOtherButton(true, "@movedown"); + break; + case BET_MAX_BET_ONE_SPIN: + setOkButtonText("@ok"); + setCancelButtonText("@spin"); + setShowOtherButton(true, "@bet_one"); + break; + case OK: + case DEFAULT: + default: + setOkButtonText("@ok"); + setShowCancelButton(false); + break; + } + } + + @Override + protected void onDisplayRequest() { + addReturnableProperty("List.lstList", "SelectedRow"); + addReturnableProperty("bg.caption.lblTitle", "Text"); + } + + public void addListItem(String name, long id, Object object) { + SuiListBoxItem item = new SuiListBoxItem(name, id, object); int index = list.size(); - - addDataItem("List.dataList:Name", String.valueOf(index)); - setProperty("List.dataList." + index + ":Text", name); - + String sIndex = String.valueOf(index); + addDataItem("List.dataList", "Name", sIndex); + setProperty("List.dataList." + sIndex, "Text", name); + list.add(item); } public void addListItem(String name) { - addListItem(name, 0); + addListItem(name, -1, null); } - - public void addItemSelectionCallback(int eventId, ISuiCallback callback) { - List returnList = new ArrayList(); - returnList.add("List.lstList:SelectedRow"); - addCallback(eventId, "", Trigger.OK, returnList, callback); - } - - public long getListItemId(int index) { - SuiListBoxItem item = list.get(index); - - if (item == null) return 0; - else return item.getId(); + + public void addListItem(String name, Object object) { + addListItem(name, -1, object); } public SuiListBoxItem getListItem(int index) { - SuiListBoxItem item = list.get(index); - return item; + return list.get(index); } - - public static int getSelectedIndex(List returnParams) { return Integer.parseInt(returnParams.get(0)); } - + public List getList() { return list; } - public enum ListBoxType { - OK, - OK_CANCEL, - DEFAULT; - } - public static class SuiListBoxItem { + private Object object; private String name; private long id; - public SuiListBoxItem(String name, long id) { + public SuiListBoxItem(String name, long id, Object object) { this.name = name; this.id = id; + this.object = object; } public String getName() { return this.name; } public long getId() { return this.id; } + public Object getObject() { return this.object; } } } diff --git a/src/resources/sui/SuiMessageBox.java b/src/resources/sui/SuiMessageBox.java index 816c6014a..62b1f2c5d 100644 --- a/src/resources/sui/SuiMessageBox.java +++ b/src/resources/sui/SuiMessageBox.java @@ -27,61 +27,80 @@ ***********************************************************************************/ package resources.sui; -import java.util.ArrayList; -import java.util.List; - import resources.player.Player; public class SuiMessageBox extends SuiBaseWindow { - public SuiMessageBox(Player owner, MessageBoxType type, String title, String prompt) { - super("Script.messageBox", owner, title, prompt); - - setProperty("btnRevert:visible", "False"); - switch(type) { - case OK: - setProperty("btnOk:visible", "True"); - setProperty("btnOk:Text", "@ok"); - setProperty("btnCancel:visible", "False"); - break; - case OK_CANCEL: - setProperty("btnOk:visible", "True"); - setProperty("btnCancel:visible", "True"); - setProperty("btnOk:Text", "@ok"); - setProperty("btnCancel:Text", "@cancel"); - break; - case YES_NO: - setProperty("btnOk:visible", "True"); - setProperty("btnCancel:visible", "True"); - setProperty("btnOk:Text", "@yes"); - setProperty("btnCancel:Text", "@no"); - break; - default: break; - } + public SuiMessageBox(Player owner, SuiButtons buttons, String title, String prompt) { + super("Script.messageBox", owner, buttons, title, prompt); + } + + public SuiMessageBox(Player owner, SuiButtons buttons, String title, String prompt, String callbackScript, String function) { + super("Script.messageBox", owner, buttons, title, prompt, callbackScript, function); + } + + public SuiMessageBox(Player owner, SuiButtons buttons, String title, String prompt, String callback, ISuiCallback suiCallback) { + super("Script.messageBox", owner, buttons, title, prompt, callback, suiCallback); } public SuiMessageBox(Player owner, String title, String prompt) { - this(owner, MessageBoxType.OK_CANCEL, title, prompt); + this(owner, SuiButtons.OK_CANCEL, title, prompt); } - - public void addOkCancelButtonsCallback(int okEventId, int cancelEventId, ISuiCallback callback) { - List returnParams = new ArrayList(); - returnParams.add("btnOk:Text"); - returnParams.add("btnCancel:Text"); - addCallback(okEventId, "", Trigger.OK, returnParams, callback); - addCallback(cancelEventId, "", Trigger.CANCEL, returnParams, callback); + + @Override + protected void setButtons(SuiButtons buttons) { + switch(buttons) { + case OK_CANCEL: + setOkButtonText(); + setCancelButtonText(); + setShowRevertButton(false); + break; + case YES_NO: + setOkButtonText("@yes"); + setCancelButtonText("@no"); + setShowRevertButton(false); + break; + case YES_NO_CANCEL: + setOkButtonText("@yes"); + setRevertButtonText("@no"); + setCancelButtonText(); + break; + case YES_NO_MAYBE: + setOkButtonText("@yes"); + setRevertButtonText("@maybe"); + setCancelButtonText("@no"); + break; + case YES_NO_ABSTAIN: + setOkButtonText("@yes"); + setCancelButtonText("@no"); + setRevertButtonText("@abstain"); + break; + case RETRY_CANCEL: + setOkButtonText("@retry"); + setCancelButtonText("@cancel"); + setShowRevertButton(false); + break; + case RETRY_ABORT_CANCEL: + setOkButtonText("@abort"); + setCancelButtonText("@cancel"); + setRevertButtonText("@retry"); + break; + case OK: + default: + setOkButtonText(); + setShowRevertButton(false); + setShowCancelButton(false); + break; + } } - - public void addOkButtonCallback(int eventId, ISuiCallback callback) { - List returnParams = new ArrayList(); - returnParams.add("btnOk:Text"); - addCallback(eventId, "", Trigger.OK, returnParams, callback); + + private void setShowRevertButton(boolean shown) { + String value = String.valueOf(shown); + setProperty("btnRevert", "Enabled", value); + setProperty("btnRevert", "Visible", value); } - - public enum MessageBoxType { - OK, - OK_CANCEL, - YES_NO, - DEFAULT; + + private void setRevertButtonText(String text) { + setProperty("btnRevert", "Text", text); } } diff --git a/src/resources/sui/SuiTableWindow.java b/src/resources/sui/SuiTableWindow.java index 2ec4ca424..5b7fa2480 100644 --- a/src/resources/sui/SuiTableWindow.java +++ b/src/resources/sui/SuiTableWindow.java @@ -36,21 +36,69 @@ public class SuiTableWindow extends SuiBaseWindow { private List table; - public SuiTableWindow(Player owner, String title, String prompt) { - super("Script.tablePage", owner, title, prompt); - table = new ArrayList(); + public SuiTableWindow(Player owner, SuiButtons buttons, String title, String prompt, boolean exportBtn) { + super("Script.tablePage", owner, buttons, title, prompt); + table = new ArrayList<>(); - if (prompt == null) - setProperty("comp.Prompt:Visible", "false"); + if (prompt == null || prompt.isEmpty()) + setProperty("comp.Prompt", "Visible", "false"); + + setShowExportButton(false); + + clearDataSource("comp.TablePage.dataTable"); + + } + + @Override + protected void setButtons(SuiButtons buttons) { + switch(buttons) { + case OK_CANCEL: + setOkButtonText(); + setCancelButtonText(); + break; + case OK_CANCEL_ALL: + setOkButtonText(); + setCancelButtonText(); + setShowOtherButton(true, "@all"); + break; + case OK_REFRESH: + setOkButtonText(); + setCancelButtonText("@refresh"); + break; + case OK_REFRESH_CANCEL: + setOkButtonText(); + setCancelButtonText(); + setShowOtherButton(true, "@refresh"); + break; + case YES_NO: + setOkButtonText("@yes"); + setCancelButtonText("@no"); + break; + case REFRESH: + setOkButtonText("@refresh"); + setShowCancelButton(false); + break; + case REFRESH_CANCEL: + setOkButtonText("@refresh"); + setCancelButtonText(); + break; + case OK: + default: + setShowCancelButton(false); + setOkButtonText(); + break; + } } public void addColumn(String columnName, String type) { int index = table.size(); SuiTableColumn column = new SuiTableColumn(); - addTableDataSource("comp.TablePage.dataTable:Name", String.valueOf(index)); - setProperty("comp.TablePage.dataTable." + index + ":Label", columnName); - setProperty("comp.TablePage.dataTable." + index + ":Type", type); + String sIndex = String.valueOf(index); + + addDataSource("comp.TablePage.dataTable", "Name", sIndex); + setProperty("comp.TablePage.dataTable." + sIndex, "Label", columnName); + setProperty("comp.TablePage.dataTable." + sIndex, "Type", type); table.add(column); } @@ -66,20 +114,16 @@ public class SuiTableWindow extends SuiBaseWindow { SuiTableCell cell = new SuiTableCell(cellName, cellObjId); column.getCells().add(cell); - addDataItem("comp.TablePage.dataTable." + columnIndex + ":Name", "data" + cellIndex); - setProperty("comp.TablePage.dataTable." + columnIndex + ".data" + cellIndex + ":Value", cellName); + addDataItem("comp.TablePage.dataTable." + columnIndex, "Name", "data" + cellIndex); + setProperty("comp.TablePage.dataTable." + columnIndex + ".data" + cellIndex, "Value", cellName); } public void addCell(String cellName, int columnIndex) { addCell(cellName, 0, columnIndex); } - - public void showExportButton(boolean show) { - setProperty("btnExport:Visible", String.valueOf(show)); - } - + public void setScrollExtent(int x, int z) { - setProperty("comp.TablePage.header:ScrollExtent", String.valueOf(x) + "," + String.valueOf(z)); + setProperty("comp.TablePage.header", "ScrollExtent", String.valueOf(x) + "," + String.valueOf(z)); } public long getCellId(int column, int row) { @@ -95,7 +139,11 @@ public class SuiTableWindow extends SuiBaseWindow { if (cell == null) return null; else return cell.getValue(); } - + + private void setShowExportButton(boolean show) { + setProperty("btnExport", "Visible", String.valueOf(show)); + } + private static class SuiTableColumn { private List cells; @@ -105,7 +153,7 @@ public class SuiTableWindow extends SuiBaseWindow { } public SuiTableColumn() { - this(new ArrayList()); + this(new ArrayList<>()); } public List getCells() { return this.cells; } diff --git a/src/resources/sui/SuiWindow.java b/src/resources/sui/SuiWindow.java index 0edd7a84e..3b30f8837 100644 --- a/src/resources/sui/SuiWindow.java +++ b/src/resources/sui/SuiWindow.java @@ -29,151 +29,298 @@ package resources.sui; import intents.sui.SuiWindowIntent; import intents.sui.SuiWindowIntent.SuiWindowEvent; +import network.packets.Packet; +import resources.encodables.Encodable; +import resources.player.Player; +import resources.server_info.Log; import java.nio.ByteBuffer; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import network.packets.Packet; -import resources.encodables.Encodable; -import resources.player.Player; - public class SuiWindow implements Encodable { private int id; - private String script; + private String suiScript; private Player owner; private long rangeObjId; private float maxDistance = 0; private List components = new ArrayList<>(); - private Map scriptCallbacks; - private Map javaCallbacks; - - public SuiWindow(String script, Player owner) { - this.script = script; + private Map callbacks; + private Map scriptCallbacks; + private boolean hasSubscriptionComponent = false; + + public SuiWindow() { + } + + public SuiWindow(String suiScript, Player owner) { + this.suiScript = suiScript; this.owner = owner; } public final void clearDataSource(String dataSource) { - SuiComponent component = createComponent((byte) 1); - - component.getNarrowParams().add(dataSource); + SuiComponent component = new SuiComponent(SuiComponent.Type.CLEAR_DATA_SOURCE, dataSource); components.add(component); } - - public final void addChildWidget(String property, String value) { - SuiComponent component = createComponent((byte) 2); - - addNarrowParams(component, property); - - component.getWideParams().add(value); - components.add(component); - } - - public final void setProperty(String property, String value) { - SuiComponent component = createComponent((byte) 3); - - addNarrowParams(component, property); - - component.getWideParams().add(value); - components.add(component); - } - - public final void addDataItem(String name, String value) { - SuiComponent component = createComponent((byte) 4); - - addNarrowParams(component, name); - - component.getWideParams().add(value); - components.add(component); - } - - private void addCallbackComponent(String source, Trigger trigger, List returnParams) { - SuiComponent component = createComponent((byte) 5); - - component.getNarrowParams().add(source); - component.getNarrowParams().add(new String(new byte[] {trigger.getByte()}, Charset.forName("UTF-8"))); - component.getNarrowParams().add("handleSUI"); - - for (String returnParam : returnParams) { - addNarrowParams(component, returnParam); - } - - components.add(component); - } - - public final void addDataSource(String name, String value) { - SuiComponent component = createComponent((byte) 6); - - addNarrowParams(component, name); - - component.getWideParams().add(value); - components.add(component); - } - - public final void clearDataSourceContainer(String dataSource) { - SuiComponent component = createComponent((byte) 7); - - addNarrowParams(component, dataSource); - - components.add(component); - } - - public final void addTableDataSource(String dataSource, String value) { - SuiComponent component = createComponent((byte) 8); - - addNarrowParams(component, dataSource); - - component.getWideParams().add(value); - components.add(component); - } - - public final void addCallback(int eventId, String source, Trigger trigger, List returnParams, ISuiCallback callback) { - addCallbackComponent(source, trigger, returnParams); - - if (javaCallbacks == null) - javaCallbacks = new HashMap<>(); - javaCallbacks.put(eventId, callback); - } - - public final void addCallback(int eventId, String source, Trigger trigger, List returnParams, String callbackScript) { - addCallbackComponent(source, trigger, returnParams); - - if (scriptCallbacks == null) - scriptCallbacks = new HashMap<>(); - scriptCallbacks.put(eventId, callbackScript); - } - private SuiComponent createComponent(byte type) { - SuiComponent component = new SuiComponent(); - component.setType(SuiComponent.Type.valueOf(type)); - - return component; + public final void addChildWidget(String type, String childWidget, String parentWidget) { + SuiComponent component = new SuiComponent(SuiComponent.Type.ADD_CHILD_WIDGET, parentWidget); + + component.addNarrowParam(type); + component.addNarrowParam(childWidget); + + components.add(component); } - - private void addNarrowParams(SuiComponent component, String property) { - for (String s : property.split(":")) { - component.getNarrowParams().add(s); + + public final void setProperty(String widget, String property, String value) { + SuiComponent component = new SuiComponent(SuiComponent.Type.SET_PROPERTY, widget); + + component.addNarrowParam(property); + component.addWideParam(value); + + components.add(component); + } + + public final void addDataItem(String dataSource, String name, String value) { + SuiComponent component = new SuiComponent(SuiComponent.Type.ADD_DATA_ITEM, dataSource); + + component.addNarrowParam(name); + component.addWideParam(value); + + components.add(component); + } + + private void subscribeToEvent(int event, String widgetSource, String callback) { + SuiComponent component = getSubscriptionForEvent(event, widgetSource); + if (component != null) { + Log.i("SuiWindow", "Added event callback %d to %s when the event is already subscribed to, replacing callback to %s", event, widgetSource, callback); + component.getNarrowParams().set(2, callback); + } else { + component = new SuiComponent(SuiComponent.Type.SUBSCRIBE_TO_EVENT, widgetSource); + component.addNarrowParam(getWrappedEventString(event)); + component.addNarrowParam(callback); + + components.add(component); } + if (!hasSubscriptionComponent()) + hasSubscriptionComponent = true; + } + + private void subscribeToPropertyEvent(int event, String widgetSource, String propertyWidget, String propertyName) { + SuiComponent component = getSubscriptionForEvent(event, widgetSource); + if (component != null) { + // This component already has the trigger and source param, just need to add the widget and property + // for client to return the value to the server + component.addNarrowParam(propertyWidget); + component.addNarrowParam(propertyName); + } else { + component = new SuiComponent(SuiComponent.Type.SUBSCRIBE_TO_EVENT, widgetSource); + component.addNarrowParam(getWrappedEventString(event)); + component.addNarrowParam(""); + component.addNarrowParam(propertyWidget); + component.addNarrowParam(propertyName); + components.add(component); + } + if (!hasSubscriptionComponent()) + hasSubscriptionComponent = true; + } + + private void addDataSourceContainer(String dataSourceContainer, String name, String value) { + SuiComponent component = new SuiComponent(SuiComponent.Type.ADD_DATA_SOURCE_CONTAINER, dataSourceContainer); + + component.addNarrowParam(name); + component.addWideParam(value); + + components.add(component); + } + + public final void clearDataSourceContainer(String dataSourceContainer) { + SuiComponent component = new SuiComponent(SuiComponent.Type.CLEAR_DATA_SOURCE_CONTAINER, dataSourceContainer); + components.add(component); + } + + public final void addDataSource(String dataSource, String name, String value) { + SuiComponent component = new SuiComponent(SuiComponent.Type.ADD_DATA_SOURCE, dataSource); + + component.addNarrowParam(name); + component.addWideParam(value); + + components.add(component); + } + + public final void addReturnableProperty(SuiEvent event, String source, String widget, String property) { + subscribeToPropertyEvent(event.getValue(), source, widget, property); + } + + public final void addReturnableProperty(SuiEvent event, String widget, String property) { + addReturnableProperty(event, "", widget, property); + } + + public final void addReturnableProperty(String widget, String property) { + subscribeToPropertyEvent(SuiEvent.OK_PRESSED.getValue(), "", widget, property); + subscribeToPropertyEvent(SuiEvent.CANCEL_PRESSED.getValue(), "", widget, property); + } + + public final void addCallback(SuiEvent event, String source, String name, ISuiCallback callback) { + subscribeToEvent(event.getValue(), source, name); + addJavaCallback(name, callback); + } + + public final void addCallback(SuiEvent event, String name, ISuiCallback callback) { + addCallback(event, "", name, callback); + } + + public final void addCallback(SuiEvent event, String source, String script, String function) { + subscribeToEvent(event.getValue(), source, function); + addScriptCallback(function, script); + } + + public final void addCallback(SuiEvent event, String script, String function) { + addCallback(event, "", script, function); + } + + public final void addCallback(String source, String script, String function) { + subscribeToEvent(SuiEvent.OK_PRESSED.getValue(), source, function); + subscribeToEvent(SuiEvent.CANCEL_PRESSED.getValue(), source, function); + addScriptCallback(function, script); + } + + public final void addCallback(String script, String function) { + addCallback("", script, function); + } + + public final void addCallback(String source, String name, ISuiCallback callback) { + subscribeToEvent(SuiEvent.OK_PRESSED.getValue(), source, name); + subscribeToEvent(SuiEvent.CANCEL_PRESSED.getValue(), source, name); + addJavaCallback(name, callback); + } + + public final void addCallback(String name, ISuiCallback callback) { + addCallback("", name, callback); + } + + public final SuiComponent getSubscriptionForEvent(int event, String widget) { + for (SuiComponent component : components) { + if (component.getType() != SuiComponent.Type.SUBSCRIBE_TO_EVENT) + continue; + + List narrowParams = component.getNarrowParams(); + int eventType = component.getSubscribedToEventType(); + + if (eventType == event && component.getTarget().equals(widget)) + return component; + } + return null; + } + + public final SuiComponent getSubscriptionByIndex(int index) { + int count = 0; + for (SuiComponent component : components) { + if (component.getType() == SuiComponent.Type.SUBSCRIBE_TO_EVENT) { + if (index == count) return component; + else count++; + } + } + return null; + } + + public final void display() { + onDisplayRequest(); + new SuiWindowIntent(owner, this, SuiWindowEvent.NEW).broadcast(); + } + + public final void display(Player player) { + onDisplayRequest(); + new SuiWindowIntent(player, this, SuiWindowEvent.NEW).broadcast(); + } + + public final long getRangeObjId() { + return rangeObjId; + } + + public final void setRangeObjId(long rangeObjId) { + this.rangeObjId = rangeObjId; + } + + public final int getId() { + return id; + } + + public final void setId(int id) { + this.id = id; + } + + public final String getSuiScript() { + return suiScript; + } + + public final Player getOwner() { + return owner; + } + + public final float getMaxDistance() { + return maxDistance; + } + + public final void setMaxDistance(float maxDistance) { + this.maxDistance = maxDistance; + } + + public final List getComponents() { + return components; + } + + public final ISuiCallback getJavaCallback(String name) { + return callbacks != null ? callbacks.get(name) : null; + } + + public final String getCallbackScript(String function) { + return scriptCallbacks != null ? scriptCallbacks.get(function) : null; + } + + public final boolean hasCallbackFunction(String function) { + return scriptCallbacks != null && scriptCallbacks.containsKey(function); + } + + public final boolean hasJavaCallback(String name) { + return callbacks != null && callbacks.containsKey(name); + } + + public final boolean hasSubscriptionComponent() { + return hasSubscriptionComponent; + } + + // Add a simple ok/cancel button subscriptions if no callbacks is assigned so the server is sent a SuiEventNotification when client destroys the page. + // Doing it this way will ensures the server removes the stored SuiWindow from memory. + private void prepare() { + if (hasSubscriptionComponent()) + return; + + subscribeToEvent(SuiEvent.OK_PRESSED.getValue(), "", "handleSUI"); + subscribeToEvent(SuiEvent.CANCEL_PRESSED.getValue(), "", "handleSUI"); + } + + protected void onDisplayRequest() { + prepare(); + } + + private void addJavaCallback(String name, ISuiCallback callback) { + if (callbacks == null) callbacks = new HashMap<>(); + + callbacks.put(name, callback); + } + + private void addScriptCallback(String function, String script) { + if (scriptCallbacks == null) scriptCallbacks = new HashMap<>(); + + scriptCallbacks.put(function, script); + } + + private String getWrappedEventString(int event) { + return new String(new byte[]{(byte) event}); } - - public final void display() { new SuiWindowIntent(owner, this, SuiWindowEvent.NEW).broadcast(); } - public final void display(Player player) { new SuiWindowIntent(player, this, SuiWindowEvent.NEW).broadcast();} - - public final long getRangeObjId() { return rangeObjId; } - public final void setRangeObjId(long rangeObjId) { this.rangeObjId = rangeObjId; } - public final int getId() { return id; } - public final void setId(int id) { this.id = id; } - public final String getScript() { return script; } - public final Player getOwner() { return owner; } - public final float getMaxDistance() { return maxDistance; } - public final void setMaxDistance(float maxDistance) { this.maxDistance = maxDistance; } - public final List getComponents() { return components; } - public final ISuiCallback getJavaCallback(int eventType) { return ((javaCallbacks == null) ? null : javaCallbacks.get(eventType)); } - public final String getScriptCallback(int eventType) { return ((scriptCallbacks == null) ? null : scriptCallbacks.get(eventType)); } @Override public byte[] encode() { @@ -186,9 +333,9 @@ public class SuiWindow implements Encodable { listSize += data.length; } - ByteBuffer data = ByteBuffer.allocate(34 + script.length() + listSize); + ByteBuffer data = ByteBuffer.allocate(34 + suiScript.length() + listSize); Packet.addInt(data, id); - Packet.addAscii(data, script); + Packet.addAscii(data, suiScript); Packet.addList(data, componentData); Packet.addLong(data, rangeObjId); Packet.addFloat(data, maxDistance); @@ -200,28 +347,12 @@ public class SuiWindow implements Encodable { @Override public void decode(ByteBuffer data) { - id = Packet.getInt(data); - script = Packet.getAscii(data); - components = Packet.getList(data, SuiComponent.class); - rangeObjId = Packet.getLong(data); - maxDistance = Packet.getFloat(data); + id = Packet.getInt(data); + suiScript = Packet.getAscii(data); + components = Packet.getList(data, SuiComponent.class); + rangeObjId = Packet.getLong(data); + maxDistance = Packet.getFloat(data); // unk long // unk int } - - public enum Trigger { - UPDATE ((byte) 4), - OK ((byte) 9), - CANCEL ((byte) 10); - - private byte b; - - Trigger(byte b) { - this.b = b; - } - - public byte getByte() { - return b; - } - } } diff --git a/src/services/sui/SuiService.java b/src/services/sui/SuiService.java index 21af9a022..f71e08ae9 100644 --- a/src/services/sui/SuiService.java +++ b/src/services/sui/SuiService.java @@ -27,29 +27,33 @@ ***********************************************************************************/ package services.sui; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; - +import intents.network.GalacticPacketIntent; +import intents.sui.SuiWindowIntent; +import intents.sui.SuiWindowIntent.SuiWindowEvent; import network.packets.Packet; import network.packets.swg.SWGPacket; import network.packets.swg.zone.server_ui.SuiCreatePageMessage; import network.packets.swg.zone.server_ui.SuiEventNotification; -import intents.network.GalacticPacketIntent; -import intents.sui.SuiWindowIntent; -import intents.sui.SuiWindowIntent.SuiWindowEvent; import resources.control.Intent; import resources.control.Service; import resources.player.Player; +import resources.server_info.Log; import resources.sui.ISuiCallback; +import resources.sui.SuiComponent; +import resources.sui.SuiEvent; import resources.sui.SuiWindow; -import services.player.PlayerManager; import utilities.Scripts; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + public class SuiService extends Service { - private Map windows; - + private final Map> windows; + public SuiService() { windows = new ConcurrentHashMap<>(); } @@ -81,10 +85,10 @@ public class SuiService extends Service { return; Packet p = intent.getPacket(); if (p instanceof SWGPacket) - processSwgPacket(intent.getPlayerManager(), player, intent.getGalaxy().getName(), (SWGPacket) p); + processSwgPacket(player, (SWGPacket) p); } - private void processSwgPacket(PlayerManager pm, Player player, String galaxyName, SWGPacket p) { + private void processSwgPacket(Player player, SWGPacket p) { switch(p.getPacketType()) { case SUI_EVENT_NOTIFICATION: if (p instanceof SuiEventNotification) @@ -100,38 +104,85 @@ public class SuiService extends Service { displayWindow(i.getPlayer(), i.getWindow()); } - private void handleSuiEventNotification(Player player, SuiEventNotification r) { - SuiWindow window = windows.get(r.getWindowId()); - - if (window == null) { - System.err.println("Null window id " + r.getWindowId()); + private void handleSuiEventNotification(Player player, SuiEventNotification p) { + List activeWindows = windows.get(player.getNetworkId()); + if (activeWindows == null || activeWindows.size() <= 0) { + Log.i("SuiService:SuiEventNotification", "There are no active windows for %s!", player); return; } + + SuiWindow window = getWindowById(activeWindows, p.getWindowId()); - int eventId = r.getEventId(); - if (window.getJavaCallback(eventId) != null) { - ISuiCallback callback = window.getJavaCallback(eventId); - callback.handleEvent(player, player.getCreatureObject(), eventId, r.getDataStrings()); - } else if (window.getScriptCallback(eventId) != null) { - String callbackScript = window.getScriptCallback(eventId); - Scripts.invoke(callbackScript, "callback", player, player.getCreatureObject(), eventId, r.getDataStrings()); + if (window == null) { + Log.i("SuiService:SuiEventNotification", "Received window ID %i that is not assigned to the player %s", p.getWindowId(), player); + return; } + + SuiComponent component = window.getSubscriptionByIndex(p.getEventIndex()); + + if (component == null) { + Log.i("SuiService:SuiEventNotification", "SuiWindow %s retrieved null subscription from supplied event index %i", window, p.getEventIndex()); + return; + } + + List suiSubscribedProperties = component.getSubscribedProperties(); + + if (suiSubscribedProperties == null) + return; + + List eventNotificationProperties = p.getSubscribedToProperties(); + int eventPropertySize = eventNotificationProperties.size(); + + if (suiSubscribedProperties.size() < eventPropertySize) + return; + + String callback = component.getSubscribeToEventCallback(); + SuiEvent event = SuiEvent.valueOf(component.getSubscribedToEventType()); + + Map parameters = new HashMap<>(); + for (int i = 0; i < eventPropertySize; i++) { + parameters.put(suiSubscribedProperties.get(i), eventNotificationProperties.get(i)); + } + + parameters.forEach((k, v) -> System.out.println("Key: " + k + " | Value: " + v)); + if (window.hasCallbackFunction(callback)) { + String script = window.getCallbackScript(callback); + Scripts.invoke(script, callback, player, player.getCreatureObject(), event, parameters); + } else if (window.hasJavaCallback(callback)) { + ISuiCallback suiCallback = window.getJavaCallback(callback); + suiCallback.handleEvent(player, player.getCreatureObject(), event, parameters); + } + + // Both of these events "closes" the sui window for the client, so we have no need for the server to continue tracking the window. + if (event == SuiEvent.OK_PRESSED || event == SuiEvent.CANCEL_PRESSED) + activeWindows.remove(window); } private void displayWindow(Player player, SuiWindow window) { - int id = createWindowId(new Random()); + int id = createWindowId(); window.setId(id); - + SuiCreatePageMessage packet = new SuiCreatePageMessage(window); player.sendPacket(packet); - - windows.put(id, window); + + long networkId = player.getNetworkId(); + List activeWindows = windows.get(networkId); + if (activeWindows == null) { + activeWindows = new ArrayList<>(); + windows.put(networkId, activeWindows); + } + activeWindows.add(window); } - - private int createWindowId(Random ran) { - int id = ran.nextInt(); - if (windows.containsKey(id)) - return createWindowId(ran); - else return id; + + private SuiWindow getWindowById(List windows, int id) { + for (SuiWindow window : windows) { + if (window.getId() == id) + return window; + } + return null; + } + + public static int createWindowId() { + return (int) (System.currentTimeMillis() % Integer.MAX_VALUE); } } diff --git a/src/utilities/IntentFactory.java b/src/utilities/IntentFactory.java index b370b45a8..d2abf1122 100644 --- a/src/utilities/IntentFactory.java +++ b/src/utilities/IntentFactory.java @@ -1,6 +1,7 @@ package utilities; import intents.sui.SuiWindowIntent; +import network.packets.swg.zone.chat.ChatSystemMessage; import resources.Terrain; import resources.encodables.OutOfBandPackage; import resources.encodables.ProsePackage; @@ -88,6 +89,15 @@ public final class IntentFactory { new ChatBroadcastIntent(target, new ProsePackage("StringId", new StringId(table, key), objects)).broadcast(); } + /** + * Sends a message to just the console chat for the target. + * @param target Player to receive the message + * @param message Message to display in the players chat console. + */ + public void sendConsoleMessage(Player target, String message) { + target.sendPacket(new ChatSystemMessage(ChatSystemMessage.SystemChatType.CHAT, message)); + } + /** * Sends a mail to the receiver with the specified subject, message, from the specified sender. * @param receiver Player receiving the mail. diff --git a/src/utilities/Scripts.java b/src/utilities/Scripts.java index 2a8ff4b54..76c9cd7a3 100644 --- a/src/utilities/Scripts.java +++ b/src/utilities/Scripts.java @@ -48,6 +48,9 @@ public class Scripts { ENGINE.eval("var RadialOption = Java.type('resources.radial.RadialOption')"); ENGINE.eval("var RadialItem = Java.type('resources.radial.RadialItem')"); ENGINE.eval("var Log = Java.type('resources.server_info.Log')"); + ENGINE.eval("var SuiWindow = Java.type('resources.sui.SuiBaseWindow')"); + ENGINE.eval("var SuiButtons = Java.type('resources.sui.SuiButtons')"); + ENGINE.eval("var SuiEvent = Java.type('resources.sui.SuiEvent')"); } catch (ScriptException e) { e.printStackTrace(); }