mirror of
https://github.com/ProjectSWGCore/Holocore.git
synced 2026-01-15 23:05:45 -05:00
Fixed startup issue with StaticPvpZoneLoader and changed the network code to use built-in Java classes for async i/o
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
image: openjdk:12
|
|
||||||
pipelines:
|
pipelines:
|
||||||
default:
|
default:
|
||||||
- step:
|
- step:
|
||||||
@@ -11,7 +10,7 @@ pipelines:
|
|||||||
- client-holocore/**
|
- client-holocore/**
|
||||||
- step:
|
- step:
|
||||||
name: test, build, and deploy
|
name: test, build, and deploy
|
||||||
#image: openjdk:12
|
image: openjdk:12
|
||||||
caches:
|
caches:
|
||||||
- docker
|
- docker
|
||||||
- gradle
|
- gradle
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class StaticPvpZoneLoader extends DataLoader {
|
|||||||
private final double radius;
|
private final double radius;
|
||||||
|
|
||||||
public StaticPvpZoneInfo(SdbLoader.SdbResultSet set) {
|
public StaticPvpZoneInfo(SdbLoader.SdbResultSet set) {
|
||||||
id = (int) set.getInt("id");
|
id = (int) set.getInt("pvp_zone_id");
|
||||||
|
|
||||||
location = Location.builder()
|
location = Location.builder()
|
||||||
.setX(set.getInt("x"))
|
.setX(set.getInt("x"))
|
||||||
|
|||||||
@@ -47,14 +47,16 @@ import me.joshlarson.jlcommon.log.Log
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.net.SocketAddress
|
import java.net.SocketAddress
|
||||||
import java.nio.ByteBuffer
|
import java.nio.channels.AsynchronousCloseException
|
||||||
import java.nio.channels.SocketChannel
|
import java.nio.channels.AsynchronousSocketChannel
|
||||||
|
import java.nio.channels.ClosedChannelException
|
||||||
|
import java.nio.channels.CompletionHandler
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
|
|
||||||
class NetworkClient(private val socket: SocketChannel) {
|
class NetworkClient(private val socket: AsynchronousSocketChannel) {
|
||||||
|
|
||||||
private val remoteAddress: SocketAddress? = try { socket.remoteAddress } catch (e: IOException) { null }
|
private val remoteAddress: SocketAddress? = try { socket.remoteAddress } catch (e: IOException) { null }
|
||||||
private val inboundBuffer: NetBuffer
|
private val inboundBuffer: NetBuffer
|
||||||
@@ -99,33 +101,39 @@ class NetworkClient(private val socket: SocketChannel) {
|
|||||||
return "NetworkClient[$remoteAddress]"
|
return "NetworkClient[$remoteAddress]"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addToInbound(data: ByteBuffer) {
|
private fun startRead() {
|
||||||
synchronized(inboundBuffer) {
|
socket.read(inboundBuffer.buffer, null, object : CompletionHandler<Int, Any?> {
|
||||||
if (data.remaining() > inboundBuffer.remaining()) {
|
override fun completed(result: Int?, attachment: Any?) {
|
||||||
StandardLog.onPlayerError(this, player, "Possible hack attempt detected with buffer overflow. Closing connection to $remoteAddress")
|
try {
|
||||||
close(ConnectionStoppedReason.APPLICATION)
|
inboundBuffer.flip()
|
||||||
return
|
while (NetworkProtocol.canDecode(inboundBuffer)) {
|
||||||
}
|
val p = NetworkProtocol.decode(inboundBuffer)
|
||||||
try {
|
if (p == null || !allowInbound(p))
|
||||||
inboundBuffer.add(data)
|
continue
|
||||||
inboundBuffer.flip()
|
p.socketAddress = remoteAddress
|
||||||
while (NetworkProtocol.canDecode(inboundBuffer)) {
|
processPacket(p)
|
||||||
val p = NetworkProtocol.decode(inboundBuffer)
|
intentChain.broadcastAfter(InboundPacketIntent(player, p))
|
||||||
if (p == null || !allowInbound(p))
|
}
|
||||||
continue
|
inboundBuffer.compact()
|
||||||
p.socketAddress = remoteAddress
|
} catch (e: HolocoreSessionException) {
|
||||||
processPacket(p)
|
onSessionError(e)
|
||||||
intentChain.broadcastAfter(InboundPacketIntent(player, p))
|
} catch (e: IOException) {
|
||||||
|
Log.w("Failed to process inbound packets. IOException: %s", e.message)
|
||||||
|
close()
|
||||||
}
|
}
|
||||||
inboundBuffer.compact()
|
|
||||||
} catch (e: HolocoreSessionException) {
|
startRead()
|
||||||
onSessionError(e)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.w("Failed to process inbound packets. IOException: %s", e.message)
|
|
||||||
close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
override fun failed(exc: Throwable?, attachment: Any?) {
|
||||||
|
if (exc != null) {
|
||||||
|
if (exc !is AsynchronousCloseException && exc !is ClosedChannelException)
|
||||||
|
Log.w(exc)
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addToOutbound(p: SWGPacket) {
|
private fun addToOutbound(p: SWGPacket) {
|
||||||
@@ -134,12 +142,12 @@ class NetworkClient(private val socket: SocketChannel) {
|
|||||||
try {
|
try {
|
||||||
val buffer = NetworkProtocol.encode(p).buffer
|
val buffer = NetworkProtocol.encode(p).buffer
|
||||||
while (connected.get() && buffer.hasRemaining()) {
|
while (connected.get() && buffer.hasRemaining()) {
|
||||||
socket.write(buffer)
|
socket.write(buffer).get()
|
||||||
if (buffer.hasRemaining())
|
if (buffer.hasRemaining())
|
||||||
Delay.sleepMilli(1)
|
Delay.sleepMilli(1)
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (t: Throwable) {
|
||||||
StandardLog.onPlayerError(this, player, "failed to write network data. ${e.javaClass.name}: ${e.message}")
|
StandardLog.onPlayerError(this, player, "failed to write network data. ${t.javaClass.name}: ${t.message}")
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,6 +158,7 @@ class NetworkClient(private val socket: SocketChannel) {
|
|||||||
StandardLog.onPlayerTrace(this, player, "connecting")
|
StandardLog.onPlayerTrace(this, player, "connecting")
|
||||||
status.set(SessionStatus.CONNECTING)
|
status.set(SessionStatus.CONNECTING)
|
||||||
intentChain.broadcastAfter(ConnectionOpenedIntent(player))
|
intentChain.broadcastAfter(ConnectionOpenedIntent(player))
|
||||||
|
startRead()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onConnected() {
|
private fun onConnected() {
|
||||||
|
|||||||
@@ -1,216 +0,0 @@
|
|||||||
/***********************************************************************************
|
|
||||||
* Copyright (c) 2018 /// 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 <http://www.gnu.org/licenses/>. *
|
|
||||||
***********************************************************************************/
|
|
||||||
package com.projectswg.holocore.services.support.global.network;
|
|
||||||
|
|
||||||
import com.projectswg.common.network.NetBuffer;
|
|
||||||
import com.projectswg.common.network.packets.swg.holo.HoloConnectionStopped.ConnectionStoppedReason;
|
|
||||||
import com.projectswg.holocore.ProjectSWG;
|
|
||||||
import com.projectswg.holocore.ProjectSWG.CoreException;
|
|
||||||
import com.projectswg.holocore.intents.support.global.network.CloseConnectionIntent;
|
|
||||||
import com.projectswg.holocore.intents.support.global.network.ConnectionClosedIntent;
|
|
||||||
import com.projectswg.holocore.resources.support.data.server_info.StandardLog;
|
|
||||||
import com.projectswg.holocore.resources.support.data.server_info.mongodb.PswgDatabase;
|
|
||||||
import com.projectswg.holocore.resources.support.global.network.NetworkClient;
|
|
||||||
import com.projectswg.holocore.resources.support.global.network.UDPServer;
|
|
||||||
import com.projectswg.holocore.resources.support.global.network.UDPServer.UDPPacket;
|
|
||||||
import com.projectswg.holocore.resources.support.global.player.Player;
|
|
||||||
import me.joshlarson.jlcommon.concurrency.BasicThread;
|
|
||||||
import me.joshlarson.jlcommon.control.IntentHandler;
|
|
||||||
import me.joshlarson.jlcommon.control.Service;
|
|
||||||
import me.joshlarson.jlcommon.log.Log;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.SelectionKey;
|
|
||||||
import java.nio.channels.Selector;
|
|
||||||
import java.nio.channels.ServerSocketChannel;
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public class NetworkClientService extends Service {
|
|
||||||
|
|
||||||
private static final int INBOUND_BUFFER_SIZE = 4096;
|
|
||||||
|
|
||||||
private final ServerSocketChannel tcpServer;
|
|
||||||
private final BasicThread acceptThreadPool;
|
|
||||||
private final Map<Long, NetworkClient> clients;
|
|
||||||
private final ByteBuffer inboundBuffer;
|
|
||||||
private final UDPServer udpServer;
|
|
||||||
private volatile boolean operational;
|
|
||||||
|
|
||||||
public NetworkClientService() {
|
|
||||||
this.acceptThreadPool = new BasicThread("network-client-accept", this::acceptLoop);
|
|
||||||
this.clients = new ConcurrentHashMap<>();
|
|
||||||
this.inboundBuffer = ByteBuffer.allocate(INBOUND_BUFFER_SIZE);
|
|
||||||
this.operational = true;
|
|
||||||
{
|
|
||||||
int bindPort = getBindPort();
|
|
||||||
try {
|
|
||||||
tcpServer = ServerSocketChannel.open();
|
|
||||||
tcpServer.bind(new InetSocketAddress(bindPort), 64);
|
|
||||||
tcpServer.configureBlocking(false);
|
|
||||||
udpServer = new UDPServer(bindPort, 32);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new CoreException("Failed to start networking", e);
|
|
||||||
}
|
|
||||||
udpServer.setCallback(this::onUdpPacket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean start() {
|
|
||||||
acceptThreadPool.start();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isOperational() {
|
|
||||||
return operational;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean stop() {
|
|
||||||
for (NetworkClient client : clients.values())
|
|
||||||
client.close(ConnectionStoppedReason.APPLICATION);
|
|
||||||
|
|
||||||
try {
|
|
||||||
tcpServer.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w("Failed to close TCP server");
|
|
||||||
}
|
|
||||||
acceptThreadPool.stop(true);
|
|
||||||
return acceptThreadPool.awaitTermination(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean terminate() {
|
|
||||||
udpServer.close();
|
|
||||||
return super.terminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void acceptLoop() {
|
|
||||||
try (Selector selector = Selector.open()) {
|
|
||||||
tcpServer.register(selector, SelectionKey.OP_ACCEPT);
|
|
||||||
while (tcpServer.isOpen()) {
|
|
||||||
selector.select();
|
|
||||||
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
SelectionKey key = it.next();
|
|
||||||
if (key.isAcceptable()) {
|
|
||||||
acceptConnection(selector);
|
|
||||||
}
|
|
||||||
if (key.isReadable()) {
|
|
||||||
read(key);
|
|
||||||
}
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.a(e);
|
|
||||||
} finally {
|
|
||||||
operational = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void acceptConnection(Selector selector) {
|
|
||||||
try {
|
|
||||||
SocketChannel client = tcpServer.accept();
|
|
||||||
if (client != null) {
|
|
||||||
client.configureBlocking(false);
|
|
||||||
NetworkClient networkClient = new NetworkClient(client);
|
|
||||||
client.register(selector, SelectionKey.OP_READ, networkClient);
|
|
||||||
clients.put(networkClient.getId(), networkClient);
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
Log.w("%s: Failed to accept connection", getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void read(SelectionKey key) {
|
|
||||||
Player player = null;
|
|
||||||
try {
|
|
||||||
SocketChannel channel = (SocketChannel) key.channel();
|
|
||||||
NetworkClient client = (NetworkClient) key.attachment();
|
|
||||||
player = client.getPlayer();
|
|
||||||
inboundBuffer.clear();
|
|
||||||
channel.read(inboundBuffer);
|
|
||||||
inboundBuffer.flip();
|
|
||||||
client.addToInbound(inboundBuffer);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
if (player != null)
|
|
||||||
StandardLog.onPlayerError(this, player, "failed to read data");
|
|
||||||
else
|
|
||||||
Log.w("%s: Failed to read data", getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disconnect(long networkId) {
|
|
||||||
disconnect(clients.get(networkId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disconnect(NetworkClient client) {
|
|
||||||
if (client == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
client.close(ConnectionStoppedReason.APPLICATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onUdpPacket(UDPPacket packet) {
|
|
||||||
if (packet.getLength() <= 0)
|
|
||||||
return;
|
|
||||||
if (packet.getData()[0] == 1) {
|
|
||||||
sendState(packet.getAddress(), packet.getPort());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendState(InetAddress addr, int port) {
|
|
||||||
String status = ProjectSWG.getGalaxy().getStatus().name();
|
|
||||||
NetBuffer data = NetBuffer.allocate(3 + status.length());
|
|
||||||
data.addByte(1);
|
|
||||||
data.addAscii(status);
|
|
||||||
udpServer.send(port, addr, data.array());
|
|
||||||
}
|
|
||||||
|
|
||||||
@IntentHandler
|
|
||||||
private void handleCloseConnectionIntent(CloseConnectionIntent ccii) {
|
|
||||||
disconnect(ccii.getPlayer().getNetworkId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@IntentHandler
|
|
||||||
private void handleConnectionClosedIntent(ConnectionClosedIntent cci) {
|
|
||||||
disconnect(cci.getPlayer().getNetworkId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getBindPort() {
|
|
||||||
return PswgDatabase.INSTANCE.getConfig().getInt(this, "bindPort", 44463);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
/***********************************************************************************
|
||||||
|
* Copyright (c) 2018 /// 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 <http:></http:>//www.gnu.org/licenses/>. *
|
||||||
|
*/
|
||||||
|
package com.projectswg.holocore.services.support.global.network
|
||||||
|
|
||||||
|
import com.projectswg.common.network.NetBuffer
|
||||||
|
import com.projectswg.common.network.packets.swg.holo.HoloConnectionStopped.ConnectionStoppedReason
|
||||||
|
import com.projectswg.holocore.ProjectSWG
|
||||||
|
import com.projectswg.holocore.ProjectSWG.CoreException
|
||||||
|
import com.projectswg.holocore.intents.support.global.network.CloseConnectionIntent
|
||||||
|
import com.projectswg.holocore.intents.support.global.network.ConnectionClosedIntent
|
||||||
|
import com.projectswg.holocore.resources.support.data.server_info.mongodb.PswgDatabase
|
||||||
|
import com.projectswg.holocore.resources.support.global.network.NetworkClient
|
||||||
|
import com.projectswg.holocore.resources.support.global.network.UDPServer
|
||||||
|
import com.projectswg.holocore.resources.support.global.network.UDPServer.UDPPacket
|
||||||
|
import me.joshlarson.jlcommon.control.IntentHandler
|
||||||
|
import me.joshlarson.jlcommon.control.Service
|
||||||
|
import me.joshlarson.jlcommon.log.Log
|
||||||
|
import java.io.IOException
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.net.InetSocketAddress
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.nio.channels.AsynchronousServerSocketChannel
|
||||||
|
import java.nio.channels.AsynchronousSocketChannel
|
||||||
|
import java.nio.channels.CompletionHandler
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
class NetworkClientService : Service() {
|
||||||
|
|
||||||
|
private var tcpServer: AsynchronousServerSocketChannel
|
||||||
|
private val clients: MutableMap<Long, NetworkClient>
|
||||||
|
private val inboundBuffer: ByteBuffer
|
||||||
|
private var udpServer: UDPServer
|
||||||
|
@Volatile
|
||||||
|
private var operational: Boolean = false
|
||||||
|
|
||||||
|
private val bindPort: Int
|
||||||
|
get() = PswgDatabase.config!!.getInt(this, "bindPort", 44463)
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.clients = ConcurrentHashMap()
|
||||||
|
this.inboundBuffer = ByteBuffer.allocate(INBOUND_BUFFER_SIZE)
|
||||||
|
this.operational = true
|
||||||
|
|
||||||
|
val bindPort = bindPort
|
||||||
|
try {
|
||||||
|
tcpServer = AsynchronousServerSocketChannel.open()
|
||||||
|
tcpServer.bind(InetSocketAddress(bindPort), 64)
|
||||||
|
udpServer = UDPServer(bindPort, 32)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw CoreException("Failed to start networking", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
udpServer.setCallback { this.onUdpPacket(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun start(): Boolean {
|
||||||
|
tcpServer.accept(null, object : CompletionHandler<AsynchronousSocketChannel, Any?> {
|
||||||
|
override fun completed(result: AsynchronousSocketChannel?, attachment: Any?) {
|
||||||
|
tcpServer.accept(null, this) // starts the next listen
|
||||||
|
if (result != null)
|
||||||
|
handleConnection(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun failed(exc: Throwable?, attachment: Any?) {
|
||||||
|
if (exc != null)
|
||||||
|
Log.w(exc)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isOperational(): Boolean {
|
||||||
|
return operational
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stop(): Boolean {
|
||||||
|
for (client in clients.values)
|
||||||
|
client.close(ConnectionStoppedReason.APPLICATION)
|
||||||
|
|
||||||
|
try {
|
||||||
|
tcpServer.close()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.w("Failed to close TCP server")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun terminate(): Boolean {
|
||||||
|
udpServer.close()
|
||||||
|
return super.terminate()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleConnection(socket: AsynchronousSocketChannel) {
|
||||||
|
val networkClient = NetworkClient(socket)
|
||||||
|
clients[networkClient.id] = networkClient
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun disconnect(networkId: Long) {
|
||||||
|
disconnect(clients[networkId])
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun disconnect(client: NetworkClient?) {
|
||||||
|
if (client == null)
|
||||||
|
return
|
||||||
|
|
||||||
|
client.close(ConnectionStoppedReason.APPLICATION)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onUdpPacket(packet: UDPPacket) {
|
||||||
|
if (packet.length <= 0)
|
||||||
|
return
|
||||||
|
if (packet.data[0].toInt() == 1) {
|
||||||
|
sendState(packet.address, packet.port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendState(addr: InetAddress, port: Int) {
|
||||||
|
val status = ProjectSWG.getGalaxy().status.name
|
||||||
|
val data = NetBuffer.allocate(3 + status.length)
|
||||||
|
data.addByte(1)
|
||||||
|
data.addAscii(status)
|
||||||
|
udpServer.send(port, addr, data.array())
|
||||||
|
}
|
||||||
|
|
||||||
|
@IntentHandler
|
||||||
|
private fun handleCloseConnectionIntent(ccii: CloseConnectionIntent) {
|
||||||
|
disconnect(ccii.player.networkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
@IntentHandler
|
||||||
|
private fun handleConnectionClosedIntent(cci: ConnectionClosedIntent) {
|
||||||
|
disconnect(cci.player.networkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private val INBOUND_BUFFER_SIZE = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user