Importing
library is an additional library for TERA modules. Its folder must be named library, not library-master. Declare it as a dependency in module.json; access the interface through mod.require.library.
module.exports = function LibraryExample(mod) {
const lib = mod.require.library;
mod.command.add('lib-position', () => {
if (!mod.game.isIngame) return;
mod.command.message(JSON.stringify(lib.player.loc));
});
};
Public components are entity, player, effect, packet and library. mods contains references to loaded components. Call utilities through lib.library, for example lib.library.dist3D(a, b). lib.command and lib.cmd reference the command interface.
Entity
lib.entity maintains players, mobs, npcs, unknown and entities objects indexed by gameId. State is cleared on zone loading; check that an entry exists before using it.
Entries in players/mobs/npcs/unknown expose pos with x/y/z/w coordinates/direction, info.huntingZoneId, info.templateId, name, job and race. The entities collection contains instances of the newer Entity class: huntingZoneId and templateId are direct properties and getLocation() retrieves the position. That class's info and loc getters throw; do not mix the two entry formats.
The historical README describes appearance aliases outfit, app, apperance, appearance and fields weapon, body, hand, feet, underwear, head, face, styleHead, styleFace, styleBack, styleWeapon, styleBody, styleFootprint, styleBodyDye, bodyDye. The inspected implementation does not populate those aliases: do not treat them as an available API for new development.
| Method | Result |
|---|---|
getLocationForThisEntity(id) |
Position from a matching collection, or undefined |
getLocationForPlayer(id) |
Player position; the entry must exist |
getLocationForMob(id), getLocationForNpc(id) |
Mob/NPC position; the entry must exist |
getEntityData(id) |
Entity data from the collections |
getEntitiesData(huntingZoneId, templateId) |
Entities matching the template |
isNearEntity(pos, playerRadius = 50, entityRadius = 50) |
Check players and the mobs collection |
isNearPlayer(...), isNearBoss(...) |
The same checks for players/mobs separately |
getSettingsForEntity(id, object) |
object[huntingZoneId][templateId] for an existing entity |
Despite its name, isNearBoss iterates over mobs. Proximity uses positionsIntersect, whose geometry is described below; it is not a universal point-within-radius test.
Player
lib.player.isMe(gameId) checks the current character. Main properties:
| Properties | Meaning |
|---|---|
serverId, playerId, templateId, gameId, name, level |
Identifiers and character data |
race, job |
Numeric values derived from templateId, unlike mod.game.me strings |
onMount, alive, onPegasus, inCombat |
Character state |
loc, pos |
Coordinates, direction w, update timestamp updated |
moving, zone, channel |
Movement, zone and channel |
inven |
weapon, effects, crystals, equipment |
stamina, health, maxHealth, mana, maxMana |
Stats after updates |
attackSpeed, attackSpeedBonus, aspdDivider, aspd |
Attack speed values and calculated factor |
playersInParty, partyLeader |
Party information |
race = Math.floor((templateId - 10101) / 100) and job = (templateId - 10101) % 100. Player appearance aliases from the older README are also absent from the inspected implementation. Do not assume other properties are populated before their game packets arrive.
Effect
lib.effect stores abnormals, glyphs and permanentBuffs as ID → state objects. hasAbnormality(id), hasGlyph(id) and hasBuff(id) test === true. hasEffect(id) returns the first truthy state from the three stores; absent entries can produce undefined, so use it as a condition rather than expecting literal false.
getAbnormalities(), getGlyphs() and getBuffs() return the actual stores, not copies. Expired effects may leave keys with false values: check the value rather than key existence. State resets on S_LOGIN.
Coordinates and skills
Methods of lib.library:
| Method | Behavior |
|---|---|
dist2D(a, b), dist3D(a, b) |
Distances |
applyDistance(loc, distance) |
Mutates x/y along loc.w in radians and returns the same object |
positionsIntersect(a, b, aRadius, bRadius) |
Tests (aRadius-bRadius)² <= distanceXY² <= (aRadius+bRadius)² |
fromAngle(w), toAngle(w) |
Radians to the 16-bit angle scale and back |
getSkillInfo(id, usingMask = true, bossSkill = false) |
Decodes a legacy numeric skill ID |
positionsIntersect ignores Z and excludes complete containment when radii differ. For “within R”, use dist2D <= R or Vec3.sqrDist2D.
getSkillInfo returns raw, id, skill, sub and level; methods setValues, getBaseId(skill = 1, level = 1, sub = 0) and setValuesTo(skill, level, sub) update/construct the numeric form. This legacy format using mask 0x4000000 does not replace the modern parser's skillid object.
Packets and DataCenter
lib.packet chooses definitions using an internal patch table. The library uses lib.packet.get_all(name) to return arguments for mod.hook(...result, callback). This is a compatibility table for the installed library version, not automatic support for every server.
| lib.library method | Purpose |
|---|---|
getEvent(opcode, version, payload) |
Parse a Buffer through Dispatch.fromRaw |
getPayload(opcode, version, data) |
Serialize through Dispatch.toRaw |
getPacketInformation(identifier) |
Resolve a definition |
parseSystemMessage(message), buildSystemMessage(message) |
System-message API wrappers |
query(query, ...args) |
queryData wrapper; findAll depends on whether arguments exist |
queryM(queries) |
Sequentially run [query, ...args] arrays and concatenate results |
queryF(query, concat = true, findAll = true, children = true, attributeFilter = null) |
Parameterless query with optional node merging |
getQueryEntry(queryData, path, ...argsData) |
Search an already retrieved tree |
For predictable result control in new code, prefer direct mod.queryData. version/protocolVersion on lib.library refer to the network protocol, not the npm package version; command is the command interface and sp is the result of an attempt to detect Skill Prediction.
Utilities
| lib.library method | Behavior |
|---|---|
arraysItemInArray(a, b) |
Whether any element of a occurs in b; the README used a different spelling |
jsonEqual(a, b) |
Compares JSON.stringify output; key order matters |
objectLength(obj) |
Number of own enumerable keys |
getRandomInt(min, max) |
Integer including min, excluding max |
jsonStringify(data, spaces), parseJson(data) |
JSON with custom BI/- string encoding for BigInt |
saveFile(filePath, data, dirname) |
Synchronous write; objects use ordinary JSON.stringify |
readFile(dirname, filePath) |
Synchronous read returning a Buffer |
print(...args) |
Diagnostic output using util.inspect |
Explicitly pass your module directory for file operations: saveFile defaults to a directory inside the library itself. Ordinary JSON.stringify does not support BigInt; the library's custom encoding differs from Toolbox settings encoding.
Inheritance and deprecated API
You can directly import a class for specialized inheritance, but this couples your module to library internals. In the current version Player, like Entity, uses the second mods argument; the old super(mod) example is insufficient.
const Player = require('../library/class/player');
class CustomPlayer extends Player {
constructor(mod, mods) {
super(mod, mods);
}
}
module.exports = CustomPlayer;
Additional instances register their own hooks. Usually the existing lib.player is sufficient. emptyLong() and long() throw in the current implementation: use BigInt. opositeDirection (with that spelling) and getDirectionTo are deprecated and log warnings. startSkillsPackets from the README is absent from current class/library.js; do not depend on it.
Sources: mods/library/README.md, mods/library/index.js, mods/library/class/{library,entity,player,effect,packet}.js.