|
| 1 | +## Introduction |
| 2 | +ShowScript 3 is a programming language that allows you to schedule commands and other actions to be executed at specified timecodes. Here's what it looks like: |
| 3 | + |
| 4 | + |
| 5 | +```groovy |
| 6 | +ticks(0) { |
| 7 | + cmd { |
| 8 | + "broadcast Hello World!" |
| 9 | + } |
| 10 | +} |
| 11 | +
|
| 12 | +seconds(2) { |
| 13 | + cmd { |
| 14 | + "broadcast This will run 2 seconds after the show starts" |
| 15 | + } |
| 16 | +} |
| 17 | +
|
| 18 | +``` |
| 19 | + |
| 20 | +## Basic Concepts |
| 21 | + |
| 22 | +At its core, a ShowScript is a text file (ending in the `.groovy` extension) that defines what actions should happen and when. The file is broken up into blocks of "Timecodes" with one or more blocks of "Actions" inside of them to be executed at that timecode. |
| 23 | + |
| 24 | +### Timecodes |
| 25 | + |
| 26 | +A Timecode block may be specified multiple ways: |
| 27 | + |
| 28 | +#### Ticks `(ticks)` |
| 29 | +The fundamental time unit of the Minecraft server. 20 ticks is equal to 1 second. |
| 30 | +```groovy |
| 31 | +ticks(20) { |
| 32 | +... |
| 33 | +} |
| 34 | +``` |
| 35 | + |
| 36 | +#### Seconds (`seconds`) |
| 37 | +For you convenience, you can also use seconds as a unit for your timecode block: |
| 38 | +```groovy |
| 39 | +seconds(1) { |
| 40 | +... |
| 41 | +} |
| 42 | +``` |
| 43 | +Fractional seconds are also supported: |
| 44 | + |
| 45 | +```groovy |
| 46 | +seconds(1.5) { |
| 47 | +... |
| 48 | +} |
| 49 | +``` |
| 50 | + |
| 51 | +If you provide a fractional second that does not line up evenly on a tick, it will be rounded down to the nearest tick. |
| 52 | + |
| 53 | +> Multiple actions in one tick will not always be run in the same order as they are written in the show file. |
| 54 | +{.is-warning} |
| 55 | + |
| 56 | +### Actions |
| 57 | +Inside of your Timecode blocks, you can set any number of Actions to be executed at that timecode. ShowScript 3 supports a few different types of actions: |
| 58 | + |
| 59 | +#### Command (`cmd`) |
| 60 | +Run a command in the console of your server. Any command from any plugin that can be run from console can be used! On MCParks, we primarily use commands from in-house custom plugins. |
| 61 | +```groovy |
| 62 | +cmd { |
| 63 | + "any command you can run in console" |
| 64 | +} |
| 65 | +``` |
| 66 | + |
| 67 | +#### Text (`text`) |
| 68 | +Display a piece of `text` to all players within `range` blocks of `x`/`y`/`z` in world `world` |
| 69 | +```groovy |
| 70 | +text { |
| 71 | + world = "world" |
| 72 | + x = 0 |
| 73 | + y = 0 |
| 74 | + z = 0 |
| 75 | + text = "your text here" |
| 76 | + range = 10 |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +### Show (`show`) |
| 81 | + |
| 82 | +Start another show (either ShowScript 2 or 3)! |
| 83 | + |
| 84 | +```groovy |
| 85 | +show { |
| 86 | + name = "showName" |
| 87 | + <argumentName> = <argValue> // arguments are only required if the show requires arguments. See the "Show arguments" section for more information |
| 88 | + // arguments are parsed as Strings right now; proper support for arbitrary scripts is coming soon |
| 89 | +} |
| 90 | +
|
| 91 | +``` |
| 92 | + |
| 93 | +### Comments |
| 94 | + |
| 95 | +It's important to write comments in your code so other people know what's going on! |
| 96 | + |
| 97 | +ShowScript 3 supports single line comments: |
| 98 | +```groovy |
| 99 | +// this is a comment |
| 100 | +``` |
| 101 | + |
| 102 | +and multi-line comments: |
| 103 | +```groovy |
| 104 | +/* this |
| 105 | +is |
| 106 | +a |
| 107 | +comment |
| 108 | +that spans |
| 109 | +multiple |
| 110 | +lines! |
| 111 | +*/ |
| 112 | +``` |
| 113 | + |
| 114 | +### Show arguments |
| 115 | + |
| 116 | +Sometimes, you may want to write a ShowScript that is reusable under different circumstances. |
| 117 | + |
| 118 | +Say you want to write a show that sets the time of day using `/time set <timeOfDay>`, and you know you'll need one that runs `/time set day` and `/time set night`. You *could* write this as two separate shows: |
| 119 | + |
| 120 | + |
| 121 | +```groovy |
| 122 | +// setDay.groovy |
| 123 | +ticks(0) { |
| 124 | + cmd { |
| 125 | + "time set day" |
| 126 | + } |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | + |
| 131 | +```groovy |
| 132 | +// setNight.groovy |
| 133 | +ticks(0) { |
| 134 | + cmd { |
| 135 | + "time set night" |
| 136 | + } |
| 137 | +} |
| 138 | +``` |
| 139 | + |
| 140 | +But, ShowScript 3 lets you turn this show into a "function" that can be called with any input you want, like this: |
| 141 | + |
| 142 | +```groovy |
| 143 | +// setTime.groovy |
| 144 | +show { timeOfDay -> |
| 145 | + ticks(0) { |
| 146 | + cmd { |
| 147 | + "time set ${timeOfDay}" |
| 148 | + } |
| 149 | + } |
| 150 | +} |
| 151 | +``` |
| 152 | + |
| 153 | +You can then use the `--args` flag when starting your show to specify the argument to pass: `/show start setTime --args "day"`, for example (yes, you need to wrap the string `"day"` in quotes. If you're interested in why, check out the . And since the `/time set <timeOfDay>` command can take *any* time of day, |
| 154 | + |
| 155 | + |
| 156 | +Your show can have more than one argument, too: |
| 157 | +```groovy |
| 158 | +// adder.groovy |
| 159 | +show { num1, num2 -> |
| 160 | + ticks(0) { |
| 161 | + cmd { |
| 162 | + "broadcast ${num1 + num2}" |
| 163 | + } |
| 164 | + } |
| 165 | +} |
| 166 | +``` |
| 167 | +You would start this show with `/show start adder --args 1, 2` if you want `/broadcast 3` to be executed. Multiple arguments are separated with commas (`,`). |
| 168 | +## Advanced Concepts |
| 169 | + |
| 170 | +### Variables |
| 171 | + |
| 172 | +Sometimes there will be a string, number, or some other piece of data that repeats _constantly_ in your shows (coordinates, an armorstand's name, preamble to an `imagemap animate` command, etc). It's bad style to repeat this code over and over again, so you can use variables to avoid repetition. |
| 173 | + |
| 174 | +#### Variable definition and assignment |
| 175 | + |
| 176 | +Variables can be defined using the `def` keyword followed by a variable name: |
| 177 | +```groovy |
| 178 | +def myCoolVariable |
| 179 | +
|
| 180 | +``` |
| 181 | + |
| 182 | +You can assign variables for later use: |
| 183 | +```groovy |
| 184 | +myCoolVariable = 5 |
| 185 | +``` |
| 186 | + |
| 187 | +You can also definite and assign a variable in one step, like this: |
| 188 | +```groovy |
| 189 | +def myCoolVariable = 5 |
| 190 | +
|
| 191 | +def approximatelyPi = 3.1415 |
| 192 | +
|
| 193 | +def isRyanCool = true |
| 194 | +``` |
| 195 | + |
| 196 | +Variable definition and assignment can happen outside of a timecode block and can be used anywhere in your show (it will be initialized when `/show start` is initially called) |
| 197 | +```groovy |
| 198 | +def imagemapAnimate = "imagemap animate 163 55 703 https://mcparks.us/images/WDW/MK/Tomorrowland/Space/Preshow1" |
| 199 | +
|
| 200 | +ticks(0) { |
| 201 | + cmd { |
| 202 | + "${imagemapAnimate}/001.png" |
| 203 | + } |
| 204 | +} |
| 205 | +
|
| 206 | +ticks(10) { |
| 207 | + cmd { |
| 208 | + "${imagemapAnimate}/002.png" |
| 209 | + } |
| 210 | +} |
| 211 | +``` |
| 212 | + |
| 213 | +Variable definition and assignment can happen in a timecode block, too, but the variable can only be used in that block (it will be initialized when the timecode block runs) |
| 214 | +```groovy |
| 215 | +ticks(0) { |
| 216 | + def location = "105 65 222" |
| 217 | + cmd { |
| 218 | + "asa animate ${location} ..." |
| 219 | + } |
| 220 | + |
| 221 | + cmd { |
| 222 | + "imagemap animate ${location} ..." |
| 223 | + } |
| 224 | +} |
| 225 | +
|
| 226 | +ticks(10) { |
| 227 | + // this will produce an error |
| 228 | + cmd { |
| 229 | + "broadcast location is ${location}" |
| 230 | + } |
| 231 | +} |
| 232 | +
|
| 233 | +``` |
| 234 | + |
| 235 | +You can also define a variable outside a timecode block, but change its value in different timecode blocks: |
| 236 | + |
| 237 | +```groovy |
| 238 | +def theNumber = 0 |
| 239 | +ticks(1) { |
| 240 | + theNumber = theNumber + 1 |
| 241 | +} |
| 242 | +
|
| 243 | +ticks(2) { |
| 244 | + theNumber = theNumber + 1 |
| 245 | +} |
| 246 | +
|
| 247 | +ticks(3) { |
| 248 | + cmd { |
| 249 | + "broadcast theNumber is ${theNumber}" // will broadcast "theNumber is 2" |
| 250 | + } |
| 251 | +} |
| 252 | +
|
| 253 | +``` |
| 254 | + |
| 255 | + |
| 256 | + |
| 257 | + |
| 258 | +### Programming |
| 259 | + |
| 260 | +A lot of the power of ShowScript 3 comes from the fact that it's powered by the Groovy programming language. All [semantics](https://groovy-lang.org/semantics.html) of the Groovy programming language, including `if` statements/conditionals, `for`/`while` loops, and more. |
| 261 | + |
| 262 | +> It's important that any code you run is PERFORMANT! If you think the code you're running might be resource intensive (looping over a lot of entities, running intense math every single tick, etc), ask in #technicians for guidance on how to accomplish your goal as performantly as possible! |
| 263 | +{.is-warning} |
| 264 | + |
| 265 | +Here are examples of this power: |
| 266 | + |
| 267 | +```groovy |
| 268 | +def imagemapAnimate = "imagemap animate 163 55 703 https://mcparks.us/images/WDW/MK/Tomorrowland/Space/Preshow1" // preamble for an imagemap animate command in the Space Mountain preshow monitor |
| 269 | +
|
| 270 | +for (int i=1; i<=42; i++) { // there are 42 frames in this video, named `001.png` to `042.png` |
| 271 | + def formattedNumber = String.format("%03d", i) // use Java's String formatting (which Groovy inherits) to format the number to 3 digits |
| 272 | + ticks(i*10) { // create a timecode block for every 10 ticks |
| 273 | + cmd { |
| 274 | + "${imagemapAnimate}/${formattedNumber}.png" // the commmand is the preamble we defined on line 1, followed by a '/', followed by the number of the frame, followed by .png |
| 275 | + } |
| 276 | + } |
| 277 | +} |
| 278 | +``` |
| 279 | + |
| 280 | + |
| 281 | + |
| 282 | +### Accessing server info |
| 283 | + |
| 284 | +ShowScript 3 has some convenience methods for accessing information from the Minecraft server that you can use in programming to make certain decisions. |
| 285 | +> Be careful when accessing server information, especially when running methods on objects on `World`s, `Player`s, etc -- these methods have the power to change literally _anything_ on the server! |
| 286 | +{.is-warning} |
| 287 | + |
| 288 | + |
| 289 | + |
| 290 | + |
| 291 | +#### `world(String worldName)` (returns: [World](https://helpch.at/docs/1.12.2/org/bukkit/World.html)) |
| 292 | + |
| 293 | +Example usage: |
| 294 | + |
| 295 | +```groovy |
| 296 | +ticks(0) { |
| 297 | + def time = world("world").getTime() |
| 298 | + if (time > 12000) { |
| 299 | + cmd { |
| 300 | + "broadcast it is night time" |
| 301 | + } |
| 302 | + } else { |
| 303 | + cmd { |
| 304 | + "broadcast it is day time" |
| 305 | + } |
| 306 | + } |
| 307 | +} |
| 308 | +``` |
| 309 | + |
| 310 | +#### `player(String playerName)` (returns: [Player](https://helpch.at/docs/1.12.2/org/bukkit/entity/Player.html)) |
| 311 | + |
| 312 | +Example usage: |
| 313 | +```groovy |
| 314 | +ticks(0) { |
| 315 | + def ryanLocation = player("RyanHecht_").getLocation() |
| 316 | + |
| 317 | + cmd { |
| 318 | + "broadcast Ryan is at ${ryanLocation.getX()}, ${ryanLocation.getY()}, ${ryanLocation.getZ()}" |
| 319 | + } |
| 320 | +} |
| 321 | +``` |
| 322 | +#### `location(String worldName, double x, double y, double z)` (returns: [Location](https://helpch.at/docs/1.12.2/org/bukkit/Location.html)) |
| 323 | + |
| 324 | +#### `location(World world, double x, double y, double z)` |
| 325 | +#### `location(double x, double y, double z)` (creates a location in the world called "world") |
| 326 | + |
| 327 | +#### `onlinePlayers()` (returns List\<Player\>) |
| 328 | +Get a list of all the players on the server |
| 329 | + |
| 330 | +#### `runningShows()` (returns List\<ShowScheduler\>) |
| 331 | +Get a list of all running shows |
| 332 | + |
| 333 | +`ShowScheduler` has these methods: |
| 334 | +```java |
| 335 | + public String getName(); |
| 336 | + |
| 337 | + public int getSyntaxVersion(); |
| 338 | + |
| 339 | + public Integer getShowTaskId(); |
| 340 | + |
| 341 | + public void stopShow(); |
| 342 | + |
| 343 | + public int getTimecode(); |
| 344 | + ``` |
| 345 | + |
| 346 | +#### `isShowRunning(String showName)` returns `boolean` |
| 347 | +Returns `true` if a show of that name is running, otherwise `false` |
| 348 | + |
| 349 | +### Other convenience methods |
| 350 | + |
| 351 | +#### `sin(double angle)` (returns double) |
| 352 | +Get the mathematical sine of an angle |
| 353 | + |
| 354 | +#### `cos(double angle)` (returns double) |
| 355 | +Get the mathematical cosine of an angle |
| 356 | + |
| 357 | +#### `tan(double angle)` (returns double) |
| 358 | +Get the mathematical tangent of an angle |
0 commit comments