// An ItemTicket version to increase efficiency for the host void TicketValidityCheck(ItemTicket ticket, NetworkMessageInfo message) { // We know that DetermineTicketIndex will either return a correct index or an invalid index if it doesn't work int index = DetermineTicketIndex(ticket); // Using the validity of the index we can tell if the ticket is available and then check if it's still valid bool response = IsValidIndex(index) && m_requestTickets[index].IsValid(); // Silly Unity workaround if (message.Equals(m_blankMessage)) { RespondToTicketValidityCheck(response); } else { networkView.RPC("RespondToTicketValidityCheck", message.sender, response); } }
void RequestItem(int itemID, int preferredIndex, NetworkMessageInfo message) { if (Network.isServer) { ItemTicket ticket = new ItemTicket(); int index = DetermineDesiredIndex(itemID, preferredIndex, RequestCheck.Unrequested); if (IsValidIndex(index)) { // Create the ticket ticket.uniqueID = ticketNumber++; ticket.itemID = itemID; ticket.itemIndex = index; // Ensure the item is successfully reserved ReserveItem(index, ticket); } // Else send back an invalid ticket //Debug.Log("Index: " + index + ", itemID: " + itemID + ", preferredIndex: " + preferredIndex + "."); // This is the only way I've found to check if the message is blank, an alternative method would be preferable if (message.Equals(m_blankMessage)) { RespondToItemRequest(ticket); } else { networkView.RPC("RespondToItemRequest", message.sender, ticket.uniqueID, ticket.itemID, ticket.itemIndex); } } else { ResetResponse(true); Debug.LogError("A client attempted to call RequestItem in NetworkInventory."); } }
void RequestAdd(int itemID, int index, bool adminMode, NetworkMessageInfo info) { if (Network.isServer) { // Create the default response ItemTicket ticket = new ItemTicket(-1, itemID, index); // We now need to check if the itemID is valid if (itemID >= 0) { bool isValidIndex = IsValidIndex(index); // An item can only be requested to be replaced if the item hasn't been requested or we're running in admin mode if (!isValidIndex || !m_isItemRequested[index] || adminMode) { if (isValidIndex) { // Check to see if the item at the index is null, if so we know it is an add request. if (!m_inventory[index]) { if (!IsInventoryFull()) { ticket.uniqueID = ticketNumber++; ++addRequests; ReserveItem(index, ticket); } } // We know it is a replace request so it doesn't matter if the inventory is full, we also know that the item // is either unrequested or we have access to overwrite it because of the intial conditions. else { ticket.uniqueID = ticketNumber++; ReserveItem(index, ticket); } } // If the index is invalid it should be added on to the end which is an add request. else if (!IsInventoryFull()) { ticket.uniqueID = ticketNumber++; ++addRequests; ReserveItem(index, ticket); } } } // Silly workaround for RPC sending limitation if (info.Equals(m_blankMessage)) { RespondToAddRequest(ticket); } else { networkView.RPC("RespondToAddRequest", info.sender, ticket.uniqueID, ticket.itemID, ticket.itemIndex); } } // A client called the function else { ResetResponse(true); Debug.LogError("A client attempted to call RequestAdd in NetworkInventory"); } }
internal void SendRequiredModList(string modList, NetworkMessageInfo info) { GadgetCore.CoreLogger.Log("Client has sent local mod list. Processing..."); try { bool isCompatible = true; List <string> incompatibleReasons = new List <string>(); HashSet <string> handledGadgets = new HashSet <string>(); string[][] splitModList = string.IsNullOrEmpty(modList) ? new string[0][] : modList.Split(',').Select(x => x.Split(':')).ToArray(); foreach (GadgetInfo mod in Gadgets.ListAllGadgetInfos().Where(x => x.Gadget.Enabled && x.Attribute.RequiredOnClients)) { handledGadgets.Add(mod.Attribute.Name); string clientVersion = splitModList.SingleOrDefault(x => x[0] == mod.Attribute.Name)?[1]; if (clientVersion == null) { isCompatible = false; incompatibleReasons.Add($"The Gadget '{mod.Attribute.Name}' (From the mod '{mod.ModName}') is not present on the client"); continue; } int[] clientVersionNums = clientVersion.Split('.').Select(x => int.Parse(x)).Take(4).ToArray(); int[] hostVersionNums = mod.Gadget.GetModVersionString().Split('.').Select(x => int.Parse(x)).ToArray(); hostVersionNums = hostVersionNums.Concat(Enumerable.Repeat(0, 4 - hostVersionNums.Length)).ToArray(); clientVersionNums = clientVersionNums.Concat(Enumerable.Repeat(0, 4 - clientVersionNums.Length)).ToArray(); if (!((mod.Attribute.GadgetCoreVersionSpecificity == VersionSpecificity.MAJOR && clientVersionNums[0] == hostVersionNums[0] && (clientVersionNums[1] > hostVersionNums[1] || (clientVersionNums[1] == hostVersionNums[1] && (clientVersionNums[2] > hostVersionNums[2] || (clientVersionNums[2] == hostVersionNums[2] && clientVersionNums[3] >= hostVersionNums[3]))))) || (mod.Attribute.GadgetCoreVersionSpecificity == VersionSpecificity.MINOR && clientVersionNums[0] == hostVersionNums[0] && clientVersionNums[1] == hostVersionNums[1] && (clientVersionNums[2] > hostVersionNums[2] || (clientVersionNums[2] == hostVersionNums[2] && clientVersionNums[3] >= hostVersionNums[3]))) || (mod.Attribute.GadgetCoreVersionSpecificity == VersionSpecificity.NONBREAKING && clientVersionNums[0] == hostVersionNums[0] && clientVersionNums[1] == hostVersionNums[1] && clientVersionNums[2] == hostVersionNums[2] && clientVersionNums[3] >= hostVersionNums[3]) || (mod.Attribute.GadgetCoreVersionSpecificity == VersionSpecificity.BUGFIX && clientVersionNums[0] == hostVersionNums[0] && clientVersionNums[1] == hostVersionNums[1] && clientVersionNums[2] == hostVersionNums[2] && clientVersionNums[3] == hostVersionNums[3]))) { isCompatible = false; incompatibleReasons.Add($"The Gadget '{mod.Attribute.Name}' (From the mod '{mod.ModName}') is of incompatible versions: Host: {mod.Gadget.GetModVersionString()}, Client: {clientVersion}"); continue; } } if (handledGadgets.Count != splitModList.Length) { isCompatible = false; foreach (string[] modEntry in splitModList.Where(x => !handledGadgets.Contains(x[0]))) { incompatibleReasons.Add($"The Gadget '{modEntry[0]}' (From an unknown mod) is present on the client, but not on the host"); } } if (isCompatible) { if (info.Equals(serverNMI)) { GadgetCore.CoreLogger.Log("Self-connection succesfully established and identified."); ReceiveIDMatrixData(GadgetNetwork.GenerateIDMatrixData()); } else { GadgetCore.CoreLogger.Log("A client connected with compatible mods: " + info.sender.ipAddress); string matrixData = GadgetNetwork.GenerateIDMatrixData(); if (matrixData.Length <= 4096) { GadgetCore.CoreLogger.Log("Sending ID Matrix data as a single block..."); view.RPC("ReceiveIDMatrixData", info.sender, matrixData); } else { string[] splitMatrixData = matrixData.SplitOnLength(MaxChunkSize).ToArray(); GadgetCore.CoreLogger.Log($"Sending ID Matrix data as {splitMatrixData.Length} chunks..."); for (int i = 0; i < splitMatrixData.Length; i++) { view.RPC("ReceiveIDMatrixDataChunk", info.sender, splitMatrixData[i], i, splitMatrixData.Length); } } } } else { GadgetCore.CoreLogger.LogWarning("A client tried to connect with incompatible mods: " + info.sender.ipAddress + Environment.NewLine + " - " + incompatibleReasons.Concat(Environment.NewLine + " - ")); if (Network.isServer) { DisconnectWithMessage(info.sender, "Your mods are incompatible with the server:" + Environment.NewLine + " - " + incompatibleReasons.Concat(Environment.NewLine + " - ")); } else { Network.Disconnect(); } } } catch (Exception e) { GadgetCore.CoreLogger.LogWarning("The following error occured processing an incoming client's mod list: " + info.sender.ipAddress + Environment.NewLine + modList + Environment.NewLine + e.ToString()); if (Network.isServer) { DisconnectWithMessage(info.sender, "An error occured processing your mod list:" + Environment.NewLine + modList + Environment.NewLine + e.ToString()); } else { Network.Disconnect(); } } }