Skip to content

Commit 24ac7a9

Browse files
committed
chore: improve network send/recieve & contextual some fields
1 parent b8da971 commit 24ac7a9

File tree

3 files changed

+190
-1
lines changed

3 files changed

+190
-1
lines changed

src/OTAPI.UnifiedServerProcess/Core/Patching/FieldFilterPatching/ForceInstanceProcessor.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ public class ForceInstanceProcessor() : IFieldFilterArgProcessor
1212
"Terraria.GameContent.PressurePlateHelper.EntityCreationLock",
1313
"Terraria.GameContent.Creative.CreativePowerManager._initialized",
1414
"Terraria.Recipe.numRecipes",
15-
"Terraria.ID.ContentSamples.NpcBestiarySortingId"
15+
"Terraria.ID.ContentSamples.NpcBestiarySortingId",
16+
"Terraria.Main.autoGen",
17+
"Terraria.Main.AutogenSeedName",
18+
"Terraria.Main.AutogenProgress",
1619
};
1720
readonly static string[] types = new string[] {
1821
"Terraria.ObjectData.TileObjectData",
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using ModFramework;
2+
using Mono.Cecil;
3+
using Mono.Cecil.Cil;
4+
using Mono.Cecil.Rocks;
5+
using MonoMod.Utils;
6+
using OTAPI.UnifiedServerProcess.Commons;
7+
using System;
8+
using System.IO;
9+
using System.Linq;
10+
11+
[Modification(ModType.PostMerge, "Add overload of GetData", ModPriority.Early)]
12+
[MonoMod.MonoModIgnore]
13+
void PatchMessageBuffer(ModFwModder modder) {
14+
var module = modder.Module;
15+
16+
var byteRef = module.TypeSystem.Byte;
17+
var binaryReaderRef = new TypeReference("System.IO", "BinaryReader", module, module.TypeSystem.CoreLibrary);
18+
19+
20+
var messageBufferTypeDef = modder.Module.GetType("Terraria.MessageBuffer");
21+
var origMethod = messageBufferTypeDef.Method("GetData");
22+
var overload = origMethod.Clone();
23+
var param_readbuffer = new ParameterDefinition("readbuffer", ParameterAttributes.None, byteRef.MakeArrayType());
24+
overload.Parameters.Add(param_readbuffer);
25+
var param_reader = new ParameterDefinition("reader", ParameterAttributes.None, binaryReaderRef);
26+
overload.Parameters.Add(param_reader);
27+
origMethod.DeclaringType.Methods.Add(overload);
28+
29+
foreach (var inst in overload.Body.Instructions.ToArray()) {
30+
if (inst.Operand is FieldReference { Name: "readBuffer", DeclaringType.FullName: "Terraria.MessageBuffer" }) {
31+
var loadThis = inst.Previous;
32+
if (!MonoModCommon.IL.TryGetReferencedParameter(overload, loadThis, out var paramThis) || paramThis.ParameterType.FullName != "Terraria.MessageBuffer") {
33+
throw new Exception("Failed to get paramThis");
34+
}
35+
var loadReadBuffer = MonoModCommon.IL.BuildParameterLoad(overload, overload.Body, param_readbuffer);
36+
loadThis.OpCode = loadReadBuffer.OpCode;
37+
loadThis.Operand = loadReadBuffer.Operand;
38+
overload.Body.Instructions.Remove(inst);
39+
}
40+
else if (inst.Operand is FieldReference { Name: "reader", DeclaringType.FullName: "Terraria.MessageBuffer" }) {
41+
var loadThis = inst.Previous;
42+
if (!MonoModCommon.IL.TryGetReferencedParameter(overload, loadThis, out var paramThis) || paramThis.ParameterType.FullName != "Terraria.MessageBuffer") {
43+
throw new Exception("Failed to get paramThis");
44+
}
45+
var loadReadBuffer = MonoModCommon.IL.BuildParameterLoad(overload, overload.Body, param_reader);
46+
loadThis.OpCode = loadReadBuffer.OpCode;
47+
loadThis.Operand = loadReadBuffer.Operand;
48+
overload.Body.Instructions.Remove(inst);
49+
}
50+
else if (inst.Operand is MethodReference { Name: "ResetReader", DeclaringType.FullName: "Terraria.MessageBuffer" }) {
51+
52+
var loadThis = inst.Previous;
53+
if (!MonoModCommon.IL.TryGetReferencedParameter(overload, loadThis, out var paramThis) || paramThis.ParameterType.FullName != "Terraria.MessageBuffer") {
54+
throw new Exception("Failed to get paramThis");
55+
}
56+
57+
var resetReaderRef = new MethodReference("ResetReader", module.TypeSystem.Void, messageBufferTypeDef) { HasThis = true };
58+
resetReaderRef.Parameters.AddRange([
59+
new(byteRef.MakeArrayType()),
60+
new(binaryReaderRef.MakeByReferenceType()),
61+
]);
62+
inst.Operand = resetReaderRef;
63+
64+
var il = overload.Body.GetILProcessor();
65+
il.InsertAfter(loadThis, [
66+
MonoModCommon.IL.BuildParameterLoad(overload, overload.Body, param_readbuffer),
67+
MonoModCommon.IL.BuildParameterLoadAddress(overload, overload.Body, param_reader),
68+
]);
69+
}
70+
}
71+
72+
origMethod.Body.Variables.Clear();
73+
origMethod.Body.ExceptionHandlers.Clear();
74+
origMethod.Body.Instructions.Clear();
75+
var body = origMethod.Body.Instructions;
76+
77+
body.Add(Instruction.Create(OpCodes.Ldarg_0));
78+
foreach (var p in origMethod.Parameters) {
79+
body.Add(MonoModCommon.IL.BuildParameterLoad(origMethod, origMethod.Body, p));
80+
}
81+
body.Add(Instruction.Create(OpCodes.Ldarg_0));
82+
body.Add(Instruction.Create(OpCodes.Ldfld, new FieldReference("readBuffer", param_readbuffer.ParameterType, messageBufferTypeDef)));
83+
body.Add(Instruction.Create(OpCodes.Ldarg_0));
84+
body.Add(Instruction.Create(OpCodes.Ldfld, new FieldReference("reader", param_reader.ParameterType, messageBufferTypeDef)));
85+
var overloadRef = new MethodReference(overload.Name, overload.ReturnType, overload.DeclaringType) { HasThis = overload.HasThis };
86+
overloadRef.Parameters.AddRange(overload.Parameters.Select(p => new ParameterDefinition(p.ParameterType)));
87+
body.Add(Instruction.Create(OpCodes.Call, overloadRef));
88+
body.Add(Instruction.Create(OpCodes.Ret));
89+
}
90+
91+
namespace Terraria
92+
{
93+
public class MessageBuffer
94+
{
95+
public void ResetReader(byte[] readBuffer, out BinaryReader reader) {
96+
reader = new BinaryReader(new MemoryStream(readBuffer));
97+
}
98+
}
99+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#pragma warning disable CS8321 // Local function is declared but never used
2+
#pragma warning disable CS0436 // Type conflicts with imported type
3+
#nullable disable
4+
using ModFramework;
5+
using System;
6+
using System.Buffers;
7+
using System.Net.Sockets;
8+
using Terraria.Net;
9+
using Terraria.Net.Sockets;
10+
using Terraria.Social;
11+
12+
[Modification(ModType.PreWrite, "Add Method to ISocket", ModPriority.Early)]
13+
[MonoMod.MonoModIgnore]
14+
void NetplayConnectionCheck(ModFwModder modder) {
15+
Console.WriteLine("Added method to ISocket");
16+
}
17+
18+
namespace Terraria.Net.Sockets
19+
{
20+
public interface ISocket
21+
{
22+
void Close();
23+
void AsyncSendNoCopy(byte[] data, int offset, int size, SocketSendCallback callback, object state = null);
24+
void AsyncSend(ReadOnlyMemory<byte> data, SocketSendCallback callback, object state = null);
25+
}
26+
public class TcpSocket : ISocket
27+
{
28+
[MonoMod.MonoModIgnore]
29+
void ISocket.Close() { }
30+
public TcpClient _connection;
31+
void ISocket.AsyncSendNoCopy(byte[] data, int offset, int size, SocketSendCallback callback, object state = null) {
32+
_connection.GetStream().BeginWrite(data, offset, size, static result => {
33+
var tuple = (Tuple<TcpSocket, SocketSendCallback, object>)result.AsyncState;
34+
try {
35+
tuple.Item1._connection.GetStream().EndWrite(result);
36+
tuple.Item2(tuple.Item3);
37+
}
38+
catch (Exception) {
39+
((ISocket)tuple.Item1).Close();
40+
}
41+
}, new Tuple<TcpSocket, SocketSendCallback, object>(this, callback, state));
42+
}
43+
void ISocket.AsyncSend(ReadOnlyMemory<byte> data, SocketSendCallback callback, object state = null) {
44+
var array = ArrayPool<byte>.Shared.Rent(data.Length);
45+
data.CopyTo(array);
46+
_connection.GetStream().BeginWrite(array, 0, data.Length, static result => {
47+
var tuple = (Tuple<TcpSocket, byte[], SocketSendCallback, object>)result.AsyncState;
48+
try {
49+
tuple.Item1._connection.GetStream().EndWrite(result);
50+
tuple.Item3(tuple.Item4);
51+
}
52+
catch (Exception) {
53+
((ISocket)tuple.Item1).Close();
54+
}
55+
finally {
56+
ArrayPool<byte>.Shared.Return(tuple.Item2);
57+
}
58+
}, new Tuple<TcpSocket, byte[], SocketSendCallback, object>(this, array, callback, state));
59+
}
60+
}
61+
public class SocialSocket : ISocket
62+
{
63+
[MonoMod.MonoModIgnore]
64+
void ISocket.Close() { }
65+
public RemoteAddress _remoteAddress;
66+
void ISocket.AsyncSendNoCopy(byte[] data, int offset, int size, SocketSendCallback callback, object state = null) {
67+
if (offset is not 0) {
68+
var copy = ArrayPool<byte>.Shared.Rent(size);
69+
Buffer.BlockCopy(data, offset, copy, 0, size);
70+
SocialAPI.Network.Send(_remoteAddress, copy, size);
71+
ArrayPool<byte>.Shared.Return(copy);
72+
callback.BeginInvoke(state, null, null);
73+
}
74+
else {
75+
SocialAPI.Network.Send(_remoteAddress, data, size);
76+
callback.BeginInvoke(state, null, null);
77+
}
78+
}
79+
void ISocket.AsyncSend(ReadOnlyMemory<byte> data, SocketSendCallback callback, object state = null) {
80+
var copy = ArrayPool<byte>.Shared.Rent(data.Length);
81+
data.CopyTo(copy);
82+
SocialAPI.Network.Send(_remoteAddress, copy, data.Length);
83+
ArrayPool<byte>.Shared.Return(copy);
84+
callback.BeginInvoke(state, null, null);
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)