The Spatials V3 devblog 2015-09-21

Internal development notes, very slightly cleaned up and commented a week later.

The focus for the past week was to start the work on the in-station logistics system.

- need now text display plus scrolling, v2 gui parity
	void iconText(std::string iconFrame, std::string iconColor, std::string text, std::string textColor)
	void animateScreenMoveBy(cocos2d::CCNode* node, float d, float x, float y)
	void animateFadeOut(cocos2d::CCNode* node, float d)

V2 often made use of scrolling text over the map when something interesting happened. This has been implemented now in V3, as an Scheme ECS system. It’s also a good example on how to do a simple, custom display system.

- job for dismantling objects
	component, system
	red tintc
	finally need a "ready" flag component on objects
		added by successful construction
		removed when flagged for dismantling
	patch erase tool to:
		when ready, inject component
		when not ready, just destroy

The object dismantling tool was still running in editor mode. It has been replaced with a proper enitity job plus its system.

- logistics phase 1: basic items
	ItemComponent
		kind: Resource*
		amount
	display system for must(ItemC,PosC)+exclude(ChildC)
	maker: ItemMake (with auto scheme binding style)

This commit introduced logistics to V3. For starters a new ItemComponent was introduced, which represents a Resource kind plus a stack size.

- item index component: have a custom kind depending on its resource
	purely a flag to speed up item finding, has no data
	precalc kind (hashed internal resource name) into Resource

In order to fully leverage the ECS system entities which desire to represent a Resource kind can be directly indexed with the hash of the internal name of the resource. This will make it much faster to lookup item stacks in the world.

- Entity* TileMapSystem::closestEntityWithValidPath(float x, float y, AspectInst* ai)
- use closestEntityWithValidPath in WorkerSystem, do not pick jobs with an invalid path

Some logic was using a fast approach to finding nearby stuff, without taking into account the pathfinding. A new helper has been introduced to look up entities with a valid path from a given position.

- logistics phase 2: JobC/JobsSys also handles gathering of resources, optionally
	JobC also has logistics reqs (requiredResource, requiredAmount)
	JobsSys is now a little state machine
		current state idx is kept inside WorkerC, and reset on acquiring a new job
	JobsSys state -1: if logistics reqs go state 0, else go state 1
	JobsSys state 0
		if worker not pathing, find a parent-less ItemC ent comatible with res/amnt, then path to it
			if cannot find, drop the BusyC of job ent and worker ent, this is not job/worker for them
		on every JobsSys tick check if we can pick the required resources from the 9-neigh of the worker
			once picked, make it a child of the worker and go state 1
	JobsSys state 1
		same logic as existing (path to job position, action pose for N ticks)
- if req amount is for example 10, and there's 2 stacks of 8 and 4, JobsSys cannot send the officer to pick both of them
	re-run state 0 while the held amount by the worker is less than the required
	abort job when impossible to find more
- current logic is hardcoded to an amount of 1, including the item finder, which never checks amount, only kind
	-> after the previous fix this is not a problem anymore

The big one for the past week. The first phase of logistics just introduced the existence of item stacks. Phase 2 also made it optional for jobs to require a certain amount of resources. JobsSystem was enhanced to introduce a seek-and-pick behavior for worker entities, which now will find and approach nearby available stacks of items, picking and stacking items, until they meed the required amount, then go and perform their job. The tracking behaviour for picked stacks is just adding ChildComponent with trackPosition = true. The choice of generic components/systems for modelling relationships between entities (ChildComponent, BusyComponent) is proving to be very successful.

- helper: Entity* ItemHeldBy(World* world, Entity* worker, Resource* resource);
- helper: Entity* ItemDepositIn(World* world, Entity* worker, Entity* picked);
- helper: Entity* ItemPick(World* world, Entity* stack, int amount);
- helper: Entity* ItemPickHeldBy(World* world, Entity* worker, Resource* resource, int amount);

A series of C++ but Scheme-callable helpers related to items and item stacks were implemented. Rather than hardcoding item stacking logic into JobsSystem, all the code related to stacks has been implemented as stand alone functions that assume almost nothing about the involved entities. This will make it possible for any interested system to participate in logistics and item management.

- item consumption after a succesful job with logistics
	don't do in JobsSys, do inside the respective systems?
		general gathering does not require consumption for example
	example system (using objbuild.scm for now) is destroying held amount

A choice was made to not implement any resource consuption logic in JobsSystem. Just as a previous choice was made to not implement any logic for completed jobs, it will be the responsability of the system that spawned the job to apply any required logic over the picked resources, if any.

- system that detects item ents attached to idle workers and drops them on floor

It’s possible to get a worker interrupted while they are in the middle of a job in a way that makes it impossible to resume it (deleting the job’s object, for example). When this happens the worker can be left idling, but still holding an item stack. A very simple system was implemented to detect those workers and make them drop the stack on he ground, which will make lose its ChildComppment and make it available for picking again. The system was implemented in Scheme and its logic is just four lines of code:

(define-mod-export autodrop-component (bridge-hash "autodrop-component"))

(define-mod-export (station-autodrop-system-post-process s e)
	([ 	held (ItemHeldBy (s #@world) e (persisting-null)) ]
		(unless (persisting-null? held)
			(ecs-remove-component held ChildComponent_Kind))))

(define-mod-export (make-station-autodrop-system body world)
	(ecs-make-system
		name: "station-autodrop-system"
		world: world
		aspect: (ecs-aspect
			must: (list PositionComponent_Kind autodrop-component)
			exclude: (list BusyComponent_Kind))
		phase: 30
		hooks: (list 'station-autodrop-system-post-process)))

All the entities that desire to be tracked by this system just need to add an autodrop-component.

- use nonlinear zoom in mouse wheel under windows

Finally :)