diff --git a/.classpath b/.classpath index 16ca8f86e..05e69b75e 100644 --- a/.classpath +++ b/.classpath @@ -6,7 +6,6 @@ - @@ -18,15 +17,13 @@ - - - - - + + + diff --git a/.project b/.project index 0dca9e05c..2a27ec28f 100644 --- a/.project +++ b/.project @@ -5,24 +5,13 @@ - - org.python.pydev.PyDevBuilder - - - org.eclipse.jdt.core.javabuilder - - org.eclipse.m2e.core.maven2Builder - - - - org.eclipse.m2e.core.maven2Nature org.eclipse.jdt.core.javanature org.python.pydev.pythonNature diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 672496e10..13b3428ac 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.8 diff --git a/lib/PSWGCommon.jar b/lib/PSWGCommon.jar index efa0304bc..296b9c56c 100644 Binary files a/lib/PSWGCommon.jar and b/lib/PSWGCommon.jar differ diff --git a/src/network/packets/swg/SWGPacket.java b/src/network/packets/swg/SWGPacket.java index fe80574e5..507d018d5 100644 --- a/src/network/packets/swg/SWGPacket.java +++ b/src/network/packets/swg/SWGPacket.java @@ -54,7 +54,7 @@ public abstract class SWGPacket extends Packet { } public boolean checkDecode(NetBuffer data, int crc) { - data.position(2); + data.getShort(); this.crc = data.getInt(); this.type = PacketType.fromCrc(crc); if (this.crc == crc) diff --git a/src/network/packets/swg/zone/PlayClientEffectObjectMessage.java b/src/network/packets/swg/zone/PlayClientEffectObjectMessage.java index 454b505fd..540879b2b 100644 --- a/src/network/packets/swg/zone/PlayClientEffectObjectMessage.java +++ b/src/network/packets/swg/zone/PlayClientEffectObjectMessage.java @@ -37,7 +37,11 @@ public class PlayClientEffectObjectMessage extends SWGPacket { private String effectFile; private String effectLocation; private long objectId; - + + public PlayClientEffectObjectMessage() { + + } + public PlayClientEffectObjectMessage(String effectFile, String effectLocation, long objectId) { this.effectFile = effectFile; this.effectLocation = effectLocation; diff --git a/src/network/packets/swg/zone/SceneCreateObjectByCrc.java b/src/network/packets/swg/zone/SceneCreateObjectByCrc.java index da872ef6f..bc479c62d 100644 --- a/src/network/packets/swg/zone/SceneCreateObjectByCrc.java +++ b/src/network/packets/swg/zone/SceneCreateObjectByCrc.java @@ -51,6 +51,7 @@ public class SceneCreateObjectByCrc extends SWGPacket { this.hyperspace = hyperspace; } + @Override public void decode(NetBuffer data) { if (!super.checkDecode(data, CRC)) return; @@ -60,6 +61,7 @@ public class SceneCreateObjectByCrc extends SWGPacket { hyperspace = data.getBoolean(); } + @Override public NetBuffer encode() { NetBuffer data = NetBuffer.allocate(47); data.addShort(5); diff --git a/src/network/packets/swg/zone/UpdatePostureMessage.java b/src/network/packets/swg/zone/UpdatePostureMessage.java index 136aba0cd..2944cbed7 100644 --- a/src/network/packets/swg/zone/UpdatePostureMessage.java +++ b/src/network/packets/swg/zone/UpdatePostureMessage.java @@ -52,6 +52,7 @@ public class UpdatePostureMessage extends SWGPacket { this.objId = objId; } + @Override public void decode(NetBuffer data) { if (!super.checkDecode(data, CRC)) return; @@ -59,9 +60,9 @@ public class UpdatePostureMessage extends SWGPacket { objId = data.getLong(); } + @Override public NetBuffer encode() { - int length = 16; - NetBuffer data = NetBuffer.allocate(length); + NetBuffer data = NetBuffer.allocate(15); data.addShort(3); data.addInt(CRC); data.addByte(posture); diff --git a/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java b/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java index e0696b420..29feafd36 100644 --- a/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java +++ b/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java @@ -42,6 +42,10 @@ public class ChatOnEnteredRoom extends SWGPacket { private int chatRoomId; private int sequence; + public ChatOnEnteredRoom() { + + } + public ChatOnEnteredRoom(ChatAvatar avatar, int chatRoomId, int sequence) { this(avatar, ChatResult.NONE, chatRoomId, sequence); } @@ -57,6 +61,7 @@ public class ChatOnEnteredRoom extends SWGPacket { decode(data); } + @Override public void decode(NetBuffer data) { if (!super.checkDecode(data, CRC)) return; @@ -66,6 +71,7 @@ public class ChatOnEnteredRoom extends SWGPacket { sequence = data.getInt(); } + @Override public NetBuffer encode() { NetBuffer data = NetBuffer.allocate(avatar.getLength() + 18); data.addShort(5); diff --git a/src/network/packets/swg/zone/chat/ChatSystemMessage.java b/src/network/packets/swg/zone/chat/ChatSystemMessage.java index c48fe796f..d1ad04d09 100644 --- a/src/network/packets/swg/zone/chat/ChatSystemMessage.java +++ b/src/network/packets/swg/zone/chat/ChatSystemMessage.java @@ -33,14 +33,15 @@ import network.packets.swg.SWGPacket; import resources.encodables.OutOfBandPackage; public class ChatSystemMessage extends SWGPacket { + public static final int CRC = getCrc("ChatSystemMessage"); - - private int type = 0; - private String message = ""; + private OutOfBandPackage oob; + private String message; + private int type; public ChatSystemMessage() { - + this(0, ""); } public ChatSystemMessage(int type, String message) { @@ -54,11 +55,11 @@ public class ChatSystemMessage extends SWGPacket { } public ChatSystemMessage(SystemChatType type, String message) { - this(type.ordinal(), message); + this(type.getType(), message); } public ChatSystemMessage(SystemChatType type, OutOfBandPackage oob) { - this(type.ordinal(), oob); + this(type.getType(), oob); } @Override @@ -78,7 +79,7 @@ public class ChatSystemMessage extends SWGPacket { if (oobExists) length += 4 + oob.getLength(); else - length += 15 + message.length() * 2; + length += 8 + message.length() * 2; NetBuffer data = NetBuffer.allocate(length); data.addShort(4); @@ -96,16 +97,35 @@ public class ChatSystemMessage extends SWGPacket { } public SystemChatType getType() { - for (SystemChatType t : SystemChatType.values()) { - if (type == t.ordinal()) return t; + switch (type) { + case 0: + default: + return SystemChatType.SCREEN_AND_CHAT; + case 1: + return SystemChatType.SCREEN; + case 2: + return SystemChatType.CHAT; } - return SystemChatType.SCREEN_AND_CHAT; } - public String getMessage() { return message; } + + public String getMessage() { + return message; + } public enum SystemChatType { - SCREEN_AND_CHAT, - SCREEN, - CHAT + SCREEN_AND_CHAT (0x00), + SCREEN (0x01), + CHAT (0x02); + + int type; + + SystemChatType(int type) { + this.type = type; + } + + public int getType() { + return type; + } } + } diff --git a/src/network/packets/swg/zone/deltas/DeltasMessage.java b/src/network/packets/swg/zone/deltas/DeltasMessage.java index d4e8281e6..4961c2d8b 100644 --- a/src/network/packets/swg/zone/deltas/DeltasMessage.java +++ b/src/network/packets/swg/zone/deltas/DeltasMessage.java @@ -42,9 +42,14 @@ public class DeltasMessage extends SWGPacket { private byte[] deltaData; private int update; + public DeltasMessage() { + + } + public DeltasMessage(long objId, BaselineType type, int typeNumber, int update, byte[] data) { this.objId = objId; this.type = type; + this.update = update; this.num = typeNumber; this.deltaData = data; } @@ -58,12 +63,12 @@ public class DeltasMessage extends SWGPacket { if (!super.checkDecode(data, CRC)) return; objId = data.getLong(); - type = BaselineType.valueOf(new StringBuffer(new String(data.getArray(4), ascii)).reverse().toString()); + type = BaselineType.valueOf(reverse(new String(data.getArray(4), ascii))); num = data.getByte(); NetBuffer deltaDataBuffer = NetBuffer.wrap(data.getArrayLarge()); deltaDataBuffer.getShort(); update = deltaDataBuffer.getShort(); - deltaData = data.getArray(deltaDataBuffer.remaining()); + deltaData = deltaDataBuffer.getArray(deltaDataBuffer.remaining()); } @Override @@ -72,7 +77,7 @@ public class DeltasMessage extends SWGPacket { data.addShort(5); data.addInt(CRC); data.addLong(objId); - data.addRawArray(new StringBuffer(type.toString()).reverse().toString().getBytes(ascii)); + data.addRawArray(reverse(type.toString()).getBytes(ascii)); data.addByte(num); data.addInt(deltaData.length + 4); data.addShort(1); // updates - only 1 cause we're boring @@ -120,4 +125,8 @@ public class DeltasMessage extends SWGPacket { public void setUpdate(int update) { this.update = update; } + + private String reverse(String str) { + return new StringBuffer(str).reverse().toString(); + } } diff --git a/src/network/packets/swg/zone/insertion/ChatRoomList.java b/src/network/packets/swg/zone/insertion/ChatRoomList.java index 36fb1af5b..ef836d9f2 100644 --- a/src/network/packets/swg/zone/insertion/ChatRoomList.java +++ b/src/network/packets/swg/zone/insertion/ChatRoomList.java @@ -27,6 +27,7 @@ ***********************************************************************************/ package network.packets.swg.zone.insertion; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -41,6 +42,10 @@ public class ChatRoomList extends SWGPacket { private Collection rooms; + public ChatRoomList() { + this.rooms = new ArrayList<>(); + } + public ChatRoomList(ChatRoom... rooms) { this.rooms = Arrays.asList(rooms); } diff --git a/src/network/packets/swg/zone/object_controller/ObjectController.java b/src/network/packets/swg/zone/object_controller/ObjectController.java index dd12e956c..f806ec47b 100644 --- a/src/network/packets/swg/zone/object_controller/ObjectController.java +++ b/src/network/packets/swg/zone/object_controller/ObjectController.java @@ -91,8 +91,10 @@ public abstract class ObjectController extends SWGPacket { public static final ObjectController decodeController(NetBuffer data) { if (data.array().length < 14) return null; - data.position(10); + int pos = data.position(); + data.position(pos+10); int crc = data.getInt(); + data.position(pos); switch (crc) { case 0x0071: return new DataTransform(data); case 0x00CC: return new CombatAction(data); diff --git a/src/resources/config/ConfigFile.java b/src/resources/config/ConfigFile.java index 483201674..df1850ea5 100644 --- a/src/resources/config/ConfigFile.java +++ b/src/resources/config/ConfigFile.java @@ -36,7 +36,9 @@ public enum ConfigFile { /** Meant for networking-related configuration. Includes Login and Zone configuration */ NETWORK ("cfg/network.cfg"), /** Meant for specific in-game features that may be better disabled or tweaked */ - FEATURES("cfg/features.cfg"); + FEATURES("cfg/features.cfg"), + /** Meant for debug features to help fix problems in-game */ + DEBUG("cfg/debug.cfg"); private static final Map NAMEMAP = new HashMap<>(); private String filename; diff --git a/src/resources/network/BaselineObject.java b/src/resources/network/BaselineObject.java index 84903a2bd..5273530cf 100644 --- a/src/resources/network/BaselineObject.java +++ b/src/resources/network/BaselineObject.java @@ -33,13 +33,17 @@ import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.List; +import com.projectswg.common.debug.Log; import com.projectswg.common.encoding.StringType; import com.projectswg.common.network.NetBuffer; +import com.projectswg.common.utilities.ByteUtilities; import network.packets.swg.zone.baselines.Baseline; import network.packets.swg.zone.baselines.Baseline.BaselineType; +import resources.config.ConfigFile; import resources.objects.SWGObject; import resources.player.Player; +import resources.server_info.DataManager; public class BaselineObject { @@ -182,7 +186,9 @@ public class BaselineObject { baselineData.set(type-1, null); } DeltaBuilder builder = new DeltaBuilder((SWGObject) this, this.type, type, update, value); - builder.send(); + boolean sent = builder.send(); + if (sent && isDeltaLogging()) + Log.v("Delta [type=%d, update=%d, value=%s] = %s", type, update, value, ByteUtilities.getHexString(builder.getEncodedData())); } public final void sendDelta(int type, int update, Object value, StringType strType) { @@ -191,7 +197,13 @@ public class BaselineObject { baselineData.set(type-1, null); } DeltaBuilder builder = new DeltaBuilder((SWGObject) this, this.type, type, update, value, strType); - builder.send(); + boolean sent = builder.send(); + if (sent && isDeltaLogging()) + Log.v("Delta %s: [type=%d, update=%d, value=%s, strType=%s] = %s", this, type, update, value, strType, ByteUtilities.getHexString(builder.getEncodedData())); + } + + private boolean isDeltaLogging() { + return DataManager.getConfig(ConfigFile.DEBUG).getBoolean("DEBUG-DELTA-LOGGING", false); } private Baseline createBaseline(Player target, int num, BaselineCreator bc) { diff --git a/src/resources/network/DeltaBuilder.java b/src/resources/network/DeltaBuilder.java index 57ce29afa..c23ba6d05 100644 --- a/src/resources/network/DeltaBuilder.java +++ b/src/resources/network/DeltaBuilder.java @@ -60,17 +60,26 @@ public class DeltaBuilder { this.updateType = updateType; } - public void send() { + public boolean send() { DeltasMessage message = getBuiltMessage(); Player owner = object.getOwner(); - if (owner != null && owner.getPlayerState() == PlayerState.ZONED_IN) + boolean sent = false; + if (owner != null && owner.getPlayerState() == PlayerState.ZONED_IN) { owner.sendPacket(message); - if (num == 3 || num == 6) // Shared Objects - object.sendObservers(message); + sent = true; + } + if (num == 3 || num == 6) { // Shared Objects + sent = object.sendObservers(message) > 0 || sent; + } + return sent; } public DeltasMessage getBuiltMessage() { return new DeltasMessage(object.getObjectId(), type, num, updateType, data); } + public byte [] getEncodedData() { + return data; + } + } diff --git a/src/resources/network/TCPServer.java b/src/resources/network/TCPServer.java deleted file mode 100644 index 282d5655c..000000000 --- a/src/resources/network/TCPServer.java +++ /dev/null @@ -1,294 +0,0 @@ -/*********************************************************************************** -* 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.network; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.AsynchronousCloseException; -import java.nio.channels.ClosedByInterruptException; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.SelectableChannel; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import com.projectswg.common.debug.Log; - -import utilities.ThreadUtilities; - - -public class TCPServer { - - private final ExecutorService callbackExecutor; - private final Map sockets; - private final InetAddress addr; - private final int port; - private final int bufferSize; - private final TCPListener listener; - private ServerSocketChannel channel; - private NetworkCallback callback; - - public TCPServer(int port, int bufferSize) { - this(null, port, bufferSize); - } - - public TCPServer(InetAddress addr, int port, int bufferSize) { - this.callbackExecutor = Executors.newSingleThreadExecutor(ThreadUtilities.newThreadFactory("tcp-server-callback-executor")); - this.sockets = new HashMap<>(); - this.addr = addr; - this.port = port; - this.bufferSize = bufferSize; - this.listener = new TCPListener(); - this.channel = null; - } - - public void bind() throws IOException { - channel = ServerSocketChannel.open(); - channel.socket().bind(new InetSocketAddress(addr, port)); - channel.configureBlocking(false); - listener.start(); - } - - public SocketChannel connectTo(InetAddress addr, int port) throws IOException { - return connectTo(new InetSocketAddress(addr, port)); - } - - public SocketChannel connectTo(InetSocketAddress sock) throws IOException { - synchronized (sockets) { - SocketChannel sc = sockets.get(sock); - if (sc == null || (!sc.isConnected() && !sc.isConnectionPending())) { - sc = SocketChannel.open(sock); - sc.configureBlocking(false); - sockets.put(sock, sc); - } - return sc; - } - } - - public boolean disconnect(SocketAddress sock) { - synchronized (sockets) { - SocketChannel sc = sockets.get(sock); - if (sc == null) - return false; - sockets.remove(sock); - try { - Socket s = sc.socket(); - sc.close(); - if (callback != null) - callbackExecutor.execute(() -> callback.onConnectionDisconnect(s, sock)); - return true; - } catch (IOException e) { - Log.e(e); - return false; - } - } - } - - private boolean disconnect(SocketChannel sc) { - try { - return disconnect(sc.getRemoteAddress()); - } catch (IOException e) { - return false; - } - } - - public boolean close() { - listener.stop(); - callbackExecutor.shutdown(); - try { - if (channel != null) - channel.close(); - return true; - } catch (IOException e) { - Log.e(e); - } - return false; - } - - public boolean send(InetSocketAddress sock, ByteBuffer data) { - synchronized (sockets) { - SocketChannel sc = sockets.get(sock); - try { - if (sc != null && sc.isConnected()) { - while (data.hasRemaining()) - sc.write(data); - return true; - } - } catch (IOException e) { - Log.e("Terminated connection with %s. Error: %s", sock.toString(), e.getMessage()); - disconnect(sc); - } - } - return false; - } - - public void setCallback(NetworkCallback callback) { - this.callback = callback; - } - - private class TCPListener implements Runnable { - - private final ByteBuffer buffer; - private Thread thread; - private boolean running; - - public TCPListener() { - buffer = ByteBuffer.allocateDirect(bufferSize); - running = false; - thread = null; - } - - public void start() { - running = true; - thread = new Thread(this); - thread.start(); - } - - public void stop() { - running = false; - if (thread != null) - thread.interrupt(); - thread = null; - } - - public void run() { - try (Selector selector = setupSelector()) { - while (running) { - try { - selector.select(); - processSelectionKeys(selector); - } catch (Exception e) { - Log.e(e); - try { - Thread.sleep(100); - } catch (InterruptedException e1) { - break; - } - } - } - } catch (IOException e) { - Log.e(e); - } - } - - private Selector setupSelector() throws IOException { - Selector selector = Selector.open(); - channel.register(selector, SelectionKey.OP_ACCEPT); - return selector; - } - - private void processSelectionKeys(Selector selector) throws ClosedChannelException { - for (SelectionKey key : selector.selectedKeys()) { - if (!key.isValid()) - continue; - if (key.isAcceptable()) { - accept(selector); - } else if (key.isReadable()) { - SelectableChannel selectable = key.channel(); - if (selectable instanceof SocketChannel) { - boolean canRead = true; - while (canRead) - canRead = read(key, (SocketChannel) selectable); - } - } - } - } - - private void accept(Selector selector) { - try { - while (channel.isOpen()) { - SocketChannel sc = channel.accept(); - if (sc == null) - break; - sc.socket().setKeepAlive(true); - sc.socket().setPerformancePreferences(0, 1, 2); - sc.socket().setTrafficClass(0x10); // Low Delay bit - SocketChannel old = sockets.get(sc.getRemoteAddress()); - if (old != null) - disconnect(old); - sockets.put(sc.getRemoteAddress(), sc); - sc.configureBlocking(false); - sc.register(selector, SelectionKey.OP_READ); - if (callback != null) { - SocketAddress address = sc.getRemoteAddress(); - callbackExecutor.execute(() -> callback.onIncomingConnection(sc.socket(), address)); - } - } - } catch (AsynchronousCloseException e) { - - } catch (IOException e) { - Log.a(e); - } - } - - private boolean read(SelectionKey key, SocketChannel s) { - try { - buffer.position(0); - buffer.limit(bufferSize); - int n = s.read(buffer); - buffer.flip(); - if (n < 0) { - key.cancel(); - disconnect(s); - } else if (n > 0) { - ByteBuffer smaller = ByteBuffer.allocate(n); - smaller.put(buffer); - if (callback != null) { - SocketAddress address = s.getRemoteAddress(); - callbackExecutor.execute(() -> callback.onIncomingData(s.socket(), address, smaller.array())); - } - return true; - } - } catch (ClosedByInterruptException e) { - key.cancel(); - disconnect(s); - stop(); - } catch (IOException e) { - if (e.getMessage() != null && e.getMessage().toLowerCase(Locale.US).contains("connection reset")) - Log.e("Connection Reset with %s", s.socket().getRemoteSocketAddress()); - else { - Log.e(e); - } - key.cancel(); - disconnect(s); - } - return false; - } - } - -} diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index 6b20c5228..27720d9e8 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -644,8 +644,6 @@ public abstract class SWGObject extends BaselineObject implements Comparable SWGObjectFactory.save(c, stream)); } + @Override public void read(NetBufferStream stream) { switch(stream.getByte()) { case 4: diff --git a/src/services/chat/ChatManager.java b/src/services/chat/ChatManager.java index 491b8c94f..762094cae 100644 --- a/src/services/chat/ChatManager.java +++ b/src/services/chat/ChatManager.java @@ -310,16 +310,16 @@ public class ChatManager extends Manager { } private void broadcastAreaMessage(String message, Player broadcaster) { - broadcaster.getCreatureObject().sendObserversAndSelf(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.ordinal(), message)); + broadcaster.getCreatureObject().sendObserversAndSelf(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.getType(), message)); } private void broadcastPlanetMessage(String message, Terrain terrain) { - ChatSystemMessage packet = new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.ordinal(), message); + ChatSystemMessage packet = new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.getType(), message); new NotifyPlayersPacketIntent(packet, terrain).broadcast(); } private void broadcastGalaxyMessage(String message) { - ChatSystemMessage packet = new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.ordinal(), message); + ChatSystemMessage packet = new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.getType(), message); new NotifyPlayersPacketIntent(packet).broadcast(); } diff --git a/src/services/chat/ChatRoomService.java b/src/services/chat/ChatRoomService.java index b86e79857..d778929c2 100644 --- a/src/services/chat/ChatRoomService.java +++ b/src/services/chat/ChatRoomService.java @@ -374,7 +374,7 @@ public class ChatRoomService extends Service { } private void handleChatRoomListRequest(Player player) { - player.sendPacket(new ChatRoomList(chatRoomHandler.getRoomList(player))); + player.sendPacket(new ChatRoomList()); } } diff --git a/src/services/network/NetworkClientManager.java b/src/services/network/NetworkClientManager.java index cc35a04be..f5d2ae5ae 100644 --- a/src/services/network/NetworkClientManager.java +++ b/src/services/network/NetworkClientManager.java @@ -30,13 +30,15 @@ package services.network; import java.io.IOException; import java.net.BindException; import java.net.InetAddress; -import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; +import java.nio.channels.SocketChannel; import com.projectswg.common.control.Manager; import com.projectswg.common.debug.Log; import com.projectswg.common.network.NetBuffer; +import com.projectswg.common.network.TCPServer; +import com.projectswg.common.network.TCPServer.TCPCallback; import intents.network.CloseConnectionIntent; import main.ProjectSWG.CoreException; @@ -44,8 +46,6 @@ import network.AdminNetworkClient; import network.NetworkClient; import network.packets.swg.holo.HoloConnectionStopped.ConnectionStoppedReason; import resources.config.ConfigFile; -import resources.network.NetworkCallback; -import resources.network.TCPServer; import resources.network.UDPServer; import resources.network.UDPServer.UDPPacket; import resources.server_info.DataManager; @@ -151,7 +151,7 @@ public class NetworkClientManager extends Manager { udpServer.send(port, addr, data.array()); } - private class StandardNetworkCallback implements NetworkCallback { + private class StandardNetworkCallback implements TCPCallback { private final PacketSender sender; @@ -160,7 +160,7 @@ public class NetworkClientManager extends Manager { } @Override - public void onIncomingConnection(Socket s, SocketAddress addr) { + public void onIncomingConnection(SocketChannel s, SocketAddress addr) { NetworkClient client = clientManager.createSession(addr, sender); client.onConnected(); inboundManager.onSessionCreated(client); @@ -168,7 +168,7 @@ public class NetworkClientManager extends Manager { } @Override - public void onConnectionDisconnect(Socket s, SocketAddress addr) { + public void onConnectionDisconnect(SocketChannel s, SocketAddress addr) { NetworkClient client = clientManager.getClient(addr); if (client != null) { client.onDisconnected(ConnectionStoppedReason.APPLICATION); @@ -180,13 +180,13 @@ public class NetworkClientManager extends Manager { } @Override - public void onIncomingData(Socket s, SocketAddress addr, byte [] data) { + public void onIncomingData(SocketChannel s, SocketAddress addr, byte [] data) { inboundManager.onInboundData(addr, data); } } - private class AdminNetworkCallback implements NetworkCallback { + private class AdminNetworkCallback implements TCPCallback { private final PacketSender sender; @@ -195,7 +195,7 @@ public class NetworkClientManager extends Manager { } @Override - public void onIncomingConnection(Socket s, SocketAddress addr) { + public void onIncomingConnection(SocketChannel s, SocketAddress addr) { NetworkClient client = clientManager.createAdminSession(addr, sender); client.onConnected(); inboundManager.onSessionCreated(client); @@ -203,7 +203,7 @@ public class NetworkClientManager extends Manager { } @Override - public void onConnectionDisconnect(Socket s, SocketAddress addr) { + public void onConnectionDisconnect(SocketChannel s, SocketAddress addr) { NetworkClient client = clientManager.getClient(addr); if (client != null) { client.onDisconnected(ConnectionStoppedReason.APPLICATION); @@ -215,7 +215,7 @@ public class NetworkClientManager extends Manager { } @Override - public void onIncomingData(Socket s, SocketAddress addr, byte [] data) { + public void onIncomingData(SocketChannel s, SocketAddress addr, byte [] data) { inboundManager.onInboundData(addr, data); } diff --git a/src/services/network/NetworkProtocol.java b/src/services/network/NetworkProtocol.java index 07e7abec7..60cd52afb 100644 --- a/src/services/network/NetworkProtocol.java +++ b/src/services/network/NetworkProtocol.java @@ -30,6 +30,7 @@ package services.network; import java.io.EOFException; import com.projectswg.common.debug.Assert; +import com.projectswg.common.debug.Log; import com.projectswg.common.network.NetBuffer; import com.projectswg.common.network.NetBufferStream; @@ -43,7 +44,9 @@ public class NetworkProtocol { public NetBuffer encode(Packet p) { NetBuffer encoded = p.encode(); - encoded.position(0); + encoded.flip(); + if (encoded.remaining() != encoded.capacity()) + Log.w("Packet %s has invalid array length. Expected: %d Actual: %d", p, encoded.remaining(), encoded.capacity()); int decompressedLength = encoded.remaining(); boolean compressed = false; if (compressed) { @@ -106,7 +109,7 @@ public class NetworkProtocol { data.addByte(bitmask); data.addShort((short) packet.remaining()); data.addShort((short) rawLength); - data.addRawArray(packet.array()); + data.add(packet); data.flip(); return data; } @@ -118,7 +121,7 @@ public class NetworkProtocol { buffer.getShort(); int crc = buffer.getInt(); buffer.position(0); - if (crc == 0x80CE5E46) { + if (crc == ObjectController.CRC) { return ObjectController.decodeController(buffer); } else { SWGPacket packet = PacketType.getForCrc(crc); diff --git a/src/services/network/OutboundNetworkManager.java b/src/services/network/OutboundNetworkManager.java index db2625ed1..233972b55 100644 --- a/src/services/network/OutboundNetworkManager.java +++ b/src/services/network/OutboundNetworkManager.java @@ -29,10 +29,10 @@ package services.network; import com.projectswg.common.control.Service; import com.projectswg.common.debug.Assert; +import com.projectswg.common.network.TCPServer; import intents.network.OutboundPacketIntent; import network.NetworkClient; -import resources.network.TCPServer; public class OutboundNetworkManager extends Service { diff --git a/src/services/network/PacketSender.java b/src/services/network/PacketSender.java index 327b9bcbb..b62cf1b00 100644 --- a/src/services/network/PacketSender.java +++ b/src/services/network/PacketSender.java @@ -27,13 +27,14 @@ ***********************************************************************************/ package services.network; +import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.nio.channels.SocketChannel; import com.projectswg.common.debug.Log; import com.projectswg.common.network.NetBuffer; - -import resources.network.TCPServer; +import com.projectswg.common.network.TCPServer; public class PacketSender { @@ -51,7 +52,18 @@ public class PacketSender { } public void sendPacket(InetSocketAddress addr, NetBuffer data) { - tcpServer.send(addr, data.getBuffer()); + SocketChannel sc = tcpServer.getChannel(addr); + if (sc == null) + return; + try { + while (data.hasRemaining()) { + sc.write(data.getBuffer()); + } + } catch (IOException e) { + Log.e("Failed to write to channel: %s", addr); + Log.e(e); + tcpServer.disconnect(addr); + } } } diff --git a/src/services/objects/ObjectAwareness.java b/src/services/objects/ObjectAwareness.java index f329b0c41..9a87421a6 100644 --- a/src/services/objects/ObjectAwareness.java +++ b/src/services/objects/ObjectAwareness.java @@ -271,7 +271,7 @@ public class ObjectAwareness extends Service implements TerrainMapCallback { private void handleDataTransform(DataTransform dt, ObjectManager objectManager) { SWGObject obj = objectManager.getObjectById(dt.getObjectId()); - Assert.test(obj instanceof CreatureObject); + Assert.test(obj instanceof CreatureObject, "DataTransform object not CreatureObject! Was: " + (obj==null?"null":obj.getClass())); Location requestedLocation = new Location(dt.getLocation()); requestedLocation.setTerrain(obj.getTerrain()); moveObjectWithTransform(obj, null, requestedLocation, dt.getSpeed(), dt.getUpdateCounter()); @@ -280,7 +280,7 @@ public class ObjectAwareness extends Service implements TerrainMapCallback { private void handleDataTransformWithParent(DataTransformWithParent dt, ObjectManager objectManager) { SWGObject obj = objectManager.getObjectById(dt.getObjectId()); SWGObject parent = objectManager.getObjectById(dt.getCellId()); - Assert.test(obj instanceof CreatureObject); + Assert.test(obj instanceof CreatureObject, "DataTransformWithParent object not CreatureObject! Was: " + (obj==null?"null":obj.getClass())); if (parent == null) { Log.w("Unknown data transform parent! Obj: %d/%s Parent: %d", dt.getObjectId(), obj, dt.getCellId()); return; diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java index 394867a58..6906d5434 100644 --- a/src/services/objects/ObjectManager.java +++ b/src/services/objects/ObjectManager.java @@ -29,21 +29,15 @@ package services.objects; import java.util.Hashtable; import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import com.projectswg.common.control.Manager; import com.projectswg.common.debug.Log; -import intents.RequestZoneInIntent; import intents.network.GalacticPacketIntent; import intents.object.DestroyObjectIntent; import intents.object.ObjectCreatedIntent; import network.packets.Packet; -import network.packets.swg.ErrorMessage; -import network.packets.swg.zone.insertion.SelectCharacter; import network.packets.swg.zone.object_controller.IntendedTarget; import resources.objects.SWGObject; import resources.objects.building.BuildingObject; @@ -51,12 +45,10 @@ import resources.objects.cell.CellObject; import resources.objects.creature.CreatureObject; import resources.objects.custom.AIObject; import resources.persistable.SWGObjectFactory; -import resources.player.Player; import resources.server_info.CachedObjectDatabase; import resources.server_info.ObjectDatabase; import resources.server_info.StandardLog; import services.map.MapManager; -import services.player.PlayerManager; import services.spawn.SpawnerService; import services.spawn.StaticService; @@ -217,11 +209,7 @@ public class ObjectManager extends Manager { private void processGalacticPacketIntent(GalacticPacketIntent gpi) { Packet packet = gpi.getPacket(); - if (packet instanceof SelectCharacter) { - PlayerManager pm = gpi.getPlayerManager(); - long characterId = ((SelectCharacter) packet).getCharacterId(); - zoneInCharacter(pm, gpi.getPlayer(), characterId); - } else if (packet instanceof IntendedTarget) { + if (packet instanceof IntendedTarget) { IntendedTarget intendedTarget = (IntendedTarget) packet; CreatureObject creatureObject = gpi.getPlayer().getCreatureObject(); long targetId = intendedTarget.getTargetId(); @@ -266,36 +254,4 @@ public class ObjectManager extends Manager { return object; } - private void zoneInCharacter(PlayerManager playerManager, Player player, long characterId) { - SWGObject creatureObj = getObjectById(characterId); - if (creatureObj == null) { - Log.e("Failed to start zone - CreatureObject could not be fetched from database [Character: %d User: %s]", characterId, player.getUsername()); - sendClientFatal(player, "Failed to zone", "You were not found in the database\nTry relogging to fix this problem", 10, TimeUnit.SECONDS); - return; - } - if (!(creatureObj instanceof CreatureObject)) { - Log.e("Failed to start zone - Object is not a CreatureObject [Character: %d User: %s]", characterId, player.getUsername()); - sendClientFatal(player, "Failed to zone", "There has been an internal server error: Not a Creature.\nPlease delete your character and create a new one", 10, TimeUnit.SECONDS); - return; - } - if (((CreatureObject) creatureObj).getPlayerObject() == null) { - Log.e("Failed to start zone - CreatureObject doesn't have a ghost [Character: %d User: %s", characterId, player.getUsername()); - sendClientFatal(player, "Failed to zone", "There has been an internal server error: Null Ghost.\nPlease delete your character and create a new one", 10, TimeUnit.SECONDS); - return; - } - new RequestZoneInIntent(player, (CreatureObject) creatureObj).broadcast(); - } - - private void sendClientFatal(Player player, String title, String message, long timeToRead, TimeUnit time) { - player.sendPacket(new ErrorMessage(title, message, false)); - ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); - service.schedule(new Runnable() { - @Override - public void run() { - player.sendPacket(new ErrorMessage(title, message, true)); - service.shutdownNow(); - } - }, timeToRead, time); - } - } diff --git a/src/services/player/ZoneManager.java b/src/services/player/ZoneManager.java index 9285fc4fa..dcdf955ca 100644 --- a/src/services/player/ZoneManager.java +++ b/src/services/player/ZoneManager.java @@ -54,7 +54,9 @@ import network.packets.swg.zone.SetWaypointColor; import network.packets.swg.zone.ShowBackpack; import network.packets.swg.zone.ShowHelmet; import network.packets.swg.zone.chat.ChatSystemMessage; +import network.packets.swg.zone.insertion.SelectCharacter; import resources.config.ConfigFile; +import resources.objects.SWGObject; import resources.objects.creature.CreatureMood; import resources.objects.player.PlayerObject; import resources.objects.waypoint.WaypointObject; @@ -63,15 +65,19 @@ import resources.player.Player; import resources.player.Player.PlayerServer; import resources.player.PlayerEvent; import resources.server_info.DataManager; +import services.objects.ObjectManager; +import services.player.zone.ZoneRequester; public class ZoneManager extends Manager { private final CharacterCreationService characterCreationService; + private final ZoneRequester zoneRequester; private String commitHistory; public ZoneManager() { characterCreationService = new CharacterCreationService(); + zoneRequester = new ZoneRequester(); commitHistory = ""; addChildService(characterCreationService); @@ -113,6 +119,8 @@ public class ZoneManager extends Manager { handleShowHelmet(player, (ShowHelmet) p); if (p instanceof LagRequest && player.getPlayerServer() == PlayerServer.ZONE) handleLagRequest(player); + if (p instanceof SelectCharacter) + handleSelectCharacter(intent.getObjectManager(), player, ((SelectCharacter) p).getCharacterId()); } public boolean characterExistsForName(String name) { @@ -199,4 +207,9 @@ public class ZoneManager extends Manager { player.sendPacket(new ClientPermissionsMessage()); } + private void handleSelectCharacter(ObjectManager objectManager, Player player, long characterId) { + SWGObject creatureObj = objectManager.getObjectById(characterId); + zoneRequester.onZoneRequested(creatureObj, player, characterId); + } + } diff --git a/src/services/player/zone/ZoneRequester.java b/src/services/player/zone/ZoneRequester.java new file mode 100644 index 000000000..4c9eadd07 --- /dev/null +++ b/src/services/player/zone/ZoneRequester.java @@ -0,0 +1,94 @@ +/************************************************************************************ + * 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 services.player.zone; + +import java.util.concurrent.TimeUnit; + +import com.projectswg.common.data.location.Location; +import com.projectswg.common.data.location.Terrain; +import com.projectswg.common.debug.Log; + +import intents.RequestZoneInIntent; +import intents.chat.ChatBroadcastIntent; +import network.packets.swg.ErrorMessage; +import resources.config.ConfigFile; +import resources.objects.SWGObject; +import resources.objects.creature.CreatureObject; +import resources.player.Player; +import resources.server_info.DataManager; +import utilities.ScheduledUtilities; + +public class ZoneRequester { + + public boolean onZoneRequested(SWGObject creatureObject, Player player, long characterId) { + if (!initialChecks(creatureObject, player, characterId)) + return false; + if (!debugChecks(creatureObject, player, characterId)) + return false; + new RequestZoneInIntent(player, (CreatureObject) creatureObject).broadcast(); + return true; + } + + private boolean initialChecks(SWGObject creatureObject, Player player, long characterId) { + if (creatureObject == null) { + Log.e("Failed to start zone - CreatureObject could not be fetched from database [Character: %d User: %s]", characterId, player.getUsername()); + sendClientFatal(player, "Failed to zone", "You were not found in the database\nTry relogging to fix this problem", 10, TimeUnit.SECONDS); + return false; + } + if (!(creatureObject instanceof CreatureObject)) { + Log.e("Failed to start zone - Object is not a CreatureObject [Character: %d User: %s]", characterId, player.getUsername()); + sendClientFatal(player, "Failed to zone", "There has been an internal server error: Not a Creature.\nPlease delete your character and create a new one", 10, TimeUnit.SECONDS); + return false; + } + if (((CreatureObject) creatureObject).getPlayerObject() == null) { + Log.e("Failed to start zone - CreatureObject doesn't have a ghost [Character: %d User: %s", characterId, player.getUsername()); + sendClientFatal(player, "Failed to zone", "There has been an internal server error: Null Ghost.\nPlease delete your character and create a new one", 10, TimeUnit.SECONDS); + return false; + } + return true; + } + + private boolean debugChecks(SWGObject creatureObject, Player player, long characterId) { + if (isSafeZone()) { + Location safeLocation = new Location(0, 0, 0, Terrain.DEV_AREA); + creatureObject.setLocation(safeLocation); + new ChatBroadcastIntent(player, "Safe-zoning into dev terrain at " + safeLocation.getPosition()).broadcast(); + } + return true; + } + + private boolean isSafeZone() { + return DataManager.getConfig(ConfigFile.DEBUG).getBoolean("DEBUG-ZONE-SAFE", false); + } + + private void sendClientFatal(Player player, String title, String message, long timeToRead, TimeUnit time) { + player.sendPacket(new ErrorMessage(title, message, false)); + ScheduledUtilities.run(() -> player.sendPacket(new ErrorMessage(title, message, true)), timeToRead, time); + } + +} diff --git a/src/utilities/Scripts.java b/src/utilities/Scripts.java index 4dde887c0..e8ebb0cb7 100644 --- a/src/utilities/Scripts.java +++ b/src/utilities/Scripts.java @@ -40,25 +40,33 @@ import javax.script.ScriptException; import com.projectswg.common.debug.Log; - public class Scripts { - - private static final String SCRIPTS = "scripts/"; - private static final String EXTENSION = ".js"; - private static final ScriptEngine ENGINE = new ScriptEngineManager().getEngineByName("nashorn"); - private static final Invocable INVOCABLE = (Invocable) ENGINE; + + private static final String SCRIPTS; + private static final String EXTENSION; + private static final ScriptEngine ENGINE; + private static final Invocable INVOCABLE; static { - ENGINE.put("intentFactory", new IntentFactory()); - try { - 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.SuiWindow')"); - ENGINE.eval("var SuiButtons = Java.type('resources.sui.SuiButtons')"); - ENGINE.eval("var SuiEvent = Java.type('resources.sui.SuiEvent')"); - } catch (ScriptException e) { - Log.e(e); + ScriptEngineManager engineManager = new ScriptEngineManager(); + SCRIPTS = "scripts/"; + EXTENSION = ".js"; + ENGINE = engineManager.getEngineByName("nashorn"); + INVOCABLE = (Invocable) ENGINE; + if (ENGINE == null) { + Log.e("ScriptEngine is null!"); + } else { + try { + ENGINE.put("intentFactory", new IntentFactory()); + ENGINE.eval("var RadialOption = Java.type('resources.radial.RadialOption')"); + ENGINE.eval("var RadialItem = Java.type('resources.radial.RadialItem')"); + ENGINE.eval("var Log = Java.type('com.projectswg.common.debug.Log')"); + ENGINE.eval("var SuiWindow = Java.type('resources.sui.SuiWindow')"); + ENGINE.eval("var SuiButtons = Java.type('resources.sui.SuiButtons')"); + ENGINE.eval("var SuiEvent = Java.type('resources.sui.SuiEvent')"); + } catch (Throwable t) { + Log.e(t); + } } } diff --git a/test/resources/objects/awareness/TestAware.java b/test/resources/objects/awareness/TestAware.java index f4dacab7c..0baebcb61 100644 --- a/test/resources/objects/awareness/TestAware.java +++ b/test/resources/objects/awareness/TestAware.java @@ -37,6 +37,7 @@ import org.junit.runners.JUnit4; import resources.objects.SWGObject; import resources.objects.cell.CellObject; import resources.player.Player; +import test_resources.GenericCreatureObject; @RunWith(JUnit4.class) public class TestAware { diff --git a/test/resources/objects/awareness/TestAwarenessHandler.java b/test/resources/objects/awareness/TestAwarenessHandler.java index a932baef3..f8ba94ed0 100644 --- a/test/resources/objects/awareness/TestAwarenessHandler.java +++ b/test/resources/objects/awareness/TestAwarenessHandler.java @@ -44,6 +44,7 @@ import resources.objects.SWGObject; import resources.objects.building.BuildingObject; import resources.objects.creature.CreatureObject; import services.objects.ClientBuildoutService; +import test_resources.GenericCreatureObject; @RunWith(JUnit4.class) public class TestAwarenessHandler { diff --git a/test/resources/objects/awareness/TestTerrainMap.java b/test/resources/objects/awareness/TestTerrainMap.java index 204055ae1..e14ade838 100644 --- a/test/resources/objects/awareness/TestTerrainMap.java +++ b/test/resources/objects/awareness/TestTerrainMap.java @@ -46,6 +46,7 @@ import resources.objects.SWGObject; import resources.objects.cell.CellObject; import resources.objects.creature.CreatureObject; import services.objects.ClientBuildoutService; +import test_resources.GenericCreatureObject; @RunWith(JUnit4.class) public class TestTerrainMap { @@ -121,6 +122,7 @@ public class TestTerrainMap { AtomicBoolean onlyWithinRange = new AtomicBoolean(true); GenericCreatureObject creature = new GenericCreatureObject(1); MapCallback callback = new MapCallback() { + @Override public void onWithinRange(SWGObject obj, SWGObject inRange) { if (obj.equals(creature) && !withinRange.remove(inRange)) { Log.e("Not in list: %s", inRange); diff --git a/test/resources/objects/awareness/TestTerrainMapChunk.java b/test/resources/objects/awareness/TestTerrainMapChunk.java index 64f672168..9ab4cdebf 100644 --- a/test/resources/objects/awareness/TestTerrainMapChunk.java +++ b/test/resources/objects/awareness/TestTerrainMapChunk.java @@ -39,6 +39,7 @@ import com.projectswg.common.data.location.Terrain; import resources.objects.SWGObject; import resources.objects.cell.CellObject; +import test_resources.GenericCreatureObject; @RunWith(JUnit4.class) public class TestTerrainMapChunk { diff --git a/src/resources/network/NetworkCallback.java b/test/services/player/zone/TestZoneRequester.java similarity index 54% rename from src/resources/network/NetworkCallback.java rename to test/services/player/zone/TestZoneRequester.java index 4f0541d14..b989ae88a 100644 --- a/src/resources/network/NetworkCallback.java +++ b/test/services/player/zone/TestZoneRequester.java @@ -25,15 +25,74 @@ * along with Holocore. If not, see . * * * ***********************************************************************************/ -package resources.network; +package services.player.zone; -import java.net.Socket; -import java.net.SocketAddress; +import java.util.concurrent.atomic.AtomicBoolean; -public interface NetworkCallback { +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import network.packets.Packet; +import network.packets.swg.ErrorMessage; +import resources.objects.player.PlayerObject; +import resources.player.Player; +import test_resources.GenericCreatureObject; + +@RunWith(JUnit4.class) +public class TestZoneRequester { - void onIncomingConnection(Socket s, SocketAddress addr); - void onConnectionDisconnect(Socket s, SocketAddress addr); - void onIncomingData(Socket s, SocketAddress addr, byte [] data); + @Test + public void testNullCreatureObject() { + ZoneRequester zr = new ZoneRequester(); + TZRPlayer player = new TZRPlayer(); + Assert.assertFalse(zr.onZoneRequested(null, player, 0)); + Assert.assertTrue(player.isSentError()); + } + + + @Test + public void testInvalidCreatureObject() { + ZoneRequester zr = new ZoneRequester(); + TZRPlayer player = new TZRPlayer(); + Assert.assertFalse(zr.onZoneRequested(new PlayerObject(1), player, 0)); + Assert.assertTrue(player.isSentError()); + } + + @Test + public void testNullPlayerObject() { + ZoneRequester zr = new ZoneRequester(); + TZRPlayer player = new TZRPlayer(); + GenericCreatureObject creature = new GenericCreatureObject(5); + creature.setSlot("ghost", null); + Assert.assertFalse(zr.onZoneRequested(creature, player, 5)); + Assert.assertTrue(player.isSentError()); + } + + @Test + public void testValidCreatureObject() { + ZoneRequester zr = new ZoneRequester(); + TZRPlayer player = new TZRPlayer(); + GenericCreatureObject creature = new GenericCreatureObject(5); + Assert.assertTrue(zr.onZoneRequested(creature, player, 5)); + Assert.assertFalse(player.isSentError()); + } + + private static class TZRPlayer extends Player { + + private final AtomicBoolean sentError = new AtomicBoolean(false); + + @Override + public void sendPacket(Packet ... packets) { + if (packets.length == 1 && packets[0] instanceof ErrorMessage) + sentError.set(true); + } + + public boolean isSentError() { + return sentError.get(); + } + + } } diff --git a/test/resources/objects/awareness/GenericCreatureObject.java b/test/test_resources/GenericCreatureObject.java similarity index 96% rename from test/resources/objects/awareness/GenericCreatureObject.java rename to test/test_resources/GenericCreatureObject.java index 96973b460..20109851b 100644 --- a/test/resources/objects/awareness/GenericCreatureObject.java +++ b/test/test_resources/GenericCreatureObject.java @@ -25,7 +25,7 @@ * along with Holocore. If not, see . * * * ***********************************************************************************/ -package resources.objects.awareness; +package test_resources; import network.packets.Packet; import resources.objects.creature.CreatureObject; @@ -33,13 +33,14 @@ import resources.objects.player.PlayerObject; import resources.player.Player; import resources.player.PlayerState; -class GenericCreatureObject extends CreatureObject { +public class GenericCreatureObject extends CreatureObject { private Player player; public GenericCreatureObject(long objectId) { super(objectId); player = new Player() { + @Override public void sendPacket(Packet ... packets) { // Nah }