diff --git a/Content.Server/Research/Systems/ResearchSystem.Technology.cs b/Content.Server/Research/Systems/ResearchSystem.Technology.cs
index 9bd71cf7c6..7578d316c5 100644
--- a/Content.Server/Research/Systems/ResearchSystem.Technology.cs
+++ b/Content.Server/Research/Systems/ResearchSystem.Technology.cs
@@ -131,25 +131,6 @@ public sealed partial class ResearchSystem
RaiseLocalEvent(uid, ref ev);
}
- ///
- /// Adds a lathe recipe to the specified technology database
- /// without checking if it can be unlocked.
- ///
- public void AddLatheRecipe(EntityUid uid, string recipe, TechnologyDatabaseComponent? component = null)
- {
- if (!Resolve(uid, ref component))
- return;
-
- if (component.UnlockedRecipes.Contains(recipe))
- return;
-
- component.UnlockedRecipes.Add(recipe);
- Dirty(uid, component);
-
- var ev = new TechnologyDatabaseModifiedEvent();
- RaiseLocalEvent(uid, ref ev);
- }
-
///
/// Returns whether a technology can be unlocked on this database,
/// taking parent technologies into account.
diff --git a/Content.Server/Research/TechnologyDisk/Components/TechnologyDiskComponent.cs b/Content.Server/Research/TechnologyDisk/Components/TechnologyDiskComponent.cs
deleted file mode 100644
index eb5a0623a0..0000000000
--- a/Content.Server/Research/TechnologyDisk/Components/TechnologyDiskComponent.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Content.Shared.Random;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Server.Research.TechnologyDisk.Components;
-
-[RegisterComponent]
-public sealed partial class TechnologyDiskComponent : Component
-{
- ///
- /// The recipe that will be added. If null, one will be randomly generated
- ///
- [DataField("recipes")]
- public List? Recipes;
-
- ///
- /// A weighted random prototype for how rare each tier should be.
- ///
- [DataField("tierWeightPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
- public string TierWeightPrototype = "TechDiskTierWeights";
-}
diff --git a/Content.Server/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs b/Content.Server/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs
deleted file mode 100644
index 176b2b68bc..0000000000
--- a/Content.Server/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-using System.Linq;
-using Content.Server.Popups;
-using Content.Server.Research.Systems;
-using Content.Server.Research.TechnologyDisk.Components;
-using Content.Shared.Examine;
-using Content.Shared.Interaction;
-using Content.Shared.Random;
-using Content.Shared.Random.Helpers;
-using Content.Shared.Research.Components;
-using Content.Shared.Research.Prototypes;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Server.Research.TechnologyDisk.Systems;
-
-public sealed class TechnologyDiskSystem : EntitySystem
-{
- [Dependency] private readonly PopupSystem _popup = default!;
- [Dependency] private readonly ResearchSystem _research = default!;
- [Dependency] private readonly IPrototypeManager _prototype = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
-
- ///
- public override void Initialize()
- {
- SubscribeLocalEvent(OnAfterInteract);
- SubscribeLocalEvent(OnExamine);
- SubscribeLocalEvent(OnMapInit);
- }
-
- private void OnAfterInteract(EntityUid uid, TechnologyDiskComponent component, AfterInteractEvent args)
- {
- if (args.Handled || !args.CanReach || args.Target is not { } target)
- return;
-
- if (!HasComp(target) || !TryComp(target, out var database))
- return;
-
- if (component.Recipes != null)
- {
- foreach (var recipe in component.Recipes)
- {
- _research.AddLatheRecipe(target, recipe, database);
- }
- }
- _popup.PopupEntity(Loc.GetString("tech-disk-inserted"), target, args.User);
- QueueDel(uid);
- args.Handled = true;
- }
-
- private void OnExamine(EntityUid uid, TechnologyDiskComponent component, ExaminedEvent args)
- {
- var message = Loc.GetString("tech-disk-examine-none");
- if (component.Recipes != null && component.Recipes.Any())
- {
- var prototype = _prototype.Index(component.Recipes[0]);
- var resultPrototype = _prototype.Index(prototype.Result);
- message = Loc.GetString("tech-disk-examine", ("result", resultPrototype.Name));
-
- if (component.Recipes.Count > 1) //idk how to do this well. sue me.
- message += " " + Loc.GetString("tech-disk-examine-more");
- }
- args.PushMarkup(message);
- }
-
- private void OnMapInit(EntityUid uid, TechnologyDiskComponent component, MapInitEvent args)
- {
- if (component.Recipes != null)
- return;
-
- var weightedRandom = _prototype.Index(component.TierWeightPrototype);
- var tier = int.Parse(weightedRandom.Pick(_random));
-
- //get a list of every distinct recipe in all the technologies.
- var techs = new List>();
- foreach (var tech in _prototype.EnumeratePrototypes())
- {
- if (tech.Tier != tier)
- continue;
-
- techs.AddRange(tech.RecipeUnlocks);
- }
- techs = techs.Distinct().ToList();
-
- if (!techs.Any())
- return;
-
- //pick one
- component.Recipes = new();
- component.Recipes.Add(_random.Pick(techs));
- }
-}
diff --git a/Content.Shared/Research/Systems/SharedResearchSystem.cs b/Content.Shared/Research/Systems/SharedResearchSystem.cs
index 9819e949b8..81c6950f28 100644
--- a/Content.Shared/Research/Systems/SharedResearchSystem.cs
+++ b/Content.Shared/Research/Systems/SharedResearchSystem.cs
@@ -280,4 +280,23 @@ public abstract class SharedResearchSystem : EntitySystem
comp.UnlockedTechnologies.Clear();
Dirty(uid, comp);
}
+
+ ///
+ /// Adds a lathe recipe to the specified technology database
+ /// without checking if it can be unlocked.
+ ///
+ public void AddLatheRecipe(EntityUid uid, string recipe, TechnologyDatabaseComponent? component = null)
+ {
+ if (!Resolve(uid, ref component))
+ return;
+
+ if (component.UnlockedRecipes.Contains(recipe))
+ return;
+
+ component.UnlockedRecipes.Add(recipe);
+ Dirty(uid, component);
+
+ var ev = new TechnologyDatabaseModifiedEvent();
+ RaiseLocalEvent(uid, ref ev);
+ }
}
diff --git a/Content.Shared/Research/TechnologyDisk/Components/TechnologyDiskComponent.cs b/Content.Shared/Research/TechnologyDisk/Components/TechnologyDiskComponent.cs
new file mode 100644
index 0000000000..ce8a138bdb
--- /dev/null
+++ b/Content.Shared/Research/TechnologyDisk/Components/TechnologyDiskComponent.cs
@@ -0,0 +1,24 @@
+using Content.Shared.Random;
+using Content.Shared.Research.Prototypes;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Research.TechnologyDisk.Components;
+
+[RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentState]
+public sealed partial class TechnologyDiskComponent : Component
+{
+ ///
+ /// The recipe that will be added. If null, one will be randomly generated
+ ///
+ [DataField]
+ [AutoNetworkedField]
+ public List>? Recipes;
+
+ ///
+ /// A weighted random prototype for how rare each tier should be.
+ ///
+ [DataField]
+ public ProtoId TierWeightPrototype = "TechDiskTierWeights";
+}
diff --git a/Content.Shared/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs b/Content.Shared/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs
new file mode 100644
index 0000000000..b0d615fcb3
--- /dev/null
+++ b/Content.Shared/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs
@@ -0,0 +1,94 @@
+using Content.Shared.Examine;
+using Content.Shared.Interaction;
+using Content.Shared.Popups;
+using Content.Shared.Random.Helpers;
+using Content.Shared.Research.Components;
+using Content.Shared.Research.Prototypes;
+using Content.Shared.Research.Systems;
+using Content.Shared.Research.TechnologyDisk.Components;
+using Robust.Shared.Network;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Shared.Research.TechnologyDisk.Systems;
+
+public sealed class TechnologyDiskSystem : EntitySystem
+{
+ [Dependency] private readonly INetManager _net = default!;
+ [Dependency] private readonly IPrototypeManager _protoMan = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedResearchSystem _research = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnAfterInteract);
+ SubscribeLocalEvent(OnExamine);
+ }
+
+ private void OnMapInit(Entity ent, ref MapInitEvent args)
+ {
+ if (ent.Comp.Recipes != null)
+ return;
+
+ var weightedRandom = _protoMan.Index(ent.Comp.TierWeightPrototype);
+ var tier = int.Parse(weightedRandom.Pick(_random));
+
+ //get a list of every distinct recipe in all the technologies.
+ var techs = new HashSet>();
+ foreach (var tech in _protoMan.EnumeratePrototypes())
+ {
+ if (tech.Tier != tier)
+ continue;
+
+ techs.UnionWith(tech.RecipeUnlocks);
+ }
+
+ if (techs.Count == 0)
+ return;
+
+ //pick one
+ ent.Comp.Recipes = [];
+ ent.Comp.Recipes.Add(_random.Pick(techs));
+ Dirty(ent);
+ }
+
+ private void OnAfterInteract(Entity ent, ref AfterInteractEvent args)
+ {
+ if (args.Handled || !args.CanReach || args.Target is not { } target)
+ return;
+
+ if (!HasComp(target) || !TryComp(target, out var database))
+ return;
+
+ if (ent.Comp.Recipes != null)
+ {
+ foreach (var recipe in ent.Comp.Recipes)
+ {
+ _research.AddLatheRecipe(target, recipe, database);
+ }
+ }
+ _popup.PopupClient(Loc.GetString("tech-disk-inserted"), target, args.User);
+ if (_net.IsServer)
+ QueueDel(ent);
+ args.Handled = true;
+ }
+
+ private void OnExamine(Entity ent, ref ExaminedEvent args)
+ {
+ var message = Loc.GetString("tech-disk-examine-none");
+ if (ent.Comp.Recipes != null && ent.Comp.Recipes.Count > 0)
+ {
+ var prototype = _protoMan.Index(ent.Comp.Recipes[0]);
+ var resultPrototype = _protoMan.Index(prototype.Result);
+ message = Loc.GetString("tech-disk-examine", ("result", resultPrototype.Name));
+
+ if (ent.Comp.Recipes.Count > 1) //idk how to do this well. sue me.
+ message += " " + Loc.GetString("tech-disk-examine-more");
+ }
+ args.PushMarkup(message);
+ }
+}