LCOV - code coverage report
Current view: top level - src - system.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 14 60 23.3 %
Date: 2022-02-03 16:15:05 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : 
       3             : import 'package:uuid/uuid.dart';
       4             : 
       5             : import 'component.dart';
       6             : import 'entity.dart';
       7             : import 'extensions/extensions.dart';
       8             : import 'mixins.dart';
       9             : 
      10             : // A function that takes JSON data and returns a component.
      11             : typedef ComponentDeserializerFunction = Component? Function(Map<String, dynamic> data);
      12             : 
      13             : // A function that takes a component and returns JSON-esque data.
      14             : typedef ComponentSerializerFunction = Map<String, dynamic> Function(SerializableComponent component);
      15             : 
      16             : // A function that takes in an entity and returns JSON-esque data.
      17             : typedef EntityToJsonFunction = Map<String, dynamic> Function(Entity entity);
      18             : 
      19             : // A function that takes in an entity and returns T which would be a value
      20             : // that can be used to determine if an entity is unique.
      21             : typedef EntityUniqueKeyGeneratorFunction<T> = T Function(Entity entity);
      22             : 
      23             : // A function that takes in JSON and returns an Entity;
      24             : typedef EntityFromJsonFunction = Entity Function(
      25             :   Map<String, dynamic> json,
      26             :   EntitySystem system,
      27             : );
      28             : 
      29             : /// This system is for keeping track of all created entities.
      30             : class EntitySystem<T> {
      31             :   final uuid = const Uuid();
      32             : 
      33             :   // The listener that updates the public list of entities.
      34             :   late StreamSubscription _listener;
      35             : 
      36             :   EntityUniqueKeyGeneratorFunction<T>? uniqueKeyGeneratorFunction;
      37             : 
      38           1 :   EntitySystem() {
      39             :     // When entities updates, map over and update the public entity list.
      40           5 :     _listener = _entities.stream.listen((ents) {
      41           2 :       final list = ents.values.toList();
      42           2 :       entities.add(list);
      43             :     });
      44             :   }
      45             : 
      46             :   // Generate a system with a custom unique key generator function.
      47           0 :   static EntitySystem<T> withUniqueKeyGenerator<T>(
      48             :     EntityUniqueKeyGeneratorFunction<T> uniqueKeyGeneratorFunction,
      49             :   ) {
      50           0 :     final system = EntitySystem<T>();
      51           0 :     system.uniqueKeyGeneratorFunction = uniqueKeyGeneratorFunction;
      52             :     return system;
      53             :   }
      54             : 
      55             :   /// A list of registered deserializer functions.
      56             :   List<ComponentDeserializerFunction> deserializers = [
      57             :     componentFromJson,
      58             :   ];
      59             : 
      60             :   /// A list of registered serializer functions.
      61             :   List<ComponentSerializerFunction> serializers = [
      62             :     componentToJson,
      63             :   ];
      64             : 
      65             :   /// The function called to turn an entity into JSON.
      66             :   EntityToJsonFunction entityToJsonFunction = defaultEntityToJsonFunction;
      67             : 
      68             :   /// The function called to turn JSON into an entity;
      69             :   EntityFromJsonFunction entityFromJsonFunction = defaultEntityFromJsonFunction;
      70             : 
      71             :   /// The internal registry of all created entities.
      72             :   final _entities = <T, Entity>{}.bs;
      73             : 
      74             :   /// An observable list of entities.
      75             :   final entities = <Entity>[].bs;
      76             : 
      77             :   /// Call this to release resources and workers.
      78           0 :   void dispose() {
      79             :     /// Clear entities and cancel subscription.
      80           0 :     _listener.cancel();
      81           0 :     _entities.close();
      82           0 :     entities.close();
      83             :   }
      84             : 
      85             :   /// Remove all entities.
      86           0 :   void flush() {
      87           0 :     if (_entities.hasValue) {
      88           0 :       _entities.value.forEach((guid, e) => e.destroy());
      89           0 :       _entities.value.clear();
      90             :     }
      91             :   }
      92             : 
      93             :   /// Register a deserializer function.
      94           0 :   void registerDeserializer(ComponentDeserializerFunction deserializer) {
      95           0 :     if (!deserializers.contains(deserializer)) {
      96           0 :       deserializers.add(deserializer);
      97             :     }
      98             :   }
      99             : 
     100             :   /// Register a serializer function.
     101           0 :   void registerSerializer(ComponentSerializerFunction serializer) {
     102           0 :     if (!serializers.contains(serializer)) {
     103           0 :       serializers.add(serializer);
     104             :     }
     105             :   }
     106             : 
     107             :   /// The way a new entity should be created.
     108           1 :   Entity create() {
     109           3 :     final entity = Entity(uuid.v4(), this);
     110           1 :     return setEntity(entity);
     111             :   }
     112             : 
     113             :   /// Deserializing entities from JSON.
     114           0 :   Entity createFromJson(Map<String, dynamic> json) {
     115           0 :     final entity = entityFromJsonFunction(json, this);
     116           0 :     return setEntity(entity);
     117             :   }
     118             : 
     119             :   /// This function actually sets the entity in the list.
     120             :   /// Left public so that if you want to use your own method for creating entities
     121             :   /// you can, as long as you call this method so the system tracks the entity.
     122           1 :   Entity setEntity(Entity entity) {
     123           2 :     final current = _entities.value;
     124             :     // If we have a custom key generator use that.
     125             :     late final T key;
     126           1 :     if (uniqueKeyGeneratorFunction != null) {
     127           0 :       key = uniqueKeyGeneratorFunction!(entity);
     128             :     } else {
     129           1 :       key = entity.guid as T;
     130             :     }
     131           7 :     final newList = Map.fromIterables([...current.keys, key], [...current.values, entity]);
     132           2 :     _entities.add(newList);
     133             :     // Return the entity.
     134           4 :     return _entities.value[entity.guid]!;
     135             :   }
     136             : 
     137             :   /// Standard serializer that turns an entity into JSON.
     138           0 :   Map<String, dynamic> entityToJson(Entity entity) {
     139           0 :     return entityToJsonFunction(entity);
     140             :   }
     141             : 
     142             :   /// When an entity has been destroyed, we remove it from the list
     143             :   /// and that will automatically sync that to the observable list.
     144           0 :   void destroyed(Entity entity) {
     145           0 :     final current = _entities.value;
     146             :     // Drop the guid and remove the entity from the list.
     147           0 :     final newList = Map.fromIterables([...current.keys], [...current.values].where((e) => e != entity));
     148             :     // Set the new list.
     149           0 :     _entities.add(newList);
     150             :   }
     151             : }
     152             : 
     153             : /// Standard serializer that turns an entity into JSON.
     154           0 : Map<String, dynamic> defaultEntityToJsonFunction(Entity entity) {
     155           0 :   List<Map<String, dynamic>> componentData = [];
     156           0 :   entity.components.value.forEach(
     157           0 :     (type, component) {
     158           0 :       if (component is SerializableComponent) {
     159           0 :         componentData.add({'type': type.toString(), 'data': (component as SerializableComponent).toJson()});
     160             :       }
     161             :     },
     162             :   );
     163           0 :   return <String, dynamic>{
     164             :     'components': componentData,
     165             :   };
     166             : }
     167             : 
     168           0 : Entity defaultEntityFromJsonFunction(Map<String, dynamic> json, EntitySystem system) {
     169           0 :   var e = Entity(json['guid'], system);
     170           0 :   if (json['components'] != null) {
     171           0 :     final comps = json['components'] as List<dynamic>;
     172           0 :     for (var compData in comps) {
     173             :       final data = compData as Map<String, dynamic>;
     174           0 :       Component? c = componentFromJson(data);
     175             :       // if not contained in default system, check serializers.
     176             :       if (c == null) {
     177           0 :         for (var serializer in system.deserializers) {
     178           0 :           c = serializer.call(data);
     179             :         }
     180             :       }
     181             : 
     182             :       /// If we actually got a component, add it.
     183             :       if (c != null) {
     184           0 :         e += c;
     185             :       }
     186             :     }
     187             :   }
     188             : 
     189             :   return e;
     190             : }
     191             : 
     192             : /// A map of strings to types.
     193           0 : Component? componentFromJson(Map<String, dynamic> json) {
     194             :   return null;
     195             : }
     196             : 
     197           0 : Map<String, dynamic> componentToJson(SerializableComponent component) {
     198           0 :   return component.toJson();
     199             : }

Generated by: LCOV version 1.15