Skip to content

Commit 052a1d7

Browse files
committed
Translate template ids on player transfers
1 parent b37c426 commit 052a1d7

File tree

15 files changed

+1095
-2
lines changed

15 files changed

+1095
-2
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package com.wurmonline.server.intra;
2+
3+
import java.io.IOException;
4+
import java.nio.ByteBuffer;
5+
import java.util.logging.Level;
6+
import java.util.logging.Logger;
7+
8+
import org.gotti.wurmunlimited.modcomm.intra.BBHelper;
9+
import org.gotti.wurmunlimited.modcomm.intra.IntraRequest;
10+
import org.gotti.wurmunlimited.modcomm.intra.ModIntraServer;
11+
import org.gotti.wurmunlimited.modcomm.intra.ModIntraServerConstants;
12+
13+
import com.wurmonline.communication.SocketConnection;
14+
import com.wurmonline.server.ServerEntry;
15+
import com.wurmonline.server.Servers;
16+
17+
/**
18+
* ModIntraServer message type
19+
* @author ago
20+
*/
21+
public final class ModIntraServerMessage extends IntraCommand implements IntraServerProtocol {
22+
private static final Logger logger = Logger.getLogger(ModIntraServerMessage.class.getName());
23+
24+
private final ServerEntry server;
25+
private IntraClient client;
26+
private boolean done;
27+
private boolean sent;
28+
private String message;
29+
private byte[] data;
30+
private IntraRequest handler;
31+
32+
/**
33+
* Create intra server message
34+
* @param serverEntry Target server
35+
* @param handler Message handler
36+
* @param payload Request payload
37+
*/
38+
public ModIntraServerMessage(final ServerEntry serverEntry, IntraRequest handler, byte[] payload) {
39+
this.done = false;
40+
this.sent = false;
41+
this.server = serverEntry;
42+
this.message = handler.getName();
43+
this.data = payload;
44+
this.handler = handler;
45+
}
46+
47+
/**
48+
* Called from Server.poll
49+
*/
50+
public boolean poll() {
51+
if (this.server.id == Servers.localServer.id) {
52+
return true;
53+
}
54+
// Client is null, so connect to the target
55+
if (this.client == null) {
56+
try {
57+
this.client = new IntraClient(server.INTRASERVERADDRESS, Integer.parseInt(server.INTRASERVERPORT), this);
58+
this.client.login(this.server.INTRASERVERPASSWORD, true);
59+
ModIntraServerMessage.logger.log(Level.INFO, "connecting to " + this.server.id);
60+
} catch (IOException iox) {
61+
this.client.disconnect("Failed.");
62+
this.client = null;
63+
ModIntraServerMessage.logger.log(Level.INFO, "Failed");
64+
this.done = true;
65+
}
66+
}
67+
// Client is not null and we're not done
68+
if (this.client != null && !this.done) {
69+
// check for timeouts
70+
if (System.currentTimeMillis() > this.timeOutAt) {
71+
this.done = handler.handleTimeout();
72+
}
73+
// Main processing loop
74+
if (!this.done) {
75+
try {
76+
// we're logged in but have not sent the message. Send it
77+
if (this.client.loggedIn && !this.sent) {
78+
79+
SocketConnection connection = ModIntraServer.getConnection(this.client);
80+
81+
final ByteBuffer buf = connection.getBuffer();
82+
buf.put(ModIntraServerConstants.CMD_MODCOMM);
83+
buf.put(ModIntraServerConstants.PACKET_MESSAGE);
84+
BBHelper.putUtf8String(buf, message);
85+
buf.put(data);
86+
connection.flush();
87+
88+
this.sent = true;
89+
this.timeOutAt = System.currentTimeMillis() + this.timeOutTime;
90+
}
91+
// poll the connection
92+
if (!this.done) {
93+
this.client.update();
94+
}
95+
} catch (IOException iox) {
96+
this.done = true;
97+
}
98+
}
99+
// we're done. Disconnect
100+
if (this.done && this.client != null) {
101+
this.client.disconnect("Done");
102+
this.client = null;
103+
}
104+
}
105+
return this.done;
106+
}
107+
108+
public void commandExecuted(final IntraClient aClient) {
109+
this.done = true;
110+
}
111+
112+
public void commandFailed(final IntraClient aClient) {
113+
this.done = true;
114+
}
115+
116+
public void dataReceived(final IntraClient aClient) {
117+
this.done = true;
118+
}
119+
120+
public void reschedule(final IntraClient aClient) {
121+
this.done = true;
122+
}
123+
124+
public void remove(final IntraClient aClient) {
125+
this.done = true;
126+
}
127+
128+
public void receivingData(final ByteBuffer buffer) {
129+
this.done = this.done || handler.handleReply(buffer);
130+
}
131+
132+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.gotti.wurmunlimited.modcomm.intra;
2+
3+
import java.nio.ByteBuffer;
4+
import java.nio.charset.StandardCharsets;
5+
6+
/**
7+
* ByteBuffer helper
8+
*/
9+
public class BBHelper {
10+
11+
/**
12+
* put an utf-8 string (byte count + bytes)
13+
* @param buffer ByteBuffer
14+
* @param string String
15+
*/
16+
public static void putUtf8String(ByteBuffer buffer, String string) {
17+
byte[] charData = string.getBytes(StandardCharsets.UTF_8);
18+
buffer.putInt(charData.length);
19+
buffer.put(charData);
20+
}
21+
22+
/**
23+
* read an utf-8 string (byte count + bytes)
24+
* @param buffer Byte buffer
25+
* @return string
26+
*/
27+
public static String getUtf8String(ByteBuffer buffer) {
28+
int lenght = buffer.getInt();
29+
byte[] data = new byte[lenght];
30+
buffer.get(data);
31+
return new String(data, StandardCharsets.UTF_8);
32+
}
33+
34+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.gotti.wurmunlimited.modcomm.intra;
2+
3+
import java.nio.ByteBuffer;
4+
5+
/**
6+
* ModIntraServer request
7+
*/
8+
public interface IntraRequest {
9+
10+
/**
11+
* @return Unique message name
12+
*/
13+
String getName();
14+
15+
/**
16+
* Handle the reply
17+
* @param recvBuffer Receive buffer
18+
* @return true if the request is done
19+
*/
20+
boolean handleReply(ByteBuffer recvBuffer);
21+
22+
/**
23+
* Handle a timeout
24+
* @return true to finish the request
25+
*/
26+
default boolean handleTimeout() {
27+
return true;
28+
}
29+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.gotti.wurmunlimited.modcomm.intra;
2+
3+
import java.nio.ByteBuffer;
4+
5+
import com.wurmonline.communication.SocketConnection;
6+
7+
/**
8+
* ModIntraServer request handler (receiving end)
9+
*/
10+
@FunctionalInterface
11+
public interface IntraRequestHandler {
12+
13+
/**
14+
* Handle the request
15+
* @param connection Connection
16+
* @param recvBuffer Receive buffer
17+
*/
18+
void handleRequest(SocketConnection connection, ByteBuffer recvBuffer);
19+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package org.gotti.wurmunlimited.modcomm.intra;
2+
3+
import java.lang.reflect.Field;
4+
5+
import org.gotti.wurmunlimited.modcomm.intra.playertransfer.ModPlayerTransfer;
6+
import org.gotti.wurmunlimited.modloader.ReflectionUtil;
7+
import org.gotti.wurmunlimited.modloader.classhooks.HookException;
8+
import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
9+
10+
import com.wurmonline.communication.SocketConnection;
11+
import com.wurmonline.server.intra.IntraClient;
12+
import com.wurmonline.server.intra.IntraServerConnection;
13+
14+
import javassist.CannotCompileException;
15+
import javassist.ClassPool;
16+
import javassist.CtClass;
17+
import javassist.NotFoundException;
18+
import javassist.expr.ExprEditor;
19+
import javassist.expr.MethodCall;
20+
21+
/**
22+
* Intra server communication.
23+
*/
24+
public class ModIntraServer {
25+
26+
// Reflection fields
27+
private static Field intraClientConnection;
28+
private static Field intraServerConnectionConn;
29+
30+
// internal api handler
31+
private static ModIntraServerHandler modCommHandler;
32+
33+
/**
34+
* init
35+
*/
36+
public static void init() {
37+
// create api handler
38+
modCommHandler = new ModIntraServerHandler();
39+
40+
// class hooks
41+
final ClassPool classPool = HookManager.getInstance().getClassPool();
42+
try {
43+
CtClass ctCommunicator = classPool.getCtClass("com.wurmonline.server.intra.IntraServerConnection");
44+
45+
HookManager.getInstance().addCallback(ctCommunicator, "modcomm", modCommHandler);
46+
47+
ctCommunicator.getMethod("reallyHandle", "(ILjava/nio/ByteBuffer;)V").instrument(new ExprEditor() {
48+
private boolean first = true;
49+
50+
@Override
51+
public void edit(MethodCall m) throws CannotCompileException {
52+
if (m.getMethodName().equals("get") && first) {
53+
m.replace("$_ = $proceed($$);" + "if ($_ == " + ModIntraServerConstants.CMD_MODCOMM + ") { modcomm.handle(this, $0); return; }");
54+
first = false;
55+
}
56+
}
57+
});
58+
} catch (NotFoundException | CannotCompileException e) {
59+
throw new RuntimeException("Error initializing ModComm", e);
60+
}
61+
62+
// Init player transfers
63+
ModPlayerTransfer.init();
64+
}
65+
66+
/**
67+
* Start communications
68+
*/
69+
public static void serverStarted() {
70+
try {
71+
intraClientConnection = ReflectionUtil.getField(IntraClient.class, "connection");
72+
intraServerConnectionConn = ReflectionUtil.getField(IntraServerConnection.class, "conn");
73+
74+
ModPlayerTransfer.serverStarted();
75+
} catch (NoSuchFieldException e) {
76+
throw new HookException(e);
77+
}
78+
}
79+
80+
/**
81+
* Helper to retrieve a {@link SocketConnection} from an {@link IntraClient}
82+
*
83+
* @param client
84+
* intra client
85+
* @return socket connection
86+
*/
87+
public static SocketConnection getConnection(IntraClient client) {
88+
try {
89+
return ReflectionUtil.getPrivateField(client, intraClientConnection);
90+
} catch (IllegalArgumentException | IllegalAccessException | ClassCastException e) {
91+
throw new HookException(e);
92+
}
93+
}
94+
95+
/**
96+
* Helper to retrieve a {@link SocketConnection} from an {@link IntraServerConnection}
97+
*
98+
* @param connection
99+
* intra server connection
100+
* @return socket connection
101+
*/
102+
public static SocketConnection getConnection(IntraServerConnection connection) {
103+
try {
104+
return ReflectionUtil.getPrivateField(connection, intraServerConnectionConn);
105+
} catch (IllegalArgumentException | IllegalAccessException | ClassCastException e) {
106+
throw new HookException(e);
107+
}
108+
}
109+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.gotti.wurmunlimited.modcomm.intra;
2+
3+
public class ModIntraServerConstants {
4+
/**
5+
* Command ID for all packets used by this system, should not collide with any packets used by WU (see {@link IntraServerProtocol})})
6+
*/
7+
public static final byte CMD_MODCOMM = -100;
8+
9+
/**
10+
* Packet types for the internal protocol
11+
*/
12+
public static final byte PACKET_MESSAGE = 1;
13+
}

0 commit comments

Comments
 (0)