Skip to content

Commit

Permalink
Add couriers animation syncing
Browse files Browse the repository at this point in the history
  • Loading branch information
starfi5h committed Oct 4, 2022
1 parent 4aeed4e commit 3e22ce5
Show file tree
Hide file tree
Showing 7 changed files with 356 additions and 5 deletions.
19 changes: 19 additions & 0 deletions NebulaModel/Packets/Logistics/DispenserCourierPacket.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace NebulaModel.Packets.Logistics
{
public class DispenserCourierPacket
{
public int PlayerId { get; set; }
public int DispenserId { get; set; }
public int ItemId { get; set; }
public int ItemCount { get; set; }

public DispenserCourierPacket() { }
public DispenserCourierPacket(int playerId, int dispenserId, int itemId, int itemCount)
{
PlayerId = playerId;
DispenserId = dispenserId;
ItemId = itemId;
ItemCount = itemCount;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using NebulaAPI;
using NebulaModel.Logger;
using NebulaModel.Networking;
using NebulaModel.Packets;
using NebulaModel.Packets.Logistics;
using NebulaWorld;
using System;

namespace NebulaNetwork.PacketProcessors.Logistics
{
[RegisterPacketProcessor]
internal class DispenserCourierProcessor : PacketProcessor<DispenserCourierPacket>
{
public override void ProcessPacket(DispenserCourierPacket packet, NebulaConnection conn)
{
PlanetFactory factory = GameMain.mainPlayer.factory;
DispenserComponent[] pool = factory?.transport.dispenserPool;
if (pool != null && packet.DispenserId > 0 && packet.DispenserId < pool.Length && pool[packet.DispenserId].id == packet.DispenserId)
{
DispenserComponent dispenser = pool[packet.DispenserId];
Multiplayer.Session.Couriers.AddCourier(packet.PlayerId, factory.entityPool[dispenser.entityId].pos, packet.ItemId, packet.ItemCount);
dispenser.pulseSignal = 2;
}
}
}
}
14 changes: 9 additions & 5 deletions NebulaPatcher/Patches/Dynamic/GameData_Patch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,12 +286,16 @@ public static void SetForNewGame_Postfix(GameData __instance)
[HarmonyPatch(nameof(GameData.GameTick))]
public static void GameTick_Postfix(GameData __instance, long time)
{
if (!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost)
if (!Multiplayer.IsActive)
{
if (Multiplayer.IsActive)
{
Multiplayer.Session.Launch.CollectProjectile();
}
return;
}

Multiplayer.Session.Couriers.GameTick(time);

if (Multiplayer.Session.LocalPlayer.IsHost)
{
Multiplayer.Session.Launch.CollectProjectile();
return;
}
Multiplayer.Session.Launch.LaunchProjectile();
Expand Down
62 changes: 62 additions & 0 deletions NebulaPatcher/Patches/Dynamic/LogisticCourierRendererr_Patch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using HarmonyLib;
using NebulaModel;
using NebulaWorld;
using System;

namespace NebulaPatcher.Patches.Dynamic
{
[HarmonyPatch(typeof(LogisticCourierRenderer))]
internal class LogisticCourierRendererr_Patch
{
[HarmonyPrefix]
[HarmonyPatch(nameof(LogisticCourierRenderer.Update))]
public static bool Update_Prefix(LogisticCourierRenderer __instance)
{
if (!Multiplayer.IsActive)
{
return true;
}

__instance.courierCount = 0;
if (__instance.transport == null)
{
return false;
}
for (int i = 1; i < __instance.transport.dispenserCursor; i++)
{
DispenserComponent dispenserComponent = __instance.transport.dispenserPool[i];
if (dispenserComponent != null && dispenserComponent.id == i)
{
int num = __instance.courierCount + dispenserComponent.workCourierCount;
if (num > 0)
{
while (__instance.capacity < num)
{
__instance.Expand2x();
}
Array.Copy(dispenserComponent.workCourierDatas, 0, __instance.couriersArr, __instance.courierCount, dispenserComponent.workCourierCount);
__instance.courierCount = num;
}
}
}

// Add remote couriers animation
int courierCount = __instance.courierCount + Multiplayer.Session.Couriers.CourierCount;
if (courierCount > 0)
{
while (__instance.capacity < courierCount)
{
__instance.Expand2x();
}
Array.Copy(Multiplayer.Session.Couriers.CourierDatas, 0, __instance.couriersArr, __instance.courierCount, Multiplayer.Session.Couriers.CourierCount);
__instance.courierCount = courierCount;
}

if (__instance.couriersBuffer != null)
{
__instance.couriersBuffer.SetData(__instance.couriersArr, 0, 0, __instance.courierCount);
}
return false;
}
}
}
42 changes: 42 additions & 0 deletions NebulaPatcher/Patches/Transpilers/DispenserComponent_Transpiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,36 @@ public static IEnumerable<CodeInstruction> InternalTick_Transpiler(IEnumerable<C
.RemoveInstruction()
.Insert(new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DispenserComponent_Transpiler), "PickFromStorage")));

// When courier go from idle to work for player order, broadcast to all players on the same planet
// c# 107:
//>> Insert IdleCourierToWork(this) => IdleCourierToWork
// this.workCourierCount++;
matcher
.MatchForward(false,
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "workCourierCount"),
new CodeMatch(OpCodes.Ldc_I4_1),
new CodeMatch(OpCodes.Add),
new CodeMatch(i => i.opcode == OpCodes.Stfld && ((FieldInfo)i.operand).Name == "workCourierCount"))
.Insert(
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DispenserComponent_Transpiler), "IdleCourierToWork")));

// c# 170: (same as above)
matcher
.Advance(8)
.MatchForward(false,
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "workCourierCount"),
new CodeMatch(OpCodes.Ldc_I4_1),
new CodeMatch(OpCodes.Add),
new CodeMatch(i => i.opcode == OpCodes.Stfld && ((FieldInfo)i.operand).Name == "workCourierCount"))
.Insert(
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DispenserComponent_Transpiler), "IdleCourierToWork")));

// When courier back to home, test if it recycles items from player. If true, broadcast item increase in distributor storage.
// c# 604:
// bool useBan = this.orders[j].otherId >= 0;
Expand Down Expand Up @@ -83,5 +113,17 @@ public static int InsertIntoStorage(PlanetFactory factory, int entityId, int ite
}
return factory.InsertIntoStorage(entityId, itemId, count, inc, out remainInc, useBan);
}

public static void IdleCourierToWork(DispenserComponent dispenser)
{
if (Multiplayer.IsActive)
{
Multiplayer.Session.Network.SendPacketToLocalPlanet(
new DispenserCourierPacket(Multiplayer.Session.LocalPlayer.Id,
dispenser.id,
dispenser.workCourierDatas[dispenser.workCourierCount].itemId,
dispenser.workCourierDatas[dispenser.workCourierCount].itemCount));
}
}
}
}
193 changes: 193 additions & 0 deletions NebulaWorld/Logistics/CourierManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
using NebulaAPI;
using NebulaModel.Logger;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace NebulaWorld.Logistics
{
public class CourierManager
{
public int CourierCount { get; private set; }
public CourierData[] CourierDatas { get; private set; }

private Vector3[] EntityPositions;
private Dictionary<int, Vector3> PlayerPostions;
private int tmp_iter;
private float courierSpeed;

public CourierManager()
{
CourierCount = 0;
CourierDatas = new CourierData[10];
EntityPositions = new Vector3[10];
PlayerPostions = new Dictionary<int, Vector3>();
tmp_iter = 0;
}

public void Dispose()
{
CourierCount = 0;
CourierDatas = null;
EntityPositions = null;
PlayerPostions = null;
}

public void AddCourier(int playerId, in Vector3 entityPos, int itemId, int itemCount)
{
if (CourierCount >= CourierDatas.Length)
{
CourierData[] sourceArray = CourierDatas;
CourierDatas = new CourierData[CourierDatas.Length * 2];
Array.Copy(sourceArray, CourierDatas, CourierCount);
Vector3[] sourceArray2 = EntityPositions;
EntityPositions = new Vector3[CourierDatas.Length * 2];
Array.Copy(sourceArray2, EntityPositions, CourierCount);
}
CourierDatas[CourierCount].begin = entityPos;
CourierDatas[CourierCount].end = entityPos;
CourierDatas[CourierCount].endId = playerId;
CourierDatas[CourierCount].direction = 1f;
CourierDatas[CourierCount].maxt = 1f;
CourierDatas[CourierCount].t = 0f;
CourierDatas[CourierCount].itemId = itemId;
CourierDatas[CourierCount].itemCount = itemCount;
CourierDatas[CourierCount].gene = tmp_iter++;
EntityPositions[CourierCount] = entityPos;
CourierCount++;
DeterminePosition();

courierSpeed = GameMain.history.logisticCourierSpeedModified;
}

private void DeterminePosition()
{
PlayerPostions.Clear();
using (Multiplayer.Session.World.GetRemotePlayersModels(out Dictionary<ushort, RemotePlayerModel> remotePlayersModels))
{
foreach (RemotePlayerModel model in remotePlayersModels.Values)
{
// Check only players on the same planet
if (model.Movement.GetLastPosition().LocalPlanetId != GameMain.mainPlayer.planetId)
{
continue;
}
// Cache players positions for courier position updating
PlayerPostions.Add(model.Movement.PlayerID, model.PlayerTransform.position);
}
}
}

public void GameTick(long time)
{
if (CourierCount <= 0 || GameMain.mainPlayer.factory == null)
{
return;
}

DeterminePosition();

// Calculate extra couriers position for animation
for (int j = 0; j < CourierCount; j++)
{
if (CourierDatas[j].maxt <= 0f)
{
continue;
}
if (!PlayerPostions.ContainsKey(CourierDatas[j].endId))
{
// player does not exist, mark to remove later on
CourierDatas[j].maxt = 0;
continue;
}
if (CourierDatas[j].direction > 0f) // (CourierDatas[j].endId < 0 && CourierDatas[j].direction > 0f)
{
Vector3 EntityPos = EntityPositions[j];
ref Vector3 courierPtr = ref CourierDatas[j].end;
Vector3 playerPos = PlayerPostions[CourierDatas[j].endId];
Vector3 vector1 = playerPos - courierPtr;
Vector3 vector2 = playerPos - EntityPos;
float courierToPlayerDist = vector1.magnitude;
float entityToPlayerDist = vector2.magnitude;
float courierHeight = courierPtr.magnitude;
float playerHeight = playerPos.magnitude;
if (courierToPlayerDist < 1.4f)
{
float entityHeight = EntityPos.magnitude;
double cosValue = (double)(EntityPos.x * playerPos.x + EntityPos.y * playerPos.y + EntityPos.z * playerPos.z) / (entityHeight * playerHeight);
if (cosValue < -1.0)
{
cosValue = -1.0;
}
else if (cosValue > 1.0)
{
cosValue = 1.0;
}
// courier reach player
CourierDatas[j].begin = EntityPos;
CourierDatas[j].maxt = (float)(Math.Acos(cosValue) * ((entityHeight + playerHeight) * 0.5));
CourierDatas[j].maxt = (float)Math.Sqrt((double)(CourierDatas[j].maxt * CourierDatas[j].maxt) + (entityHeight - playerHeight) * (entityHeight - playerHeight));
CourierDatas[j].t = CourierDatas[j].maxt;
}
else
{
CourierDatas[j].begin = courierPtr;
float progress = courierSpeed * 0.016666668f / courierToPlayerDist;
if (progress > 1f)
{
progress = 1f;
}
Vector3 vector3 = new(vector1.x * progress, vector1.y * progress, vector1.z * progress);
float totalTime = courierToPlayerDist / courierSpeed;
if (totalTime < 0.03333333f)
{
totalTime = 0.03333333f;
}
float deltaHeight = (playerHeight - courierHeight) / totalTime * 0.016666668f;
courierPtr += vector3;
courierPtr = courierPtr.normalized * (courierHeight + deltaHeight);
if (entityToPlayerDist > CourierDatas[j].maxt)
{
CourierDatas[j].maxt = entityToPlayerDist;
}
CourierDatas[j].t = courierToPlayerDist;
if (CourierDatas[j].t >= CourierDatas[j].maxt * 0.99f)
{
CourierDatas[j].t = CourierDatas[j].maxt * 0.99f;
}
}
}
else
{
CourierDatas[j].t += 0.016666668f * courierSpeed * CourierDatas[j].direction;
}


if (CourierDatas[j].t >= CourierDatas[j].maxt)
{
// Courier reach remote player
CourierDatas[j].t = CourierDatas[j].maxt;
CourierDatas[j].direction = -1f;
}
else if (CourierDatas[j].t <= 0f)
{
// Courier back to home
CourierDatas[j].maxt = 0;
}
}

// Remove marked couriers
int i = 0;
for (int j = 0; j < CourierCount; j++)
{
if (CourierDatas[j].maxt > 0)
{
CourierDatas[i++] = CourierDatas[j];
EntityPositions[i++] = EntityPositions[j];
}
}
CourierCount = i;
}

}
}
Loading

0 comments on commit 3e22ce5

Please sign in to comment.