11use bevy:: prelude:: * ;
2+ use forces:: prelude:: { RotationalWorkEvent , WorkDoneEvent } ;
23
34/// Enum representing different types of energy
45#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash , Component , Reflect ) ]
@@ -86,7 +87,7 @@ pub struct EnergyTransferEvent {
8687/// Component for precise energy accounting
8788#[ derive( Component , Debug , Reflect ) ]
8889#[ reflect( Component ) ]
89- pub struct EnergyAccountingLedger {
90+ pub struct EnergyBalance {
9091 /// History of all transactions, newest first
9192 pub transactions : Vec < EnergyTransaction > ,
9293 /// Maximum number of transactions to store
@@ -116,7 +117,7 @@ pub struct EnergyTransaction {
116117 pub duration : f32 ,
117118}
118119
119- impl Default for EnergyAccountingLedger {
120+ impl Default for EnergyBalance {
120121 fn default ( ) -> Self {
121122 Self {
122123 transactions : Vec :: new ( ) ,
@@ -127,7 +128,7 @@ impl Default for EnergyAccountingLedger {
127128 }
128129}
129130
130- impl EnergyAccountingLedger {
131+ impl EnergyBalance {
131132 /// Record a new energy transaction
132133 pub fn record_transaction ( & mut self , transaction : EnergyTransaction ) {
133134 match transaction. transaction_type {
@@ -258,6 +259,72 @@ impl EnergyDriftMonitor {
258259 }
259260}
260261
262+ /// System to ensure entities with Mass have energy balance tracking
263+ pub fn initialize_energy_balance (
264+ mut commands : Commands ,
265+ query : Query < Entity , ( With < forces:: prelude:: Mass > , Without < EnergyBalance > ) > ,
266+ ) {
267+ for entity in query. iter ( ) {
268+ commands. entity ( entity) . insert ( EnergyBalance :: default ( ) ) ;
269+ }
270+ }
271+
272+ /// System to track work done by forces and record in energy balance
273+ pub fn track_work_from_forces (
274+ mut work_events : MessageReader < WorkDoneEvent > ,
275+ mut query : Query < & mut EnergyBalance > ,
276+ time : Res < Time > ,
277+ ) {
278+ for event in work_events. read ( ) {
279+ if let Ok ( mut ledger) = query. get_mut ( event. entity ) {
280+ // Correct transaction direction based on work sign
281+ let ( transaction_type, source, destination) = if event. work > 0.0 {
282+ ( TransactionType :: Input , None , Some ( event. entity ) )
283+ } else {
284+ ( TransactionType :: Output , Some ( event. entity ) , None )
285+ } ;
286+
287+ ledger. record_transaction ( EnergyTransaction {
288+ transaction_type,
289+ amount : event. work . abs ( ) ,
290+ source,
291+ destination,
292+ timestamp : time. elapsed_secs ( ) ,
293+ transfer_rate : event. work . abs ( ) / time. delta_secs ( ) . max ( f32:: EPSILON ) ,
294+ duration : time. delta_secs ( ) ,
295+ } ) ;
296+ }
297+ }
298+ }
299+
300+ /// System to track rotational work done by torques and record in energy balance
301+ pub fn track_rotational_work_from_torques (
302+ mut work_events : MessageReader < RotationalWorkEvent > ,
303+ mut query : Query < & mut EnergyBalance > ,
304+ time : Res < Time > ,
305+ ) {
306+ for event in work_events. read ( ) {
307+ if let Ok ( mut ledger) = query. get_mut ( event. entity ) {
308+ // Same logic as linear work: positive work = energy input, negative = output
309+ let ( transaction_type, source, destination) = if event. work > 0.0 {
310+ ( TransactionType :: Input , None , Some ( event. entity ) )
311+ } else {
312+ ( TransactionType :: Output , Some ( event. entity ) , None )
313+ } ;
314+
315+ ledger. record_transaction ( EnergyTransaction {
316+ transaction_type,
317+ amount : event. work . abs ( ) ,
318+ source,
319+ destination,
320+ timestamp : time. elapsed_secs ( ) ,
321+ transfer_rate : event. work . abs ( ) / time. delta_secs ( ) . max ( f32:: EPSILON ) ,
322+ duration : time. delta_secs ( ) ,
323+ } ) ;
324+ }
325+ }
326+ }
327+
261328/// Plugin to manage energy conservation systems
262329pub struct EnergyConservationPlugin ;
263330
@@ -269,11 +336,22 @@ impl Plugin for EnergyConservationPlugin {
269336 . register_type :: < EnergyQuantity > ( )
270337 . register_type :: < TransactionType > ( )
271338 . register_type :: < EnergyTransaction > ( )
272- . register_type :: < EnergyAccountingLedger > ( )
339+ . register_type :: < EnergyBalance > ( )
273340 // Add resources
274341 . init_resource :: < EnergyConservationTracker > ( )
275342 // Add event channel
276- . add_message :: < EnergyTransferEvent > ( ) ;
343+ . add_message :: < EnergyTransferEvent > ( )
344+ // Add systems with explicit ordering
345+ . add_systems (
346+ Update ,
347+ (
348+ initialize_energy_balance,
349+ ApplyDeferred ,
350+ ( track_work_from_forces, track_rotational_work_from_torques)
351+ . after ( forces:: PhysicsSet :: ApplyForces ) ,
352+ )
353+ . chain ( ) ,
354+ ) ;
277355 }
278356}
279357
@@ -284,7 +362,7 @@ mod tests {
284362 #[ test]
285363 fn test_ledger_arithmetic ( ) {
286364 // Test that net_energy_change = total_input - total_output
287- let mut ledger = EnergyAccountingLedger :: default ( ) ;
365+ let mut ledger = EnergyBalance :: default ( ) ;
288366
289367 ledger. record_transaction ( EnergyTransaction {
290368 transaction_type : TransactionType :: Input ,
@@ -324,7 +402,7 @@ mod tests {
324402 #[ test]
325403 fn test_current_flux_sums_active_rates ( ) {
326404 // Test that current_flux sums transfer rates correctly
327- let mut ledger = EnergyAccountingLedger :: default ( ) ;
405+ let mut ledger = EnergyBalance :: default ( ) ;
328406
329407 let current_time = 10.0 ;
330408
0 commit comments