ResearchSystem.Technology.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using Content.Shared.Database;
  2. using Content.Shared.Research.Components;
  3. using Content.Shared.Research.Prototypes;
  4. using JetBrains.Annotations;
  5. namespace Content.Server.Research.Systems;
  6. public sealed partial class ResearchSystem
  7. {
  8. /// <summary>
  9. /// Syncs the primary entity's database to that of the secondary entity's database.
  10. /// </summary>
  11. public void Sync(EntityUid primaryUid, EntityUid otherUid, TechnologyDatabaseComponent? primaryDb = null, TechnologyDatabaseComponent? otherDb = null)
  12. {
  13. if (!Resolve(primaryUid, ref primaryDb) || !Resolve(otherUid, ref otherDb))
  14. return;
  15. primaryDb.MainDiscipline = otherDb.MainDiscipline;
  16. primaryDb.CurrentTechnologyCards = otherDb.CurrentTechnologyCards;
  17. primaryDb.SupportedDisciplines = otherDb.SupportedDisciplines;
  18. primaryDb.UnlockedTechnologies = otherDb.UnlockedTechnologies;
  19. primaryDb.UnlockedRecipes = otherDb.UnlockedRecipes;
  20. Dirty(primaryUid, primaryDb);
  21. var ev = new TechnologyDatabaseSynchronizedEvent();
  22. RaiseLocalEvent(primaryUid, ref ev);
  23. }
  24. /// <summary>
  25. /// If there's a research client component attached to the owner entity,
  26. /// and the research client is connected to a research server, this method
  27. /// syncs against the research server, and the server against the local database.
  28. /// </summary>
  29. /// <returns>Whether it could sync or not</returns>
  30. public void SyncClientWithServer(EntityUid uid, TechnologyDatabaseComponent? databaseComponent = null, ResearchClientComponent? clientComponent = null)
  31. {
  32. if (!Resolve(uid, ref databaseComponent, ref clientComponent, false))
  33. return;
  34. if (!TryComp<TechnologyDatabaseComponent>(clientComponent.Server, out var serverDatabase))
  35. return;
  36. Sync(uid, clientComponent.Server.Value, databaseComponent, serverDatabase);
  37. }
  38. /// <summary>
  39. /// Tries to add a technology to a database, checking if it is able to
  40. /// </summary>
  41. /// <returns>If the technology was successfully added</returns>
  42. public bool UnlockTechnology(EntityUid client,
  43. string prototypeid,
  44. EntityUid user,
  45. ResearchClientComponent? component = null,
  46. TechnologyDatabaseComponent? clientDatabase = null)
  47. {
  48. if (!PrototypeManager.TryIndex<TechnologyPrototype>(prototypeid, out var prototype))
  49. return false;
  50. return UnlockTechnology(client, prototype, user, component, clientDatabase);
  51. }
  52. /// <summary>
  53. /// Tries to add a technology to a database, checking if it is able to
  54. /// </summary>
  55. /// <returns>If the technology was successfully added</returns>
  56. public bool UnlockTechnology(EntityUid client,
  57. TechnologyPrototype prototype,
  58. EntityUid user,
  59. ResearchClientComponent? component = null,
  60. TechnologyDatabaseComponent? clientDatabase = null)
  61. {
  62. if (!Resolve(client, ref component, ref clientDatabase, false))
  63. return false;
  64. if (!TryGetClientServer(client, out var serverEnt, out _, component))
  65. return false;
  66. if (!CanServerUnlockTechnology(client, prototype, clientDatabase, component))
  67. return false;
  68. AddTechnology(serverEnt.Value, prototype);
  69. TrySetMainDiscipline(prototype, serverEnt.Value);
  70. ModifyServerPoints(serverEnt.Value, -prototype.Cost);
  71. UpdateTechnologyCards(serverEnt.Value);
  72. _adminLog.Add(LogType.Action, LogImpact.Medium,
  73. $"{ToPrettyString(user):player} unlocked {prototype.ID} (discipline: {prototype.Discipline}, tier: {prototype.Tier}) at {ToPrettyString(client)}, for server {ToPrettyString(serverEnt.Value)}.");
  74. return true;
  75. }
  76. /// <summary>
  77. /// Adds a technology to the database without checking if it could be unlocked.
  78. /// </summary>
  79. [PublicAPI]
  80. public void AddTechnology(EntityUid uid, string technology, TechnologyDatabaseComponent? component = null)
  81. {
  82. if (!Resolve(uid, ref component))
  83. return;
  84. if (!PrototypeManager.TryIndex<TechnologyPrototype>(technology, out var prototype))
  85. return;
  86. AddTechnology(uid, prototype, component);
  87. }
  88. /// <summary>
  89. /// Adds a technology to the database without checking if it could be unlocked.
  90. /// </summary>
  91. public void AddTechnology(EntityUid uid, TechnologyPrototype technology, TechnologyDatabaseComponent? component = null)
  92. {
  93. if (!Resolve(uid, ref component))
  94. return;
  95. //todo this needs to support some other stuff, too
  96. foreach (var generic in technology.GenericUnlocks)
  97. {
  98. if (generic.PurchaseEvent != null)
  99. RaiseLocalEvent(generic.PurchaseEvent);
  100. }
  101. component.UnlockedTechnologies.Add(technology.ID);
  102. foreach (var unlock in technology.RecipeUnlocks)
  103. {
  104. if (component.UnlockedRecipes.Contains(unlock))
  105. continue;
  106. component.UnlockedRecipes.Add(unlock);
  107. }
  108. Dirty(uid, component);
  109. var ev = new TechnologyDatabaseModifiedEvent();
  110. RaiseLocalEvent(uid, ref ev);
  111. }
  112. /// <summary>
  113. /// Returns whether a technology can be unlocked on this database,
  114. /// taking parent technologies into account.
  115. /// </summary>
  116. /// <returns>Whether it could be unlocked or not</returns>
  117. public bool CanServerUnlockTechnology(EntityUid uid,
  118. TechnologyPrototype technology,
  119. TechnologyDatabaseComponent? database = null,
  120. ResearchClientComponent? client = null)
  121. {
  122. if (!Resolve(uid, ref client, ref database, false))
  123. return false;
  124. if (!TryGetClientServer(uid, out _, out var serverComp, client))
  125. return false;
  126. if (!IsTechnologyAvailable(database, technology))
  127. return false;
  128. if (technology.Cost > serverComp.Points)
  129. return false;
  130. return true;
  131. }
  132. private void OnDatabaseRegistrationChanged(EntityUid uid, TechnologyDatabaseComponent component, ref ResearchRegistrationChangedEvent args)
  133. {
  134. if (args.Server != null)
  135. return;
  136. component.MainDiscipline = null;
  137. component.CurrentTechnologyCards = new List<string>();
  138. component.SupportedDisciplines = new List<string>();
  139. component.UnlockedTechnologies = new List<string>();
  140. component.UnlockedRecipes = new List<string>();
  141. Dirty(uid, component);
  142. }
  143. }