diff --git a/modifiers/field/field.modifier.lx b/modifiers/field/field.modifier.lx new file mode 100644 index 0000000..153ee9a --- /dev/null +++ b/modifiers/field/field.modifier.lx @@ -0,0 +1,16 @@ +modifier = { + description = "A Field of Slots" + field = "field" + display = "Field" + class = "Field" + dependency = [] + + blocks = { + data = { + fields = [ + { name="slot_scale" type="number" default=1 } + { name="slot_distance" type="number" default=50 } + ] + } + } +} \ No newline at end of file diff --git a/modifiers/field/field.modifier.wren b/modifiers/field/field.modifier.wren new file mode 100644 index 0000000..ea4ccf0 --- /dev/null +++ b/modifiers/field/field.modifier.wren @@ -0,0 +1,488 @@ + +//-- this file is generated! don't try editing it. + +import "luxe: io" for IO +import "luxe: bytes" for Byter, Bytes +import "luxe: world" for Block + +//`modifiers/field/field > runtime` types + + class ModifierRuntime { + + construct new() { + } //new + + } //ModifierRuntime + +//`modifiers/field/field > runtime` compilers + + class ModifierRuntimeCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 0 + + return size + + } //bytes_count + + validate(from_source_id, elements) { + + var fields = { + "type": false, //:luxe:internal + "uuid": false, //:luxe:internal + "luxe.self.modifier": false, //:luxe:internal + } + for(element in elements) { + var instance = element.value + for(field in instance) { + if(fields[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`") + } //if not found + } //each field + for(field in fields) { + var required = field.value + if(required && instance[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)") + } + } //each field + } //each element + + } //validate + + write(compiler, instance, out) { + + //version + out.write_int32(0) + + return out + + } //write + + bytes_count_block() { + + return 8 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/field/field > runtime")) + + //fields count + out.write_int32(0) + + } //write_block + + write(instance) { + + var size = bytes_count(instance) + var out = Byter.new(size+8) + + out.write_string("LUXEMRTM") + + write(instance, out) + + return out + + } //write + + } //ModifierRuntimeCompiler + +//`modifiers/field/field > runtime` block types + + class BlockModifierRuntime { + + field { "field" } + source { "modifiers/field/field > runtime" } + + construct new(block) { + _block = block + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + } + + construct new() { + _block = Block.create() + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + Block.set_type(_block, "modifiers/field/field > runtime") + } //new + + instance_type { + + class BlockInstModifierRuntime { + slot { _slot } + entity { Block.get_handle(_block, _slot) } + block_set_slot(value) { + _slot=value + return this + } + construct new(block, slot) { + _block = block + _slot = slot + } //new + block { _block } + } //BlockInstModifierRuntime + + return BlockInstModifierRuntime + + } //instance_type + + block { _block } + count { Block.get_count(_block) } + add() { Block.add(_block) } + append(other_block) { Block.append(_block, other_block) } + each(c, fn) { + for(i in 0 ... c) { + fn.call(0, _inst.block_set_slot(i)) + } + } //each + + [slot, inst] { _inst.block_set_slot(slot) } + + [slot] { _inst_type.new(_block, slot) } + } //BlockModifierRuntime + + +//`modifiers/field/field > data` types + + class ModifierData { + + construct new() { + _slot_scale = 1 + _slot_distance = 50 + } //new + + slot_scale { _slot_scale } + slot_scale=(vvv) { _slot_scale = vvv } + + slot_distance { _slot_distance } + slot_distance=(vvv) { _slot_distance = vvv } + + } //ModifierData + +//`modifiers/field/field > data` compilers + + class ModifierDataCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 8 // slot_scale + + size = size + 8 // slot_distance + + size = size + 0 + + return size + + } //bytes_count + + validate(from_source_id, elements) { + + var fields = { + "type": false, //:luxe:internal + "uuid": false, //:luxe:internal + "luxe.self.modifier": false, //:luxe:internal + "slot_scale": false, + "slot_distance": false, + } + for(element in elements) { + var instance = element.value + for(field in instance) { + if(fields[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`") + } //if not found + } //each field + for(field in fields) { + var required = field.value + if(required && instance[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)") + } + } //each field + } //each element + + } //validate + + write(compiler, instance, out) { + + //version + out.write_int32(0) + + var slot_scale = instance["slot_scale"] + if(slot_scale == null) slot_scale = 1 + out.write_float64(slot_scale) + + + var slot_distance = instance["slot_distance"] + if(slot_distance == null) slot_distance = 50 + out.write_float64(slot_distance) + + + return out + + } //write + + bytes_count_block() { + + return 40 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/field/field > data")) + + //fields count + out.write_int32(2) + + // slot_scale + out.write_uint32(compiler.string.hash("slot_scale")) + out.write_uint32(467038368) //type number + var slot_scale_default = 1 + out.write_float64(slot_scale_default) + + + // slot_distance + out.write_uint32(compiler.string.hash("slot_distance")) + out.write_uint32(467038368) //type number + var slot_distance_default = 50 + out.write_float64(slot_distance_default) + + + } //write_block + + write(instance) { + + var size = bytes_count(instance) + var out = Byter.new(size+8) + + out.write_string("LUXEMDTA") + + write(instance, out) + + return out + + } //write + + } //ModifierDataCompiler + +//`modifiers/field/field > data` block types + + class BlockModifierData { + + field { "field" } + source { "modifiers/field/field > data" } + + construct new(block) { + _block = block + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + } + + construct new() { + _block = Block.create() + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + Block.add(_block, "slot_scale", "number", 1) + Block.add(_block, "slot_distance", "number", 50) + Block.set_type(_block, "modifiers/field/field > data") + } //new + + instance_type { + + class BlockInstModifierData { + slot_scale { Block.get(_block, "slot_scale", _slot) } + slot_scale=(v) { Block.set(_block, "slot_scale", _slot, v) } + slot_distance { Block.get(_block, "slot_distance", _slot) } + slot_distance=(v) { Block.set(_block, "slot_distance", _slot, v) } + slot { _slot } + entity { Block.get_handle(_block, _slot) } + block_set_slot(value) { + _slot=value + return this + } + construct new(block, slot) { + _block = block + _slot = slot + } //new + block { _block } + } //BlockInstModifierData + + return BlockInstModifierData + + } //instance_type + + block { _block } + count { Block.get_count(_block) } + add() { Block.add(_block) } + append(other_block) { Block.append(_block, other_block) } + each(c, fn) { + for(i in 0 ... c) { + fn.call(0, _inst.block_set_slot(i)) + } + } //each + + [slot, inst] { _inst.block_set_slot(slot) } + + [slot] { _inst_type.new(_block, slot) } + } //BlockModifierData + + +//`modifiers/field/field > world` types + + class ModifierWorld { + + construct new() { + } //new + + } //ModifierWorld + +//`modifiers/field/field > world` compilers + + class ModifierWorldCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 0 + + return size + + } //bytes_count + + validate(from_source_id, elements) { + + var fields = { + "type": false, //:luxe:internal + "uuid": false, //:luxe:internal + "luxe.self.modifier": false, //:luxe:internal + } + for(element in elements) { + var instance = element.value + for(field in instance) { + if(fields[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`") + } //if not found + } //each field + for(field in fields) { + var required = field.value + if(required && instance[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)") + } + } //each field + } //each element + + } //validate + + write(compiler, instance, out) { + + //version + out.write_int32(0) + + return out + + } //write + + bytes_count_block() { + + return 8 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/field/field > world")) + + //fields count + out.write_int32(0) + + } //write_block + + write(instance) { + + var size = bytes_count(instance) + var out = Byter.new(size+8) + + out.write_string("LUXEMWLD") + + write(instance, out) + + return out + + } //write + + } //ModifierWorldCompiler + +//`modifiers/field/field > world` block types + + class BlockModifierWorld { + + field { "field" } + source { "modifiers/field/field > world" } + + construct new(block) { + _block = block + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + } + + construct new() { + _block = Block.create() + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + Block.set_type(_block, "modifiers/field/field > world") + } //new + + instance_type { + + class BlockInstModifierWorld { + slot { _slot } + entity { Block.get_handle(_block, _slot) } + block_set_slot(value) { + _slot=value + return this + } + construct new(block, slot) { + _block = block + _slot = slot + } //new + block { _block } + } //BlockInstModifierWorld + + return BlockInstModifierWorld + + } //instance_type + + block { _block } + count { Block.get_count(_block) } + add() { Block.add(_block) } + append(other_block) { Block.append(_block, other_block) } + each(c, fn) { + for(i in 0 ... c) { + fn.call(0, _inst.block_set_slot(i)) + } + } //each + + [slot, inst] { _inst.block_set_slot(slot) } + + [slot] { _inst_type.new(_block, slot) } + } //BlockModifierWorld + diff --git a/modifiers/field/field.wren b/modifiers/field/field.wren new file mode 100644 index 0000000..a6efb7d --- /dev/null +++ b/modifiers/field/field.wren @@ -0,0 +1,60 @@ +import "luxe: io" for IO +import "luxe: world" for World, Entity, Modifiers, ModifierSystem + +//User facing API +//This is what the user of your modifier will interact with +class Field { + + static create(entity) { Modifiers.create(This, entity) } + static destroy(entity) { Modifiers.destroy(This, entity) } + static has(entity) { Modifiers.has(This, entity) } + + static get_distance(entity) { + var data = Modifiers.get(This, entity) + return data.slot_distance + } + + static get_scale(entity) { + var data = Modifiers.get(This, entity) + return data.slot_scale + } +} //Field + +//Your modifier system implementation. +//This speaks to the engine and your user facing API +//to do the actual work. You'll get notified when things change +//in the world and respond to them here. +class FieldSystem is ModifierSystem { + + construct new() { + //called when your system is first created. + } + + init(world) { + _world = world + //called when your modifier is created in a world + } + + destroy() { + //called when your modifier is removed from a world + } + + attach(entity, data) { + //called when attached to an entity + } + + detach(entity, data) { + //called when detached from an entity, like on destroy + } + + tick(delta) { + //called usually once every frame. + //called when the world that this modifier lives in, is ticked + each {|entity, data| + //use data.* + } + } //tick + +} //FieldSystem + +var Modifier = FieldSystem //required \ No newline at end of file diff --git a/modifiers/slot/slot.modifier.lx b/modifiers/slot/slot.modifier.lx index cad68d6..407890d 100644 --- a/modifiers/slot/slot.modifier.lx +++ b/modifiers/slot/slot.modifier.lx @@ -9,6 +9,8 @@ modifier = { data = { fields = [ { name="coord" type="float3" default=[0, 0, 0] } + { name="auto_naming" type="boolean" default=false } + { name="field" type="id32" editor="entity" default="" } ] } } diff --git a/modifiers/slot/slot.modifier.wren b/modifiers/slot/slot.modifier.wren index 8ef57d2..bee2bb1 100644 --- a/modifiers/slot/slot.modifier.wren +++ b/modifiers/slot/slot.modifier.wren @@ -157,11 +157,19 @@ import "luxe: world" for Block construct new() { _coord = [0, 0, 0] + _auto_naming = false + _field = "" } //new coord { _coord } coord=(vvv) { _coord = vvv } + auto_naming { _auto_naming } + auto_naming=(vvv) { _auto_naming = vvv } + + field { _field } + field=(vvv) { _field = vvv } + } //ModifierData //`modifiers/slot/slot > data` compilers @@ -177,6 +185,10 @@ import "luxe: world" for Block size = size + 12 // coord + size = size + 4 // auto_naming + + size = size + 4 // field + size = size + 0 return size @@ -190,6 +202,8 @@ import "luxe: world" for Block "uuid": false, //:luxe:internal "luxe.self.modifier": false, //:luxe:internal "coord": false, + "auto_naming": false, + "field": false, } for(element in elements) { var instance = element.value @@ -220,13 +234,23 @@ import "luxe: world" for Block out.write_float32(coord[2]) + var auto_naming = instance["auto_naming"] + if(auto_naming == null) auto_naming = false + out.write_int32(auto_naming ? 1 : 0) + + + var field = instance["field"] + if(field == null) field = "" + out.write_uint32((field && field != "") ? compiler.string.hash(field) : 0) + + return out } //write bytes_count_block() { - return 28 + return 52 } //bytes_count_block @@ -236,7 +260,7 @@ import "luxe: world" for Block out.write_uint32(compiler.string.hash("modifiers/slot/slot > data")) //fields count - out.write_int32(1) + out.write_int32(3) // coord out.write_uint32(compiler.string.hash("coord")) @@ -247,6 +271,20 @@ import "luxe: world" for Block out.write_float32(coord_default[2]) + // auto_naming + out.write_uint32(compiler.string.hash("auto_naming")) + out.write_uint32(1710517951) //type boolean + var auto_naming_default = false + out.write_int32(auto_naming_default ? 1 : 0) + + + // field + out.write_uint32(compiler.string.hash("field")) + out.write_uint32(2729592961) //type id32 + var field_default = "" + out.write_uint32((field_default && field_default != "") ? compiler.string.hash(field_default) : 0) + + } //write_block write(instance) { @@ -282,6 +320,8 @@ import "luxe: world" for Block _inst_type = instance_type _inst = _inst_type.new(_block, 0) Block.add(_block, "coord", "float3", [0, 0, 0]) + Block.add(_block, "auto_naming", "boolean", false) + Block.add(_block, "field", "id32", "") Block.set_type(_block, "modifiers/slot/slot > data") } //new @@ -290,6 +330,10 @@ import "luxe: world" for Block class BlockInstModifierData { coord { Block.get(_block, "coord", _slot) } coord=(v) { Block.set(_block, "coord", _slot, v) } + auto_naming { Block.get(_block, "auto_naming", _slot) } + auto_naming=(v) { Block.set(_block, "auto_naming", _slot, v) } + field { Block.get(_block, "field", _slot) } + field=(v) { Block.set(_block, "field", _slot, v) } slot { _slot } entity { Block.get_handle(_block, _slot) } block_set_slot(value) { diff --git a/modifiers/slot/slot.wren b/modifiers/slot/slot.wren index 556bd74..eb981be 100644 --- a/modifiers/slot/slot.wren +++ b/modifiers/slot/slot.wren @@ -1,6 +1,9 @@ import "luxe: io" for IO import "luxe: world" for World, Entity, Modifiers, ModifierSystem, Transform import "utils/hex" for Hex +import "utils/vec" for Vec +import "modifiers/field/field" for Field +import "luxe: assets" for Strings //User facing API //This is what the user of your modifier will interact with @@ -10,6 +13,16 @@ class Slot { static destroy(entity) { Modifiers.destroy(This, entity) } static has(entity) { Modifiers.has(This, entity) } + static set_coord(entity, coord){ + var data = Modifiers.get(This, entity) + data.coord = coord + } + + static get_coord(entity, coord){ + var data = Modifiers.get(This, entity) + return data.coord + } + } //Slot //Your modifier system implementation. @@ -25,6 +38,8 @@ class SlotSystem is ModifierSystem { init(world) { _world = world //called when your modifier is created in a world + + if(World.tag_has(_world, "edit")) _positions = {} } destroy() { @@ -45,12 +60,43 @@ class SlotSystem is ModifierSystem { //called usually once every frame. //called when the world that this modifier lives in, is ticked each {|entity, data| + var distance = 50 + var scale = 1 + + find_entity(entity, Strings.get(data.field)) + .then{|field| + distance = Field.get_distance(field) + scale = Field.get_scale(field) + } + var pos = Transform.get_pos(entity) - var coord = Hex.pos_to_coord(pos, 50) //todo: get scale from field - coord = Hex.round(coord) - pos = Hex.coord_to_pos(coord, 50) - Transform.set_pos(entity, pos.x, pos.y) - data.coord = coord + if(!Vec.approximately(_positions[entity], pos)){ + var coord = Hex.pos_to_coord(pos, distance) + coord = Hex.round(coord) + data.coord = coord + pos = Hex.coord_to_pos(coord, distance) + Transform.set_pos(entity, pos.x, pos.y, pos.z) + _positions[entity] = pos + Transform.set_scale(entity, scale, scale, 1) + if(data.auto_naming){ + var name = "Slot_(%(coord.x),%(coord.y),%(coord.z))" + if(Entity.get_name(entity) != name){ + var num = 1 + while(Entity.valid(Entity.get_named(_world, name)) && Entity.get_named(_world, name) != entity){ + num = num + 1 + name = "Slot_(%(coord.x),%(coord.y),%(coord.z))_%(num)" + } + Entity.set_name(entity, name) + } + } + } else { + //we could optimize this by not doing it every frame... ...in theory + pos = Hex.coord_to_pos(data.coord, distance) + Transform.set_pos(entity, pos.x, pos.y, pos.z) + _positions[entity] = pos + } + + Transform.set_scale(entity, scale, scale, 1) } } //tick diff --git a/prototype/layout_7x5.prototype.lx b/prototype/layout_7x5.prototype.lx index faac696..8b70847 100644 --- a/prototype/layout_7x5.prototype.lx +++ b/prototype/layout_7x5.prototype.lx @@ -1,74 +1,70 @@ prototype = { elements = { - slot_1,-1,0 = { + Slot_(0,0,0).11G = { modifiers = { - sprite = { - material = "material/hexagon" - height = 64 - type = "luxe: modifier/sprite" - width = 64 - } //sprite slot = { + auto_naming = true type = "modifiers/slot/slot" + field = "455ce044-0613-47f3-83b7-cc962dd417d4" } //slot transform = { - scale = [1.5 1.5 1] //scale - pos = [86.602539 0 0] //pos - link = "455ce044-0613-47f3-83b7-cc962dd417d4" + pos = [-86.602539 0 0] //pos type = "luxe: modifier/transform" - rotation = [0 -0 0] //rotation } //transform } //modifiers - uuid = "81cb28ce-7f4d-4a8a-bbf2-b681ead0955a" - } //slot_1,-1,0 - slot_1,0,-1 = { + uuid = "530f545e-5d2e-4071-92da-445643d00a5e" + prototype = { + source = "prototype/slot" + elements = {} //elements + } //prototype + } //Slot_(0,0,0).11G + slot-2vG = { modifiers = { - sprite = { - material = "material/hexagon" - height = 64 - type = "luxe: modifier/sprite" - width = 64 - } //sprite slot = { + auto_naming = true type = "modifiers/slot/slot" + field = "455ce044-0613-47f3-83b7-cc962dd417d4" } //slot transform = { - scale = [1.5 1.5 1] //scale - pos = [43.30127 75 0] //pos - link = "455ce044-0613-47f3-83b7-cc962dd417d4" + pos = [-43.30127 75 0] //pos type = "luxe: modifier/transform" - rotation = [0 -0 0] //rotation } //transform } //modifiers - uuid = "44930a60-0581-4703-aebc-5a633b88de3a" - } //slot_1,0,-1 - slot_0,0,0 = { + uuid = "3dfd2d98-3ad6-4a30-a329-480051cd0c97" + prototype = { + source = "prototype/slot" + elements = {} //elements + } //prototype + } //slot-2vG + slot-1GB = { modifiers = { - sprite = { - material = "material/hexagon" - height = 64 - type = "luxe: modifier/sprite" - width = 64 - } //sprite slot = { + auto_naming = true type = "modifiers/slot/slot" + field = "455ce044-0613-47f3-83b7-cc962dd417d4" } //slot transform = { - scale = [1.5 1.5 1] //scale - pos = [0 -0 0] //pos - link = "455ce044-0613-47f3-83b7-cc962dd417d4" + pos = [0 0 0] //pos type = "luxe: modifier/transform" - rotation = [0 -0 0] //rotation } //transform } //modifiers - uuid = "63febcbe-b95f-4f6f-ad64-e8360383e9a4" - } //slot_0,0,0 + uuid = "22fcb4e7-1995-4973-a290-be2704541713" + prototype = { + source = "prototype/slot" + elements = {} //elements + } //prototype + } //slot-1GB field = { modifiers = { transform = { pos = [0 0 0] //pos type = "luxe: modifier/transform" } //transform + field = { + slot_scale = 1.5 + slot_distance = 50 + type = "modifiers/field/field" + } //field } //modifiers uuid = "455ce044-0613-47f3-83b7-cc962dd417d4" } //field diff --git a/prototype/slot.prototype.lx b/prototype/slot.prototype.lx new file mode 100644 index 0000000..05c12f3 --- /dev/null +++ b/prototype/slot.prototype.lx @@ -0,0 +1,20 @@ +prototype = { + elements = { + bg = { + modifiers = { + sprite = { + material = "material/hexagon" + height = 64 + flip_v = false + flip_h = false + type = "luxe: modifier/sprite" + width = 64 + } //sprite + transform = { + type = "luxe: modifier/transform" + } //transform + } //modifiers + uuid = "8763b0a1-320c-4747-ae21-97488df187e8" + } //bg + } //elements +} //prototype diff --git a/utils/vec.wren b/utils/vec.wren index 7622c91..52bf488 100644 --- a/utils/vec.wren +++ b/utils/vec.wren @@ -39,4 +39,19 @@ class Vec{ } return result } + + static approximately(first, second){ + if(!(first is List) || !(second is List)) return false + if(first.count != second.count) return false + var count = first.count + if(count < 1) return true + if((first[0] - second[0]).abs > 0.001) return false + if(count < 2) return true + if((first[1] - second[1]).abs > 0.001) return false + if(count < 3) return true + if((first[2] - second[2]).abs > 0.001) return false + if(count < 4) return true + if((first[3] - second[3]).abs > 0.001) return false + return true + } } \ No newline at end of file