2using Microsoft.Xna.Framework;
 
    3using Microsoft.Xna.Framework.Graphics;
 
    6using System.Collections.Generic;
 
   10using Terraria.Localization;
 
   12using Terraria.ModLoader.Core;
 
   13using Terraria.ModLoader.UI.DownloadManager;
 
   14using Terraria.ModLoader.UI;
 
   20        internal class ModHeader
 
   28            public ModHeader(
string name, 
Version version, 
byte[] hash, 
bool signed) {
 
   30                this.version = version;
 
   36            public bool Matches(TmodFile mod) => name == mod.name && version == mod.version && hash.SequenceEqual(mod.hash);
 
   37            public override string ToString() => name + 
" v" + version;
 
   40        internal class NetConfig
 
   42            public string modname;
 
   43            public string configname;
 
   46            public NetConfig(
string modname, 
string configname, 
string json) {
 
   47                this.modname = modname;
 
   48                this.configname = configname;
 
   54        internal static bool downloadModsFromServers = 
true;
 
   55        internal static bool onlyDownloadSignedMods = 
false;
 
   57        internal static bool[] isModdedClient = 
new bool[256];
 
   64            netID >= 0 && netID < netMods.Length ? 
netMods[netID] : 
null;
 
   69        internal static List<NetConfig> pendingConfigs = 
new List<NetConfig>();
 
   74        internal static void AssignNetIDs() {
 
   76            for (
short i = 0; i < 
netMods.Length; i++)
 
   80        internal static void Unload() {
 
   82            if (!Main.dedServ && Main.netMode != 1) 
 
   86        internal static void SyncMods(
int clientIndex) {
 
   87            var p = 
new ModPacket(MessageID.SyncMods);
 
   93            p.Write(syncMods.Count);
 
   94            foreach (var mod 
in syncMods) { 
 
   96                p.Write(mod.Version.ToString());
 
   97                p.Write(mod.File.hash);
 
   98                p.Write(mod.File.ValidModBrowserSignature);
 
  106            var queue = 
new Queue<Mod>(syncMods.Where(m => m.Side == 
ModSide.Both));
 
  107            while (queue.Count > 0) {
 
  108                foreach (var dep 
in AssemblyManager.GetDependencies(queue.Dequeue())) {
 
  109                    if (dep.Side == 
ModSide.NoSync && !syncMods.Contains(dep)) {
 
  118            if (!
ConfigManager.Configs.TryGetValue(mod, out var configs)) {
 
  123            var serverConfigs = configs.Where(x => x.Mode == 
ConfigScope.ServerSide).ToArray();
 
  124            p.Write(serverConfigs.Length);
 
  125            foreach (var config 
in serverConfigs) {
 
  126                string json = JsonConvert.SerializeObject(config, 
ConfigManager.serializerSettingsCompact);
 
  127                Logging.Terraria.Info($
"Sending Server Config {config.mod.Name} {config.Name}: {json}");
 
  129                p.Write(config.Name);
 
  134        internal static void SyncClientMods(
BinaryReader reader) {
 
  135            if (!SyncClientMods(reader, out 
bool needsReload))
 
  145        internal static bool SyncClientMods(
BinaryReader reader, out 
bool needsReload) {
 
  147            Logging.tML.Info($
"Server reports AllowVanillaClients set to {AllowVanillaClients}");
 
  149            Main.statusText = Language.GetTextValue(
"tModLoader.MPSyncingMods");
 
  151            var modFiles = ModOrganizer.FindMods();
 
  154            pendingConfigs.Clear();
 
  155            var syncSet = 
new HashSet<string>();
 
  156            var blockedList = 
new List<ModHeader>();
 
  158            int n = reader.ReadInt32();
 
  159            for (
int i = 0; i < n; i++) {
 
  160                var header = 
new ModHeader(reader.ReadString(), 
new Version(reader.ReadString()), reader.ReadBytes(20), reader.ReadBoolean());
 
  161                syncSet.Add(header.name);
 
  163                int configCount = reader.ReadInt32();
 
  164                for (
int c = 0; c < configCount; c++)
 
  165                    pendingConfigs.Add(
new NetConfig(header.name, reader.ReadString(), reader.ReadString()));
 
  167                var clientMod = clientMods.SingleOrDefault(m => m.Name == header.name);
 
  168                if (clientMod != 
null && header.Matches(clientMod.File))
 
  173                var localVersions = modFiles.Where(m => m.Name == header.name).ToArray();
 
  174                var matching = Array.Find(localVersions, mod => header.Matches(mod.modFile));
 
  175                if (matching != 
null) {
 
  176                    matching.Enabled = 
true;
 
  181                if (localVersions.Length > 0)
 
  182                    header.path = localVersions[0].modFile.path;
 
  184                if (downloadModsFromServers && (header.signed || !onlyDownloadSignedMods))
 
  187                    blockedList.Add(header);
 
  190            foreach (var mod 
in clientMods)
 
  191                if (mod.Side == 
ModSide.Both && !syncSet.Contains(mod.Name)) {
 
  196            if (blockedList.Count > 0) {
 
  197                var msg = Language.GetTextValue(
"tModLoader.MPServerModsCantDownload");
 
  198                msg += downloadModsFromServers
 
  199                    ? Language.GetTextValue(
"tModLoader.MPServerModsCantDownloadReasonSigned")
 
  200                    : Language.GetTextValue(
"tModLoader.MPServerModsCantDownloadReasonAutomaticDownloadDisabled");
 
  201                msg += 
".\n" + Language.GetTextValue(
"tModLoader.MPServerModsCantDownloadChangeSettingsHint") + 
"\n";
 
  202                foreach (var mod 
in blockedList)
 
  206                Interface.errorMessage.Show(msg, 0);
 
  212                foreach (var pendingConfig 
in pendingConfigs)
 
  213                    JsonConvert.PopulateObject(pendingConfig.json, 
ConfigManager.GetConfig(pendingConfig), 
ConfigManager.serializerSettingsCompact);
 
  219                    foreach (var pendingConfig 
in pendingConfigs)
 
  230            var p = 
new ModPacket(MessageID.ModFile);
 
  238        internal const int CHUNK_SIZE = 16384;
 
  239        internal static void SendMod(
string modName, 
int toClient) {
 
  241            var path = mod.File.path;
 
  242            var fs = File.OpenRead(path);
 
  245                var p = 
new ModPacket(MessageID.ModFile);
 
  246                p.Write(mod.DisplayName);
 
  251            var buf = 
new byte[CHUNK_SIZE];
 
  253            while ((count = fs.Read(buf, 0, buf.Length)) > 0) {
 
  254                var p = 
new ModPacket(MessageID.ModFile, CHUNK_SIZE + 3);
 
  255                p.Write(buf, 0, count);
 
  269                    Interface.progress.Show(displayText: reader.ReadString(), cancel: 
CancelDownload);
 
  279                Interface.progress.Progress = downloadingFile.Position / (float)
downloadingLength;
 
  284                    using (mod.Open()) { }
 
  287                        throw new Exception(Language.GetTextValue(
"tModLoader.MPErrorModHashMismatch"));
 
  289                    if (
downloadingMod.signed && onlyDownloadSignedMods && !mod.ValidModBrowserSignature)
 
  290                        throw new Exception(Language.GetTextValue(
"tModLoader.MPErrorModNotSigned"));
 
  303                    Logging.tML.Error(
"Unknown error during mod sync", exc2);
 
  306                var msg = Language.GetTextValue(
"tModLoader.MPErrorModDownloadError", 
downloadingMod.name);
 
  308                Interface.errorMessage.Show(msg + e, 0);
 
  310                Netplay.disconnect = 
true;
 
  322            Netplay.disconnect = 
true;
 
  328                ModLoader.OnSuccessfulLoad = NetReload();
 
  342        internal static bool NetReloadActive;
 
  343        internal static Action NetReload() {
 
  345            var path = Main.ActivePlayerFileData.Path;
 
  346            var isCloudSave = Main.ActivePlayerFileData.IsCloudSave;
 
  347            NetReloadActive = 
true;
 
  349                NetReloadActive = 
false;
 
  351                Player.GetFileData(path, isCloudSave).SetAsActive();
 
  353                Main.player[Main.myPlayer].hostile = 
false;
 
  354                Main.clientPlayer = (Player)Main.player[Main.myPlayer].clientClone();
 
  361        internal static void SendNetIDs(
int toClient) {
 
  362            var p = 
new ModPacket(MessageID.ModPacket);
 
  369            p.Write(Player.MaxBuffs);
 
  376            var list = 
new List<Mod>();
 
  377            var n = reader.ReadInt32();
 
  378            for (
short i = 0; i < n; i++) {
 
  379                var name = reader.ReadString();
 
  380                var mod = mods.SingleOrDefault(m => m.Name == name);
 
  390            int serverMaxBuffs = reader.ReadInt32();
 
  391            if (serverMaxBuffs != Player.MaxBuffs) {
 
  392                Netplay.disconnect = 
true;
 
  393                Main.statusText = $
"The server expects Player.MaxBuffs of {serverMaxBuffs}\nbut this client reports {Player.MaxBuffs}.\nSome mod is behaving poorly.";
 
  398        internal static bool ReadUnderflowBypass = 
false; 
 
  399        internal static void HandleModPacket(
BinaryReader reader, 
int whoAmI, 
int length) {
 
  405            var 
id = 
NetModCount < 256 ? reader.ReadByte() : reader.ReadInt16();
 
  406            int start = (int)reader.BaseStream.Position;
 
  407            int actualLength = length - 1 - (
NetModCount < 256 ? 1 : 2);
 
  409                ReadUnderflowBypass = 
false;
 
  411                if (!ReadUnderflowBypass && reader.BaseStream.Position - start != actualLength) {
 
  412                    throw new IOException($
"Read underflow {reader.BaseStream.Position - start} of {actualLength} bytes caused by {GetMod(id).Name} in HandlePacket");
 
  417            if (Main.netMode == 1) {
 
  423        internal static bool HijackGetData(ref 
byte messageType, ref 
BinaryReader reader, 
int playerNumber) {
 
  428            bool hijacked = 
false;
 
  429            long readerPos = reader.BaseStream.Position;
 
  430            long biggestReaderPos = readerPos;
 
  432                if (mod.HijackGetData(ref messageType, ref reader, playerNumber)) {
 
  434                    biggestReaderPos = Math.Max(reader.BaseStream.Position, biggestReaderPos);
 
  436                reader.BaseStream.Position = readerPos;
 
  439                reader.BaseStream.Position = biggestReaderPos;
 
  444        internal static bool HijackSendData(
int whoAmI, 
int msgType, 
int remoteClient, 
int ignoreClient, NetworkText text, 
int number, 
float number2, 
float number3, 
float number4, 
int number5, 
int number6, 
int number7) {
 
  445            bool hijacked = 
false;
 
  447                hijacked |= mod.
HijackSendData(whoAmI, msgType, remoteClient, ignoreClient, text, number, number2, number3, number4, number5, number6, number7);
 
  467        internal static void ResetNetDiag() {
 
  468            if (
netMods == 
null || Main.netMode == 2) 
return;
 
  469            for (
int i = 0; i < 
netMods.Length; i++) {
 
  477        internal static void DrawModDiagnoseNet() {
 
  481            for (
int j = -1; j < 
netMods.Length; j++) {
 
  482                int i = j + Main.maxMsg + 2;
 
  485                int xAdjust = i / 50;
 
  487                y += (i - xAdjust * 50) * 13;
 
  489                    Main.spriteBatch.DrawString(Main.fontMouseText, 
"Mod          Received(#, Bytes)     Sent(#, Bytes)", 
new Vector2((
float)x, (
float)y), Color.White, 0f, 
default(Vector2), scale, SpriteEffects.None, 0f);
 
  492                Main.spriteBatch.DrawString(Main.fontMouseText, 
netMods[j].
Name, 
new Vector2(x, y), Color.White, 0f, 
default(Vector2), scale, SpriteEffects.None, 0f);
 
  494                Main.spriteBatch.DrawString(Main.fontMouseText, 
rxMsgType[j].ToString(), 
new Vector2(x, y), Color.White, 0f, 
default(Vector2), scale, SpriteEffects.None, 0f);
 
  496                Main.spriteBatch.DrawString(Main.fontMouseText, 
rxDataType[j].ToString(), 
new Vector2(x, y), Color.White, 0f, 
default(Vector2), scale, SpriteEffects.None, 0f);
 
  498                Main.spriteBatch.DrawString(Main.fontMouseText, 
txMsgType[j].ToString(), 
new Vector2(x, y), Color.White, 0f, 
default(Vector2), scale, SpriteEffects.None, 0f);
 
  500                Main.spriteBatch.DrawString(Main.fontMouseText, 
txDataType[j].ToString(), 
new Vector2(x, y), Color.White, 0f, 
default(Vector2), scale, SpriteEffects.None, 0f);
 
virtual void OnChanged()
This hook is called anytime new config values have been set and are ready to take effect....
 
This serves as the central class from which item-related functions are carried out....
 
Mod is an abstract class that you will override. It serves as a central place from which the mod's co...
 
virtual void HandlePacket(BinaryReader reader, int whoAmI)
Called whenever a net message / packet is received from a client (if this is a server) or the server ...
 
virtual string Name
Stores the name of the mod. This name serves as the mod's identification, and also helps with saving ...
 
virtual bool HijackSendData(int whoAmI, int msgType, int remoteClient, int ignoreClient, NetworkText text, int number, float number2, float number3, float number4, int number5, int number6, int number7)
Hijacks the send data method. Only use if you absolutely know what you are doing. If any hooks return...
 
virtual void Close()
Close is called before Unload, and may be called at any time when mod unloading is imminent (such as ...
 
This serves as the central class which loads mods. It contains many static fields and methods related...
 
static Mod GetMod(string name)
Gets the instance of the Mod with the specified name.
 
static ModHeader downloadingMod
 
static Mod GetMod(int netID)
 
static void ReadNetIDs(BinaryReader reader)
 
static void SendServerConfigs(ModPacket p, Mod mod)
 
static void CancelDownload()
 
static void SetupDiagnostics()
 
static void AddNoSyncDeps(List< Mod > syncMods)
 
static long downloadingLength
 
static bool IsModdedClient(int i)
 
static void OnModsDownloaded(bool needsReload)
 
static bool AllowVanillaClients
 
static void DownloadNextMod()
 
static Queue< ModHeader > downloadQueue
 
static FileStream downloadingFile
 
This class inherits from BinaryWriter. This means that you can use all of its writing functions to se...
 
void Send(int toClient=-1, int ignoreClient=-1)
Sends all the information you've written between client and server. If the toClient parameter is non-...
 
This is where all ModWorld hooks are gathered and called.
 
ConfigScope
Each ModConfig class has a different scope. Failure to use the correct mode will lead to bugs.
 
ModSide
A ModSide enum defines how mods are synced between clients and servers. You can set your mod's ModSid...