├── .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 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.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 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 | [](https://github.com/astorks/ScriptableMC-Engine/releases/latest)
4 | [](https://www.spigotmc.org/resources/scriptablemc-engine.74690/)
5 | 
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 | > 
53 |
54 | > `/jsex sender.sendMessage(lib.org.bukkit.ChatColor.GREEN + "Hello World!")`
55 | > 
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 |