{
  "_args": [
    [
      {
        "raw": "github:meishuu/tera-proxy-game",
        "scope": null,
        "escapedName": null,
        "name": null,
        "rawSpec": "github:meishuu/tera-proxy-game",
        "spec": "github:meishuu/tera-proxy-game",
        "type": "hosted",
        "hosted": {
          "type": "github",
          "ssh": "git@github.com:meishuu/tera-proxy-game.git",
          "sshUrl": "git+ssh://git@github.com/meishuu/tera-proxy-game.git",
          "httpsUrl": "git+https://github.com/meishuu/tera-proxy-game.git",
          "gitUrl": "git://github.com/meishuu/tera-proxy-game.git",
          "shortcut": "github:meishuu/tera-proxy-game",
          "directUrl": "https://raw.githubusercontent.com/meishuu/tera-proxy-game/master/package.json"
        }
      },
      "C:\\Users\\YarNova\\Local Apps\\tera-proxy"
    ]
  ],
  "_from": "meishuu/tera-proxy-game",
  "_id": "tera-proxy-game@1.0.0",
  "_inCache": true,
  "_location": "/tera-proxy-game",
  "_phantomChildren": {},
  "_requested": {
    "raw": "github:meishuu/tera-proxy-game",
    "scope": null,
    "escapedName": null,
    "name": null,
    "rawSpec": "github:meishuu/tera-proxy-game",
    "spec": "github:meishuu/tera-proxy-game",
    "type": "hosted",
    "hosted": {
      "type": "github",
      "ssh": "git@github.com:meishuu/tera-proxy-game.git",
      "sshUrl": "git+ssh://git@github.com/meishuu/tera-proxy-game.git",
      "httpsUrl": "git+https://github.com/meishuu/tera-proxy-game.git",
      "gitUrl": "git://github.com/meishuu/tera-proxy-game.git",
      "shortcut": "github:meishuu/tera-proxy-game",
      "directUrl": "https://raw.githubusercontent.com/meishuu/tera-proxy-game/master/package.json"
    }
  },
  "_requiredBy": [
    "#USER",
    "/"
  ],
  "_resolved": "git://github.com/meishuu/tera-proxy-game.git#9852265f656f8c77cc7d09fc839b7fc9df19da88",
  "_shasum": "56c1e7889f5dfd608d2d7f65c0aa4966c977cd73",
  "_shrinkwrap": null,
  "_spec": "github:meishuu/tera-proxy-game",
  "_where": "C:\\Users\\YarNova\\Local Apps\\tera-proxy",
  "author": {
    "name": "meishu"
  },
  "bugs": {
    "url": "https://github.com/meishuu/tera-proxy-game/issues"
  },
  "dependencies": {
    "binary-search": "^1.3.2",
    "error-stack-parser": "^2.0.0",
    "tera-data-parser": "github:meishuu/tera-data-parser-js"
  },
  "description": "Modular event handling through a TERA proxy server.",
  "devDependencies": {
    "eslint": "^3.8.1",
    "eslint-config-google": "^0.7.0"
  },
  "engines": {
    "node": ">=6.0.0"
  },
  "gitHead": "9852265f656f8c77cc7d09fc839b7fc9df19da88",
  "homepage": "https://github.com/meishuu/tera-proxy-game#readme",
  "license": "GPL-3.0",
  "main": "lib/index.js",
  "name": "tera-proxy-game",
  "optionalDependencies": {},
  "peerDependencies": {
    "tera-data": "*"
  },
  "readme": "# tera-proxy-game\n\nHosts a TCP proxy server to read, modify, and inject network data between a TERA game client and server.\nModular system built on event-based hooks allows for easy creation and usage of script mods.\n\n## Example\n```coffeescript\nGameProxy = require 'game'\n\nserver = GameProxy.createServer { host: '208.67.49.92', port: 10001 },\n  (dispatch) -> dispatch.load 'logger'\n\nserver.listen 9247, '127.0.0.1', ->\n  address = server.address()\n  console.log 'listening on %s:%d', address.address, address.port\n```\n\n## Building a Module\n\nA module loaded through `dispatch.load(name)` is instantiated similarly to:\n\n```coffeescript\nmodule = require name\nmodules[name] = new module dispatch\n```\n\nThus, a loadable module's export must be a function. Since this function is called with `new`,\nthe context of `this` will be unique to each connection to the proxy.\n\nAs an example of a simple module, we can set up a hook on `sSpawnUser` to turn everyone else into an elin:\n\n```coffeescript\nmodule.exports = (dispatch) ->\n  # set up a pre hook\n  dispatch.hook 'sSpawnUser', (event) ->\n    # calculate the user's class from the model\n    job = (event.model - 10101) % 100\n    \n    # if the user is a gunner (9) or brawler (10),\n    if job > 8\n      # don't do anything\n      return\n\n    # calculate the user's race from the model\n    race = (event.model - 10101) // 100\n    \n    # modify the model \n    event.model += (9 - race) * 100\n    \n    # return\n    true # marks the event object as having changed\n```\n\nFor a slightly more complex example, we can make a module that replaces the string `{me}` in\nchat messages with the name of the character being played.\n\n```coffeescript\n# export a class rather than a simple function as an example\nmodule.exports = class Me\n  # set up hooks in the constructor\n  constructor: (dispatch) ->\n    # initialize properties\n    @name = ''\n\n    # hook sLogin to save character name\n    dispatch.hook 'sLogin', @onLogin.bind @\n    \n    # hook cChat and cWhisper to replace \"{me}\"\n    dispatch.hook 'cChat', @onChat.bind @\n    dispatch.hook 'cWhisper', @onChat.bind @\n\n  # method used as event handler for sLogin\n  onLogin: (event) ->\n    # save character name\n    @name = event.name\n\n    # explicit return ensures that this hook will not cause the message to be\n    # dropped or reconstructed\n    return\n\n  # method used as event handler for cChat and cWhisper\n  onChat: (event) ->\n    # replace {me} with the name of our character (from object property)\n    message = event.message.replace /\\{me\\}/g, @name\n    \n    # if the message changed,\n    if message isnt event.message\n      # save the new value in the event object\n      event.message = message\n\n      # return value of true will flag the event object as modified\n      true # this will cause the message to be reconstructed\n```\n\n## The Protocol\n\nThe `def/` directory holds all the definitions for messages, including a mapping of message names to opcodes in `_map.def`.\nGenerally, `_map.def` will need to be updated on every major version bump of TERA. One method of easily accomplishing this\nis written in [GoneUp's Tera Packet Viewer](https://github.com/GoneUp/Tera_PacketViewer/blob/Dev/Opcode%20DLL/README.txt).\nNote that the official message names are converted to camel case, e.g., `S_SPAWN_USER` becomes `sSpawnUser` here.\n\nAll other `.def` files must be named after a message and contain a list of field type and name information. This is used\nto both parse the raw network data into a JavaScript object and convert said object back into a buffer. As an example from\n`sGuildHistory`:\n\n```\ncount  events\noffset events\n\nint32 page\nint32 pages\narray events\n- offset initiator\n- offset description\n- int64  date\n- int32  event\n- string initiator\n- string description\n```\n\nA line must consist of:\n * An optional series of `-` for array definitions. These may be separated by spaces.\n   To nest arrays, just add one more `-` to the front.\n * A field type. Valid types listed below.\n * At least one space.\n * A field name to be used for the resulting JavaScript object.\n\nA `#` and anything after it on the line are comments and will be ignored when parsing.\n\nThe following field types are supported:\n\n * `array`: Converts to a JavaScript array. Both `count` and `offset` metatypes are required for this field.\n   This implicitly includes an `offset here` and an `offset next` at the beginning of each array item.\n * `byte`: A single byte. Also used for booleans.\n * `bytes`: Converts to a [Node `Buffer`](https://nodejs.org/api/buffer.html).\n   Both `count` and `offset` metatypes are required for this field.\n * `count`, `offset`: Synonymous with `uint16`. `count` dictates the length of an `array` or `bytes` field, while\n   `offset` indicates the byte offset from the beginning of the message for `array`, `bytes`, and `string`.\n * `int16`, `uint16`, `int32`, `uint32`, `float`: Self-explanatory.\n * `int64`, `uint64`: Converts to an `Int64` object; see below.\n * `string`: Reads a sequence of `uint16`, ending when `NUL` (`0x0000`) is encountered. Converts to a normal JavaScript string.\n   `offset` is required for this field.\n\nSince JavaScript only supports numbers to 53 bits of precision, an `Int64` object must be used for 64-bit integers.\nIt contains the properties `low` and `high` as well as an `equals()` method to compare against other `Int64`s.\n\n## API Reference\n\n### `Dispatch`\n\nAn instance of `Dispatch` is created for every connection to the proxy game server.\n\n * `hook(name, [type], cb)`\n * `unhook(name, [type], cb)`\n\nAdds or removes a hook for a message.\n\n`name` will usually be the name of the message being watched for, but it can also be `\"*\"` to catch all messages.\nIf `\"*\"` is used, then `type` is forced to `\"raw\"`.\n\n`type` defaults to `\"pre\"` for a pre-hook, which will pass the parsed message data as an argument to `cb`.\n`type` can also be `\"raw\"`, in which case a `Buffer` containing the raw message data will be passed instead.\nIf `name` is `\"*\"`, this will always be `\"raw\"`.\n\n`cb` receives:\n * For a `pre` hook,\n   * `event`: The `Object` of the parsed message data.\n   * Return value is `true` if `event` is modified, or `false` to stop and silence the message.\n     Other return values are ignored.\n * For a `raw` hook,\n   * `code`: The opcode of the message as an integer.\n   * `data`: The `Buffer` of the raw message data.\n   * `fromServer`: `true` if the message was sent by the server, `false` otherwise.\n   * Return value is a `Buffer` of the modified message data to use, or `false` to stop and silence the message.\n     Other return values are ignored.\n\nWhen a hooked message is received, `Dispatch` performs the following sequence of actions:\n\n 1. Run all `*` hooks.\n    * If a `Buffer` is returned, use it as the new data buffer.\n    * If `false` is returned, exit immediately and do not forward the message.\n    * Otherwise, keep executing hooks.\n 2. Run all `raw` hooks. Return values are interpreted the same as above.\n 3. If there are any `pre` hooks, parse the message data into an object and then run all `pre` hooks.\n    * If `true` is returned, the hook is signifying that it has modified the event object and\n      it will need to be repacked into a `Buffer` when all hooks have been called.\n    * If `false` is returned, exit immediately and do not forward the message.\n    * Otherwise, keep executing hooks.\n 4. Reconstruct the message data if necessary, and forward it to the intended recipient.\n\nNote that if a `pre` hook changes the event object but no `pre` hook returns `true`, the changes will not\nbe saved because `Dispatch` will not know to reconstruct the message.\n\n * `toClient(buffer)`\n * `toClient(name, data)`\n * `toServer(buffer)`\n * `toServer(name, data)`\n\nConstructs and sends a packet to either the TERA client or server.\n\nIf `buffer` is used, it will simply be sent as-is (before encryption).\n\nIf `data` is used, `name` must be the message name.\n\n * `load(name, [from])`\n\nLoad the module referenced by `name` using `from.require()`. You will likely want to pass the `module`\nfrom the calling context in order to emulate a `require()` from there; otherwise, it will default to\nloading the module as if `require()` were called from inside `dispatch.coffee`. See the\n[module.require documentation](https://nodejs.org/api/modules.html#modules_module_require_id) for more\ndetails.\n\nReturns `true` if successful, `false` otherwise.\n\n * `unload(name)`\n\nUnloads the module referenced by `name`, calling the `destructor()` method on the module if it exists.\nThis does not automatically remove hooks, which should be done in `destructor()`.\n\nReturns `true` if successful, `false` otherwise.\n\n * `close()`\n\nUnloads all modules and removes all hooks.\n",
  "readmeFilename": "README.md",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/meishuu/tera-proxy-game.git"
  },
  "scripts": {
    "lint": "eslint ."
  },
  "version": "1.0.0"
}
