mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-04 02:49:18 +00:00 
			
		
		
		
	Update networking example
	
		
			
	
		
	
	
		
	
		
			Some checks are pending
		
		
	
	
	
				
					
				
			
		
			Some checks are pending
		
		
	
	
This commit is contained in:
		
							parent
							
								
									53f705ac2e
								
							
						
					
					
						commit
						a6ba9f4bd5
					
				
					 13 changed files with 252 additions and 129 deletions
				
			
		| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
--!native
 | 
					--!native
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
local Matter = require(ReplicatedStorage.DevPackages.matter)
 | 
					local Matter = require(ReplicatedStorage.DevPackages.Matter)
 | 
				
			||||||
local ecr = require(ReplicatedStorage.DevPackages.ecr)
 | 
					local ecr = require(ReplicatedStorage.DevPackages.ecr)
 | 
				
			||||||
local newWorld = Matter.World.new()
 | 
					local newWorld = Matter.World.new()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					--!strict
 | 
				
			||||||
 | 
					local RunService = game:GetService("RunService")
 | 
				
			||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
local jecs = require(ReplicatedStorage.ecs)
 | 
					local jecs = require(ReplicatedStorage.ecs)
 | 
				
			||||||
local types = require("./types")
 | 
					local types = require("./types")
 | 
				
			||||||
| 
						 | 
					@ -5,31 +7,58 @@ local types = require("./types")
 | 
				
			||||||
local Networked = jecs.tag()
 | 
					local Networked = jecs.tag()
 | 
				
			||||||
local NetworkedPair = jecs.tag()
 | 
					local NetworkedPair = jecs.tag()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local Renderable = jecs.component() :: jecs.Id<Instance>
 | 
					local InstanceMapping = jecs.component() :: jecs.Id<Instance>
 | 
				
			||||||
jecs.meta(Renderable, Networked)
 | 
					jecs.meta(InstanceMapping, jecs.OnAdd, function(component)
 | 
				
			||||||
 | 
						jecs.meta(component, jecs.OnAdd, function(entity, _, instance)
 | 
				
			||||||
 | 
							if RunService:IsServer() then
 | 
				
			||||||
 | 
								instance:SetAttribute("entity_server")
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								instance:SetAttribute("entity_client")
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end)
 | 
				
			||||||
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function networked_id(ct)
 | 
				
			||||||
 | 
						jecs.meta(ct, Networked)
 | 
				
			||||||
 | 
						return ct
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					local function networked_pair(ct)
 | 
				
			||||||
 | 
						jecs.meta(ct, NetworkedPair)
 | 
				
			||||||
 | 
						return ct
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					local function instance_mapping_id(ct)
 | 
				
			||||||
 | 
						jecs.meta(ct, InstanceMapping)
 | 
				
			||||||
 | 
						return ct
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local Poison = jecs.component() :: jecs.Id<number>
 | 
					local Renderable = jecs.component() :: types.Id<Instance>
 | 
				
			||||||
jecs.meta(Poison, Networked)
 | 
					local Poison = jecs.component() :: types.Id<number>
 | 
				
			||||||
 | 
					local Health = jecs.component() :: types.Id<number>
 | 
				
			||||||
local Health = jecs.component() :: jecs.Id<number>
 | 
					local Player = jecs.component() :: types.Id<Player>
 | 
				
			||||||
jecs.meta(Health, Networked)
 | 
					local Debuff = jecs.tag() :: types.Entity
 | 
				
			||||||
 | 
					local Lifetime = jecs.component() :: types.Id<{
 | 
				
			||||||
local Player = jecs.component() :: jecs.Id<Player>
 | 
						duration: number,
 | 
				
			||||||
jecs.meta(Player, Networked)
 | 
						created: number
 | 
				
			||||||
 | 
					}>
 | 
				
			||||||
 | 
					local Destroy = jecs.tag()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local components = {
 | 
					local components = {
 | 
				
			||||||
	Renderable = Renderable,
 | 
						Renderable = networked_id(instance_mapping_id(Renderable)),
 | 
				
			||||||
	Player = Player,
 | 
						Player = networked_id(Player),
 | 
				
			||||||
	Poison = Poison,
 | 
						Poison = networked_id(Poison),
 | 
				
			||||||
	Health = Health,
 | 
						Health = networked_id(Health),
 | 
				
			||||||
 | 
						Lifetime = networked_id(Lifetime),
 | 
				
			||||||
 | 
						Debuff = networked_id(Debuff),
 | 
				
			||||||
 | 
						Destroy = networked_id(Destroy),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						-- We have to define that some builtin IDs can also be networked
 | 
				
			||||||
 | 
						ChildOf = networked_pair(jecs.ChildOf),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Networked = Networked,
 | 
						Networked = Networked,
 | 
				
			||||||
	NetworkedPair = NetworkedPair,
 | 
						NetworkedPair = NetworkedPair,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for name, component in components do
 | 
					for name, component in components :: {[string]: types.Id<any> } do
 | 
				
			||||||
	jecs.meta(component, jecs.Name, name)
 | 
						jecs.meta(component, jecs.Name, name)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,4 +10,5 @@ local world = observers_add(jecs.world())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local systems = ReplicatedStorage.systems
 | 
					local systems = ReplicatedStorage.systems
 | 
				
			||||||
SYSTEM(world, systems.receive_replication)
 | 
					SYSTEM(world, systems.receive_replication)
 | 
				
			||||||
 | 
					SYSTEM(world, systems.entities_delete)
 | 
				
			||||||
RUN(world)
 | 
					RUN(world)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										13
									
								
								demo/src/ReplicatedStorage/systems/entities_delete.luau
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										13
									
								
								demo/src/ReplicatedStorage/systems/entities_delete.luau
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--!strict
 | 
				
			||||||
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
 | 
					local types = require(ReplicatedStorage.types)
 | 
				
			||||||
 | 
					local ct = require(ReplicatedStorage.components)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function entities_delete(world: types.World, dt: number)
 | 
				
			||||||
 | 
						for e in world:each(ct.Destroy) do
 | 
				
			||||||
 | 
							world:delete(e)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return entities_delete
 | 
				
			||||||
| 
						 | 
					@ -2,45 +2,51 @@ local types = require("../types")
 | 
				
			||||||
local jecs = require(game:GetService("ReplicatedStorage").ecs)
 | 
					local jecs = require(game:GetService("ReplicatedStorage").ecs)
 | 
				
			||||||
local remotes = require("../remotes")
 | 
					local remotes = require("../remotes")
 | 
				
			||||||
local collect = require("../collect")
 | 
					local collect = require("../collect")
 | 
				
			||||||
local client_ids = {}
 | 
					local components = require("../components")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function ecs_map_get(world, id)
 | 
					local client_ids: {[jecs.Entity]: jecs.Entity } = {}
 | 
				
			||||||
	local deserialised_id = client_ids[id]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if not deserialised_id then
 | 
					local function ecs_ensure_entity(world: jecs.World, id: jecs.Entity)
 | 
				
			||||||
		if world:has(id, jecs.Name) then
 | 
						local e = 0
 | 
				
			||||||
			deserialised_id = world:entity(id)
 | 
					
 | 
				
			||||||
 | 
						local ser_id = id
 | 
				
			||||||
 | 
						local deser_id = client_ids[ser_id]
 | 
				
			||||||
 | 
						if deser_id  then
 | 
				
			||||||
 | 
							if deser_id == 0 then
 | 
				
			||||||
 | 
								local new_id = world:entity()
 | 
				
			||||||
 | 
								client_ids[ser_id] = new_id
 | 
				
			||||||
 | 
								deser_id = new_id
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
			deserialised_id = world:entity()
 | 
							if not world:exists(ser_id)
 | 
				
			||||||
 | 
								or (world:contains(ser_id) and not world:get(ser_id, jecs.Name))
 | 
				
			||||||
 | 
							then
 | 
				
			||||||
 | 
								deser_id = world:entity()
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								if world:contains(ser_id) and world:get(ser_id, jecs.Name) then
 | 
				
			||||||
 | 
									deser_id = ser_id
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									deser_id = world:entity()
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							client_ids[ser_id] = deser_id
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		client_ids[id] = deserialised_id
 | 
						e = deser_id
 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	-- local deserialised_id = client_ids[id]
 | 
						return e
 | 
				
			||||||
	-- if not deserialised_id then
 | 
					 | 
				
			||||||
	-- 	if world:has(id, jecs.Name) then
 | 
					 | 
				
			||||||
	-- 		deserialised_id = world:entity(id)
 | 
					 | 
				
			||||||
	-- 	else
 | 
					 | 
				
			||||||
	-- 		if world:exists(id) then
 | 
					 | 
				
			||||||
	-- 			deserialised_id = world:entity()
 | 
					 | 
				
			||||||
	-- 		else
 | 
					 | 
				
			||||||
	-- 			deserialised_id = world:entity(id)
 | 
					 | 
				
			||||||
	-- 		end
 | 
					 | 
				
			||||||
	-- 	end
 | 
					 | 
				
			||||||
	-- 	client_ids[id] = deserialised_id
 | 
					 | 
				
			||||||
	-- end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return deserialised_id
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function ecs_make_alive_id(world, id)
 | 
					-- local rel_render = `e{jecs.ECS_ID(rel)}v{jecs.ECS_GENERATION(rel)}`
 | 
				
			||||||
	local rel = jecs.ECS_PAIR_FIRST(id)
 | 
					-- local tgt_render = `e{jecs.ECS_ID(tgt)}v{jecs.ECS_GENERATION(tgt)}`
 | 
				
			||||||
	local tgt = jecs.ECS_PAIR_SECOND(id)
 | 
					local function ecs_deser_pairs(world, token)
 | 
				
			||||||
 | 
						local tokens = string.split(token, ",")
 | 
				
			||||||
 | 
						local rel = tonumber(tokens[1])
 | 
				
			||||||
 | 
						local tgt = tonumber(tokens[2])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rel = ecs_map_get(world, rel)
 | 
						rel = ecs_ensure_entity(world, rel)
 | 
				
			||||||
	tgt = ecs_map_get(world, tgt)
 | 
						tgt = ecs_ensure_entity(world, tgt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return jecs.pair(rel, tgt)
 | 
						return jecs.pair(rel, tgt)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -48,24 +54,30 @@ end
 | 
				
			||||||
local snapshots = collect(remotes.replication.OnClientEvent)
 | 
					local snapshots = collect(remotes.replication.OnClientEvent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return function(world: types.World)
 | 
					return function(world: types.World)
 | 
				
			||||||
 | 
						for entity in world:each(components.Destroy) do
 | 
				
			||||||
 | 
							client_ids[entity] = nil
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
    for snapshot in snapshots do
 | 
					    for snapshot in snapshots do
 | 
				
			||||||
        for id, map in snapshot do
 | 
					        for ser_id, map in snapshot do
 | 
				
			||||||
        	id = tonumber(id)
 | 
					        	local id = tonumber(ser_id)
 | 
				
			||||||
            if jecs.IS_PAIR(id) then
 | 
					            if not id then
 | 
				
			||||||
            	id = ecs_make_alive_id(world, id)
 | 
					            	id = ecs_deser_pairs(world, ser_id)
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            	id = ecs_ensure_entity(world, id)
 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            local set = map.set
 | 
					            local set = map.set
 | 
				
			||||||
            if set then
 | 
					            if set then
 | 
				
			||||||
                if jecs.is_tag(world, id) then
 | 
					                if jecs.is_tag(world, id) then
 | 
				
			||||||
                   	for _, entity in set do
 | 
					                   	for _, entity in set do
 | 
				
			||||||
                       	entity = ecs_map_get(world, entity)
 | 
					                       	entity = ecs_ensure_entity(world, entity)
 | 
				
			||||||
                  		world:add(entity, id)
 | 
					                  		world:add(entity, id)
 | 
				
			||||||
                   	end
 | 
					                   	end
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
 | 
					                	local t = os.clock()
 | 
				
			||||||
	                local values = map.values
 | 
						                local values = map.values
 | 
				
			||||||
	                for i, entity in set do
 | 
						                for i, entity in set do
 | 
				
			||||||
						entity = ecs_map_get(world, entity)
 | 
											entity = ecs_ensure_entity(world, entity)
 | 
				
			||||||
						world:set(entity, id, values[i])
 | 
											world:set(entity, id, values[i])
 | 
				
			||||||
                   	end
 | 
					                   	end
 | 
				
			||||||
			    end
 | 
								    end
 | 
				
			||||||
| 
						 | 
					@ -75,7 +87,7 @@ return function(world: types.World)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if removed then
 | 
					            if removed then
 | 
				
			||||||
                for _, entity in removed do
 | 
					                for _, entity in removed do
 | 
				
			||||||
                    entity = ecs_map_get(world, entity)
 | 
					                    entity = ecs_ensure_entity(world, entity)
 | 
				
			||||||
                    if not world:contains(entity) then
 | 
					                    if not world:contains(entity) then
 | 
				
			||||||
                        continue
 | 
					                        continue
 | 
				
			||||||
                    end
 | 
					                    end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,5 +15,8 @@ local systems = ServerScriptService.systems
 | 
				
			||||||
SYSTEM(world, systems.replication)
 | 
					SYSTEM(world, systems.replication)
 | 
				
			||||||
SYSTEM(world, systems.players_added)
 | 
					SYSTEM(world, systems.players_added)
 | 
				
			||||||
SYSTEM(world, systems.poison_hurts)
 | 
					SYSTEM(world, systems.poison_hurts)
 | 
				
			||||||
 | 
					SYSTEM(world, systems.health_regen)
 | 
				
			||||||
 | 
					SYSTEM(world, systems.lifetimes_expire)
 | 
				
			||||||
SYSTEM(world, systems.life_is_painful)
 | 
					SYSTEM(world, systems.life_is_painful)
 | 
				
			||||||
 | 
					SYSTEM(world, ReplicatedStorage.systems.entities_delete)
 | 
				
			||||||
RUN(world, 0)
 | 
					RUN(world, 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								demo/src/ServerScriptService/systems/health_regen.luau
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								demo/src/ServerScriptService/systems/health_regen.luau
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
 | 
					local ct = require(ReplicatedStorage.components)
 | 
				
			||||||
 | 
					local types = require(ReplicatedStorage.types)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return function(world: types.World, dt: number)
 | 
				
			||||||
 | 
						for e in world:query(ct.Player):without(ct.Health) do
 | 
				
			||||||
 | 
							world:set(e, ct.Health, 100)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for e, health in world:query(ct.Health) do
 | 
				
			||||||
 | 
							if math.random() < 1 / 60 / 30 then
 | 
				
			||||||
 | 
								world:set(e, ct.Health, 100)
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,19 @@
 | 
				
			||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
local ct = require(ReplicatedStorage.components)
 | 
					local ct = require(ReplicatedStorage.components)
 | 
				
			||||||
local types = require(ReplicatedStorage.types)
 | 
					local types = require(ReplicatedStorage.types)
 | 
				
			||||||
 | 
					local jecs = require(ReplicatedStorage.ecs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return function(world: types.World, dt: number)
 | 
					return function(world: types.World, dt: number)
 | 
				
			||||||
	for e in world:query(ct.Player):without(ct.Health) do
 | 
						if math.random() < (1 / 60 / 7) then
 | 
				
			||||||
		world:set(e, ct.Health, 100)
 | 
							for e in world:each(ct.Health) do
 | 
				
			||||||
 | 
								local poison = world:entity()
 | 
				
			||||||
 | 
								world:add(poison, ct.Debuff)
 | 
				
			||||||
 | 
								world:add(poison, jecs.pair(jecs.ChildOf, e))
 | 
				
			||||||
 | 
								world:set(poison, ct.Poison, 10)
 | 
				
			||||||
 | 
								world:set(poison, ct.Lifetime, {
 | 
				
			||||||
 | 
									duration = 3,
 | 
				
			||||||
 | 
									created = os.clock()
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
	for e in world:query(ct.Player, ct.Health):without(ct.Poison) do
 | 
					 | 
				
			||||||
		world:set(e, ct.Poison, 10)
 | 
					 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								demo/src/ServerScriptService/systems/lifetimes_expire.luau
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								demo/src/ServerScriptService/systems/lifetimes_expire.luau
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
 | 
					local ct = require(ReplicatedStorage.components)
 | 
				
			||||||
 | 
					local types = require(ReplicatedStorage.types)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return function(world: types.World, dt: number)
 | 
				
			||||||
 | 
						for e, lifetime in world:query(ct.Lifetime) do
 | 
				
			||||||
 | 
							if os.clock() > lifetime.created + lifetime.duration then
 | 
				
			||||||
 | 
								world:add(e, ct.Destroy)
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -12,9 +12,13 @@ return function(world: types.World, dt: number)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for entity, player in world:query(ct.Player):without(ct.Renderable) do
 | 
						for entity, player in world:query(ct.Player):without(ct.Renderable) do
 | 
				
			||||||
		local character = player.Character
 | 
							local character = player.Character
 | 
				
			||||||
		if character then
 | 
							if not character then
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
		if not character.Parent then
 | 
							if not character.Parent then
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		world:set(entity, ct.Renderable, character)
 | 
							world:set(entity, ct.Renderable, character)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,18 @@
 | 
				
			||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
local ct = require(ReplicatedStorage.components)
 | 
					local ct = require(ReplicatedStorage.components)
 | 
				
			||||||
return function(world, dt)
 | 
					local types = require(ReplicatedStorage.types)
 | 
				
			||||||
	for e, poison, health in world:query(ct.Poison, ct.Health) do
 | 
					local jecs = require(ReplicatedStorage.ecs)
 | 
				
			||||||
		local health_after_tick = health - poison * dt * 0.05
 | 
					
 | 
				
			||||||
		if health_after_tick < 0 then
 | 
					return function(world: types.World, dt: number)
 | 
				
			||||||
			world:remove(e, ct.Health)
 | 
						for e, poison_tick in world:query(ct.Poison, jecs.pair(jecs.ChildOf, jecs.w)) do
 | 
				
			||||||
 | 
							local tgt = world:target(e, jecs.ChildOf)
 | 
				
			||||||
 | 
							local health = world:get(tgt, ct.Health)
 | 
				
			||||||
 | 
							if not health then
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		world:set(e, ct.Health, health_after_tick)
 | 
					
 | 
				
			||||||
 | 
							if math.random() < 1 / 60 / 1 and health > 1 then
 | 
				
			||||||
 | 
								world:set(tgt, ct.Health, health - 1)
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--!strict
 | 
				
			||||||
 | 
					local Players = game:GetService("Players")
 | 
				
			||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
local types = require("../../ReplicatedStorage/types")
 | 
					local ct = require(ReplicatedStorage.components)
 | 
				
			||||||
local ct = require("../../ReplicatedStorage/components")
 | 
					local components = ct :: { [string]: jecs.Entity }
 | 
				
			||||||
 | 
					local remotes = require(ReplicatedStorage.remotes)
 | 
				
			||||||
local jecs = require(ReplicatedStorage.ecs)
 | 
					local jecs = require(ReplicatedStorage.ecs)
 | 
				
			||||||
local remotes = require("../../ReplicatedStorage/remotes")
 | 
					local collect = require(ReplicatedStorage.collect)
 | 
				
			||||||
local components = ct :: {[string]: jecs.Entity }
 | 
					local ty = require(ReplicatedStorage.types)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return function(world: ty.World)
 | 
					return function(world: ty.World)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,9 +23,10 @@ return function(world: ty.World)
 | 
				
			||||||
    local networked_pairs = {}
 | 
					    local networked_pairs = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for component in world:each(ct.Networked) do
 | 
					    for component in world:each(ct.Networked) do
 | 
				
			||||||
    	local name = world:get(component, jecs.Name) :: string
 | 
							local name = assert(world:get(component, jecs.Name), "Invalid component")
 | 
				
			||||||
		if components[name] == nil then
 | 
							if components[name] == nil then
 | 
				
			||||||
			continue
 | 
								error("Invalid component:"..name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        storages[component] = {}
 | 
					        storages[component] = {}
 | 
				
			||||||
| 
						 | 
					@ -32,14 +37,15 @@ return function(world: ty.World)
 | 
				
			||||||
	for relation in world:each(ct.NetworkedPair) do
 | 
						for relation in world:each(ct.NetworkedPair) do
 | 
				
			||||||
		local name = world:get(relation, jecs.Name) :: string
 | 
							local name = world:get(relation, jecs.Name) :: string
 | 
				
			||||||
		if not components[name] then
 | 
							if not components[name] then
 | 
				
			||||||
			continue
 | 
								error("Invalid component")
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		table.insert(networked_pairs, relation)
 | 
							table.insert(networked_pairs, relation)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, component in networked_components do
 | 
						for _, component in networked_components do
 | 
				
			||||||
		local name = world:get(component, jecs.Name) :: string
 | 
							local name = world:get(component, jecs.Name)
 | 
				
			||||||
		if not components[name] then
 | 
							if not components[name] then
 | 
				
			||||||
 | 
								-- error("Invalid component")
 | 
				
			||||||
			error(`Networked Component (%id{component}%name{name})`)
 | 
								error(`Networked Component (%id{component}%name{name})`)
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		local is_tag = jecs.is_tag(world, component)
 | 
							local is_tag = jecs.is_tag(world, component)
 | 
				
			||||||
| 
						 | 
					@ -103,12 +109,16 @@ return function(world: ty.World)
 | 
				
			||||||
	end)
 | 
						end)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- local requested_snapshots = collect(remotes.request_snapshot.OnServerEvent)
 | 
				
			||||||
    local players_added = collect(Players.PlayerAdded)
 | 
					    local players_added = collect(Players.PlayerAdded)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return function()
 | 
					    return function()
 | 
				
			||||||
        local snapshot_lazy: ty.Snapshot
 | 
					        local snapshot_lazy: ty.Snapshot
 | 
				
			||||||
        local set_ids_lazy: { jecs.Entity }
 | 
					        local set_ids_lazy: { jecs.Entity }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        -- In the future maybe it should be requested by the player instead when they
 | 
				
			||||||
 | 
					        -- are ready to receive the replication. Otherwise streaming could be complicated
 | 
				
			||||||
 | 
					        -- with intances references being nil.
 | 
				
			||||||
		for player in players_added do
 | 
							for player in players_added do
 | 
				
			||||||
			if not snapshot_lazy then
 | 
								if not snapshot_lazy then
 | 
				
			||||||
				snapshot_lazy, set_ids_lazy =  {}, {}
 | 
									snapshot_lazy, set_ids_lazy =  {}, {}
 | 
				
			||||||
| 
						 | 
					@ -126,7 +136,7 @@ return function(world: ty.World)
 | 
				
			||||||
						if is_tag then
 | 
											if is_tag then
 | 
				
			||||||
							set_values = table.create(entities_len, true)
 | 
												set_values = table.create(entities_len, true)
 | 
				
			||||||
						else
 | 
											else
 | 
				
			||||||
							local column = archetype.columns[archetype.records[component]]
 | 
												local column = archetype.columns_map[component]
 | 
				
			||||||
							table.move(column, 1, entities_len, set_n + 1, set_values)
 | 
												table.move(column, 1, entities_len, set_n + 1, set_values)
 | 
				
			||||||
						end
 | 
											end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,7 +145,15 @@ return function(world: ty.World)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					local set = table.move(set_ids_lazy, 1, set_n, 1, {})
 | 
										local set = table.move(set_ids_lazy, 1, set_n, 1, {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					snapshot_lazy[tostring(component)] = {
 | 
										local ser_id: string = nil :: any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if jecs.IS_PAIR(component) then
 | 
				
			||||||
 | 
											ser_id = `{jecs.pair_first(world, component)},{jecs.pair_first(world, component)}`
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											ser_id = tostring(component)
 | 
				
			||||||
 | 
										end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								    	snapshot_lazy[ser_id] = {
 | 
				
			||||||
	                    set = if set_n > 0 then set else nil,
 | 
						                    set = if set_n > 0 then set else nil,
 | 
				
			||||||
	                    values = if set_n > 0 then set_values else nil,
 | 
						                    values = if set_n > 0 then set_values else nil,
 | 
				
			||||||
	                }
 | 
						                }
 | 
				
			||||||
| 
						 | 
					@ -159,7 +177,7 @@ return function(world: ty.World)
 | 
				
			||||||
		            set_n += 1
 | 
							            set_n += 1
 | 
				
			||||||
		            set_ids[set_n] = e
 | 
							            set_ids[set_n] = e
 | 
				
			||||||
		            set_values[set_n] = v or true
 | 
							            set_values[set_n] = v or true
 | 
				
			||||||
		        elseif world:contains(e) then
 | 
							        elseif not world:contains(e) then
 | 
				
			||||||
		            removed_n += 1
 | 
							            removed_n += 1
 | 
				
			||||||
		            removed_ids[removed_n] = e
 | 
							            removed_ids[removed_n] = e
 | 
				
			||||||
		        end
 | 
							        end
 | 
				
			||||||
| 
						 | 
					@ -176,7 +194,15 @@ return function(world: ty.World)
 | 
				
			||||||
            if dirty then
 | 
					            if dirty then
 | 
				
			||||||
            	local removed = table.move(removed_ids, 1, removed_n, 1, {}) :: { jecs.Entity }
 | 
					            	local removed = table.move(removed_ids, 1, removed_n, 1, {}) :: { jecs.Entity }
 | 
				
			||||||
             	local set = table.move(set_ids, 1, set_n, 1, {}) :: { jecs.Entity }
 | 
					             	local set = table.move(set_ids, 1, set_n, 1, {}) :: { jecs.Entity }
 | 
				
			||||||
	            snapshot[tostring(component)] = {
 | 
						            local ser_id: string = nil :: any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if jecs.IS_PAIR(component) then
 | 
				
			||||||
 | 
										ser_id = `{jecs.pair_first(world, component)},{jecs.pair_second(world, component)}`
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										ser_id = tostring(component)
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						            snapshot[ser_id] = {
 | 
				
			||||||
                    set = if set_n > 0 then set else nil,
 | 
					                    set = if set_n > 0 then set else nil,
 | 
				
			||||||
                    values = if set_n > 0 then set_values else nil,
 | 
					                    values = if set_n > 0 then set_values else nil,
 | 
				
			||||||
                    removed = if removed_n > 0 then removed else nil
 | 
					                    removed = if removed_n > 0 then removed else nil
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,11 +24,6 @@ type Id<T=unknown> = jecs.Id<T>
 | 
				
			||||||
local entity_visualiser = require("@tools/entity_visualiser")
 | 
					local entity_visualiser = require("@tools/entity_visualiser")
 | 
				
			||||||
local dwi = entity_visualiser.stringify
 | 
					local dwi = entity_visualiser.stringify
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST("repro", function()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST("bulk", function()
 | 
					TEST("bulk", function()
 | 
				
			||||||
	local world = jecs.world()
 | 
						local world = jecs.world()
 | 
				
			||||||
	local A = world:component()
 | 
						local A = world:component()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue