diff --git a/src/resources/collections/SWGList.java b/src/resources/collections/SWGList.java index cfcc9cd55..d9b350016 100644 --- a/src/resources/collections/SWGList.java +++ b/src/resources/collections/SWGList.java @@ -27,6 +27,14 @@ ***********************************************************************************/ package resources.collections; +import network.packets.swg.zone.baselines.Baseline.BaselineType; +import resources.network.BaselineBuilder.Encodable; +import resources.network.DeltaBuilder; +import resources.objects.SWGObject; +import resources.player.PlayerState; +import utilities.Encoder; +import utilities.Encoder.StringType; + import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.AbstractList; @@ -36,22 +44,12 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; -import network.packets.swg.zone.baselines.Baseline.BaselineType; -import resources.network.BaselineBuilder.Encodable; -import resources.network.DeltaBuilder; -import resources.objects.SWGObject; -import resources.player.PlayerState; -import utilities.ByteUtilities; -import utilities.Encoder; -import utilities.Encoder.StringType; - /** - * Supports a list of elements which automatically sends data as a delta when changed. + * Supports a list of elements which automatically sends data as a delta when changed for baselines. * @author Waverunner * * @param Element that implements {@link Encodable} in order for data to be sent, or a basic type. */ -@SuppressWarnings("unused") public class SWGList extends AbstractList implements Encodable { private static final long serialVersionUID = 1L; @@ -61,8 +59,7 @@ public class SWGList extends AbstractList implements Encodable { private int updateType; private transient int updateCount; private int dataSize; - - private boolean indexed = true; + private boolean noUpdates = false; private StringType strType = StringType.UNSPECIFIED; @@ -72,32 +69,54 @@ public class SWGList extends AbstractList implements Encodable { * and that is to just take the data from this map and put it all together! */ private Map data = new ConcurrentHashMap<>(); - private List list = new CopyOnWriteArrayList(); // thread-safe list + private List list = new CopyOnWriteArrayList<>(); // thread-safe list private LinkedList deltas = new LinkedList<>(); private int deltaSize; - + + /** + * Creates a new {@link SWGList} for the defined baseline with the given view and update. Note that this is an extension of {@link AbstractList} and makes use of {@link java.util.ArrayList} + * @param baseline {@link BaselineType} for this list, should be the same as the parent class this list resides in + * @param view The baseline number this list resides in + * @param updateType The update variable used for sending a delta, it's the operand count that this list resides at within the baseline + */ public SWGList(BaselineType baseline, int view, int updateType) { this.baseline = baseline; this.view = view; this.updateType = updateType; } - - public SWGList(BaselineType baseline, int view, int updateType, boolean indexed) { - this(baseline, view, updateType); - this.indexed = indexed; - } - - public SWGList(BaselineType baseline, int view, int updateType, boolean indexed, StringType strType) { - this (baseline, view, updateType, indexed); + + /** + * Creates a new {@link SWGList} with the given StringType to encode in. Note that this constructor must be used if the elements within the list is a String. + * @param baseline + * @param view + * @param updateType + * @param strType + */ + public SWGList(BaselineType baseline, int view, int updateType, StringType strType) { + this (baseline, view, updateType); this.strType = strType; } - - public SWGList(BaselineType baseline, int view, int updateType, boolean indexed, StringType strType, boolean noUpdates) { - this (baseline, view, updateType, indexed, strType); + + /** + * Creates a ew {@link SWGList} with delta sending either enabled or disabled + * @param baseline + * @param view + * @param updateType + * @param strType + * @param noUpdates + */ + public SWGList(BaselineType baseline, int view, int updateType, StringType strType, boolean noUpdates) { + this (baseline, view, updateType, strType); this.noUpdates = noUpdates; } - + + /** + * Appends the specified element to the end of this list if it doesn't already exist. Once added, the updateCount is incremented by one + * and data for the object is encoded. A add delta is then sent using {@link DeltaBuilder} if noUpdates = false (false by default) + * @param e element to be appended to this list + * @return true if the element was added + */ @Override public boolean add(E e) { updateCount++; @@ -111,6 +130,13 @@ public class SWGList extends AbstractList implements Encodable { return added; } + /** + * Inserts the specified element at the specified position in this list. Shifts the element currently + * at that position (if any) and any subsequent elements to the right (adds one to their indices). + * A add delta is then sent using {@link DeltaBuilder} if noUpdates = false (false by default) + * @param index index at which the specified element is to be inserted + * @param e element to be inserted + */ @Override public void add(int index, E e) { updateCount++; @@ -119,6 +145,14 @@ public class SWGList extends AbstractList implements Encodable { addObjectData(index, e); } + /** + * Replaces the element at the specified position in this list with the specified element. + * A change delta is then sent using {@link DeltaBuilder} if noUpdates = false (false by default). Since this + * sends a change delta, it should only be used for replacing an element, not for adding one. + * @param index index of the element to replace + * @param element + * @return + */ @Override public E set(int index, E element) { // Sends a "change" delta @@ -131,7 +165,8 @@ public class SWGList extends AbstractList implements Encodable { addObjectData(index, element, (byte) 2); return previous; } - + + @Override public E remove(int index) { // Method is also called for remove(E element), just replaced by the index @@ -231,11 +266,11 @@ public class SWGList extends AbstractList implements Encodable { private void createDeltaData(byte[] delta, byte update) { synchronized(deltas) { - byte[] combindedUpdate = new byte[delta.length + 1]; - combindedUpdate[0] = update; - System.arraycopy(delta, 0, combindedUpdate, 1, delta.length); + byte[] combinedUpdate = new byte[delta.length + 1]; + combinedUpdate[0] = update; + System.arraycopy(delta, 0, combinedUpdate, 1, delta.length); deltaSize += delta.length + 1; - deltas.add(combindedUpdate); + deltas.add(combinedUpdate); } } @@ -245,17 +280,16 @@ public class SWGList extends AbstractList implements Encodable { data.put(index, encodedData); dataSize += encodedData.length; - - if (indexed && !noUpdates) { - ByteBuffer buffer = ByteBuffer.allocate(encodedData.length + 2).order(ByteOrder.LITTLE_ENDIAN); - buffer.putShort((short) index); - buffer.put(encodedData); - - byte[] indexedBytes = buffer.array(); - createDeltaData(indexedBytes, update); - } else if (!noUpdates) { - createDeltaData(encodedData, update); - } + + if (noUpdates) + return; + + ByteBuffer buffer = ByteBuffer.allocate(encodedData.length + 2).order(ByteOrder.LITTLE_ENDIAN); + buffer.putShort((short) index); + buffer.put(encodedData); + + byte[] indexedBytes = buffer.array(); + createDeltaData(indexedBytes, update); } private void addObjectData(int index, Object obj) { @@ -267,12 +301,13 @@ public class SWGList extends AbstractList implements Encodable { dataSize -= data.remove(index).length; } - if (indexed && !noUpdates) { - // Only the index is sent for removing data - ByteBuffer buffer = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN); - buffer.putShort((short) index); - createDeltaData(buffer.array(), update); - } + if (noUpdates) + return; + + // Only the index is sent for removing data + ByteBuffer buffer = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN); + buffer.putShort((short) index); + createDeltaData(buffer.array(), update); } // Removes obj size of data without removing it from the data map diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 3e67347ff..6c4f6de33 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -90,10 +90,10 @@ public class CreatureObject extends TangibleObject { private HologramColour hologramColour = HologramColour.DEFAULT; private SWGList baseAttributes = new SWGList(BaselineType.CREO, 1, 2); - private SWGList skills = new SWGList(BaselineType.CREO, 1, 3, false, StringType.ASCII); - private SWGList hamEncumbList = new SWGList(BaselineType.CREO, 4, 2, true); - private SWGList attributes = new SWGList(BaselineType.CREO, 6, 21, true); - private SWGList maxAttributes = new SWGList(BaselineType.CREO, 6, 22, true); + private SWGList skills = new SWGList(BaselineType.CREO, 1, 3, StringType.ASCII); // SWGSet + private SWGList hamEncumbList = new SWGList(BaselineType.CREO, 4, 2); + private SWGList attributes = new SWGList(BaselineType.CREO, 6, 21); + private SWGList maxAttributes = new SWGList(BaselineType.CREO, 6, 22); private SWGList equipmentList = new SWGList(BaselineType.CREO, 6, 23); private SWGList appearanceList = new SWGList(BaselineType.CREO, 6, 33); diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java index a822a50f5..4ee48f211 100644 --- a/src/resources/objects/player/PlayerObject.java +++ b/src/resources/objects/player/PlayerObject.java @@ -49,8 +49,8 @@ public class PlayerObject extends IntangibleObject { private String biography = ""; // PLAY 03 - private SWGList flagsList = new SWGList<>(BaselineType.PLAY, 3, 5, false, StringType.UNSPECIFIED, true); - private SWGList profileFlags = new SWGList<>(BaselineType.PLAY, 3, 6, false, StringType.UNSPECIFIED, true); + private SWGList flagsList = new SWGList<>(BaselineType.PLAY, 3, 5, StringType.UNSPECIFIED, true); + private SWGList profileFlags = new SWGList<>(BaselineType.PLAY, 3, 6, StringType.UNSPECIFIED, true); private String title = ""; private int bornDate = 0; private int playTime = 0; diff --git a/test/resources/collections/SWGListTest.java b/test/resources/collections/SWGListTest.java new file mode 100644 index 000000000..28ded8a6f --- /dev/null +++ b/test/resources/collections/SWGListTest.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * 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.collections; + +import network.packets.swg.zone.baselines.Baseline; +import org.junit.Assert; +import org.junit.Test; +import utilities.Encoder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Created by Waverunner on 6/7/2015 + */ +public class SWGListTest { + + @Test + public void testAdd() throws Exception { + int size = 24; + String[] strings = new String[24]; + for (int i = 0; i < size; i++) { + strings[i] = "test" + String.valueOf(i); + } + + SWGList swgList = new SWGList<>(Baseline.BaselineType.PLAY, 3, 6, Encoder.StringType.ASCII); + long start = System.nanoTime(); + Collections.addAll(swgList, strings); + long end = System.nanoTime(); + + Assert.assertArrayEquals(strings, swgList.toArray()); + System.out.println("SWGList: Took "+ (end-start)/1E6 + "ms to add " + size + " elements"); + + List list = new ArrayList<>(); + long startList = System.nanoTime(); + Collections.addAll(list, strings); + long endList = System.nanoTime(); + + Assert.assertArrayEquals(swgList.toArray(), list.toArray()); + System.out.println("ArrayList: Took "+ (endList-startList)/1E6 + "ms to add " + size + " elements"); + } + + @Test + public void testSet() throws Exception { + + } + + @Test + public void testRemove() throws Exception { + + } + + @Test + public void testEncode() throws Exception { + int size = 24; + String[] strings = new String[24]; + for (int i = 0; i < size; i++) { + strings[i] = "test" + String.valueOf(i); + } + + SWGList swgList = new SWGList<>(Baseline.BaselineType.PLAY, 3, 6, Encoder.StringType.ASCII); + Collections.addAll(swgList, strings); + + long start = System.nanoTime(); + swgList.encode(); + long end = System.nanoTime(); + + System.out.println("SWGList: Took " + (end-start)/1E6 + "ms to encode data"); + + } +} \ No newline at end of file