├── .github └── workflows │ ├── build-dev.yml │ └── release.yml ├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── dataSources.local.xml ├── dictionaries │ └── Ashton.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jarRepositories.xml ├── kotlinc.xml ├── libraries-with-intellij-classes.xml ├── misc.xml ├── uiDesigner.xml └── vcs.xml ├── LICENSE ├── README.md ├── ScriptableMC-Engine-Core ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── com │ ├── pixlfox │ └── scriptablemc │ │ ├── ScriptablePluginEngineBootstrapper.kt │ │ ├── ScriptablePluginEngineCommands.kt │ │ ├── ScriptablePluginEngineConfig.kt │ │ ├── core │ │ ├── ScriptablePluginCommandManager.kt │ │ ├── ScriptablePluginContext.kt │ │ ├── ScriptablePluginEngine.kt │ │ ├── ScriptablePluginEventManager.kt │ │ ├── ScriptablePluginLogger.kt │ │ ├── ScriptablePluginMessenger.kt │ │ └── ScriptablePluginScheduler.kt │ │ └── utils │ │ └── UnzipUtil.kt │ └── smc │ ├── exceptions │ └── ScriptNotFoundException.kt │ ├── utils │ ├── ItemBuilder.kt │ └── MysqlWrapper.kt │ └── version │ ├── MinecraftVersions.kt │ └── Version.kt ├── ScriptableMC-Engine-JS ├── build.gradle.kts └── src │ └── main │ ├── kotlin │ └── com │ │ └── pixlfox │ │ └── scriptablemc │ │ └── js │ │ ├── JavaScriptPluginEngineBootstrapper.kt │ │ ├── JavaScriptPluginEngineCommands.kt │ │ ├── JavaScriptPluginEngineConfig.kt │ │ └── core │ │ ├── JavaScriptPluginContext.kt │ │ └── JavaScriptPluginEngine.kt │ └── resources │ ├── config_js.yml │ └── plugin.yml ├── ScriptableMC-Engine.ipr ├── ScriptableMC-Engine.iws ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.github/workflows/build-dev.yml: -------------------------------------------------------------------------------- 1 | name: Build Dev 2 | on: 3 | push: 4 | branches: 5 | - dev 6 | pull_request: 7 | branches: 8 | - dev 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-java@v2 15 | with: 16 | distribution: 'adopt' 17 | java-version: '11' 18 | - uses: actions/setup-node@v2 19 | with: 20 | node-version: '14' 21 | - name: Fix gradlew permissions 22 | run: chmod +x ./gradlew 23 | - name: Build plugin jar files with Gradle 24 | run: ./gradlew :shadowJarAll 25 | - name: Copy artifacts 26 | run: | 27 | mkdir artifacts 28 | cp ./build/ScriptableMC-Engine-JS.jar ./artifacts/ 29 | cp ./build/ScriptableMC-Engine-JS-Bundled.jar ./artifacts/ 30 | - uses: actions/upload-artifact@v2 31 | with: 32 | name: ScriptableMC-Engine-DEV 33 | path: artifacts/ 34 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Build and Upload Release Artifacts 2 | on: 3 | release: 4 | types: [created] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Set up JDK 11 11 | uses: actions/setup-java@v2 12 | with: 13 | distribution: 'adopt' 14 | java-version: '11' 15 | - name: Set up Node.js 14 16 | uses: actions/setup-node@v2 17 | with: 18 | node-version: '14' 19 | - name: Fix gradlew permissions 20 | run: chmod +x ./gradlew 21 | - name: Export TypeScript Libraries with Gradle 22 | run: ./gradlew :ScriptableMC-Tools-TS:Standalone:exportTypeScriptLibraries 23 | - name: Compile TypeScript libraries and create archives 24 | run: | 25 | cd ./ScriptableMC-Tools-TS/Standalone/lib/ 26 | npm install 27 | npm run compile 28 | cd ./ts/ 29 | zip -r ../ScriptableMC-TypeScript-Lib.zip ./* 30 | cd ../js/ 31 | zip -r ../ScriptableMC-JavaScript-Lib.zip ./* 32 | cd ../ 33 | cp ./ScriptableMC-JavaScript-Lib.zip ../../../ScriptableMC-Engine-JS/src/main/resources/libraries.zip 34 | - name: Export lib-smc with gradle 35 | run: ./gradlew :ScriptableMC-Tools-TS:Standalone:generateLibSMCRelease 36 | - name: Compile lib-smc, create archive, and publish 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 40 | run: | 41 | cd ./ScriptableMC-Tools-TS/Standalone/lib-smc/ 42 | npm install 43 | npm run compile 44 | npm publish ./js --access public 45 | zip -r ./Lib-SMC.zip ./* 46 | - name: Build JS Engine with Gradle 47 | run: ./gradlew :shadowJarAll 48 | - name: Upload JavaScript Engine Plugin Jar 49 | uses: skx/github-action-publish-binaries@master 50 | env: 51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 52 | with: 53 | args: 'build/ScriptableMC-Engine-JS.jar' 54 | - name: Upload Bundled JavaScript Engine Plugin Jar 55 | uses: skx/github-action-publish-binaries@master 56 | env: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | with: 59 | args: 'build/ScriptableMC-Engine-JS-Bundled.jar' 60 | - name: Upload TypeScript Tools Plugin Jar 61 | uses: skx/github-action-publish-binaries@master 62 | env: 63 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | with: 65 | args: 'build/ScriptableMC-Tools-TS.jar' 66 | - name: Upload Standalone TypeScript Tools 67 | uses: skx/github-action-publish-binaries@master 68 | env: 69 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 70 | with: 71 | args: 'build/ScriptableMC-Tools-TS-Standalone.jar' 72 | - name: Upload TypeScript Libraries 73 | uses: skx/github-action-publish-binaries@master 74 | env: 75 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 76 | with: 77 | args: 'ScriptableMC-Tools-TS/Standalone/lib/ScriptableMC-TypeScript-Lib.zip' 78 | - name: Upload JavaScript Libraries 79 | uses: skx/github-action-publish-binaries@master 80 | env: 81 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 82 | with: 83 | args: 'ScriptableMC-Tools-TS/Standalone/lib/ScriptableMC-JavaScript-Lib.zip' 84 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/shelf 3 | /android.tests.dependencies 4 | /confluence/target 5 | /dependencies/repo 6 | /dist 7 | /local 8 | /gh-pages 9 | /ideaSDK 10 | /clionSDK 11 | /android-studio/sdk 12 | out/ 13 | /tmp 14 | workspace.xml 15 | *.versionsBackup 16 | /idea/testData/debugger/tinyApp/classes* 17 | /jps-plugin/testData/kannotator 18 | /js/js.translator/testData/out/ 19 | /js/js.translator/testData/out-min/ 20 | .gradle/ 21 | build/ 22 | !**/src/**/build 23 | !**/test/**/build 24 | *.iml 25 | !**/testData/**/*.iml 26 | .idea/libraries/Gradle*.xml 27 | .idea/libraries/Maven*.xml 28 | .idea/artifacts/PILL_*.xml 29 | .idea/modules 30 | .idea/runConfigurations/JPS_*.xml 31 | .idea/runConfigurations/PILL_*.xml 32 | .idea/libraries 33 | .idea/modules.xml 34 | .idea/gradle.xml 35 | .idea/compiler.xml 36 | .idea/inspectionProfiles/profiles_settings.xml 37 | .idea/.name 38 | .idea/artifacts/dist_auto_* 39 | .idea/artifacts/ideaPlugin.xml 40 | kotlin-ultimate/ 41 | node_modules/ 42 | .rpt2_cache/ 43 | libraries/tools/kotlin-test-nodejs-runner/lib/ 44 | local.properties 45 | lib 46 | lib-smc -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/dataSources.local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/dictionaries/Ashton.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bukkit 5 | commandapi 6 | ecmascript 7 | graal 8 | jorelali 9 | jsex 10 | jsexec 11 | jsreload 12 | jsrl 13 | minuskube 14 | nashorn 15 | papermc 16 | pixlfox 17 | scriptable 18 | scriptableplugin 19 | scriptablepluginmenu 20 | tsdef 21 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | 49 | 50 | 54 | 55 | 59 | 60 | 64 | 65 | 69 | 70 | 74 | 75 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/libraries-with-intellij-classes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 64 | 65 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScriptableMC-Engine 2 | 3 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/astorks/ScriptableMC-Engine?label=ScriptableMC&style=for-the-badge)](https://github.com/astorks/ScriptableMC-Engine/releases/latest) 4 | [![SpigotMC Resource](https://img.shields.io/badge/SpigotMC-Resource-yellow?style=for-the-badge)](https://www.spigotmc.org/resources/scriptablemc-engine.74690/) 5 | ![License](https://img.shields.io/github/license/astorks/ScriptableMC-Engine?style=for-the-badge) 6 | 7 | Run JavaScript/TypeScript plugins for Minecraft 1.17 using the GraalJS script engine.
8 | Supported Minecraft Versions: Bukkit/Spigot/Paper **1.17**
9 | Previous Minecraft Versions: [Use v1.3.X version of the plugin](https://github.com/astorks/ScriptableMC-Engine/tree/1.3.x)
10 | 11 | #### New v1.17.X 12 | **We are switching to a new version numbering to match the supporting minecraft version.**
13 | **New v1.17.X builds of this plugin will only work with Minecraft 1.17+**
14 | **For Minecraft v1.12-1.16 you should use v1.3.X of this plugin.**
15 | 16 | **This plugin is in a preview state, there may be breaking changes, missing features, and possibly a few bugs.**
17 | Feel free to create an issue if you find any missing features, bugs, or just have an idea for a great feature to add. 18 | 19 | **This plugin requires running your minecraft server with OpenJDK, Standard JDK, or the GraalVM java runtime.**
20 | Most linux servers already use OpenJDK, however if you're running windows or want a fully supported java runtime that supports AOT javascript compilation you can install [GraalVM-CE](https://github.com/graalvm/graalvm-ce-builds/releases/latest). 21 | 22 | GraalVM-CE is a free open source java runtime created by Oracle that is pre-packaged with the GraalJS Engine allowing all javascript engine features including AOT compilation of javascript. 23 | 24 | ## Installing The JavaScript Engine Plugin 25 | ##### If your server is running on a Standard JDK 26 | - Download the latest [`ScriptableMC-Engine-JS-Bundled.jar`](https://github.com/astorks/ScriptableMC-Engine/releases/latest/download/ScriptableMC-Engine-JS-Bundled.jar) and place it in your plugins folder. 27 | ##### If your server is running on a GraalVM JDK 28 | - Download the latest [`ScriptableMC-Engine-JS.jar`](https://github.com/astorks/ScriptableMC-Engine/releases/latest/download/ScriptableMC-Engine-JS.jar) and place it in your plugins folder. 29 | 30 | Take a look at [ScriptableMC-TypeScript](https://github.com/astorks/ScriptableMC-TypeScript) for a full typescript plugin example. 31 | You can take the typescript example and compile it, then directly modify the javascript if you don't want to use typescript. 32 | 33 | ## Commands and Permissions 34 | ##### ScritableMC Base Command 35 | | Command | Alias | Description | Permission | 36 | | ------------- | ------------- |-----------------------------------------------------| ------------------------ | 37 | | `/scriptablemc menu` | `/smc m` | Opens an inventory menu that allows you to control the script engines. | `scriptablemc.menu` | 38 | | `/scriptablemc info` | `/smc i` | Prints plugin version and all loaded script engine versions if available. | `scriptablemc.info` | 39 | | `/scriptablemc reload` | `/smc rl` | Fully reloads all script engines and all script files. | `scriptablemc.reload` | 40 | | `/scriptablemc version` | `/smc v` | Check the github releases for any updates. | `scriptablemc.version` | 41 | 42 | ##### ScritableMC JavaScript Engine Commands 43 | | Command | Alias | Description | Permission | 44 | | ------------- | ------------- |-----------------------------------------------------| ------------------------ | 45 | | `/scriptablemc javascript reload` | `/smc js rl` `/jsrl` | Fully reloads the javascript engine and all script files. | `scriptablemc.js.reload` | 46 | | `/scriptablemc javascript execute ` | `/smc js ex ` `/jsex ` | Executes javascript source and prints the return value. | `scriptablemc.js.execute` | 47 | | `/scriptablemc javascript file ` | `/smc js f ` `/jsexf` | Executes javascript file from the scripts folder. | `scriptablemc.js.execute.file` | 48 | | `/scriptablemc javascript pastebin ` | `/smc js pb ` `/jsexpb` | Executes javascript source from a pastebin. | `scriptablemc.js.execute.pastebin` | 49 | 50 | ### `/smc javascript execute` Command Example 51 | > `/jsex return 1 + 1`
52 | > ![2](https://i.imgur.com/1MkiDxW.png) 53 | 54 | > `/jsex sender.sendMessage(lib.org.bukkit.ChatColor.GREEN + "Hello World!")`
55 | > ![Hello World!](https://i.imgur.com/1dzwpqy.png) 56 | 57 | 58 | ### Third Party Libraries 59 | https://github.com/MinusKube/SmartInvs - Inventory helper library
60 | https://github.com/lucko/helper - MinecraftVersions helper library
61 | https://github.com/jkcclemens/khttp - HTTP helper library
62 | https://github.com/aikar/commands - Built-in commands and auto-completion
63 | https://github.com/tr7zw/Item-NBT-API - NBT helper library
64 | https://github.com/apache/commons-io - FileUtils helper library
65 | https://github.com/graalvm/graaljs - JavaScript engine 66 | -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar 2 | 3 | plugins { 4 | java 5 | id("org.jetbrains.kotlin.jvm") 6 | // id("com.github.johnrengelman.shadow") 7 | id("io.github.goooler.shadow") 8 | id("org.jetbrains.gradle.plugin.idea-ext") 9 | } 10 | 11 | var graalvmVersion = findProperty("dependencies.graalvm.version") ?: "23.0.2" 12 | var spigotmcVersion = findProperty("dependencies.spigotmc.version") ?: "1.20.4-R0.1-SNAPSHOT" 13 | 14 | java { 15 | sourceCompatibility = JavaVersion.VERSION_17 16 | targetCompatibility = JavaVersion.VERSION_17 17 | } 18 | 19 | idea { 20 | module { 21 | isDownloadJavadoc = true 22 | isDownloadSources = true 23 | } 24 | } 25 | 26 | val coreShadow by configurations.creating 27 | 28 | dependencies { 29 | // Kotlin Standard Library & Reflection 30 | implementation("org.jetbrains.kotlin:kotlin-stdlib") 31 | implementation("org.jetbrains.kotlin:kotlin-reflect") 32 | 33 | // SpigotMC API 34 | compileOnly("org.spigotmc:spigot-api:$spigotmcVersion") { 35 | isChanging = true 36 | } 37 | 38 | // GraalVM SDK & GraalJS Engine 39 | compileOnly("org.graalvm.sdk:graal-sdk:$graalvmVersion") 40 | compileOnly("org.graalvm.truffle:truffle-api:$graalvmVersion") 41 | 42 | // 3rd-Party Libraries 43 | implementation("com.github.kittinunf.fuel:fuel:2.3.1") 44 | implementation("com.github.kittinunf.fuel:fuel-json:2.3.1") 45 | implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT") 46 | compileOnly("me.clip:placeholderapi:2.11.5") 47 | 48 | 49 | coreShadow(project) 50 | coreShadow("org.spigotmc:spigot-api:$spigotmcVersion:shaded") 51 | coreShadow("org.graalvm.sdk:graal-sdk:$graalvmVersion") 52 | coreShadow("org.graalvm.truffle:truffle-api:$graalvmVersion") 53 | coreShadow("com.github.kittinunf.fuel:fuel:2.3.1") 54 | coreShadow("com.github.kittinunf.fuel:fuel-json:2.3.1") 55 | coreShadow("co.aikar:acf-paper:0.5.1-SNAPSHOT") 56 | coreShadow("me.clip:placeholderapi:2.11.5") 57 | 58 | testImplementation("junit", "junit", "4.12") 59 | } 60 | 61 | tasks.shadowJar { 62 | configurations = listOf(coreShadow) 63 | archiveFileName.set("ScriptableMC-Engine-Core.jar") 64 | } 65 | 66 | tasks.compileKotlin { 67 | kotlinOptions.jvmTarget = "17" 68 | kotlinOptions.javaParameters = true 69 | } 70 | tasks.compileTestKotlin { 71 | kotlinOptions.jvmTarget = "17" 72 | kotlinOptions.javaParameters = true 73 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/ScriptablePluginEngineBootstrapper.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc 2 | 3 | import co.aikar.commands.PaperCommandManager 4 | import com.pixlfox.scriptablemc.core.ScriptablePluginEngine 5 | import com.smc.version.Version 6 | import org.bukkit.command.CommandSender 7 | import org.bukkit.plugin.java.JavaPlugin 8 | import java.io.File 9 | import java.io.FileOutputStream 10 | import java.io.IOException 11 | import java.io.OutputStream 12 | import java.util.logging.Level 13 | 14 | @Suppress("unused", "MemberVisibilityCanBePrivate") 15 | abstract class ScriptablePluginEngineBootstrapper : JavaPlugin() { 16 | lateinit var scriptEngine: ScriptablePluginEngine 17 | lateinit var commandManager: PaperCommandManager 18 | abstract val chatMessagePrefix: String 19 | abstract val scriptLanguage: String 20 | 21 | lateinit var sharedDataFolder: File 22 | 23 | val pluginVersion: Version 24 | get() = Version.parse("v${description.version}") 25 | 26 | abstract fun reloadScriptEngine(sender: CommandSender? = null) 27 | 28 | override fun onLoad() { 29 | sharedDataFolder = File(file.parent, "ScriptableMC") 30 | registerScriptEngine(scriptLanguage, this) 31 | } 32 | 33 | override fun saveResource(resourcePath: String, replace: Boolean) { 34 | val resourceStream = getResource(resourcePath.replace('\\', '/')) 35 | ?: throw IllegalArgumentException("The embedded resource '$resourcePath' cannot be found in $file") 36 | val outFile = File(sharedDataFolder, resourcePath) 37 | val lastIndex = resourcePath.lastIndexOf('/') 38 | val outDir = File(sharedDataFolder, resourcePath.substring(0, if (lastIndex >= 0) lastIndex else 0)) 39 | if (!outDir.exists()) { 40 | outDir.mkdirs() 41 | } 42 | try { 43 | if (!outFile.exists() || replace) { 44 | val out: OutputStream = FileOutputStream(outFile) 45 | val buf = ByteArray(1024) 46 | var len: Int 47 | while (resourceStream.read(buf).also { len = it } > 0) { 48 | out.write(buf, 0, len) 49 | } 50 | out.close() 51 | resourceStream.close() 52 | } else { 53 | logger.log( 54 | Level.WARNING, 55 | "Could not save " + outFile.name + " to " + outFile + " because " + outFile.name + " already exists." 56 | ) 57 | } 58 | } catch (ex: IOException) { 59 | logger.log(Level.SEVERE, "Could not save " + outFile.name + " to " + outFile, ex) 60 | } 61 | } 62 | 63 | override fun saveDefaultConfig() { 64 | 65 | } 66 | 67 | override fun saveConfig() { 68 | super.saveConfig() 69 | } 70 | 71 | fun versionCheck(sender: CommandSender? = null) { 72 | // if(config.getBoolean("version_check", true)) { 73 | // khttp.async.get("https://api.github.com/repos/astorks/ScriptableMC-Engine/releases/latest") { 74 | // val githubReleaseInfo = this.jsonObject 75 | // val latestReleaseVersion = Version.parse(githubReleaseInfo.getString("tag_name")) 76 | // val currentVersion = Version.parse("v${description.version}") 77 | // val releaseLink = githubReleaseInfo.getString("html_url") 78 | // 79 | // if (currentVersion.isBefore(latestReleaseVersion)) { 80 | // sender?.sendMessage("$chatMessagePrefix ${ChatColor.YELLOW}An update was found.") 81 | // sender?.sendMessage("$chatMessagePrefix CurrentVersion: $currentVersion, LatestRelease: $latestReleaseVersion.") 82 | // sender?.sendMessage("$chatMessagePrefix Download Page: $releaseLink") 83 | // logger.warning("An update was found. CurrentVersion: $currentVersion, LatestRelease: $latestReleaseVersion") 84 | // logger.fine("Download Page: $releaseLink") 85 | // } 86 | // else { 87 | // sender?.sendMessage("$chatMessagePrefix No updates found.") 88 | // sender?.sendMessage("$chatMessagePrefix CurrentVersion: $currentVersion, LatestRelease: $latestReleaseVersion") 89 | // if (config.getBoolean("debug", false)) { 90 | // logger.info("No updates found. CurrentVersion: $currentVersion, LatestRelease: $latestReleaseVersion") 91 | // } 92 | // } 93 | // } 94 | // } 95 | } 96 | 97 | companion object { 98 | private val scriptEngines: MutableMap = mutableMapOf() 99 | /** 100 | * Patches the bukkit class loader to allow for GraalVM class loading from inside plugin jar. 101 | * A bit hackish but it works. 102 | * https://stackoverflow.com/questions/56712178/graalvm-no-language-and-polyglot-implementation-was-found-on-the-classpath 103 | */ 104 | fun patchClassLoader(_class: Class<*>, callback: () -> Unit) { 105 | val oldCl = Thread.currentThread().contextClassLoader 106 | Thread.currentThread().contextClassLoader = _class.classLoader 107 | callback() 108 | Thread.currentThread().contextClassLoader = oldCl 109 | } 110 | 111 | @JvmStatic 112 | fun registerScriptEngine(language: String, scriptEngineMain: ScriptablePluginEngineBootstrapper) { 113 | scriptEngines[language] = scriptEngineMain 114 | } 115 | 116 | @JvmStatic 117 | fun releaseScriptEngine(language: String) { 118 | scriptEngines[language] = null 119 | } 120 | 121 | @JvmStatic 122 | fun resolveScriptEngine(language: String): ScriptablePluginEngineBootstrapper? { 123 | return scriptEngines.getOrDefault(language, null) 124 | } 125 | 126 | @JvmStatic 127 | fun getAllScriptEngines(): Array { 128 | return scriptEngines.values.filterNotNull().toTypedArray() 129 | } 130 | 131 | @JvmStatic @JvmOverloads 132 | fun reloadAllScriptEngines(sender: CommandSender? = null) { 133 | for(scriptEngine in getAllScriptEngines()) { 134 | scriptEngine.reloadScriptEngine(sender) 135 | } 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/ScriptablePluginEngineCommands.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc 2 | 3 | import co.aikar.commands.BaseCommand 4 | import co.aikar.commands.annotation.CommandAlias 5 | import co.aikar.commands.annotation.CommandPermission 6 | import co.aikar.commands.annotation.Subcommand 7 | import org.bukkit.ChatColor 8 | import org.bukkit.command.CommandSender 9 | 10 | @Suppress("unused") 11 | @CommandAlias("scriptablemc|smc") 12 | class ScriptablePluginEngineCommands(private val bootstrapper: ScriptablePluginEngineBootstrapper) : BaseCommand() { 13 | 14 | @Subcommand("info|i") 15 | @CommandAlias("smci") 16 | @CommandPermission("scriptablemc.info") 17 | fun info(sender: CommandSender) { 18 | sender.sendMessage("-----------------------------------------------------") 19 | sender.sendMessage("- ${ChatColor.DARK_PURPLE}ScriptableMC Version: ${bootstrapper.description.version}") 20 | sender.sendMessage("-----------------------------------------------------") 21 | for (scriptEngineMain in ScriptablePluginEngineBootstrapper.getAllScriptEngines()) { 22 | if (scriptEngineMain.scriptLanguage == "js") { 23 | val scriptEngine = scriptEngineMain.scriptEngine 24 | val isGraalRuntime = scriptEngine?.eval("if (typeof Graal != 'undefined') { Graal.isGraalRuntime() } else { false }")?.asBoolean() == true 25 | 26 | sender.sendMessage("- ${ChatColor.DARK_GREEN}ScriptableMC JavaScript Engine: ${scriptEngineMain.pluginVersion}") 27 | sender.sendMessage("- ${ if(isGraalRuntime) ChatColor.GREEN else ChatColor.YELLOW }GraalVM Java Runtime: $isGraalRuntime") 28 | if(isGraalRuntime) { 29 | sender.sendMessage("${ChatColor.GREEN}GraalVM Runtime Version: ${scriptEngine?.eval("Graal.versionGraalVM")}") 30 | sender.sendMessage("${ChatColor.GREEN}GraalJS Version: ${scriptEngine?.eval("Graal.versionJS")}") 31 | } 32 | else { 33 | sender.sendMessage("- ${ChatColor.GREEN}GraalJS Engine Version: v21.1.0") 34 | } 35 | sender.sendMessage("-----------------------------------------------------") 36 | } 37 | else if(scriptEngineMain.scriptLanguage == "python") { 38 | sender.sendMessage("- ${ChatColor.DARK_BLUE}ScriptableMC Python Engine: ${scriptEngineMain.pluginVersion}") 39 | sender.sendMessage("- ${ChatColor.BLUE}GraalPython Version: v21.1.0") 40 | sender.sendMessage("-----------------------------------------------------") 41 | 42 | } 43 | } 44 | } 45 | 46 | @Subcommand("version|v") 47 | @CommandAlias("smcv") 48 | @CommandPermission("scriptablemc.versioncheck") 49 | fun version(sender: CommandSender) { 50 | bootstrapper.versionCheck(sender) 51 | } 52 | 53 | @Subcommand("reload|rl") 54 | @CommandAlias("smcrl") 55 | @CommandPermission("scriptablemc.reload") 56 | fun reload(sender: CommandSender) { 57 | ScriptablePluginEngineBootstrapper.reloadAllScriptEngines(sender) 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/ScriptablePluginEngineConfig.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc 2 | 3 | import org.bukkit.configuration.file.FileConfiguration 4 | 5 | abstract class ScriptablePluginEngineConfig(private val config: FileConfiguration) { 6 | val rootScriptsFolder: String 7 | get() = readConfigString("root_scripts_folder", "./scripts") 8 | 9 | abstract val mainScriptFiles: List 10 | abstract val executeCommandTemplate: String 11 | abstract val scriptMimeType: String 12 | 13 | val autoEnablePlugins: Boolean 14 | get() = readConfigBoolean("auto_enable_plugins", true) 15 | 16 | val debug: Boolean 17 | get() = readConfigBoolean("debug", false) 18 | 19 | val extractLibs: Boolean 20 | get() = readConfigBoolean("extract_libs", true) 21 | 22 | val debugger: ScriptEngineDebuggerConfig 23 | get() = ScriptEngineDebuggerConfig(this) 24 | 25 | @JvmOverloads 26 | fun readConfigString(path: String, def: String = ""): String { 27 | val input = config.getString(path, def).orEmpty() 28 | val regex = Regex("[@|\\\$]\\{(.*)}") 29 | 30 | return regex.replace(input) { 31 | val configValue = readConfigString(it.groups[1]!!.value) 32 | configValue 33 | } 34 | } 35 | 36 | @JvmOverloads 37 | fun readConfigStringList(path: String, def: List = listOf()): List { 38 | val inputList = config.getStringList(path) 39 | val regex = Regex("[@|\\\$]\\{(.*)}") 40 | 41 | if(inputList.isEmpty()) { 42 | inputList.addAll(def) 43 | } 44 | 45 | for((index, input) in inputList.withIndex()) { 46 | inputList[index] = regex.replace(input) { 47 | val configValue = readConfigString(it.groups[1]!!.value) 48 | configValue 49 | } 50 | } 51 | 52 | return inputList 53 | } 54 | 55 | @JvmOverloads 56 | fun readConfigBoolean(path: String, def: Boolean = false): Boolean { 57 | return readConfigString(path, def.toString()).equals("true", true) 58 | } 59 | 60 | class ScriptEngineDebuggerConfig(private val config: ScriptablePluginEngineConfig) { 61 | val enabled: Boolean 62 | get() = config.readConfigBoolean("debugger.enabled", false) 63 | 64 | val address: String 65 | get() = config.readConfigString("debugger.address", "127.0.0.1:9229") 66 | 67 | val waitAttached: Boolean 68 | get() = config.readConfigBoolean("debugger.wait_attached", true) 69 | } 70 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/core/ScriptablePluginCommandManager.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.core 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.command.CommandMap 5 | import org.bukkit.command.PluginCommand 6 | import org.bukkit.plugin.Plugin 7 | import java.lang.reflect.InvocationTargetException 8 | import java.util.HashMap 9 | 10 | @Suppress("unused", "MemberVisibilityCanBePrivate") 11 | class ScriptablePluginCommandManager(private val context: ScriptablePluginContext) { 12 | 13 | private val commands: MutableList = mutableListOf() 14 | 15 | fun newCommand(name: String): PluginCommand? { 16 | var command: PluginCommand? = null 17 | 18 | try { 19 | val c = PluginCommand::class.java.getDeclaredConstructor(String::class.java, Plugin::class.java) 20 | c.isAccessible = true 21 | 22 | command = c.newInstance(name, context.javaPlugin as Plugin) 23 | } catch (e: SecurityException) { 24 | e.printStackTrace() 25 | } catch (e: IllegalArgumentException) { 26 | e.printStackTrace() 27 | } catch (e: IllegalAccessException) { 28 | e.printStackTrace() 29 | } catch (e: InstantiationException) { 30 | e.printStackTrace() 31 | } catch (e: InvocationTargetException) { 32 | e.printStackTrace() 33 | } catch (e: NoSuchMethodException) { 34 | e.printStackTrace() 35 | } 36 | 37 | return command 38 | } 39 | 40 | fun registerCommand(command: PluginCommand) { 41 | val bukkitCommandMap = Bukkit.getServer().javaClass.getDeclaredField("commandMap") 42 | bukkitCommandMap.isAccessible = true 43 | val commandMap = bukkitCommandMap.get(Bukkit.getServer()) as CommandMap 44 | commandMap.register(context.pluginName.lowercase(), command) 45 | commands.add(command) 46 | bukkitCommandMap.isAccessible = false 47 | 48 | if(context.engine.debugEnabled) { 49 | context.engine.bootstrapper.logger.info("[${context.pluginName}] Registered command ${command.name}.") 50 | } 51 | } 52 | 53 | fun unregisterCommand(command: PluginCommand) { 54 | val commandMapField = Bukkit.getServer().javaClass.getDeclaredField("commandMap") 55 | commandMapField.isAccessible = true 56 | val commandMap = commandMapField.get(Bukkit.getServer()) as CommandMap 57 | 58 | var knownCommandsField = commandMap.javaClass.superclass.declaredFields.firstOrNull { it.name.equals("knownCommands", false) } 59 | 60 | if(knownCommandsField == null) { // Pre-MCv1.13 command unregister fix 61 | knownCommandsField = commandMap.javaClass.declaredFields.firstOrNull { it.name.equals("knownCommands", false) } 62 | } 63 | 64 | knownCommandsField?.isAccessible = true 65 | val knownCommands = knownCommandsField?.get(commandMap) as HashMap<*, *>? 66 | 67 | command.unregister(commandMap) 68 | 69 | knownCommands?.remove(command.name) 70 | commands.remove(command) 71 | 72 | commandMapField.isAccessible = false 73 | knownCommandsField?.isAccessible = false 74 | 75 | if(context.engine.debugEnabled) { 76 | context.engine.bootstrapper.logger.info("[${context.pluginName}] Unregistered command ${command.name}.") 77 | } 78 | } 79 | 80 | fun unregisterAllCommands(): Int { 81 | val commands = commands.toTypedArray() 82 | for(command in commands) { 83 | unregisterCommand(command) 84 | } 85 | return commands.size 86 | } 87 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/core/ScriptablePluginContext.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.core 2 | 3 | import com.smc.version.Version 4 | import me.clip.placeholderapi.PlaceholderAPI 5 | import org.bukkit.Bukkit 6 | import org.bukkit.Material 7 | import org.bukkit.OfflinePlayer 8 | import org.bukkit.Server 9 | import org.bukkit.event.Event 10 | import org.bukkit.event.Listener 11 | import org.bukkit.command.PluginCommand 12 | import org.bukkit.entity.Player 13 | import org.bukkit.plugin.* 14 | import org.bukkit.plugin.java.JavaPlugin 15 | import org.bukkit.plugin.messaging.PluginMessageListener 16 | import org.bukkit.plugin.messaging.PluginMessageListenerRegistration 17 | import org.graalvm.polyglot.Value 18 | 19 | 20 | @Suppress("MemberVisibilityCanBePrivate", "unused") 21 | abstract class ScriptablePluginContext: Listener { 22 | abstract val engine: ScriptablePluginEngine 23 | abstract val pluginName: String 24 | abstract val pluginInstance: Value 25 | open val pluginIcon: Material = Material.STONE 26 | open val pluginPriority: Int = 0 27 | 28 | lateinit var logger: ScriptablePluginLogger 29 | internal set 30 | 31 | lateinit var scheduler: ScriptablePluginScheduler 32 | internal set 33 | 34 | lateinit var commandManager: ScriptablePluginCommandManager 35 | internal set 36 | 37 | lateinit var eventManager: ScriptablePluginEventManager 38 | internal set 39 | 40 | lateinit var messenger: ScriptablePluginMessenger 41 | internal set 42 | 43 | var isEnabled: Boolean = false 44 | internal set 45 | 46 | val server: Server 47 | get() = Bukkit.getServer() 48 | 49 | val pluginVersion: Version 50 | get() = engine.pluginVersion 51 | 52 | val javaPlugin: JavaPlugin 53 | get() = engine.bootstrapper 54 | 55 | val servicesManager: ServicesManager 56 | get() = Bukkit.getServicesManager() 57 | 58 | open fun load() { 59 | logger = ScriptablePluginLogger(this) 60 | eventManager = ScriptablePluginEventManager(this) 61 | scheduler = ScriptablePluginScheduler(this) 62 | commandManager = ScriptablePluginCommandManager(this) 63 | messenger = ScriptablePluginMessenger(this) 64 | 65 | if(engine.debugEnabled) { 66 | logger.info("Loading scriptable plugin context.") 67 | } 68 | 69 | if(pluginInstance.hasMember("onLoad")) { 70 | if(pluginInstance.canInvokeMember("onLoad")) { 71 | pluginInstance.invokeMember("onLoad") 72 | } else { 73 | logger.warning("onLoad method is not invokable.") 74 | } 75 | } 76 | } 77 | 78 | open fun enable() { 79 | if(engine.debugEnabled) { 80 | logger.info("Enabling scriptable plugin context.") 81 | } 82 | 83 | if(pluginInstance.hasMember("onEnable")) { 84 | if(pluginInstance.canInvokeMember("onEnable")) { 85 | pluginInstance.invokeMember("onEnable") 86 | } else { 87 | logger.warning("onEnable method is not invokable.") 88 | } 89 | } 90 | 91 | isEnabled = true 92 | } 93 | 94 | open fun disable() { 95 | if(engine.debugEnabled) { 96 | logger.info("Disabling scriptable plugin context.") 97 | } 98 | 99 | if(pluginInstance.hasMember("onDisable")) { 100 | if(pluginInstance.canInvokeMember("onDisable")) { 101 | pluginInstance.invokeMember("onDisable") 102 | } else { 103 | logger.warning("onDisable method is not invokable.") 104 | } 105 | } 106 | 107 | isEnabled = false 108 | } 109 | 110 | open fun unload() { 111 | scheduler.cancelAllTasks() 112 | commandManager.unregisterAllCommands() 113 | eventManager.unregisterAllEvents() 114 | 115 | if(engine.debugEnabled) { 116 | logger.info("Unloading scriptable plugin context.") 117 | } 118 | 119 | if(pluginInstance.hasMember("onUnload")) { 120 | if(pluginInstance.canInvokeMember("onUnload")) { 121 | pluginInstance.invokeMember("onUnload") 122 | } else { 123 | logger.warning("onUnload method is not invokable.") 124 | } 125 | } 126 | } 127 | 128 | fun getBukkitServiceRegistration(className: String): Any? { 129 | val serviceClass = servicesManager.knownServices.firstOrNull { e -> e.name == className } 130 | 131 | if(serviceClass != null) { 132 | return getBukkitServiceRegistration(serviceClass) 133 | } 134 | 135 | return null 136 | } 137 | 138 | fun getBukkitServiceRegistration(_class: Class<*>): Any? { 139 | return servicesManager.getRegistration(_class) 140 | } 141 | 142 | // 143 | @Deprecated("use getEventManager().registerEvent(eventClass, executor)", ReplaceWith("eventManager.registerEvent(eventClass, executor)")) 144 | fun registerEvent(eventClass: Class, executor: EventExecutor) { 145 | eventManager.registerEvent(eventClass, executor) 146 | } 147 | 148 | @Deprecated("use getMessenger().registerIncomingPluginChannel(channelName, listener)", ReplaceWith("messenger.registerIncomingPluginChannel(channelName, listener)")) 149 | fun registerIncomingPluginChannel(channelName: String, listener: PluginMessageListener): PluginMessageListenerRegistration { 150 | return messenger.registerIncomingPluginChannel(channelName, listener) 151 | } 152 | 153 | @Deprecated("use getMessenger().unregisterIncomingPluginChannel(channel)", ReplaceWith("messenger.unregisterIncomingPluginChannel(channel)")) 154 | fun unregisterIncomingPluginChannel(channel: String) { 155 | messenger.unregisterIncomingPluginChannel(channel) 156 | } 157 | 158 | @Deprecated("use getMessenger().registerOutgoingPluginChannel(channel)", ReplaceWith("messenger.registerOutgoingPluginChannel(channel)")) 159 | fun registerOutgoingPluginChannel(channel: String) { 160 | messenger.registerOutgoingPluginChannel(channel) 161 | } 162 | 163 | @Deprecated("use getMessenger().unregisterOutgoingPluginChannel(channel)", ReplaceWith("messenger.unregisterOutgoingPluginChannel(channel)")) 164 | fun unregisterOutgoingPluginChannel(channel: String) { 165 | messenger.unregisterOutgoingPluginChannel(channel) 166 | } 167 | 168 | @Deprecated("use getCommandManager().newCommand(name)", ReplaceWith("commandManager.newCommand(name)")) 169 | fun newCommand(name: String): PluginCommand? { 170 | return commandManager.newCommand(name) 171 | } 172 | 173 | @Deprecated("use getCommandManager().registerCommand(command)", ReplaceWith("commandManager.registerCommand(command)")) 174 | fun registerCommand(command: PluginCommand) { 175 | commandManager.registerCommand(command) 176 | } 177 | 178 | @Deprecated("use getCommandManager().unregisterCommand(command)", ReplaceWith("commandManager.unregisterCommand(command)")) 179 | fun unregisterCommand(command: PluginCommand) { 180 | return commandManager.unregisterCommand(command) 181 | } 182 | 183 | @Deprecated("use PlaceholderAPI.setPlaceholders(player, placeholderText)", ReplaceWith("PlaceholderAPI.setPlaceholders(player, placeholderText)")) 184 | fun setPlaceholders(player: Player, placeholderText: String): String { 185 | if(Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { 186 | return PlaceholderAPI.setPlaceholders(player, placeholderText) 187 | } 188 | 189 | engine.bootstrapper.logger.warning("[$pluginName] Placeholder API is missing.") 190 | return placeholderText 191 | } 192 | 193 | @Deprecated("use PlaceholderAPI.setPlaceholders(player, placeholderText)", ReplaceWith("PlaceholderAPI.setPlaceholders(player, placeholderText)")) 194 | fun setPlaceholders(player: OfflinePlayer, placeholderText: String): String { 195 | if(Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { 196 | return PlaceholderAPI.setPlaceholders(player, placeholderText) 197 | } 198 | 199 | engine.bootstrapper.logger.warning("[$pluginName] Placeholder API is missing.") 200 | return placeholderText 201 | } 202 | // 203 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/core/ScriptablePluginEngine.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.core 2 | 3 | import com.pixlfox.scriptablemc.ScriptablePluginEngineBootstrapper 4 | import com.pixlfox.scriptablemc.ScriptablePluginEngineConfig 5 | import com.smc.exceptions.ScriptNotFoundException 6 | import com.smc.version.Version 7 | import org.bukkit.command.CommandSender 8 | import org.graalvm.polyglot.* 9 | import java.io.File 10 | import java.util.* 11 | 12 | @Suppress("MemberVisibilityCanBePrivate", "unused") 13 | abstract class ScriptablePluginEngine { 14 | abstract val languageName: String 15 | abstract val languageFileExtension: String 16 | abstract val bootstrapper: ScriptablePluginEngineBootstrapper 17 | abstract val debugEnabled: Boolean 18 | 19 | abstract val scriptablePlugins: MutableList 20 | 21 | abstract val graalContext: Context 22 | abstract val globalBindings: Value 23 | 24 | abstract val config: ScriptablePluginEngineConfig 25 | 26 | val pluginVersion: Version 27 | get() = bootstrapper.pluginVersion 28 | 29 | var enabledAllPlugins: Boolean = false 30 | internal set 31 | 32 | val startupErrors: MutableList = mutableListOf() 33 | 34 | open fun start() { 35 | startupErrors.clear() 36 | 37 | globalBindings.putMember("engine", this) 38 | 39 | loadAllHelperClasses() 40 | 41 | for(mainScriptFile in config.mainScriptFiles) { 42 | loadMainScript(mainScriptFile) 43 | } 44 | } 45 | 46 | open fun close() { 47 | disableAllPlugins() 48 | unloadAllPlugins() 49 | graalContext.close(true) 50 | } 51 | 52 | open fun loadAllHelperClasses() { 53 | for(helperClass in preLoadClasses) { 54 | try { 55 | javaClass.classLoader.loadClass(if(helperClass.startsWith("*")) helperClass.substring(1) else helperClass) 56 | } 57 | catch (e: Exception) { 58 | if(!helperClass.startsWith("*")) { 59 | bootstrapper.logger.warning("Failed to load helper class \"$helperClass\" via classloader.") 60 | e.printStackTrace() 61 | } 62 | } 63 | } 64 | } 65 | 66 | open fun enableAllPlugins() { 67 | val scriptablePlugins = scriptablePlugins.toList() 68 | 69 | for (pluginContext in scriptablePlugins.filter { !it.isEnabled }.sortedByDescending { it.pluginPriority }) { 70 | enablePlugin(pluginContext) 71 | } 72 | enabledAllPlugins = true 73 | } 74 | 75 | open fun disableAllPlugins() { 76 | val scriptablePlugins = scriptablePlugins.toList() 77 | 78 | for (pluginContext in scriptablePlugins.filter { it.isEnabled }.sortedBy { it.pluginPriority }) { 79 | disablePlugin(pluginContext) 80 | } 81 | enabledAllPlugins = false 82 | } 83 | 84 | open fun unloadAllPlugins() { 85 | val scriptablePlugins = scriptablePlugins.toList() 86 | 87 | for (pluginContext in scriptablePlugins.sortedBy { it.pluginPriority }) { 88 | unloadPlugin(pluginContext) 89 | } 90 | } 91 | 92 | open fun enablePlugin(pluginContext: ScriptablePluginContext) { 93 | if(!pluginContext.isEnabled) { 94 | pluginContext.enable() 95 | } 96 | else { 97 | bootstrapper.logger.warning("Trying to enable an already-enabled scriptable plugin context.") 98 | } 99 | } 100 | 101 | open fun disablePlugin(pluginContext: ScriptablePluginContext) { 102 | if(pluginContext.isEnabled) { 103 | pluginContext.disable() 104 | } 105 | else { 106 | bootstrapper.logger.warning("Trying to disabled an already-disabled scriptable plugin context.") 107 | } 108 | } 109 | 110 | open fun getPluginInstance(name: String): Value? { 111 | return getPluginInstance(scriptablePlugins.firstOrNull { it.pluginName == name }) 112 | } 113 | 114 | open fun getPluginInstance(pluginContext: ScriptablePluginContext?): Value? { 115 | return pluginContext?.pluginInstance 116 | } 117 | 118 | open fun eval(source: Source): Value { 119 | return graalContext.eval(source) 120 | } 121 | 122 | open fun evalCommandSender(source: String, sender: CommandSender): Value { 123 | val tempScriptFile = File("${config.rootScriptsFolder}/${UUID.randomUUID()}.$languageFileExtension") 124 | try { 125 | tempScriptFile.writeText(source) 126 | return evalFile(tempScriptFile) 127 | } 128 | finally { 129 | tempScriptFile.delete() 130 | } 131 | } 132 | 133 | open fun evalFile(filePath: String): Value { 134 | val scriptFile = File("${config.rootScriptsFolder}/$filePath") 135 | 136 | return if(scriptFile.exists()) { 137 | eval( 138 | Source.newBuilder(languageName, scriptFile) 139 | .name(scriptFile.name) 140 | .mimeType(config.scriptMimeType) 141 | .interactive(false) 142 | .build() 143 | ) 144 | } else { 145 | throw ScriptNotFoundException(scriptFile) 146 | } 147 | } 148 | 149 | open fun evalFile(scriptFile: File): Value { 150 | return if(scriptFile.exists()) { 151 | eval( 152 | Source.newBuilder(languageName, scriptFile) 153 | .name(scriptFile.name) 154 | .mimeType(config.scriptMimeType) 155 | .interactive(false) 156 | .build() 157 | ) 158 | } else { 159 | throw ScriptNotFoundException(scriptFile) 160 | } 161 | } 162 | 163 | open fun eval(source: String): Value { 164 | return graalContext.eval( 165 | Source.newBuilder(languageName, source,"${UUID.randomUUID()}.$languageFileExtension") 166 | .mimeType(config.scriptMimeType) 167 | .interactive(false) 168 | .cached(false) 169 | .build() 170 | ) 171 | } 172 | 173 | open fun loadMainScript(path: String) { 174 | try { 175 | if(config.debug) { 176 | bootstrapper.logger.info("Loading main script file: $path") 177 | } 178 | 179 | val mainScriptFile = File(path) 180 | if(!mainScriptFile.parentFile.exists()) { 181 | mainScriptFile.parentFile.mkdirs() 182 | } 183 | 184 | if(mainScriptFile.exists()) { 185 | val mainReturn = eval( 186 | Source.newBuilder(languageName, mainScriptFile) 187 | .name(mainScriptFile.name) 188 | .mimeType(config.scriptMimeType) 189 | .interactive(false) 190 | .cached(false) 191 | .build() 192 | ) 193 | 194 | // Load exported JsPlugins 195 | for(key in mainReturn.memberKeys) { 196 | this.loadPlugin(mainReturn.getMember(key)) 197 | } 198 | } 199 | else { 200 | throw ScriptNotFoundException(mainScriptFile) 201 | } 202 | } 203 | catch(ex: Exception) { 204 | startupErrors.add(ex) 205 | } 206 | } 207 | 208 | abstract fun loadPlugin(scriptableClass: Value): ScriptablePluginContext 209 | abstract fun unloadPlugin(pluginContext: ScriptablePluginContext) 210 | 211 | companion object { 212 | val preLoadClasses: Array = arrayOf( 213 | "com.smc.version.Version", 214 | "com.smc.version.MinecraftVersions", 215 | "com.smc.utils.ItemBuilder", 216 | "com.smc.utils.MysqlWrapper", 217 | "*org.apache.commons.io.FileUtils", 218 | "*me.clip.placeholderapi.PlaceholderAPI" 219 | ) 220 | } 221 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/core/ScriptablePluginEventManager.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.core 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.event.Event 5 | import org.bukkit.event.EventPriority 6 | import org.bukkit.event.HandlerList 7 | import org.bukkit.plugin.EventExecutor 8 | 9 | @Suppress("unused", "MemberVisibilityCanBePrivate") 10 | class ScriptablePluginEventManager(private val context: ScriptablePluginContext) { 11 | @JvmOverloads 12 | fun registerEvent( 13 | eventClass: Class, 14 | executor: EventExecutor, 15 | priority: EventPriority = EventPriority.NORMAL, 16 | ignoreCancelled: Boolean = false 17 | ) { 18 | Bukkit.getServer().pluginManager.registerEvent(eventClass, context, priority, executor, context.javaPlugin, ignoreCancelled) 19 | } 20 | 21 | fun unregisterAllEvents() { 22 | HandlerList.unregisterAll(context.javaPlugin) 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/core/ScriptablePluginLogger.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.core 2 | 3 | import java.util.logging.Level 4 | import java.util.logging.LogRecord 5 | import java.util.logging.Logger 6 | 7 | class ScriptablePluginLogger(private val context: ScriptablePluginContext) : Logger(context.javaPlugin.description.prefix ?: context.javaPlugin.description.name, null) { 8 | init { 9 | parent = context.javaPlugin.server.logger.parent 10 | level = Level.ALL 11 | } 12 | 13 | override fun log(logRecord: LogRecord) { 14 | logRecord.message = "[${context.pluginName}] ${logRecord.message}" 15 | super.log(logRecord) 16 | } 17 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/core/ScriptablePluginMessenger.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.core 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.plugin.messaging.PluginMessageListener 5 | import org.bukkit.plugin.messaging.PluginMessageListenerRegistration 6 | 7 | @Suppress("unused", "MemberVisibilityCanBePrivate") 8 | class ScriptablePluginMessenger(private val context: ScriptablePluginContext) { 9 | private val messenger = Bukkit.getMessenger() 10 | 11 | fun registerIncomingPluginChannel(channelName: String, listener: PluginMessageListener): PluginMessageListenerRegistration { 12 | return messenger.registerIncomingPluginChannel(context.javaPlugin, channelName, listener) 13 | } 14 | 15 | fun unregisterIncomingPluginChannel(channel: String) { 16 | messenger.unregisterIncomingPluginChannel(context.javaPlugin, channel) 17 | } 18 | 19 | fun registerOutgoingPluginChannel(channel: String) { 20 | messenger.registerOutgoingPluginChannel(context.javaPlugin, channel) 21 | } 22 | 23 | fun unregisterOutgoingPluginChannel(channel: String) { 24 | messenger.unregisterOutgoingPluginChannel(context.javaPlugin, channel) 25 | } 26 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/core/ScriptablePluginScheduler.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.core 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.plugin.java.JavaPlugin 5 | import org.bukkit.scheduler.BukkitTask 6 | 7 | @Suppress("unused", "MemberVisibilityCanBePrivate") 8 | class ScriptablePluginScheduler(private val context: ScriptablePluginContext) { 9 | private val serverScheduler = Bukkit.getScheduler() 10 | private val tasks = mutableListOf() 11 | 12 | fun runTaskTimer(delay: Long, period: Long, run: () -> Unit): BukkitTask { 13 | val task = serverScheduler.runTaskTimer(context.javaPlugin, Runnable { run.invoke() }, delay, period) 14 | tasks.add(task) 15 | return task 16 | } 17 | 18 | fun cancelTask(task: BukkitTask) { 19 | if(!task.isCancelled) { 20 | task.cancel() 21 | } 22 | tasks.remove(task) 23 | } 24 | 25 | fun cancelAllTasks(): Int { 26 | val tasks = tasks.toTypedArray() 27 | for(task in tasks) { 28 | cancelTask(task) 29 | } 30 | return tasks.size 31 | } 32 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/pixlfox/scriptablemc/utils/UnzipUtil.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.utils 2 | 3 | import java.io.* 4 | import java.util.zip.ZipInputStream 5 | 6 | 7 | /** 8 | * This utility extracts files and directories of a standard zip file to 9 | * a destination directory. 10 | * @author www.codejava.net 11 | */ 12 | @Suppress("unused") 13 | class UnzipUtility { 14 | companion object { 15 | /** 16 | * Size of the buffer to read/write data 17 | */ 18 | private const val BUFFER_SIZE = 4096 19 | 20 | /** 21 | * Extracts a zip file from the zipStream to a directory specified by 22 | * destDirectory (will be created if does not exists) 23 | * @param zipStream 24 | * @param destDir 25 | * @throws IOException 26 | */ 27 | @Throws(IOException::class) 28 | fun unzip(zipStream: InputStream, destDir: File) { 29 | if(!destDir.exists()) { 30 | destDir.mkdirs() 31 | } 32 | 33 | val zipIn = ZipInputStream(zipStream) 34 | var entry = zipIn.nextEntry 35 | // iterates over entries in the zip file 36 | while (entry != null) { 37 | val filePath = destDir.path + File.separator + entry.name 38 | if (!entry.isDirectory) { // if the entry is a file, extracts it 39 | extractFile(zipIn, filePath) 40 | } else { // if the entry is a directory, make the directory 41 | val dir = File(filePath) 42 | dir.mkdir() 43 | } 44 | zipIn.closeEntry() 45 | entry = zipIn.nextEntry 46 | } 47 | zipIn.close() 48 | } 49 | 50 | /** 51 | * Extracts a zip file specified by the zipFilePath to a directory specified by 52 | * destDirectory (will be created if does not exists) 53 | * @param zipFilePath 54 | * @param destDirectory 55 | * @throws IOException 56 | */ 57 | @Throws(IOException::class) 58 | fun unzip(zipFilePath: String, destDirectory: String) = unzip(FileInputStream(zipFilePath), File(destDirectory)) 59 | 60 | /** 61 | * Extracts a zip file specified by the zipFilePath to a directory specified by 62 | * destDirectory (will be created if does not exists) 63 | * @param zipFilePath 64 | * @param destDir 65 | * @throws IOException 66 | */ 67 | @Throws(IOException::class) 68 | fun unzip(zipFilePath: String, destDir: File) = unzip(FileInputStream(zipFilePath), destDir) 69 | 70 | /** 71 | * Extracts a zip entry (file entry) 72 | * @param zipIn 73 | * @param filePath 74 | * @throws IOException 75 | */ 76 | @Throws(IOException::class) 77 | private fun extractFile(zipIn: ZipInputStream, filePath: String) { 78 | val bos = BufferedOutputStream(FileOutputStream(filePath)) 79 | val bytesIn = ByteArray(BUFFER_SIZE) 80 | var read: Int 81 | while (zipIn.read(bytesIn).also { read = it } != -1) { 82 | bos.write(bytesIn, 0, read) 83 | } 84 | bos.close() 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/smc/exceptions/ScriptNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.smc.exceptions 2 | 3 | import java.io.File 4 | 5 | class ScriptNotFoundException(scriptFile: File) : Exception("Unable to load script: ${scriptFile.absolutePath}.") -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/smc/utils/ItemBuilder.kt: -------------------------------------------------------------------------------- 1 | package com.smc.utils 2 | 3 | import org.bukkit.Material 4 | import org.bukkit.enchantments.Enchantment 5 | import org.bukkit.inventory.ItemStack 6 | 7 | @Suppress("unused") 8 | class ItemBuilder(private val itemStack: ItemStack) { 9 | 10 | constructor(material: Material): this(ItemStack(material)) 11 | 12 | fun setDisplayName(displayName: String): ItemBuilder { 13 | val itemMeta = itemStack.itemMeta 14 | itemMeta?.setDisplayName(displayName) 15 | itemStack.itemMeta = itemMeta 16 | 17 | return this 18 | } 19 | 20 | fun getDisplayName(): String { 21 | val itemMeta = itemStack.itemMeta 22 | if(itemMeta != null) { 23 | return itemMeta.displayName 24 | } 25 | 26 | return "" 27 | } 28 | 29 | fun setLore(lore: Array): ItemBuilder { 30 | val itemMeta = itemStack.itemMeta 31 | itemMeta?.lore = lore.toList() 32 | itemStack.itemMeta = itemMeta 33 | 34 | return this 35 | } 36 | 37 | fun getLore(): Array { 38 | val itemMeta = itemStack.itemMeta 39 | if(itemMeta != null && itemMeta.lore != null) { 40 | return itemMeta.lore!!.toTypedArray() 41 | } 42 | 43 | return arrayOf() 44 | } 45 | 46 | fun isUnbreakable(isUnbreakable: Boolean): ItemBuilder { 47 | val itemMeta = itemStack.itemMeta 48 | itemMeta?.isUnbreakable = isUnbreakable 49 | itemStack.itemMeta = itemMeta 50 | 51 | return this 52 | } 53 | 54 | @JvmOverloads 55 | fun addEnchant(enchantment: Enchantment, level: Int = 1, ignoreLevelRestriction: Boolean = false): ItemBuilder { 56 | val itemMeta = itemStack.itemMeta 57 | itemMeta?.addEnchant(enchantment, level, ignoreLevelRestriction) 58 | itemStack.itemMeta = itemMeta 59 | 60 | return this 61 | } 62 | 63 | fun removeEnchantment(enchantment: Enchantment): ItemBuilder { 64 | val itemMeta = itemStack.itemMeta 65 | itemMeta?.removeEnchant(enchantment) 66 | itemStack.itemMeta = itemMeta 67 | 68 | return this 69 | } 70 | 71 | fun build(): ItemStack { 72 | return itemStack 73 | } 74 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/smc/utils/MysqlWrapper.kt: -------------------------------------------------------------------------------- 1 | package com.smc.utils 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.plugin.java.JavaPlugin 5 | import java.sql.Connection 6 | import java.sql.DriverManager 7 | import java.sql.PreparedStatement 8 | import java.sql.Statement 9 | 10 | @Suppress("unused", "MemberVisibilityCanBePrivate") 11 | class MysqlWrapper(private val host: String, private val port: Int, private val database: String, private val username: String, private val password: String) { 12 | private var connection: Connection? = null 13 | 14 | fun openConnection() { 15 | synchronized (this) { 16 | if (connection != null && !connection!!.isClosed) { 17 | return; 18 | } 19 | 20 | Class.forName("com.mysql.jdbc.Driver"); 21 | connection = DriverManager.getConnection("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database, this.username, this.password); 22 | } 23 | } 24 | 25 | fun openConnectionAsync(javaPlugin: JavaPlugin, callback: (() -> Unit)? = null) = executeAsync(javaPlugin) { 26 | this.openConnection() 27 | 28 | if(callback != null) { 29 | callback() 30 | } 31 | } 32 | 33 | fun executeAsync(javaPlugin: JavaPlugin, asyncFunction: (() -> Unit)) = Bukkit.getScheduler().runTaskAsynchronously(javaPlugin, Runnable { 34 | asyncFunction() 35 | }); 36 | 37 | fun getBaseConnection(): Connection? = connection 38 | 39 | fun close() = connection?.close() 40 | fun isClosed() = connection?.isClosed != false 41 | fun isReadOnly(): Boolean = connection?.isReadOnly == true 42 | 43 | fun createStatement(): Statement? = connection?.createStatement() 44 | fun createStatement(resultSetType: Int, resultSetConcurrency: Int): Statement? = connection?.createStatement(resultSetType, resultSetConcurrency) 45 | fun createStatement(resultSetType: Int, resultSetConcurrency: Int, resultSetHoldability: Int): Statement? = connection?.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability) 46 | 47 | fun prepareStatement(sql: String): PreparedStatement? = connection?.prepareStatement(sql) 48 | fun prepareStatement(sql: String, autoGeneratedKeys: Int): PreparedStatement? = connection?.prepareStatement(sql, autoGeneratedKeys) 49 | fun prepareStatement(sql: String, resultSetType: Int, resultSetConcurrency: Int): PreparedStatement? = connection?.prepareStatement(sql, resultSetType, resultSetConcurrency) 50 | fun prepareStatement(sql: String, resultSetType: Int, resultSetConcurrency: Int, resultSetHoldability: Int): PreparedStatement? = connection?.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability) 51 | fun prepareStatement(sql: String, columnIndexes: IntArray): PreparedStatement? = connection?.prepareStatement(sql, columnIndexes) 52 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/smc/version/MinecraftVersions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of helper, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | * 25 | * Converted to Kotlin by: AStorks 26 | */ 27 | 28 | package com.smc.version 29 | 30 | import com.smc.version.Version.Companion.parse 31 | import org.bukkit.Bukkit 32 | import java.util.regex.Pattern 33 | 34 | @Suppress("unused") 35 | class MinecraftVersions private constructor(){ 36 | companion object { 37 | /** 38 | * Version 1.20 39 | */ 40 | @JvmField 41 | val v1_20 = parse("1.20") 42 | 43 | /** 44 | * Version 1.19.3 - the update the broke a ton of plugins... 45 | */ 46 | @JvmField 47 | val v1_19_3 = parse("1.19.3") 48 | 49 | /** 50 | * Version 1.19 51 | */ 52 | @JvmField 53 | val v1_19 = parse("1.19") 54 | 55 | /** 56 | * Version 1.18 57 | */ 58 | @JvmField 59 | val v1_18 = parse("1.18") 60 | 61 | /** 62 | * Version 1.17 - caves and cliffs update 63 | */ 64 | @JvmField 65 | val v1_17 = parse("1.17") 66 | 67 | /** 68 | * Version 1.16 - nether update 69 | */ 70 | @JvmField 71 | val v1_16 = parse("1.16") 72 | 73 | /** 74 | * Version 1.15 - buzzy bees update 75 | */ 76 | @JvmField 77 | val v1_15 = parse("1.15") 78 | 79 | /** 80 | * Version 1.14 - village and pillage update 81 | */ 82 | @JvmField 83 | val v1_14 = parse("1.14") 84 | 85 | /** 86 | * Version 1.13 - update aquatic. 87 | */ 88 | @JvmField 89 | val v1_13 = parse("1.13") 90 | 91 | /** 92 | * Version 1.12 - the world of color update. 93 | */ 94 | @JvmField 95 | val v1_12 = parse("1.12") 96 | 97 | /** 98 | * Version 1.11 - the exploration update. 99 | */ 100 | @JvmField 101 | val v1_11 = parse("1.11") 102 | 103 | /** 104 | * Version 1.10 - the frostburn update. 105 | */ 106 | @JvmField 107 | val v1_10 = parse("1.10") 108 | 109 | /** 110 | * Version 1.9 - the combat update. 111 | */ 112 | @JvmField 113 | val v1_9 = parse("1.9") 114 | 115 | /** 116 | * Version 1.8 - the "bountiful" update. 117 | */ 118 | @JvmField 119 | val v1_8 = parse("1.8") 120 | 121 | /** 122 | * Version 1.7.8 - the update that changed the skin format (and distribution - R.I.P. player disguise) 123 | */ 124 | @JvmField 125 | val v1_7_8 = parse("1.7.8") 126 | 127 | /** 128 | * Version 1.7.2 - the update that changed the world. 129 | */ 130 | @JvmField 131 | val v1_7_2 = parse("1.7.2") 132 | 133 | /** 134 | * Version 1.6.1 - the horse update. 135 | */ 136 | @JvmField 137 | val v1_6_1 = parse("1.6.1") 138 | 139 | /** 140 | * Version 1.5.0 - the redstone update. 141 | */ 142 | @JvmField 143 | val v1_5_0 = parse("1.5.0") 144 | 145 | /** 146 | * Version 1.4.2 - the scary update (Wither Boss). 147 | */ 148 | @JvmField 149 | val v1_4_2 = parse("1.4.2") 150 | 151 | /** 152 | * Regular expression used to parse version strings. 153 | */ 154 | private val VERSION_PATTERN = 155 | Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-\\.]+)\\s*\\)") 156 | 157 | /** 158 | * The version of the runtime 159 | */ 160 | @JvmField 161 | val RUNTIME_VERSION = parseServerVersion(Bukkit.getVersion()) 162 | 163 | private fun parseServerVersion(serverVersion: String): Version { 164 | val version = VERSION_PATTERN.matcher(serverVersion) 165 | return if (version.matches() && version.group(1) != null) { 166 | parse(version.group(1)) 167 | } else { 168 | throw IllegalStateException("Cannot parse version String '$serverVersion'") 169 | } 170 | } 171 | } 172 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-Core/src/main/kotlin/com/smc/version/Version.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of helper, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | * 25 | * Converted to Kotlin by: AStorks 26 | */ 27 | 28 | package com.smc.version 29 | 30 | import java.util.* 31 | import kotlin.Comparator 32 | 33 | @Suppress("unused", "MemberVisibilityCanBePrivate") 34 | class Version private constructor(val major: Int, val minor: Int, val build: Int): Comparable { 35 | 36 | @Suppress("unused", "MemberVisibilityCanBePrivate") 37 | companion object { 38 | @JvmStatic 39 | val COMPARATOR: Comparator = Comparator.nullsFirst( 40 | Comparator 41 | .comparingInt { obj: Version -> obj.major } 42 | .thenComparingInt { obj: Version -> obj.minor } 43 | .thenComparingInt { obj: Version -> obj.build } 44 | ) 45 | 46 | /** 47 | * Creates a new [Version] with the given properties. 48 | * 49 | * @param major the major component 50 | * @param minor the minor component 51 | * @param build the build component 52 | * @return a version instance 53 | */ 54 | @JvmStatic 55 | fun of(major: Int, minor: Int, build: Int): Version { 56 | return Version(major, minor, build) 57 | } 58 | 59 | /** 60 | * Parses a [Version] from a version string, in the format 61 | * `major.minor.build` 62 | * 63 | * @param version the version in text form. 64 | * @throws IllegalArgumentException if unable to parse 65 | */ 66 | @JvmStatic 67 | @Throws(IllegalArgumentException::class) 68 | fun parse(version: String): Version { 69 | val versionComponents = parseVersion(version) 70 | val major = versionComponents[0] 71 | val minor = versionComponents[1] 72 | val build = versionComponents[2] 73 | return Version(major, minor, build) 74 | } 75 | 76 | @JvmStatic 77 | private fun parseVersion(version: String): IntArray { 78 | val elements = if(version.startsWith("v", true)) version.substring(1).split(".").toTypedArray() else version.split(".").toTypedArray() 79 | val numbers = IntArray(3) 80 | // Make sure it's even a valid version 81 | check(elements.isNotEmpty()) { "Corrupt version: $version" } 82 | // The String 1 or 1.2 is interpreted as 1.0.0 and 1.2.0 respectively. 83 | for (i in 0 until Math.min(numbers.size, elements.size)) { 84 | numbers[i] = elements[i].trim { it <= ' ' }.toInt() 85 | } 86 | return numbers 87 | } 88 | } 89 | 90 | /** 91 | * Gets the version String (major.minor.build) only. 92 | * 93 | * @return a normal version string. 94 | */ 95 | fun getVersion(): String { 96 | return "$major.$minor.$build" 97 | } 98 | 99 | override fun compareTo(other: Version): Int { 100 | return COMPARATOR.compare(this, other) 101 | } 102 | 103 | /** 104 | * Gets if this version was released after another version. 105 | * 106 | * @param other the other version 107 | * @return if this version was released after another version 108 | */ 109 | fun isAfter(other: Version): Boolean { 110 | return compareTo(other) > 0 111 | } 112 | 113 | /** 114 | * Gets if this version was released after another version, or is equal to it. 115 | * 116 | * @param other the other version 117 | * @return if this version was released after another version, or is equal to it. 118 | */ 119 | fun isAfterOrEq(other: Version): Boolean { 120 | return compareTo(other) >= 0 121 | } 122 | 123 | /** 124 | * Gets if this version was released before another version. 125 | * 126 | * @param other the other version 127 | * @return if this version was released before another version 128 | */ 129 | fun isBefore(other: Version): Boolean { 130 | return compareTo(other) < 0 131 | } 132 | 133 | /** 134 | * Gets if this version was released before another version, or is equal to it. 135 | * 136 | * @param other the other version 137 | * @return if this version was released before another version, or is equal to it. 138 | */ 139 | fun isBeforeOrEq(other: Version): Boolean { 140 | return compareTo(other) <= 0 141 | } 142 | 143 | /** 144 | * Gets if this version was released in the period between two other versions, or is equal 145 | * to either of them. 146 | * 147 | * @param o1 the first other version 148 | * @param o2 the second other version 149 | * @return if this version was released between the others 150 | */ 151 | fun isBetween(o1: Version, o2: Version): Boolean { 152 | return isAfterOrEq(o1) && isBeforeOrEq(o2) || isBeforeOrEq(o1) && isAfterOrEq(o2) 153 | } 154 | 155 | override fun equals(other: Any?): Boolean { 156 | if (other == null) return false 157 | if (other === this) return true 158 | if (other !is Version) return false 159 | return major == other.major && minor == other.minor && build == other.build 160 | } 161 | 162 | override fun hashCode(): Int { 163 | return Objects.hash(major, minor, build) 164 | } 165 | 166 | override fun toString(): String { // Convert to a String that we can parse back again 167 | return String.format("v%s", getVersion()) 168 | } 169 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-JS/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar 2 | import org.apache.tools.ant.filters.ReplaceTokens 3 | import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName 4 | 5 | plugins { 6 | java 7 | id("org.jetbrains.kotlin.jvm") 8 | // id("com.github.johnrengelman.shadow") 9 | id("io.github.goooler.shadow") 10 | id("org.jetbrains.gradle.plugin.idea-ext") 11 | } 12 | 13 | var pluginVersion = findProperty("plugin.version") ?: "2.0.0-dev" 14 | var graalvmVersion = findProperty("dependencies.graalvm.version") ?: "23.0.2" 15 | var spigotmcVersion = findProperty("dependencies.spigotmc.version") ?: "1.20.4-R0.1-SNAPSHOT" 16 | 17 | version = pluginVersion 18 | 19 | java { 20 | sourceCompatibility = JavaVersion.VERSION_17 21 | targetCompatibility = JavaVersion.VERSION_17 22 | 23 | } 24 | 25 | idea { 26 | module { 27 | isDownloadJavadoc = true 28 | isDownloadSources = true 29 | } 30 | } 31 | 32 | val baseShadow: Configuration by configurations.creating 33 | val engineShadow: Configuration by configurations.creating 34 | 35 | dependencies { 36 | implementation(project(":ScriptableMC-Engine-Core")) 37 | 38 | // SpigotMC API 39 | compileOnly("org.spigotmc:spigot-api:$spigotmcVersion") { 40 | isChanging = true 41 | } 42 | 43 | compileOnly("org.graalvm.sdk:graal-sdk:$graalvmVersion") 44 | compileOnly("org.graalvm.truffle:truffle-api:$graalvmVersion") 45 | compileOnly("co.aikar:acf-paper:0.5.1-SNAPSHOT") 46 | compileOnly("com.github.kittinunf.fuel:fuel:2.3.1") 47 | compileOnly("com.github.kittinunf.fuel:fuel-json:2.3.1") 48 | 49 | baseShadow(project) 50 | baseShadow("org.graalvm.sdk:graal-sdk:$graalvmVersion") 51 | baseShadow("org.graalvm.truffle:truffle-api:$graalvmVersion") 52 | baseShadow("com.github.kittinunf.fuel:fuel:2.3.1") 53 | baseShadow("com.github.kittinunf.fuel:fuel-json:2.3.1") 54 | baseShadow("co.aikar:acf-paper:0.5.1-SNAPSHOT") 55 | baseShadow("fr.minuskube.inv:smart-invs:1.2.7") 56 | 57 | engineShadow("org.graalvm.js:js:$graalvmVersion") 58 | engineShadow("org.graalvm.js:js-scriptengine:$graalvmVersion") 59 | engineShadow("org.graalvm.tools:chromeinspector:$graalvmVersion") 60 | engineShadow("org.graalvm.tools:profiler:$graalvmVersion") 61 | 62 | testImplementation("junit", "junit", "4.12") 63 | } 64 | 65 | tasks { 66 | processResources { 67 | expand( 68 | "smcVersion" to pluginVersion, 69 | "graalvmVersion" to graalvmVersion, 70 | "spigotmcVersion" to spigotmcVersion, 71 | ) 72 | } 73 | 74 | compileKotlin { 75 | kotlinOptions.jvmTarget = "17" 76 | kotlinOptions.javaParameters = true 77 | } 78 | 79 | compileTestKotlin { 80 | kotlinOptions.jvmTarget = "17" 81 | kotlinOptions.javaParameters = true 82 | } 83 | 84 | jar { 85 | archiveBaseName.set("smcjs-classes") 86 | } 87 | 88 | shadowJar { 89 | enabled = false 90 | dependsOn("shadowJarBase") 91 | dependsOn("shadowJarEngine") 92 | } 93 | 94 | register("shadowJarBase", ShadowJar::class.java) { 95 | group = "shadow" 96 | configurations = listOf(baseShadow) 97 | archiveFileName.set("smcjs-$pluginVersion.jar") 98 | 99 | dependencies { 100 | exclude(dependency("org.spigotmc:spigot-api")) 101 | exclude(dependency("net.md-5:bungeecord-chat")) 102 | exclude(dependency("junit:junit")) 103 | } 104 | 105 | relocate("co.aikar.commands", "com.pixlfox.scriptablemc.acf") 106 | relocate("de.tr7zw.changeme.nbtapi", "com.smc.nbtapi") 107 | relocate("kotlin", "scriptablemc.kotlin") 108 | relocate("org.intellij", "scriptablemc.intellij") 109 | relocate("org.jetbrains", "scriptablemc.jetbrains") 110 | relocate("org.yaml", "scriptablemc.yaml") 111 | relocate("org.json", "scriptablemc.json") 112 | 113 | mergeServiceFiles() 114 | } 115 | 116 | register("shadowJarEngine", ShadowJar::class.java) { 117 | group = "shadow" 118 | configurations = listOf(baseShadow, engineShadow) 119 | archiveFileName.set("smcjs-bundle-$pluginVersion.jar") 120 | 121 | dependencies { 122 | exclude(dependency("org.spigotmc:spigot-api")) 123 | exclude(dependency("net.md-5:bungeecord-chat")) 124 | exclude(dependency("junit:junit")) 125 | } 126 | 127 | relocate("co.aikar.commands", "com.pixlfox.scriptablemc.acf") 128 | relocate("de.tr7zw.changeme.nbtapi", "com.smc.nbtapi") 129 | relocate("kotlin", "scriptablemc.kotlin") 130 | relocate("org.intellij", "scriptablemc.intellij") 131 | relocate("org.jetbrains", "scriptablemc.jetbrains") 132 | relocate("org.yaml", "scriptablemc.yaml") 133 | relocate("org.json", "scriptablemc.json") 134 | 135 | mergeServiceFiles() 136 | } 137 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-JS/src/main/kotlin/com/pixlfox/scriptablemc/js/JavaScriptPluginEngineBootstrapper.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.js 2 | 3 | import co.aikar.commands.PaperCommandManager 4 | import com.google.common.base.Charsets 5 | import com.pixlfox.scriptablemc.ScriptablePluginEngineBootstrapper 6 | import com.pixlfox.scriptablemc.ScriptablePluginEngineCommands 7 | import com.pixlfox.scriptablemc.js.core.JavaScriptPluginEngine 8 | import org.bukkit.ChatColor 9 | import org.bukkit.command.CommandSender 10 | import org.bukkit.configuration.file.FileConfiguration 11 | import org.bukkit.configuration.file.YamlConfiguration 12 | import java.io.File 13 | import java.io.InputStreamReader 14 | 15 | 16 | @Suppress("unused") 17 | class JavaScriptPluginEngineBootstrapper : ScriptablePluginEngineBootstrapper() { 18 | override val chatMessagePrefix = "${ChatColor.GRAY}[${ChatColor.DARK_AQUA}ScriptableMC-JS${ChatColor.GRAY}]${ChatColor.RESET}" 19 | override val scriptLanguage = "js" 20 | private var newConfig: YamlConfiguration? = null 21 | lateinit var jsConfigFile: File 22 | lateinit var jsConfig: JavaScriptPluginEngineConfig 23 | 24 | override fun onLoad() { 25 | super.onLoad() 26 | jsConfigFile = File(sharedDataFolder, "config_js.yml") 27 | instance = this 28 | saveDefaultConfig() 29 | } 30 | 31 | override fun onEnable() { 32 | commandManager = PaperCommandManager(this) 33 | commandManager.registerCommand(ScriptablePluginEngineCommands(this)) 34 | commandManager.registerCommand(JavaScriptPluginEngineCommands(this), true) 35 | 36 | server.scheduler.scheduleSyncDelayedTask(this, Runnable { 37 | fullLoadScriptEngine() 38 | enableScriptEngine() 39 | }) 40 | } 41 | 42 | override fun onDisable() { 43 | releaseScriptEngine(scriptLanguage) 44 | commandManager.unregisterCommands() 45 | unloadScriptEngine() 46 | } 47 | 48 | override fun saveDefaultConfig() { 49 | super.saveDefaultConfig() 50 | if (!jsConfigFile.exists()) { 51 | saveResource("config_js.yml", false) 52 | } 53 | } 54 | 55 | override fun reloadConfig() { 56 | newConfig = YamlConfiguration.loadConfiguration(jsConfigFile) 57 | val defConfigStream = getResource("config_js.yml") ?: return 58 | newConfig?.setDefaults(YamlConfiguration.loadConfiguration(InputStreamReader(defConfigStream, Charsets.UTF_8))) 59 | } 60 | 61 | override fun getConfig(): FileConfiguration { 62 | if (newConfig == null) { 63 | reloadConfig() 64 | } 65 | return newConfig!! 66 | } 67 | 68 | private fun fullUnloadScriptEngine(sender: CommandSender? = null) { 69 | patchClassLoader(javaClass) { 70 | try { 71 | scriptEngine.close() 72 | logger.info("JavaScript engine shutdown.") 73 | sender?.sendMessage("$chatMessagePrefix JavaScript engine shutdown.") 74 | } catch (e: Exception) { 75 | logger.warning("JavaScript engine failed to shutdown.") 76 | e.printStackTrace() 77 | 78 | sender?.sendMessage("$chatMessagePrefix ${ChatColor.DARK_RED}JavaScript engine failed to shutdown. Check the server console.") 79 | } 80 | } 81 | } 82 | 83 | private fun unloadScriptEngine(sender: CommandSender? = null) { 84 | patchClassLoader(javaClass) { 85 | try { 86 | scriptEngine.disableAllPlugins() 87 | scriptEngine.unloadAllPlugins() 88 | } catch (e: Exception) { 89 | logger.warning("JavaScript engine failed to unload.") 90 | e.printStackTrace() 91 | 92 | sender?.sendMessage("$chatMessagePrefix ${ChatColor.DARK_RED}JavaScript engine failed to unload. Check the server console.") 93 | } 94 | } 95 | } 96 | 97 | private fun fullLoadScriptEngine(sender: CommandSender? = null) { 98 | versionCheck() 99 | patchClassLoader(javaClass) { 100 | try { 101 | jsConfig = JavaScriptPluginEngineConfig(config) 102 | scriptEngine = JavaScriptPluginEngine(this, jsConfig) 103 | scriptEngine.start() 104 | if(scriptEngine.startupErrors.any()) { 105 | for(error in scriptEngine.startupErrors) { 106 | error.printStackTrace() 107 | if(sender != null) { 108 | sender.sendMessage("$chatMessagePrefix ${ChatColor.RED}$error") 109 | for (stackTrace in error.stackTrace.filter { it.fileName?.endsWith(".js") == true }) { 110 | sender.sendMessage("${ChatColor.RED}$stackTrace") 111 | } 112 | } 113 | } 114 | 115 | logger.warning("JavaScript engine started with errors.") 116 | sender?.sendMessage("$chatMessagePrefix ${ChatColor.YELLOW}JavaScript engine started with errors.") 117 | } 118 | else { 119 | logger.info("JavaScript engine started.") 120 | sender?.sendMessage("$chatMessagePrefix ${ChatColor.GREEN}JavaScript engine started.") 121 | } 122 | } 123 | catch (error: Exception) { 124 | error.printStackTrace() 125 | if(sender != null) { 126 | sender.sendMessage("$chatMessagePrefix ${ChatColor.DARK_RED}$error") 127 | for (stackTrace in error.stackTrace) { 128 | sender.sendMessage("${ChatColor.RED}$stackTrace") 129 | } 130 | } 131 | 132 | logger.severe("JavaScript engine failed to start.") 133 | sender?.sendMessage("$chatMessagePrefix ${ChatColor.DARK_RED}JavaScript engine failed to start.") 134 | } 135 | } 136 | } 137 | 138 | private fun loadScriptEngine(sender: CommandSender? = null) { 139 | patchClassLoader(javaClass) { 140 | try { 141 | scriptEngine.start() 142 | if(scriptEngine.startupErrors.any()) { 143 | for(error in scriptEngine.startupErrors) { 144 | error.printStackTrace() 145 | if(sender != null) { 146 | sender.sendMessage("$chatMessagePrefix ${ChatColor.RED}$error") 147 | for (stackTrace in error.stackTrace.filter { it.fileName?.endsWith(".js") == true }) { 148 | sender.sendMessage("${ChatColor.RED}$stackTrace") 149 | } 150 | } 151 | } 152 | 153 | logger.warning("JavaScript engine reloaded with errors.") 154 | sender?.sendMessage("$chatMessagePrefix ${ChatColor.YELLOW}JavaScript engine reloaded with errors.") 155 | } 156 | else { 157 | logger.info("JavaScript engine reloaded.") 158 | sender?.sendMessage("$chatMessagePrefix ${ChatColor.GREEN}JavaScript engine reloaded.") 159 | } 160 | } 161 | catch (error: Exception) { 162 | error.printStackTrace() 163 | if(sender != null) { 164 | sender.sendMessage("$chatMessagePrefix ${ChatColor.DARK_RED}$error") 165 | for (stackTrace in error.stackTrace) { 166 | sender.sendMessage("${ChatColor.RED}$stackTrace") 167 | } 168 | } 169 | 170 | logger.severe("JavaScript engine failed to reload.") 171 | sender?.sendMessage("$chatMessagePrefix ${ChatColor.DARK_RED}JavaScript engine failed to reload.") 172 | } 173 | } 174 | } 175 | 176 | private fun enableScriptEngine(sender: CommandSender? = null) { 177 | if(jsConfig.autoEnablePlugins) { 178 | patchClassLoader(javaClass) { 179 | try { 180 | scriptEngine.enableAllPlugins() 181 | logger.info("JavaScript engine enabled.") 182 | sender?.sendMessage("$chatMessagePrefix ${ChatColor.GREEN}JavaScript engine enabled.") 183 | } catch (error: Exception) { 184 | error.printStackTrace() 185 | if(sender != null) { 186 | sender.sendMessage("$chatMessagePrefix ${ChatColor.DARK_RED}$error") 187 | for (stackTrace in error.stackTrace) { 188 | sender.sendMessage("${ChatColor.RED}$stackTrace") 189 | } 190 | } 191 | 192 | logger.severe("JavaScript engine failed to enable.") 193 | sender?.sendMessage("$chatMessagePrefix ${ChatColor.DARK_RED}JavaScript engine failed to enable.") 194 | } 195 | } 196 | } 197 | } 198 | 199 | override fun reloadScriptEngine(sender: CommandSender?) { 200 | unloadScriptEngine(sender) 201 | saveDefaultConfig() 202 | reloadConfig() 203 | loadScriptEngine(sender) 204 | enableScriptEngine(sender) 205 | } 206 | 207 | fun fullReloadScriptEngine(sender: CommandSender?) { 208 | fullUnloadScriptEngine(sender) 209 | saveDefaultConfig() 210 | reloadConfig() 211 | fullLoadScriptEngine(sender) 212 | enableScriptEngine(sender) 213 | } 214 | 215 | companion object { 216 | var instance: JavaScriptPluginEngineBootstrapper? = null 217 | private set 218 | } 219 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-JS/src/main/kotlin/com/pixlfox/scriptablemc/js/JavaScriptPluginEngineCommands.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.js 2 | 3 | import co.aikar.commands.BaseCommand 4 | import co.aikar.commands.annotation.CommandAlias 5 | import co.aikar.commands.annotation.CommandPermission 6 | import co.aikar.commands.annotation.Subcommand 7 | import co.aikar.commands.annotation.Syntax 8 | import com.github.kittinunf.fuel.httpGet 9 | import com.github.kittinunf.result.success 10 | import org.bukkit.ChatColor 11 | import org.bukkit.command.CommandSender 12 | import org.graalvm.polyglot.PolyglotException 13 | 14 | 15 | @Suppress("unused") 16 | @CommandAlias("scriptablemc|smc") 17 | @Subcommand("javascript|js") 18 | class JavaScriptPluginEngineCommands(private val bootstrapper: JavaScriptPluginEngineBootstrapper) : BaseCommand() { 19 | 20 | // @Subcommand("fullreload|frl") 21 | // @CommandAlias("jsfrl") 22 | // @CommandPermission("scriptablemc.js.fullreload") 23 | // fun fullReload(sender: CommandSender) { 24 | // bootstrapper.fullReloadScriptEngine(sender) 25 | // } 26 | 27 | @Subcommand("reload|rl") 28 | @CommandAlias("jsrl") 29 | @CommandPermission("scriptablemc.js.reload") 30 | fun reload(sender: CommandSender) { 31 | bootstrapper.fullReloadScriptEngine(sender) 32 | } 33 | 34 | // @Subcommand("pastebin|pb") 35 | // @CommandAlias("jsexpb") 36 | // @CommandPermission("scriptablemc.js.execute.pastebin") 37 | // @Syntax("") 38 | // fun executePastebin(sender: CommandSender, code: String) { 39 | // val (_, _, result) = "https://pastebin.com/raw/$code".httpGet().responseString() 40 | // result.success { 41 | // executeCode(sender, it) 42 | // } 43 | // } 44 | 45 | @Subcommand("exhttp|exh") 46 | @CommandAlias("jsexh") 47 | @CommandPermission("scriptablemc.js.execute.http") 48 | @Syntax("") 49 | fun executeHttp(sender: CommandSender, url: String) { 50 | var pixlfoxRegex = Regex("https://paste.pixlfox.net/([a-zA-Z0-9]*?)\$") 51 | val pastebinRegex = Regex("https://pastebin.com/(.*?)\$") 52 | 53 | var parsedUrl = url 54 | 55 | 56 | if(url.matches(pixlfoxRegex)) { 57 | val match = pixlfoxRegex.matchEntire(url) 58 | if(match != null) { 59 | val pasteCode = match.groups[1]?.value 60 | if(pasteCode != null) { 61 | parsedUrl = "https://paste.pixlfox.net/$pasteCode/raw" 62 | } 63 | } 64 | } 65 | 66 | if(url.matches(pastebinRegex)) { 67 | val match = pastebinRegex.matchEntire(url) 68 | if(match != null) { 69 | val pastebinCode = match.groups[1]?.value 70 | if(pastebinCode != null) { 71 | parsedUrl = "https://pastebin.com/raw/$pastebinCode" 72 | } 73 | } 74 | } 75 | 76 | val (_, _, result) = parsedUrl.httpGet().responseString() 77 | result.success { 78 | executeCode(sender, it) 79 | } 80 | } 81 | 82 | @Subcommand("execute|ex") 83 | @CommandAlias("jsex") 84 | @CommandPermission("scriptablemc.js.execute") 85 | @Syntax("") 86 | fun execute(sender: CommandSender, code: String) { 87 | executeCode(sender, code) 88 | } 89 | 90 | private fun executeCode(sender: CommandSender, code: String) { 91 | try { 92 | val response = bootstrapper.scriptEngine.evalCommandSender(code, sender) 93 | 94 | for (key in response.memberKeys) { 95 | sender.sendMessage("$key: ${response.getMember(key)}") 96 | } 97 | } catch (e: PolyglotException) { 98 | e.printStackTrace() 99 | 100 | sender.sendMessage("${ChatColor.RED}$e") 101 | for (stackTrace in e.stackTrace) { 102 | if (stackTrace.fileName?.endsWith(".js", true) == true) { 103 | sender.sendMessage("${ChatColor.YELLOW}$stackTrace") 104 | } 105 | } 106 | } catch (e: Exception) { 107 | e.printStackTrace() 108 | 109 | sender.sendMessage("${ChatColor.DARK_RED}$e") 110 | for (stackTrace in e.stackTrace) { 111 | if (stackTrace.className.startsWith("com.pixlfox.scriptablemc", true)) { 112 | sender.sendMessage("${ChatColor.RED}$stackTrace") 113 | } 114 | } 115 | } 116 | } 117 | 118 | @Subcommand("file|f") 119 | @CommandAlias("jsexf") 120 | @CommandPermission("scriptablemc.js.execute.file") 121 | @Syntax("") 122 | fun executeFile(sender: CommandSender, filePath: String) { 123 | if(filePath.equals("main.js", true)) { 124 | sender.sendMessage("${ChatColor.DARK_RED}Unable to execute the main script entrypoint. Use the command /jsrl to reload scripts.") 125 | return 126 | } 127 | 128 | try { 129 | val response = bootstrapper.scriptEngine.evalFile(filePath) 130 | 131 | for (key in response.memberKeys) { 132 | sender.sendMessage("$key: ${response.getMember(key)}") 133 | } 134 | } 135 | catch (e: Exception) { 136 | e.printStackTrace() 137 | 138 | sender.sendMessage("${ChatColor.DARK_RED}$e") 139 | for (stackTrace in e.stackTrace) { 140 | sender.sendMessage("${ChatColor.DARK_RED}$stackTrace") 141 | } 142 | } 143 | } 144 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-JS/src/main/kotlin/com/pixlfox/scriptablemc/js/JavaScriptPluginEngineConfig.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.js 2 | 3 | import com.pixlfox.scriptablemc.ScriptablePluginEngineConfig 4 | import org.bukkit.configuration.file.FileConfiguration 5 | 6 | class JavaScriptPluginEngineConfig(config: FileConfiguration) : ScriptablePluginEngineConfig(config) { 7 | override val mainScriptFiles: List 8 | get() = readConfigStringList("main_script_files", listOf("\${root_scripts_folder}/main.js")) 9 | 10 | override val executeCommandTemplate: String 11 | get() = readConfigString("execute_command_template", "import * as lib from './lib/global.js';\n" + 12 | "new (class EvalCommandSenderContext {\n" + 13 | " execute(sender, server, servicesManager) {\n" + 14 | " %SOURCE%\n" + 15 | " }\n" + 16 | "})()") 17 | 18 | override val scriptMimeType: String 19 | get() = readConfigString("script_mime_type", "application/javascript+module") 20 | 21 | val commonJsModulesEnabled: Boolean 22 | get() = readConfigBoolean("common_js.enabled", false) 23 | 24 | val commonJsModulesPath: String 25 | get() = readConfigString("common_js.modules_path", "\${root_scripts_folder}/node_modules") 26 | 27 | val commonJsGlobalsFile: String 28 | get() = readConfigString("common_js.globals_file", "globals.js") 29 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-JS/src/main/kotlin/com/pixlfox/scriptablemc/js/core/JavaScriptPluginContext.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.js.core 2 | 3 | import com.pixlfox.scriptablemc.core.ScriptablePluginContext 4 | import com.pixlfox.scriptablemc.core.ScriptablePluginEngine 5 | import com.pixlfox.scriptablemc.core.ScriptablePluginLogger 6 | import com.pixlfox.scriptablemc.core.ScriptablePluginScheduler 7 | import org.bukkit.Material 8 | import org.bukkit.event.HandlerList 9 | import org.graalvm.polyglot.Value 10 | 11 | 12 | @Suppress("MemberVisibilityCanBePrivate", "unused") 13 | class JavaScriptPluginContext(override val engine: ScriptablePluginEngine, override val pluginName: String, override val pluginPriority: Int, override val pluginIcon: Material, override val pluginInstance: Value) : ScriptablePluginContext() { 14 | companion object { 15 | fun newInstance(pluginName: String, pluginPriority: Int, pluginIcon: Material, engine: ScriptablePluginEngine, pluginInstance: Value): ScriptablePluginContext { 16 | if(engine.debugEnabled) { 17 | engine.bootstrapper.logger.info("[$pluginName] Creating new JavaScript plugin context.") 18 | } 19 | 20 | return JavaScriptPluginContext(engine, pluginName, pluginPriority, pluginIcon, pluginInstance) 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-JS/src/main/kotlin/com/pixlfox/scriptablemc/js/core/JavaScriptPluginEngine.kt: -------------------------------------------------------------------------------- 1 | package com.pixlfox.scriptablemc.js.core 2 | 3 | import com.pixlfox.scriptablemc.ScriptablePluginEngineBootstrapper 4 | import com.pixlfox.scriptablemc.core.ScriptablePluginContext 5 | import com.pixlfox.scriptablemc.core.ScriptablePluginEngine 6 | import com.pixlfox.scriptablemc.js.JavaScriptPluginEngineConfig 7 | import com.pixlfox.scriptablemc.utils.UnzipUtility 8 | import org.bukkit.Material 9 | import org.graalvm.polyglot.* 10 | import org.graalvm.polyglot.io.IOAccess 11 | import java.io.File 12 | 13 | 14 | @Suppress("MemberVisibilityCanBePrivate", "unused") 15 | class JavaScriptPluginEngine(override val bootstrapper: ScriptablePluginEngineBootstrapper, override val config: JavaScriptPluginEngineConfig): ScriptablePluginEngine() { 16 | 17 | override val languageName: String = "js" 18 | override val languageFileExtension: String = "js" 19 | override val debugEnabled: Boolean = config.debug 20 | override val graalContext: Context 21 | override val globalBindings: Value 22 | override val scriptablePlugins: MutableList = mutableListOf() 23 | 24 | init { 25 | if(config.extractLibs) { 26 | val librariesResource = bootstrapper.getResource("libraries.zip") 27 | val libFolder = File("${config.rootScriptsFolder}/lib") 28 | if (librariesResource != null && !libFolder.exists()) { 29 | if(debugEnabled) { 30 | bootstrapper.logger.info("Extracting javascript libraries from ScriptableMC-Engine-JS resources to ${libFolder.path}...") 31 | } 32 | UnzipUtility.unzip(librariesResource, libFolder) 33 | } 34 | } 35 | 36 | var contextBuilder = Context 37 | .newBuilder(languageName) 38 | .allowAllAccess(true) 39 | .allowExperimentalOptions(true) 40 | .allowHostAccess(HostAccess.ALL) 41 | .allowHostClassLoading(true) 42 | .allowIO(IOAccess.ALL) 43 | .allowCreateThread(true) 44 | .option("js.ecmascript-version", "latest") 45 | .option("engine.WarnInterpreterOnly", "false") 46 | .option("log.file", "logs/script-engine.log") 47 | .option("js.esm-eval-returns-exports", "true") 48 | 49 | if(config.commonJsModulesEnabled) { 50 | if(config.debug) { 51 | bootstrapper.logger.info("Enabling CommonJS support...") 52 | } 53 | 54 | if (!File(config.commonJsModulesPath).exists()) { 55 | if(config.debug) { 56 | bootstrapper.logger.info("CommonJS creating modules folder: ${config.commonJsModulesPath}") 57 | } 58 | File(config.commonJsModulesPath).mkdirs() 59 | } 60 | else { 61 | if(config.debug) { 62 | bootstrapper.logger.info("CommonJS using modules folder: ${config.commonJsModulesPath}") 63 | } 64 | } 65 | 66 | contextBuilder = contextBuilder 67 | .option("js.commonjs-require", "true") 68 | .option("js.commonjs-require-cwd", config.commonJsModulesPath) 69 | 70 | if (File(File(config.commonJsModulesPath), config.commonJsGlobalsFile).exists()) { 71 | if(config.debug) { 72 | bootstrapper.logger.info("CommonJS using globals: ${File(File(config.commonJsModulesPath), config.commonJsGlobalsFile).path}") 73 | } 74 | contextBuilder = contextBuilder 75 | .option("js.commonjs-global-properties", config.commonJsGlobalsFile) 76 | } 77 | else { 78 | if(config.debug) { 79 | bootstrapper.logger.warning("CommonJS unable to read globals: ${File(File(config.commonJsModulesPath), config.commonJsGlobalsFile).path}") 80 | } 81 | } 82 | 83 | bootstrapper.logger.info("CommonJS support enabled.") 84 | } 85 | 86 | if(config.debugger.enabled) { 87 | contextBuilder = contextBuilder 88 | .option("inspect", config.debugger.address) 89 | .option("inspect.Path", "smc-engine-js") 90 | .option("inspect.Suspend", "false") 91 | .option("inspect.Secure", "false") 92 | .option("inspect.WaitAttached", "${config.debugger.waitAttached}") 93 | } 94 | 95 | graalContext = contextBuilder.build() 96 | 97 | globalBindings = graalContext.getBindings(languageName) 98 | } 99 | 100 | override fun start() { 101 | instance = this 102 | super.start() 103 | } 104 | 105 | override fun close() { 106 | instance = null 107 | super.close() 108 | } 109 | 110 | override fun loadPlugin(scriptableClass: Value): ScriptablePluginContext { 111 | val pluginInstance = scriptableClass.newInstance() 112 | val pluginName = pluginInstance.getMember("pluginName").asString() 113 | var pluginIcon = Material.STONE 114 | var pluginPriority = 0 115 | if(pluginInstance.hasMember("icon")) { 116 | try { 117 | pluginIcon = pluginInstance.getMember("icon").`as`(Material::class.java) 118 | } 119 | catch(_: Exception) { } 120 | } 121 | if(pluginInstance.hasMember("priority")) { 122 | try { 123 | pluginPriority = pluginInstance.getMember("priority").asInt() 124 | } 125 | catch(_: Exception) { } 126 | } 127 | val pluginContext = JavaScriptPluginContext.newInstance(pluginName, pluginPriority, pluginIcon, this, pluginInstance) 128 | pluginInstance.putMember("context", pluginContext) 129 | scriptablePlugins.add(pluginContext) 130 | pluginContext.load() 131 | return pluginContext 132 | } 133 | 134 | override fun unloadPlugin(pluginContext: ScriptablePluginContext) { 135 | if(pluginContext.isEnabled) { 136 | pluginContext.disable() 137 | } 138 | 139 | pluginContext.unload() 140 | scriptablePlugins.remove(pluginContext) 141 | } 142 | 143 | companion object { 144 | var instance: JavaScriptPluginEngine? = null 145 | private set 146 | } 147 | } -------------------------------------------------------------------------------- /ScriptableMC-Engine-JS/src/main/resources/config_js.yml: -------------------------------------------------------------------------------- 1 | # Root scripts folder 2 | # Example inside plugin folder: ./plugins/ScriptableMC/scripts 3 | # Default: ./scripts 4 | root_scripts_folder: './scripts' 5 | 6 | # Script MIME type 7 | # JavaScript Module: application/javascript+module 8 | # Pure JavaScript: application/javascript 9 | # Default: application/javascript+module 10 | script_mime_type: 'application/javascript+module' 11 | 12 | # Main script files 13 | # The main entry point javascript files 14 | # Default: @{root_scripts_folder}/main.js 15 | main_script_files: 16 | - '@{root_scripts_folder}/main.js' 17 | 18 | # Auto-Enable all scriptable plugins after executing all main scripts 19 | # If set to false you will have to manually enable all plugins 20 | # via engine.enableAllPlugins() after you have loaded all plugins 21 | # Default: true 22 | auto_enable_plugins: true 23 | 24 | # Prints some additional debugging messages 25 | # Default: false 26 | debug: false 27 | 28 | # Version check on script engine start 29 | # If enabled will make a request to the github api to check for updates 30 | # and notify you if any updates are available 31 | # Default: true 32 | version_check: true 33 | 34 | # Automatically extract js libraries to scripts lib folder if lib folder is missing 35 | # If you set this to false you'll need to download and extract the libs manually. 36 | # Default: true 37 | extract_libs: true 38 | 39 | # Execute command template 40 | # This is the code that will be executed with /jsex and /smc javascript execute 41 | # If a class is returned it will be instantiated and continued on as an object 42 | # If object is returned and has a method execute script engine will call 43 | # returnedObject.execute(sender: CommandSender, server: BukkitServer, servicesManager) 44 | # as well as set returnedObject.sender, returnedObject.server, and returnedObject.servicesManager 45 | # you can also add additional methods, vars to the template source below 46 | # Otherwise the script engine will return last execute code 47 | # %SOURCE% will be replaced with the command source. 48 | execute_command_template: " 49 | new (class EvalCommandSenderContext { 50 | execute(sender, server, servicesManager) { 51 | %SOURCE% 52 | } 53 | })()" 54 | 55 | common_js: 56 | # Enable CommonJS `require()` support 57 | # Allows the use of CommonJS NPM modules 58 | # Default: false 59 | enabled: false 60 | 61 | # CommonJS modules path 62 | # The default path to load CommonJS modules from. 63 | # Default: @{root_scripts_folder}/node_modules 64 | modules_path: '@{root_scripts_folder}/node_modules' 65 | 66 | # CommonJS globals file name 67 | # The CommonJS globals file used to define global CommonJS values 68 | # Relative to the `common_js.modules_path` folder 69 | # Default: globals.js 70 | globals_file: 'globals.js' 71 | 72 | # Chrome debugger settings 73 | # **WARNING** THE DEBUGGER SHOULD NEVER BE ENABLED ON A PUBLIC SERVER 74 | # IT IS INTENDED ONLY FOR DEBUGGING THE SCRIPT ENGINE AND CAN BREAK/FREEZE YOUR WHOLE SERVER 75 | # Default: enabled: false, address: 127.0.0.1:9229, wait_attached: true 76 | # If enabled: true and wait_attached: true the whole minecraft server will freeze until the chrome debugger is attached 77 | # this is useful for debugging the script engine startup 78 | # To enable remote debugging set address: 0.0.0.0:9229 79 | debugger: 80 | enabled: false 81 | address: 127.0.0.1:9229 82 | wait_attached: true -------------------------------------------------------------------------------- /ScriptableMC-Engine-JS/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: ScriptableMC-Engine-JS 2 | description: 'Run JavaScript/TypeScript plugins for Bukkit/Spigot/Paper Minecraft 1.19' 3 | version: '${smcVersion}' 4 | api-version: '1.13' 5 | author: AStorks 6 | main: com.pixlfox.scriptablemc.js.JavaScriptPluginEngineBootstrapper 7 | softdepend: [PlaceholderAPI, CommandAPI] -------------------------------------------------------------------------------- /ScriptableMC-Engine.ipr: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 89 | 90 | 91 | 1.6 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /ScriptableMC-Engine.iws: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 35 | 36 | 50 | 51 | 52 | 53 | 54 | 55 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 95 | 96 | 97 | 111 | 112 | 113 | 129 | 130 | 131 | 132 | 146 | 147 | 148 | 151 | 152 | 153 | 154 | localhost 155 | 5050 156 | 157 | 158 | 159 | 160 | 173 | 174 | 175 | 176 | 177 | 178 | 204 | 205 | 206 | 207 | 208 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | id("org.jetbrains.kotlin.jvm") version "1.9.22" apply false 4 | // id("com.github.johnrengelman.shadow") version "8.1.1" apply false 5 | id("io.github.goooler.shadow") version "8.1.2" apply false 6 | id("org.jetbrains.gradle.plugin.idea-ext") version "1.1.7" apply false 7 | } 8 | 9 | allprojects { 10 | group = project.findProperty("maven_group") ?: "com.pixlfox.scriptablemc" 11 | version = project.findProperty("plugin.version") ?: "2.0.0-SNAPSHOT" 12 | 13 | repositories { 14 | mavenCentral() 15 | maven { 16 | name = "JitPack" 17 | url = uri("https://jitpack.io") 18 | } 19 | maven { 20 | name = "spigotmc" 21 | url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") 22 | } 23 | maven { 24 | name = "spigotmc nexus" 25 | url = uri("https://hub.spigotmc.org/nexus/content/repositories/sonatype-nexus-snapshots/") 26 | } 27 | maven { 28 | name = "minecraft" 29 | url = uri("https://libraries.minecraft.net") 30 | } 31 | maven { 32 | name = "papermc" 33 | url = uri("https://papermc.io/repo/repository/maven-public/") 34 | } 35 | maven { 36 | name = "placeholderapi" 37 | url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") 38 | } 39 | maven { 40 | name = "aikar-acf" 41 | url = uri("https://repo.aikar.co/content/groups/aikar/") 42 | } 43 | maven { 44 | name = "codemc-repo" 45 | url = uri("https://repo.codemc.org/repository/maven-public/") 46 | } 47 | } 48 | } 49 | 50 | tasks.register("shadowJarAll") { 51 | group = "shadow" 52 | 53 | dependsOn(":ScriptableMC-Engine-Core:shadowJar") 54 | dependsOn(":ScriptableMC-Engine-JS:shadowJarBase") 55 | dependsOn(":ScriptableMC-Engine-JS:shadowJarEngine") 56 | 57 | doFirst { 58 | if(!file("./build/libs").exists()) file("./build/libs").mkdirs() 59 | } 60 | 61 | doLast { 62 | file("./ScriptableMC-Engine-Core/build/libs/ScriptableMC-Engine-Core.jar").copyTo(file("./build/libs/ScriptableMC-Engine-Core.jar"), overwrite = true) 63 | file("./ScriptableMC-Engine-JS/build/libs/ScriptableMC-Engine-JS.jar").copyTo(file("./build/libs/ScriptableMC-Engine-JS.jar"), overwrite = true) 64 | file("./ScriptableMC-Engine-JS/build/libs/ScriptableMC-Engine-JS-Bundled.jar").copyTo(file("./build/libs/ScriptableMC-Engine-JS-Bundled.jar"), overwrite = true) 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | maven.group=com.pixlfox 3 | plugin.version=2.0.1-dev 4 | dependencies.graalvm.version=23.0.2 5 | dependencies.spigotmc.version=1.20.4-R0.1-SNAPSHOT -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astorks/ScriptableMC-Engine/8301ea1588281bd3346b1585bb4168fe4151c7ff/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "ScriptableMC-Engine" 2 | 3 | include("ScriptableMC-Engine-Core") 4 | include("ScriptableMC-Engine-JS") --------------------------------------------------------------------------------