Skip to content

Commit

Permalink
Add IsClosestPlayer check before sending out mecha drones
Browse files Browse the repository at this point in the history
  • Loading branch information
starfi5h committed Mar 23, 2024
1 parent 4d6bfcb commit c1946b7
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
14 changes: 14 additions & 0 deletions NebulaPatcher/Patches/Dynamic/ConstructionModuleComponent_Patch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using HarmonyLib;
using NebulaModel.Packets.Players;
using NebulaWorld;
using NebulaWorld.Player;

#endregion

Expand All @@ -25,4 +26,17 @@ public static void EjectMechaDrone_Prefix(PlanetFactory factory, Player player,
var packet = new PlayerEjectMechaDronePacket(playerId, planetId, targetObjectId, next1ObjectId, next2ObjectId, next3ObjectId, priority);
Multiplayer.Session.Network.SendPacketToLocalStar(packet);
}

[HarmonyPrefix]
[HarmonyPatch(nameof(ConstructionModuleComponent.InsertTmpBuildTarget))]
public static bool InsertTmpBuildTarget_Prefix(ConstructionModuleComponent __instance, int objectId, float value)
{
if (__instance.entityId != 0 || value < DroneManager.MinSqrDistance) return true; // BAB, or distance is very close
if (!Multiplayer.IsActive) return true;

// Only send out mecha drones if local player is the closest player to the target prebuild
if (GameMain.localPlanet == null) return true;
var sqrDistToOtherPlayer = Multiplayer.Session.Drones.GetClosestRemotePlayerSqrDistance(GameMain.localPlanet.factory.prebuildPool[objectId].pos);
return value <= sqrDistToOtherPlayer;
}
}
63 changes: 63 additions & 0 deletions NebulaPatcher/Patches/Transpilers/ConstructionSystem_Transpiler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#region

using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using NebulaModel.Logger;
using NebulaModel.Packets.Factory;
using NebulaWorld;
using NebulaWorld.Player;
using UnityEngine;

#endregion

namespace NebulaPatcher.Patches.Transpilers;

[HarmonyPatch(typeof(ConstructionSystem))]
internal class ConstructionSystem_Transpiler
{
[HarmonyTranspiler]
[HarmonyPatch(nameof(ConstructionSystem.AddBuildTargetToModules))]
public static IEnumerable<CodeInstruction> AddBuildTargetToModules_Transpiler(IEnumerable<CodeInstruction> instructions)
{
try
{
/* Sync Prebuild.itemRequired changes by player, insert local method call after player.package.TakeTailItems
Replace: if (num8 <= num) { this.player.mecha.constructionModule.InsertBuildTarget ... }
With: if (num8 <= num && IsClosestPlayer(ref pos)) { this.player.mecha.constructionModule.InsertBuildTarget ... }
*/

var codeMatcher = new CodeMatcher(instructions)
.MatchForward(true,
new CodeMatch(OpCodes.Ldloc_S),
new CodeMatch(OpCodes.Ldloc_0),
new CodeMatch(OpCodes.Bgt_Un)
);
Log.Info(codeMatcher.IsValid);
var sqrDist = codeMatcher.InstructionAt(-2).operand;
var skipLabel = codeMatcher.Operand;
codeMatcher.Advance(1)
.Insert(
new CodeInstruction(OpCodes.Ldloc_S, sqrDist),
new CodeInstruction(OpCodes.Ldarg_2), //ref Vector3 pos
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(ConstructionSystem_Transpiler), nameof(IsClosestPlayer))),
new CodeInstruction(OpCodes.Brfalse_S, skipLabel)
);

return codeMatcher.InstructionEnumeration();
}
catch (System.Exception e)
{
Log.Error("Transpiler ConstructionSystem.AddBuildTargetToModules failed.");
Log.Error(e);
return instructions;
}
}

static bool IsClosestPlayer(float sqrDist, ref Vector3 pos)
{
if (!Multiplayer.IsActive || sqrDist < DroneManager.MinSqrDistance) return true;
return sqrDist <= Multiplayer.Session.Drones.GetClosestRemotePlayerSqrDistance(pos);
}
}
26 changes: 26 additions & 0 deletions NebulaWorld/Player/DroneManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ namespace NebulaWorld.Player;

public class DroneManager : IDisposable
{
public const float MinSqrDistance = 225.0f;

private readonly Dictionary<ushort, PlayerPosition> cachedPositions = [];
private Vector3[] localPlayerPos = new Vector3[2];
private int localPlayerCount = 0;
private long lastCheckedTick = 0;
private readonly List<CraftData> crafts = [];
private readonly Stack<int> craftRecyleIds = [];
Expand Down Expand Up @@ -68,6 +72,8 @@ public void RefreshCachedPositions()
if (GameMain.gameTick != lastCheckedTick)
{
lastCheckedTick = GameMain.gameTick;
localPlayerCount = 0;
var currentLocalPlanetId = GameMain.localPlanet?.id ?? int.MinValue;
//CachedPositions.Clear();

using (Multiplayer.Session.World.GetRemotePlayersModels(out var remotePlayersModels))
Expand All @@ -89,11 +95,31 @@ public void RefreshCachedPositions()
{
cachedPositions.Add(model.Movement.PlayerID, new PlayerPosition(ejectPos, model.Movement.localPlanetId));
}

if (currentLocalPlanetId != localPlanetId) continue;
if (localPlayerCount >= localPlayerPos.Length)
{
var newArray = new Vector3[localPlayerPos.Length * 2];
Array.Copy(localPlayerPos, newArray, localPlayerPos.Length);
localPlayerPos = newArray;
}
localPlayerPos[localPlayerCount++] = playerPos;
}
}
}
}

public float GetClosestRemotePlayerSqrDistance(Vector3 pos)
{
var result = float.MaxValue;
for (var i = 0; i < localPlayerCount; i++)
{
var sqrMagnitude = (pos - localPlayerPos[i]).sqrMagnitude;
if (sqrMagnitude < result) result = sqrMagnitude;
}
return result;
}

public Vector3 GetPlayerEjectPosition(ushort playerId)
{
return cachedPositions.TryGetValue(playerId, out var value) ? value.Position : GameMain.mainPlayer.position;
Expand Down

0 comments on commit c1946b7

Please sign in to comment.