├── .classpath ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .project ├── .travis.yml ├── README.md ├── build.local.properties.sample ├── build.properties ├── build.xml ├── contributing.md ├── docs ├── API-Reference.md ├── Anatomy-of-a-Plugin.md ├── Frequently-Asked-Questions.md ├── Using-Java-APIs-In-Javascript.md ├── YoungPersonsGuideToProgrammingMinecraft.md └── img │ ├── arcex1.png │ ├── blocktype1.png │ ├── box0ex1.png │ ├── boxaex1.png │ ├── boxex1.png │ ├── castleex1.png │ ├── chessboardex1.png │ ├── cornerstone1.png │ ├── cottageex1.png │ ├── cottageroadex1.png │ ├── cowclicker.png │ ├── cylinder0ex1.png │ ├── cylinderex1.png │ ├── dancefloorex1.png │ ├── door2ex1.png │ ├── doorex1.png │ ├── firework.png │ ├── fortex1.png │ ├── gardenex1.png │ ├── hemisphereex1.png │ ├── hemisphereex2.png │ ├── lcdclockex1.png │ ├── mazeex1.png │ ├── prismex1.png │ ├── rainbowex1.png │ ├── scriptcraft-chat-color.png │ ├── signex1.png │ ├── signex2.png │ ├── skyscraper.png │ ├── skyscraper_floor.png │ ├── sphereex1.png │ ├── spiralstair1.png │ ├── templeex1.png │ ├── times-trees.png │ ├── treeex1.png │ ├── ypgpm_2boxes.png │ ├── ypgpm_3dshapes.jpg │ ├── ypgpm_datavalues.png │ ├── ypgpm_echo_date.png │ ├── ypgpm_ex_dwell.png │ ├── ypgpm_greet.png │ ├── ypgpm_mc_cr.png │ └── ypgpm_whd.jpg ├── lib ├── .gitignore ├── canarymod-1.8.0.jar └── spigot-api-1.13.2-R0.1-SNAPSHOT-shaded.jar ├── license.txt ├── release-notes.md ├── screenshots ├── 2012-12-27_13.25.06.png ├── 2012-12-28_13.38.07.png ├── 2012-12-28_23.04.33.png ├── blocktype-example.png ├── castles-interlocking.png ├── forts-castles.png └── temple.png ├── src ├── .prettierrc ├── docs │ ├── java │ │ └── jscript.java │ ├── js │ │ ├── generateApiDocs.js │ │ ├── generateEntitiesDocBukkit.js │ │ ├── generateEventsHelper.js │ │ ├── generateItemsDocBukkit.js │ │ ├── generateItemsDocCanary.js │ │ ├── generateSoundsDocBukkit.js │ │ ├── generateSoundsDocCanary.js │ │ └── generateTOC.js │ └── templates │ │ └── ypgpm.md └── main │ ├── java │ ├── bukkit │ │ └── org │ │ │ └── scriptcraftjs │ │ │ └── bukkit │ │ │ └── ScriptCraftPlugin.java │ └── canary │ │ └── org │ │ └── scriptcraftjs │ │ └── canarymod │ │ └── ScriptCraftPlugin.java │ ├── js │ ├── .prettierrc~ │ ├── lib │ │ ├── .gitignore │ │ ├── command.js │ │ ├── console.js │ │ ├── events-bukkit.js │ │ ├── events-canary.js │ │ ├── events.js │ │ ├── find.js │ │ ├── java-utils.js │ │ ├── js-patch.js │ │ ├── legacy-check.js │ │ ├── persistence.js │ │ ├── plugin.js │ │ ├── readme.md │ │ ├── require.js │ │ ├── scriptcraft.js │ │ ├── tabcomplete-jsp.js │ │ ├── tabcomplete.js │ │ ├── task-bukkit.js │ │ └── task-canary.js │ ├── modules │ │ ├── at.js │ │ ├── babel-register.js │ │ ├── block-colors.js │ │ ├── blockhelper.js │ │ ├── blocks.js │ │ ├── bukkit │ │ │ ├── fireworks.js │ │ │ ├── input.js │ │ │ ├── inventory.js │ │ │ ├── items.js │ │ │ ├── recipes.js │ │ │ └── sounds.js │ │ ├── canary │ │ │ ├── fireworks.js │ │ │ ├── input.js │ │ │ ├── inventory.js │ │ │ ├── items.js │ │ │ ├── recipes.js │ │ │ └── sounds.js │ │ ├── classroom │ │ │ └── index.js │ │ ├── drone │ │ │ ├── arc.js │ │ │ ├── bed.js │ │ │ ├── blocktype.js │ │ │ ├── copypaste.js │ │ │ ├── cylinders.js │ │ │ ├── doors.js │ │ │ ├── firework.js │ │ │ ├── garden.js │ │ │ ├── index.js │ │ │ ├── ladder.js │ │ │ ├── movement.js │ │ │ ├── prism.js │ │ │ ├── rand.js │ │ │ ├── sign.js │ │ │ ├── sphere.js │ │ │ ├── stairs.js │ │ │ ├── test.js │ │ │ └── trees.js │ │ ├── entities.js │ │ ├── fireworks.js │ │ ├── http │ │ │ ├── package.json │ │ │ └── request.js │ │ ├── input.js │ │ ├── inventory │ │ │ └── index.js │ │ ├── items.js │ │ ├── lightning.js │ │ ├── minigames │ │ │ └── scoreboard.js │ │ ├── recipes.js │ │ ├── sc-mqtt.js │ │ ├── signs │ │ │ ├── menu.js │ │ │ ├── package.json │ │ │ └── signs.js │ │ ├── slash.js │ │ ├── sounds.js │ │ ├── spawn.js │ │ ├── teleport.js │ │ ├── utils │ │ │ ├── package.json │ │ │ ├── string-exts.js │ │ │ └── utils.js │ │ └── watcher.js │ ├── plugins │ │ ├── alias │ │ │ └── alias.js │ │ ├── arrows.js │ │ ├── at.js │ │ ├── classroom.js │ │ ├── commando │ │ │ ├── commando-test.js │ │ │ └── commando.js │ │ ├── drone │ │ │ ├── contrib │ │ │ │ ├── castle.js │ │ │ │ ├── chessboard.js │ │ │ │ ├── cottage.js │ │ │ │ ├── dancefloor.js │ │ │ │ ├── fort.js │ │ │ │ ├── hangtorch.js │ │ │ │ ├── lcd-clock.js │ │ │ │ ├── logo.js │ │ │ │ ├── mazegen.js │ │ │ │ ├── rainbow.js │ │ │ │ ├── redstonewire.js │ │ │ │ ├── spawn.js │ │ │ │ ├── spiral_stairs.js │ │ │ │ └── temple.js │ │ │ └── drone.js │ │ ├── entities.js │ │ ├── examples │ │ │ ├── example-1-hello-module.js │ │ │ ├── example-2-hello-command.js │ │ │ ├── example-3-hello-ops-only.js │ │ │ ├── example-4-hello-parameters.js │ │ │ ├── example-5-hello-using-module.js │ │ │ ├── example-6-hello-player.js │ │ │ └── example-7-hello-events.js │ │ ├── homes │ │ │ └── homes.js │ │ ├── minigames │ │ │ ├── NumberGuess.js │ │ │ └── cow-clicker.js │ │ ├── signs │ │ │ └── examples.js │ │ └── spawn.js │ └── readme.md │ └── resources │ ├── Canary.inf │ ├── boot.js │ ├── config.yml │ └── plugin.yml └── target └── scriptcraft.jar /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/main/js/lib/json2.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "nashorn": true 6 | }, 7 | "globals": { 8 | "__plugin": true, 9 | "server": true, 10 | "events": true, 11 | "addUnloadHandler": true, 12 | "__dirname": true, 13 | "persist": true, 14 | "isOp": true, 15 | "echo": true, 16 | "scload": true, 17 | "nashorn": true, 18 | "plugin": true, // not the same as __plugin!!! 19 | "command": true, 20 | "config": true, 21 | "window": false, 22 | "document": false 23 | }, 24 | "extends": "eslint:recommended", 25 | "rules": { 26 | "indent": [ 27 | "error", 28 | 2 29 | ], 30 | "no-fallthrough": [ 31 | 0 32 | ], 33 | "no-useless-escape": [ 34 | 0 35 | ], 36 | "quotes": [ 37 | "error", 38 | "single" 39 | ], 40 | "no-console": [ 41 | 0 42 | ], 43 | "semi": [ 44 | "error", 45 | "always" 46 | ] 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | *.class 3 | *.js~ 4 | *.js# 5 | *.md# 6 | *.md~ 7 | *.mdt~ 8 | *.mdt# 9 | *.iml 10 | *.#* 11 | *.idea 12 | .DS_Store 13 | build.local.properties 14 | /src/main/javascript/lib/.#tabcomplete.js 15 | /src/main/javascript/plugins/.#example-1.js 16 | /nbproject/private/private.xml 17 | /nbproject/project.xml 18 | /src/docs/nbproject/private/ 19 | /src/docs/build//#build.xml# 20 | /#build.xml# 21 | /src/docs/build/classes/generateApiDocs.js 22 | /src/docs/build/classes/generateTOC.js 23 | /src/docs/build/classes/hello.js 24 | /src/docs/build/classes/.netbeans_automatic_build 25 | /src/docs/build/classes/.netbeans_update_resources 26 | build 27 | nbproject 28 | /manifest.mf 29 | /platform.properties 30 | CopyLibs -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ScriptCraft 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | dist: xenial 3 | jdk: 4 | - oraclejdk9 5 | 6 | -------------------------------------------------------------------------------- /build.local.properties.sample: -------------------------------------------------------------------------------- 1 | # Copy this file to build.local.properties and modify appropriately 2 | 3 | # This setting will ensure the bukkit server will give you ops 4 | op.name=YOUR_USERID_HERE 5 | -------------------------------------------------------------------------------- /build.properties: -------------------------------------------------------------------------------- 1 | scriptcraft-version=3.4.0 2 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Status 2 | 3 | [![Travis Build Status](https://api.travis-ci.org/walterhiggins/ScriptCraft.png)](http://travis-ci.org/walterhiggins/ScriptCraft) 4 | 5 | # Notes for Contributors 6 | 7 | This project uses a Maven-like directory structure... 8 | 9 | src + 10 | main + 11 | java + 12 | net + 13 | walterhiggins + 14 | scriptcraft + 15 | ScriptCraftPlugin.java 16 | 17 | js + 18 | lib + 19 | (core javascript code goes here. Modules in this directory 20 | should not be 'require'd by plugin or module authors) 21 | modules + 22 | (this is where module authors should put modules for 23 | use by others) 24 | plugins + 25 | (this is where plugins - scriptcraft extensions for use by 26 | operators and players should go) 27 | resources + 28 | plugin.yml 29 | docs + 30 | templates + 31 | (documentation templates go here. If you want to make 32 | changes to the young persons guide should be made to ypgpm.md) 33 | ypgpm.md 34 | javascript + 35 | (javascript source used to build the API reference and 36 | table of contents for the API reference and Programming Guide 37 | is located here) 38 | docs + 39 | (the following files should not be edited directly because they are constructed 40 | during the build process - yeah I know they strictly shouldn't be under source control but 41 | it's nice to have the markdown docs on github for reading by non-contributors) 42 | 43 | API-Reference.md 44 | Young-Persons-Guide.md 45 | 46 | (this project is build using Ant, type `ant` at the command line to build.) 47 | 48 | build.xml 49 | build.properties 50 | 51 | ## Core javascript modules 52 | 53 | ScriptCraft's deployed core consists of a single Java source file (the 54 | Bukkit Plugin) and a tiny set of javascript source files located in 55 | the src/main/javascript/lib directory. All other javascript files are 56 | optional modules and plugins. `scriptcraft.js` is the first file 57 | loaded by the Java plugin. scriptcraft.js in turn loads the require.js 58 | file which initializes the commonJS `require()` function and all other 59 | files in the lib directory are then loaded. Finally all of the modules 60 | in the plugins directory are automatically loaded and any exports are 61 | automatically exported to the global namespace. For example a file 62 | called `greet.js` located in the plugins folder... 63 | 64 | // plugins/greet.js contents 65 | 66 | exports.greet = function(sender){ 67 | sender.sendMessage('hello') 68 | } 69 | 70 | ... will be loaded at startup and the `greet` function will be 71 | global. Anyone with operator privileges can type `/js greet(self)` at 72 | the in-game command prompt to execute the function. 73 | 74 | ## Coding Conventions 75 | 76 | See for a recommended 77 | approach to writing javascript code for ScriptCraft. ScriptCraft is 78 | aimed at younger programmers so readability is important - moreso than 79 | cleverness. If submitting new code for inclusion in ScriptCraft please 80 | ensure it is documented using the guidelines below... 81 | 82 | ## Documentation contributions 83 | 84 | The Young persons guide to programming source file is located at 85 | /src/docs/templates/ypgpm.md . *Do not make changes to 86 | /docs/YoungPersonsGuide.md* 87 | 88 | The API Reference is generated by the build from markdown comments 89 | embedded in the javascript source. If you would like comments for 90 | contributed code to be included in the API reference then enclose your 91 | comment as follows: 92 | 93 | * Start the comment block with a `/**********` (a forward-slash 94 | followed by 10 or more asterisk characters). *The start block must 95 | be at the start of the line*. 96 | 97 | * End the comment block with a `***/` (3 asterisk followed by a 98 | forward slash) at the start of a new line. 99 | 100 | This is an example of a comment which will be included in the API reference... 101 | 102 | /********************* 103 | ## foo() function 104 | 105 | The foo() function performs foo-type operatations on all bars. 106 | 107 | ### Parameters 108 | 109 | * name : Name of the foo 110 | * count: Number of foos to perform 111 | 112 | ### Returns 113 | foo() returns a list of foos that were changed. 114 | 115 | ***/ 116 | 117 | Top level comments for a module should be a H2 heading `##`. Please 118 | don't use a H1 heading ( `#` ) as this is used for the top-level API 119 | document title. 120 | -------------------------------------------------------------------------------- /docs/Frequently-Asked-Questions.md: -------------------------------------------------------------------------------- 1 | ## Using Other Plugins from ScriptCraft 2 | The following question gets asked a lot so I'm going to try to answer it here: 3 | 4 | > How to use other bukkit plugins API? 5 | > Like PermissionEX API. 6 | > I can check permission group by java code: 7 | > ru.tehkode.permissions.bukkit.PermissionsEx.getUser(player).inGroup("moderator"); 8 | > But I can't run this code in JavaScript. 9 | > -- [Bukkit forum question][1] 10 | 11 | [1]: http://dev.bukkit.org/bukkit-plugins/scriptcraft/?page=2#c48 12 | 13 | The above question refers to using ScriptCraft for CraftBukkit so I'll answer that first: 14 | 15 | You can get the permissionsEx (or any other Bukkit plugin) like this... 16 | ```javascript 17 | var pex = server.pluginManager.getPlugin('PermissionsEx'); 18 | if (pex.getUser(player).inGroup('moderator') ) { 19 | ... 20 | } 21 | ``` 22 | Generally if you want to use another plugin's API, then get the plugin object by name and then call its methods. In the above example the `pex` variable refers to the aforementioned `PermissionsEx` Plugin. Once you have that reference you can call any of the plugin's methods just as you would in Java. The tricky part is getting the reference and that's where `server.pluginManager.getPlugin()` comes in. 23 | 24 | To get a reference to and work with another plugin's API using ScriptCraft for CanaryMod the same principle applies. Say you've installed ScriptCraft and the dConomy plugin: 25 | 26 | ```javascript 27 | var Canary = Packages.net.canarymod.Canary; 28 | var pluginMgr = Canary.pluginManager(); 29 | var dConomy = pluginMgr.getPlugin('dConomy'); 30 | var dConomyServer = dConomy.modServer; 31 | // from here on in you can access all of the dConomyServer object's calls 32 | // e.g. dConomyServer.newTransaction() 33 | ``` 34 | 35 | The only difference between CanaryMod and Bukkit is how you get the plugin reference. In Bukkit it's: 36 | 37 | ```javascript 38 | var otherPlugin = server.pluginManager.getPlugin('PLUGIN_NAME_GOES_HERE'); 39 | ``` 40 | 41 | whereas in CanaryMod it's: 42 | 43 | ```javascript 44 | var Canary = Packages.net.canarymod.Canary; 45 | var otherPlugin = Canary.pluginManager().getPlugin('PLUGIN_NAME_GOES_HERE'); 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/img/arcex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/arcex1.png -------------------------------------------------------------------------------- /docs/img/blocktype1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/blocktype1.png -------------------------------------------------------------------------------- /docs/img/box0ex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/box0ex1.png -------------------------------------------------------------------------------- /docs/img/boxaex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/boxaex1.png -------------------------------------------------------------------------------- /docs/img/boxex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/boxex1.png -------------------------------------------------------------------------------- /docs/img/castleex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/castleex1.png -------------------------------------------------------------------------------- /docs/img/chessboardex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/chessboardex1.png -------------------------------------------------------------------------------- /docs/img/cornerstone1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/cornerstone1.png -------------------------------------------------------------------------------- /docs/img/cottageex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/cottageex1.png -------------------------------------------------------------------------------- /docs/img/cottageroadex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/cottageroadex1.png -------------------------------------------------------------------------------- /docs/img/cowclicker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/cowclicker.png -------------------------------------------------------------------------------- /docs/img/cylinder0ex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/cylinder0ex1.png -------------------------------------------------------------------------------- /docs/img/cylinderex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/cylinderex1.png -------------------------------------------------------------------------------- /docs/img/dancefloorex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/dancefloorex1.png -------------------------------------------------------------------------------- /docs/img/door2ex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/door2ex1.png -------------------------------------------------------------------------------- /docs/img/doorex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/doorex1.png -------------------------------------------------------------------------------- /docs/img/firework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/firework.png -------------------------------------------------------------------------------- /docs/img/fortex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/fortex1.png -------------------------------------------------------------------------------- /docs/img/gardenex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/gardenex1.png -------------------------------------------------------------------------------- /docs/img/hemisphereex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/hemisphereex1.png -------------------------------------------------------------------------------- /docs/img/hemisphereex2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/hemisphereex2.png -------------------------------------------------------------------------------- /docs/img/lcdclockex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/lcdclockex1.png -------------------------------------------------------------------------------- /docs/img/mazeex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/mazeex1.png -------------------------------------------------------------------------------- /docs/img/prismex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/prismex1.png -------------------------------------------------------------------------------- /docs/img/rainbowex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/rainbowex1.png -------------------------------------------------------------------------------- /docs/img/scriptcraft-chat-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/scriptcraft-chat-color.png -------------------------------------------------------------------------------- /docs/img/signex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/signex1.png -------------------------------------------------------------------------------- /docs/img/signex2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/signex2.png -------------------------------------------------------------------------------- /docs/img/skyscraper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/skyscraper.png -------------------------------------------------------------------------------- /docs/img/skyscraper_floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/skyscraper_floor.png -------------------------------------------------------------------------------- /docs/img/sphereex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/sphereex1.png -------------------------------------------------------------------------------- /docs/img/spiralstair1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/spiralstair1.png -------------------------------------------------------------------------------- /docs/img/templeex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/templeex1.png -------------------------------------------------------------------------------- /docs/img/times-trees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/times-trees.png -------------------------------------------------------------------------------- /docs/img/treeex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/treeex1.png -------------------------------------------------------------------------------- /docs/img/ypgpm_2boxes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/ypgpm_2boxes.png -------------------------------------------------------------------------------- /docs/img/ypgpm_3dshapes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/ypgpm_3dshapes.jpg -------------------------------------------------------------------------------- /docs/img/ypgpm_datavalues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/ypgpm_datavalues.png -------------------------------------------------------------------------------- /docs/img/ypgpm_echo_date.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/ypgpm_echo_date.png -------------------------------------------------------------------------------- /docs/img/ypgpm_ex_dwell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/ypgpm_ex_dwell.png -------------------------------------------------------------------------------- /docs/img/ypgpm_greet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/ypgpm_greet.png -------------------------------------------------------------------------------- /docs/img/ypgpm_mc_cr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/ypgpm_mc_cr.png -------------------------------------------------------------------------------- /docs/img/ypgpm_whd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/docs/img/ypgpm_whd.jpg -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | /canarymod.jar 2 | -------------------------------------------------------------------------------- /lib/canarymod-1.8.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/lib/canarymod-1.8.0.jar -------------------------------------------------------------------------------- /lib/spigot-api-1.13.2-R0.1-SNAPSHOT-shaded.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/lib/spigot-api-1.13.2-R0.1-SNAPSHOT-shaded.jar -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Walter Higgins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /screenshots/2012-12-27_13.25.06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/screenshots/2012-12-27_13.25.06.png -------------------------------------------------------------------------------- /screenshots/2012-12-28_13.38.07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/screenshots/2012-12-28_13.38.07.png -------------------------------------------------------------------------------- /screenshots/2012-12-28_23.04.33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/screenshots/2012-12-28_23.04.33.png -------------------------------------------------------------------------------- /screenshots/blocktype-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/screenshots/blocktype-example.png -------------------------------------------------------------------------------- /screenshots/castles-interlocking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/screenshots/castles-interlocking.png -------------------------------------------------------------------------------- /screenshots/forts-castles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/screenshots/forts-castles.png -------------------------------------------------------------------------------- /screenshots/temple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/screenshots/temple.png -------------------------------------------------------------------------------- /src/.prettierrc: -------------------------------------------------------------------------------- 1 | # .prettierrc 2 | printWidth: 80 3 | singleQuote: true 4 | tabWidth: 2 5 | useTabs: false 6 | semi: true 7 | 8 | -------------------------------------------------------------------------------- /src/docs/java/jscript.java: -------------------------------------------------------------------------------- 1 | import javax.script.*; 2 | import java.io.FileReader; 3 | import net.canarymod.api.inventory.ItemType; 4 | 5 | public class jscript 6 | { 7 | public static void main(String[] args) throws Exception 8 | { 9 | ScriptEngineManager factory = new ScriptEngineManager(); 10 | ScriptEngine engine = factory.getEngineByName("JavaScript"); 11 | // Adding bindings to work with GraalJS 12 | Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); 13 | bindings.put("polyglot.js.allowAllAccess", true); 14 | bindings.put("polyglot.js.nashorn-compat", true); 15 | 16 | java.io.File file = new java.io.File(args[0]); 17 | engine.put("engine",engine); 18 | engine.put("args",args); 19 | try { 20 | engine.put("cmItemTypeClass",Class.forName("net.canarymod.api.inventroy.ItemType")); 21 | }catch(Exception e){ 22 | } 23 | FileReader fr = new java.io.FileReader(file); 24 | engine.eval(fr); 25 | fr.close(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/docs/js/generateApiDocs.js: -------------------------------------------------------------------------------- 1 | /*global load, args, Packages*/ 2 | /* 3 | This script is run at build time to generate api.md - a single Markdown document containing documentation for ScriptCraft's API 4 | */ 5 | function foreach(array, func) { 6 | for (var i = 0; i < array.length; i++) { 7 | func(array[i], i, array); 8 | } 9 | } 10 | /* 11 | find - a (very) basic implementation of the unix command line tool. 12 | */ 13 | function find(dir, store, re) { 14 | var files = dir.listFiles(); 15 | foreach(files, function(filename) { 16 | filename = '' + filename; 17 | var file = new File(filename); 18 | if (file.isDirectory()) { 19 | find(file, store, re); 20 | } else { 21 | if (typeof re == 'undefined') store.push(filename); 22 | else if (filename.match(re)) store.push(filename); 23 | } 24 | }); 25 | } 26 | /* 27 | the main module file for a given directory 28 | (assuming the main module is in a file with the same name as the parent 29 | directory) - e.g. drone/drone.js 30 | */ 31 | function sorter(precedence) { 32 | return function(a, b) { 33 | // convert from Java string to JS string 34 | a = '' + a; 35 | b = '' + b; 36 | var aparts = a.split(/\//); 37 | var bparts = b.split(/\//); 38 | var adir = aparts.slice(3, aparts.length - 1).join('/'); 39 | var afile = aparts[aparts.length - 1]; 40 | var bdir = bparts.slice(3, bparts.length - 1).join('/'); 41 | var bfile = bparts[bparts.length - 1]; 42 | 43 | for (var i = 0; i < precedence.length; i++) { 44 | var re = precedence[i]; 45 | if (a.match(re) && b.match(re)) { 46 | if (afile < bfile) return -1; 47 | if (afile > bfile) return 1; 48 | } 49 | if (a.match(re)) return -1; 50 | if (b.match(re)) return 1; 51 | } 52 | if (adir < bdir) return -1; 53 | if (adir > bdir) return 1; 54 | afile = afile.replace(/\.js$/, ''); 55 | if (afile == adir) { 56 | return -1; 57 | } else { 58 | var result = 0; 59 | if (afile < bfile) { 60 | result = -1; 61 | } 62 | if (afile > bfile) { 63 | result = 1; 64 | } 65 | //err.println("afile: " + afile + ", bfile:" + bfile + ",result=" + result); 66 | 67 | return result; 68 | } 69 | }; 70 | } 71 | var err = java.lang.System.err; 72 | args = Array.prototype.slice.call(args, 1); 73 | 74 | if (typeof importPackage == 'undefined') { 75 | // load compatibility script 76 | load('nashorn:mozilla_compat.js'); 77 | } 78 | var dir = args[0]; 79 | 80 | var io = Packages.java.io; 81 | var File = io.File; 82 | var store = []; 83 | find(new io.File(dir), store, /\/[a-zA-Z0-9_\-]+\.js$/); 84 | 85 | store.sort( 86 | sorter([ 87 | /lib\/scriptcraft\.js$/, 88 | /lib\/require\.js$/, 89 | /lib\/plugin\.js$/, 90 | /lib\/events\.js$/, 91 | /lib\/events\-helper\-canary/, 92 | /lib\/events\-helper\-bukkit/, 93 | /lib\//, 94 | /modules\/drone\/index\.js/, 95 | /modules\/drone\//, 96 | /plugins\/drone\//, 97 | /modules\//, 98 | /examples\// 99 | ]) 100 | ); 101 | 102 | var contents = []; 103 | foreach(store, function(filename) { 104 | if (filename.match(/babel\.js/)) { 105 | return; 106 | } 107 | if (filename.match(/underscore\.js/)) { 108 | return; 109 | } 110 | var br = new io.BufferedReader(new io.FileReader(filename)); 111 | var line; 112 | while ((line = br.readLine()) != null) { 113 | contents.push(line); 114 | } 115 | br.close(); 116 | }); 117 | 118 | var len = contents.length; 119 | var writeComment = false; 120 | var startComment = /^\/\*{10}/; 121 | var endComment = /^\*{3}\//; 122 | 123 | for (var i = 0; i < contents.length; i++) { 124 | var line = contents[i]; 125 | if (line.match(startComment)) { 126 | writeComment = true; 127 | i++; 128 | } 129 | if (line.match(endComment)) { 130 | writeComment = false; 131 | } 132 | if (writeComment) { 133 | java.lang.System.out.println(contents[i]); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/docs/js/generateEntitiesDocBukkit.js: -------------------------------------------------------------------------------- 1 | args = Array.prototype.slice.call(args, 1); 2 | // [0] = type, [1] = lib.jar [2] = blockX, [3] = classX 3 | var out = java.lang.System.out, 4 | err = java.lang.System.err, 5 | entry = null; 6 | var content = [ 7 | '', 8 | '## Entities module', 9 | 'The Entities module provides a suite of functions - one for each possible entity type. ', 10 | 'It acts as a helper or enumerated module to assist in use with the `spawn` module and command. ', 11 | 'This module is useful for TAB-completion at the in-game prompt. ', 12 | '', 13 | 'When each function is called with no parameters, it will return the appropriate EntityType object. ', 14 | 'For example `entities.polar_bear()` will return an `EntityType.POLAR_BEAR` object. ', 15 | '', 16 | "When each function is called with a single parameter - an entity - the entity's type will be compared and return true or false. ", 17 | '', 18 | '### Usage', 19 | '', 20 | ' entities.zombie(); // returns a SpigotMC/CanaryMod EntityType.ZOMBIE enum value', 21 | " entities.zombie( mob ); // compares the entity's type to a zombie, returns true if mob type is zombie, false otherwise", 22 | ' entities.player( self ); // at the in-game prompt this should return true (compares self to a player entity type)', 23 | ' entities.rabbit( self ); // at the in-game prompt this should return false (compares self to a rabbit entity type)', 24 | '', 25 | 'The following functions are provided:', 26 | '' 27 | ]; 28 | 29 | var enumVals = [], 30 | t, 31 | i, 32 | name; 33 | var entitytypes = org.bukkit.entity.EntityType.values(); 34 | for (t in entitytypes) { 35 | if (entitytypes[t] && entitytypes[t].ordinal) { 36 | name = entitytypes[t].name(); 37 | name = ('' + name).replace(/^(.*)/, function(a) { 38 | return a.toLowerCase(); 39 | }); 40 | enumVals.push(' * ' + name + '()'); 41 | } 42 | } 43 | enumVals.sort(); 44 | content = content.concat(enumVals); 45 | content.push(''); 46 | for (i = 0; i < content.length; i++) { 47 | out.println(content[i]); 48 | } 49 | -------------------------------------------------------------------------------- /src/docs/js/generateEventsHelper.js: -------------------------------------------------------------------------------- 1 | /*global args*/ 2 | args = Array.prototype.slice.call(args, 1); 3 | // [0] = type, [1] = lib.jar [2] = blockX, [3] = classX 4 | var File = java.io.File, 5 | FileReader = java.io.FileReader, 6 | FileInputStream = java.io.FileInputStream, 7 | FRAMEWORK = args[0], 8 | out = java.lang.System.out, 9 | err = java.lang.System.err, 10 | Modifier = java.lang.reflect.Modifier, 11 | clz, 12 | ZipInputStream = java.util.zip.ZipInputStream, 13 | zis = new ZipInputStream(new FileInputStream(args[1])), 14 | entry = null; 15 | var content = [ 16 | '/*********************', 17 | '## Events Helper Module (' + FRAMEWORK + ' version)', 18 | 'The Events helper module provides a suite of functions - one for each possible event.', 19 | 'For example, the events.' + 20 | args[2] + 21 | '() function is just a wrapper function which calls events.on(' + 22 | args[3] + 23 | ', callback, priority)', 24 | 'This module is a convenience wrapper for easily adding new event handling functions in Javascript. ', 25 | 'At the in-game or server-console prompt, players/admins can type `events.` and use TAB completion ', 26 | 'to choose from any of the approx. 160 different event types to listen to.', 27 | '', 28 | '### Usage', 29 | '', 30 | ' events.' + args[2] + '( function( event ) { ', 31 | " echo( event.player, 'You broke a block!'); ", 32 | ' });', 33 | '', 34 | 'The crucial difference is that the events module now has functions for each of the built-in events. The functions are accessible via TAB-completion so will help beginning programmers to explore the events at the server console window.', 35 | '', 36 | '***/' 37 | ]; 38 | var canary = false; 39 | if (FRAMEWORK == 'CanaryMod') { 40 | canary = true; 41 | } 42 | 43 | for (var i = 0; i < content.length; i++) { 44 | out.println(content[i]); 45 | } 46 | var names = []; 47 | while ((entry = zis.nextEntry) != null) { 48 | names.push(String(entry.name)); 49 | } 50 | names.sort(); 51 | names.forEach(function(name) { 52 | var re1 = /org\/bukkit\/event\/.+Event\.class$/; 53 | if (canary) { 54 | re1 = /net\/canarymod\/hook\/.+Hook\.class$/; 55 | } 56 | if (re1.test(name)) { 57 | name = name.replace(/\//g, '.').replace('.class', ''); 58 | try { 59 | clz = java.lang.Class.forName(name); 60 | } catch (e) { 61 | err.println('Warning: could not Class.forName("' + name + '")'); 62 | clz = engine.eval(name); 63 | } 64 | var isAbstract = Modifier.isAbstract(clz.getModifiers()); 65 | if (isAbstract) { 66 | return; 67 | } 68 | var parts = name.split('.'); 69 | var shortName = null; 70 | if (canary) { 71 | shortName = name.replace('net.canarymod.hook.', ''); 72 | } 73 | if (!canary) { 74 | shortName = name.replace('org.bukkit.event.', ''); 75 | } 76 | var fname = parts 77 | .reverse() 78 | .shift() 79 | .replace(/^(.)/, function(a) { 80 | return a.toLowerCase(); 81 | }); 82 | if (!canary) { 83 | fname = fname.replace(/Event$/, ''); 84 | } 85 | if (canary) { 86 | fname = fname.replace(/Hook$/, ''); 87 | } 88 | var javaDoc = canary 89 | ? 'https://ci.visualillusionsent.net/job/CanaryLib/javadoc/net/canarymod/hook/' 90 | : 'https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/'; 91 | var comment = [ 92 | '/*********************', 93 | '### events.' + fname + '()', 94 | '', 95 | '#### Parameters', 96 | '', 97 | ' * callback - A function which is called whenever the [' + 98 | shortName + 99 | ' event](' + 100 | javaDoc + 101 | shortName.replace('.', '/') + 102 | '.html) is fired', 103 | '', 104 | ' * priority - optional - see events.on() for more information.', 105 | '', 106 | '***/' 107 | //http://jd.bukkit.org/rb/apidocs/org/bukkit/event/player/PlayerJoinEvent.html 108 | ]; 109 | for (var i = 0; i < comment.length; i++) { 110 | out.println(comment[i]); 111 | } 112 | out.println('exports.' + fname + ' = function(callback,priority){ '); 113 | if (canary) { 114 | out.println( 115 | ' return events.on(Packages.' + name + ',callback,priority);' 116 | ); 117 | } else { 118 | out.println(' return events.on(' + name + ',callback,priority);'); 119 | } 120 | out.println('};'); 121 | } 122 | }); 123 | -------------------------------------------------------------------------------- /src/docs/js/generateItemsDocBukkit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var out = java.lang.System.out; 3 | var content = [ 4 | '', 5 | '## Items module (SpigotMC version)', 6 | 'The Items module provides a suite of functions - one for each possible item.', 7 | 'See https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html for a list of possible items', 8 | '', 9 | '### Usage', 10 | '', 11 | ' items.book(); // returns org.bukkit.Material.BOOK', 12 | ' items.book(2); // returns a new org.bukkit.inventory.ItemStack object of 2 books', 13 | ' items.book( itemType ); // compares itemType parameter to org.bukkit.Material.BOOK or an Item of type book', 14 | '', 15 | 'The following functions are provided:', 16 | '' 17 | ]; 18 | 19 | var enumVals = [], 20 | t, 21 | i, 22 | name; 23 | 24 | var types = org.bukkit.Material.values(); 25 | 26 | for (t in types) { 27 | if (types[t] && types[t].ordinal) { 28 | name = ('' + types[t].name()).toLowerCase(); 29 | name = name.replace(/(_.)/g, function(a) { 30 | return a.replace(/_/, '').toUpperCase(); 31 | }); 32 | enumVals.push(' * ' + name + '()'); 33 | } 34 | } 35 | enumVals.sort(); 36 | content = content.concat(enumVals); 37 | content.push(''); 38 | for (i = 0; i < content.length; i++) { 39 | out.println(content[i]); 40 | } 41 | -------------------------------------------------------------------------------- /src/docs/js/generateItemsDocCanary.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global cmItemTypeClass*/ 3 | var out = java.lang.System.out; 4 | var content = [ 5 | '', 6 | '## Items module (CanaryMod version)', 7 | 'The Items module provides a suite of functions - one for each possible item.', 8 | 'See https://ci.visualillusionsent.net/job/CanaryLib/javadoc/net/canarymod/api/inventory/ItemType.html for a list of possible items', 9 | '', 10 | '### Usage', 11 | '', 12 | ' items.book(); // returns net.canarymod.api.inventory.ItemType.Book', 13 | ' items.book(2); // returns a new net.canarymod.api.inventory.Item object with an amount 2 (2 books)', 14 | ' items.book( itemType ); // compares itemType parameter to ItemType.Book or an Item of type book', 15 | '', 16 | 'The following functions are provided:', 17 | '' 18 | ]; 19 | 20 | //var ItemType = java.lang.Class.forName('net.canarymod.api.inventory.ItemType'); 21 | var materials = cmItemTypeClass.getDeclaredFields(); 22 | 23 | enumVals = []; 24 | for (i = 0; i < materials.length; i++) { 25 | if (materials[i].type != cmItemTypeClass) { 26 | continue; 27 | } 28 | var materialField = materials[i]; 29 | name = ('' + materialField.name).replace(/^(.)/, function(a) { 30 | return a.toLowerCase(); 31 | }); 32 | enumVals.push(' * ' + name + '()'); 33 | } 34 | enumVals.sort(); 35 | content = content.concat(enumVals); 36 | content.push(''); 37 | for (i = 0; i < content.length; i++) { 38 | out.println(content[i]); 39 | } 40 | -------------------------------------------------------------------------------- /src/docs/js/generateSoundsDocBukkit.js: -------------------------------------------------------------------------------- 1 | var out = java.lang.System.out; 2 | var content = [ 3 | '', 4 | '## Sounds module (SpigotMC version)', 5 | '', 6 | 'This module provides a simple way to play sounds.', 7 | '', 8 | '### Usage', 9 | '', 10 | ' var sounds = require("sounds");', 11 | ' // plays ENTITY_WOLF_HOWL sound at full volume and medium pitch', 12 | ' sounds.play( org.bukkit.Sound.ENTITY_WOLF_HOWL, self, 1, 0); ', 13 | ' // same as previous statement', 14 | ' sounds.play( org.bukkit.Sound.ENTITY_WOLF_HOWL , self );', 15 | '', 16 | 'The play() function takes as parameters:', 17 | '', 18 | ' * A Sound value (see https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Sound.html for a list of possible values)', 19 | ' * A Location orbject or any object which has a location', 20 | ' * The Volume parameter is in the range 0 to 1 (default: 1)', 21 | ' * The Pitch parameter is in the range 0 to 4 (default: 0)', 22 | '', 23 | 'In addition, the Sounds module provides a suite of helper functions - one for each possible sound. ', 24 | '', 25 | ' var sounds = require("sounds");', 26 | ' // same as previous examples', 27 | ' sounds.entityWolfHowl( self );', 28 | '', 29 | 'Each of the following functions takes as parameters:', 30 | '', 31 | ' * A Location orbject or any object which has a location', 32 | ' * The Volume parameter is in the range 0 to 1 (default: 1)', 33 | ' * The Pitch parameter is in the range 0 to 4 (default: 0)', 34 | '', 35 | 'The following functions are provided for convenience and to help beginners explore sounds using TAB completion:', 36 | '' 37 | ]; 38 | 39 | var enumVals = [], 40 | i; 41 | var sound, 42 | soundName, 43 | sounds = org.bukkit.Sound.values(); 44 | for (i = 0; i < sounds.length; i++) { 45 | sound = sounds[i]; 46 | soundName = '' + sound.name(); 47 | var methodName = ('' + soundName) 48 | .toLowerCase() 49 | .replace(/_(.)/g, function(a, b) { 50 | return b.toUpperCase(); 51 | }); 52 | enumVals.push(' * ' + methodName + '()'); 53 | } 54 | enumVals.sort(); 55 | content = content.concat(enumVals); 56 | content.push(''); 57 | for (i = 0; i < content.length; i++) { 58 | out.println(content[i]); 59 | } 60 | -------------------------------------------------------------------------------- /src/docs/js/generateSoundsDocCanary.js: -------------------------------------------------------------------------------- 1 | var out = java.lang.System.out; 2 | var content = [ 3 | '', 4 | '## Sounds module (CanaryMod version)', 5 | '', 6 | 'This module provides a simple way to play sounds.', 7 | '', 8 | '### Usage', 9 | '', 10 | ' var sounds = require("sounds");', 11 | ' // plays WOLF_HOWL sound at full volume and medium pitch', 12 | ' sounds.play( Packages.net.canarymod.api.world.effects.SoundEffect.Type.WOLF_HOWL, self, 1, 0); ', 13 | ' // same as previous statement', 14 | ' sounds.play( Packages.net.canarymod.api.world.effects.SoundEffect.Type.WOLF_HOWL, self );', 15 | '', 16 | 'The play() function takes as parameters:', 17 | '', 18 | ' * A Sound value (see https://ci.visualillusionsent.net/job/CanaryLib/javadoc/net/canarymod/api/world/effects/SoundEffect.Type.html for a list of possible values)', 19 | ' * A Location orbject or any object which has a location', 20 | ' * The Volume parameter is in the range 0 to 1 (default: 1)', 21 | ' * The Pitch parameter is in the range 0 to 4 (default: 0)', 22 | '', 23 | 'In addition, the Sounds module provides a suite of helper functions - one for each possible sound. ', 24 | '', 25 | ' var sounds = require("sounds");', 26 | ' // same as previous examples', 27 | ' sounds.wolfHowl( self );', 28 | '', 29 | 'Each of the following functions takes as parameters:', 30 | '', 31 | ' * A Location orbject or any object which has a location', 32 | ' * The Volume parameter is in the range 0 to 1 (default: 1)', 33 | ' * The Pitch parameter is in the range 0 to 4 (default: 0)', 34 | '', 35 | 'The following functions are provided for convenience and to help beginners explore sounds using TAB completion:', 36 | '' 37 | ]; 38 | 39 | var enumVals = [], 40 | i, 41 | sound, 42 | soundName, 43 | sounds; 44 | sounds = Packages.net.canarymod.api.world.effects.SoundEffect.Type.values(); 45 | for (i = 0; i < sounds.length; i++) { 46 | sound = sounds[i]; 47 | soundName = '' + sound.name(); 48 | methodName = ('' + soundName).toLowerCase().replace(/_(.)/g, function(a, b) { 49 | return b.toUpperCase(); 50 | }); 51 | enumVals.push(' * ' + methodName + '()'); 52 | } 53 | enumVals.sort(); 54 | content = content.concat(enumVals); 55 | content.push(''); 56 | for (i = 0; i < content.length; i++) { 57 | out.println(content[i]); 58 | } 59 | -------------------------------------------------------------------------------- /src/docs/js/generateTOC.js: -------------------------------------------------------------------------------- 1 | args = Array.prototype.slice.call(args, 1); 2 | 3 | // wph 20140105 trim not availabe in String on Mac OS. 4 | if (typeof String.prototype.trim == 'undefined') { 5 | String.prototype.trim = function() { 6 | return this.replace(/^\s+|\s+$/g, ''); 7 | }; 8 | } 9 | 10 | var template = args[0]; 11 | 12 | var BufferedReader = java.io.BufferedReader; 13 | var FileReader = java.io.FileReader; 14 | 15 | var contents = [], 16 | line = undefined; 17 | var br = new BufferedReader(new FileReader(template)); 18 | 19 | while ((line = br.readLine()) != null) { 20 | contents.push(line); 21 | } 22 | br.close(); 23 | 24 | var anchors = {}; 25 | 26 | var createLink = function(text) { 27 | var result = text.replace(/_/g, '_'); 28 | result = result.replace(/[^a-zA-Z0-9 _\-]/g, ''); 29 | result = result.replace(/ /g, '-'); 30 | var result = result.toLowerCase(); 31 | if (anchors[result]) { 32 | result = result + '-' + anchors[result]++; 33 | } 34 | anchors[result] = 1; 35 | return result; 36 | }; 37 | java.lang.System.out.println('## Table of Contents'); 38 | 39 | for (var i = 0; i < contents.length; i++) { 40 | line = contents[i]; 41 | if (line.match(/^##\s+/)) { 42 | var h2 = line.match(/^##\s+(.*)/)[1].trim(); 43 | var link = createLink(h2); 44 | java.lang.System.out.println(' * [' + h2 + '](#' + link + ')'); 45 | } 46 | if (line.match(/^###\s+/)) { 47 | var h3 = line.match(/^###\s+(.*)/)[1].trim(); 48 | var link = createLink(h3); 49 | java.lang.System.out.println(' * [' + h3 + '](#' + link + ')'); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/bukkit/org/scriptcraftjs/bukkit/ScriptCraftPlugin.java: -------------------------------------------------------------------------------- 1 | package org.scriptcraftjs.bukkit; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandSender; 5 | import org.bukkit.plugin.java.JavaPlugin; 6 | 7 | import javax.script.Invocable; 8 | import javax.script.ScriptEngine; 9 | import javax.script.ScriptEngineManager; 10 | // imports for GraalJS bindings 11 | import javax.script.Bindings; 12 | import javax.script.ScriptContext; 13 | 14 | import java.io.InputStreamReader; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public class ScriptCraftPlugin extends JavaPlugin 19 | { 20 | public boolean canary = false; 21 | public boolean bukkit = true; 22 | // right now all ops share the same JS context/scope 23 | // need to look at possibly having context/scope per operator 24 | //protected Map playerContexts = new HashMap(); 25 | private String NO_JAVASCRIPT_MESSAGE = "No JavaScript Engine available. ScriptCraft will not work without Javascript."; 26 | protected ScriptEngine engine = null; 27 | 28 | @Override public void onEnable() 29 | { 30 | Thread currentThread = Thread.currentThread(); 31 | ClassLoader previousClassLoader = currentThread.getContextClassLoader(); 32 | currentThread.setContextClassLoader(getClassLoader()); 33 | try { 34 | ScriptEngineManager factory = new ScriptEngineManager(); 35 | // This older fix does not work with GraalVM in R21.2.0; in this case 36 | // it does not return any engine ('engine' is null) 37 | //ScriptEngineManager factory = new ScriptEngineManager(null); 38 | this.engine = factory.getEngineByName("JavaScript"); 39 | 40 | if (this.engine == null) { 41 | this.getLogger().severe(NO_JAVASCRIPT_MESSAGE); 42 | } else { 43 | // Enrico, adding bindings to work with GraalJS, 44 | // see https://www.graalvm.org/reference-manual/js/NashornMigrationGuide/ 45 | Bindings bindings = this.engine.getBindings(ScriptContext.ENGINE_SCOPE); 46 | bindings.put("polyglot.js.allowAllAccess", true); 47 | bindings.put("polyglot.js.nashorn-compat", true); 48 | 49 | Invocable inv = (Invocable) this.engine; 50 | this.engine.eval(new InputStreamReader(this.getResource("boot.js"))); 51 | inv.invokeFunction("__scboot", this, engine); 52 | } 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | this.getLogger().severe(e.getMessage()); 56 | } finally { 57 | currentThread.setContextClassLoader(previousClassLoader); 58 | } 59 | } 60 | 61 | public List onTabComplete(CommandSender sender, Command cmd, 62 | String alias, 63 | String[] args) 64 | { 65 | List result = new ArrayList(); 66 | if (this.engine == null) { 67 | this.getLogger().severe(NO_JAVASCRIPT_MESSAGE); 68 | return null; 69 | } 70 | try { 71 | Invocable inv = (Invocable)this.engine; 72 | inv.invokeFunction("__onTabComplete", result, sender, cmd, alias, args); 73 | } catch (Exception e) { 74 | sender.sendMessage(e.getMessage()); 75 | e.printStackTrace(); 76 | } 77 | return result; 78 | } 79 | 80 | public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) 81 | { 82 | boolean result = false; 83 | Object jsResult = null; 84 | if (this.engine == null) { 85 | this.getLogger().severe(NO_JAVASCRIPT_MESSAGE); 86 | return false; 87 | } 88 | try { 89 | jsResult = ((Invocable)this.engine).invokeFunction("__onCommand", sender, cmd, label, args); 90 | } catch (Exception se) { 91 | this.getLogger().severe(se.toString()); 92 | se.printStackTrace(); 93 | sender.sendMessage(se.getMessage()); 94 | } 95 | if (jsResult != null){ 96 | return ((Boolean)jsResult).booleanValue(); 97 | } 98 | return result; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/js/.prettierrc~: -------------------------------------------------------------------------------- 1 | # .prettierrc 2 | printWidth: 80 3 | singleQuotes: true 4 | -------------------------------------------------------------------------------- /src/main/js/lib/.gitignore: -------------------------------------------------------------------------------- 1 | /events-helper-bukkit.js 2 | /events-helper-canary.js 3 | -------------------------------------------------------------------------------- /src/main/js/lib/command.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* 3 | command management - allow for non-ops to execute approved javascript code. 4 | */ 5 | var _commands = {}, 6 | _cmdInterceptors = []; 7 | /* 8 | execute a JSP command. 9 | */ 10 | var executeCmd = function(args, player) { 11 | var name, 12 | cmd, 13 | intercepted, 14 | result = null; 15 | 16 | if (args.length === 0) { 17 | throw new Error('Usage: jsp command-name command-parameters'); 18 | } 19 | name = args[0]; 20 | cmd = _commands[name]; 21 | if (typeof cmd === 'undefined') { 22 | // it's not a global command - pass it on to interceptors 23 | intercepted = false; 24 | for (var i = 0; i < _cmdInterceptors.length; i++) { 25 | if (_cmdInterceptors[i](args, player)) intercepted = true; 26 | } 27 | if (!intercepted) { 28 | console.warn('Command %s is not recognised', name); 29 | } 30 | } else { 31 | try { 32 | result = cmd.callback(args.slice(1), player); 33 | } catch (e) { 34 | console.error( 35 | 'Error while trying to execute command: ' + JSON.stringify(args) 36 | ); 37 | throw e; 38 | } 39 | } 40 | return result; 41 | }; 42 | /* 43 | define a new JSP command. 44 | */ 45 | var defineCmd = function(name, func, options, intercepts) { 46 | if (typeof name == 'function') { 47 | intercepts = options; 48 | options = func; 49 | func = name; 50 | name = func.name; 51 | } 52 | 53 | if (typeof options == 'undefined') { 54 | options = []; 55 | } 56 | _commands[name] = { callback: func, options: options }; 57 | if (intercepts) { 58 | _cmdInterceptors.push(func); 59 | } 60 | return func; 61 | }; 62 | exports.command = defineCmd; 63 | exports.commands = _commands; 64 | exports.exec = executeCmd; 65 | -------------------------------------------------------------------------------- /src/main/js/lib/console.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /************************************************************************* 3 | ## console global variable 4 | 5 | ScriptCraft provides a `console` global variable with the followng methods... 6 | 7 | * log() 8 | * info() 9 | * warn() 10 | * error() 11 | 12 | The ScriptCraft console methods work like the [Web API implementation][webcons]. 13 | 14 | ### Example 15 | 16 | console.log('Hello %s', 'world'); 17 | 18 | Basic variable substitution is supported (ScriptCraft's implementation 19 | of console uses the Bukkit Plugin [Logger][lgr] or Canary Plugin [Logman][cmlgr] under the hood and 20 | uses [java.lang.String.format()][strfmt] for variable 21 | substitution. All output will be sent to the server console (not 22 | in-game). 23 | 24 | ### Using string substitutions 25 | 26 | ScriptCraft uses Java's [String.format()][strfmt] so any string substitution identifiers supported by 27 | `java.lang.String.format()` are supported (e.g. %s , %d etc). 28 | 29 | for (var i=0; i<5; i++) { 30 | console.log("Hello, %s. You've called me %d times.", "Bob", i+1); 31 | } 32 | 33 | [lgr]: http://jd.bukkit.org/beta/apidocs/org/bukkit/plugin/PluginLogger.html 34 | [cmlgr]: https://ci.visualillusionsent.net/job/CanaryLib/javadoc/net/canarymod/logger/Logman.html 35 | [strfmt]: http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#format(java.lang.String, java.lang.Object...) 36 | [webcons]: https://developer.mozilla.org/en-US/docs/Web/API/console 37 | 38 | ***/ 39 | function argsToArray(args) { 40 | var result = []; 41 | for (var i = 0; i < args.length; i++) { 42 | result.push(args[i]); 43 | } 44 | return result; 45 | } 46 | function consMsg(params) { 47 | var args = argsToArray(params); 48 | if (args.length > 1) { 49 | return java.lang.String.format(args[0], args.slice(1)); 50 | } else { 51 | return args[0]; 52 | } 53 | } 54 | 55 | module.exports = function(logger) { 56 | function bukkitLog(level, restOfArgs) { 57 | logger['log(java.util.logging.Level,java.lang.String)']( 58 | java.util.logging.Level[level], 59 | consMsg(restOfArgs) 60 | ); 61 | } 62 | 63 | if (__plugin.canary) { 64 | return { 65 | log: function() { 66 | logger.info(consMsg(arguments)); 67 | }, 68 | info: function() { 69 | logger.info(consMsg(arguments)); 70 | }, 71 | warn: function() { 72 | logger.warn(consMsg(arguments)); 73 | }, 74 | error: function() { 75 | logger.error(consMsg(arguments)); 76 | } 77 | }; 78 | } else { 79 | return { 80 | log: function() { 81 | bukkitLog('INFO', arguments); 82 | }, 83 | info: function() { 84 | bukkitLog('INFO', arguments); 85 | }, 86 | warn: function() { 87 | bukkitLog('WARNING', arguments); 88 | }, 89 | error: function() { 90 | bukkitLog('SEVERE', arguments); 91 | } 92 | }; 93 | } 94 | }; 95 | -------------------------------------------------------------------------------- /src/main/js/lib/events-bukkit.js: -------------------------------------------------------------------------------- 1 | /*global Java, exports, org, __plugin */ 2 | var bkEventPriority = org.bukkit.event.EventPriority, 3 | bkHandlerList = org.bukkit.event.HandlerList, 4 | bkPluginManager = org.bukkit.Bukkit.pluginManager; 5 | 6 | // Ask Nashorn to generate a class implementing the Listener 7 | // interface, so that we may instantiate it to tag our event 8 | // handlers. 9 | var ScriptCraftListener = Java.extend(org.bukkit.event.Listener, {}); 10 | 11 | exports.on = function( 12 | /* Java Class */ 13 | eventType, 14 | /* function( registeredListener, event) */ 15 | 16 | handler, 17 | /* (optional) String (HIGH, HIGHEST, LOW, LOWEST, NORMAL, MONITOR), */ 18 | priority 19 | ) { 20 | if (typeof priority == 'undefined') { 21 | priority = bkEventPriority.HIGHEST; 22 | } else { 23 | priority = bkEventPriority[priority.toUpperCase().trim()]; 24 | } 25 | 26 | var result = {}; 27 | var eventExecutor = function(l, evt) { 28 | function cancel() { 29 | if (evt instanceof org.bukkit.event.Cancellable) { 30 | evt.setCancelled(true); 31 | } 32 | } 33 | /* 34 | let handlers use this.cancel() to cancel the current event 35 | or this.unregister() to unregister from future events. 36 | */ 37 | var bound = {}; 38 | for (var i in result) { 39 | bound[i] = result[i]; 40 | } 41 | bound.cancel = cancel; 42 | handler.call(bound, evt, cancel); 43 | }; 44 | 45 | // Create an instance of our empty Listener implementation to track the handler 46 | var listener = new ScriptCraftListener(); 47 | 48 | bkPluginManager.registerEvent( 49 | eventType.class, 50 | listener, 51 | priority, 52 | eventExecutor, 53 | __plugin 54 | ); 55 | 56 | result.unregister = function() { 57 | bkHandlerList.unregisterAll(listener); 58 | }; 59 | 60 | return result; 61 | }; 62 | -------------------------------------------------------------------------------- /src/main/js/lib/events-canary.js: -------------------------------------------------------------------------------- 1 | /*global exports, require, Packages, __plugin*/ 2 | var cmPriority = Packages.net.canarymod.plugin.Priority, 3 | cmCanary = Packages.net.canarymod.Canary, 4 | cmPluginListener = Packages.net.canarymod.plugin.PluginListener; 5 | var cmHookExecutor = cmCanary.hooks(); 6 | 7 | exports.on = function( 8 | /* Java Class */ 9 | eventType, 10 | /* function( registeredListener, event) */ 11 | 12 | handler, 13 | /* (optional) String (CRITICAL, HIGH, NORMAL, LOW, PASSIVE), */ 14 | priority 15 | ) { 16 | var regd, eventExecutor; 17 | 18 | if (typeof priority == 'undefined') { 19 | priority = cmPriority.NORMAL; 20 | } else { 21 | priority = cmPriority[priority.toUpperCase().trim()]; 22 | } 23 | 24 | var result = {}; 25 | eventExecutor = __plugin.getDispatcher(function(l, e) { 26 | function cancel() { 27 | if (e.setCanceled) { 28 | e.setCanceled(); 29 | } 30 | } 31 | /* 32 | let handlers use this.cancel() to cancel the current event 33 | or this.unregister() to unregister from future events. 34 | */ 35 | var bound = {}; 36 | for (var i in result) { 37 | bound[i] = result[i]; 38 | } 39 | bound.cancel = cancel; 40 | try { 41 | handler.call(bound, e, cancel); 42 | } catch (error) { 43 | console.log( 44 | 'Error while executing handler:' + 45 | handler + 46 | ' for event type:' + 47 | eventType + 48 | ' error: ' + 49 | error 50 | ); 51 | } 52 | }); 53 | /* 54 | wph 20130222 issue #64 bad interaction with Essentials plugin 55 | if another plugin tries to unregister a Listener (not a Plugin or a RegisteredListener) 56 | then BOOM! the other plugin will throw an error because Rhino can't coerce an 57 | equals() method from an Interface. 58 | The workaround is to make the ScriptCraftPlugin java class a Listener. 59 | Should only unregister() registered plugins in ScriptCraft js code. 60 | */ 61 | eventType = eventType.class; 62 | regd = new cmPluginListener({}); 63 | cmHookExecutor.registerHook( 64 | regd, 65 | __plugin, 66 | eventType, 67 | eventExecutor, 68 | priority 69 | ); 70 | result.unregister = function() { 71 | cmHookExecutor.unregisterPluginListener(regd); 72 | }; 73 | return result; 74 | }; 75 | -------------------------------------------------------------------------------- /src/main/js/lib/events.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /************************************************************************ 3 | ## events Module 4 | 5 | The Events module provides a thin wrapper around CanaryMod's or 6 | Bukkit's Event-handling API. The Java-based CanaryMod and Bukkit 7 | Events APIs make use of Java Annotations which are not available in 8 | Javascript, so this module provides a simple way to listen to 9 | minecraft events in javascript. 10 | 11 | ### events.on() static method 12 | 13 | This method is used to register event listeners. This method is called by all of the Event Helper methods. 14 | The `events` object has functions for registering listeners for each type of event. For example, you can register a block-break listener using events.on: 15 | 16 | ```javascript 17 | events.on( Packages.net.canarymod.hook.player.BlockDestroyHook, function( evt, cancel ) { 18 | echo(evt.player, evt.player.name + ' broke a block!'); 19 | } ); 20 | ``` 21 | 22 | or you can (and probably should) use the more succinct: 23 | 24 | ```javascript 25 | events.blockDestroy( function( evt, cancel ) { 26 | echo(evt.player, evt.player.name + ' broke a block!'); 27 | } ); 28 | ``` 29 | 30 | The events.on method can be used to register standard CanaryMod/Bukkit 31 | events and can also be used to register non-standard events - that is 32 | - events provided by plugins. 33 | 34 | #### Parameters 35 | 36 | * eventType - A Java class. See the [CanaryMod Hook API][cmEvtApi] or [Bukkit Event API][buk] for details of the many event types. 37 | 38 | * callback - A function which will be called whenever the event 39 | fires. The callback in turn takes 2 parameters: 40 | 41 | - event : the event fired 42 | - cancel : a function which if invoked will cancel the event - not all event types are cancelable; this function only cancels cancelable events). 43 | 44 | * priority (optional - default: "CRITICAL" for CanaryMod or "HIGHEST" for Bukkit) - 45 | The priority the listener/callback takes over other listeners to the same event. 46 | Possible values for CanaryMod are "CRITICAL", "HIGH", "LOW", "NORMAL" and "PASSIVE". 47 | For an explanation of what the different CanaryMod Hook priorities 48 | mean, refer to CanaryMod's [Hook Priority class][cmPriority]. 49 | Possible values for Bukkit are "HIGH", "HIGHEST", "LOW", "LOWEST", "NORMAL", "MONITOR". 50 | For an explanation of what the different Bukkit Event priorities 51 | mean, refer to bukkit's [Event API Reference][buk2]. 52 | 53 | #### Returns 54 | 55 | An object which can be used to unregister the listener. 56 | 57 | #### Example: 58 | 59 | The following code will print a message on screen every time a block is broken in the game 60 | 61 | ```javascript 62 | events.on( Packages.net.canarymod.hook.player.BlockDestroyHook, function( evt, cancel ) { 63 | echo(evt.player, evt.player.name + ' broke a block!'); 64 | } ); 65 | ``` 66 | 67 | To handle an event only once and unregister from further events... 68 | 69 | ```javascript 70 | events.on( Packages.net.canarymod.hook.player.BlockDestroyHook, function( evt, cancel ) { 71 | echo( evt.player, evt.player.name + ' broke a block!'); 72 | this.unregister(); 73 | } ); 74 | ``` 75 | 76 | The `this` keyword when used inside the callback function refers to 77 | the Listener object created by ScriptCraft. It has 2 methods 78 | `unregister()` which can be used to stop listening and `cancel()` 79 | which can be used to cancel the current event. The object returned by 80 | `events.on()` only has the `unregister()` method, the `cancel()` 81 | method is only available from within the event handling function. 82 | 83 | To unregister a listener *outside* of the listener function... 84 | 85 | ```javascript 86 | var myBlockBreakListener = events.on( Packages.net.canarymod.hook.player.BlockDestroyHook, function( evt ) { ... } ); 87 | ... 88 | myBlockBreakListener.unregister(); 89 | ``` 90 | 91 | [buk2]: http://wiki.bukkit.org/Event_API_Reference 92 | [buk]: http://jd.bukkit.org/dev/apidocs/index.html?org/bukkit/event/Event.html 93 | [cmEvtApi]: https://ci.visualillusionsent.net/job/CanaryLib/javadoc/net/canarymod/hook/Hook.html 94 | [cmPriority]: https://ci.visualillusionsent.net/job/CanaryLib/javadoc/net/canarymod/plugin/Priority.html 95 | 96 | ***/ 97 | var helper; 98 | /*global __plugin, module, require*/ 99 | if (__plugin.canary) { 100 | module.exports = require('events-canary'); 101 | helper = require('events-helper-canary'); 102 | // backwards-compatibility with canarymod 1.7.9 for book listings 103 | if (helper.connection && !helper.connect) { 104 | helper.connect = helper.connection; 105 | } 106 | } else { 107 | module.exports = require('events-bukkit'); 108 | helper = require('events-helper-bukkit'); 109 | } 110 | for (var func in helper) { 111 | module.exports[func] = helper[func]; 112 | } 113 | -------------------------------------------------------------------------------- /src/main/js/lib/find.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var File = java.io.File; 3 | module.exports = function find(dir, filter) { 4 | var result = []; 5 | function recurse(dir, store) { 6 | var files, 7 | len, 8 | i, 9 | file, 10 | dirfile = new File(dir); 11 | 12 | if (typeof filter == 'undefined') { 13 | files = dirfile.list(); 14 | } else { 15 | files = dirfile.list(filter); 16 | } 17 | len = files.length; 18 | i = 0; 19 | for (; i < len; i++) { 20 | file = new File(dir + '/' + files[i]); 21 | if (file.isDirectory()) { 22 | recurse(file.canonicalPath, store); 23 | } else { 24 | store.push(('' + file.canonicalPath).replace(/\\\\/g, '/')); 25 | } 26 | } 27 | } 28 | recurse(dir, result); 29 | return result; 30 | }; 31 | -------------------------------------------------------------------------------- /src/main/js/lib/java-utils.js: -------------------------------------------------------------------------------- 1 | exports.isJavaObject = function(o) { 2 | if (o === global) { 3 | return false; 4 | } 5 | if (o !== undefined && o !== null) { 6 | try { 7 | // this throws error for java objects in jre7 8 | if (typeof o.constructor === 'function') { 9 | return false; 10 | } 11 | } catch (e) { 12 | return true; 13 | } 14 | try { 15 | var result = o.getClass ? true : false; // throws error for Enums/Class in jre7 16 | if (result == true) { 17 | return result; 18 | } 19 | } catch (e2) { 20 | // fail silently and move on to next test 21 | } 22 | // java classes don't have a getClass so just because .getClass isn't present 23 | // doesn't mean it's not a Java Enum or Class (.getClass only works for object instances?) 24 | if (o instanceof java.lang.Object) { 25 | return true; 26 | } 27 | } 28 | return o instanceof java.lang.Object; 29 | }; 30 | -------------------------------------------------------------------------------- /src/main/js/lib/js-patch.js: -------------------------------------------------------------------------------- 1 | module.exports = function($) { 2 | // wph 20140105 trim not availabe in String on Mac OS. 3 | if (typeof String.prototype.trim == 'undefined') { 4 | String.prototype.trim = function() { 5 | return this.replace(/^\s+|\s+$/g, ''); 6 | }; 7 | } 8 | 9 | // wph 20140316 Java 1.6.0_65 on mac does not have Function.prototype.bind 10 | // code from http://webreflection.blogspot.ie/2010/02/functionprototypebind.html 11 | if (typeof Function.prototype.bind == 'undefined') { 12 | Function.prototype.bind = (function(slice) { 13 | // (C) WebReflection - Mit Style License 14 | function bind(context) { 15 | var self = this; // "trapped" function reference 16 | // only if there is more than an argument 17 | // we are interested into more complex operations 18 | // this will speed up common bind creation 19 | // avoiding useless slices over arguments 20 | if (1 < arguments.length) { 21 | // extra arguments to send by default 22 | var $arguments = slice.call(arguments, 1); 23 | return function() { 24 | return self.apply( 25 | context, 26 | // thanks @kangax for this suggestion 27 | arguments.length 28 | ? // concat arguments with those received 29 | $arguments.concat(slice.call(arguments)) 30 | : // send just arguments, no concat, no slice 31 | $arguments 32 | ); 33 | }; 34 | } 35 | // optimized callback 36 | return function() { 37 | // speed up when function is called without arguments 38 | return arguments.length 39 | ? self.apply(context, arguments) 40 | : self.call(context); 41 | }; 42 | } 43 | // the named function 44 | return bind; 45 | })(Array.prototype.slice); 46 | } 47 | 48 | if (__plugin.canary) { 49 | require('task-canary')($); 50 | } else { 51 | require('task-bukkit')($); 52 | } 53 | 54 | return function unitTest(console) { 55 | /* 56 | sanity tests 57 | */ 58 | $.setTimeout(function() { 59 | console.log('js-patch setTimeout() test complete'); 60 | }, 100); 61 | var clearMe = $.setTimeout(function() { 62 | console.error('js-patch clearTimeout() test failed'); 63 | }, 100); 64 | $.clearTimeout(clearMe); 65 | 66 | var runs = 3; 67 | var clearAfterRuns = $.setInterval(function() { 68 | runs--; 69 | if (runs == 0) { 70 | $.clearInterval(clearAfterRuns); 71 | } 72 | if (runs < 0) { 73 | console.error('js-patch clearInterval test failed.'); 74 | } 75 | }, 100); 76 | }; 77 | }; 78 | -------------------------------------------------------------------------------- /src/main/js/lib/legacy-check.js: -------------------------------------------------------------------------------- 1 | var File = java.io.File; 2 | /* 3 | wph 20140102 - warn if legacy 'mcserver/js-plugins' or 4 | 'mcserver/plugins/scriptcraft' directories are present 5 | */ 6 | module.exports = function(jsPluginsRootDir) { 7 | var mcServerDir = new File(jsPluginsRootDir.canonicalPath).parentFile; 8 | if (mcServerDir == null) { 9 | console.warn( 10 | 'Could not find parent directory for ' + jsPluginsRootDir.canonicalPath 11 | ); 12 | return; 13 | } 14 | var legacyExists = false, 15 | legacyDirs = [new File(mcServerDir, 'js-plugins')]; 16 | 17 | for (var i = 0; i < legacyDirs.length; i++) { 18 | if (legacyDirs[i].exists() && legacyDirs[i].isDirectory()) { 19 | legacyExists = true; 20 | 21 | console.warn( 22 | 'Legacy ScriptCraft directory %s was found. This directory is no longer used.', 23 | legacyDirs[i].canonicalPath 24 | ); 25 | console.warn( 26 | 'Please put plugins in the ' + 27 | jsPluginsRootDir.canonicalPath + 28 | '/plugins directory' 29 | ); 30 | } 31 | } 32 | if (legacyExists) { 33 | console.info( 34 | 'The working directory for %s is %s', 35 | __plugin, 36 | jsPluginsRootDir.canonicalPath 37 | ); 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /src/main/js/lib/persistence.js: -------------------------------------------------------------------------------- 1 | var _dataDir = null, 2 | _persistentData = {}; 3 | 4 | module.exports = function(rootDir, $) { 5 | var _load = function(name) { 6 | var result = $.scloadJSON( 7 | _dataDir.canonicalPath + '/' + name + '-store.json' 8 | ); 9 | return result; 10 | }; 11 | 12 | var _save = function(name, objToSave) { 13 | $.scsave(objToSave, _dataDir.canonicalPath + '/' + name + '-store.json'); 14 | }; 15 | 16 | _dataDir = new java.io.File(rootDir, 'data'); 17 | 18 | $.persist = function(name, data, write) { 19 | var i, dataFromFile; 20 | if (typeof data == 'undefined') { 21 | data = {}; 22 | } 23 | if (typeof write == 'undefined') { 24 | write = false; 25 | } 26 | if (!write) { 27 | dataFromFile = _load(name); 28 | if (typeof dataFromFile != 'undefined') { 29 | for (i in dataFromFile) { 30 | data[i] = dataFromFile[i]; 31 | } 32 | } 33 | } else { 34 | // flush data to file 35 | _save(name, data); 36 | } 37 | _persistentData[name] = data; 38 | return data; 39 | }; 40 | /* 41 | persist on shutdown 42 | */ 43 | $.addUnloadHandler(function() { 44 | var name, data; 45 | for (name in _persistentData) { 46 | data = _persistentData[name]; 47 | _save(name, data); 48 | } 49 | }); 50 | }; 51 | -------------------------------------------------------------------------------- /src/main/js/lib/plugin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global persist,exports,config,__plugin,require*/ 3 | var find = require('./find'); 4 | /* 5 | plugin management 6 | */ 7 | var _plugins = {}; 8 | 9 | function _plugin( 10 | /* String */ moduleName, 11 | /* Object */ moduleObject, 12 | isPersistent 13 | ) { 14 | // 15 | // don't load plugin more than once 16 | // 17 | if (typeof _plugins[moduleName] != 'undefined') { 18 | return _plugins[moduleName].module; 19 | } 20 | 21 | var pluginData = { persistent: isPersistent, module: moduleObject }; 22 | if (typeof moduleObject.store == 'undefined') { 23 | moduleObject.store = {}; 24 | } 25 | _plugins[moduleName] = pluginData; 26 | 27 | if (isPersistent) { 28 | moduleObject.store = persist(moduleName, moduleObject.store); 29 | } 30 | return moduleObject; 31 | } 32 | 33 | function _autoload(context, pluginDir, options) { 34 | /* 35 | Reload all of the .js files in the given directory 36 | */ 37 | var sourceFiles = [], 38 | property, 39 | module, 40 | pluginPath; 41 | sourceFiles = find(pluginDir); 42 | 43 | var len = sourceFiles.length; 44 | if (config && config.verbose) { 45 | console.info(len + ' scriptcraft plugins found in ' + pluginDir); 46 | } 47 | 48 | for (var i = 0; i < len; i++) { 49 | pluginPath = sourceFiles[i]; 50 | if (!pluginPath.match(/\.js$/)) { 51 | continue; 52 | } 53 | module = {}; 54 | 55 | try { 56 | module = require(pluginPath, options); 57 | for (property in module) { 58 | /* 59 | all exports in plugins become members of context object 60 | */ 61 | context[property] = module[property]; 62 | } 63 | } catch (e) { 64 | var msg = 'Plugin ' + pluginPath + ' ' + e; 65 | console.error(msg); 66 | } 67 | } 68 | } 69 | exports.plugin = _plugin; 70 | exports.autoload = _autoload; 71 | -------------------------------------------------------------------------------- /src/main/js/lib/readme.md: -------------------------------------------------------------------------------- 1 | # lib directory 2 | 3 | This directory contains core scriptcraft files and modules. 4 | 5 | * plugin.js - A module which provides support for persistent plugins (plugins which need to save state) 6 | * require.js - The require() function implementation. See [Node.js modules] documentation. 7 | * scriptcraft.js - The core scriptcraft code. 8 | * events.js - Event handling module for use by plugin/module developers. 9 | 10 | When `require('modulename')` is called, if a file in the current working directory called 'modulename' is not found then the `lib` folder is the first location that `require()` looks for modules. 11 | 12 | [njsmod]: http://nodejs.org/api/modules.html 13 | -------------------------------------------------------------------------------- /src/main/js/lib/tabcomplete-jsp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var _commands = require('command').commands; 3 | /* 4 | Tab completion for the /jsp commmand 5 | */ 6 | var __onTabCompleteJSP = function(result, cmdArgs) { 7 | var cmdInput = cmdArgs[0], 8 | opts, 9 | cmd, 10 | len, 11 | i; 12 | cmd = _commands[cmdInput]; 13 | if (cmd) { 14 | if (typeof cmd.options === 'function') { 15 | opts = cmd.options(); 16 | } else { 17 | opts = cmd.options; 18 | } 19 | len = opts.length; 20 | if (cmdArgs.length > 1) { 21 | // partial e.g. /jsp chat_color dar 22 | for (i = 0; i < len; i++) { 23 | if (opts[i].indexOf(cmdArgs[1]) == 0) { 24 | result.add(opts[i]); 25 | } 26 | } 27 | } 28 | } else { 29 | if (cmdArgs.length == 0) { 30 | for (i in _commands) { 31 | result.add(i); 32 | } 33 | } else { 34 | // partial e.g. /jsp ho 35 | // should tabcomplete to home 36 | // 37 | for (i in _commands) { 38 | if (i.indexOf(cmdInput) == 0) { 39 | result.add(i); 40 | } 41 | } 42 | } 43 | } 44 | return result; 45 | }; 46 | module.exports = __onTabCompleteJSP; 47 | -------------------------------------------------------------------------------- /src/main/js/lib/task-bukkit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global __plugin, module, server*/ 3 | function bukkitSetTimeout(callback, delayInMillis) { 4 | var delay = Math.ceil(delayInMillis / 50); 5 | 6 | // This does not work, as GraalJS does not enable picking the specific runTaskLater() 7 | // overloaded funciton out of the different possibilities as Nashorn does 8 | // (see https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/javascript.html and 9 | // https://www.gitmemory.com/issue/graalvm/graaljs/37/739925131 10 | // In principle, GraalJS should support this method but at least in GraalJS 21.2.0 this is not working. 11 | // Reverting to work-around as per https://github.com/walterhiggins/ScriptCraft/issues/396 12 | // 13 | // var task = server.scheduler[ 14 | // 'runTaskLater(org.bukkit.plugin.Plugin, java.lang.Runnable ,long)' 15 | // ](__plugin, callback, delay); 16 | var Run = Java.type('java.lang.Runnable'); 17 | var MyRun = Java.extend(Run, { 18 | run: callback 19 | }); 20 | var task = server.scheduler.runTaskLater(__plugin, new MyRun(), delay); 21 | 22 | return task; 23 | } 24 | function bukkitClearTimeout(task) { 25 | task.cancel(); 26 | } 27 | function bukkitSetInterval(callback, intervalInMillis) { 28 | var delay = Math.ceil(intervalInMillis / 50); 29 | // See comment in bukkitSetTimeout() 30 | // var task = server.scheduler[ 31 | // 'runTaskTimer(org.bukkit.plugin.Plugin, java.lang.Runnable ,long, long)' 32 | // ](__plugin, callback, delay, delay); 33 | var Run = Java.type('java.lang.Runnable'); 34 | var MyRun = Java.extend(Run, { 35 | run: callback 36 | }); 37 | var task = server.scheduler.runTaskTimer(__plugin, new MyRun(), delay, delay); 38 | 39 | return task; 40 | } 41 | function bukkitClearInterval(bukkitTask) { 42 | bukkitTask.cancel(); 43 | } 44 | module.exports = function($) { 45 | $.setTimeout = bukkitSetTimeout; 46 | $.clearTimeout = bukkitClearTimeout; 47 | $.setInterval = bukkitSetInterval; 48 | $.clearInterval = bukkitClearInterval; 49 | }; 50 | -------------------------------------------------------------------------------- /src/main/js/lib/task-canary.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global Packages, __plugin, module*/ 3 | /* 4 | javascript programmers familiar with setTimeout know that it expects 5 | a delay in milliseconds. However, bukkit's scheduler expects a delay in ticks 6 | (where 1 tick = 1/20th second) 7 | */ 8 | function canarySetTimeout(callback, delayInMillis) { 9 | var cmTaskManager = Packages.net.canarymod.tasks.ServerTaskManager; 10 | var delay = Math.ceil(delayInMillis / 50); 11 | var task = __plugin.createServerTask(callback, delay, false); 12 | cmTaskManager.addTask(task); 13 | return task; 14 | } 15 | function canaryClearTimeout(task) { 16 | var cmTaskManager = Packages.net.canarymod.tasks.ServerTaskManager; 17 | cmTaskManager.removeTask(task); 18 | } 19 | function canarySetInterval(callback, intervalInMillis) { 20 | var cmTaskManager = Packages.net.canarymod.tasks.ServerTaskManager; 21 | var delay = Math.ceil(intervalInMillis / 50); 22 | var task = __plugin.createServerTask(callback, delay, true); 23 | cmTaskManager.addTask(task); 24 | return task; 25 | } 26 | function canaryClearInterval(task) { 27 | var cmTaskManager = Packages.net.canarymod.tasks.ServerTaskManager; 28 | cmTaskManager.removeTask(task); 29 | } 30 | module.exports = function($) { 31 | $.setTimeout = canarySetTimeout; 32 | $.clearTimeout = canaryClearTimeout; 33 | $.setInterval = canarySetInterval; 34 | $.clearInterval = canaryClearInterval; 35 | }; 36 | -------------------------------------------------------------------------------- /src/main/js/modules/at.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var utils = require('utils'); 3 | /************************************************************************ 4 | ## The at Module 5 | 6 | The at module provides a single function `at()` which can be used to schedule 7 | repeating (or non-repeating) tasks to be done at a particular time. 8 | 9 | ### at() function 10 | 11 | The utils.at() function will perform a given task at a given time in the 12 | (minecraft) day. 13 | 14 | #### Parameters 15 | 16 | * time24hr : The time in 24hr form - e.g. 9:30 in the morning is '09:30' while 9:30 pm is '21:30', midnight is '00:00' and midday is '12:00' 17 | * callback : A javascript function which will be invoked at the given time. 18 | * worlds : (optional) An array of worlds. Each world has its own clock. If no array of worlds is specified, all the server's worlds are used. 19 | * repeat : (optional) true or false, default is true (repeat the task every day) 20 | 21 | #### Example 22 | 23 | To warn players when night is approaching: 24 | 25 | ```javascript 26 | var utils = require('utils'), 27 | at = require('at'); 28 | function warning(){ 29 | utils.players(function( player ) { 30 | echo( player, 'The night is dark and full of terrors!' ); 31 | }); 32 | } 33 | at('19:00', warning); 34 | ``` 35 | To run a task only once at the next given time: 36 | ```javascript 37 | var utils = require('utils'), 38 | at = require('at'); 39 | function wakeup(){ 40 | utils.players(function( player ) { 41 | echo( player, "Wake Up Folks!" ); 42 | }); 43 | } 44 | at('06:00', wakeup, null, false); 45 | ``` 46 | 47 | ***/ 48 | var SECOND = 1000; 49 | var POLLING_INTERVAL = 3 * SECOND; // this is probably precise enough 50 | 51 | function at(time24hr, callback, pWorlds, repeat) { 52 | if (arguments.length === 0) { 53 | // TODO: Document this behaviour 54 | console.log(tasksToString()); 55 | return; 56 | } 57 | var timeParts = time24hr.split(':'); 58 | var timeMins = timeParts[0] * 60 + timeParts[1] * 1; 59 | if (!pWorlds || pWorlds === undefined) { 60 | pWorlds = utils.worlds(); 61 | } 62 | if (repeat === undefined) { 63 | repeat = true; 64 | } 65 | utils.foreach(pWorlds, function(world) { 66 | atAddTask(timeMins, callback, world, repeat); 67 | }); 68 | } 69 | var atTasks = {}; 70 | 71 | function tasksToString() { 72 | var result = ''; 73 | for (var world in atTasks) { 74 | result += 'world: ' + world + '\n'; 75 | for (var time in atTasks[world]) { 76 | var scheduledFuncs = atTasks[world][time]; 77 | for (var i = 0; i < scheduledFuncs.length; i++) { 78 | result += ' ' + time + ': ' + scheduledFuncs[i].constructor + '\n'; 79 | } 80 | } 81 | result += '(current world time: ' + utils.time24(world) + ')\n'; 82 | } 83 | return result; 84 | } 85 | /* 86 | constructs a function which will be called every x ticks to 87 | track the schedule for a given world 88 | */ 89 | function atMonitorFactory(world) { 90 | var worldName = '' + world.name; 91 | var lastRun = null; 92 | 93 | return function atMonitorForWorld() { 94 | var timeMins = utils.time24(world); 95 | if (timeMins === lastRun) { 96 | return; 97 | } 98 | if (lastRun === null) { 99 | lastRun = timeMins - 1; 100 | } else { 101 | lastRun = lastRun % 1440; 102 | } 103 | var worldSchedule = atTasks[worldName]; 104 | if (!worldSchedule) { 105 | return; 106 | } 107 | while (lastRun > timeMins ? lastRun <= 1440 : lastRun < timeMins) { 108 | var tasks = worldSchedule[lastRun++]; 109 | if (!tasks) { 110 | continue; 111 | } 112 | utils.foreach(tasks, function(task, i) { 113 | if (!task) { 114 | return; 115 | } 116 | setTimeout(task.callback.bind(null, timeMins, world), 1); 117 | if (!task.repeat) { 118 | tasks[i] = null; 119 | } 120 | }); 121 | } 122 | }; 123 | } 124 | function atAddTask(timeMins, callback, world, repeat) { 125 | var worldName = '' + world.name; 126 | if (!atTasks[worldName]) { 127 | atTasks[worldName] = {}; 128 | } 129 | if (!atTasks[worldName][timeMins]) { 130 | atTasks[worldName][timeMins] = []; 131 | } 132 | atTasks[worldName][timeMins].push({ callback: callback, repeat: repeat }); 133 | } 134 | var atMonitors = []; 135 | function onLoadStartMonitor(event) { 136 | var monitor = setInterval(atMonitorFactory(event.world), POLLING_INTERVAL); 137 | atMonitors.push(monitor); 138 | } 139 | if (__plugin.canary) { 140 | events.loadWorld(onLoadStartMonitor); 141 | } 142 | if (__plugin.bukkit) { 143 | events.worldLoad(onLoadStartMonitor); 144 | } 145 | 146 | addUnloadHandler(function() { 147 | utils.foreach(atMonitors, function(atInterval) { 148 | clearInterval(atInterval); 149 | }); 150 | }); 151 | 152 | module.exports = at; 153 | -------------------------------------------------------------------------------- /src/main/js/modules/babel-register.js: -------------------------------------------------------------------------------- 1 | var babel = require('babel'); 2 | function xform(code) { 3 | return babel.transform(code, { presets: ['es2015'] }).code; 4 | } 5 | function xformVerbose(code) { 6 | var js = babel.transform(code, { presets: ['es2015'] }).code; 7 | console.log(js); 8 | return js; 9 | } 10 | var len = global._moduleHooks.length; 11 | var registered = false; 12 | for (var i = 0; i < len; i++) { 13 | if (global._moduleHooks[i] === xform) { 14 | registered = true; 15 | break; 16 | } 17 | } 18 | if (!registered) { 19 | global._moduleHooks.unshift(xform); 20 | global._replHooks.unshift(xformVerbose); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/js/modules/block-colors.js: -------------------------------------------------------------------------------- 1 | var colors = { 2 | white: 0, 3 | orange: 1, 4 | magenta: 2, 5 | lightblue: 3, 6 | yellow: 4, 7 | lime: 5, 8 | pink: 6, 9 | gray: 7, 10 | lightgray: 8, 11 | cyan: 9, 12 | purple: 10, 13 | blue: 11, 14 | brown: 12, 15 | green: 13, 16 | red: 14, 17 | black: 15 18 | }; 19 | module.exports = colors; 20 | -------------------------------------------------------------------------------- /src/main/js/modules/bukkit/fireworks.js: -------------------------------------------------------------------------------- 1 | /* 2 | create a firework at the given location 3 | */ 4 | function bukkitFirework(location) { 5 | var bkColor = org.bukkit.Color; 6 | var bkFireworkEffect = org.bukkit.FireworkEffect; 7 | var bkEntityType = org.bukkit.entity.EntityType; 8 | 9 | var randInt = function(n) { 10 | return Math.floor(Math.random() * n); 11 | }; 12 | var getColor = function(i) { 13 | var colors = [ 14 | bkColor.AQUA, 15 | bkColor.BLACK, 16 | bkColor.BLUE, 17 | bkColor.FUCHSIA, 18 | bkColor.GRAY, 19 | bkColor.GREEN, 20 | bkColor.LIME, 21 | bkColor.MAROON, 22 | bkColor.NAVY, 23 | bkColor.OLIVE, 24 | bkColor.ORANGE, 25 | bkColor.PURPLE, 26 | bkColor.RED, 27 | bkColor.SILVER, 28 | bkColor.TEAL, 29 | bkColor.WHITE, 30 | bkColor.YELLOW 31 | ]; 32 | return colors[i]; 33 | }; 34 | var fw = location.world.spawnEntity(location, bkEntityType.FIREWORK); 35 | var fwm = fw.getFireworkMeta(); 36 | var fwTypes = [ 37 | bkFireworkEffect.Type.BALL, 38 | bkFireworkEffect.Type.BALL_LARGE, 39 | bkFireworkEffect.Type.BURST, 40 | bkFireworkEffect.Type.CREEPER, 41 | bkFireworkEffect.Type.STAR 42 | ]; 43 | var type = fwTypes[randInt(5)]; 44 | 45 | var r1i = randInt(17); 46 | var r2i = randInt(17); 47 | var c1 = getColor(r1i); 48 | var c2 = getColor(r2i); 49 | var effectBuilder = bkFireworkEffect 50 | .builder() 51 | .flicker(Math.round(Math.random()) == 0) 52 | .withColor(c1) 53 | .withFade(c2) 54 | .trail(Math.round(Math.random()) == 0); 55 | effectBuilder['with'](type); 56 | var effect = effectBuilder.build(); 57 | fwm.addEffect(effect); 58 | fwm.setPower(randInt(2) + 1); 59 | fw.setFireworkMeta(fwm); 60 | } 61 | module.exports = bukkitFirework; 62 | -------------------------------------------------------------------------------- /src/main/js/modules/bukkit/input.js: -------------------------------------------------------------------------------- 1 | var bkPrompt = org.bukkit.conversations.Prompt, 2 | bkConversationFactory = org.bukkit.conversations.ConversationFactory; 3 | 4 | function bukkitAsyncInput(sender, promptMesg, callback) { 5 | var repeat = function() { 6 | bukkitAsyncInput(sender, promptMesg, callback); 7 | }; 8 | var prompt = new bkPrompt({ 9 | getPromptText: function(/* ctx */) { 10 | return promptMesg; 11 | }, 12 | acceptInput: function(ctx, value) { 13 | callback.apply( 14 | { repeat: repeat, sender: sender, message: promptMesg, value: value }, 15 | [value, sender, repeat] 16 | ); 17 | return null; 18 | }, 19 | blocksForInput: function(/* ctx */) { 20 | return true; 21 | } 22 | }); 23 | 24 | new bkConversationFactory(__plugin) 25 | .withModality(false) 26 | .withFirstPrompt(prompt) 27 | .buildConversation(sender) 28 | .begin(); 29 | } 30 | module.exports = bukkitAsyncInput; 31 | -------------------------------------------------------------------------------- /src/main/js/modules/bukkit/inventory.js: -------------------------------------------------------------------------------- 1 | function inventory(entity) { 2 | var inv = entity.inventory; 3 | var result = { 4 | add: function(items) { 5 | inv.addItem([items]); 6 | return result; 7 | }, 8 | remove: function(items) { 9 | inv.removeItem([items]); 10 | return result; 11 | }, 12 | contains: function(items) { 13 | return inv['contains(org.bukkit.inventory.ItemStack)'](items); 14 | } 15 | }; 16 | return result; 17 | } 18 | module.exports = inventory; 19 | -------------------------------------------------------------------------------- /src/main/js/modules/bukkit/items.js: -------------------------------------------------------------------------------- 1 | /*global require, module, Packages */ 2 | var bkItemStack = Packages.org.bukkit.inventory.ItemStack; 3 | var bkMaterial = Packages.org.bukkit.Material; 4 | var items = function(material, amount) { 5 | material = material.toUpperCase(); 6 | return new bkItemStack(bkMaterial[material], amount); 7 | }; 8 | 9 | var materials = bkMaterial.values(); 10 | 11 | for (var i = 0; i < materials.length; i++) { 12 | var name = ('' + materials[i].name()).toLowerCase(); 13 | name = name.replace(/(_.)/g, function(a) { 14 | return a.replace(/_/, '').toUpperCase(); 15 | }); 16 | 17 | items[name] = (function(material) { 18 | return function(amount) { 19 | if (typeof amount == 'undefined') { 20 | return material; 21 | } 22 | if (typeof amount == 'number') { 23 | return new bkItemStack(material, amount); 24 | } else { 25 | return amount == material; 26 | } 27 | }; 28 | })(materials[i]); 29 | } 30 | 31 | module.exports = items; 32 | -------------------------------------------------------------------------------- /src/main/js/modules/bukkit/recipes.js: -------------------------------------------------------------------------------- 1 | var bkShapedRecipe = org.bukkit.inventory.ShapedRecipe; 2 | 3 | exports.add = function(recipe) { 4 | var result = new bkShapedRecipe(recipe.result); 5 | result.shape(recipe.shape[0], recipe.shape[1], recipe.shape[2]); 6 | for (var i in recipe.ingredients) { 7 | result.setIngredient( 8 | new java.lang.Character(i), 9 | recipe.ingredients[i].getData() 10 | ); 11 | } 12 | server.addRecipe(result); 13 | return result; 14 | }; 15 | exports.remove = function(recipe) { 16 | server.removeRecipe(recipe); 17 | }; 18 | -------------------------------------------------------------------------------- /src/main/js/modules/bukkit/sounds.js: -------------------------------------------------------------------------------- 1 | var bkLocation = Packages.org.bukkit.Location, 2 | i = 0, 3 | foreach = require('utils').foreach, 4 | allSounds = Packages.org.bukkit.Sound.values(), 5 | len = allSounds.length, 6 | sound, 7 | soundName; 8 | 9 | function play(sound, locationOrHasLocation, volume, pitch) { 10 | var location = null; 11 | if (!locationOrHasLocation) return; 12 | if (locationOrHasLocation instanceof bkLocation) { 13 | location = locationOrHasLocation; 14 | } else { 15 | locationOrHasLocation = locationOrHasLocation.location; 16 | if (locationOrHasLocation && locationOrHasLocation instanceof bkLocation) { 17 | location = locationOrHasLocation; 18 | } 19 | } 20 | if (!location) { 21 | console.warn('sounds.play() needs a location'); 22 | return; 23 | } 24 | if (typeof volume == 'undefined') volume = 1; 25 | if (typeof pitch == 'undefined') pitch = 1; 26 | location.world.playSound(location, sound, volume, pitch); 27 | } 28 | 29 | for (; i < len; i++) { 30 | sound = allSounds[i]; 31 | soundName = '' + sound.name(); 32 | var methodName = soundName.toLowerCase().replace(/_(.)/g, function(a, b) { 33 | return b.toUpperCase(); 34 | }); 35 | exports[methodName] = (function(sound) { 36 | return function() { 37 | switch (arguments.length) { 38 | case 3: 39 | exports.play(sound, arguments[0], arguments[1], arguments[2]); 40 | break; 41 | case 2: 42 | // TODO: possible combinations: 43 | // location, volume, 44 | // volume pitch 45 | exports.play(sound, arguments[0], arguments[1]); 46 | break; 47 | case 1: 48 | exports.play(sound, arguments[0]); 49 | break; 50 | case 0: 51 | // play the sound at full vol, medium pitch for all players 52 | // 53 | foreach(server.onlinePlayers, function(player) { 54 | exports.play(sound, player, 1, 0); 55 | }); 56 | break; 57 | default: 58 | } 59 | }; 60 | })(sound); 61 | } 62 | exports.play = play; 63 | -------------------------------------------------------------------------------- /src/main/js/modules/canary/fireworks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require, Packages, module*/ 3 | var items = require('items'); 4 | var Canary = Packages.net.canarymod.Canary; 5 | var cmFireworkHelper = 6 | Packages.net.canarymod.api.inventory.helper.FireworkHelper; 7 | var cmExplosionType = 8 | Packages.net.canarymod.api.inventory.helper.FireworkHelper.ExplosionType; 9 | var explosionTypes = ['STAR', 'BURST', 'CREEPER', 'LARGE', 'SMALL']; 10 | var cmDyeColor = Packages.net.canarymod.api.DyeColor; 11 | var entityFactory = Canary.factory().entityFactory; 12 | var cmEntityType = Packages.net.canarymod.api.entity.EntityType; 13 | 14 | function canaryFirework(location) { 15 | var firework = items.fireworkStar(1); 16 | cmFireworkHelper.addStarColors(firework, cmDyeColor.values()); 17 | cmFireworkHelper.setDoesFlicker(firework, true); 18 | cmFireworkHelper.setDoesTrail(firework, true); 19 | 20 | // use a random explosion type 21 | var rnd = Math.floor(Math.random() * explosionTypes.length); 22 | var type = explosionTypes[rnd]; 23 | cmFireworkHelper.setStarExplosionType(firework, cmExplosionType[type]); 24 | var rocket = items.fireworkRocket(1); 25 | cmFireworkHelper.setFlightDuration(rocket, 3); 26 | cmFireworkHelper.attachFireworkStars(rocket, [firework]); 27 | var rocketEntity = entityFactory.newEntity( 28 | cmEntityType.FIREWORKROCKET, 29 | location 30 | ); 31 | rocketEntity.item = rocket; 32 | rocketEntity.spawn(); 33 | } 34 | 35 | module.exports = canaryFirework; 36 | -------------------------------------------------------------------------------- /src/main/js/modules/canary/input.js: -------------------------------------------------------------------------------- 1 | function canaryAsyncInput(sender, promptMesg, callback) { 2 | sender.message(promptMesg); 3 | function repeat() { 4 | setTimeout(function() { 5 | listener.unregister(); // avoid CME 6 | canaryAsyncInput(sender, promptMesg, callback); 7 | }, 1); 8 | } 9 | var listener = events.chat(function(event) { 10 | if (event.player == sender) { 11 | var receivers = event.getReceiverList(); 12 | if (receivers.size() == 1 && receivers.contains(sender)) { 13 | var value = event.message; 14 | var that = this; 15 | event.setCanceled(); 16 | callback.apply( 17 | { repeat: repeat, sender: sender, message: promptMesg, value: value }, 18 | [value, sender, repeat] 19 | ); 20 | setTimeout(function() { 21 | that.unregister(); 22 | }, 10); 23 | } 24 | } 25 | }, 'CRITICAL'); 26 | // unregister after 30 seconds 27 | setTimeout(function() { 28 | listener.unregister(); 29 | }, 30000); 30 | } 31 | module.exports = canaryAsyncInput; 32 | -------------------------------------------------------------------------------- /src/main/js/modules/canary/inventory.js: -------------------------------------------------------------------------------- 1 | function inventory(entity) { 2 | var inv = entity.inventory; 3 | var result = { 4 | add: function(items) { 5 | inv['addItem(net.canarymod.api.inventory.Item)'](items); 6 | return result; 7 | }, 8 | remove: function(items) { 9 | inv['decreaseItemStackSize(int, int)'](items.id, items.amount); 10 | return result; 11 | }, 12 | contains: function(items) { 13 | var type = items.type; 14 | var amount = items.amount; 15 | return inv['hasItemStack(ItemType, int )'](type, amount); 16 | } 17 | }; 18 | return result; 19 | } 20 | module.exports = inventory; 21 | -------------------------------------------------------------------------------- /src/main/js/modules/canary/items.js: -------------------------------------------------------------------------------- 1 | /*global require, Packages, module*/ 2 | var ItemType = Packages.net.canarymod.api.inventory.ItemType; 3 | var Canary = Packages.net.canarymod.Canary; 4 | var itemFactory = Canary.factory().itemFactory; 5 | 6 | function items(material, amount) { 7 | material = material.toUpperCase(); 8 | var result = itemFactory['newItem(net.canarymod.api.inventory.ItemType)']( 9 | material 10 | ); 11 | result.amount = amount; 12 | return result; 13 | } 14 | function getMaterialHandler(material) { 15 | return function(amount) { 16 | if (typeof amount == 'undefined') { 17 | return material; 18 | } 19 | if (typeof amount == 'number') { 20 | var itemStack = itemFactory[ 21 | 'newItem(net.canarymod.api.inventory.ItemType)' 22 | ](material); 23 | itemStack.amount = amount; 24 | return itemStack; 25 | } else { 26 | var result = amount == material; 27 | if (!result) { 28 | if (amount.getId && amount.getData) { 29 | var m2 = ItemType.fromIdAndData(amount.id, amount.data); 30 | result = m2 == material; 31 | } 32 | } 33 | return result; 34 | } 35 | }; 36 | } 37 | 38 | var itemTypeClass = ItemType.class; 39 | var materials = itemTypeClass.getDeclaredFields(); 40 | var name; 41 | for (var i = 0; i < materials.length; i++) { 42 | if (materials[i].type != itemTypeClass) { 43 | continue; 44 | } 45 | var materialField = materials[i]; 46 | name = '' + materialField.name; 47 | name = name.replace(/^(.)/, function(a) { 48 | return a.toLowerCase(); 49 | }); 50 | 51 | items[name] = getMaterialHandler(materialField.get(ItemType)); 52 | } 53 | 54 | module.exports = items; 55 | -------------------------------------------------------------------------------- /src/main/js/modules/canary/recipes.js: -------------------------------------------------------------------------------- 1 | var cm = Packages.net.canarymod; 2 | var cmRecipe = cm.api.inventory.recipes.CraftingRecipe; 3 | var cmRecipeRow = cm.api.inventory.recipes.RecipeRow; 4 | 5 | function addRecipe(recipe) { 6 | return server.addRecipe(createRecipe(recipe)); 7 | } 8 | function createRecipe(recipe) { 9 | if (!recipe) { 10 | return null; 11 | } 12 | var result, rows, i, j, cells, rr; 13 | if (recipe.shape) { 14 | rows = []; 15 | for (i = 0; i < recipe.shape.length; i++) { 16 | cells = recipe.shape[i].split(''); 17 | rr = []; 18 | for (j = 0; j < cells.length; j++) { 19 | if (cells[j] != ' ') { 20 | rr.push(recipe.ingredients[cells[j]]); 21 | } 22 | } 23 | rows.push(new cmRecipeRow(recipe.shape[i], rr)); 24 | } 25 | /* 26 | wph 20150607 short-term workaround for nashorn defect 27 | https://bugs.openjdk.java.net/browse/JDK-8072596 28 | */ 29 | if (typeof Java !== 'undefined' && typeof Java.type === 'function') { 30 | var RecipeRowArrayType = Java.type( 31 | 'net.canarymod.api.inventory.recipes.RecipeRow[]' 32 | ); 33 | rows = Java.to(rows, RecipeRowArrayType); 34 | } 35 | result = cmRecipe.createShapedRecipe(recipe.result, rows); 36 | } else { 37 | result = cmRecipe.createShapelessRecipe(recipe.result, recipe.ingredients); 38 | } 39 | return result; 40 | } 41 | function removeRecipe(recipe) { 42 | server.removeRecipe(recipe); 43 | } 44 | exports.create = createRecipe; 45 | exports.add = addRecipe; 46 | exports.remove = removeRecipe; 47 | -------------------------------------------------------------------------------- /src/main/js/modules/canary/sounds.js: -------------------------------------------------------------------------------- 1 | var allSounds = Packages.net.canarymod.api.world.effects.SoundEffect.Type.values(), 2 | cmSoundEffect = Packages.net.canarymod.api.world.effects.SoundEffect, 3 | foreach = require('utils').foreach, 4 | i = 0, 5 | len = allSounds.length, 6 | sound, 7 | soundName; 8 | 9 | function playSound(sound, locationOrHasLocation, volume, pitch) { 10 | var location = null; 11 | if (!locationOrHasLocation) return; 12 | if (locationOrHasLocation.world) { 13 | location = locationOrHasLocation; 14 | } else { 15 | locationOrHasLocation = locationOrHasLocation.location; 16 | if (locationOrHasLocation && locationOrHasLocation.world) { 17 | location = locationOrHasLocation; 18 | } 19 | } 20 | if (!location) { 21 | console.warn('sounds.play() needs a location'); 22 | return; 23 | } 24 | if (typeof volume == 'undefined') volume = 1; 25 | if (typeof pitch == 'undefined') pitch = 1; 26 | var soundEffect = new cmSoundEffect( 27 | sound, 28 | location.x, 29 | location.y, 30 | location.z, 31 | volume, 32 | pitch 33 | ); 34 | location.world.playSound(soundEffect); 35 | } 36 | 37 | for (; i < len; i++) { 38 | sound = allSounds[i]; 39 | soundName = '' + sound.name(); 40 | var methodName = soundName.toLowerCase().replace(/_(.)/g, function(a, b) { 41 | return b.toUpperCase(); 42 | }); 43 | exports[methodName] = (function(sound) { 44 | return function() { 45 | switch (arguments.length) { 46 | case 3: 47 | playSound(sound, arguments[0], arguments[1], arguments[2]); 48 | break; 49 | case 2: 50 | // TODO: possible combinations: 51 | // location, volume, 52 | // volume pitch 53 | playSound(sound, arguments[0], arguments[1]); 54 | break; 55 | case 1: 56 | playSound(sound, arguments[0]); 57 | break; 58 | case 0: 59 | // play the sound at full vol, medium pitch for all players 60 | // 61 | foreach(server.playerList, function(player) { 62 | playSound(sound, player, 1, 0); 63 | }); 64 | default: 65 | } 66 | }; 67 | })(sound); 68 | } 69 | 70 | exports.play = playSound; 71 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/bed.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var blocks = require('blocks'); 3 | /************************************************************************ 4 | ### Drone.bed() method 5 | 6 | Creates a bed. The foot of the bed will be at the drone's location and 7 | the head of the bed will extend away from the drone. 8 | 9 | #### Example 10 | To create a bed at the in-game prompt, look at a block then type: 11 | 12 | ```javascript 13 | /js bed() 14 | ``` 15 | 16 | Like most Drone methods, this returns the drone so it can be chained like so: 17 | 18 | ```javascript 19 | this 20 | .fwd(3) 21 | .bed() 22 | .back(3) 23 | ``` 24 | ***/ 25 | var bedDirections = { 26 | 0: 3, // east 27 | 1: 0, // south 28 | 2: 1, // west 29 | 3: 2 // north 30 | }; 31 | module.exports = function(Drone) { 32 | Drone.extend(function bed() { 33 | this.then(function() { 34 | var foot = this.setBlock( 35 | blocks.bed, 36 | bedDirections[this.dir], 37 | 0, 38 | 0, 39 | 0, 40 | false 41 | ); 42 | var head = this.setBlock( 43 | blocks.bed, 44 | bedDirections[this.dir] + 8, 45 | 0, 46 | 0, 47 | 1, 48 | false 49 | ); 50 | if (Drone.bountiful) { 51 | var prop = require('blockhelper').property; 52 | var BedHalf = 53 | Packages.net.canarymod.api.world.blocks.properties.helpers 54 | .BedProperties.Half; 55 | prop(foot) 56 | .set('facing', this.dir) 57 | .set('part', BedHalf.FOOT); 58 | prop(head) 59 | .set('facing', this.dir) 60 | .set('part', BedHalf.HEAD); 61 | } 62 | if (__plugin.canary) { 63 | foot.update(); 64 | head.update(); 65 | } 66 | }); 67 | }); 68 | }; 69 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/cylinders.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /************************************************************************** 4 | ### Drone.cylinder() method 5 | 6 | A convenience method for building cylinders. Building begins radius blocks to the right and forward. 7 | 8 | #### Parameters 9 | 10 | * block - the block id - e.g. 6 for an oak sapling or '6:2' for a birch sapling. Alternatively you can use any one of the `blocks` values e.g. `blocks.sapling.birch` 11 | * radius 12 | * height 13 | 14 | #### Example 15 | 16 | To create a cylinder of Iron 7 blocks in radius and 1 block high... 17 | 18 | cylinder(blocks.iron, 7 , 1); 19 | 20 | ![cylinder example](img/cylinderex1.png) 21 | 22 | ### Drone.cylinder0() method 23 | 24 | A version of cylinder that hollows out the middle. 25 | 26 | #### Example 27 | 28 | To create a hollow cylinder of Iron 7 blocks in radius and 1 block high... 29 | 30 | cylinder0(blocks.iron, 7, 1); 31 | 32 | ![cylinder0 example](img/cylinder0ex1.png) 33 | 34 | ***/ 35 | 36 | function cylinder0(block, radius, height, exactParams) { 37 | var arcParams = { 38 | radius: radius, 39 | fill: false, 40 | orientation: 'horizontal', 41 | stack: height 42 | }; 43 | 44 | if (exactParams) { 45 | for (var p in exactParams) { 46 | arcParams[p] = exactParams[p]; 47 | } 48 | } else { 49 | var md = this.getBlockIdAndMeta(block); 50 | arcParams.blockType = md[0]; 51 | arcParams.meta = md[1]; 52 | } 53 | return this.arc(arcParams); 54 | } 55 | function cylinder(block, radius, height, exactParams) { 56 | var arcParams = { 57 | radius: radius, 58 | fill: true, 59 | orientation: 'horizontal', 60 | stack: height 61 | }; 62 | 63 | if (exactParams) { 64 | arcParams.blockType = exactParams.blockType; 65 | arcParams.meta = exactParams.meta; 66 | } else { 67 | var md = this.getBlockIdAndMeta(block); 68 | arcParams.blockType = md[0]; 69 | arcParams.meta = md[1]; 70 | } 71 | return this.arc(arcParams); 72 | } 73 | module.exports = function(Drone) { 74 | Drone.extend(cylinder0); 75 | Drone.extend(cylinder); 76 | }; 77 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/doors.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | 'use strict'; 3 | /************************************************************************* 4 | ### Drone.door() method 5 | 6 | create a door - if a parameter is supplied an Iron door is created otherwise a wooden door is created. 7 | 8 | #### Parameters 9 | 10 | * doorType (optional - default wood) - If a parameter is provided then the door is Iron. 11 | 12 | #### Example 13 | 14 | To create a wooden door at the crosshairs/drone's location... 15 | 16 | var drone = new Drone(self); 17 | drone.door(); 18 | 19 | To create an iron door... 20 | 21 | drone.door( blocks.door_iron ); 22 | 23 | ![iron door](img/doorex1.png) 24 | 25 | ### Drone.door_iron() method 26 | 27 | create an Iron door. 28 | 29 | ### Drone.door2() method 30 | 31 | Create double doors (left and right side) 32 | 33 | #### Parameters 34 | 35 | * doorType (optional - default wood) - If a parameter is provided then the door is Iron. 36 | 37 | #### Example 38 | 39 | To create double-doors at the cross-hairs/drone's location... 40 | 41 | drone.door2(); 42 | 43 | ![double doors](img/door2ex1.png) 44 | 45 | ### Drone.door2_iron() method 46 | 47 | Create double iron doors 48 | 49 | ***/ 50 | 51 | var blocks = require('blocks'); 52 | /*global require, Packages, __plugin*/ 53 | function door(doorMaterial, hinge) { 54 | if (typeof doorMaterial == 'undefined') { 55 | doorMaterial = blocks.door_wood; // wood 56 | } 57 | if (typeof hinge == 'undefined') { 58 | hinge = 'left'; 59 | } 60 | var Drone = this.constructor; 61 | this.then(function() { 62 | var lower = this.setBlock(doorMaterial, this.dir, 0, 0, 0, false); 63 | var upper = this.setBlock( 64 | doorMaterial, 65 | hinge == 'left' ? 8 : 9, 66 | 0, 67 | 1, 68 | 0, 69 | false 70 | ); 71 | if (Drone.bountiful) { 72 | var DoorHalf = Packages.net.minecraft.block.BlockDoor.EnumDoorHalf, 73 | HingePosition = 74 | Packages.net.minecraft.block.BlockDoor.EnumHingePosition, 75 | prop = require('blockhelper').property; 76 | prop(lower) 77 | .set('facing', this.dir) 78 | .set('half', DoorHalf.LOWER); 79 | prop(upper) 80 | .set( 81 | 'hinge', 82 | hinge == 'left' ? HingePosition.LEFT : HingePosition.RIGHT 83 | ) 84 | .set('half', DoorHalf.UPPER); 85 | } 86 | if (__plugin.canary) { 87 | lower.update(); 88 | upper.update(); 89 | } 90 | }); 91 | } 92 | module.exports = function(Drone) { 93 | Drone.extend(door); 94 | 95 | Drone.extend(function door_iron() { 96 | this.door(blocks.door_iron); 97 | }); 98 | 99 | Drone.extend(function door2(doorMaterial) { 100 | if (typeof doorMaterial == 'undefined') { 101 | doorMaterial = blocks.door_wood; 102 | } 103 | this.door(doorMaterial, 'left') 104 | .right() 105 | .door(doorMaterial, 'right') 106 | .left(); 107 | }); 108 | Drone.extend(function door2_iron() { 109 | this.door2(blocks.door_iron); 110 | }); 111 | }; 112 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/firework.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global module, require*/ 3 | var fireworks = require('fireworks'); 4 | /************************************************************************* 5 | ### Drone.firework() method 6 | 7 | Launches a firework at the drone's location. 8 | 9 | #### Example 10 | 11 | To launch a firework: 12 | 13 | var drone = new Drone(self); 14 | drone.firework(); 15 | 16 | ***/ 17 | module.exports = function(Drone) { 18 | Drone.extend(function firework() { 19 | fireworks.firework(this.getLocation()); 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/garden.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | 'use strict'; 3 | /************************************************************************ 4 | ### Drone.garden() method 5 | 6 | places random flowers and long grass (similar to the effect of placing bonemeal on grass) 7 | 8 | #### Parameters 9 | 10 | * width - the width of the garden 11 | * length - how far from the drone the garden extends 12 | 13 | #### Example 14 | 15 | To create a garden 10 blocks wide by 5 blocks long... 16 | 17 | garden(10,5); 18 | 19 | ![garden example](img/gardenex1.png) 20 | 21 | ***/ 22 | var blocks = require('blocks'); 23 | 24 | function garden(width, depth) { 25 | if (typeof width == 'undefined') { 26 | width = 10; 27 | } 28 | if (typeof depth == 'undefined') { 29 | depth = width; 30 | } 31 | // make sure grass is present first 32 | this.box(blocks.grass, width, 1, depth).up(); 33 | 34 | // make flowers more common than long grass 35 | var dist = {}; 36 | dist[blocks.rose] = 3; 37 | dist[blocks.dandelion] = 3; 38 | dist[blocks.grass_tall] = 2; 39 | dist[blocks.air] = 1; 40 | 41 | this.rand(dist, width, 1, depth, false /* don't overwrite */).down(); 42 | } 43 | module.exports = function(Drone) { 44 | Drone.extend(garden); 45 | }; 46 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/ladder.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require, module*/ 3 | /************************************************************************ 4 | ### Drone.ladder() method 5 | 6 | Creates a ladder extending skyward. 7 | 8 | #### Parameters 9 | 10 | * height (optional - default 1) 11 | 12 | #### Example 13 | 14 | To create a ladder extending 10 blocks high: 15 | 16 | var drone = new Drone(self); 17 | drone.ladder(10) 18 | 19 | At the in-game prompt, look at a block and then type: 20 | 21 | /js ladder(10) 22 | 23 | A ladder 10 blocks high will be created at the point you were looking at. 24 | 25 | #### Since 26 | ##### 3.0.3 27 | ***/ 28 | var blocks = require('blocks'); 29 | 30 | function ladder(height) { 31 | this.then(function ladderLater() { 32 | var block = this.getBlock(); 33 | if (block.typeId == blocks.air || block.typeId == blocks.ladder) { 34 | this.box(blocks.ladder, 1, height, 1, true); 35 | } else { 36 | this.back() 37 | .box(blocks.ladder, 1, height, 1, true) 38 | .fwd(); 39 | } 40 | }); 41 | } 42 | 43 | module.exports = function(Drone) { 44 | Drone.extend(ladder); 45 | }; 46 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/prism.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require, module*/ 3 | /************************************************************************ 4 | ### Drone.prism() method 5 | 6 | Creates a prism. This is useful for roofs on houses. 7 | 8 | #### Parameters 9 | 10 | * block - the block id - e.g. 6 for an oak sapling or '6:2' for a birch sapling. 11 | Alternatively you can use any one of the `blocks` values e.g. `blocks.sapling.birch` 12 | * width - the width of the prism 13 | * length - the length of the prism (will be 2 time its height) 14 | 15 | #### Example 16 | 17 | prism(blocks.oak,3,12); 18 | 19 | ![prism example](img/prismex1.png) 20 | 21 | ### Drone.prism0() method 22 | 23 | A variation on `prism` which hollows out the inside of the prism. It 24 | uses the same parameters as `prism`. 25 | 26 | ***/ 27 | var STAIRBLOCKS = { 28 | 53: '5:0', // oak wood 29 | 67: 4, // cobblestone 30 | 108: 45, // brick 31 | 109: 98, // stone brick 32 | 114: 112, // nether brick 33 | 128: 24, // sandstone 34 | 134: '5:1', // spruce wood 35 | 135: '5:2', // birch wood 36 | 136: '5:3', // jungle wood 37 | 156: 155 // quartz 38 | }; 39 | // 40 | // prism private implementation 41 | // 42 | function prism(block, w, d) { 43 | var stairEquiv = STAIRBLOCKS[block]; 44 | if (stairEquiv) { 45 | this.fwd() 46 | .prism(stairEquiv, w, d - 2) 47 | .back() 48 | .stairs(block, w, d / 2) 49 | .fwd(d - 1) 50 | .right(w - 1) 51 | .turn(2) 52 | .stairs(block, w, d / 2) 53 | .turn(2) 54 | .left(w - 1) 55 | .back(d - 1); 56 | } else { 57 | var c = 0; 58 | var d2 = d; 59 | while (d2 >= 1) { 60 | this.cuboid(block, w, 1, d2); 61 | d2 -= 2; 62 | this.fwd().up(); 63 | c++; 64 | } 65 | this.down(c).back(c); 66 | } 67 | return this; 68 | } 69 | // 70 | // prism0 private implementation 71 | // 72 | function prism0(block, w, d) { 73 | this.stairs(block, w, d / 2) 74 | .fwd(d - 1) 75 | .right(w - 1) 76 | .turn(2) 77 | .stairs(block, w, d / 2) 78 | .turn(2) 79 | .left(w - 1) 80 | .back(d - 1); 81 | 82 | var se = STAIRBLOCKS[block]; 83 | if (se) { 84 | this.fwd() 85 | .prism(se, 1, d - 2) 86 | .right(w - 1) 87 | .prism(se, 1, d - 2) 88 | .left(w - 1) 89 | .back(); 90 | } 91 | } 92 | module.exports = function(Drone) { 93 | Drone.extend(prism0); 94 | Drone.extend(prism); 95 | }; 96 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/rand.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require, module*/ 3 | /************************************************************************ 4 | ### Drone.rand() method 5 | 6 | rand takes either an array (if each blockid has the same chance of occurring) or an object where each property is a blockid and the value is it's weight (an integer) 7 | 8 | #### Example 9 | 10 | place random blocks stone, mossy stone and cracked stone (each block has the same chance of being picked) 11 | 12 | rand( [blocks.brick.stone, blocks.brick.mossy, blocks.brick.cracked ],w,d,h) 13 | 14 | to place random blocks stone has a 50% chance of being picked, 15 | 16 | var distribution = {}; 17 | distribution[ blocks.brick.stone ] = 5; 18 | distribution[ blocks.brick.mossy ] = 3; 19 | distribution[ blocks.brick.cracked ] = 2; 20 | 21 | rand( distribution, width, height, depth) 22 | 23 | regular stone has a 50% chance, mossy stone has a 30% chance and cracked stone has just a 20% chance of being picked. 24 | 25 | ***/ 26 | // 27 | // standard fisher-yates shuffle algorithm 28 | // 29 | function fisherYates(myArray) { 30 | var i = myArray.length; 31 | if (i == 0) return false; 32 | while (--i) { 33 | var j = Math.floor(Math.random() * (i + 1)); 34 | var tempi = myArray[i]; 35 | var tempj = myArray[j]; 36 | myArray[i] = tempj; 37 | myArray[j] = tempi; 38 | } 39 | } 40 | function _rand(blockDistribution) { 41 | if (!(blockDistribution.constructor == Array)) { 42 | var a = []; 43 | for (var p in blockDistribution) { 44 | var n = blockDistribution[p]; 45 | for (var i = 0; i < n; i++) { 46 | a.push(p); 47 | } 48 | } 49 | blockDistribution = a; 50 | } 51 | while (blockDistribution.length < 1000) { 52 | // make array bigger so that it's more random 53 | blockDistribution = blockDistribution.concat(blockDistribution); 54 | } 55 | fisherYates(blockDistribution); 56 | return blockDistribution; 57 | } 58 | function rand(dist, width, height, depth, overwrite) { 59 | if (typeof overwrite == 'undefined') { 60 | overwrite = true; 61 | } 62 | var randomized = _rand(dist); 63 | this.boxa(randomized, width, height, depth, overwrite); 64 | } 65 | module.exports = function(Drone) { 66 | Drone.extend(rand); 67 | }; 68 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/sign.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require, echo,__plugin, module*/ 3 | var blocks = require('blocks'); 4 | /************************************************************************ 5 | ### Drone.wallsign() method 6 | 7 | Creates a wall sign (A sign attached to a wall) 8 | 9 | #### Parameters 10 | 11 | * message - can be a string or an array of strings 12 | 13 | #### Example 14 | 15 | drone.wallsign(['Welcome','to','Scriptopia']); 16 | 17 | ![wall sign](img/signex2.png) 18 | 19 | ### Drone.signpost() method 20 | 21 | Creates a free-standing signpost 22 | 23 | #### Parameters 24 | 25 | * message - can be a string or an array of strings 26 | 27 | #### Example 28 | 29 | drone.signpost(['Hello','World']); 30 | 31 | ![ground sign](img/signex1.png) 32 | 33 | ### Drone.sign() method 34 | 35 | Deprecated: Use signpost() or wallsign() methods instead. 36 | 37 | Signs must use block 63 (stand-alone signs) or 68 (signs on walls) 38 | 39 | #### Parameters 40 | 41 | * message - can be a string or an array of strings. 42 | * block - can be 63 or 68 43 | 44 | #### Example 45 | 46 | To create a free-standing sign... 47 | 48 | drone.sign(["Hello","World"], blocks.sign_post); 49 | 50 | ![ground sign](img/signex1.png) 51 | 52 | ... to create a wall mounted sign... 53 | 54 | drone.sign(["Welcome","to","Scriptopia"], blocks.sign ); 55 | 56 | ![wall sign](img/signex2.png) 57 | 58 | ***/ 59 | function putSign(drone, texts, blockId, meta) { 60 | var i, 61 | len = texts.length, 62 | block, 63 | isSign, 64 | setLine; 65 | 66 | if (blockId != blocks.sign_post && blockId != blocks.sign) { 67 | throw new Error( 68 | 'Invalid Parameter: blockId must be blocks.sign_post or blocks.sign' 69 | ); 70 | } 71 | block = drone.setBlock(blockId, meta); 72 | if (__plugin.canary) { 73 | isSign = function(block) { 74 | var sign = block.getTileEntity(); 75 | return sign.setTextOnLine; 76 | }; 77 | setLine = function(block, i) { 78 | var sign = block.getTileEntity(); 79 | sign.setTextOnLine(texts[i], i); 80 | sign.update(); 81 | }; 82 | } 83 | if (__plugin.bukkit) { 84 | isSign = function(block) { 85 | return block.state && block.state.setLine; 86 | }; 87 | setLine = function(block, i) { 88 | var sign = block.state; 89 | sign.setLine(i, texts[i]); 90 | sign.update(true); 91 | }; 92 | } 93 | if (isSign(block)) { 94 | if (len > 4) { 95 | len = 4; 96 | } 97 | for (i = 0; i < len; i++) { 98 | setLine(block, i, texts[i]); 99 | } 100 | } 101 | } 102 | function signpost(message) { 103 | this.then(function() { 104 | this.sign(message, blocks.sign_post); 105 | }); 106 | } 107 | function wallsign(message) { 108 | /* 109 | must allow for /js wallsign() while looking at a wall block 110 | */ 111 | this.then(function() { 112 | var block = this.getBlock(); 113 | if (block.typeId == blocks.air || block.typeId == blocks.sign) { 114 | this.sign(message, blocks.sign); 115 | } else { 116 | this.back() 117 | .sign(message, blocks.sign) 118 | .fwd(); 119 | } 120 | }); 121 | } 122 | function sign(message, block) { 123 | if (message.constructor != Array) { 124 | message = [message]; 125 | } 126 | var bm = this.getBlockIdAndMeta(block); 127 | block = bm[0]; 128 | var meta = bm[1]; 129 | if (block !== blocks.sign_post && block !== blocks.sign) { 130 | var usage = 131 | 'Usage: sign("message", blocks.sign_post) or sign("message", blocks.sign)'; 132 | if (this.player) { 133 | echo(this.player, usage); 134 | } 135 | console.error(usage); 136 | return; 137 | } 138 | putSign(this, message, block, meta); 139 | } 140 | module.exports = function(Drone) { 141 | Drone.extend(sign); 142 | Drone.extend(signpost); 143 | Drone.extend(wallsign); 144 | }; 145 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/stairs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global module*/ 3 | /************************************************************************** 4 | ### Drone.stairs() function 5 | 6 | The stairs() function will build a flight of stairs 7 | 8 | #### Parameters 9 | 10 | * blockType - should be one of the following: 11 | 12 | * blocks.stairs.oak 13 | * blocks.stairs.cobblestone 14 | * blocks.stairs.brick 15 | * blocks.stairs.stone 16 | * blocks.stairs.nether 17 | * blocks.stairs.sandstone 18 | * blocks.stairs.spruce 19 | * blocks.stairs.birch 20 | * blocks.stairs.jungle 21 | * blocks.stairs.quartz 22 | 23 | * width - The width of the staircase - default is 1 24 | * height - The height of the staircase - default is 1 25 | 26 | #### Example 27 | 28 | To build an oak staircase 3 blocks wide and 5 blocks tall: 29 | 30 | /js stairs(blocks.stairs.oak, 3, 5) 31 | 32 | Staircases do not have any blocks beneath them. 33 | 34 | ***/ 35 | var blocks = require('blocks'); 36 | /*global require*/ 37 | function stairs(blockType, width, height) { 38 | if (typeof width === 'undefined') width = 1; 39 | if (typeof height === 'undefined') height = 1; 40 | if (typeof blockType === 'undefined') { 41 | blockType = blocks.stairs.oak; 42 | } 43 | var bm = this.getBlockIdAndMeta(blockType); 44 | this.then(function() { 45 | this.chkpt('_stairs'); 46 | while (height > 0) { 47 | this.traverseWidth(width, function() { 48 | this.setBlock(bm[0], bm[1]); 49 | }); 50 | 51 | this.fwd().up(); 52 | height -= 1; 53 | } 54 | this.move('_stairs'); 55 | }); 56 | } 57 | module.exports = function(Drone) { 58 | Drone.extend(stairs); 59 | }; 60 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global module*/ 3 | function testHorizontalStrokeWidth() { 4 | this.arc({ 5 | blockType: 42, 6 | meta: 0, 7 | radius: 8, 8 | orientation: 'horizontal', 9 | strokeWidth: 3, 10 | quadrants: { 11 | topright: true, 12 | topleft: true, 13 | bottomleft: true, 14 | bottomright: true 15 | } 16 | }); 17 | } 18 | function testVerticalStrokeWidth() { 19 | this.arc({ 20 | blockType: 42, 21 | meta: 0, 22 | radius: 8, 23 | orientation: 'vertical', 24 | strokeWidth: 3, 25 | quadrants: { 26 | topright: true, 27 | topleft: true, 28 | bottomleft: true, 29 | bottomright: true 30 | } 31 | }); 32 | } 33 | module.exports = function(Drone) { 34 | Drone.prototype.testHorizontalStrokeWidth = testHorizontalStrokeWidth; 35 | Drone.prototype.testVerticalStrokeWidth = testVerticalStrokeWidth; 36 | }; 37 | -------------------------------------------------------------------------------- /src/main/js/modules/drone/trees.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require, __plugin, Packages, org, echo, module */ 3 | var blocks = require('blocks'); 4 | /************************************************************************ 5 | ### Drone Trees methods 6 | 7 | * oak() 8 | * spruce() 9 | * birch() 10 | * jungle() 11 | 12 | #### Example 13 | 14 | To create 4 trees in a row, point the cross-hairs at the ground then type `/js ` and ... 15 | 16 | up( ).oak( ).right(8 ).spruce( ).right(8 ).birch( ).right(8 ).jungle( ); 17 | 18 | Trees won't always generate unless the conditions are right. You 19 | should use the tree methods when the drone is directly above the 20 | ground. Trees will usually grow if the drone's current location is 21 | occupied by Air and is directly above an area of grass (That is why 22 | the `up()` method is called first). 23 | 24 | ![tree example](img/treeex1.png) 25 | 26 | None of the tree methods require parameters. Tree methods will only be 27 | successful if the tree is placed on grass in a setting where trees can 28 | grow. 29 | 30 | ***/ 31 | function bukkitTreeFactory(k, v) { 32 | return function() { 33 | var block = this.getBlock(); 34 | if (block.typeId == blocks.grass) { 35 | this.up(); 36 | } 37 | var treeLoc = this.getLocation(); 38 | treeLoc.world.generateTree(treeLoc, v); 39 | if (block.typeId == blocks.grass) { 40 | this.down(); 41 | } 42 | }; 43 | } 44 | function canaryTreeFactory(k) { 45 | return function() { 46 | var block = this.getBlock(); 47 | if (block.typeId == blocks.grass) { 48 | this.up(); 49 | } 50 | var treeLoc = this.getLocation(); 51 | if (!treeLoc.world.generateTree) { 52 | var msg = k + '() is not supported in this version'; 53 | if (this.player) { 54 | echo(this.player, msg); 55 | } 56 | console.log(msg); 57 | return; 58 | } 59 | var cmTreeType = Packages.net.canarymod.api.world.TreeType; 60 | var trees = { 61 | oak: cmTreeType.BIGOAK, 62 | birch: cmTreeType.BIRCH, 63 | jungle: cmTreeType.JUNGLE, 64 | spruce: cmTreeType.SPRUCE 65 | }; 66 | 67 | treeLoc.world.generateTree(treeLoc, trees[k]); 68 | if (block.typeId == blocks.grass) { 69 | this.down(); 70 | } 71 | }; 72 | } 73 | module.exports = function(Drone) { 74 | var trees = { 75 | oak: null, 76 | birch: null, 77 | jungle: null, 78 | spruce: null 79 | }; 80 | var p; 81 | if (__plugin.canary) { 82 | for (p in trees) { 83 | Drone.extend(p, canaryTreeFactory(p, trees[p])); 84 | } 85 | } 86 | if (__plugin.bukkit) { 87 | var bkTreeType = org.bukkit.TreeType; 88 | trees = { 89 | oak: bkTreeType.BIG_TREE, 90 | birch: bkTreeType.BIRCH, 91 | jungle: bkTreeType.JUNGLE, 92 | spruce: bkTreeType.REDWOOD 93 | }; 94 | for (p in trees) { 95 | Drone.extend(p, bukkitTreeFactory(p, trees[p])); 96 | } 97 | } 98 | }; 99 | -------------------------------------------------------------------------------- /src/main/js/modules/entities.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var entities = {}, 3 | entitytypes, 4 | t, 5 | name; 6 | if (__plugin.bukkit) { 7 | entitytypes = org.bukkit.entity.EntityType.values(); 8 | } 9 | if (__plugin.canary) { 10 | entitytypes = Packages.net.canarymod.api.entity.EntityType.values(); 11 | } 12 | function getEntityHandler(entityType) { 13 | return function(entity) { 14 | if (arguments.length == 0) { 15 | return entityType; 16 | } 17 | if (arguments.length == 1) { 18 | if (entity) { 19 | if (__plugin.bukkit) { 20 | return entity.type == entityType; 21 | } 22 | if (__plugin.canary) { 23 | return entity.entityType == entityType; 24 | } 25 | } 26 | } 27 | return null; 28 | }; 29 | } 30 | for (t in entitytypes) { 31 | if (entitytypes[t] && entitytypes[t].ordinal) { 32 | name = ('' + entitytypes[t].name()).replace(/^(.*)/, function(a) { 33 | return a.toLowerCase(); 34 | }); 35 | entities[name] = getEntityHandler(entitytypes[t]); 36 | } 37 | } 38 | module.exports = entities; 39 | -------------------------------------------------------------------------------- /src/main/js/modules/fireworks.js: -------------------------------------------------------------------------------- 1 | /************************************************************************ 2 | ## Fireworks Module 3 | 4 | The fireworks module makes it easy to create fireworks using 5 | ScriptCraft. The module has a single function `firework` which takes 6 | a `org.bukkit.Location` as its 1 and only parameter. 7 | 8 | ### Examples 9 | 10 | The module also extends the `Drone` object adding a `firework` method 11 | so that fireworks can be created as a part of a Drone chain. For 12 | Example.... 13 | 14 | /js firework() 15 | 16 | ... creates a single firework, while .... 17 | 18 | /js firework().fwd(3).times(5) 19 | 20 | ... creates 5 fireworks in a row. Fireworks have also been added as a 21 | possible option for the `arrow` module. To have a firework launch 22 | where an arrow strikes... 23 | 24 | /js arrows.firework() 25 | 26 | To call the fireworks.firework() function directly, you must provide a 27 | location. For example... 28 | 29 | /js var fireworks = require('fireworks'); 30 | /js fireworks.firework( self.location ); 31 | 32 | ![firework example](img/firework.png) 33 | 34 | ***/ 35 | 36 | if (__plugin.canary) { 37 | exports.firework = require('./canary/fireworks'); 38 | } else { 39 | exports.firework = require('./bukkit/fireworks'); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/js/modules/http/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http", 3 | "main": "./request.js" 4 | } 5 | -------------------------------------------------------------------------------- /src/main/js/modules/http/request.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## Http Module 3 | 4 | For handling http requests. Not to be confused with the more robust 5 | and functional 'http' module bundled with Node.js. 6 | 7 | ### http.request() function 8 | 9 | The http.request() function will fetch a web address asynchronously (on a 10 | separate thread)and pass the URL's response to a callback function 11 | which will be executed synchronously (on the main thread). In this 12 | way, http.request() can be used to fetch web content without blocking the 13 | main thread of execution. 14 | 15 | #### Parameters 16 | 17 | * request: The request details either a plain URL e.g. "https://scriptcraft.js/sample.json" or an object with the following properties... 18 | 19 | - url: The URL of the request. 20 | - method: Should be one of the standard HTTP methods, GET, POST, PUT, DELETE (defaults to GET). 21 | - params: A Javascript object with name-value pairs. This is for supplying parameters to the server. 22 | 23 | * callback: The function to be called when the Web request has completed. This function takes the following parameters... 24 | - responseCode: The numeric response code from the server. If the server did not respond with 200 OK then the response parameter will be undefined. 25 | - response: A string (if the response is of type text) or object containing the HTTP response body. 26 | 27 | #### Example 28 | 29 | The following example illustrates how to use http.request to make a request to a JSON web service and evaluate its response... 30 | 31 | ```javascript 32 | var jsResponse; 33 | var http = require('http'); 34 | http.request('https://scriptcraftjs.org/sample.json',function(responseCode, responseBody){ 35 | jsResponse = JSON.parse( responseBody ); 36 | }); 37 | ``` 38 | The following example illustrates a more complex use-case POSTing parameters to a CGI process on a server... 39 | 40 | ```javascript 41 | var http = require('http'); 42 | http.request( { 43 | url: 'http://pixenate.com/pixenate/pxn8.pl', 44 | method: 'POST', 45 | params: {script: '[]'} 46 | }, 47 | function( responseCode, responseBody ) { 48 | var jsObj = JSON.parse( responseBody ); 49 | }); 50 | ``` 51 | 52 | ***/ 53 | 54 | /*global exports, encodeURIComponent, server, __plugin, setTimeout*/ 55 | function paramsToString(params) { 56 | var result = '', 57 | paramNames = [], 58 | i; 59 | for (i in params) { 60 | paramNames.push(i); 61 | } 62 | for (i = 0; i < paramNames.length; i++) { 63 | result += paramNames[i] + '=' + encodeURIComponent(params[paramNames[i]]); 64 | if (i < paramNames.length - 1) result += '&'; 65 | } 66 | return result; 67 | } 68 | function invokeNow(fn) { 69 | if (__plugin.bukkit) { 70 | server.scheduler['runTask(org.bukkit.plugin.Plugin, java.lang.Runnable)']( 71 | __plugin, 72 | fn 73 | ); 74 | return; 75 | } 76 | if (__plugin.canary) { 77 | fn(); 78 | return; 79 | } 80 | } 81 | function invokeLater(fn) { 82 | if (__plugin.bukkit) { 83 | server.scheduler['runTaskAsynchronously(org.bukkit.plugin.Plugin, java.lang.Runnable)'](__plugin, fn); 84 | return; 85 | } 86 | if (__plugin.canary) { 87 | setTimeout(fn, 20); 88 | return; 89 | } 90 | } 91 | exports.request = function(request, callback) { 92 | invokeLater(function() { 93 | var url, paramsAsString, conn, requestMethod; 94 | if (typeof request === 'string') { 95 | url = request; 96 | requestMethod = 'GET'; 97 | } else { 98 | url = request.url; 99 | paramsAsString = paramsToString(request.params); 100 | if (request.method) { 101 | requestMethod = request.method; 102 | } else { 103 | requestMethod = 'GET'; 104 | } 105 | if (requestMethod == 'GET' && request.params) { 106 | // append each parameter to the URL 107 | url = request.url + '?' + paramsAsString; 108 | } 109 | } 110 | conn = new java.net.URL(url).openConnection(); 111 | conn.requestMethod = requestMethod; 112 | conn.doOutput = true; 113 | conn.instanceFollowRedirects = false; 114 | 115 | if (conn.requestMethod == 'POST') { 116 | conn.doInput = true; 117 | // put each parameter in the outputstream 118 | conn.setRequestProperty( 119 | 'Content-Type', 120 | 'application/x-www-form-urlencoded' 121 | ); 122 | conn.setRequestProperty('charset', 'utf-8'); 123 | conn.setRequestProperty('Content-Length', '' + paramsAsString.length); 124 | conn.useCaches = false; 125 | var wr = new java.io.DataOutputStream(conn.getOutputStream()); 126 | wr.writeBytes(paramsAsString); 127 | wr.flush(); 128 | wr.close(); 129 | } 130 | var rc = conn.responseCode; 131 | var response; 132 | var stream; 133 | if (rc == 200) { 134 | stream = conn.getInputStream(); 135 | response = new java.util.Scanner(stream).useDelimiter('\\A').next(); 136 | } 137 | invokeNow(function() { 138 | callback(rc, response); 139 | }); 140 | }); 141 | }; 142 | -------------------------------------------------------------------------------- /src/main/js/modules/input.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## Asynchronous Input Module 3 | 4 | The `input` module provides a simple way to prompt players for input at the 5 | in-game prompt. In Javascript browser environments the `prompt()` function provides 6 | a way to block execution and ask the user for input. Execution is blocked until the user 7 | provides input using the modal dialog and clicks OK. Unfortunately Minecraft provides no 8 | equivalent modal dialog which can be used to gather player text input. The only way to gather text 9 | input from the player in Minecraft is to do so asynchronously. That is - a prompt message can be 10 | sent to the player but the player is not obliged to provide input immediately, nor does the program 11 | execution block until the player does so. 12 | 13 | So ScriptCraft has no `prompt()` implementation because `prompt()` is a synchronous function and 14 | Minecraft's API provides no equivalent functions or classes which can be used to implement this synchronously. 15 | The Minecraft API does however have a 'Conversation' API which allows for prompting of the player and asynchronously gathering text input from the player. 16 | 17 | This new `input()` function is best illustrated by example. The following code is for a number-guessing game: 18 | 19 | ```javascript 20 | var input = require('input'); 21 | exports.numberguess = function(player){ 22 | var randomNumber = Math.ceil(Math.random() * 10); 23 | input( player, 'Think of a number between 1 and 10 (q to quit)', function( guess, guesser, repeat ) { 24 | if ( guess == 'q'){ 25 | return; 26 | } 27 | if ( +guess !== randomNumber ) { 28 | if (+guess < randomNumber ) { 29 | echo( guesser, 'Too low - guess again'); 30 | } 31 | if (+guess > randomNumber ) { 32 | echo( guesser, 'Too high - guess again'); 33 | } 34 | repeat(); 35 | } else { 36 | echo( guesser, 'You guessed correctly'); 37 | } 38 | }); 39 | }; 40 | ``` 41 | 42 | The `input()` function takes 3 parameters, the player, a prompt message and a callback which will be invoked when the player has entered some text at the in-game command prompt. 43 | The callback is bound to an object which has the following properties: 44 | 45 | * sender : The player who input the text 46 | * value : The value of the text which has been input. 47 | * message: The message prompt. 48 | * repeat: A function which when invoked will repeat the original prompt. (this is for flow control) 49 | 50 | The callback function as well as being bound to an object with the above properties (so you can use this.value inside your callback to get the value which has just been input), can also take the following parameters (in exact order): 51 | 52 | * value 53 | * sender 54 | * repeat 55 | 56 | The `value` parameter will be the same as `this.value`, the `repeat` parameter will be the same as `this.repeat` and so on. 57 | 58 | ***/ 59 | if (__plugin.canary) { 60 | module.exports = require('./canary/input'); 61 | } else { 62 | module.exports = require('./bukkit/input'); 63 | } 64 | -------------------------------------------------------------------------------- /src/main/js/modules/inventory/index.js: -------------------------------------------------------------------------------- 1 | /************************************************************************ 2 | ## Inventory Module 3 | This module provides functions to add items to, remove items from and check the 4 | contents of a player or NPC's inventory. 5 | 6 | ### Usage 7 | The inventory module is best used in conjunction with the items module. See below for examples of usage. 8 | 9 | ```javascript 10 | var inventory = require('inventory'); 11 | var items = require('items'); 12 | var utils = require('utils'); 13 | 14 | // gives every player 2 cookies and a baked potatoe 15 | var bakedPotato = items.bakedPotato(1); 16 | var cookies2 = items.cookie(2); 17 | 18 | utils.players(function( player ){ 19 | inventory( player ) 20 | .add( cookies2 ) 21 | .add( bakedPotato ) 22 | }); 23 | 24 | // give a player 6 cookies then take away 4 of them 25 | 26 | inventory( player ) 27 | .add( items.cookie(6) ) 28 | .remove ( items.cookie(4) ) 29 | 30 | // check if a player has any cookies 31 | 32 | var hasCookies = inventory(player).contains( items.cookie(1) ); 33 | 34 | // Enchant an item and give it to the player (CraftBukkit/Spigot only) 35 | 36 | var luck = org.bukkit.enchantments.Enchantment.getByName("LUCK"); 37 | var luckyRod = items.fishingRod( 1 ); 38 | luckyRod.addEnchantment( luck, 3); 39 | inventory( player ).add( luckyRod ); 40 | 41 | ``` 42 | The inventory module exposes a single function which when passed a player or NPC will return an object with 3 methods: 43 | 44 | * add : Adds items to the inventory (Expects parameters of type `net.canarymod.api.inventory.Item` - I strongly recommend using the `items` module for constructing items) 45 | * remove : removes items from the inventory (Expects parameters of type `net.canarymod.api.inventory.Item` - I strongly recommend using the `items` module for constructing items) 46 | * contains : checks to see if there is the specified type and amount of item in the inventory (Expects parameters of type `net.canarymod.api.inventory.Item` - I strongly recommend using the `items` module for constructing items) 47 | 48 | ***/ 49 | if (__plugin.canary) { 50 | module.exports = require('../canary/inventory'); 51 | } else { 52 | module.exports = require('../bukkit/inventory'); 53 | } 54 | -------------------------------------------------------------------------------- /src/main/js/modules/items.js: -------------------------------------------------------------------------------- 1 | if (__plugin.canary) { 2 | module.exports = require('./canary/items'); 3 | } else { 4 | module.exports = require('./bukkit/items'); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/js/modules/lightning.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /************************************************************************ 3 | ## Lightning module 4 | 5 | Causes a bolt of lightning to strike. 6 | 7 | ### Usage 8 | ```javascript 9 | // strike lightning wherever a player's arrow lands 10 | var lightning = require('lightning'); 11 | events.projectileHit( function( event ){ 12 | if ( entities.arrow( event.projectile ) // it's an arrow 13 | && entities.player( event.projectile.owner ) // it was shot by a player 14 | ) { 15 | lightning( event.projectile ); // strike lightning at the arrow location 16 | } 17 | }); 18 | ``` 19 | 20 | ***/ 21 | module.exports = function lightning(something) { 22 | if (__plugin.canary && something.location) { 23 | return something.location.world.makeLightningBolt(something.location); 24 | } 25 | if (__plugin.bukkit && something.location) { 26 | return something.location.world.strikeLightning(something.location); 27 | } 28 | console.log('Need an object with a location property for lightning strike'); 29 | return null; 30 | }; 31 | -------------------------------------------------------------------------------- /src/main/js/modules/minigames/scoreboard.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* 3 | wph 20150103 - temporarily commenting out - textcolors was removed. 4 | var textcolors = require('textcolors'); 5 | */ 6 | var sb; 7 | if (__plugin.canary) { 8 | var Canary = Packages.net.canarymod.Canary; 9 | sb = Canary.scoreboards().getScoreboard(); 10 | } else { 11 | console.warn('Scoreboard not yet supported in CraftBukkit'); 12 | return; 13 | } 14 | function execCommand(command) { 15 | server.executeVanillaCommand(server, command); 16 | } 17 | /* 18 | function getTeamByName( teamName ){ 19 | var allTeams = sb.getTeams().toArray(); 20 | for (var i = 0;i < allTeams.length; i++){ 21 | if (allTeams[i].displayName == teamName){ 22 | return allTeams[i]; 23 | } 24 | } 25 | return null; 26 | } 27 | */ 28 | function createScoreboard(objectiveName, displayName) { 29 | execCommand( 30 | 'scoreboard objectives add ' + objectiveName + ' dummy ' + displayName 31 | ); 32 | execCommand('scoreboard objectives setdisplay sidebar ' + objectiveName); 33 | } 34 | function addTeamToScoreboard(teamName /*, color*/) { 35 | execCommand('scoreboard teams add ' + teamName); 36 | /* 37 | wph 20150103 - temporarily commenting out - textcolors was removed. 38 | team.prefix = textcolors.colorize(color, ''); 39 | */ 40 | //var team = getTeamByName( teamName ); 41 | //execCommand('scoreboard teams option ' + teamName + ' color ' + color); 42 | } 43 | function removeScoreboard(name) { 44 | //execCommand('scoreboard objectives remove ' + name ); 45 | sb['removeScoreObjective(String)'](name); 46 | } 47 | function addPlayerToTeam(objectiveName, teamName, playerName) { 48 | execCommand('scoreboard teams join ' + teamName + ' ' + playerName); 49 | execCommand( 50 | 'scoreboard players set ' + playerName + ' ' + objectiveName + ' -1' 51 | ); 52 | updatePlayerScore(objectiveName, playerName, 0); 53 | } 54 | 55 | function updatePlayerScore(objectiveName, playerName, score) { 56 | /* 57 | wph 20150801 - this fails with CanaryMod 1.8.2 so use command instead - messy for ops but non-ops won't see messages 58 | 59 | var sc = sb['getScore(String, ScoreObjective)']( playerName, sb.getScoreObjective( objectiveName) ); 60 | sc.score = score; 61 | */ 62 | execCommand( 63 | 'scoreboard players set ' + playerName + ' ' + objectiveName + ' ' + score 64 | ); 65 | } 66 | 67 | function removeTeamFromScoreboard(teamName) { 68 | execCommand('scoreboard teams remove ' + teamName); 69 | //sb['removeTeam(String)'](teamName); 70 | } 71 | exports.create = createScoreboard; 72 | exports.addTeam = addTeamToScoreboard; 73 | exports.removeTeam = removeTeamFromScoreboard; 74 | exports.addPlayerToTeam = addPlayerToTeam; 75 | exports.updateScore = updatePlayerScore; 76 | exports.remove = removeScoreboard; 77 | -------------------------------------------------------------------------------- /src/main/js/modules/recipes.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## The recipes module 3 | 4 | The Recipes module provides convenience functions for adding and removing recipes 5 | from the game. 6 | 7 | ### Example 8 | To add an EnderBow to the game (assumes there's an enchanted Item variable called enderBow)... 9 | 10 | var recipes = require('recipes'); 11 | var items = require('items'); 12 | ... 13 | var enderBowRecipe = recipes.create( { 14 | result: enderBow, 15 | ingredients: { 16 | E: items.enderPearl(1), 17 | S: items.stick(1), 18 | W: items.string(1) 19 | }, 20 | shape: [ 'ESW', 21 | 'SEW', 22 | 'ESW' ] 23 | } ); 24 | // add to server 25 | var addedRecipe = server.addRecipe( enderBowRecipe ); 26 | // to remove... 27 | server.removeRemove( addedRecipe ); 28 | 29 | ***/ 30 | if (__plugin.canary) { 31 | module.exports = require('./canary/recipes'); 32 | } else { 33 | module.exports = require('./bukkit/recipes'); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/js/modules/signs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "signs", 3 | "main": "./signs.js" 4 | } 5 | -------------------------------------------------------------------------------- /src/main/js/modules/signs/signs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global __plugin, require, module, exports*/ 3 | /************************************************************************ 4 | ## Signs Module 5 | 6 | The Signs Module can be used by plugin authors to create interactive 7 | signs - that is - signs which display a list of choices which can be 8 | changed by interacting (right-clicking) with the sign. 9 | 10 | ### signs.menu() function 11 | 12 | This function is used to construct a new interactive menu on top of an 13 | existing sign in the game world. 14 | 15 | #### Parameters 16 | 17 | * Label : A string which will be displayed in the topmost line of the 18 | sign. This label is not interactive. 19 | * options : An array of strings which can be selected on the sign by 20 | right-clicking/interacting. 21 | * callback : A function which will be called whenever a player 22 | interacts (changes selection) on a sign. This callback in turn 23 | takes as its parameter, an object with the following properties... 24 | 25 | * player : The player who interacted with the sign. 26 | * sign : The [org.bukkit.block.Sign][buksign] which the player interacted with. 27 | * text : The text for the currently selected option on the sign. 28 | * number : The index of the currently selected option on the sign. 29 | 30 | * selectedIndex : optional: A number (starting at 0) indicating which 31 | of the options should be selected by default. 0 is the default. 32 | 33 | #### Returns 34 | This function does not itself do much. It does however return a 35 | function which when invoked with a given 36 | [org.bukkit.block.Sign][buksign] object, will convert that sign into 37 | an interactive sign. 38 | 39 | #### Example: Create a sign which changes the time of day. 40 | 41 | ##### plugins/signs/time-of-day.js 42 | 43 | ```javascript 44 | var utils = require('utils'), 45 | signs = require('signs'); 46 | 47 | var onTimeChoice = function(event){ 48 | var selectedIndex = event.number; 49 | // convert to Minecraft time 0 = Dawn, 6000 = midday, 12000 = dusk, 18000 = midnight 50 | var time = selectedIndex * 6000; 51 | event.player.location.world.setTime(time); 52 | }; 53 | 54 | // signs.menu returns a function which can be called for one or more signs in the game. 55 | var convertToTimeMenu = signs.menu('Time of Day', 56 | ['Dawn', 'Midday', 'Dusk', 'Midnight'], 57 | onTimeChoice); 58 | 59 | exports.time_sign = function( player ){ 60 | var sign = signs.getTargetedBy(player); 61 | if ( !sign ) { 62 | throw new Error('You must look at a sign'); 63 | } 64 | convertToTimeMenu(sign); 65 | }; 66 | ``` 67 | 68 | To use the above function at the in-game prompt, look at an existing 69 | sign and type... 70 | 71 | /js time_sign(self); 72 | 73 | ... and the sign you're looking at will become an interactive sign 74 | which changes the time each time you interact (right-click) with it. 75 | 76 | ### signs.getTargetedBy() function 77 | 78 | This function takes a [org.bukkit.entity.LivingEntity][bukle] as a 79 | parameter and returns a [org.bukkit.block.Sign][buksign] object which 80 | the entity has targeted. It is a utility function for use by plugin authors. 81 | 82 | #### Example 83 | 84 | ```javascript 85 | var signs = require('signs'), 86 | utils = require('utils'); 87 | var player = utils.player('tom1234'); 88 | var sign = signs.getTargetedBy( player ); 89 | if ( !sign ) { 90 | echo( player, 'Not looking at a sign'); 91 | } 92 | ``` 93 | 94 | [buksign]: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/block/Sign.html 95 | [bukle]: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/LivingEntity.html 96 | 97 | ***/ 98 | function hasSign(block) { 99 | if (__plugin.canary) { 100 | if (block && block.tileEntity && block.tileEntity.setTextOnLine) { 101 | return block.tileEntity; 102 | } 103 | } 104 | if (__plugin.bukkit) { 105 | if (block && block.state && block.state.setLine) { 106 | return block.state; 107 | } 108 | } 109 | return false; 110 | } 111 | var utils = require('utils'); 112 | var menu = require('./menu')(hasSign); 113 | // include all menu exports 114 | for (var i in menu) { 115 | exports[i] = menu[i]; 116 | } 117 | 118 | function getTargetedBy(livingEntity) { 119 | var location = utils.getMousePos(livingEntity); 120 | if (!location) { 121 | return null; 122 | } 123 | return hasSign(utils.blockAt(location)); 124 | } 125 | exports.getTargetedBy = getTargetedBy; 126 | exports.hasSign = hasSign; 127 | -------------------------------------------------------------------------------- /src/main/js/modules/slash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global module, require, server, __plugin*/ 3 | var _ = require('underscore'); 4 | /************************************************************************ 5 | ## The slash Module 6 | 7 | This module provides a single function which makes it easy to execute 8 | minecraft commands via javascript. 9 | 10 | ### The slash() function 11 | 12 | This function makes it easy to execute one or more minecraft commands. 13 | 14 | #### Parameters 15 | 16 | * commands : A String or Array of strings - each string is a command to be executed. 17 | * sender: (optional) The player on whose behalf the commands should be executed. If not specified the commands will be executed as the server console user. 18 | 19 | #### Examples 20 | 21 | Invoke the `/defaultgamemode creative` command (as server). 22 | 23 | ```javascript 24 | var slash = require('slash'); 25 | slash('defaultgamemode creative'); 26 | ``` 27 | 28 | Set the time of day to Midday and toggle downfall (as player 'JohnDoe'): 29 | 30 | ```javascript 31 | var slash = require('slash'), 32 | utils = require('utils'); 33 | var johnDoe = utils.player('John_Doe'); 34 | 35 | slash([ 36 | 'time set 6000', 37 | 'toggledownfall' 38 | ], johnDoe); 39 | ``` 40 | 41 | ***/ 42 | function slash(commands, sender) { 43 | if (_.isArray(commands)) { 44 | _.each(commands, function(command) { 45 | slash(command, sender); 46 | }); 47 | return; 48 | } 49 | if (__plugin.canary) { 50 | if (sender === server) { 51 | server.consoleCommand(commands); 52 | } else { 53 | server.consoleCommand(commands, sender); 54 | } 55 | } 56 | if (__plugin.bukkit) { 57 | if (!sender) { 58 | // if sender is not specified assume server console 59 | server.dispatchCommand(server.consoleSender, commands); 60 | } else { 61 | server.dispatchCommand(sender, commands); 62 | } 63 | } 64 | } 65 | module.exports = slash; 66 | -------------------------------------------------------------------------------- /src/main/js/modules/sounds.js: -------------------------------------------------------------------------------- 1 | if (__plugin.canary) { 2 | module.exports = require('./canary/sounds'); 3 | } else { 4 | module.exports = require('./bukkit/sounds'); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/js/modules/spawn.js: -------------------------------------------------------------------------------- 1 | /*global require, module, __plugin, Packages*/ 2 | 'use strict'; 3 | var entities = require('entities'); 4 | /************************************************************************ 5 | ## Spawn Module 6 | 7 | Provides a single function to 'spawn' an entity at a given location. 8 | 9 | ### Parameters 10 | 11 | * entityType - The type of entity to spawn. This can be a string (see entities module for reference) or a framework-specific object type (see https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/EntityType.html). A list of [all possible entities][ents] functions (equivalent to the EntityType enum). 12 | 13 | * location - where the entity should be spawned. 14 | 15 | [ents]: #entities-module 16 | 17 | ### Example 18 | 19 | Using the entities module as a helper, spawn a new polar bear at the world's default spawn location: 20 | 21 | ```javascript 22 | var entities = require('entities'), 23 | spawn = require('spawn'); 24 | ... 25 | var spawnLocation = world.spawnLocation; 26 | spawn(entities.polar_bear(), spawnLocation); 27 | ``` 28 | 29 | This module is in turn used by the Drone's `spawn()` method and the `jsp spawn` command. 30 | ***/ 31 | module.exports = function(entityType, location) { 32 | var entityTypeFn; 33 | if (typeof entityType === 'string') { 34 | entityTypeFn = entities[entityType.toLowerCase()]; 35 | entityType = entityTypeFn(); 36 | } 37 | var world = location.world; 38 | if (__plugin.bukkit) { 39 | world.spawnEntity(location, entityType); 40 | } 41 | if (__plugin.canary) { 42 | var Canary = Packages.net.canarymod.Canary, 43 | entityInstance = Canary.factory().entityFactory.newEntity( 44 | entityType, 45 | location 46 | ); 47 | entityInstance.spawn(); 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /src/main/js/modules/teleport.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global __plugin, org, module, require*/ 3 | var utils = require('utils'); 4 | /************************************************************************ 5 | ## Teleport Module 6 | 7 | This module provides a function to teleport entities (Players or NPCs). 8 | 9 | ### Parameters 10 | 11 | * entity - The player or NPC to be teleported. If of type String, then a player with that name will be teleported. 12 | * destination - The location to which they should be teleported. If not of type Location but is a Player, Block or any 13 | object which has a `location` property then that works too. If of type String, then it's assumed that the destination is the player with that name. 14 | 15 | ### Example 16 | 17 | The following code will teleport each player back to their spawn position. 18 | 19 | ```javascript 20 | var teleport = require('teleport'), 21 | utils = require('utils'), 22 | players = utils.players(), 23 | i = 0; 24 | for ( ; i < players.length; i++ ) { 25 | teleport( players[i], players[i].spawnPosition ); 26 | } 27 | ``` 28 | 29 | The following code will teleport 'tom' to 'jane's location. 30 | 31 | ```javascript 32 | var teleport = require('teleport'); 33 | teleport('tom' , 'jane'); 34 | ``` 35 | ***/ 36 | function teleport(entity, destination) { 37 | if (typeof entity === 'string' || entity instanceof java.lang.String) { 38 | entity = utils.player(entity); 39 | } 40 | if ( 41 | typeof destination === 'string' || 42 | destination instanceof java.lang.String 43 | ) { 44 | var player = utils.player(destination); 45 | if (player) { 46 | destination = player.location; 47 | } 48 | } else { 49 | if (destination.location) { 50 | destination = destination.location; 51 | } 52 | } 53 | if (__plugin.bukkit) { 54 | var bkTeleportCause = 55 | org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; 56 | entity.teleport(destination, bkTeleportCause.PLUGIN); 57 | } 58 | if (__plugin.canary) { 59 | var cmTeleportCause = 60 | Packages.net.canarymod.hook.player.TeleportHook.TeleportCause; 61 | entity.teleportTo(destination, cmTeleportCause.PLUGIN); 62 | } 63 | } 64 | module.exports = teleport; 65 | -------------------------------------------------------------------------------- /src/main/js/modules/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "utils", 3 | "main": "./utils.js" 4 | } 5 | -------------------------------------------------------------------------------- /src/main/js/modules/utils/string-exts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /************************************************************************ 3 | String class extensions 4 | ----------------------- 5 | The following chat-formatting methods are added to the javascript String class.. 6 | 7 | * aqua() 8 | * black() 9 | * blue() 10 | * bold() 11 | * brightgreen() 12 | * darkaqua() 13 | * darkblue() 14 | * darkgray() 15 | * darkgreen() 16 | * purple() 17 | * darkpurple() 18 | * darkred() 19 | * gold() 20 | * gray() 21 | * green() 22 | * italic() 23 | * lightpurple() 24 | * indigo() 25 | * green() 26 | * red() 27 | * pink() 28 | * yellow() 29 | * white() 30 | * strike() 31 | * random() 32 | * magic() 33 | * underline() 34 | * reset() 35 | 36 | Example 37 | ------- 38 | 39 | /js var boldGoldText = "Hello World".bold().gold(); 40 | /js echo(self, boldGoldText ); 41 | 42 |

Hello World

43 | 44 | ***/ 45 | var COLOR_CHAR = '\u00a7'; 46 | var formattingCodes = { 47 | aqua: 'b', 48 | black: '0', 49 | blue: '9', 50 | bold: 'l', 51 | brightgreen: 'a', 52 | darkaqua: '3', 53 | darkblue: '1', 54 | darkgray: '8', 55 | darkgreen: '2', 56 | purple: 'd', 57 | darkpurple: '5', 58 | darkred: '4', 59 | gold: '6', 60 | gray: '7', 61 | green: 'a', 62 | italic: 'o', 63 | lightpurple: 'd', 64 | indigo: '9', 65 | red: 'c', 66 | pink: 'd', 67 | yellow: 'e', 68 | white: 'f', 69 | strike: 'm', 70 | random: 'k', 71 | magic: 'k', 72 | underline: 'n', 73 | reset: 'r' 74 | }; 75 | for (var method in formattingCodes) { 76 | String.prototype[method] = (function(c) { 77 | return function() { 78 | return c + this; 79 | }; 80 | })(COLOR_CHAR + formattingCodes[method]); 81 | } 82 | -------------------------------------------------------------------------------- /src/main/js/plugins/at.js: -------------------------------------------------------------------------------- 1 | // ensure that the at world-load event handlers are 2 | // registered early in server startup 3 | require('at'); 4 | // nothing more needed. 5 | -------------------------------------------------------------------------------- /src/main/js/plugins/classroom.js: -------------------------------------------------------------------------------- 1 | /*global require, exports, command*/ 2 | var cr = require('classroom'); 3 | 4 | command( 5 | function classroom(params, sender) { 6 | if (params[0] == 'on') { 7 | cr.allowScripting(true, sender); 8 | } else { 9 | cr.allowScripting(false, sender); 10 | } 11 | }, 12 | ['on', 'off'] 13 | ); 14 | exports.classroom = cr; 15 | -------------------------------------------------------------------------------- /src/main/js/plugins/commando/commando-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | A test of the commando plugin. 3 | Adds a new `/js-time` command with 4 possible options: Dawn, Midday, Dusk, Midnight 4 | */ 5 | if (__plugin.canary) { 6 | console.warn('commando-test not yet supported in CanaryMod'); 7 | return; 8 | } 9 | var commando = require('./commando').commando, 10 | times = ['Dawn', 'Midday', 'Dusk', 'Midnight']; 11 | 12 | commando( 13 | 'js-time', 14 | function(params, sender) { 15 | var time = '' + params[0].toLowerCase(), 16 | i = 0; 17 | if (sender.location) { 18 | for (; i < 4; i++) { 19 | if (times[i].toLowerCase() == time) { 20 | sender.location.world.setTime(i * 6000); 21 | break; 22 | } 23 | } 24 | } else { 25 | echo(sender, 'This command only works in-world'); 26 | } 27 | }, 28 | times 29 | ); 30 | -------------------------------------------------------------------------------- /src/main/js/plugins/commando/commando.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## Commando Plugin 3 | 4 | ### Description 5 | 6 | commando is a plugin which can be used to add completely new commands 7 | to Minecraft. Normally ScriptCraft only allows for provision of new 8 | commands as extensions to the jsp command. For example, to create a 9 | new simple command for use by all players... 10 | 11 | /js command('hi', function(args,player){ echo( player, 'Hi ' + player.name); }); 12 | 13 | ... then players can use this command by typing... 14 | 15 | /jsp hi 16 | 17 | ... A couple of ScriptCraft users have asked for the ability to take 18 | this a step further and allow the global command namespace to be 19 | populated so that when a developer creates a new command using the 20 | 'command' function, then the command is added to the global command 21 | namespace so that players can use it simply like this... 22 | 23 | /hi 24 | 25 | ... There are good reasons why ScriptCraft's core `command()` function 26 | does not do this. Polluting the global namespace with commands would 27 | make ScriptCraft a bad citizen in that Plugins should be able to work 28 | together in the same server and - as much as possible - not step on 29 | each others' toes. The CraftBukkit team have very good reasons for 30 | forcing Plugins to declare their commands in the plugin.yml 31 | configuration file. It makes approving plugins easier and ensures that 32 | craftbukkit plugins behave well together. While it is possible to 33 | override other plugins' commands, the CraftBukkit team do not 34 | recommend this. However, as ScriptCraft users have suggested, it 35 | should be at the discretion of server administrators as to when 36 | overriding or adding new commands to the global namespace is good. 37 | 38 | So this is where `commando()` comes in. It uses the exact same 39 | signature as the core `command()` function but will also make the 40 | command accessible without the `jsp` prefix so instead of having to 41 | type `/jsp hi` for the above command example, players simply type 42 | `/hi` . This functionality is provided as a plugin rather than as part 43 | of the ScriptCraft core. 44 | 45 | ### Example hi-command.js 46 | 47 | var commando = require('../commando'); 48 | commando('hi', function(args,player){ 49 | echo( player, 'Hi ' + player.name); 50 | }); 51 | 52 | ...Displays a greeting to any player who issues the `/hi` command. 53 | 54 | ### Example - timeofday-command.js 55 | 56 | var times = {Dawn: 0, Midday: 6000, Dusk: 12000, Midnight:18000}; 57 | commando('timeofday', function(params,player){ 58 | player.location.world.setTime(times[params[0]]); 59 | }, 60 | ['Dawn','Midday','Dusk','Midnight']); 61 | 62 | ... changes the time of day using a new `/timeofday` command (options are Dawn, Midday, Dusk, Midnight) 63 | 64 | ### Caveats 65 | 66 | Since commands registered using commando are really just appendages to 67 | the `/jsp` command and are not actually registered globally (it just 68 | looks like that to the player), you won't be able to avail of tab 69 | completion for the command itself or its parameters (unless you go the 70 | traditional route of adding the `jsp` prefix). This plugin uses the 71 | [PlayerCommandPreprocessEvent][pcppevt] which allows plugins to 72 | intercepts all commands and inject their own commands instead. If 73 | anyone reading this knows of a better way to programmatically add new 74 | global commands for a plugin, please let me know. 75 | 76 | [pcppevt]: http://jd.bukkit.org/dev/apidocs/org/bukkit/event/player/PlayerCommandPreprocessEvent.html 77 | 78 | ***/ 79 | if (__plugin.canary) { 80 | console.warn('commando plugin is not yet supported in CanaryMod'); 81 | return; 82 | } 83 | var commands = {}; 84 | 85 | exports.commando = function(name, func, options, intercepts) { 86 | var result = command(name, func, options, intercepts); 87 | commands[name] = result; 88 | return result; 89 | }; 90 | 91 | events.playerCommandPreprocess(function(evt) { 92 | var msg = '' + evt.message; 93 | var parts = msg.match(/^\/([^\s]+)/); 94 | if (!parts) { 95 | return; 96 | } 97 | if (parts.length < 2) { 98 | return; 99 | } 100 | var command = parts[1]; 101 | if (commands[command]) { 102 | evt.message = '/jsp ' + msg.replace(/^\//, ''); 103 | } 104 | }); 105 | events.serverCommand(function(evt) { 106 | var msg = '' + evt.command; 107 | var parts = msg.match(/^\/*([^\s]+)/); 108 | if (!parts) { 109 | return; 110 | } 111 | if (parts.length < 2) { 112 | return; 113 | } 114 | var command = parts[1]; 115 | if (commands[command]) { 116 | var newCmd = 'jsp ' + msg.replace(/^\//, ''); 117 | if (config.verbose) { 118 | console.log('Redirecting to : %s', newCmd); 119 | } 120 | evt.command = newCmd; 121 | } 122 | }); 123 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/castle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require */ 3 | var Drone = require('drone'), 4 | blocks = require('blocks'); 5 | /************************************************************************ 6 | ### Drone.castle() method 7 | 8 | Creates a Castle. A castle is just a big wide fort with 4 taller forts at each corner. 9 | See also Drone.fort() method. 10 | 11 | #### Parameters 12 | 13 | * side - How many blocks wide and long the castle will be (default: 24. Must be greater than 19) 14 | * height - How tall the castle will be (default: 10. Must be geater than 7) 15 | 16 | #### Example 17 | 18 | At the in-game prompt you can create a castle by looking at a block and typing: 19 | 20 | ```javascript 21 | /js castle() 22 | ``` 23 | 24 | Alternatively you can create a new Drone object from a Player or Location object and call the castle() method. 25 | 26 | ```javascript 27 | var d = new Drone(player); 28 | d.castle(); 29 | ``` 30 | ![castle example](img/castleex1.png) 31 | 32 | ***/ 33 | function castle(side, height) { 34 | // 35 | // use sensible default parameter values 36 | // if no parameters are supplied 37 | // 38 | if (typeof side == 'undefined') side = 24; 39 | if (typeof height == 'undefined') height = 10; 40 | if (height < 8 || side < 20) 41 | throw new java.lang.RuntimeException( 42 | 'Castles must be at least 20 wide X 8 tall' 43 | ); 44 | // 45 | // how big the towers at each corner will be... 46 | // 47 | var towerSide = 10; 48 | var towerHeight = height + 4; 49 | 50 | // 51 | // the main castle building will be front and right of the first tower 52 | // 53 | this.chkpt('castle') 54 | .fwd(towerSide / 2) 55 | .right(towerSide / 2) 56 | .fort(side, height) 57 | .move('castle'); 58 | // 59 | // now place 4 towers at each corner (each tower is another fort) 60 | // 61 | for (var corner = 0; corner < 4; corner++) { 62 | // construct a 'tower' fort 63 | this.fort(towerSide, towerHeight) 64 | .chkpt('tower-' + corner) 65 | .fwd(towerSide - 1) 66 | .right(towerSide - 3) 67 | .up(towerHeight - 5) // create 2 doorways from main castle rampart into each tower 68 | .box(blocks.air, 1, 2, 1) 69 | .back(2) 70 | .right(2) 71 | .box(blocks.air, 1, 2, 1) 72 | .move('tower-' + corner) 73 | .fwd(side + towerSide - 1) // move forward the length of the castle then turn right 74 | .turn(); 75 | } 76 | this.move('castle'); 77 | } 78 | Drone.extend(castle); 79 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/chessboard.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require */ 3 | var Drone = require('drone'), 4 | blocks = require('blocks'); 5 | /************************************************************************ 6 | ### Drone.chessboard() method 7 | 8 | Creates a tile pattern of given block types and size 9 | 10 | #### Parameters 11 | 12 | * whiteBlock - (optional: default blocks.wool.white) 13 | * blackBlock - (optional: default blocks.wool.black) 14 | * width - width of the chessboard 15 | * length - length of the chessboard 16 | 17 | #### Example 18 | 19 | At the in-game prompt you can create a chessboard by looking at a block and typing: 20 | 21 | ```javascript 22 | /js chessboard() 23 | ``` 24 | 25 | Alternatively you can create a new Drone object from a Player or Location object and call the chessboard() method. 26 | 27 | ```javascript 28 | var d = new Drone(player); 29 | d.chessboard(); 30 | ``` 31 | ![chessboard example](img/chessboardex1.png) 32 | 33 | ***/ 34 | Drone.extend('chessboard', function(whiteBlock, blackBlock, width, depth) { 35 | var i; 36 | 37 | if (typeof whiteBlock == 'undefined') { 38 | whiteBlock = blocks.wool.white; 39 | } 40 | if (typeof blackBlock == 'undefined') { 41 | blackBlock = blocks.wool.black; 42 | } 43 | if (typeof width == 'undefined') { 44 | width = 8; 45 | } 46 | if (typeof depth == 'undefined') { 47 | depth = width; 48 | } 49 | var squares = [blackBlock, whiteBlock]; 50 | 51 | this.chkpt('chessboard-start'); 52 | for (i = 0; i < depth; i++) { 53 | this.boxa(squares, width, 1, 1).fwd(); 54 | squares = squares.reverse(); 55 | } 56 | this.move('chessboard-start'); 57 | }); 58 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/cottage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require */ 3 | var Drone = require('drone'), 4 | blocks = require('blocks'); 5 | /************************************************************************ 6 | ### Drone.cottage() method 7 | 8 | Creates a simple but cosy dwelling. 9 | 10 | #### Example 11 | 12 | At the in-game prompt you can create a cottage by looking at a block and typing: 13 | 14 | ```javascript 15 | /js cottage() 16 | ``` 17 | 18 | Alternatively you can create a new Drone object from a Player or Location object and call the cottage() method. 19 | 20 | ```javascript 21 | var d = new Drone(player); 22 | d.cottage(); 23 | ``` 24 | ![cottage example](img/cottageex1.png) 25 | 26 | ***/ 27 | function cottage() { 28 | this.chkpt('cottage') 29 | .down() 30 | .box(blocks.birch, 7, 1, 6) // birch wood floor 31 | .up() 32 | .box(blocks.air, 7, 5, 6) // clear area first 33 | .box0(blocks.moss_stone, 7, 2, 6) // 4 walls 34 | .right(3) 35 | .door() // door front and center 36 | .up(1) 37 | .left(2) 38 | .box(blocks.glass_pane) // windows to left and right 39 | .right(4) 40 | .box(blocks.glass_pane) 41 | .left(5) 42 | .up() 43 | .prism0(blocks.stairs.oak, 7, 6) // add a roof 44 | .down() 45 | .right(4) 46 | .back() 47 | .wallsign(['Home', 'Sweet', 'Home']) 48 | .fwd() 49 | .move('cottage') 50 | .right(3) 51 | .fwd(4) 52 | .up() 53 | .hangtorch() // place a torch on wall 54 | .move('cottage') 55 | .right() 56 | .fwd(3) 57 | .bed() // place a bed against left wall 58 | .fwd() 59 | .right(4) 60 | .box(blocks.furnace) // place a furnace against right wall 61 | .move('cottage'); 62 | } 63 | /************************************************************************ 64 | ### Drone.cottage_road() method 65 | 66 | Creates a tree-lined avenue with cottages on both sides. 67 | 68 | #### Parameters 69 | 70 | * numberOfCottages: The number of cottages to build in total (optional: default 6) 71 | 72 | #### Example 73 | 74 | At the in-game prompt you can create a cottage road by looking at a block and typing: 75 | 76 | ```javascript 77 | /js cottage_road() 78 | ``` 79 | 80 | Alternatively you can create a new Drone object from a Player or Location object and call the cottage_road() method. 81 | 82 | ```javascript 83 | var d = new Drone(player); 84 | d.cottage_road(); 85 | ``` 86 | ![cottage_road example](img/cottageroadex1.png) 87 | 88 | ***/ 89 | 90 | // 91 | // a more complex script that builds an tree-lined avenue with 92 | // cottages on both sides. 93 | // 94 | function cottage_road(numberCottages) { 95 | if (typeof numberCottages == 'undefined') { 96 | numberCottages = 6; 97 | } 98 | var i = 0, 99 | distanceBetweenTrees = 11; 100 | // 101 | // step 1 build the road. 102 | // 103 | var cottagesPerSide = Math.floor(numberCottages / 2); 104 | this 105 | // make sure the drone's state is saved. 106 | .chkpt('cottage_road') 107 | // build the road 108 | .box( 109 | blocks.double_slab.stone, 110 | 3, 111 | 1, 112 | cottagesPerSide * (distanceBetweenTrees + 1) 113 | ) 114 | .up() 115 | // now centered in middle of road 116 | .right() 117 | // will be returning to this position later 118 | .chkpt('cottage_road_cr'); 119 | 120 | // 121 | // step 2 line the road with trees 122 | // 123 | for (; i < cottagesPerSide + 1; i++) { 124 | this.left(5) 125 | .oak() 126 | .right(10) 127 | .oak() 128 | .left(5) // return to middle of road 129 | .fwd(distanceBetweenTrees + 1); // move forward. 130 | } 131 | this.move('cottage_road_cr').back(6); // move back 1/2 the distance between trees 132 | 133 | // this function builds a path leading to a cottage. 134 | function pathAndCottage(drone) { 135 | drone 136 | .down() 137 | .box(blocks.double_slab.stone, 1, 1, 5) 138 | .fwd(5) 139 | .left(3) 140 | .up() 141 | .cottage(); 142 | return drone; 143 | } 144 | // 145 | // step 3 build cottages on each side 146 | // 147 | for (i = 0; i < cottagesPerSide; i++) { 148 | this.fwd(distanceBetweenTrees + 1).chkpt('r' + i); 149 | // build cottage on left 150 | pathAndCottage(this.turn(3)).move('r' + i); 151 | // build cottage on right 152 | pathAndCottage(this.turn()).move('r' + i); 153 | } 154 | // return drone to where it was at start of function 155 | this.move('cottage_road'); 156 | } 157 | Drone.extend(cottage_road); 158 | Drone.extend(cottage); 159 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/dancefloor.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require, clearInterval, setInterval*/ 3 | var Drone = require('drone'), 4 | blocks = require('blocks'), 5 | SECOND = 1000; 6 | /************************************************************************ 7 | ### Drone.dancefloor() method 8 | Create an animated dance floor of colored tiles some of which emit light. 9 | The tiles change color every second creating a strobe-lit dance-floor effect. 10 | See it in action here [http://www.youtube.com/watch?v=UEooBt6NTFo][ytdance] 11 | 12 | #### Parameters 13 | 14 | * width - how wide the dancefloor should be (optional: default 5) 15 | * length - how long the dancefloor should be (optional: default 5) 16 | * duration - the time duration for which the lights should change (optional: default 30 seconds) 17 | 18 | #### Example 19 | 20 | At the in-game prompt you can create a dancefloor by looking at a block and typing: 21 | 22 | ```javascript 23 | /js dancefloor() 24 | ``` 25 | 26 | Alternatively you can create a new Drone object from a Player or Location object and call the dancefloor() method. 27 | 28 | ```javascript 29 | var d = new Drone(player); 30 | d.dancefloor(); 31 | ``` 32 | 33 | [ytdance]: http://www.youtube.com/watch?v=UEooBt6NTFo 34 | ![dancefloor example](img/dancefloorex1.png) 35 | ***/ 36 | 37 | // 38 | function dancefloor(width, length, duration) { 39 | if (typeof width == 'undefined') width = 5; 40 | if (typeof length == 'undefined') length = width; 41 | if (typeof duration === 'undefined') { 42 | duration = 30; 43 | } 44 | // 45 | // create a separate Drone object to lay down disco tiles 46 | // 47 | var disco = new Drone(this.x, this.y, this.z, this.dir, this.world); 48 | // 49 | // under-floor lighting 50 | // 51 | disco 52 | .down() 53 | .box(blocks.glowstone, width, 1, length) 54 | .up(); 55 | 56 | // 57 | // strobe gets called in a java thread - disco only lasts 30 seconds. 58 | // 59 | var task = null; 60 | var strobe = function() { 61 | disco.rand(blocks.rainbow, width, 1, length); 62 | duration--; 63 | if (duration == 0) { 64 | // turn off the lights 65 | clearInterval(task); 66 | } 67 | }; 68 | task = setInterval(strobe, 1 * SECOND); 69 | } 70 | Drone.extend(dancefloor); 71 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/fort.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require */ 3 | var Drone = require('drone'), 4 | blocks = require('blocks'); 5 | /************************************************************************ 6 | ### Drone.fort() method 7 | 8 | Constructs a medieval fort. 9 | 10 | #### Parameters 11 | 12 | * side - How many blocks whide and long the fort will be (default: 18 . Must be greater than 9) 13 | * height - How tall the fort will be (default: 6 . Must be greater than 3) 14 | 15 | #### Example 16 | 17 | At the in-game prompt you can create a fort by looking at a block and typing: 18 | 19 | ```javascript 20 | /js fort() 21 | ``` 22 | 23 | Alternatively you can create a new Drone object from a Player or Location object and call the fort() method. 24 | 25 | ```javascript 26 | var d = new Drone(player); 27 | d.fort(); 28 | ``` 29 | ![fort example](img/fortex1.png) 30 | 31 | ***/ 32 | 33 | function fort(side, height) { 34 | var turret, i, torch; 35 | 36 | if (typeof side == 'undefined') { 37 | side = 18; 38 | } 39 | if (typeof height == 'undefined') { 40 | height = 6; 41 | } 42 | // make sure side is even 43 | if (side % 2) { 44 | side++; 45 | } 46 | var battlementWidth = 3; 47 | if (side <= 12) { 48 | battlementWidth = 2; 49 | } 50 | if (height < 4 || side < 10) { 51 | throw new java.lang.RuntimeException( 52 | 'Forts must be at least 10 wide X 4 tall' 53 | ); 54 | } 55 | // 56 | // build walls. 57 | // 58 | this.chkpt('fort') 59 | .down() 60 | .chessboard(blocks.wool.black, blocks.wool.white, side) 61 | .up() 62 | .box0(blocks.brick.stone, side, height - 1, side) 63 | .up(height - 1); 64 | // 65 | // build battlements 66 | // 67 | for (i = 0; i <= 3; i++) { 68 | turret = [ 69 | blocks.stairs.stone, 70 | blocks.stairs.stone + ':' + Drone.PLAYER_STAIRS_FACING[(this.dir + 2) % 4] 71 | ]; 72 | this.box(blocks.brick.stone) // solid brick corners 73 | .up() 74 | .box(blocks.torch) 75 | .down() // light a torch on each corner 76 | .fwd() 77 | .boxa(turret, 1, 1, side - 2) 78 | .fwd(side - 2) 79 | .turn(); 80 | } 81 | // 82 | // build battlement's floor 83 | // 84 | this.move('fort') 85 | .up(height - 2) 86 | .fwd() 87 | .right(); 88 | 89 | for (i = 0; i < battlementWidth; i++) { 90 | var bside = side - (2 + i * 2); 91 | this.box0(blocks.slab.oak, bside, 1, bside) 92 | .fwd() 93 | .right(); 94 | } 95 | // 96 | // add door 97 | // 98 | torch = blocks.torch + ':' + Drone.PLAYER_TORCH_FACING[this.dir]; 99 | this.move('fort') 100 | .right(side / 2 - 1) 101 | .door2() // double doors 102 | .back() 103 | .left() 104 | .up() 105 | .box(torch) // left torch 106 | .right(3) 107 | .box(torch); // right torch 108 | // 109 | // add ladder up to battlements 110 | // 111 | this.move('fort') 112 | .right(side / 2 - 3) 113 | .fwd() // move inside fort 114 | .turn(2) 115 | .box(blocks.air, 1, height - 1, 1) 116 | .ladder(height - 1) 117 | .move('fort'); 118 | } 119 | Drone.extend(fort); 120 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/hangtorch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require, __plugin, org*/ 3 | var Drone = require('drone'), 4 | blocks = require('blocks'); 5 | /************************************************************************ 6 | ### Drone.hangtorch() method 7 | 8 | Adds a hanging torch to a wall. This method will try to hang a torch 9 | against a wall. It will traverse backwards until it finds a block 10 | adjacent to air and hang the torch. If it can't find a block next to 11 | air it will log a message in the server. 12 | 13 | #### Example 14 | 15 | At the in-game prompt you can create a hanging torch by looking at a 16 | block and typing: 17 | 18 | ```javascript 19 | /js hangtorch() 20 | ``` 21 | 22 | Alternatively you can create a new Drone object from a Player or 23 | Location object and call the hangtorch() method. 24 | 25 | ```javascript 26 | var d = new Drone(player); 27 | d.hangtorch(); 28 | ``` 29 | 30 | ***/ 31 | function canHang(block) { 32 | if (__plugin.bukkit) { 33 | var bkMaterial = org.bukkit.Material; 34 | if ( 35 | block.type.equals(bkMaterial.AIR) || 36 | block.type.equals(bkMaterial.VINE) 37 | ) { 38 | return true; 39 | } 40 | } 41 | if (__plugin.canary) { 42 | if (block.typeId == blocks.air || block.typeId == blocks.vines) { 43 | return true; 44 | } 45 | } 46 | return false; 47 | } 48 | function hangtorch() { 49 | var torch = blocks.torch + ':' + Drone.PLAYER_TORCH_FACING[this.dir]; 50 | var moves = 0; 51 | var block = this.getBlock(); 52 | 53 | while (!canHang(block)) { 54 | moves++; 55 | this.back(); 56 | if (moves == 10) { 57 | this.fwd(moves); 58 | console.log('nowhere to hang torch'); 59 | return; 60 | } 61 | block = this.getBlock(); 62 | } 63 | this.box(torch).fwd(moves); 64 | } 65 | Drone.extend(hangtorch); 66 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/lcd-clock.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require, setInterval, clearInterval, __plugin, exports*/ 3 | /************************************************************************* 4 | ### Drone.lcdclock() method. 5 | 6 | Constructs a large LCD Clock. The clock will display the current time of day. 7 | The clock can be stopped by calling the stopLCD() method of the Drone which created the clock. 8 | 9 | #### Parameters 10 | 11 | * foregroundBlock (Optional - default is blocks.glowstone) 12 | * backgroundBlock (Optional - default is blocks.wool.black) 13 | * borderBlock (Optional - a border around the LCD display - default none) 14 | 15 | #### Example 16 | 17 | At the in-game prompt you can create a LCD clock by looking at a block and typing: 18 | 19 | ```javascript 20 | /js var clock = lcdclock() 21 | /js clock.stopLCD() 22 | ``` 23 | 24 | Alternatively you can create a new Drone object from a Player or Location object and call the lcdclock() method. 25 | 26 | ```javascript 27 | var d = new Drone(player); 28 | d.lcdclock(); 29 | d.stopLCD(); 30 | ``` 31 | ![lcdclock example](img/lcdclockex1.png) 32 | ***/ 33 | var blocks = require('blocks'), 34 | utils = require('utils'), 35 | Drone = require('drone'); 36 | 37 | function lcdclock(fgColor, bgColor, border) { 38 | var drone = this; 39 | var lastSecs = [0, 0, 0, 0], 40 | world = drone.world, 41 | intervalId = -1; 42 | 43 | function update(secs) { 44 | var digits = [0, 0, 0, 0], 45 | s = secs % 60, 46 | m = (secs - s) / 60; 47 | digits[3] = s % 10; 48 | digits[2] = (s - digits[3]) / 10; 49 | digits[1] = m % 10; 50 | digits[0] = (m - digits[1]) / 10; 51 | // 52 | // updating all 4 digits each time is expensive 53 | // only update digits which have changed (in most cases - just 1) 54 | // 55 | if (digits[3] != lastSecs[3]) { 56 | drone 57 | .right(14) 58 | .blocktype('' + digits[3], fgColor, bgColor, true) 59 | .left(14); 60 | } 61 | if (digits[2] != lastSecs[2]) { 62 | drone 63 | .right(10) 64 | .blocktype('' + digits[2], fgColor, bgColor, true) 65 | .left(10); 66 | } 67 | if (digits[1] != lastSecs[1]) { 68 | drone 69 | .right(4) 70 | .blocktype('' + digits[1], fgColor, bgColor, true) 71 | .left(4); 72 | } 73 | if (digits[0] != lastSecs[0]) { 74 | drone.blocktype('' + digits[0], fgColor, bgColor, true); 75 | } 76 | lastSecs[0] = digits[0]; 77 | lastSecs[1] = digits[1]; 78 | lastSecs[2] = digits[2]; 79 | lastSecs[3] = digits[3]; 80 | } 81 | if (typeof bgColor == 'undefined') { 82 | bgColor = blocks.wool.black; 83 | } 84 | if (typeof fgColor == 'undefined') { 85 | fgColor = blocks.glowstone; 86 | } 87 | if (border) { 88 | drone.box(border, 21, 9, 1); 89 | drone.up().right(); 90 | } 91 | drone.blocktype('00:00', fgColor, bgColor, true); 92 | 93 | function tick() { 94 | var timeOfDayInMins = utils.time24(world); 95 | update(timeOfDayInMins); 96 | } 97 | intervalId = setInterval(tick, 800); 98 | this.stopLCD = function() { 99 | clearInterval(intervalId); 100 | }; 101 | } 102 | 103 | Drone.extend(lcdclock); 104 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/mazegen.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require*/ 3 | /************************************************************************ 4 | ### Drone.maze() method 5 | 6 | Maze generation based on http://rosettacode.org/wiki/Maze_generation#JavaScript 7 | 8 | #### Parameters 9 | 10 | * width (optional - default 10) 11 | * length (optional - default 10) 12 | 13 | #### Example 14 | 15 | At the in-game prompt you can create a maze by looking at a block and typing: 16 | 17 | ```javascript 18 | /js maze() 19 | ``` 20 | 21 | Alternatively you can create a new Drone object from a Player or Location object and call the maze() method. 22 | 23 | ```javascript 24 | var d = new Drone(player); 25 | d.maze(); 26 | ``` 27 | ![maze example](img/mazeex1.png) 28 | 29 | ***/ 30 | var Drone = require('drone'), 31 | blocks = require('blocks'); 32 | 33 | // User-facing code starts here 34 | // Example: Try /js maze(5,7) 35 | Drone.extend(function maze(width, length) { 36 | if (typeof width === 'undefined') { 37 | width = 10; 38 | } 39 | if (typeof length === 'undefined') { 40 | length = 10; 41 | } 42 | var m = maze_make(width, length); 43 | if (m.x > 0 && m.y > 0) { 44 | maze_draw(maze_display(m), this); 45 | } 46 | }); 47 | // 48 | // Implementation 49 | // 50 | function maze_make(x, y) { 51 | var n = x * y - 1; 52 | if (n < 0) { 53 | console.log('illegal maze dimensions'); 54 | return { x: 0, y: 0 }; 55 | } 56 | var horiz = []; 57 | var j; 58 | for (j = 0; j < x + 1; j++) horiz[j] = []; 59 | var verti = []; 60 | for (j = 0; j < y + 1; j++) verti[j] = []; 61 | var here = [Math.floor(Math.random() * x), Math.floor(Math.random() * y)]; 62 | var path = [here]; 63 | var unvisited = []; 64 | for (j = 0; j < x + 2; j++) { 65 | unvisited[j] = []; 66 | for (var k = 0; k < y + 1; k++) 67 | unvisited[j].push( 68 | j > 0 && j < x + 1 && k > 0 && (j != here[0] + 1 || k != here[1] + 1) 69 | ); 70 | } 71 | while (0 < n) { 72 | var potential = [ 73 | [here[0] + 1, here[1]], 74 | [here[0], here[1] + 1], 75 | [here[0] - 1, here[1]], 76 | [here[0], here[1] - 1] 77 | ]; 78 | var neighbors = []; 79 | for (j = 0; j < 4; j++) 80 | if (unvisited[potential[j][0] + 1][potential[j][1] + 1]) 81 | neighbors.push(potential[j]); 82 | if (neighbors.length) { 83 | n = n - 1; 84 | var next = neighbors[Math.floor(Math.random() * neighbors.length)]; 85 | unvisited[next[0] + 1][next[1] + 1] = false; 86 | if (next[0] == here[0]) 87 | horiz[next[0]][(next[1] + here[1] - 1) / 2] = true; 88 | else verti[(next[0] + here[0] - 1) / 2][next[1]] = true; 89 | path.push((here = next)); 90 | } else here = path.pop(); 91 | } 92 | return { x: x, y: y, horiz: horiz, verti: verti }; 93 | } 94 | 95 | function maze_display(m) { 96 | var text = [], 97 | k, 98 | j; 99 | for (j = 0; j < m.x * 2 + 1; j++) { 100 | var line = []; 101 | if (0 == j % 2) 102 | for (k = 0; k < m.y * 4 + 1; k++) 103 | if (0 == k % 4) line[k] = '+'; 104 | else if (j > 0 && m.verti[j / 2 - 1][Math.floor(k / 4)]) line[k] = ' '; 105 | else line[k] = '-'; 106 | else 107 | for (k = 0; k < m.y * 4 + 1; k++) 108 | if (0 == k % 4) 109 | if (k > 0 && m.horiz[(j - 1) / 2][k / 4 - 1]) line[k] = ' '; 110 | else line[k] = '|'; 111 | else line[k] = ' '; 112 | if (0 == j) line[1] = line[2] = line[3] = ' '; 113 | if (m.x * 2 - 1 == j) line[4 * m.y] = ' '; 114 | text.push(line.join('') + ' \r\n'); // TWEAKED: space added to get an even number of columns 115 | } 116 | return text.join(''); 117 | } 118 | 119 | // ScriptCraft stuff starts here 120 | // Helper function to parse the ASCII art into Drone actions 121 | // You might also consider creating a new maze_display but for now this will do the work 122 | function maze_draw(maze_string, d) { 123 | // d is the Drone to use 124 | d.chkpt('maze-start'); 125 | for (var j = 0; j < maze_string.length; j += 2) { 126 | switch (maze_string.substr(j, 2)) { 127 | case ' ': 128 | d.box(0).fwd(); // Make sure to empty this position 129 | break; 130 | case '\r\n': 131 | d.move('maze-start'); 132 | d.right().chkpt('maze-start'); 133 | break; 134 | default: 135 | // '+ ', '+-', '--', '| ' 136 | if (j == 0) { 137 | d.box(blocks.glowstone, 1, 2, 1); // highlight the maze entry and exit 138 | } else if (j == maze_string.length - 4) { 139 | d.box(blocks.glass, 1, 2, 1); 140 | } else { 141 | d.box(blocks.oak, 1, 2, 1); 142 | } 143 | d.fwd(); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/rainbow.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require*/ 3 | var Drone = require('drone'), 4 | blocks = require('blocks'); 5 | 6 | /************************************************************************ 7 | ### Drone.rainbow() method 8 | 9 | Creates a Rainbow. 10 | 11 | #### Parameters 12 | 13 | * radius (optional - default:18) - The radius of the rainbow 14 | 15 | #### Example 16 | 17 | At the in-game prompt you can create a rainbow by looking at a block and typing: 18 | ```javascript 19 | /js rainbow() 20 | ``` 21 | 22 | Alternatively you can create a new Drone object from a Player or Location object and call the rainbow() method. 23 | 24 | ```javascript 25 | var d = new Drone(player); 26 | d.rainbow(30); 27 | ``` 28 | 29 | ![rainbow example](img/rainbowex1.png) 30 | 31 | ***/ 32 | function rainbow(radius) { 33 | var i, colors, bm; 34 | 35 | if (typeof radius == 'undefined') { 36 | radius = 18; 37 | } 38 | 39 | this.chkpt('rainbow'); 40 | this.down(radius); 41 | // copy blocks.rainbow and add air at end (to compensate for strokewidth) 42 | colors = blocks.rainbow.slice(0); 43 | colors.push(blocks.air); 44 | for (i = 0; i < colors.length; i++) { 45 | bm = this.getBlockIdAndMeta(colors[i]); 46 | this.arc({ 47 | blockType: bm[0], 48 | meta: bm[1], 49 | radius: radius - i, 50 | strokeWidth: 2, 51 | quadrants: { 52 | topright: true, 53 | topleft: true 54 | }, 55 | orientation: 'vertical' 56 | }) 57 | .right() 58 | .up(); 59 | } 60 | return this.move('rainbow'); 61 | } 62 | Drone.extend(rainbow); 63 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/redstonewire.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require*/ 3 | var Drone = require('drone'); 4 | 5 | // 6 | // usage: 7 | // [1] to place a new block with redstone wire on it (block on bottom, redstone on top) 8 | // /js wireblock(blocks.sandstone); 9 | // 10 | // [2] to drop wire on to an existing block 11 | // /js wire() 12 | // 13 | // [3] to place a (redstone) torch on a new block 14 | // /js torchblock(blocks.sandstone) 15 | // 16 | // [4] to place a repeater on a new block 17 | // /js repeaterblock(blocks.sandstone) 18 | // 19 | // [5] To create a long redstone wire (with necessary repeaters, powererd by a single torch) 20 | // /js wirestraight(blocks.sandstone, distance) 21 | // 22 | // [6] To create a 'road' with redstone torches and wire lining each side 23 | // /js redstoneroad(blocks.stone, blocks.sandstone, 25) 24 | 25 | Drone.extend('wireblock', function(blockType) { 26 | this.chkpt('wireblock') 27 | .box(blockType, 1, 2, 1) // 2 blocks tall, top block will be wire dropped on lower 28 | .up(); 29 | 30 | this.world.getBlockAt(this.x, this.y, this.z).setTypeId(55); //apply wire 31 | 32 | return this.move('wireblock'); 33 | }); 34 | 35 | Drone.extend('wire', function() { 36 | this.chkpt('wire').up(); 37 | 38 | this.world.getBlockAt(this.x, this.y, this.z).setTypeId(55); // apply wire 39 | 40 | return this.move('wire'); 41 | }); 42 | 43 | Drone.extend('torchblock', function(blockType) { 44 | this.box(blockType, 1, 2, 1) // 2 blocks tall 45 | .up(); 46 | 47 | this.world.getBlockAt(this.x, this.y, this.z).setTypeId(76); // apply torch 48 | 49 | return this.down(); 50 | }); 51 | 52 | Drone.extend('repeaterblock', function(blockType) { 53 | this.chkpt('repeaterblock') 54 | .box(blockType, 1, 2, 1) 55 | .up(); 56 | 57 | var block = this.world.getBlockAt(this.x, this.y, this.z); 58 | block.setTypeId(94); // apply repeater 59 | 60 | // redstone repeater dirs: north=0,east=1,south=2,west=3 61 | var direction = [1, 2, 3, 0][this.dir]; // convert drone dir to repeater dir. 62 | block.setData(direction); 63 | 64 | return this.move('repeaterblock'); 65 | }); 66 | 67 | Drone.extend('wirestraight', function(blockType, distance) { 68 | this.chkpt('wirestraight'); 69 | 70 | this.torchblock(blockType); 71 | this.fwd(); 72 | 73 | for (var i = 1; i < distance; i++) { 74 | if (i % 14 == 0) { 75 | this.repeaterblock(blockType); 76 | } else { 77 | this.wireblock(blockType); 78 | } 79 | 80 | this.fwd(); 81 | } 82 | 83 | return this.move('wirestraight'); 84 | }); 85 | 86 | Drone.extend('redstoneroad', function( 87 | roadBlockType, 88 | redstoneunderBlockType, 89 | distance 90 | ) { 91 | return this.down() 92 | .wirestraight(redstoneunderBlockType, distance) 93 | .right() 94 | .box(roadBlockType, 4, 1, distance) 95 | .right(4) 96 | .wirestraight(redstoneunderBlockType, distance) 97 | .up(); 98 | }); 99 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/spawn.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var spawnFn = require('spawn'), 3 | Drone = require('drone'); 4 | function spawn(entityType) { 5 | spawnFn(entityType, this.getBlock().location); 6 | } 7 | Drone.extend(spawn); 8 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/spiral_stairs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require*/ 3 | var Drone = require('drone'), 4 | blocks = require('blocks'); 5 | 6 | /************************************************************************ 7 | ### Drone.spiral_stairs() method 8 | 9 | Constructs a spiral staircase with slabs at each corner. 10 | 11 | #### Parameters 12 | 13 | * stairBlock - The block to use for stairs, should be one of the following... 14 | - 'oak' 15 | - 'spruce' 16 | - 'birch' 17 | - 'jungle' 18 | - 'cobblestone' 19 | - 'brick' 20 | - 'stone' 21 | - 'nether' 22 | - 'sandstone' 23 | - 'quartz' 24 | * flights - The number of flights of stairs to build. 25 | 26 | ![Spiral Staircase](img/spiralstair1.png) 27 | 28 | #### Example 29 | 30 | To construct a spiral staircase 5 floors high made of oak... 31 | 32 | spiral_stairs('oak', 5); 33 | 34 | ***/ 35 | function spiral_stairs(stairBlock, flights) { 36 | this.chkpt('spiral_stairs'); 37 | 38 | for (var i = 0; i < flights; i++) { 39 | this.box(blocks.stairs[stairBlock]) 40 | .up() 41 | .fwd() 42 | .box(blocks.stairs[stairBlock]) 43 | .up() 44 | .fwd() 45 | .box(blocks.slab[stairBlock]) 46 | .turn() 47 | .fwd(); 48 | } 49 | this.move('spiral_stairs'); 50 | } 51 | Drone.extend(spiral_stairs); 52 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/contrib/temple.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require*/ 3 | var Drone = require('drone'), 4 | blocks = require('blocks'); 5 | /************************************************************************ 6 | ### Drone.temple() method 7 | 8 | Constructs a mayan temple. 9 | 10 | #### Parameters 11 | 12 | * side - How many blocks wide and long the temple will be (default: 20) 13 | 14 | #### Example 15 | 16 | At the in-game prompt you can create a temple by looking at a block and typing: 17 | 18 | ```javascript 19 | /js temple() 20 | ``` 21 | 22 | Alternatively you can create a new Drone object from a Player or Location object and call the temple() method. 23 | 24 | ```javascript 25 | var d = new Drone(player); 26 | d.temple(); 27 | ``` 28 | ![temple example](img/templeex1.png) 29 | 30 | ***/ 31 | function temple(side) { 32 | if (!side) { 33 | side = 20; 34 | } 35 | this.chkpt('temple'); 36 | 37 | while (side > 4) { 38 | var middle = Math.round((side - 2) / 2); 39 | this.chkpt('temple-corner') 40 | .box(blocks.brick.mossy, side, 1, side) 41 | .right(middle) 42 | .box(blocks.stairs.stone) 43 | .right() 44 | .box(blocks.stairs.stone) 45 | .move('temple-corner') 46 | .up() 47 | .fwd() 48 | .right(); 49 | side = side - 2; 50 | } 51 | 52 | this.move('temple'); 53 | } 54 | Drone.extend(temple); 55 | -------------------------------------------------------------------------------- /src/main/js/plugins/drone/drone.js: -------------------------------------------------------------------------------- 1 | /*global require, exports*/ 2 | var blocks = require('blocks'); 3 | exports.Drone = require('drone'); 4 | exports.blocks = blocks; 5 | -------------------------------------------------------------------------------- /src/main/js/plugins/entities.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global require, exports*/ 3 | /* 4 | make entities a global variable for use at in-game prompt 5 | Tab completion is a useful way to discover what entity types are available. 6 | */ 7 | var entities = require('entities'); 8 | exports.entities = entities; 9 | -------------------------------------------------------------------------------- /src/main/js/plugins/examples/example-1-hello-module.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## Example Plugin #1 - A simple extension to Minecraft. 3 | 4 | A simple minecraft plugin. The most basic module. 5 | 6 | ### Usage: 7 | 8 | At the in-game prompt type ... 9 | 10 | /js hello(self) 11 | 12 | ... and a message `Hello {player-name}` will appear (where 13 | {player-name} is replaced by your own name). 14 | 15 | This example demonstrates the basics of adding new functionality which 16 | is only usable by server operators or users with the 17 | scriptcraft.evaluate permission. By default, only ops are granted this 18 | permission. 19 | 20 | The `hello` function below is only usable by players with the scriptcraft.evaluate 21 | permission since it relies on the `/js` command to execute. 22 | 23 | exports.hello = function(player){ 24 | echo( player, 'Hello ' + player.name); 25 | }; 26 | 27 | ***/ 28 | exports.hello = function(player) { 29 | echo(player, 'Hello ' + player.name); 30 | }; 31 | -------------------------------------------------------------------------------- /src/main/js/plugins/examples/example-2-hello-command.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## Example Plugin #2 - Making extensions available for all players. 3 | 4 | A simple minecraft plugin. Commands for other players. 5 | 6 | ### Usage: 7 | 8 | At the in-game prompt type ... 9 | 10 | /jsp hello 11 | 12 | ... and a message `Hello {player-name}` will appear (where {player-name} is 13 | replaced by your own name). 14 | 15 | This example demonstrates the basics of adding new functionality 16 | which is usable all players or those with the scriptcraft.proxy 17 | permission. By default, all players are granted this permission. 18 | 19 | This differs from example 1 in that a new 'jsp ' command extension 20 | is defined. Since all players can use the `jsp` command, all players 21 | can use the new extension. Unlike the previous example, the `jsp hello` 22 | command does not evaluate javascript code so this command is much more secure. 23 | 24 | command('hello', function (parameters, player) { 25 | echo( player, 'Hello ' + player.name); 26 | }); 27 | 28 | ***/ 29 | 30 | command('hello', function(parameters, player) { 31 | echo(player, 'Hello ' + player.name); 32 | }); 33 | -------------------------------------------------------------------------------- /src/main/js/plugins/examples/example-3-hello-ops-only.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## Example Plugin #3 - Limiting use of commands to operators only. 3 | 4 | A simple minecraft plugin. Commands for operators only. 5 | 6 | ### Usage: 7 | 8 | At the in-game prompt type ... 9 | 10 | /jsp op-hello 11 | 12 | ... and a message `Hello {player-name}` will appear (where {player-name} is 13 | replaced by your own name). 14 | 15 | This example demonstrates the basics of adding new functionality 16 | which is usable all players or those with the scriptcraft.proxy 17 | permission. By default, all players are granted this permission. In 18 | this command though, the function checks to see if the player is an 19 | operator and if they aren't will return immediately. 20 | 21 | This differs from example 2 in that the function will only print a 22 | message for operators. 23 | 24 | command('op-hello', function (parameters, player) { 25 | if ( !isOp(player) ){ 26 | echo( player, 'Only operators can do this.'); 27 | return; 28 | } 29 | echo( player, 'Hello ' + player.name); 30 | }); 31 | ***/ 32 | 33 | command('op-hello', function(parameters, player) { 34 | /* 35 | this is how you limit based on player privileges 36 | */ 37 | if (!isOp(player)) { 38 | echo(player, 'Only operators can do this.'); 39 | return; 40 | } 41 | echo(player, 'Hello ' + player.name); 42 | }); 43 | -------------------------------------------------------------------------------- /src/main/js/plugins/examples/example-4-hello-parameters.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## Example Plugin #4 - Using parameters in commands. 3 | 4 | A simple minecraft plugin. Handling parameters. 5 | 6 | ### Usage: 7 | 8 | At the in-game prompt type ... 9 | 10 | /jsp hello-params Hi 11 | /jsp hello-params Saludos 12 | /jsp hello-params Greetings 13 | 14 | ... and a message `Hi {player-name}` or `Saludos {player-name}` etc 15 | will appear (where {player-name} is replaced by your own name). 16 | 17 | This example demonstrates adding and using parameters in commands. 18 | 19 | This differs from example 3 in that the greeting can be changed from 20 | a fixed 'Hello ' to anything you like by passing a parameter. 21 | 22 | command( 'hello-params', function ( parameters, player ) { 23 | var salutation = parameters[0] ; 24 | echo( player, salutation + ' ' + player.name ); 25 | }); 26 | 27 | ***/ 28 | 29 | command('hello-params', function(parameters, player) { 30 | /* 31 | parameters is an array (or list) of strings. parameters[0] 32 | refers to the first element in the list. Arrays in Javascript 33 | are 0-based. That is, the 1st element is parameters[0], the 2nd 34 | element is parameters[1], the 3rd element is parameters[2] and 35 | so on. In this example, parameters[1] refers to the first word 36 | which appears after `jsp hello-params `. 37 | */ 38 | var salutation = parameters[0]; 39 | echo(player, salutation + ' ' + player.name); 40 | }); 41 | -------------------------------------------------------------------------------- /src/main/js/plugins/examples/example-5-hello-using-module.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## Example Plugin #5 - Re-use - Using your own and others modules. 3 | 4 | A simple minecraft plugin. Using Modules. 5 | 6 | ### Usage: 7 | 8 | At the in-game prompt type ... 9 | 10 | /jsp hello-module 11 | 12 | ... and a message `Hello {player-name}` will appear (where {player-name} is 13 | replaced by your own name). 14 | 15 | This example demonstrates the use of modules. In 16 | example-1-hello-module.js we created a new javascript module. In 17 | this example, we use that module... 18 | 19 | * We load the module using the `require()` function. Because this 20 | module and the module we require are n the same directory, we 21 | specify `'./example-1-hello-module'` as the path (when loading a 22 | module from the same directory, `./` at the start of the path 23 | indicates that the file should be searched for in the same 24 | directory. 25 | 26 | * We assign the loaded module to a variable (`greetings`) and then 27 | use the module's `hello` method to display the message. 28 | 29 | Source Code... 30 | 31 | var greetings = require('./example-1-hello-module'); 32 | command( 'hello-module', function( parameters, player ) { 33 | greetings.hello( player ); 34 | }); 35 | 36 | ***/ 37 | var greetings = require('./example-1-hello-module'); 38 | 39 | command('hello-module', function(parameters, player) { 40 | greetings.hello(player); 41 | }); 42 | -------------------------------------------------------------------------------- /src/main/js/plugins/examples/example-6-hello-player.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## Example Plugin #6 - Re-use - Using 'utils' to get Player objects. 3 | 4 | A simple minecraft plugin. Finding players by name. 5 | 6 | ### Usage: 7 | 8 | At the in-game prompt type ... 9 | 10 | /jsp hello-byname {player-name} 11 | 12 | ... substituting {player-name} with the name of a player currently 13 | online and a message `Hello ...` will be sent to the named 14 | player. 15 | 16 | This example builds on example-5 and also introduces a new concept - 17 | use of shared modules. That is : modules which are not specific to 18 | any one plugin or set of plugins but which can be used by all 19 | plugins. Shared modules should be placed in the 20 | `scriptcraft/modules` directory. 21 | 22 | * The utils module is used. Because the 'utils' module is 23 | located in the modules folder we don't need to specify an exact 24 | path, just 'utils' will do. 25 | 26 | * The `utils.player()` function is used to obtain a player object 27 | matching the player name. Once a player object is obtained, a 28 | message is sent to that player. 29 | 30 | Source Code ... 31 | 32 | var utils = require('utils'); 33 | var greetings = require('./example-1-hello-module'); 34 | 35 | command( 'hello-byname', function( parameters, sender ) { 36 | var playerName = parameters[0]; 37 | var recipient = utils.player( playerName ); 38 | if ( recipient ) { 39 | greetings.hello( recipient ); 40 | } else { 41 | echo( sender, 'Player ' + playerName + ' not found.' ); 42 | } 43 | }); 44 | 45 | ***/ 46 | 47 | var utils = require('utils'); 48 | var greetings = require('./example-1-hello-module'); 49 | 50 | command('hello-byname', function(parameters, sender) { 51 | var playerName = parameters[0]; 52 | var recipient = utils.player(playerName); 53 | if (recipient) { 54 | greetings.hello(recipient); 55 | } else { 56 | echo(sender, 'Player ' + playerName + ' not found.'); 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /src/main/js/plugins/examples/example-7-hello-events.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global events, echo, isOp, __plugin*/ 3 | /************************************************************************* 4 | ## Example Plugin #7 - Listening for events, Greet players when they join the game. 5 | 6 | A simple event-driven minecraft plugin. How to handle Events. 7 | 8 | This example demonstrates event-driven programming. The code below 9 | will display the version of ScriptCraft every time an operator joins 10 | the game. This module is notable from previous modules for the 11 | following reasons... 12 | 13 | 1. It does not export any functions or variables. That's fine. Not 14 | all modules need export stuff. Code in this module will be 15 | executed when the module is first loaded. Because it is in the 16 | `/scriptcraft/plugins` directory, it will be loaded automatically 17 | when the server starts up. 18 | 19 | 2. It uses ScriptCraft's `events` module to add a new *Event 20 | Handler*. An *Event Handler* is a function that gets 21 | called whenever a particular *event* happens in the game. The 22 | function defined below will only be executed whenever a player 23 | joins the game. This style of program is sometimes refered to as 24 | *Event-Driven Programming*. 25 | 26 | Adding new *Event Handlers* in ScriptCraft is relatively easy. Use one 27 | of the `events` module's functions to add a new event handler. The 28 | events module has many functions - one for each type of event. Each 29 | function takes a single parameter: 30 | 31 | * The event handling function (also sometimes refered to as a 32 | 'callback'). In ScriptCraft, this function takes a single 33 | parameter, an event object. All of the information about the event 34 | is in the event object. 35 | 36 | In the example below, if a player joins the server and is an operator, 37 | then the ScriptCraft plugin information will be displayed to that 38 | player. 39 | 40 | ```javascript 41 | function onJoin( event ){ 42 | if ( isOp(event.player) ) { 43 | echo( event.player, 'Welcome to ' + __plugin ); 44 | } 45 | } 46 | events.connection( onJoin ); 47 | ``` 48 | First the onJoin() function is defined, this is our event handler - 49 | the function we wish to be called every time some new player joins the 50 | game. Then we hook up - or register - that function using the 51 | events.connection() function. The events.connection function is the 52 | function responsible for adding new *connection* event handlers - that 53 | is - functions which should be invoked when there's a new *connection* 54 | event in the game. A new *connection* event is fired whenever a player 55 | joins the game. There are many other types of events you can handle in 56 | Minecraft. You can see [a full list of events here][cmEvtList]. 57 | 58 | [cmEvtList]: #events-helper-module-canary-version 59 | ***/ 60 | 61 | // wph 20140927 - event handler registration differs depending on framework. 62 | function onJoin(event) { 63 | if (isOp(event.player)) { 64 | echo(event.player, 'Welcome to ' + __plugin); 65 | } 66 | } 67 | if (__plugin.canary) { 68 | // canarymod 69 | events.connection(onJoin); 70 | } else { 71 | // bukkit 72 | events.playerJoin(onJoin); 73 | } 74 | -------------------------------------------------------------------------------- /src/main/js/plugins/minigames/NumberGuess.js: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | ## NumberGuess mini-game: 3 | 4 | ### Description 5 | This is a very simple number guessing game. Minecraft will ask you to 6 | guess a number between 1 and 10 and you will tell you if you're too 7 | hight or too low when you guess wrong. The purpose of this mini-game 8 | code is to demonstrate use of Bukkit's Conversation API. 9 | 10 | ### Example 11 | 12 | /js Game_NumberGuess.start(self) 13 | 14 | Once the game begins, guess a number by typing the `/` character 15 | followed by a number between 1 and 10. 16 | 17 | ***/ 18 | var bkPrompt = org.bukkit.conversations.Prompt, 19 | bkConversationFactory = org.bukkit.conversations.ConversationFactory, 20 | bkConversationPrefix = org.bukkit.conversations.ConversationPrefix, 21 | bkBukkit = org.bukkit.Bukkit; 22 | 23 | var sb = function(cmd) { 24 | bkBukkit.dispatchCommand(server.consoleSender, 'scoreboard ' + cmd); 25 | }; 26 | 27 | exports.Game_NumberGuess = { 28 | start: function(sender) { 29 | var guesses = 0; 30 | 31 | sb('objectives add NumberGuess dummy Guesses'); 32 | sb('players set ' + sender.name + ' NumberGuess ' + guesses); 33 | sb('objectives setdisplay sidebar NumberGuess'); 34 | 35 | var number = Math.ceil(Math.random() * 10); 36 | 37 | var prompt = new bkPrompt({ 38 | getPromptText: function(ctx) { 39 | var hint = ''; 40 | var h = ctx.getSessionData('hint'); 41 | if (h) { 42 | hint = h; 43 | } 44 | return hint + 'Think of a number between 1 and 10'; 45 | }, 46 | 47 | acceptInput: function(ctx, s) { 48 | s = s.replace(/^[^0-9]+/, ''); // strip leading non-numeric characters (e.g. '/' ) 49 | s = parseInt(s); 50 | if (s == number) { 51 | setTimeout(function() { 52 | ctx.forWhom.sendRawMessage('You guessed Correct!'); 53 | sb('objectives remove NumberGuess'); 54 | }, 100); 55 | return null; 56 | } else { 57 | if (s < number) { 58 | ctx.setSessionData('hint', 'too low\n'); 59 | } 60 | if (s > number) { 61 | ctx.setSessionData('hint', 'too high\n'); 62 | } 63 | guesses++; 64 | sb('players set ' + sender.name + ' NumberGuess ' + guesses); 65 | 66 | return prompt; 67 | } 68 | }, 69 | 70 | blocksForInput: function(/*ctx*/) { 71 | return true; 72 | } 73 | }); 74 | var convPrefix = new bkConversationPrefix({ 75 | getPrefix: function(/*ctx*/) { 76 | return '[1-10] '; 77 | } 78 | }); 79 | new bkConversationFactory(__plugin) 80 | .withModality(true) 81 | .withFirstPrompt(prompt) 82 | .withPrefix(convPrefix) 83 | .buildConversation(sender) 84 | .begin(); 85 | } 86 | }; 87 | -------------------------------------------------------------------------------- /src/main/js/plugins/signs/examples.js: -------------------------------------------------------------------------------- 1 | var signs = require('signs'); 2 | // 3 | // Usage: 4 | // 5 | // In game, create a sign , target it and type ... 6 | // 7 | // /js signs.menu_food(); 8 | // 9 | // ... or ... 10 | // 11 | // /js signs.menu_time() 12 | // 13 | 14 | var onDinnerChoice = function(event) { 15 | echo(event.player, 'You chose ' + event.text); 16 | }; 17 | var convertToDinnerMenu = signs.menu( 18 | 'Dinner', 19 | ['Lamb', 'Pork', 'Chicken', 'Duck', 'Beef'], 20 | onDinnerChoice 21 | ); 22 | 23 | var onTimeChoice = function(event) { 24 | event.player.location.world.setTime(event.number * 6000); 25 | }; 26 | var convertToTimeMenu = signs.menu( 27 | 'Time', 28 | ['Dawn', 'Midday', 'Dusk', 'Midnight'], 29 | onTimeChoice 30 | ); 31 | 32 | exports.signs = { 33 | menu_food: function(cmdSender) { 34 | var sign = signs.getTargetedBy(cmdSender); 35 | if (!sign) { 36 | throw new Error('You must look at an existing sign'); 37 | } 38 | convertToDinnerMenu(sign); 39 | }, 40 | // 41 | // This is an example sign that displays a menu of times of day 42 | // interacting with the sign will change the time of day accordingly. 43 | // 44 | // In game, create a sign , target it and type ... 45 | // 46 | // /js var signExamples = require('./signs/examples'); 47 | // /js signExamples.timeOfDay() 48 | // 49 | menu_time: function(cmdSender) { 50 | var sign = signs.getTargetedBy(cmdSender); 51 | if (!sign) { 52 | throw new Error('You must look at an existing sign'); 53 | } 54 | convertToTimeMenu(sign); 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /src/main/js/plugins/spawn.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*global Packages, __plugin, command, echo, isOp, org */ 3 | /*jslint nomen: true, indent: 2 */ 4 | /************************************************************************* 5 | ## Spawn Plugin 6 | 7 | Allows in-game operators to easily spawn creatures at current location. 8 | 9 | ### Usage 10 | 11 | /jsp spawn cow 12 | /jsp spawn sheep 13 | /jsp spawn wolf 14 | 15 | This command supports TAB completion so to see a list of possible 16 | entitities, type `/jsp spawn ' at the in-game command prompt, then 17 | press TAB. Visit 18 | (Bukkit/SpigotMC) 19 | or (CanaryMod) 20 | 21 | for a list of possible entities (creatures) which can be spawned. 22 | 23 | ***/ 24 | var entities = require('entities'), 25 | spawn = require('spawn'); 26 | var entityNames = []; 27 | for (var name in entities) { 28 | entityNames.push(name); 29 | } 30 | command( 31 | 'spawn', 32 | function(parameters, sender) { 33 | if (!isOp(sender)) { 34 | echo(sender, 'Only operators can perform this command'); 35 | return; 36 | } 37 | var location = sender.location; 38 | if (!location) { 39 | echo(sender, 'You have no location. This command only works in-game.'); 40 | return; 41 | } 42 | var name = ('' + parameters[0]).toUpperCase(); 43 | spawn(name, sender.location); 44 | }, 45 | entityNames 46 | ); 47 | -------------------------------------------------------------------------------- /src/main/js/readme.md: -------------------------------------------------------------------------------- 1 | # scriptcraft root directory 2 | 3 | This directory contains the following subdirectories... 4 | 5 | * lib - contains core scriptcraft modules and code. 6 | * modules - contains modules for use by others 7 | * plugins - contains plugins (modules which are automatically loaded and globally-namespaced at startup) 8 | 9 | If you are a minecraft modder who wants to develop simple mods then the `plugins` location is where you should probably place your .js files. 10 | 11 | If you are a minecraft modder who wants to develop more complex mods or provide an API for other modders, then modules intended for use by plugins (your own or others) should probably be placed in the `modules` directory. 12 | 13 | The `lib` directory is reserved for use by ScriptCraft. If a module is considered essential for all, or adds significantly useful new functionality to ScriptCraft then it should be placed in the `lib` directory. 14 | -------------------------------------------------------------------------------- /src/main/resources/Canary.inf: -------------------------------------------------------------------------------- 1 | main-class = org.scriptcraftjs.canarymod.ScriptCraftPlugin 2 | isLibrary = false 3 | name = ScriptCraft 4 | author = Walter Higgins 5 | version = [[version]] -------------------------------------------------------------------------------- /src/main/resources/boot.js: -------------------------------------------------------------------------------- 1 | /* 2 | This file is the first and only file executed directly from the Java Plugin. 3 | */ 4 | var __scboot = null; 5 | (function() { 6 | var File = java.io.File, 7 | FileReader = java.io.FileReader, 8 | FileOutputStream = java.io.FileOutputStream, 9 | ZipInputStream = java.util.zip.ZipInputStream, 10 | //jsPlugins = new File('plugins/scriptcraft'), 11 | jsPlugins = new File('scriptcraft'), 12 | initScript = 'lib/scriptcraft.js'; 13 | 14 | var unzip = function(zis, logger) { 15 | var entry, 16 | reason = null, 17 | unzipFile = false, 18 | zTime = 0, 19 | fTime = 0, 20 | fout = null, 21 | c, 22 | newFile; 23 | 24 | while ((entry = zis.nextEntry) != null) { 25 | newFile = new File(jsPlugins, entry.name); 26 | if (entry.isDirectory()) { 27 | newFile.mkdirs(); 28 | zis.closeEntry(); 29 | continue; 30 | } 31 | reason = null; 32 | zTime = entry.time; 33 | unzipFile = false; 34 | if (!newFile.exists()) { 35 | reason = 'NE'; 36 | unzipFile = true; 37 | } else { 38 | fTime = newFile.lastModified(); 39 | if (zTime > fTime) { 40 | reason = (zTime - fTime) / 3600000 + 'h'; 41 | unzipFile = true; 42 | } 43 | } 44 | if (unzipFile) { 45 | logger.info('Unzipping ' + newFile.canonicalPath + ' (' + reason + ')'); 46 | fout = new FileOutputStream(newFile); 47 | for (c = zis.read(); c != -1; c = zis.read()) { 48 | fout.write(c); 49 | } 50 | fout.close(); 51 | } 52 | zis.closeEntry(); 53 | } 54 | zis.close(); 55 | }; 56 | /* 57 | Called from Java plugin 58 | */ 59 | __scboot = function(plugin, engine, classLoader) { 60 | var logger = plugin.canary ? plugin.logman : plugin.logger, 61 | initScriptFile = new File(jsPlugins, initScript), 62 | zips = ['lib', 'plugins', 'modules'], 63 | i = 0, 64 | zis, 65 | len = zips.length; 66 | 67 | if (!jsPlugins.exists()) { 68 | logger.info('Directory ' + jsPlugins.canonicalPath + ' does not exist.'); 69 | logger.info( 70 | 'Initializing ' + 71 | jsPlugins.canonicalPath + 72 | ' directory with contents from plugin archive.' 73 | ); 74 | jsPlugins.mkdirs(); 75 | } 76 | 77 | for (i = 0; i < len; i++) { 78 | if (plugin.canary) { 79 | zis = new ZipInputStream( 80 | classLoader.getResourceAsStream(zips[i] + '.zip') 81 | ); 82 | unzip(zis, logger); 83 | } else { 84 | if (plugin.config.getBoolean('extract-js.' + zips[i])) { 85 | zis = new ZipInputStream(plugin.getResource(zips[i] + '.zip')); 86 | unzip(zis, logger); 87 | } 88 | } 89 | } 90 | if (plugin.bukkit) { 91 | plugin.saveDefaultConfig(); 92 | } 93 | try { 94 | engine.eval(new FileReader(initScriptFile)); 95 | __onEnable(engine, plugin, initScriptFile); 96 | } catch (e) { 97 | var msg = 'Error evaluating ' + initScriptFile + ': ' + e; 98 | plugin.canary ? logger.error(msg) : logger.severe(msg); 99 | throw e; 100 | } 101 | }; 102 | })(); 103 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | extract-js: 2 | plugins: true 3 | modules: true 4 | lib: true 5 | -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: scriptcraft 2 | main: org.scriptcraftjs.bukkit.ScriptCraftPlugin 3 | version: [[version]] 4 | commands: 5 | js: 6 | description: Evaluate javascript. 7 | usage: / Javascript code 8 | permission: scriptcraft.evaluate 9 | permission-message: You don't have permission. 10 | jsp: 11 | description: run a javascript plugin command. 12 | usage: / command-name command-parameters 13 | permission: scriptcraft.proxy 14 | permission-message: You don't have permission. 15 | 16 | permissions: 17 | scriptcraft.*: 18 | description: Gives access to all scriptcraft comands 19 | children: 20 | scriptcraft.evaluate: true 21 | scriptcraft.proxy: true 22 | scriptcraft.evaluate: 23 | description: Allows you to evaluate javascript code 24 | default: op 25 | scriptcraft.proxy: 26 | description: Allows you to run a javascript command blessed by the operator 27 | default: true 28 | -------------------------------------------------------------------------------- /target/scriptcraft.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ediloren/ScriptCraft/4731aea30fae7a5e48cdf4fbc98f590a473a7bb6/target/scriptcraft.jar --------------------------------------------------------------------------------