diff --git a/NebulaModel/Packets/Factory/UpgradeEntityRequest.cs b/NebulaModel/Packets/Factory/UpgradeEntityRequest.cs index 94f9759a1..a95370cad 100644 --- a/NebulaModel/Packets/Factory/UpgradeEntityRequest.cs +++ b/NebulaModel/Packets/Factory/UpgradeEntityRequest.cs @@ -5,20 +5,16 @@ namespace NebulaModel.Packets.Factory public class UpgradeEntityRequest { public int PlanetId { get; set; } - public Float3 pos { get; set; } - public Float4 rot { get; set; } + public int ObjId { get; set; } public int UpgradeProtoId { get; set; } - public bool IsPrebuild { get; set; } public int AuthorId { get; set; } public UpgradeEntityRequest() { } - public UpgradeEntityRequest(int planetId, Float3 pos, Float4 rot, int upgradeProtoId, bool isPrebuild, int authorId) + public UpgradeEntityRequest(int planetId, int objId, int upgradeProtoId, int authorId) { PlanetId = planetId; - this.pos = pos; - this.rot = rot; + ObjId = objId; UpgradeProtoId = upgradeProtoId; - IsPrebuild = isPrebuild; AuthorId = authorId; } } diff --git a/NebulaNetwork/PacketProcessors/Factory/Entity/UpgradeEntityRequestProcessor.cs b/NebulaNetwork/PacketProcessors/Factory/Entity/UpgradeEntityRequestProcessor.cs index 08c85de8f..d21e0e705 100644 --- a/NebulaNetwork/PacketProcessors/Factory/Entity/UpgradeEntityRequestProcessor.cs +++ b/NebulaNetwork/PacketProcessors/Factory/Entity/UpgradeEntityRequestProcessor.cs @@ -4,6 +4,7 @@ using NebulaModel.Packets.Factory; using NebulaWorld; using UnityEngine; +using NebulaModel.Logger; namespace NebulaNetwork.PacketProcessors.Factory.Entity { @@ -29,47 +30,16 @@ public override void ProcessPacket(UpgradeEntityRequest packet, NebulaConnection Multiplayer.Session.Factories.AddPlanetTimer(packet.PlanetId); ItemProto itemProto = LDB.items.Select(packet.UpgradeProtoId); - Quaternion qRot = new Quaternion(packet.rot.x, packet.rot.y, packet.rot.z, packet.rot.w); - Vector3 vPos = new Vector3(packet.pos.x, packet.pos.y, packet.pos.z); + // setting specifyPlanet here to avoid accessing a null object (see GPUInstancingManager activePlanet getter) + PlanetData pData = GameMain.gpuiManager.specifyPlanet; - if (packet.IsPrebuild) - { - for (int i = 1; i < planet.factory.prebuildCursor; i++) - { - PrebuildData pbData = planet.factory.prebuildPool[i]; - if (pbData.pos == vPos && pbData.rot == qRot) - { - DoUpgrade(planet, -i, itemProto); - break; - } - } - } - else - { - for (int i = 1; i < planet.factory.entityCursor; i++) - { - EntityData eData = planet.factory.entityPool[i]; - if (eData.pos == vPos && eData.rot == qRot) - { - DoUpgrade(planet, i, itemProto); - break; - } - } - } + GameMain.gpuiManager.specifyPlanet = planet; + planet.factory.UpgradeFinally(GameMain.mainPlayer, packet.ObjId, itemProto); + GameMain.gpuiManager.specifyPlanet = pData; Multiplayer.Session.Factories.TargetPlanet = NebulaModAPI.PLANET_NONE; Multiplayer.Session.Factories.PacketAuthor = NebulaModAPI.AUTHOR_NONE; } } - - private static void DoUpgrade(PlanetData planet, int objId, ItemProto itemProto) - { - // setting specifyPlanet here to avoid accessing a null object (see GPUInstancingManager activePlanet getter) - PlanetData pData = GameMain.gpuiManager.specifyPlanet; - - GameMain.gpuiManager.specifyPlanet = planet; - planet.factory.UpgradeFinally(GameMain.mainPlayer, objId, itemProto); - GameMain.gpuiManager.specifyPlanet = pData; - } } } diff --git a/NebulaPatcher/Patches/Dynamic/BuildTool_Common_Patch.cs b/NebulaPatcher/Patches/Dynamic/BuildTool_Common_Patch.cs index a57e09e6c..373c0f66e 100644 --- a/NebulaPatcher/Patches/Dynamic/BuildTool_Common_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/BuildTool_Common_Patch.cs @@ -44,7 +44,10 @@ public static bool CreatePrebuilds_Prefix(BuildTool __instance) //If client builds, he need to first send request to the host and wait for reply if (!Multiplayer.Session.LocalPlayer.IsHost && !Multiplayer.Session.Factories.IsIncomingRequest.Value) { - Multiplayer.Session.Network.SendPacket(new CreatePrebuildsRequest(GameMain.localPlanet?.id ?? -1, previews, Multiplayer.Session.Factories.PacketAuthor == NebulaModAPI.AUTHOR_NONE ? Multiplayer.Session.LocalPlayer.Id : Multiplayer.Session.Factories.PacketAuthor, __instance.GetType().ToString())); + if (Multiplayer.Session.BuildTools.InitialCheck(previews[0].lpos)) + { + Multiplayer.Session.Network.SendPacket(new CreatePrebuildsRequest(GameMain.localPlanet?.id ?? -1, previews, Multiplayer.Session.Factories.PacketAuthor == NebulaModAPI.AUTHOR_NONE ? Multiplayer.Session.LocalPlayer.Id : Multiplayer.Session.Factories.PacketAuthor, __instance.GetType().ToString())); + } return false; } return true; diff --git a/NebulaPatcher/Patches/Dynamic/PlanetFactory_Patch.cs b/NebulaPatcher/Patches/Dynamic/PlanetFactory_Patch.cs index ef4f46c3f..d5339d201 100644 --- a/NebulaPatcher/Patches/Dynamic/PlanetFactory_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/PlanetFactory_Patch.cs @@ -79,27 +79,7 @@ public static bool UpgradeFinally_Prefix(PlanetFactory __instance, Player player if (Multiplayer.Session.LocalPlayer.IsHost || !Multiplayer.Session.Factories.IsIncomingRequest.Value) { - bool isPrebuild = false; - Vector3 pos; - Quaternion rot; - - if (objId > 0) - { - // real entity - EntityData eData = __instance.entityPool[objId]; - pos = eData.pos; - rot = eData.rot; - } - else - { - // blueprint build preview - PrebuildData pData = __instance.prebuildPool[-objId]; - pos = pData.pos; - rot = pData.rot; - isPrebuild = true; - } - - Multiplayer.Session.Network.SendPacket(new UpgradeEntityRequest(__instance.planetId, new Float3(pos.x, pos.y, pos.z), new Float4(rot.x, rot.y, rot.z, rot.w), replace_item_proto.ID, isPrebuild, Multiplayer.Session.Factories.PacketAuthor == -1 ? Multiplayer.Session.LocalPlayer.Id : Multiplayer.Session.Factories.PacketAuthor)); + Multiplayer.Session.Network.SendPacket(new UpgradeEntityRequest(__instance.planetId, objId, replace_item_proto.ID, Multiplayer.Session.Factories.PacketAuthor == -1 ? Multiplayer.Session.LocalPlayer.Id : Multiplayer.Session.Factories.PacketAuthor)); } return Multiplayer.Session.LocalPlayer.IsHost || Multiplayer.Session.Factories.IsIncomingRequest.Value; diff --git a/NebulaPatcher/Patches/Dynamic/UIGame_Patch.cs b/NebulaPatcher/Patches/Dynamic/UIGame_Patch.cs index 87ff07ec3..f2cb2f09f 100644 --- a/NebulaPatcher/Patches/Dynamic/UIGame_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/UIGame_Patch.cs @@ -20,5 +20,17 @@ public static void _OnInit_Postfix(UIGame __instance) __instance.dfSpaceGuideOn = Config.Options.SpaceNavigationEnabled; __instance.dfVeinOn = Config.Options.VeinDistributionEnabled; } + + [HarmonyPrefix] + [HarmonyPatch(nameof(UIGame.StarmapChangingToMilkyWay))] + public static bool StarmapChangingToMilkyWay_Prefix(UIGame __instance) + { + if (Multiplayer.IsActive) + { + InGamePopup.ShowInfo("Access Denied", "Milky Way is disabled in multiplayer game.", "OK"); + return false; + } + return true; + } } } diff --git a/NebulaWorld/Factory/BuildToolManager.cs b/NebulaWorld/Factory/BuildToolManager.cs index e6924b197..d7fe0bdac 100644 --- a/NebulaWorld/Factory/BuildToolManager.cs +++ b/NebulaWorld/Factory/BuildToolManager.cs @@ -9,6 +9,10 @@ namespace NebulaWorld.Factory { public class BuildToolManager : IDisposable { + public const long WAIT_TIME = 10000; + public Vector3 LastPosition; + public long LastCheckTime; + public BuildToolManager() { } @@ -61,9 +65,10 @@ public void CreatePrebuildsRequest(CreatePrebuildsRequest packet) tmpNearcdLogic = buildTool.actionBuild.nearcdLogic; tmpPlanetPhysics = buildTool.actionBuild.planetPhysics; Multiplayer.Session.Factories.AddPlanetTimer(packet.PlanetId); - } + } bool incomingBlueprintEvent = packet.BuildToolType == typeof(BuildTool_BlueprintPaste).ToString(); + Vector3 pos = Vector3.zero; //Create Prebuilds from incoming packet and prepare new position List tmpList = new List(); @@ -72,6 +77,7 @@ public void CreatePrebuildsRequest(CreatePrebuildsRequest packet) tmpList.AddRange(buildTool.buildPreviews); buildTool.buildPreviews.Clear(); buildTool.buildPreviews.AddRange(packet.GetBuildPreviews()); + pos = buildTool.buildPreviews[0].lpos; } Multiplayer.Session.Factories.EventFactory = planet.factory; @@ -80,7 +86,7 @@ public void CreatePrebuildsRequest(CreatePrebuildsRequest packet) buildTool.factory = planet.factory; pab.factory = planet.factory; pab.noneTool.factory = planet.factory; - if (Multiplayer.Session.Factories.IsIncomingRequest.Value) + if (Multiplayer.Session.LocalPlayer.IsHost) { // Only the server needs to set these pab.planetPhysics = planet.physics; @@ -89,13 +95,13 @@ public void CreatePrebuildsRequest(CreatePrebuildsRequest packet) //Check if prebuilds can be build (collision check, height check, etc) bool canBuild = false; - if (Multiplayer.Session.Factories.IsIncomingRequest.Value) + if (Multiplayer.Session.LocalPlayer.IsHost) { GameMain.mainPlayer.mecha.buildArea = float.MaxValue; canBuild = CheckBuildingConnections(buildTool.buildPreviews, planet.factory.entityPool, planet.factory.prebuildPool); } - if (canBuild || Multiplayer.Session.Factories.IsIncomingRequest.Value) + if (canBuild || Multiplayer.Session.LocalPlayer.IsClient) { if (Multiplayer.Session.Factories.IsIncomingRequest.Value) { @@ -132,6 +138,7 @@ public void CreatePrebuildsRequest(CreatePrebuildsRequest packet) bpTool.bpCursor = incomingPreviews.Count; bpTool.bpPool = incomingPreviews.ToArray(); bpTool.CreatePrebuilds(); + pos = incomingPreviews[0].lpos; // Revert to previous data bpTool.bpCursor = previousCursor; @@ -160,6 +167,13 @@ public void CreatePrebuildsRequest(CreatePrebuildsRequest packet) Multiplayer.Session.Factories.TargetPlanet = NebulaModAPI.PLANET_NONE; Multiplayer.Session.Factories.PacketAuthor = NebulaModAPI.AUTHOR_NONE; + + if (pos == LastPosition) + { + //Reset check timer on client + Log.Info($"Receive {LastPosition}"); + LastCheckTime = 0; + } } } @@ -238,5 +252,18 @@ public bool CheckBuildingConnections(List buildPreviews, EntityDat } return true; } + + public bool InitialCheck(Vector3 pos) + { + long now = DateTimeOffset.Now.ToUnixTimeMilliseconds(); + if ((now - LastCheckTime) < WAIT_TIME && LastPosition == pos) + { + //Stop client from sending prebuilds at the same position + return false; + } + LastCheckTime = now; + LastPosition = pos; + return true; + } } } diff --git a/NebulaWorld/Factory/FactoryManager.cs b/NebulaWorld/Factory/FactoryManager.cs index ca59916e6..2afd344e2 100644 --- a/NebulaWorld/Factory/FactoryManager.cs +++ b/NebulaWorld/Factory/FactoryManager.cs @@ -232,7 +232,8 @@ public int GetNextPrebuildId(PlanetFactory factory) public void OnNewSetInserterPickTarget(int objId, int otherObjId, int inserterId, int offset, Vector3 pointPos) { - if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.Id == PacketAuthor) + // 1. Client receives the build request from itself 2. Host sends the build request + if (Multiplayer.IsActive && (Multiplayer.Session.LocalPlayer.Id == PacketAuthor || (Multiplayer.Session.LocalPlayer.IsHost && PacketAuthor == NebulaModAPI.AUTHOR_NONE))) { Multiplayer.Session.Network.SendPacketToLocalStar(new NewSetInserterPickTargetPacket(objId, otherObjId, inserterId, offset, pointPos, GameMain.localPlanet?.id ?? -1)); } @@ -240,7 +241,7 @@ public void OnNewSetInserterPickTarget(int objId, int otherObjId, int inserterId public void OnNewSetInserterInsertTarget(int objId, int otherObjId, int inserterId, int offset, Vector3 pointPos) { - if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.Id == PacketAuthor) + if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.Id == PacketAuthor || (Multiplayer.Session.LocalPlayer.IsHost && PacketAuthor == NebulaModAPI.AUTHOR_NONE)) { Multiplayer.Session.Network.SendPacketToLocalStar(new NewSetInserterInsertTargetPacket(objId, otherObjId, inserterId, offset, pointPos, GameMain.localPlanet?.id ?? -1)); }