Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Build plugins for Superpowers
- - [api](#api)
- - [data](#data)
- - [runtime](#runtime)
- - [editors](#editors)
- - [settingsEditors](#settingseditors)
- - [components](#components)
- - [componentEditors](#componenteditors)
- <a name="api"></a>
- ## API
- The api folder contains the typescript code that is accessible by the projects scripts in the client and (if needed) during the runtime.
- It typically contains 3 files
- - `index.js` where you register the plugin.
- - `MyPlugin.ts` contains the typescript code (typically a module).
- - `MyPlugin.d.ts` contains the definitions.
- For some examples, check out my `fLang` or `fTween` plugins, for instance.
- The `export` keyword in the code is important.
- If you omit it, it's like the var, function, class or interface doesn't exist if you try to access it from the project's scripts.
- If your module needs to be accessed during runtime too (when the game runs), you need to expose the module to the `window` variable like so :
- (<any>window).MyModule = MyModule;
- The definitions are not technically mandatory but you won't be able to do much without them.
- They defines what exists in the eye of the compiler, and are used to build the autocompletion information, so the definitions typically match the content exported by the code.
- Definitions are also what is shown by the Typescript API browser.
- ### Registering an api plugin
- The content of an `index.js` typically looks like this:
- var fs = require("fs");
- SupAPI.registerPlugin("typescript", "fLang", {
- code: fs.readFileSync(__dirname + "/fLang.ts", { encoding: "utf8" }).replace("reference path", "_reference path"),
- defs: fs.readFileSync(__dirname + "/fLang.d.ts", { encoding: "utf8" })
- });
- The first argument is the context (the scripting language you want to expose the api to). Leave `typescript`.
- The second argument is the plugin's name, the one that appears in the Typescript API bowser.
- The third argument is an object with a `code` and a `defs` properties.
- Here we use `fs.readFileSync(__dirname + "/[path to file]", { encoding: "utf8" })` to read the .ts and .d.ts files.
- ### Exposing a JS library
- When you want to expose a JS library, you need to get its definition files, usually from [the DefinitelyTyped repo](https://github.com/borisyankov/DefinitelyTyped), or write it yourself.
- Yo don't have to do anything for the code, except declare the main module name
- var fs = require("fs");
- SupAPI.registerPlugin("typescript", "FTWEEN", {
- code: "declare var FTWEEN;",
- defs: fs.readFileSync(__dirname + "/../lib/ftween.d.ts", { encoding: "utf8" })
- });
- You can see here I wrote code directly in the index files but also decided to put the definition files elsewhere than the api folder.
- This expose the library to Superpowers client only, another step is required to expose the library to the runtime.
- This will be done from the runtime folder.
- ---
- <a name="data"></a>
- ## Data
- The data folder contains the assets, resources and component config classes.
- Assets are the main components of the games, are created/modified via an __editor__ in Sup's client.
- They are composed of a main asset.json file, plus other files as needed.
- They can be found in the project's asset folder ("assets/[asset id]/asset.json").
- Resources are used for storing settings (like global editor parameters or assets default parameters).
- They are modified via __settings editors__ accessed through the Settings tool (Sparklinlabs's Settings plugin).
- They are composed of a single resource.json file and are found in the project's resources folder ("resources/[resource name]/resource.json")
- Component config ??
- See the Sprite plugin for an example of those classes.
- ### Resource
- From an asset class, resources can be accessed via the serverData property.
- Ie (from the SpriteAsset.ts) :
- // called when the asset is created via Sup's client
- init(options: any, callback: Function) {
- this.serverData.resources.acquire("spriteSettings", null, (err: Error, spriteSettings: any) => {
- // this.pub is the asset's data
- // most of which is saved in the asset.json file (but that depends on how it's done in asset's save() method)
- // spriteSettings.pub is the resource data
- this.pub = {
- image: new Buffer(0),
- filtering: spriteSettings.pub.filtering,
- pixelsPerUnit: spriteSettings.pub.pixelsPerUnit,
- framesPerSecond: spriteSettings.pub.framesPerSecond,
- alphaTest: spriteSettings.pub.alphaTest,
- grid: { width: 100, height: 100 },
- origin: { x: 0.5, y: 0.5 },
- animations: []
- };
- this.serverData.resources.release("spriteSettings", null);
- super.init(options, callback);
- });
- }
- From an asset editor (or a settings editor class), a resource can be accessed by subscribing to it through projectClient:
- Ie (from the Scene editor):
- function onConnected() {
- data = { projectClient: new SupClient.ProjectClient(socket, { subEntries: true }) };
- data.projectClient.subResource("sceneSettings", sceneSettingSubscriber);
- }
- var sceneSettingSubscriber = {
- onResourceReceived: (resourceId: string, resource: SceneSettingsResource) => {
- setCameraMode(resource.pub.defaultCameraMode);
- // the resource object can also be stored for later use
- },
- onResourceEdited: (resourceId: string, command: string, propertyName: string) => {
- // do stuff if needed
- }
- }
- ### Registering
- In the data's index file (Example from the sprite plugin) :
- import SpriteSettingsResource from "./SpriteSettingsResource";
- import SpriteAsset from "./SpriteAsset";
- import SpriteRendererConfig from "./SpriteRendererConfig";
- SupCore.data.registerResource("spriteSettings", SpriteSettingsResource);
- SupCore.data.registerAssetClass("sprite", SpriteAsset);
- // note that the first argument here is the asset's type
- SupCore.data.registerComponentConfigClass("SpriteRenderer", SpriteRendererConfig);
- ---
- <a name="runtime"></a>
- ## Runtime
- The runtime folder contains an index file too, and other files as needed.
- These files may contain some of theses functions:
- Note :
- - all code shown below is Typescript
- - See `app/system/SupRuntime/SupRuntime.d.ts` for the definitions of `SupRuntime.Player`.
- #### init(player: SupRuntime.Player, callback: Function)
- #### start(player: SupRuntime.Player, callback: Function)
- Both are called when the game launches.
- The callback method needs to be called at the end.
- #### loadAsset(player: SupRuntime.Player, entry: any, callback: (err: Error, asset?: any) => any)
- Allow to load any files in the asset folder.
- Called once per asset of type introduced by the plugin.
- The callback needs to be called at some point too.
- Ie:
- export function loadAsset(player: SupRuntime.Player, entry: any, callback: (err: Error, asset?: any) => any) {
- // can access :
- // entry.id, entry.name
- // how to read a file in the asset's folder:
- player.getAssetData(`assets/${entry.id}/script.txt`, "text", (err, data) => {
- // data is a string (the text content of a script for instance)
- callback(null, script);
- });
- player.getAssetData(`assets/${entry.id}/asset.json`, "json", (err, data) => {
- // data is a JS object, the asset parameters
- callback(null, data);
- });
- // can be as simple as :
- // if you don' need to do stuff with the asset's data at this point
- player.getAssetData(`assets/${entry.id}/asset.json`, "json", callback);
- }
- #### createOuterAsset(player: SupRuntime.Player, asset: any)
- Ie (from the scene plugin) :
- export function createOuterAsset(player: SupRuntime.Player, asset: any) {
- return new (<any>window).Sup.Scene(asset);
- }
- #### setupComponent(player: SupRuntime.Player, component: any, config: any)
- Do stuff with components (like get a resource then apply the info to the components).
- #### loadResource(player: SupRuntime.Player, resourceName: string, callback: (err: Error, resource?: any) => any)
- Ie (similar to assets) :
- export function loadResource(player: SupRuntime.Player, resourceName: string, callback: (err: Error, resource?: any) => any) {
- player.getAssetData(`resources/${resourceName}/resource.json`, "json", (err, data) => {
- if (err != null) { callback(err); return; }
- // do stuff if needed
- callback(null, data);
- });
- }
- For these functions to be called, you need to register plugins and resources to the SupRuntime object:
- Ie (from typescript plugin) :
- import * as script from "./script"; // contains init), start(), loadAsset()
- import * as Behavior from "./Behavior"; // contains setupComponent()
- import * as behaviorProperties from "./behaviorProperties"; // contains loadResource()
- SupRuntime.registerPlugin("script", script);
- SupRuntime.registerPlugin("Behavior", Behavior);
- SupRuntime.registerResource("behaviorProperties", behaviorProperties);
- ### Expose a JS library
- Just require the library and expose it to the window variable;
- Ie (from the fTween plugin) :
- window.FTWEEN = require("../lib/ftween.js");
- ### Register an early update functions
- This is a way to have a function runs every frame (before the scripts update() functions) :
- Ie (from the fTween plugin) :
- SupEngine.registerEarlyUpdateFunction("fTween", function() {
- window.FTWEEN.update();
- });
- ---
- <a name="editors"></a>
- ## Editors
- The editors folder contains sub-folders which contains the assets editors.
- The sub-folders must be named after the asset's type (the first argument of SupCore.data.registerAssetClass()).
- An asset editor is a standard webpage so the folder typically contains one html, css and js files.
- Each editor's folders inside the public folder may in addition contains an icon.svg file as well as a locale folder.
- ---
- <a name="settingseditors"></a>
- ## SettingsEditors
- Settings Editor classes are used to build the editors to update resources through the Settings tool (provided by the Settings plugin).
- Example of a minimal class, to edit a single param:
- import SpriteSettingsResource from "../data/SpriteSettingsResource";
- export default class SpriteSettingsEditor {
- projectClient: SupClient.ProjectClient;
- resource: SpriteSettingsResource;
- filteringRow: SupClient.table.RowParts;
- // define other row properties here
- fields: { [name: string]: HTMLInputElement|HTMLSelectElement } = {};
- constructor(container: HTMLDivElement, projectClient: SupClient.ProjectClient) {
- this.projectClient = projectClient;
- let { tbody } = SupClient.table.createTable(container);
- // start appending rows to the table
- this.filteringRow = SupClient.table.appendRow(tbody, "Filtering");
- this.fields["filtering"] = SupClient.table.appendSelectBox(this.filteringRow.valueCell, { pixelated: "Pixelated", smooth: "Smooth" });
- // append other rows here...
- // check app/SupClient/SupClient.d.ts for type of fields other than select box
- // set the chenge event listener here
- this.fields["filtering"].addEventListener("change", (event: any) => {
- this.projectClient.socket.emit("edit:resources", "spriteSettings", "setProperty", "filtering", event.target.value, (err: string) => { if (err != null) alert(err); });
- });
- // do the same for other rows...
- this.projectClient.subResource("spriteSettings", this);
- }
- onResourceReceived = (resourceId: string, resource: SpriteSettingsResource) => {
- this.resource = resource;
- for (let setting in resource.pub) {
- this.fields[setting].value = resource.pub[setting];
- }
- }
- onResourceEdited = (resourceId: string, command: string, propertyName: string) => {
- this.fields[propertyName].value = this.resource.pub[propertyName];
- }
- }
- In this case, the Ressorce class (in the data folder) would look like this:
- export default class SpriteSettingsResource extends SupCore.data.base.Resource {
- static schema = {
- filtering: { type: "enum", items: [ "pixelated", "smooth" ], mutable: true },
- // other fields here...
- // ie:
- // alphaTest: { type: "number", min: 0, max: 1, mutable: true }
- }
- constructor(pub: any, serverData: any) {
- super(pub, SpriteSettingsResource.schema, serverData);
- }
- setup() {}
- init(callback: Function) {
- this.pub = {
- filtering: "pixelated",
- // other default values here...
- // alphaTest: 0.1
- };
- super.init(callback);
- }
- }
- ### Registering
- Ie:
- import SpriteSettingsEditor from "./SpriteSettingsEditor";
- SupClient.registerSettingsEditorClass("Sprite", SpriteSettingsEditor);
- // the first argument is the name of the editor as displayed in the tool
- ---
- ## Components
- ---
- ## ComponentEditors
Advertisement
Add Comment
Please, Sign In to add comment