{"id":"mark-marks/sapphire-ecr","name":"sapphire-ecr","scope":"mark-marks","platform":"roblox","description":"Mirrored from the Wally registry.","version":"0.1.5","latest":"0.1.5","versions":["0.1.0","0.1.2","0.1.3","0.1.4","0.1.5"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{"centau/ecr":{"version":"^0.8.0","alias":"ecr"},"mark-marks/sapphire":{"version":"^0.1.2","alias":"sapphire"},"red-blox/spawn":{"version":"^1.1.0","alias":"spawn"}},"integrity":"8f3f4cab8d780ac828e0f958907e1860e4e27a1d6bcc820f973addd5265bc84e","likes":0,"downloads":0,"install":"forest install mark-marks/sapphire-ecr","url":"https://forest.dev/p/roblox/mark-marks/sapphire-ecr","files":"https://api.forest.dev/ai/package/roblox/mark-marks/sapphire-ecr/files","readme":"# sapphire-ecr\r\nA lightweight scheduler + niceties (replication, etc.) for [centau/ecr](https://github.com/centau/ecr) for [Mark-Marks/sapphire](https://github.com/Mark-Marks/sapphire)\r\n\r\n# Installation\r\n1. Install it with wally\r\n```toml\r\n[dependencies]\r\nsapphire_ecr = \"mark-marks/sapphire-ecr@LATEST\" # replace LATEST with the latest version\r\n```\r\n2. `wally install`\r\n3. Extend sapphire with it\r\n```luau\r\nlocal sapphire_ecr = require(\"@pkg/sapphire_ecr\")\r\n\r\nsapphire\r\n    :use(sapphire_ecr)\r\n```\r\n\r\n# API\r\n\r\n## Exports\r\n\r\n### .registry\r\n```luau\r\ntype registry = ecr.Registry\r\n```\r\n\r\n### .stepped_systems\r\nReadonly!\r\n```luau\r\ntype stepped_systems = { system }\r\n```\r\n\r\n### .heartbeat_systems\r\nReadonly!\r\n```luau\r\ntype heartbeat_systems = { system }\r\n```\r\n\r\n### .render_stepped_systems\r\nReadonly!\r\n```luau\r\ntype render_stepped_systems = { system }\r\n```\r\n\r\n### .ecr\r\nReexport of ecr\r\n```luau\r\nSapphireEcr.ecr = ecr\r\n```\r\n\r\n## Types\r\n\r\n### loop_type\r\n```luau\r\ntype loop_type = \"Stepped\" | \"Heartbeat\" | \"RenderStepped\"\r\n```\r\n\r\n### system\r\n```luau\r\ntype system = {\r\n    --- Fires every `RunService.Stepped`\r\n    runner: (delta_time: number) -> (),\r\n    --- 1 = lowest priority\r\n    priority: number?,\r\n    --- Defaults to \"Stepped\"\r\n    loop_type: loop_type?,\r\n}\r\n```\r\n\r\n### spawner<T...>\r\n```luau\r\ntype spawner<T...> = {\r\n    spawn: (T...) -> ecr.entity,\r\n    spawn_with_handle: (T...) -> ecr.Handle,\r\n}\r\n```\r\n\r\n### raw_data\r\n`map<component_id, map<entity_id, component_value>>`\r\nMigrated from `map<entity_id, map<component_id, component_value>>` to do SoA instead of AoS\r\n```luau\r\ntype raw_data = {\r\n    [number]: { [ecr.entity]: unknown },\r\n}\r\n```\r\n\r\n### replicator\r\n```luau\r\ntype replicator = {\r\n    get_full_data: () -> raw_data,\r\n    calculate_difference: () -> raw_data?,\r\n    apply_difference: (difference: raw_data) -> (),\r\n}\r\n```\r\n\r\n### entity\r\n```luau\r\ntype entity = ecr.entity\r\n```\r\n\r\n### Signal<T...>\r\n```luau\r\ntype Signal<T...> = ecr.Signal<T...>\r\n```\r\n\r\n### Connection\r\n```luau\r\ntype Connection = ecr.Connection\r\n```\r\n\r\n### Handle\r\n```luau\r\ntype Handle = ecr.Handle\r\n```\r\n\r\n### View<T...>\r\n```luau\r\ntype View<T...> = ecr.View<T...>\r\n```\r\n\r\n### Observer<T...>\r\n```luau\r\ntype Observer<T...> = ecr.Observer<T...>\r\n```\r\n\r\n### Group<T...>\r\n```luau\r\ntype Group<T...> = ecr.Group<T...>\r\n```\r\n\r\n### Registry\r\n```luau\r\ntype Registry = ecr.Registry\r\n```\r\n\r\n### Queue<T...>\r\n```luau\r\ntype Queue<T...> = ecr.Queue<T...>\r\n```\r\n\r\n## Registered methods\r\n\r\n### .system()\r\nRegisters a system.\r\n```luau\r\n(\r\n    singleton: sapphire.singleton\r\n)\r\n```\r\nSingletons need to follow the following format:\r\n```luau\r\ntype format = {\r\n    system: (registry: ecr.Registry) -> (delta_time: number) -> (),\r\n    --- Defaults to 1\r\n    priority: number?,\r\n    --- Defaults to `Stepped`\r\n    loop_type: loop_type?,\r\n}\r\n```\r\nSystems on the server that use `RenderStepped` will be migrated to `Heartbeat`.\r\n\r\n## Functions\r\n\r\n### .spawn_entity()\r\nCreates an entity and returns its id.\r\n```luau\r\n() -> ecr.entity\r\n```\r\n\r\n### .spawn_entity_with_handle()\r\nCreates an entity and returns a handle to it.\r\n```luau\r\n() -> ecr.Handle\r\n```\r\n\r\n### .create_spawner()\r\nCreates a spawner.\r\n```luau\r\n<T...>(\r\n    ...: T...\r\n) -> spawner<T...>\r\n```\r\n```luau\r\nlocal spawner = sapphire_ecr.create_spawner(components.part, components.velocity, components.position)\r\nfor _ = 1, 1000 do\r\n    spawner.spawn(part_template:Clone(), Vector3.zero, Vector3.zero)\r\nend\r\n```\r\n\r\n### .create_replicator\r\nCreates a \"replicator\"\r\n```luau\r\n(\r\n    ...\r\n) -> replicator\r\n```\r\nA replicator keeps track of all entities with the passed components and their values -\r\nwhenever a component is changed (add, change, remove) and the replicator listens to it, it's also changed within the contained raw data.\\\r\nThe developer can then calculate the difference on the server and send it to the client every time,\r\non which the difference is then applied to the registry.\\\r\nAlbeit it's called a replicator, it doesn't replicate the data by itself.\r\nIt allows the developer to use any networking libary to replicate the changes.\r\n```luau\r\n-- server\r\nlocal replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)\r\n\r\nfunction singleton.system()\r\n    return function()\r\n        local difference = replicator.calculate_difference()\r\n        -- There might not be any difference\r\n        if not difference then\r\n            return\r\n        end\r\n        data_replication_event.send_to_all(difference)\r\n    end\r\nend\r\n```\r\n```luau\r\n-- client\r\nlocal replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)\r\n\r\nfunction singleton.system()\r\n    return function()\r\n        for _, difference in data_replication_event.poll() do\r\n            replicator.apply_difference(difference)\r\n        end\r\n    end\r\nend\r\n```\r\n\r\n## spawner<T...>\r\n\r\n### .spawn()\r\nCreates an entity with the given components.\r\n```luau\r\n(\r\n    T...\r\n) -> ecr.entity\r\n```\r\n\r\n### .spawn_with_handle()\r\nCreates an entity with the given components and returns a handle to it.\r\n```luau\r\n(\r\n    T...\r\n) -> ecr.Handle\r\n```\r\n\r\n## replicator\r\nA replicator keeps track of all entities with the passed components and their values -\r\nwhenever a component is changed (add, change, remove) and the replicator listens to it, it's also changed within the contained raw data.\\\r\nThe developer can then calculate the difference on the server and send it to the client every time,\r\non which the difference is then applied to the registry.\\\r\nAlbeit it's called a replicator, it doesn't replicate the data by itself.\r\nIt allows the developer to use any networking libary to replicate the changes.\r\n```luau\r\n-- server\r\nlocal replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)\r\n\r\nfunction singleton.system()\r\n    return function()\r\n        local difference = replicator.calculate_difference()\r\n        -- There might not be any difference\r\n        if not difference then\r\n            return\r\n        end\r\n        data_replication_event.send_to_all(difference)\r\n    end\r\nend\r\n```\r\n```luau\r\n-- client\r\nlocal replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)\r\n\r\nfunction singleton.system()\r\n    return function()\r\n        for _, difference in data_replication_event.poll() do\r\n            replicator.apply_difference(difference)\r\n        end\r\n    end\r\nend\r\n```\r\n\r\n### .get_full_data()\r\nGets the full data representing the entire registry.\r\nUseful for initial replication to every player.\r\n```luau\r\n() -> raw_data\r\n```\r\n```luau\r\nlocal replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)\r\n\r\nPlayers.PlayerAdded:Connect(function(player)\r\n    data_replication_event.send_to(player, replicator.get_full_data())\r\nend)\r\n```\r\n\r\n### .calculate_difference()\r\nCalculates the difference between last sent data and currently stored data.\r\n```luau\r\n() -> raw_data?\r\n```\r\n```luau\r\nlocal replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)\r\n\r\nfunction singleton.system()\r\n    return function()\r\n        local difference = replicator.calculate_difference()\r\n        -- There might not be any difference\r\n        if not difference then\r\n            return\r\n        end\r\n        data_replication_event.send_to_all(difference)\r\n    end\r\nend\r\n```\r\n\r\n### .apply_difference()\r\nApplies the difference to the current data.\r\n```luau\r\n(\r\n    difference: raw_data\r\n) -> ()\r\n```\r\n```luau\r\nlocal replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)\r\n\r\nfunction singleton.system()\r\n    return function()\r\n        for _, difference in data_replication_event.poll()\r\n            replicator.apply_difference(difference)\r\n        end\r\n    end\r\nend\r\n```\r\n","readmeTruncated":false}