Merge pull request #63 from hppeng-wynn/smarter_compute_node
ComputeNode subclass that will defer updates if its value did not change
This commit is contained in:
commit
91d295ef92
3 changed files with 77 additions and 16 deletions
|
@ -124,16 +124,16 @@ const default_abils = {
|
||||||
/**
|
/**
|
||||||
* Update ability tree internal representation. (topologically sorted node list)
|
* Update ability tree internal representation. (topologically sorted node list)
|
||||||
*
|
*
|
||||||
* Signature: AbilityTreeUpdateNode(build: Build) => ATree (List of atree nodes in topological order)
|
* Signature: AbilityTreeUpdateNode(player-class: str) => ATree (List of atree nodes in topological order)
|
||||||
*/
|
*/
|
||||||
const atree_node = new (class extends ComputeNode {
|
const atree_node = new (class extends ComputeNode {
|
||||||
constructor() { super('builder-atree-update'); }
|
constructor() { super('builder-atree-update'); }
|
||||||
|
|
||||||
compute_func(input_map) {
|
compute_func(input_map) {
|
||||||
if (input_map.size !== 1) { throw "AbilityTreeUpdateNode accepts exactly one input (build)"; }
|
if (input_map.size !== 1) { throw "AbilityTreeUpdateNode accepts exactly one input (player-class)"; }
|
||||||
const [build] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element
|
const [player_class] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element
|
||||||
|
|
||||||
const atree_raw = atrees[wep_to_class.get(build.weapon.statMap.get('type'))];
|
const atree_raw = atrees[player_class];
|
||||||
if (!atree_raw) return null;
|
if (!atree_raw) return null;
|
||||||
|
|
||||||
let atree_map = new Map();
|
let atree_map = new Map();
|
||||||
|
|
|
@ -435,6 +435,17 @@ class BuildAssembleNode extends ComputeNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PlayerClassNode extends ValueCheckComputeNode {
|
||||||
|
constructor(name) { super(name); }
|
||||||
|
|
||||||
|
compute_func(input_map) {
|
||||||
|
if (input_map.size !== 1) { throw "PlayerClassNode accepts exactly one input (build)"; }
|
||||||
|
const [build] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element
|
||||||
|
|
||||||
|
return wep_to_class.get(build.weapon.statMap.get('type'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read an input field and parse into a list of powderings.
|
* Read an input field and parse into a list of powderings.
|
||||||
* Every two characters makes one powder. If parsing fails, NULL is returned.
|
* Every two characters makes one powder. If parsing fails, NULL is returned.
|
||||||
|
@ -1085,8 +1096,9 @@ function builder_graph_init() {
|
||||||
|
|
||||||
// Phase 3/3: Set up atree stuff.
|
// Phase 3/3: Set up atree stuff.
|
||||||
|
|
||||||
|
let class_node = new PlayerClassNode('builder-class').link_to(build_node);
|
||||||
// These two are defined in `atree.js`
|
// These two are defined in `atree.js`
|
||||||
atree_node.link_to(build_node, 'build');
|
atree_node.link_to(class_node, 'player-class');
|
||||||
atree_merge.link_to(build_node, 'build');
|
atree_merge.link_to(build_node, 'build');
|
||||||
atree_graph_creator = new AbilityTreeEnsureNodesNode(build_node, stat_agg_node)
|
atree_graph_creator = new AbilityTreeEnsureNodesNode(build_node, stat_agg_node)
|
||||||
.link_to(atree_collect_spells, 'spells');
|
.link_to(atree_collect_spells, 'spells');
|
||||||
|
|
|
@ -14,7 +14,10 @@ class ComputeNode {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.update_task = null;
|
this.update_task = null;
|
||||||
this.fail_cb = false; // Set to true to force updates even if parent failed.
|
this.fail_cb = false; // Set to true to force updates even if parent failed.
|
||||||
this.dirty = true;
|
this.dirty = 2; // 3 states:
|
||||||
|
// 2: dirty
|
||||||
|
// 1: possibly dirty
|
||||||
|
// 0: clean
|
||||||
this.inputs_dirty = new Map();
|
this.inputs_dirty = new Map();
|
||||||
this.inputs_dirty_count = 0;
|
this.inputs_dirty_count = 0;
|
||||||
all_nodes.push(this);
|
all_nodes.push(this);
|
||||||
|
@ -27,15 +30,17 @@ class ComputeNode {
|
||||||
if (this.inputs_dirty_count != 0) {
|
if (this.inputs_dirty_count != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.dirty) {
|
if (this.dirty === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let calc_inputs = new Map();
|
if (this.dirty == 2) {
|
||||||
for (const input of this.inputs) {
|
let calc_inputs = new Map();
|
||||||
calc_inputs.set(this.input_translation.get(input.name), input.value);
|
for (const input of this.inputs) {
|
||||||
|
calc_inputs.set(this.input_translation.get(input.name), input.value);
|
||||||
|
}
|
||||||
|
this.value = this.compute_func(calc_inputs);
|
||||||
}
|
}
|
||||||
this.value = this.compute_func(calc_inputs);
|
this.dirty = 0;
|
||||||
this.dirty = false;
|
|
||||||
for (const child of this.children) {
|
for (const child of this.children) {
|
||||||
child.mark_input_clean(this.name, this.value);
|
child.mark_input_clean(this.name, this.value);
|
||||||
}
|
}
|
||||||
|
@ -64,12 +69,12 @@ class ComputeNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_dirty() {
|
mark_dirty(dirty_state=2) {
|
||||||
if (!this.dirty) {
|
if (this.dirty < dirty_state) {
|
||||||
this.dirty = true;
|
this.dirty = dirty_state;
|
||||||
for (const child of this.children) {
|
for (const child of this.children) {
|
||||||
child.mark_input_dirty(this.name);
|
child.mark_input_dirty(this.name);
|
||||||
child.mark_dirty();
|
child.mark_dirty(dirty_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -125,6 +130,50 @@ class ComputeNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ValueCheckComputeNode extends ComputeNode {
|
||||||
|
constructor(name) { super(name); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request update of this compute node. Pushes updates to children,
|
||||||
|
* but only if this node's value changed.
|
||||||
|
*/
|
||||||
|
update() {
|
||||||
|
if (this.inputs_dirty_count != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.dirty === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let calc_inputs = new Map();
|
||||||
|
for (const input of this.inputs) {
|
||||||
|
calc_inputs.set(this.input_translation.get(input.name), input.value);
|
||||||
|
}
|
||||||
|
let val = this.compute_func(calc_inputs);
|
||||||
|
if (val !== this.value) {
|
||||||
|
this.mark_dirty(2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("soft update");
|
||||||
|
}
|
||||||
|
this.value = val;
|
||||||
|
|
||||||
|
this.dirty = 0;
|
||||||
|
for (const child of this.children) {
|
||||||
|
child.mark_input_clean(this.name, this.value);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defaulting to "dusty" state.
|
||||||
|
*/
|
||||||
|
mark_dirty(dirty_state="unused") {
|
||||||
|
return super.mark_dirty(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule a ComputeNode to be updated.
|
* Schedule a ComputeNode to be updated.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue