You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
5.2 KiB

  1. use std::collections::HashMap;
  2. use shrev::ReaderId;
  3. use space_crush_common::{
  4. components::{FleetOwned, PlayerOwned, Ship},
  5. misc::ComponentEvent,
  6. };
  7. use specs::{
  8. hibitset::BitSetLike, prelude::*, world::Index, Entities, ReadExpect, ReadStorage, System,
  9. World, WriteStorage,
  10. };
  11. use crate::{components::FleetInfo, resources::PlayerState};
  12. pub struct FleetInfoUpdate {
  13. modified: HashMap<Index, Modified>,
  14. need_update: BitSet,
  15. fleet_owned_id: ReaderId<ComponentEvent<FleetOwned>>,
  16. player_owned_id: ReaderId<ComponentEvent<PlayerOwned>>,
  17. }
  18. #[derive(Default)]
  19. struct Modified {
  20. old_fleet_id: Option<Entity>,
  21. old_player_id: Option<Entity>,
  22. }
  23. impl FleetInfoUpdate {
  24. pub fn new(world: &mut World) -> Self {
  25. let modified = HashMap::new();
  26. let need_update = BitSet::new();
  27. let fleet_owned_id = unsafe {
  28. WriteStorage::<FleetOwned>::setup(world);
  29. let mut fleet_owned = world.system_data::<WriteStorage<FleetOwned>>();
  30. fleet_owned
  31. .unprotected_storage_mut()
  32. .channel_mut()
  33. .register_reader()
  34. };
  35. let player_owned_id = unsafe {
  36. WriteStorage::<PlayerOwned>::setup(world);
  37. let mut player_owned = world.system_data::<WriteStorage<PlayerOwned>>();
  38. player_owned
  39. .unprotected_storage_mut()
  40. .channel_mut()
  41. .register_reader()
  42. };
  43. Self {
  44. modified,
  45. need_update,
  46. fleet_owned_id,
  47. player_owned_id,
  48. }
  49. }
  50. }
  51. #[derive(SystemData)]
  52. pub struct FleetInfoUpdateData<'a> {
  53. entities: Entities<'a>,
  54. player_state: ReadExpect<'a, PlayerState>,
  55. ships: ReadStorage<'a, Ship>,
  56. fleet_infos: WriteStorage<'a, FleetInfo>,
  57. fleet_owned: ReadStorage<'a, FleetOwned>,
  58. player_owned: ReadStorage<'a, PlayerOwned>,
  59. }
  60. impl<'a> System<'a> for FleetInfoUpdate {
  61. type SystemData = FleetInfoUpdateData<'a>;
  62. fn run(&mut self, data: Self::SystemData) {
  63. let FleetInfoUpdateData {
  64. entities,
  65. player_state,
  66. ships,
  67. mut fleet_infos,
  68. fleet_owned,
  69. player_owned,
  70. } = data;
  71. self.modified.clear();
  72. self.need_update.clear();
  73. /* player owned events */
  74. let events = player_owned
  75. .unprotected_storage()
  76. .channel()
  77. .read(&mut self.player_owned_id);
  78. for event in events {
  79. match event {
  80. ComponentEvent::Inserted(id) => {
  81. self.need_update.add(*id);
  82. }
  83. ComponentEvent::Modified(id, player_owned)
  84. | ComponentEvent::Removed(id, player_owned) => {
  85. self.need_update.add(*id);
  86. self.modified.entry(*id).or_default().old_player_id = Some(player_owned.owner);
  87. }
  88. }
  89. }
  90. /* fleet owned events */
  91. let events = fleet_owned
  92. .unprotected_storage()
  93. .channel()
  94. .read(&mut self.fleet_owned_id);
  95. for event in events {
  96. match event {
  97. ComponentEvent::Inserted(id) => {
  98. self.need_update.add(*id);
  99. }
  100. ComponentEvent::Modified(id, fleet_owned)
  101. | ComponentEvent::Removed(id, fleet_owned) => {
  102. self.need_update.add(*id);
  103. self.modified.entry(*id).or_default().old_fleet_id = Some(fleet_owned.owner);
  104. }
  105. }
  106. }
  107. if self.need_update.is_empty() {
  108. return;
  109. }
  110. /* update fleets */
  111. let player_id = player_state.player_id;
  112. for (fleet_id, fleet_info) in (&entities, &mut fleet_infos).join() {
  113. for (ship_id, ship, fleet_owned, player_owned, _) in (
  114. &entities,
  115. &ships,
  116. &fleet_owned,
  117. &player_owned,
  118. &self.need_update,
  119. )
  120. .join()
  121. {
  122. let new_match = fleet_owned.owner == fleet_id && player_owned.owner == player_id;
  123. let old_match = match self.modified.get(&ship_id.id()) {
  124. None => false,
  125. Some(modified) => match (modified.old_fleet_id, modified.old_player_id) {
  126. (Some(old_fleet_id), Some(old_player_id)) => {
  127. old_fleet_id != fleet_id && old_player_id == player_id
  128. }
  129. (Some(old_fleet_id), None) => {
  130. old_fleet_id != fleet_id && player_owned.owner == player_id
  131. }
  132. (None, Some(old_player_id)) => {
  133. fleet_owned.owner != fleet_id && old_player_id == player_id
  134. }
  135. (None, None) => false,
  136. },
  137. };
  138. if old_match && !new_match {
  139. fleet_info.count[ship.type_] = fleet_info.count[ship.type_].saturating_sub(1);
  140. } else if !old_match && new_match {
  141. fleet_info.count[ship.type_] += 1;
  142. }
  143. }
  144. }
  145. }
  146. }