Skip to content
ryobg edited this page Feb 15, 2018 · 7 revisions

Overview

JC API is declared by the following:

  • Instanceable containers, an objects of: JArray, JMap, JFormMap, JIntMap. Instanceable means you can create multiple instances of arrays, maps and form-maps (i.e. the same way you can have multiple arrays and strings in Papyrus)
  • JValue - in the OOP world, we say that JArray, JMap, JFormMap and JIntMap are inheriting the JValue functionality.
  • Global containers - JDB and JFormDB. Unlike instanceable containers, there is only one instance of them so you do not have to create them (a.k.a. singletons - OOP remember).
  • Utility, JC installation validation - JContainers

Instanceable containers

To use any instanceable object, you must first create (instantiate) it with the object function or retrieve it from somewhere:

int array = JArray.object()
int map = JMap.object()
int anotherArray = JDB.solveObj(".myArray")

Any function that returns an object actually returns its identifier. An identifier is a unique number that ranges from -2^31 to +2^31. There is also the concept of zero identifier which points to a non-existing object. All containers are distinguished by their identifiers.

Once created, you may put data in the array or the map:

JArray.addStr(array, "it’s me")
JArray.addForm(array, GetTargetActor())
JMap.setInt(map, "health", GetTargetActor().getAV("health"))

And read the data back:

string text = JArray.getStr(array, 0)
form actor = JArray.getForm(array, 1)
int health = JMap.getInt(map, "health")

JArray

JArray is an ordered collection (array) of values. It is dynamically resizeable, and can store any number of values of any combination of types.

JMap, JFormMap and JIntMap

All of them are associative containers (sets of keys and values where each key is associated with one value). Each key must be unique within a given container. In a JMap, a key is a string, in a JFormMap it is a form (a form is any actor, item, quest, spell - almost everything in Skyrim) and in a JIntMap the key is, obviously, an integer value.

int map = JMap.object()
JMap.setForm(map, "me", GetTargetActor())
form actor = JMap.getForm(map, "me")

JValue

JValue is an interface that shows what common functionality JArray, JMap and JFormMap share. For example, each of them can be emptied, serialized and deserialized to/from JSON and more.

int array = JArray.object()
int map = JMap.object()
-- equivalent ways to do same things.
-- all count functions return zero as new containers are empty
JValue.count(array) == JArray.count(array) == JValue.count(map)
-- write container content into file:
JValue.writeToFile(map, "map.txt")
JValue.writeToFile(array, "array.txt")

JDB

JDB is a global entry point - you put information or some value in it under a string key , and then you can access the key and its value from any script in the game. There is only one JDB in the game (ie its singleton), so each time you access it you access that one, single JDB. It is also an associative container like JMap, but the script interface is slightly different.

Typical JDB usage would involve:

  • Put data into JDB using the following JDB functions: setObj or the solve*Setter functions
  • Read the data back using solve*Getter functions

Example of a JDB already filled by different users:

{
  "vMYC": {
    "characterCount": 11,
    "some-array": []
  },
  "SWPR": [],
}

Important

Choose your root key name carefully to avoid clashes with rest of JDB and JFormDB root keys used by other users (mod authors).

More examples:

JDB.solveIntSetter(".vMYC.characterCount", 11, true)
int count = JDB.solveInt(".vMYC.characterCount")
int property potionsArray
  int function get()
    return JDB.solveObj(".SWPR.deadlyPotions")
  endfunction
  function set(int object)
    JDB.solveObjSetter(".SWPR.deadlyPotions", object, true)
  endfunction
endproperty

JFormDB

Provides a convenient way to associate values with a form. You may find it looking like a mix of JMap and JDB - like JDB, there is only one JFormDB in the game, and like JMap it is associative container. It also supports path resolving. To store or retrieve value a form and string path must be passed:

-- store...
form me = GetTargetActor()
JFormDB.setFlt(me, ".yourModFormStorage.valueKey", 10)
JFormDB.setStr(me, ".yourModFormStorage.anotherValueKey", "name")
-- and retrieve values
float value = JFormDB.getFlt(me, ".yourModFormStorage.valueKey")

A string path must consist of formStorageName and valueKey.

  • valueKey is a key used to retrieve a value or create {valueKey, value} association for a form.
  • formStorageName is a JFormMap containing {formKey, {valueKey, value}} associations. It was added to avoid possible collisions: one mod may occasionally override value written by another mod if simple paths without storage name part were allowed. The fact that it is a separate storage makes it possible to access that storage, delete it without any risk to delete another mod data:
-- Will destroy everything "yourModFormStorage" contains
JDB.setObj("formStorageName", 0)

How the set* functions work internally:

Once a value gets assigned via JFormDB.set*(formKey, ".formStorageName.valueKey", value), JFormDB looks for formStorageName in JDB (creating it if not found) and then looks for the JMap entry associated with that form key (creating it if not found) and then creates a {valueKey, value} pair.

Slightly more advanced usage:

-- Will destroy everything associated with 'me' form in "yourModFormStorage" storage
JFormDB.setEntry("yourModFormStorage", me, 0)
 
-- Custom entry type
JFormDB.setEntry("yourModFormStorage", me, JArray.object())