diff --git a/NebulaClient/MultiplayerClientSession.cs b/NebulaClient/MultiplayerClientSession.cs index c81082203..a4d746dda 100644 --- a/NebulaClient/MultiplayerClientSession.cs +++ b/NebulaClient/MultiplayerClientSession.cs @@ -6,6 +6,7 @@ using NebulaModel.Packets.Session; using NebulaModel.Utils; using NebulaWorld; +using System; using System.Net; using UnityEngine; using WebSocketSharp; @@ -81,6 +82,16 @@ public void DestroySession() { serverConnection?.SendPacket(new StarBroadcastPacket(PacketProcessor.Write(packet), GameMain.data.localStar?.id ?? -1)); } + public void SendPacketToLocalPlanet(T packet) where T : class, new() + { + serverConnection?.SendPacket(new PlanetBroadcastPacket(PacketProcessor.Write(packet), GameMain.mainPlayer.planetId)); + } + public void SendPacketToPlanet(T packet, int planetId) where T : class, new() + { + //Should send packet to particular planet + //Not needed at the moment, used only on the host side + throw new NotImplementedException(); + } public void Reconnect() { diff --git a/NebulaClient/NebulaClient.csproj b/NebulaClient/NebulaClient.csproj index 7de658d4c..2847c7abe 100644 --- a/NebulaClient/NebulaClient.csproj +++ b/NebulaClient/NebulaClient.csproj @@ -80,9 +80,11 @@ + + diff --git a/NebulaClient/PacketProcessors/Players/NewDroneOrderProcessor.cs b/NebulaClient/PacketProcessors/Players/NewDroneOrderProcessor.cs new file mode 100644 index 000000000..d53c4b6fb --- /dev/null +++ b/NebulaClient/PacketProcessors/Players/NewDroneOrderProcessor.cs @@ -0,0 +1,17 @@ +using NebulaModel.Attributes; +using NebulaModel.Networking; +using NebulaModel.Packets.Players; +using NebulaModel.Packets.Processors; +using NebulaWorld; + +namespace NebulaClient.PacketProcessors.Players +{ + [RegisterPacketProcessor] + class NewDroneOrderProcessor : IPacketProcessor + { + public void ProcessPacket(NewDroneOrderPacket packet, NebulaConnection conn) + { + SimulatedWorld.UpdateRemotePlayerDrone(packet); + } + } +} diff --git a/NebulaClient/PacketProcessors/Players/RemoveDroneOrdersProcessor.cs b/NebulaClient/PacketProcessors/Players/RemoveDroneOrdersProcessor.cs new file mode 100644 index 000000000..97bd1e2d3 --- /dev/null +++ b/NebulaClient/PacketProcessors/Players/RemoveDroneOrdersProcessor.cs @@ -0,0 +1,20 @@ +using NebulaModel.Networking; +using NebulaHost.PacketProcessors.Players; +using NebulaModel.Packets.Processors; + +namespace NebulaClient.PacketProcessors.Players +{ + class RemoveDroneOrdersProcessor : IPacketProcessor + { + public void ProcessPacket(RemoveDroneOrdersPacket packet, NebulaConnection conn) + { + if (packet.QueuedEntityIds != null) + { + for (int i = 0; i < packet.QueuedEntityIds.Length; i++) + { + GameMain.mainPlayer.mecha.droneLogic.serving.Remove(packet.QueuedEntityIds[i]); + } + } + } + } +} diff --git a/NebulaHost/MultiplayerHostSession.cs b/NebulaHost/MultiplayerHostSession.cs index 8de44b0f5..9aeb8acb6 100644 --- a/NebulaHost/MultiplayerHostSession.cs +++ b/NebulaHost/MultiplayerHostSession.cs @@ -88,6 +88,16 @@ public void DestroySession() PlayerManager.SendPacketToLocalStar(packet); } + public void SendPacketToLocalPlanet(T packet) where T : class, new() + { + PlayerManager.SendPacketToLocalPlanet(packet); + } + + public void SendPacketToPlanet(T packet, int planetId) where T : class, new() + { + PlayerManager.SendPacketToPlanet(packet, planetId); + } + private void Update() { gameStateUpdateTimer += Time.deltaTime; diff --git a/NebulaHost/NebulaHost.csproj b/NebulaHost/NebulaHost.csproj index 99591a1c9..afb1e099f 100644 --- a/NebulaHost/NebulaHost.csproj +++ b/NebulaHost/NebulaHost.csproj @@ -78,11 +78,13 @@ + + diff --git a/NebulaHost/PacketProcessors/Players/NewDroneOrderProcessor.cs b/NebulaHost/PacketProcessors/Players/NewDroneOrderProcessor.cs new file mode 100644 index 000000000..881c678be --- /dev/null +++ b/NebulaHost/PacketProcessors/Players/NewDroneOrderProcessor.cs @@ -0,0 +1,45 @@ +using NebulaModel.Attributes; +using NebulaModel.Networking; +using NebulaModel.Packets.Players; +using NebulaModel.Packets.Processors; +using NebulaWorld; +using NebulaWorld.Player; + +namespace NebulaHost.PacketProcessors.Players +{ + [RegisterPacketProcessor] + class NewDroneOrderProcessor : IPacketProcessor + { + private PlayerManager playerManager; + + public NewDroneOrderProcessor() + { + playerManager = MultiplayerHostSession.Instance.PlayerManager; + } + + public void ProcessPacket(NewDroneOrderPacket packet, NebulaConnection conn) + { + //Host does not need to know about flying drones of other players if he is not on the same planet + if (GameMain.mainPlayer.planetId != packet.PlanetId) + { + return; + } + + Player player = playerManager.GetPlayer(conn); + + if (player != null) + { + if (packet.Stage == 1 || packet.Stage == 2) + { + DroneManager.AddPlayerDronePlan(player.Id, packet.EntityId); + } + else if (packet.Stage == 3) + { + DroneManager.RemovePlayerDronePlan(player.Id, packet.EntityId); + } + + SimulatedWorld.UpdateRemotePlayerDrone(packet); + } + } + } +} diff --git a/NebulaHost/PacketProcessors/Routers/PlanetBroadcastProcessor.cs b/NebulaHost/PacketProcessors/Routers/PlanetBroadcastProcessor.cs new file mode 100644 index 000000000..94ef86a17 --- /dev/null +++ b/NebulaHost/PacketProcessors/Routers/PlanetBroadcastProcessor.cs @@ -0,0 +1,28 @@ +using NebulaModel.Attributes; +using NebulaModel.Networking; +using NebulaModel.Packets.Processors; +using NebulaModel.Packets.Routers; + +namespace NebulaHost.PacketProcessors.Routers +{ + [RegisterPacketProcessor] + class PlanetBroadcastProcessor : IPacketProcessor + { + private PlayerManager playerManager; + public PlanetBroadcastProcessor() + { + playerManager = MultiplayerHostSession.Instance.PlayerManager; + } + public void ProcessPacket(PlanetBroadcastPacket packet, NebulaConnection conn) + { + Player player = playerManager.GetPlayer(conn); + if (player != null) + { + //Forward packet to other users + playerManager.SendRawPacketToPlanet(packet.PacketObject, packet.PlanetId, conn); + //Forward packet to the host + MultiplayerHostSession.Instance.PacketProcessor.EnqueuePacketForProcessing(packet.PacketObject, conn); + } + } + } +} \ No newline at end of file diff --git a/NebulaHost/PlayerManager.cs b/NebulaHost/PlayerManager.cs index 44f7c69b2..eda15f662 100644 --- a/NebulaHost/PlayerManager.cs +++ b/NebulaHost/PlayerManager.cs @@ -1,8 +1,10 @@ -using NebulaModel.DataStructures; +using NebulaHost.PacketProcessors.Players; +using NebulaModel.DataStructures; using NebulaModel.Logger; using NebulaModel.Networking; using NebulaModel.Packets.Session; using NebulaWorld; +using NebulaWorld.Player; using NebulaWorld.Statistics; using System.Collections.Generic; using System.Linq; @@ -81,6 +83,28 @@ public Player GetSyncingPlayer(NebulaConnection conn) } } + public void SendPacketToLocalPlanet(T packet) where T : class, new() + { + foreach (Player player in GetConnectedPlayers()) + { + if (player.Data.LocalPlanetId == GameMain.data.mainPlayer.planetId) + { + player.SendPacket(packet); + } + } + } + + public void SendPacketToPlanet(T packet, int planetId) where T : class, new() + { + foreach (Player player in GetConnectedPlayers()) + { + if (player.Data.LocalPlanetId == planetId) + { + player.SendPacket(packet); + } + } + } + public void SendRawPacketToStar(byte[] rawPacket, int starId, NebulaConnection sender) { foreach (Player player in GetConnectedPlayers()) @@ -92,6 +116,17 @@ public void SendRawPacketToStar(byte[] rawPacket, int starId, NebulaConnection s } } + public void SendRawPacketToPlanet(byte[] rawPacket, int planetId, NebulaConnection sender) + { + foreach (Player player in GetConnectedPlayers()) + { + if (player.Data.LocalPlanetId == planetId && player.Connection != sender) + { + player.SendRawPacket(rawPacket); + } + } + } + public void SendPacketToOtherPlayers(T packet, Player sender) where T : class, new() { foreach (Player player in GetConnectedPlayers()) @@ -125,6 +160,21 @@ public void PlayerDisconnected(NebulaConnection conn) connectedPlayers.Remove(conn); availablePlayerIds.Enqueue(player.Id); StatisticsManager.instance.UnRegisterPlayer(player.Id); + + //Notify players about queued building plans for drones + int[] DronePlans = DroneManager.GetPlayerDronePlans(player.Id); + if (DronePlans != null && DronePlans.Length > 0 && player.Data.LocalPlanetId > 0) + { + LocalPlayer.SendPacketToPlanet(new RemoveDroneOrdersPacket(DronePlans), player.Data.LocalPlanetId); + //Remove it also from host queue, if host is on the same planet + if (GameMain.mainPlayer.planetId == player.Data.LocalPlanetId) + { + for(int i = 0; i < DronePlans.Length; i++) + { + GameMain.mainPlayer.mecha.droneLogic.serving.Remove(DronePlans[i]); + } + } + } } else { diff --git a/NebulaModel/NebulaModel.csproj b/NebulaModel/NebulaModel.csproj index f329331e8..800e325d2 100644 --- a/NebulaModel/NebulaModel.csproj +++ b/NebulaModel/NebulaModel.csproj @@ -106,13 +106,16 @@ + + + diff --git a/NebulaModel/Packets/Players/NewDroneOrderPacket.cs b/NebulaModel/Packets/Players/NewDroneOrderPacket.cs new file mode 100644 index 000000000..da0015474 --- /dev/null +++ b/NebulaModel/Packets/Players/NewDroneOrderPacket.cs @@ -0,0 +1,23 @@ +namespace NebulaModel.Packets.Players +{ + public class NewDroneOrderPacket + { + public int PlanetId { get; set; } + public int DroneId { get; set; } + public int EntityId { get; set; } + public ushort PlayerId { get; set; } + public int Stage { get; set; } + public int Priority { get; set; } + + public NewDroneOrderPacket() { } + public NewDroneOrderPacket(int planetId, int droneId, int entityId, ushort playerId, int stage, int priority) + { + PlanetId = planetId; + DroneId = droneId; + EntityId = entityId; + PlayerId = playerId; + Stage = stage; + Priority = priority; + } + } +} diff --git a/NebulaModel/Packets/Players/RemoveDroneOrdersPacket.cs b/NebulaModel/Packets/Players/RemoveDroneOrdersPacket.cs new file mode 100644 index 000000000..2dcc80f40 --- /dev/null +++ b/NebulaModel/Packets/Players/RemoveDroneOrdersPacket.cs @@ -0,0 +1,14 @@ +namespace NebulaHost.PacketProcessors.Players +{ + public class RemoveDroneOrdersPacket + { + public int[] QueuedEntityIds { get; set; } + + public RemoveDroneOrdersPacket() { } + + public RemoveDroneOrdersPacket(int[] queuedEntityIds) + { + QueuedEntityIds = queuedEntityIds; + } + } +} diff --git a/NebulaModel/Packets/Routers/PlanetBroadcastPacket.cs b/NebulaModel/Packets/Routers/PlanetBroadcastPacket.cs new file mode 100644 index 000000000..0f1e67cb0 --- /dev/null +++ b/NebulaModel/Packets/Routers/PlanetBroadcastPacket.cs @@ -0,0 +1,15 @@ +namespace NebulaModel.Packets.Routers +{ + public class PlanetBroadcastPacket + { + public byte[] PacketObject { get; set; } + public int PlanetId { get; set; } + + public PlanetBroadcastPacket() { } + public PlanetBroadcastPacket(byte[] packetObject, int planetId) + { + PacketObject = packetObject; + PlanetId = planetId; + } + } +} diff --git a/NebulaPatcher/NebulaPatcher.csproj b/NebulaPatcher/NebulaPatcher.csproj index 96a40c5a2..fbebd9cb8 100644 --- a/NebulaPatcher/NebulaPatcher.csproj +++ b/NebulaPatcher/NebulaPatcher.csproj @@ -47,6 +47,7 @@ + @@ -82,6 +83,7 @@ + diff --git a/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs b/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs index dcd46fbe2..8bb3b1e81 100644 --- a/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs @@ -157,9 +157,9 @@ private static void InitLandingPlace(GameData gameData, PlanetData planet) gameData.mainPlayer.controller.velocityOnLanding = Vector3.zero; } - [HarmonyPrefix] + [HarmonyPostfix] [HarmonyPatch("OnDraw")] - public static void OnDraw_Prefix() + public static void OnDraw_Postfix() { if (SimulatedWorld.Initialized) { @@ -199,5 +199,16 @@ public static void ArriveStar_Prefix(GameData __instance, StarData star) LocalPlayer.SendPacket(new PlayerUpdateLocalStarId(star.id)); } } + + [HarmonyPrefix] + [HarmonyPatch("LeavePlanet")] + public static void LeavePlanet_Prefix(GameData __instance) + { + //Players should clear the list of drone orders of other players when they leave the planet + if (SimulatedWorld.Initialized) + { + GameMain.mainPlayer.mecha.droneLogic.serving.Clear(); + } + } } } diff --git a/NebulaPatcher/Patches/Transpilers/MechaDroneLogic_Patch.cs b/NebulaPatcher/Patches/Transpilers/MechaDroneLogic_Patch.cs new file mode 100644 index 000000000..4eb3cca68 --- /dev/null +++ b/NebulaPatcher/Patches/Transpilers/MechaDroneLogic_Patch.cs @@ -0,0 +1,88 @@ +using HarmonyLib; +using NebulaWorld.Player; +using System.Collections.Generic; +using System.Reflection.Emit; + +namespace NebulaPatcher.Patches.Transpiler +{ + [HarmonyPatch(typeof(MechaDroneLogic))] + class MechaDroneLogic_Patch + { + /* + * Call DroneManager.BroadcastDroneOrder(int droneId, int entityId, int stage) when drone gets new order + */ + [HarmonyTranspiler] + [HarmonyPatch("UpdateTargets")] + static IEnumerable UpdateTargets_Transpiler(IEnumerable instructions) + { + var codes = new List(instructions); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Pop && + codes[i - 1].opcode == OpCodes.Callvirt && + codes[i + 1].opcode == OpCodes.Ldarg_0 && + codes[i - 2].opcode == OpCodes.Ldloc_3) + { + codes.InsertRange(i + 1, new CodeInstruction[] { + new CodeInstruction(OpCodes.Ldloc_S, 11), + new CodeInstruction(OpCodes.Ldloc_3), + new CodeInstruction(OpCodes.Ldc_I4_1), + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DroneManager), "BroadcastDroneOrder", new System.Type[] { typeof(int), typeof(int), typeof(int) })) + }); + break; + } + } + return codes; + } + + /* + * Call DroneManager.BroadcastDroneOrder(int droneId, int entityId, int stage) when drone's stage changes + */ + [HarmonyTranspiler] + [HarmonyPatch("UpdateDrones")] + static IEnumerable UpdateDrones_Transpiler(IEnumerable instructions) + { + var codes = new List(instructions); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Brfalse && + codes[i - 1].opcode == OpCodes.Call && + codes[i + 2].opcode == OpCodes.Ldloc_S && + codes[i + 1].opcode == OpCodes.Ldloc_0 && + codes[i - 2].opcode == OpCodes.Ldloca_S) + { + codes.InsertRange(i + 1, new CodeInstruction[] { + new CodeInstruction(OpCodes.Ldloc_S, 4), + new CodeInstruction(OpCodes.Ldloc_S, 7), + new CodeInstruction(OpCodes.Ldc_I4_2), + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DroneManager), "BroadcastDroneOrder", new System.Type[] { typeof(int), typeof(int), typeof(int) })) + }); + break; + } + } + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Br && + codes[i - 1].opcode == OpCodes.Pop && + codes[i + 2].opcode == OpCodes.Ldloc_S && + codes[i + 1].opcode == OpCodes.Ldloc_0 && + codes[i - 2].opcode == OpCodes.Callvirt && + codes[i - 3].opcode == OpCodes.Ldloc_S) + { + codes.InsertRange(i + 5, new CodeInstruction[] { + new CodeInstruction(OpCodes.Ldloc_S, 4), + new CodeInstruction(OpCodes.Ldloc_0), + new CodeInstruction(OpCodes.Ldloc_S, 4), + new CodeInstruction(OpCodes.Ldelema, typeof(MechaDrone)), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(MechaDrone), "targetObject")), + new CodeInstruction(OpCodes.Ldc_I4_3), + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DroneManager), "BroadcastDroneOrder", new System.Type[] { typeof(int), typeof(int), typeof(int) })) + }); + break; + } + } + return codes; + } + } +} diff --git a/NebulaWorld/INetworkProvider.cs b/NebulaWorld/INetworkProvider.cs index 86778e9b5..90178c2c6 100644 --- a/NebulaWorld/INetworkProvider.cs +++ b/NebulaWorld/INetworkProvider.cs @@ -6,6 +6,10 @@ public interface INetworkProvider void SendPacketToLocalStar(T packet) where T : class, new(); + void SendPacketToLocalPlanet(T packet) where T : class, new(); + + void SendPacketToPlanet(T packet, int planetId) where T : class, new(); + void DestroySession(); } } diff --git a/NebulaWorld/LocalPlayer.cs b/NebulaWorld/LocalPlayer.cs index 065e84f29..3d7bbfde5 100644 --- a/NebulaWorld/LocalPlayer.cs +++ b/NebulaWorld/LocalPlayer.cs @@ -32,6 +32,16 @@ public static void SetNetworkProvider(INetworkProvider provider) networkProvider?.SendPacketToLocalStar(packet); } + public static void SendPacketToLocalPlanet(T packet) where T : class, new() + { + networkProvider?.SendPacketToLocalPlanet(packet); + } + + public static void SendPacketToPlanet(T packet, int planetId) where T : class, new() + { + networkProvider?.SendPacketToPlanet(packet, planetId); + } + public static void SetReady() { if (!IsMasterClient) diff --git a/NebulaWorld/NebulaWorld.csproj b/NebulaWorld/NebulaWorld.csproj index 2d11596d0..ad00f1e20 100644 --- a/NebulaWorld/NebulaWorld.csproj +++ b/NebulaWorld/NebulaWorld.csproj @@ -51,6 +51,7 @@ + diff --git a/NebulaWorld/Player/DroneManager.cs b/NebulaWorld/Player/DroneManager.cs new file mode 100644 index 000000000..c3d1a8489 --- /dev/null +++ b/NebulaWorld/Player/DroneManager.cs @@ -0,0 +1,50 @@ +using NebulaModel.Packets.Players; +using System; +using System.Collections.Generic; + +namespace NebulaWorld.Player +{ + public static class DroneManager + { + public static int[] DronePriorities = new int[255]; + public static Random rnd = new Random(); + public static Dictionary> PlayerDroneBuildingPlans = new Dictionary>(); + + public static void BroadcastDroneOrder(int droneId, int entityId, int stage) + { + int priority = 0; + if (stage == 1 || stage == 2) + { + priority = rnd.Next(); + DronePriorities[droneId] = priority; + } + LocalPlayer.SendPacketToLocalPlanet(new NewDroneOrderPacket(GameMain.mainPlayer.planetId, droneId, entityId, LocalPlayer.PlayerId, stage, priority)); + } + + public static void AddPlayerDronePlan(ushort playerId, int entityId) + { + if (!PlayerDroneBuildingPlans.ContainsKey(playerId)) + { + PlayerDroneBuildingPlans.Add(playerId, new List()); + } + PlayerDroneBuildingPlans[playerId].Add(entityId); + } + + public static void RemovePlayerDronePlan(ushort playerId, int entityId) + { + if (PlayerDroneBuildingPlans.ContainsKey(playerId)) + { + PlayerDroneBuildingPlans[playerId].Remove(entityId); + } + } + + public static int[] GetPlayerDronePlans(ushort playerId) + { + if (PlayerDroneBuildingPlans.ContainsKey(playerId)) + { + return PlayerDroneBuildingPlans[playerId].ToArray(); + } + return null; + } + } +} diff --git a/NebulaWorld/RemotePlayerModel.cs b/NebulaWorld/RemotePlayerModel.cs index d799018e7..ef50338ad 100644 --- a/NebulaWorld/RemotePlayerModel.cs +++ b/NebulaWorld/RemotePlayerModel.cs @@ -20,7 +20,7 @@ public class RemotePlayerModel public Text StarmapNameText { get; set; } public Text StarmapMarker { get; set; } - public Player PlayerInstance { get; set; } + public global::Player PlayerInstance { get; set; } public Mecha MechaInstance { get; set; } public RemotePlayerModel(ushort playerId, string username) @@ -48,11 +48,16 @@ public RemotePlayerModel(ushort playerId, string username) PlayerTransform.gameObject.name = $"Remote Player ({playerId})"; - PlayerInstance = new Player(); + PlayerInstance = new global::Player(); MechaInstance = new Mecha(); - AccessTools.Property(typeof(Player), "mecha").SetValue(PlayerInstance, MechaInstance, null); + AccessTools.Property(typeof(global::Player), "mecha").SetValue(PlayerInstance, MechaInstance, null); MechaInstance.Init(PlayerInstance); + //Fix MechaDroneRenderers + AccessTools.Field(typeof(MechaDroneRenderer), "mat_0").SetValue(MechaInstance.droneRenderer, new Material(Configs.builtin.mechaDroneMat.shader)); + Material mat = (Material)AccessTools.Field(typeof(MechaDroneRenderer), "mat_0").GetValue(MechaInstance.droneRenderer); + MethodInvoker.GetHandler(AccessTools.Method(typeof(Material), "CopyPropertiesFromMaterial", new System.Type[] { typeof(Material) })).Invoke(mat, Configs.builtin.mechaDroneMat); + PlayerId = playerId; Username = username; } diff --git a/NebulaWorld/SimulatedWorld.cs b/NebulaWorld/SimulatedWorld.cs index 8b71cfbdf..eb10fd89f 100644 --- a/NebulaWorld/SimulatedWorld.cs +++ b/NebulaWorld/SimulatedWorld.cs @@ -6,6 +6,7 @@ using NebulaModel.Packets.Trash; using NebulaWorld.Factory; using NebulaWorld.MonoBehaviours.Remote; +using NebulaWorld.Player; using NebulaWorld.Trash; using System.Collections.Generic; using UnityEngine; @@ -114,6 +115,72 @@ public static void UpdateRemotePlayerAnimation(PlayerAnimationUpdate packet) } } + public static void UpdateRemotePlayerDrone(NewDroneOrderPacket packet) + { + if (remotePlayersModels.TryGetValue(packet.PlayerId, out RemotePlayerModel player)) + { + //Setup drone of remote player based on the drone data + ref MechaDrone drone = ref player.PlayerInstance.mecha.drones[packet.DroneId]; + MechaDroneLogic droneLogic = player.PlayerInstance.mecha.droneLogic; + + drone.stage = packet.Stage; + drone.targetObject = packet.Stage < 3 ? packet.EntityId : 0; + drone.movement = droneLogic.player.mecha.droneMovement; + if (packet.Stage == 1) + { + drone.position = player.Movement.GetLastPosition().LocalPlanetPosition.ToVector3(); + } + drone.target = (Vector3)MethodInvoker.GetHandler(AccessTools.Method(typeof(MechaDroneLogic), "_obj_hpos", new System.Type[] { typeof(int) })).Invoke(GameMain.mainPlayer.mecha.droneLogic, packet.EntityId); + drone.initialVector = drone.position + drone.position.normalized * 4.5f + ((drone.target - drone.position).normalized + UnityEngine.Random.insideUnitSphere) * 1.5f; + drone.forward = drone.initialVector; + drone.progress = 0f; + player.MechaInstance.droneCount = GameMain.mainPlayer.mecha.droneCount; + player.MechaInstance.droneSpeed = GameMain.mainPlayer.mecha.droneSpeed; + Mecha myMecha = GameMain.mainPlayer.mecha; + if (packet.Stage == 3) + { + myMecha.droneLogic.serving.Remove(packet.EntityId); + } + + if (drone.stage == 1 || drone.stage == 2) { + //Check if my drone is already going there + if (!myMecha.droneLogic.serving.Contains(packet.EntityId)) + { + myMecha.droneLogic.serving.Add(packet.EntityId); + } else + { + //resolve conflict (two drones are going to the same building) + //find my drone that is going there + int priority = 0; + int droneId = 0; + for (int i = 0; i < myMecha.droneCount; i++) + { + if (myMecha.drones[i].stage > 0 && myMecha.drones[i].targetObject == drone.targetObject) + { + priority = DroneManager.DronePriorities[i]; + droneId = i; + break; + } + } + //compare, who's drone has higher priority + if (packet.Priority > priority) + { + //their drone won, my drone has to return + ref MechaDrone myDrone = ref myMecha.drones[droneId]; + myDrone.stage = 3; + myDrone.targetObject = 0; + } else + { + //my drone won, their has to return + drone.stage = 3; + drone.targetObject = 0; + } + } + } + + } + } + public static void UpdatePlayerColor(ushort playerId, Float3 color) { Transform transform; @@ -263,7 +330,7 @@ public static void OnGameLoadCompleted() GameMain.mainPlayer.uRotation = Quaternion.Euler(LocalPlayer.Data.Rotation.ToVector3()); //Load player's saved data from the last session. - AccessTools.Property(typeof(Player), "package").SetValue(GameMain.mainPlayer, LocalPlayer.Data.Mecha.Inventory, null); + AccessTools.Property(typeof(global::Player), "package").SetValue(GameMain.mainPlayer, LocalPlayer.Data.Mecha.Inventory, null); GameMain.mainPlayer.mecha.forge = LocalPlayer.Data.Mecha.Forge; GameMain.mainPlayer.mecha.coreEnergy = LocalPlayer.Data.Mecha.CoreEnergy; GameMain.mainPlayer.mecha.reactorEnergy = LocalPlayer.Data.Mecha.ReactorEnergy; @@ -288,25 +355,28 @@ public static void OnDronesDraw() { foreach(KeyValuePair remoteModel in remotePlayersModels) { - remoteModel.Value.MechaInstance.droneRenderer.Draw(); + //Render drones of players only on the local planet + if (GameMain.mainPlayer.planetId == remoteModel.Value.Movement.localPlanetId) + { + remoteModel.Value.MechaInstance.droneRenderer.Draw(); + } } } public static void OnDronesGameTick(long time, float dt) { - double tmp = 0; - double tmp2 = 0; + double tmp = 1e10; //fake energy of remote player, needed to do the Update() + double tmp2 = 1; //Update drones positions based on their targets foreach (KeyValuePair remoteModel in remotePlayersModels) { MechaDrone[] drones = remoteModel.Value.PlayerInstance.mecha.drones; - int droneCount = remoteModel.Value.PlayerInstance.mecha.droneCount; + int droneCount = GameMain.mainPlayer.mecha.droneCount; for (int i = 0; i < droneCount; i++) { - if (drones[i].stage != 0) + //Update only moving drones of players on the same planet + if (drones[i].stage != 0 && GameMain.mainPlayer.planetId == remoteModel.Value.Movement.localPlanetId) { - //To-do: fix the correct factory here - //To-do: Optimize getting local position of player drones[i].Update(GameMain.localPlanet.factory.prebuildPool, remoteModel.Value.Movement.GetLastPosition().LocalPlanetPosition.ToVector3(), dt, ref tmp, ref tmp2, 0); } }