Skip to content

Commit

Permalink
#30 Sync bioprinter.
Browse files Browse the repository at this point in the history
  • Loading branch information
zuev93 committed Jun 19, 2023
1 parent f9e17fb commit bb3c777
Show file tree
Hide file tree
Showing 9 changed files with 338 additions and 0 deletions.
44 changes: 44 additions & 0 deletions MultiplayerMod/Game/UI/Screens/Events/ImmigrantScreenEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using HarmonyLib;
using MultiplayerMod.Core.Dependency;
using MultiplayerMod.Core.Patch;
using MultiplayerMod.Core.Scheduling;

namespace MultiplayerMod.Game.UI.Screens.Events;

[HarmonyPatch(typeof(ImmigrantScreen))]
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public static class ImmigrantScreenEvents {
public static event Action<List<ITelepadDeliverable>> ImmigrationInitialized;
public static event System.Action ImmigrationRejected;
public static event Action<ITelepadDeliverable> ImmigrationProceed;

[HarmonyPostfix]
[HarmonyPatch(nameof(ImmigrantScreen.Initialize))]
private static void Initialize(ImmigrantScreen __instance) => PatchControl.RunIfEnabled(
() => new TaskFactory(Container.Get<UnityTaskScheduler>()).StartNew(
async () => {
if (ImmigrantScreenPatch.Deliverables != null) return;

var readyDeliverables = await ImmigrantScreenPatch.WaitForAllDeliverablesReady(__instance);
if (readyDeliverables != null) {
ImmigrationInitialized?.Invoke(readyDeliverables);
ImmigrantScreenPatch.Deliverables = readyDeliverables;
}
}
)
);

[HarmonyPostfix]
[HarmonyPatch(nameof(ImmigrantScreen.OnRejectionConfirmed))]
private static void OnRejectionConfirmed() => PatchControl.RunIfEnabled(() => ImmigrationRejected?.Invoke());

[HarmonyPrefix]
[HarmonyPatch("OnProceed")]
private static void OnProceed(ImmigrantScreen __instance) =>
PatchControl.RunIfEnabled(() => ImmigrationProceed?.Invoke(__instance.selectedDeliverables[0]));

}
120 changes: 120 additions & 0 deletions MultiplayerMod/Game/UI/Screens/ImmigrantScreenPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using HarmonyLib;
using MultiplayerMod.Core.Dependency;
using MultiplayerMod.Core.Patch;
using MultiplayerMod.Core.Scheduling;
using UnityEngine;

namespace MultiplayerMod.Game.UI.Screens;

[HarmonyPatch(typeof(ImmigrantScreen))]
public static class ImmigrantScreenPatch {

private const int delayMS = 1;
private const int maxWaitMS = 50;

public static List<ITelepadDeliverable> Deliverables { get; set; }

[HarmonyPostfix]
[HarmonyPatch(nameof(ImmigrantScreen.Initialize))]
private static void Initialize(ImmigrantScreen __instance) => PatchControl.RunIfEnabled(
() => new TaskFactory(Container.Get<UnityTaskScheduler>()).StartNew(
async () => {
if (Deliverables == null) return;

// Wait until default initialize is complete
await WaitForAllDeliverablesReady(__instance);
// Create correct containers.
InitializeContainers(ImmigrantScreen.instance);
// Wait until those containers are initialized with random data.
await WaitForAllDeliverablesReady(__instance);

SetDeliverablesData(__instance);
}
)
);

public static async Task<List<ITelepadDeliverable>> WaitForAllDeliverablesReady(ImmigrantScreen instance) {
var currentDelay = 0;
while (currentDelay < maxWaitMS) {
var readyDeliverables = instance.containers?.Select(
a => a switch {
CharacterContainer container => (ITelepadDeliverable) container.stats,
CarePackageContainer packageContainer => packageContainer.carePackageInstanceData,
_ => null
}
).Where(a => a != null).ToList();
if (readyDeliverables != null && readyDeliverables.Count == instance.containers.Count)
return readyDeliverables;

await Task.Delay(delayMS);
currentDelay += delayMS;
}
return null;
}

private static void InitializeContainers(CharacterSelectionController screen) {
screen.OnReplacedEvent = null;
screen.containers?.ForEach(cc => Object.Destroy(cc.GetGameObject()));
screen.containers?.Clear();
screen.containers = new List<ITelepadDeliverableContainer>();

screen.numberOfCarePackageOptions = 0;
screen.numberOfDuplicantOptions = 0;
screen.selectedDeliverables = new List<ITelepadDeliverable>();

foreach (var deliverable in Deliverables) {
if (deliverable is MinionStartingStats) {
var characterContainer = Util.KInstantiateUI<CharacterContainer>(
screen.containerPrefab.gameObject,
screen.containerParent
);
screen.containers.Add(characterContainer);
characterContainer.SetController(screen);
characterContainer.SetReshufflingState(false);
screen.numberOfDuplicantOptions++;
} else {
var packageContainer = Util.KInstantiateUI<CarePackageContainer>(
screen.carePackageContainerPrefab.gameObject,
screen.containerParent
);
screen.containers.Add(packageContainer);
packageContainer.SetController(screen);
screen.numberOfCarePackageOptions++;
}
}
}

private static void SetDeliverablesData(CharacterSelectionController screen) {
var minionStats = Deliverables.OfType<MinionStartingStats>().ToArray();
var packageData =
Deliverables.OfType<CarePackageContainer.CarePackageInstanceData>().ToArray();
for (var i = 0; i < minionStats.Length; i++) {
SetCharacterStats(screen.containers.OfType<CharacterContainer>().ToArray()[i], minionStats[i]);
}
for (var i = 0; i < packageData.Length; i++) {
SetPackageData(screen.containers.OfType<CarePackageContainer>().ToArray()[i], packageData[i]);
}
}

private static void SetCharacterStats(CharacterContainer characterContainer, MinionStartingStats stats) {
// Based on CharacterContainer.GenerateCharacter
characterContainer.stats = stats;
characterContainer.SetAnimator();
characterContainer.SetInfoText();
}

private static void SetPackageData(
CarePackageContainer packageContainer,
CarePackageContainer.CarePackageInstanceData data
) {
// Based on CharacterContainer.GenerateCharacter
packageContainer.carePackageInstanceData = data;
packageContainer.info = data.info;
packageContainer.ClearEntryIcons();
packageContainer.SetAnimator();
packageContainer.SetInfoText();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using MultiplayerMod.Game.UI.Screens;

namespace MultiplayerMod.Multiplayer.Commands.Screens.Immigration;

[Serializable]
public class InitializeImmigration : IMultiplayerCommand {

private List<ITelepadDeliverable> deliverables;

public InitializeImmigration(List<ITelepadDeliverable> deliverables) {
this.deliverables = deliverables;
}

public void Execute() {
ImmigrantScreenPatch.Deliverables = deliverables;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using MultiplayerMod.Game.UI.Screens;

namespace MultiplayerMod.Multiplayer.Commands.Screens.Immigration;

[Serializable]
public class ProceedImmigration : IMultiplayerCommand {
private readonly ITelepadDeliverable deliverable;

public ProceedImmigration(ITelepadDeliverable deliverable) {
this.deliverable = deliverable;
}

public void Execute() {
var immigrantScreen = ImmigrantScreen.instance;
if (immigrantScreen == null) return;

immigrantScreen.RemoveLast();
immigrantScreen.AddDeliverable(deliverable);
immigrantScreen.proceedButton.SignalClick(KKeyCode.Mouse0);

ImmigrantScreenPatch.Deliverables = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using MultiplayerMod.Game.UI.Screens;

namespace MultiplayerMod.Multiplayer.Commands.Screens.Immigration;

[Serializable]
public class RejectImmigration : IMultiplayerCommand {

public void Execute() {
if (ImmigrantScreen.instance == null) return;

ImmigrantScreen.instance.OnRejectionConfirmed();

ImmigrantScreenPatch.Deliverables = null;
}
}
6 changes: 6 additions & 0 deletions MultiplayerMod/Multiplayer/Configuration/GameEventBindings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using MultiplayerMod.Game.UI.Screens.Events;
using MultiplayerMod.Game.UI.Tools.Events;
using MultiplayerMod.Multiplayer.Commands.Screens.Consumable;
using MultiplayerMod.Multiplayer.Commands.Screens.Immigration;
using MultiplayerMod.Multiplayer.Commands.Screens.Priorities;
using MultiplayerMod.Multiplayer.Commands.Screens.Research;
using MultiplayerMod.Multiplayer.Commands.Screens.Schedule;
Expand Down Expand Up @@ -76,6 +77,11 @@ private void BindScreens() {

UserMenuButtonEvents.UserMenuButtonClicked +=
(gameObject, action) => client.Send(new ClickUserMenuButton(gameObject, action));

ImmigrantScreenEvents.ImmigrationInitialized +=
containers => client.Send(new InitializeImmigration(containers));
ImmigrantScreenEvents.ImmigrationProceed += deliverable => client.Send(new ProceedImmigration(deliverable));
ImmigrantScreenEvents.ImmigrationRejected += () => client.Send(new RejectImmigration());
}

private void BindTools() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Runtime.Serialization;

namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates;

public class CarePackageInstanceDataSurrogate : ISerializationSurrogate, ISurrogateType {

public Type Type => typeof(CarePackageContainer.CarePackageInstanceData);

public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) {
var node = (CarePackageContainer.CarePackageInstanceData) obj;
info.AddValue("facadeID", node.facadeID);
info.AddValue("info.id", node.info.id);
info.AddValue("info.quantity", node.info.quantity);
info.AddValue("info.facadeID", node.info.facadeID);
}

public object SetObjectData(
object obj,
SerializationInfo info,
StreamingContext context,
ISurrogateSelector selector
) {
var node = (CarePackageContainer.CarePackageInstanceData) obj;
node.info = new CarePackageInfo(
info.GetString("info.id"),
(float) info.GetDouble("info.quantity"),
null,
info.GetString("info.facadeID")
);
node.facadeID = info.GetString("facadeID");
return node;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

namespace MultiplayerMod.Platform.Steam.Network.Messaging.Surrogates;

public class MinionStartingStatsSurrogate : ISerializationSurrogate, ISurrogateType {

public Type Type => typeof(MinionStartingStats);

public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) {
var node = (MinionStartingStats) obj;
info.AddValue("Name", node.Name);
info.AddValue("NameStringKey", node.NameStringKey);
info.AddValue("GenderStringKey", node.GenderStringKey);
info.AddValue("stressTrait", node.stressTrait?.Id);
info.AddValue("joyTrait", node.joyTrait?.Id);
info.AddValue("congenitaltrait", node.congenitaltrait?.Id);
info.AddValue("stickerType", node.stickerType);
info.AddValue("voiceIdx", node.voiceIdx);
info.AddValue("personality", node.personality?.Id);
info.AddValue("Traits", node.Traits.Select(a => a?.Id).ToArray());
info.AddValue("StartingLevels.Keys", node.StartingLevels.Keys.ToArray());
info.AddValue("StartingLevels.Values", node.StartingLevels.Values.ToArray());
info.AddValue("skillAptitudes.Keys", node.skillAptitudes.Keys.Select(a => a.Id).ToArray());
info.AddValue("skillAptitudes.Values", node.skillAptitudes.Values.ToArray());
}

public object SetObjectData(
object obj,
SerializationInfo info,
StreamingContext context,
ISurrogateSelector selector
) {
var node = (MinionStartingStats) obj;
node.Name = info.GetString("Name");
node.NameStringKey = info.GetString("NameStringKey");
node.GenderStringKey = info.GetString("GenderStringKey");
node.stressTrait = Db.Get().traits.Get(info.GetString("stressTrait"));
node.joyTrait = Db.Get().traits.Get(info.GetString("joyTrait"));
node.congenitaltrait = Db.Get().traits.TryGet(info.GetString("congenitaltrait"));
node.stickerType = info.GetString("stickerType");
node.voiceIdx = info.GetInt32("voiceIdx");
node.Traits = ((string[]) info.GetValue("Traits", typeof(string[]))).Select(id => Db.Get().traits.Get(id))
.ToList();
node.personality = Db.Get().Personalities.Get(info.GetString("personality"));
node.StartingLevels =
ToDictionary(
(string[]) info.GetValue("StartingLevels.Keys", typeof(string[])),
(int[]) info.GetValue("StartingLevels.Values", typeof(int[]))
);
node.skillAptitudes =
ToDictionary(
((string[]) info.GetValue("skillAptitudes.Keys", typeof(string[])))
.Select(key => Db.Get().SkillGroups.Get(key)).ToArray(),
(float[]) info.GetValue("skillAptitudes.Values", typeof(float[]))
);
node.IsValid = true;
return node;
}

private static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(
IReadOnlyList<TKey> keys,
IReadOnlyList<TValue> values
) {
var result = new Dictionary<TKey, TValue>();
for (var i = 0; i < keys.Count; i++) {
result[keys[i]] = values[i];
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ static SerializationSurrogates() {
Selector.Add(new PrioritySettingSurrogate());
Selector.Add(new TagSurrogate());
Selector.Add(new PathNodeSurrogate());
Selector.Add(new CarePackageInstanceDataSurrogate());
Selector.Add(new MinionStartingStatsSurrogate());
}

private static void Add<T>(this SurrogateSelector selector, T surrogate) where T : ISerializationSurrogate, ISurrogateType {
Expand Down

0 comments on commit bb3c777

Please sign in to comment.