79 lines
3.4 KiB
Plaintext
79 lines
3.4 KiB
Plaintext
// Lib is its own class because, while it would make sense to group its functions and macros in Archive.kiss,
|
|
// other files would not be able to (load "Archive.kiss") for the macro definitions without taking on Archive's constructor.
|
|
|
|
// External programs can load Lib.kiss with (loadFrom "nat-archive-tool" "src/nat/Lib.kiss")
|
|
|
|
(defMacro hasComponent [e componentType]
|
|
`(.exists .components ,e ,(symbolName componentType)))
|
|
|
|
(defMacro _componentPath [archive e componentType]
|
|
`(joinPath .archiveDir (the nat.Archive ,archive) "components" (+ (dictGet (the Map<String,String> .components ,e) ,(symbolName componentType)) ".json")))
|
|
|
|
// Changes to the object returned by (readComponent) will not be saved! Use (withWritableComponents) for making changes
|
|
(defMacro readComponent [archive e componentType]
|
|
// TODO add to the documentation a hint that macros should use fully qualified type paths so macro caller classes don't need to import everything
|
|
`(the nat.components ,componentType
|
|
(tink.Json.parse
|
|
(sys.io.File.getContent (_componentPath ,archive ,e ,componentType)))))
|
|
|
|
// Components have to be saved individually after writing because the Entity only knows their ids,
|
|
// not the data they contain. This is more ergonomically done by using (withWritableComponents...)
|
|
(defMacro writeComponent [archive e componentType c]
|
|
`(sys.io.File.saveContent
|
|
(_componentPath ,archive ,e ,componentType)
|
|
(tink.Json.stringify
|
|
(the nat.components ,componentType ,c))))
|
|
|
|
// TODO check not overwriting a component
|
|
(defMacro addComponent [archive e componentType c]
|
|
`(let [componentId (Uuid.v4)]
|
|
(dictSet .components ,e ,(symbolName componentType) componentId)
|
|
(writeComponent ,archive ,e ,componentType ,c)
|
|
,e))
|
|
|
|
// Retrieve multiple components from an Entity with mutable access.
|
|
// All components will be serialized after the block is done.
|
|
(defMacro withWritableComponents [archive e bindings &body body]
|
|
(let [bindingPairs
|
|
(groups (expList bindings) 2 Throw)
|
|
bindingList
|
|
[]
|
|
saveList
|
|
[]
|
|
retValSymbol
|
|
(symbol)]
|
|
(doFor [name type] bindingPairs
|
|
(bindingList.push `&mut ,name)
|
|
(bindingList.push `(readComponent ,archive ,e ,type))
|
|
(saveList.push `(writeComponent ,archive ,e ,type ,name)))
|
|
`(let [,@bindingList
|
|
,retValSymbol {,@body}]
|
|
,@saveList
|
|
,retValSymbol)))
|
|
|
|
(defMacro withWritableEntry [archive e &body body]
|
|
(let [retValSymbol
|
|
(symbol)]
|
|
`(let [,retValSymbol {,@body}]
|
|
(archive.refreshEntry ,e)
|
|
,retValSymbol)))
|
|
|
|
// Create a system that selects Entries according to a single string component (i.e. Name or Author) matching the given value
|
|
(defMacro stringComponentSystem [archive componentType value process]
|
|
`(new System
|
|
(lambda [archive :Entry e]
|
|
?(and (hasComponent e ,componentType)
|
|
(= ,value (readComponent ,archive e ,componentType))))
|
|
,process))
|
|
|
|
(function tagList [archive e]
|
|
(let [t
|
|
(readComponent archive e Tags)]
|
|
(collect (t.keys))))
|
|
|
|
(function tagsMatch [archive e tagsBoolExp]
|
|
(BoolExpInterp.eval tagsBoolExp (tagList archive e)))
|
|
|
|
(function componentsMatch [:nat.Entry e componentsBoolExp]
|
|
(BoolExpInterp.eval componentsBoolExp (for =>cType cId e.components cType)))
|