diff --git a/src/network/packets/Packet.java b/src/network/packets/Packet.java index fce1c99ad..7ef9fac95 100644 --- a/src/network/packets/Packet.java +++ b/src/network/packets/Packet.java @@ -29,6 +29,7 @@ package network.packets; import resources.common.CRC; import resources.encodables.Encodable; +import utilities.Encoder; import java.net.InetAddress; import java.nio.ByteBuffer; @@ -91,6 +92,26 @@ public class Packet { } } + public static void addList(ByteBuffer bb, List list) { + addInt(bb, list.size()); + for (byte[] bytes : list) { + addData(bb, bytes); + } + } + + public static void addList(ByteBuffer bb, List list, Encoder.StringType type) { + addInt(bb, list.size()); + + switch(type) { + case ASCII: for (String s : list) { addAscii(bb, s); } + break; + case UNICODE: for (String s : list) { addUnicode(bb, s); } + break; + default: System.err.println("Cannot encode StringType " + type); + break; + } + } + public static void addBoolean(ByteBuffer bb, boolean b) { bb.put(b ? (byte) 1 : (byte) 0); } @@ -143,10 +164,6 @@ public class Packet { bb.put(data); } - public static void addArray(ByteBuffer bb, byte[] b) { - bb.put(b); - } - public static void addArrayList(ByteBuffer bb, byte[] b) { addShort(bb, b.length); bb.put(b); @@ -237,12 +254,16 @@ public class Packet { * @return Amount of bytes that are read */ public static List getList(ByteBuffer bb, Class type) { - List list = new ArrayList<>(); - int size = getInt(bb); - if (size <= 0) + if (size < 0) { + System.err.println("Read list with size less than zero!"); + return null; + } else if (size == 0) { return new ArrayList<>(); + } + + List list = new ArrayList<>(); try { for (int i = 0; i < size; i++) { @@ -271,6 +292,30 @@ public class Packet { return instance; } + public static List getList(ByteBuffer bb, Encoder.StringType type) { + int size = getInt(bb); + + if (size < 0) { + System.err.println("Read list with size less than zero!"); + return null; + } else if (size == 0) { + return new ArrayList<>(); + } + + List list = new ArrayList<>(); + + switch(type) { + case ASCII: for (int i = 0; i < size; i++) { list.add(getAscii(bb)); } + break; + case UNICODE: for (int i = 0; i < size; i++) { list.add(getUnicode(bb)); } + break; + default: System.err.println("Do not know how to read list of StringType " + type); + break; + } + + return list; + } + public void decode(ByteBuffer data) { data.position(0); this.data = data; diff --git a/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java b/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java index 737913504..56528ac88 100644 --- a/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java +++ b/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java @@ -69,7 +69,7 @@ public class ChatPersistentMessageToServer extends SWGPacket { int dataLength = 31 + message.length()*2+oob.length+subject.length()*2+galaxy.length()+recipient.length(); ByteBuffer data = ByteBuffer.allocate(dataLength); addUnicode(data, message); - addArray(data, oob); + addData(data, oob); addInt(data, counter); addUnicode(data, subject); addAscii(data, "SWG"); diff --git a/src/network/packets/swg/zone/chat/ChatRoomMessage.java b/src/network/packets/swg/zone/chat/ChatRoomMessage.java index 13fb5deab..274ecd663 100644 --- a/src/network/packets/swg/zone/chat/ChatRoomMessage.java +++ b/src/network/packets/swg/zone/chat/ChatRoomMessage.java @@ -66,7 +66,7 @@ public class ChatRoomMessage extends SWGPacket { addEncodable(data, avatar); addInt(data, roomId); addUnicode(data, message); - addArray(data, oob); + addData(data, oob); return data; } } diff --git a/src/network/packets/swg/zone/chat/ChatSystemMessage.java b/src/network/packets/swg/zone/chat/ChatSystemMessage.java index 3732ae37b..9cbb744ee 100644 --- a/src/network/packets/swg/zone/chat/ChatSystemMessage.java +++ b/src/network/packets/swg/zone/chat/ChatSystemMessage.java @@ -85,7 +85,7 @@ public class ChatSystemMessage extends SWGPacket { addUnicode(data, ""); } else { addInt(data, 0); - addArray(data, oobData); + addData(data, oobData); } return data; diff --git a/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java b/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java index 10a8bef7a..a2c64d635 100644 --- a/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java +++ b/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java @@ -28,6 +28,7 @@ package network.packets.swg.zone.server_ui; import network.packets.swg.SWGPacket; +import resources.sui.SuiWindow; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -35,23 +36,13 @@ import java.util.List; public class SuiCreatePageMessage extends SWGPacket { public static final int CRC = getCrc("SuiCreatePageMessage"); + + private SuiWindow window; - private int windowId; - private String scriptName; - private List components; - private long objectId; - private float maxDistance; + public SuiCreatePageMessage() {} - public SuiCreatePageMessage() { - this(0, "", new ArrayList<>(), 0, 0); - } - - public SuiCreatePageMessage(int windowId, String scriptName, List components, long objectId, float maxDistance) { - this.windowId = windowId; - this.scriptName = scriptName; - this.components = components; - this.objectId = objectId; - this.maxDistance = maxDistance; + public SuiCreatePageMessage(SuiWindow window) { + this.window = window; } public SuiCreatePageMessage(ByteBuffer data) { @@ -61,89 +52,15 @@ public class SuiCreatePageMessage extends SWGPacket { public void decode(ByteBuffer data) { if (!super.decode(data, CRC)) return; - windowId = getInt(data); - scriptName = getAscii(data); - int compSize = getInt(data); - components.clear(); - for (int compI = 0; compI < compSize; compI++) { - SuiWindowComponent comp = new SuiWindowComponent(); - comp.setType(getByte(data)); - int wideSize = getInt(data); - for (int wideI = 0; wideI < wideSize; wideI++) - comp.getWideParams().add(getUnicode(data)); - int narrowSize = getInt(data); - for (int narrowI = 0; narrowI < narrowSize; narrowI++) - comp.getNarrowParams().add(getAscii(data)); - components.add(comp); - } - objectId = getLong(data); - maxDistance = getFloat(data); - getLong(data); - getInt(data); + window = getEncodable(data, SuiWindow.class); } public ByteBuffer encode() { - int extraSize = 0; - for (SuiWindowComponent comp : components) { - extraSize += 9; - for (String s : comp.getWideParams()) - extraSize += 4 + s.length()*2; - for (String s : comp.getNarrowParams()) - extraSize += 2 + s.length(); - } - ByteBuffer data = ByteBuffer.allocate(40+scriptName.length()+extraSize); + byte[] windowData = window.encode(); + ByteBuffer data = ByteBuffer.allocate(6 + windowData.length); addShort(data, 2); addInt( data, CRC); - addInt (data, windowId); - addAscii(data, scriptName); - addInt (data, components.size()); - for (SuiWindowComponent comp : components) { - addByte(data, comp.getType()); - addInt (data, comp.getWideParams().size()); - for (String wide : comp.getWideParams()) - addUnicode(data, wide); - addInt (data, comp.getNarrowParams().size()); - for (String narrow : comp.getNarrowParams()) - addAscii(data, narrow); - } - addLong (data, objectId); - addFloat(data, maxDistance); - addLong (data, 0); - addInt (data, 0); + addData(data, windowData); return data; } - - public static class SuiWindowComponent { - - private byte type; - private List narrowParams = new ArrayList(); - private List wideParams = new ArrayList(); - - public byte getType() { - return type; - } - public void setType(byte 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; - } - public void addNarrowParam(String param) { - narrowParams.add(param); - } - public void addWideParam(String param) { - wideParams.add(param); - } - - } - } diff --git a/src/resources/encodables/OutOfBandPackage.java b/src/resources/encodables/OutOfBandPackage.java index 293566b79..0ae149bc0 100644 --- a/src/resources/encodables/OutOfBandPackage.java +++ b/src/resources/encodables/OutOfBandPackage.java @@ -134,7 +134,7 @@ public class OutOfBandPackage implements Encodable, Serializable { Packet.addShort(bb, paddingSize); // Number of bytes for decoding to skip over when reading Packet.addByte(bb, data.getOobType().getType()); Packet.addInt(bb, data.getOobPosition()); - + Packet.addData(bb, base); bb.put(base); for (int i = 0; i < paddingSize; i++) { diff --git a/src/resources/encodables/ProsePackage.java b/src/resources/encodables/ProsePackage.java index e565404e3..c0b0ee2bd 100644 --- a/src/resources/encodables/ProsePackage.java +++ b/src/resources/encodables/ProsePackage.java @@ -208,10 +208,10 @@ public class ProsePackage implements OutOfBandData, Serializable { byte[] otherData = other.encode(); ByteBuffer bb = ByteBuffer.allocate(9 + stringData.length + actorData.length + targetData.length + otherData.length); - Packet.addArray(bb, stringData); - Packet.addArray(bb, actorData); - Packet.addArray(bb, targetData); - Packet.addArray(bb, otherData); + Packet.addData(bb, stringData); + Packet.addData(bb, actorData); + Packet.addData(bb, targetData); + Packet.addData(bb, otherData); Packet.addInt(bb, di); Packet.addFloat(bb, df); Packet.addBoolean(bb, grammarFlag); diff --git a/src/resources/encodables/player/Mail.java b/src/resources/encodables/player/Mail.java index c682237e7..6036eb706 100644 --- a/src/resources/encodables/player/Mail.java +++ b/src/resources/encodables/player/Mail.java @@ -111,7 +111,7 @@ public class Mail implements Encodable, Serializable { ByteBuffer bb = ByteBuffer.allocate(8 + (message.length() * 2) + (subject.length() * 2) + oob.length); Packet.addUnicode(bb, message); Packet.addUnicode(bb, subject); - Packet.addArray(bb, oob); + Packet.addData(bb, oob); return bb.array(); } diff --git a/src/resources/sui/SuiComponent.java b/src/resources/sui/SuiComponent.java new file mode 100644 index 000000000..2e2834ecb --- /dev/null +++ b/src/resources/sui/SuiComponent.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * 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; + +import network.packets.Packet; +import resources.encodables.Encodable; +import utilities.Encoder; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Waverunner + */ +public class SuiComponent implements Encodable { + + public SuiComponent() {} + + public SuiComponent(Type type) { + this.type = type; + } + + private Type type; + private List wideParams = new ArrayList<>(); + private List narrowParams = new ArrayList<>(); + + 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; + } + public void addNarrowParam(String param) { + narrowParams.add(param); + } + public void addWideParam(String param) { + wideParams.add(param); + } + + @Override + public byte[] encode() { + int size = 9; + + for (String param : wideParams) { size += 4 + (param.length() * 2); } + for (String param : narrowParams) { size += 2 + param.length();} + + ByteBuffer bb = ByteBuffer.allocate(size); + Packet.addByte(bb, type.getValue()); + Packet.addList(bb, wideParams, Encoder.StringType.UNICODE); + Packet.addList(bb, narrowParams, Encoder.StringType.ASCII); + + return bb.array(); + } + + @Override + public void decode(ByteBuffer data) { + type = Type.valueOf(Packet.getByte(data)); + wideParams = Packet.getList(data, Encoder.StringType.UNICODE); + narrowParams = Packet.getList(data, Encoder.StringType.ASCII); + } + + public enum Type { + NONE(0), + CLEAR_DATA_SOURCE(1), + ADD_CHILD_WIDGET(2), + SET_PROPERTY(3), + ADD_DATA_ITEM(4), + SUBSCRIBE_TO_EVENT(5), + ADD_DATA_SOURCE_CONTAINER(6), + CLEAR_DATA_SOURCE_CONTAINER(7), + ADD_DATA_SOURCE(8); + + private byte value; + + Type(int value) { + this.value = (byte) value; + } + + public byte getValue() { + return value; + } + + public static Type valueOf(byte value) { + for (Type type : Type.values()) { + if (type.getValue() == value) + return type; + } + return NONE; + } + } +} diff --git a/src/resources/sui/SuiWindow.java b/src/resources/sui/SuiWindow.java index 35d5884fb..0edd7a84e 100644 --- a/src/resources/sui/SuiWindow.java +++ b/src/resources/sui/SuiWindow.java @@ -30,22 +30,25 @@ package resources.sui; import intents.sui.SuiWindowIntent; import intents.sui.SuiWindowIntent.SuiWindowEvent; +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 resources.player.Player; -import network.packets.swg.zone.server_ui.SuiCreatePageMessage.SuiWindowComponent; -public class SuiWindow { +import network.packets.Packet; +import resources.encodables.Encodable; +import resources.player.Player; + +public class SuiWindow implements Encodable { private int id; private String script; private Player owner; private long rangeObjId; private float maxDistance = 0; - private List components = new ArrayList(); + private List components = new ArrayList<>(); private Map scriptCallbacks; private Map javaCallbacks; @@ -55,14 +58,14 @@ public class SuiWindow { } public final void clearDataSource(String dataSource) { - SuiWindowComponent component = createComponent((byte) 1); + SuiComponent component = createComponent((byte) 1); component.getNarrowParams().add(dataSource); components.add(component); } public final void addChildWidget(String property, String value) { - SuiWindowComponent component = createComponent((byte) 2); + SuiComponent component = createComponent((byte) 2); addNarrowParams(component, property); @@ -71,7 +74,7 @@ public class SuiWindow { } public final void setProperty(String property, String value) { - SuiWindowComponent component = createComponent((byte) 3); + SuiComponent component = createComponent((byte) 3); addNarrowParams(component, property); @@ -80,7 +83,7 @@ public class SuiWindow { } public final void addDataItem(String name, String value) { - SuiWindowComponent component = createComponent((byte) 4); + SuiComponent component = createComponent((byte) 4); addNarrowParams(component, name); @@ -88,8 +91,8 @@ public class SuiWindow { components.add(component); } - private final void addCallbackComponent(String source, Trigger trigger, List returnParams) { - SuiWindowComponent component = createComponent((byte) 5); + 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"))); @@ -103,7 +106,7 @@ public class SuiWindow { } public final void addDataSource(String name, String value) { - SuiWindowComponent component = createComponent((byte) 6); + SuiComponent component = createComponent((byte) 6); addNarrowParams(component, name); @@ -112,7 +115,7 @@ public class SuiWindow { } public final void clearDataSourceContainer(String dataSource) { - SuiWindowComponent component = createComponent((byte) 7); + SuiComponent component = createComponent((byte) 7); addNarrowParams(component, dataSource); @@ -120,7 +123,7 @@ public class SuiWindow { } public final void addTableDataSource(String dataSource, String value) { - SuiWindowComponent component = createComponent((byte) 8); + SuiComponent component = createComponent((byte) 8); addNarrowParams(component, dataSource); @@ -132,7 +135,7 @@ public class SuiWindow { addCallbackComponent(source, trigger, returnParams); if (javaCallbacks == null) - javaCallbacks = new HashMap(); + javaCallbacks = new HashMap<>(); javaCallbacks.put(eventId, callback); } @@ -140,18 +143,18 @@ public class SuiWindow { addCallbackComponent(source, trigger, returnParams); if (scriptCallbacks == null) - scriptCallbacks = new HashMap(); + scriptCallbacks = new HashMap<>(); scriptCallbacks.put(eventId, callbackScript); } - private SuiWindowComponent createComponent(byte type) { - SuiWindowComponent component = new SuiWindowComponent(); - component.setType(type); + private SuiComponent createComponent(byte type) { + SuiComponent component = new SuiComponent(); + component.setType(SuiComponent.Type.valueOf(type)); return component; } - private void addNarrowParams(SuiWindowComponent component, String property) { + private void addNarrowParams(SuiComponent component, String property) { for (String s : property.split(":")) { component.getNarrowParams().add(s); } @@ -168,10 +171,44 @@ public class SuiWindow { 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 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() { + + int listSize = 0; + List componentData = new ArrayList<>(); + for (SuiComponent component : components) { + byte[] data = component.encode(); + componentData.add(data); + listSize += data.length; + } + + ByteBuffer data = ByteBuffer.allocate(34 + script.length() + listSize); + Packet.addInt(data, id); + Packet.addAscii(data, script); + Packet.addList(data, componentData); + Packet.addLong(data, rangeObjId); + Packet.addFloat(data, maxDistance); + Packet.addLong(data, 0); // Window Location? + Packet.addInt(data, 0); + + return data.array(); + } + + @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); + // unk long + // unk int + } + public enum Trigger { UPDATE ((byte) 4), OK ((byte) 9), diff --git a/src/services/sui/SuiService.java b/src/services/sui/SuiService.java index 988e13a89..21af9a022 100644 --- a/src/services/sui/SuiService.java +++ b/src/services/sui/SuiService.java @@ -51,7 +51,7 @@ public class SuiService extends Service { private Map windows; public SuiService() { - windows = new ConcurrentHashMap(); + windows = new ConcurrentHashMap<>(); } @Override @@ -118,14 +118,14 @@ public class SuiService extends Service { } } - private void displayWindow(Player player, SuiWindow wnd) { + private void displayWindow(Player player, SuiWindow window) { int id = createWindowId(new Random()); - wnd.setId(id); + window.setId(id); - SuiCreatePageMessage packet = new SuiCreatePageMessage(id, wnd.getScript(), wnd.getComponents(), player.getCreatureObject().getObjectId(), wnd.getMaxDistance()); + SuiCreatePageMessage packet = new SuiCreatePageMessage(window); player.sendPacket(packet); - windows.put(id, wnd); + windows.put(id, window); } private int createWindowId(Random ran) {