Skip to content

Commit 663c3f6

Browse files
committed
chore: cross-server chat & fix some bugs
1 parent 33756c6 commit 663c3f6

File tree

18 files changed

+284
-1050
lines changed

18 files changed

+284
-1050
lines changed

src/OTAPI.UnifiedServerProcess.GlobalNetwork/IO/ConsoleClientLauncher.APIs.cs renamed to src/OTAPI.UnifiedServerProcess.GlobalNetwork/CLI/ConsoleClientLauncher.APIs.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace OTAPI.UnifiedServerProcess.GlobalNetwork.IO
1+
namespace OTAPI.UnifiedServerProcess.GlobalNetwork.CLI
22
{
33
partial class ConsoleClientLauncher
44
{

src/OTAPI.UnifiedServerProcess.GlobalNetwork/IO/ConsoleClientLauncher.CoreImpl.cs renamed to src/OTAPI.UnifiedServerProcess.GlobalNetwork/CLI/ConsoleClientLauncher.CoreImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System.Collections.Concurrent;
55
using System.Text;
66

7-
namespace OTAPI.UnifiedServerProcess.GlobalNetwork.IO
7+
namespace OTAPI.UnifiedServerProcess.GlobalNetwork.CLI
88
{
99
partial class ConsoleClientLauncher
1010
{

src/OTAPI.UnifiedServerProcess.GlobalNetwork/IO/ConsoleClientLauncher.cs renamed to src/OTAPI.UnifiedServerProcess.GlobalNetwork/CLI/ConsoleClientLauncher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Runtime.CompilerServices;
66
using UnifiedServerProcess;
77

8-
namespace OTAPI.UnifiedServerProcess.GlobalNetwork.IO
8+
namespace OTAPI.UnifiedServerProcess.GlobalNetwork.CLI
99
{
1010
public unsafe partial class ConsoleClientLauncher : ConsoleSystemContext
1111
{

src/OTAPI.UnifiedServerProcess.GlobalNetwork/IO/ConsoleColorHelper.cs renamed to src/OTAPI.UnifiedServerProcess.GlobalNetwork/CLI/ConsoleColorHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Microsoft.Xna.Framework;
22

3-
namespace OTAPI.UnifiedServerProcess.GlobalNetwork.IO
3+
namespace OTAPI.UnifiedServerProcess.GlobalNetwork.CLI
44
{
55

66
public static class ConsoleColorHelper

src/OTAPI.UnifiedServerProcess.GlobalNetwork/IO/ConsoleSpinner.cs renamed to src/OTAPI.UnifiedServerProcess.GlobalNetwork/CLI/ConsoleSpinner.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace OTAPI.UnifiedServerProcess.GlobalNetwork.IO
1+
namespace OTAPI.UnifiedServerProcess.GlobalNetwork.CLI
22
{
33
public class ConsoleSpinner
44
{
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using OTAPI.UnifiedServerProcess.GlobalNetwork.Network;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Terraria.Localization;
8+
using UnifiedServerProcess;
9+
10+
namespace OTAPI.UnifiedServerProcess.GlobalNetwork
11+
{
12+
public class ChatHandler
13+
{
14+
readonly Router router;
15+
public ChatHandler(Router router) {
16+
this.router = router;
17+
On.Terraria.Chat.Commands.SayChatCommand.ProcessIncomingMessage += ProcessIncomingMessage;
18+
}
19+
20+
private void ProcessIncomingMessage(On.Terraria.Chat.Commands.SayChatCommand.orig_ProcessIncomingMessage orig, Terraria.Chat.Commands.SayChatCommand self, RootContext root, string text, byte clientId) {
21+
orig(self, root, text, clientId);
22+
23+
var player = root.Main.player[clientId];
24+
25+
foreach (var otherServer in router.servers) {
26+
if (!otherServer.IsRunning || root == otherServer) {
27+
continue;
28+
}
29+
otherServer.ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral($"[Realm·{root.Name}] <{player.name}>: {text}"), player.ChatColor());
30+
}
31+
}
32+
}
33+
}

src/OTAPI.UnifiedServerProcess.GlobalNetwork/CommandHandler.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using Microsoft.Xna.Framework;
2-
using OTAPI.UnifiedServerProcess.GlobalNetwork.IO;
2+
using OTAPI.UnifiedServerProcess.GlobalNetwork.CLI;
33
using OTAPI.UnifiedServerProcess.GlobalNetwork.Network;
44
using OTAPI.UnifiedServerProcess.GlobalNetwork.Servers;
55
using System.Diagnostics.CodeAnalysis;
@@ -13,7 +13,12 @@ namespace OTAPI.UnifiedServerProcess.GlobalNetwork
1313
public class CommandHandler
1414
{
1515
readonly Router router;
16-
public CommandHandler(Router router) {
16+
/// <summary>
17+
///
18+
/// </summary>
19+
/// <param name="router"></param>
20+
/// <param name="chat">Ensure instatiate after <see cref="ChatHandler"/>, so that it can have higher priority in <see cref="ChatHandler.ProcessIncomingMessage"/></param>
21+
public CommandHandler(Router router, ChatHandler chat) {
1722
this.router = router;
1823
On.Terraria.Chat.Commands.SayChatCommand.ProcessIncomingMessage += ProcessIncomingMessage;
1924
On.OTAPI.HooksSystemContext.MainSystemContext.InvokeCommandProcess += ProcessConsoleMessage;

src/OTAPI.UnifiedServerProcess.GlobalNetwork/Network/Router.cs

Lines changed: 96 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,8 @@ public class Router
1515
public static readonly MessageBuffer[] globalMsgBuffers = new MessageBuffer[257];
1616
public readonly ServerContext[] clientCurrentlyServers = new ServerContext[256];
1717
static Router() {
18-
const int maxTilesX = 8400;
19-
const int maxTilesY = 2400;
20-
var tmp = new RootContext("tmp");
21-
tmp.Main.maxTilesX = maxTilesX;
22-
tmp.Main.maxTilesY = maxTilesY;
23-
2418
for (int i = 0; i < 256; i++) {
25-
globalClients[i] = new RemoteClient(tmp) {
19+
globalClients[i] = new RemoteClient() {
2620
Id = i,
2721
ReadBuffer = new byte[1024]
2822
};
@@ -39,11 +33,14 @@ public Router(int listenPort, ServerContext main, params ServerContext[] allServ
3933

4034
On.Terraria.NetMessageSystemContext.mfwh_CheckBytes += ProcessBytes;
4135
On.Terraria.NetplaySystemContext.mfwh_UpdateServerInMainThread += UpdateServerInMainThread;
36+
On.Terraria.NetMessageSystemContext.CheckCanSend += NetMessageSystemContext_CheckCanSend;
4237

4338
this.main = main;
4439
this.servers = allServers;
4540

4641
listener = new TcpListener(IPAddress.Any, listenPort);
42+
broadcastClient = new UdpClient();
43+
broadcastClient.EnableBroadcast = true;
4744

4845
var listenThread = new Thread(ServerLoop) {
4946
IsBackground = true,
@@ -52,6 +49,10 @@ public Router(int listenPort, ServerContext main, params ServerContext[] allServ
5249
listenThread.Start();
5350
}
5451

52+
private bool NetMessageSystemContext_CheckCanSend(On.Terraria.NetMessageSystemContext.orig_CheckCanSend orig, NetMessageSystemContext self, int clientIndex) {
53+
return clientCurrentlyServers[clientIndex] == self.root && globalClients[clientIndex].IsConnected();
54+
}
55+
5556
private void UpdateServerInMainThread(On.Terraria.NetplaySystemContext.orig_mfwh_UpdateServerInMainThread orig, NetplaySystemContext self) {
5657
var server = self.root;
5758
for (int i = 0; i < 256; i++) {
@@ -132,6 +133,8 @@ private void ProcessBytes(On.Terraria.NetMessageSystemContext.orig_mfwh_CheckByt
132133

133134
readonly TcpListener listener;
134135
volatile bool isListening;
136+
readonly UdpClient broadcastClient;
137+
volatile bool keepBroadcasting;
135138

136139
public event Func<TcpClient, ISocket>? CreateSocket;
137140
public event Action? Started;
@@ -152,38 +155,43 @@ void ServerLoop() {
152155
}
153156

154157
private void UpdateConnectedClients() {
155-
for (int i = 0; i < 256; i++) {
156-
var client = globalClients[i];
157-
var server = clientCurrentlyServers[i];
158-
159-
if (client.PendingTermination) {
160-
if (client.PendingTerminationApproved) {
161-
client.Reset(main);
162-
server.NetMessage.SyncDisconnectedPlayer(i);
163-
164-
bool active = server.Main.player[i].active;
165-
server.Main.player[i].active = false;
166-
if (active) {
167-
server.Player.Hooks.PlayerDisconnect(i);
168-
}
158+
try {
159+
for (int i = 0; i < 256; i++) {
160+
var client = globalClients[i];
161+
var server = clientCurrentlyServers[i];
162+
163+
if (client.PendingTermination) {
164+
if (client.PendingTerminationApproved) {
165+
client.Reset(main);
166+
server.NetMessage.SyncDisconnectedPlayer(i);
167+
168+
bool active = server.Main.player[i].active;
169+
server.Main.player[i].active = false;
170+
if (active) {
171+
server.Player.Hooks.PlayerDisconnect(i);
172+
}
169173

170-
clientCurrentlyServers[i] = main;
174+
clientCurrentlyServers[i] = main;
175+
}
176+
continue;
171177
}
172-
continue;
173-
}
174-
if (client.IsConnected()) {
175-
lock (client) {
176-
client.Update(server);
177-
server.Netplay.HasClients = true;
178+
if (client.IsConnected()) {
179+
lock (client) {
180+
client.Update(server);
181+
server.Netplay.HasClients = true;
182+
}
183+
continue;
178184
}
179-
continue;
180-
}
181-
if (client.IsActive) {
182-
client.PendingTermination = true;
183-
client.PendingTerminationApproved = true;
184-
continue;
185+
if (client.IsActive) {
186+
client.PendingTermination = true;
187+
client.PendingTerminationApproved = true;
188+
continue;
189+
}
190+
client.StatusText2 = "";
185191
}
186-
client.StatusText2 = "";
192+
}
193+
catch (Exception ex) {
194+
187195
}
188196
}
189197

@@ -196,6 +204,15 @@ static int GetClientSpace() {
196204
}
197205
return space;
198206
}
207+
static int GetActiveClientCount() {
208+
int count = 0;
209+
for (int i = 0; i < 255; i++) {
210+
if (globalClients[i].IsActive) {
211+
count += 1;
212+
}
213+
}
214+
return count;
215+
}
199216

200217
void StartListeningIfNeeded() {
201218
if (isListening || !main.IsRunning || GetClientSpace() <= 0) {
@@ -204,6 +221,7 @@ void StartListeningIfNeeded() {
204221
isListening = true;
205222
listener.Start();
206223
Task.Run(ListenLoop);
224+
Task.Run(LaunchBroadcast);
207225
}
208226
void ListenLoop() {
209227
while (main.IsRunning && GetClientSpace() > 0) {
@@ -217,6 +235,49 @@ void ListenLoop() {
217235
}
218236
listener.Stop();
219237
isListening = false;
238+
keepBroadcasting = false;
239+
}
240+
void LaunchBroadcast() {
241+
try {
242+
keepBroadcasting = true;
243+
int playerCountPosInStream = 0;
244+
byte[] data;
245+
using (MemoryStream memoryStream = new MemoryStream()) {
246+
using (BinaryWriter bw = new BinaryWriter(memoryStream)) {
247+
int value = 1010;
248+
bw.Write(value);
249+
bw.Write(ListenPort);
250+
bw.Write("Unified-Server-Process");
251+
string text = Dns.GetHostName();
252+
if (text == "localhost") {
253+
text = Environment.MachineName;
254+
}
255+
bw.Write(text);
256+
bw.Write((ushort)main.Main.maxTilesX);
257+
bw.Write(main.Main.ActiveWorldFileData.HasCrimson);
258+
bw.Write(main.Main.ActiveWorldFileData.GameMode);
259+
bw.Write(255);
260+
playerCountPosInStream = (int)memoryStream.Position;
261+
bw.Write((byte)0);
262+
bw.Write(main.Main.ActiveWorldFileData.IsHardMode);
263+
bw.Flush();
264+
data = memoryStream.ToArray();
265+
}
266+
}
267+
do {
268+
data[(int)playerCountPosInStream] = (byte)GetActiveClientCount();
269+
try {
270+
broadcastClient.Send(data, data.Length, new IPEndPoint(IPAddress.Broadcast, 8888));
271+
}
272+
catch {
273+
}
274+
Thread.Sleep(1000);
275+
}
276+
while (keepBroadcasting);
277+
}
278+
catch {
279+
keepBroadcasting = false;
280+
}
220281
}
221282

222283
void OnConnectionAccepted(ISocket client) {

src/OTAPI.UnifiedServerProcess.GlobalNetwork/Network/SyncHelper.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,16 @@ static void SendSectionsWhenJoin(this ServerContext server, int whoAmI) {
4949
static void SendWorldEntities(this ServerContext server, int whoAmI) {
5050
server.NetMessage.SyncConnectedPlayer(whoAmI);
5151
for (int i = 0; i < Terraria.Main.maxItems; i++) {
52+
server.NetMessage.TrySendData(MessageID.SyncItem, whoAmI, -1, null, i);
5253
if (server.Main.item[i].active) {
53-
server.NetMessage.TrySendData(MessageID.SyncItem, whoAmI, -1, null, i);
5454
server.NetMessage.TrySendData(MessageID.ItemOwner, whoAmI, -1, null, i);
5555
}
5656
}
5757
for (int i = 0; i < Terraria.Main.maxNPCs; i++) {
58-
if (server.Main.npc[i].active) {
59-
server.NetMessage.TrySendData(MessageID.SyncNPC, whoAmI, -1, null, i);
60-
}
58+
server.NetMessage.TrySendData(MessageID.SyncNPC, whoAmI, -1, null, i);
6159
}
6260
for (int i = 0; i < Terraria.Main.maxProjectiles; i++) {
63-
if (server.Main.projectile[i].active && (Main.projPet[server.Main.projectile[i].type] || server.Main.projectile[i].netImportant)) {
64-
server.NetMessage.TrySendData(MessageID.SyncProjectile, whoAmI, -1, null, i);
65-
}
61+
server.NetMessage.TrySendData(MessageID.SyncProjectile, whoAmI, -1, null, i);
6662
}
6763
}
6864
static void SendWorldInfo(this ServerContext server, int whoAmI) {
@@ -82,7 +78,20 @@ static void SendWorldInfo(this ServerContext server, int whoAmI) {
8278

8379
#region Sync Server Offline To Player
8480
public static void SyncServerOfflineToPlayer(ServerContext offlineServer, int plr) {
85-
81+
for (int i = 0; i < Terraria.Main.maxProjectiles; i++) {
82+
var proj = offlineServer.Main.projectile[i];
83+
if (!proj.active) {
84+
continue;
85+
}
86+
offlineServer.NetMessage.TrySendData(MessageID.KillProjectile, plr, -1, null, proj.identity, proj.owner);
87+
}
88+
for (int i = 0; i < Terraria.Main.maxPlayers; i++) {
89+
var player = offlineServer.Main.player[i];
90+
if (!player.active) {
91+
continue;
92+
}
93+
offlineServer.NetMessage.TrySendData(MessageID.PlayerActive, plr, i, null, i, 0);
94+
}
8695
}
8796
#endregion
8897

src/OTAPI.UnifiedServerProcess.GlobalNetwork/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using OTAPI.UnifiedServerProcess.GlobalNetwork.IO;
1+
using OTAPI.UnifiedServerProcess.GlobalNetwork.CLI;
22
using OTAPI.UnifiedServerProcess.GlobalNetwork.Network;
33
using OTAPI.UnifiedServerProcess.GlobalNetwork.Servers;
44
using ReLogic.OS;
@@ -42,7 +42,7 @@ static void Main(string[] args) {
4242

4343
var (router, cmdh) = WorkRunner.RunTimedWork("Creating global network...", () => {
4444
var router = new Router(7777, server1, [server1, server2]);
45-
var cmdh = new CommandHandler(router);
45+
var cmdh = new CommandHandler(router, new ChatHandler(router));
4646
return (router, cmdh);
4747
});
4848

0 commit comments

Comments
 (0)