diff --git a/.gitbook/assets/comp.gif b/.gitbook/assets/comp.gif new file mode 100644 index 0000000..ebf41ac Binary files /dev/null and b/.gitbook/assets/comp.gif differ diff --git a/.gitbook/assets/cylvector.gif b/.gitbook/assets/cylvector.gif new file mode 100644 index 0000000..839d68a Binary files /dev/null and b/.gitbook/assets/cylvector.gif differ diff --git a/.gitbook/assets/image (2).png b/.gitbook/assets/image (2).png new file mode 100644 index 0000000..95f6354 Binary files /dev/null and b/.gitbook/assets/image (2).png differ diff --git a/.gitbook/assets/lenandxyz.gif b/.gitbook/assets/lenandxyz.gif new file mode 100644 index 0000000..f16cbd0 Binary files /dev/null and b/.gitbook/assets/lenandxyz.gif differ diff --git a/.gitbook/assets/straightup.png b/.gitbook/assets/straightup.png new file mode 100644 index 0000000..3030975 Binary files /dev/null and b/.gitbook/assets/straightup.png differ diff --git a/.gitbook/assets/vectoryawandpitch.gif b/.gitbook/assets/vectoryawandpitch.gif new file mode 100644 index 0000000..ce5610c Binary files /dev/null and b/.gitbook/assets/vectoryawandpitch.gif differ diff --git a/.gitbook/assets/yawpitch.png b/.gitbook/assets/yawpitch.png new file mode 100644 index 0000000..9b441e7 Binary files /dev/null and b/.gitbook/assets/yawpitch.png differ diff --git a/README.md b/README.md index c1903db..b680597 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,3 @@ ---- -description: An entry point to Skript. ---- - # Introduction ### Welcome! @@ -13,7 +9,7 @@ We'll walk you through writing your first script, and hopefully get you more con For those of you who are already familiar with Skript, go ahead and use the navigation table on the left to jump to what you're interested in. If you're interested in helping out, the github repo is linked on the right. Pull requests are welcome! {% hint style="warning" %} -**Note:** These tutorials are for the current version of the SkriptLang Skript fork (2.7.0) and are not guaranteed to be correct for other versions or forks. This site does not include any tutorials for addons, either. +**Note:** These tutorials are for the current version of the SkriptLang Skript fork (2.13.X) and are not guaranteed to be correct for other versions or forks. This site does not include any tutorials for addons, either. {% endhint %} ## Installation @@ -23,10 +19,10 @@ Installing Skript is no different from any other plugin. You download the latest {% hint style="warning" %} You should ensure your server meets the requirements for running Skript: -* A Spigot, Paper, or Paper fork server jar. Spigot is the absolute minimum and Skript includes some features that are only accessible when using Paper or a fork of Paper. -* Minecraft Version. Skript 2.7 works for versions 1.13+. - * 1.8 support can be found [here](https://github.com/Matocolotoe/Skript-1.8/releases), but is not official, nor recommended, nor guaranteed to work. - * 1.9-1.12 support is limited to old versions of Skript that do not receive updates (2.6.4) +* A Paper or Paper fork server jar. 2.13 requires Paper, though 2.12 and below can be run with Spigot at the cost of losing some features. +* Java 17 or higher +* Minecraft Version. Skript 2.13 works for versions 1.20.4+. + * For 1.19.4+, use Skript 2.12.2. {% endhint %} After you've downloaded the jar file, put it in your `plugins` folder in your server directory. Restart the server and Skript should generate the folder `plugins/Skript`. diff --git a/SUMMARY.md b/SUMMARY.md index 9156f85..2c26875 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -16,11 +16,7 @@ * [Global and Local](core-concepts/variables/global-and-local.md) * [List Basics](core-concepts/variables/list-basics.md) * [Options and the Variables Section](core-concepts/variables/options-and-the-variables-section.md) - * [Memory Variables, Metadata, and Alternatives](core-concepts/variables/memory-variables-metadata-and-alternatives.md) -* [Lists](core-concepts/lists/README.md) - * [Filters](core-concepts/lists/filters.md) - * [Index Serialization](core-concepts/lists/indices-and-values.md) -* [Text?](core-concepts/text.md) + * [Metadata and Alternatives](core-concepts/variables/memory-variables-metadata-and-alternatives.md) * [Custom Commands](core-concepts/commands.md) * [Vectors](core-concepts/vectors/README.md) * [Vectors in Skript](core-concepts/vectors/vectors-in-skript/README.md) @@ -30,6 +26,10 @@ ## Unfinished +* [Text?](unfinished/text.md) +* [Lists](unfinished/lists/README.md) + * [Filters](unfinished/lists/filters.md) + * [Index Serialization](unfinished/lists/indices-and-values.md) * [Syntax Types](syntax-types/README.md) * [Reading Syntax](syntax-types/reading-syntax.md) * [Events](syntax-types/events.md) diff --git a/core-concepts/indentation/README.md b/core-concepts/indentation/README.md index f49001f..a17445b 100644 --- a/core-concepts/indentation/README.md +++ b/core-concepts/indentation/README.md @@ -4,12 +4,81 @@ description: In Progress # Indentation and Program Flow -show examples for commands, for events, ifs, loops, sections +Like any programming language, Skript needs some way of recognizing when code is meant to be 'within' other code, like what code a command should run, or what code should be run if an if statement succeeds. Many languages solve this with brackets, like `{}` or `()`. Skript, like Python, decides to solve this with indentation to keep the code you write cleaner and less cluttered. -Explain the exact situations in which indentation is used (sections, triggers, etc) +Indentation is a catch-all term for how far from the left margin your text starts. In Skript, we achieve this with either spaces or tabs, like so: -## Basic rules of Indentation +``` +I'm not indented. + I've been indented by 1 tab. + Only used two spaces were used for me. + A whole ten spaces were used to indent me! +``` -### For Commands and Events +## Basic rules of indentation -### In Ifs, Loops, and Sections +Skript requires that for each structure you create (ie: an event, a command, a function), you stick to a consistent pattern of indentation. This means every line in that structure has to follow the same rules. If the first line uses 2 spaces for a single level of indentation, the next line can't use a tab, or 3 spaces. Apart from that, though, you can choose whatever amount of spaces OR tabs (not both!) that you want. + +``` +# valid indentation: +Not indented + Indented by one tab + Indented by two tabs! + +# valid indentation: +Not indented + Indented by three spaces + Indented by six spaces + +# invalid indentation +Not indented + Indented by one tab + Indented by a tab and two spaces (BAD) +``` + +The standard practice is to use 2 spaces, 4 spaces, or 1 tab as your indentation. Editors like VSCode have tools to automatically indent or convert indentation for you if you have issues. + +### When to indent? + +Indentation is required whenever you want code to fall under the control of something else. Let's say you have an event, `on chat`, that you want to run code inside of. You write the event itself with no indentation, but any code inside of it has to follow with a layer of indentation: + +```applescript +on chat: + # indent your code by one layer + set message to ">> %message% <<" +``` + +For commands it's much the same, but we have the first level taken up by the entries like aliases, cooldown, description, and the trigger. So we have to indent a second time below the trigger to tell Skript that we want the code to be attached to the trigger, specifically. + +```applescript +command /test: + # the entries are indented once + aliases: t + description: a test command + trigger: + # but then our code is indented a second time to put it under the trigger. + broadcast "test" +``` + +This follows suit for things like loops, if statements, spawn sections, anything that can have code "inside" it: + +```applescript +on join: + # indent to put code in the event + set {_uuid} to player's uuid + if {banned::%{_uuid}%} is set: + # indent a second time to put code in the if statement + kick player + # go back to one level of indentation to show that this code isn't in the if statement + loop all players: + # indent again to enter the loop + if {quiet-mode::%loop-player's uuid%} is set: + # indent again to enter the if + continue + # go back one to exit the if statement + send "%player% has joined." to loop-player + # go back one to exit the loop + set {last-seen::%player's uuid%} to now +``` + +If you're ever uncertain, **a good rule of thumb is to indent one more time whenever you end a line with a colon** (`:`). diff --git a/core-concepts/indentation/conditionals.md b/core-concepts/indentation/conditionals.md index cbc906e..eaedcd9 100644 --- a/core-concepts/indentation/conditionals.md +++ b/core-concepts/indentation/conditionals.md @@ -158,7 +158,42 @@ Keep note that there is no `else if` or `else` options with this method. ## If Any and If All -new 2.7 shit +So what happens if you want to check a bunch of conditions? While you *can* use Inline Ifs or create a huge indentation pyramids, there is a much better way. Skript's `if any` and `if all` statements allow for multiple conditions in *the same condition*. This is super useful when you have tons of conditions like so: + +```applescript +if: + player's gamemode is survival + player is swimming + player is wearing a turtle helmet + player is holding a trident + player's tool is enchanted with riptide + name of player is "Aquaman" +then: + send "You passed all the conditions!" to player +else: + send "You didn't meet all the conditions! to player +``` + +{% hint style="info" %} +Notice the `else` statement! These multi-conditions can include `else if` and `else` statements inside of them! +{% endhint %} + +This works well because we can check multiple conditions without losing code quality. But what if we only need a single condition to be met out of many? For example, what if we want **both** admins and builders to have build permission? In that case, we can use `if any` like this: + +```applescript +on block place: + if any: + player is op + player's gamemode is creative + name of player is "BobTheBuilder" + then: + send "You placed a block!" to player + else: + send "You don't have permission to place blocks!" to player + cancel event +``` + +When **at least** one condition is met, the player will be able to place the block. However, if none of the conditions are met, the event will be cancelled. ## Ternary Operators diff --git a/core-concepts/indentation/functions.md b/core-concepts/indentation/functions.md index ceb7b65..0d3e03e 100644 --- a/core-concepts/indentation/functions.md +++ b/core-concepts/indentation/functions.md @@ -118,7 +118,7 @@ We've looked at functions as ways to simply run code, but one of the most powerf on join: give player customItem((name of player), golden apple) -function customItem(name: string, base-item: item) :: item: +function customItem(name: string, base-item: item) returns item: set {_item} to {_base-item} named {_name} set lore of {_item} to "&fWelcome back!" return {_item} @@ -128,7 +128,7 @@ This would give a golden apple with the player's name and some custom lore to an There's a few things to pay attention too. First, notice that now we're putting the function call in the `give` effect. It's no longer on its own line. This means we're using it as an `expression`, not an `effect`. Functions are one of, if not the only, syntax in Skript with this property. -Secondly, notice how the function definition has changed. We now have this `:: type:` bit on the end, which tells Skript what type the function is going to return. Again, if you make this plural you can return a list. +Secondly, notice how the function definition has changed. We now have this `returns type` bit on the end, which tells Skript what type the function is going to return. Again, if you make this plural you can return a list. Finally, notice the new syntax at the end of the function: `return {_item}`. This is how we tell the function what value it should return. In this case, it's `{_item}`. Return will also stop execution of the function there, like `stop` does. @@ -179,15 +179,15 @@ When a player quits, the `quit` event in `script-2.sk` runs. This can't see the Now that we've explained all the parts, let's show the whole function at once: ```applescript -[local] function functionName(parameterName: parameterType = defaultValue) :: returnType: +[local] function functionName(paramName: paramType = defaultValue) returns returnType: ``` Hopefully by now you know all these parts, but let's recap: * **\[local]**: Whether this function is local or global. (global is default) * **functionName:** the name of the function, starts with a letter and can use letters, numbers, and underscores -* **parameterName:** Optional. The name of the parameter, follows the same rules as variable names. Will be accessible as a local variable of the same name in the function. - * **parameterType:** Required if you have a parameter. Tells Skript what type the parameter will be. Use `object` if you're unsure. +* **paramName:** Optional. The name of the parameter, follows the same rules as variable names. Will be accessible as a local variable of the same name in the function. + * **paramType:** Required if you have a parameter. Tells Skript what type the parameter will be. Use `object` if you're unsure. * **defaultValue:** Optional. Allows the function calls to omit this parameter, and Skript will automatically use this value instead. * **returnType:** Optional, only use if you intend to return something. Again, use `object` if you're unsure. Remember, functions that return values can't use `wait`. diff --git a/core-concepts/indentation/loops.md b/core-concepts/indentation/loops.md index 1db9e0d..09f5a6b 100644 --- a/core-concepts/indentation/loops.md +++ b/core-concepts/indentation/loops.md @@ -1,23 +1,248 @@ ---- -description: In Progress ---- - # Loops +Loops are fantastic tools for anyone to have in their skill set. Loops allow you to repeat code, create countdowns, draw things, look for certain entities or items, and much more. They, along with conditionals, are your bread and butter for controlling how your program flows. + +In essence, loops repeat code. They have a block of code inside them and they run it, and then run it again, and again, until they're done with their job. The details about how many times they run it (and what changes between each iteration) depend on the type of the loop. + ## Types of Loops -Loop x times, loop lists, while loops +Skript, like most languages, has two main types of loops: _for_ loops and _while_ loops. Each has their own use case. + +### For Loops + +For loops are often just called "loops", but I'll be calling them for loops to ensure no one gets them confused with while loops. They look like this: + +``` +loop something: + # do something +``` + +The _something_ will be some sort of list. It could be `integers from 0 to 4`, or `all players`, or even `blocks in radius 10 of player`. There's even a special expression intended to be used in loops: `x times`. This will loop the numbers from 1 to x, or in the following example, 1 to 3. + +``` +loop 3 times: + broadcast "loop!" +``` + +Loops will run the code inside them once per item in their list. So for `3 times`, which has `1, 2, 3`, it'll run the code 3 times. + +However, it'd be really nice if we could, say, access what number it's currently on. This is where `loop-value` comes in. When you're looping something, you can get the current thing (number, player, whatever) by using `loop-value`. + +``` +loop all players: + send "hey!" to loop-value +``` + +{% hint style="info" %} +If you're looping a specific expression, like `all players`, you can use `loop-type` as another version: + +``` +loop all players: + send "hey!" to loop-player +``` +{% endhint %} + +#### Looping Over Lists + +Loops go hand in hand with lists, as every loop needs a list of something to loop over. The `%number% times` expression actually creates a list of numbers, so `set {_x::*} to 3 times` is equivalent to `set {_x::*} to 1, 2, and 3`. Use this knowledge wisely. + +This means that variable lists can also be looped, and they come with some special features. + +```applescript +set {_my-list::1} to "hey" +set {_my-list::2} to "how" +set {_my-list::are} to "you" -### X Times +loop {_my-list::*}: + broadcast "%loop-index%: %loop-value%" + # this prints the following: + # 1: hey + # 2: how + # are: you +``` -### Looping Lists +Really, just one special feature, which is `loop-index`. This lets you access the index of the current element of the list, just like how `loop-value` gives you the value. ### While Loops +While loops are the for loop's more temperamental cousin. They keep looping as long as a condition is true, which makes them great for repeating things over time, doing a specific action a dynamic number of times, or crashing your server. + +{% hint style="danger" %} +Since while loops will not stop until the condition fails, they can run infinitely, potentially crashing your server. Make sure your while loop **will always exit** **or add a wait to it.** Adding a wait stops the while loop until the delay is done, allowing your server to actually run. + +```applescript +# crashes your server +while true is true: + send "hi" + +# doesn't crash +while {_i} < 100: + add 1 to {_i} + +# doesn't crash +while true is true: + send "hi" + wait 1 tick +``` +{% endhint %} + +While loops are most often used to do periodic work while a condition is true, say, to do something every 5 ticks while a player is online. However, you do need to be careful that you can stop a while loop at will, since **reloading a script will not stop a running while loop**. + +{% hint style="warning" %} +While loops will not stop when you reload the script that they are in. They will doggedly run until their condition is no longer true. This is a good reason to either use a periodical event (when appropriate) or to add a special case to abort a loop. + +```applescript +while player is connected: + send "hi" + if {abort-while-loop} is true: + set {abort-while-loop} to false + exit loop + wait 10 seconds + +... + +command abort-loop: + trigger: + set {abort-while-loop} to true +``` +{% endhint %} + +### Do While + +Like while loops, but they check the condition at the end of the loop, rather than the start: + +```applescript +# bad, normal while loop +add 1 to {_test} +while {check::%{_test}%} is set: + add 1 to {_test} + +# cool, epic do while loop +do while {check::%{_test}%} is set: + add 1 to {_test} +``` + ## Loop-specific Syntax -continue, exit loop +As briefly referenced in the while loop section, loops have special syntaxes that can be used to control them. These syntaxes are critical to making efficient and readable code with loops. These come in two main categories, the information syntaxes and the control syntaxes. + +### Informational + +`loop-value` and `loop-index` give you information on what's currently being looped. `loop-value` is the value, and will always be present. `loop-index` is only available when looping variable lists, and gives the index of the element in the list. As previously mentioned, you can also use `loop-%type%` when looping specific types, like `loop-number` when looping `integers between 0 and 10`. + +```applescript +set {_my-list::1} to "hey" +set {_my-list::2} to "how" +set {_my-list::are} to "you" + +loop {_my-list::*}: + broadcast "%loop-index%: %loop-value%" + # this prints the following: + # 1: hey + # 2: how + # are: you +``` + +`loop-iteration` is useful for keeping track of what loop you're on. This can also be accessed with `loop-counter`. + +```applescript +# loop the first 25 elements of {_list::*} +loop {_list::*}: + if loop-iteration > 25: + stop +``` + +### Control + +`continue` is for when you want to skip the rest of the loop and _continue_ to the next element. + +```applescript +# broadcast the square of all even numbers between 1 and arg 1: +loop integers between 1 and arg 1: + # skip odd numbers + # (mod() gives the remainder, so dividing odd numbers by 2 gives a remainder of 1) + if mod(loop-number, 2) = 1: + continue + + broadcast loop-number * loop-number +``` + +`exit loop` is for, well, exiting loops. This is useful for preventing runaway while loops, as we've seen earlier, or just exiting once you find what you need. + +```applescript +# searching for {_needle} in {_haystack::*}: +loop {_haystack::*}: + if loop-value is {_needle}: + set {_index} to loop-index + exit loop # exit early, since the rest of the list doesn't matter. +broadcast "Found needle at %{_index}%!" +``` ## When to Use Loops -while loops compared to periodicals +{% hint style="info" %} +This is a more of the in-the-weeds performance comparison, so if you're just here to learn about loops, you can skip this. +{% endhint %} + +Often, people will compare the performance of these two patterns: + +```applescript +every 10 ticks: + loop all players: + # do something + +on join: + while player is connected: + # do something + wait 10 ticks +``` + +Before you keep reading, try to think about what the actual difference here is! + +I'll wait. + +Don't worry, I'll still be here. + +Alright. + +So, behind the scenes, there's a thing called a Scheduler. This is in charge of scheduling when things run on your server. When we make an `every x` periodical event, Skript tells the scheduler to run this thing every x time. This is pretty simple and straightforward, which means it's very easy for Skript to come back later and tell the scheduler to stop running it. The scheduler just gives Skript a number to call if it wants the task ended. + +The downside here is that it runs the `do something` for every player, all at once. If you have a lot of players, or a lot of work to do per player, this can sometimes result in small lag spikes every time the code runs. + +While loops, meanwhile, are a bit more complicated. Skript has to run the code within the loop to determine what the next behavior is, so when it hits the `wait 10 ticks`, it tells the scheduler "hey, can you restart this code in 10 ticks?" and the scheduler does just that. The downside, though, is that Skript doesn't really have control over the code anymore. Since every single iteration of the loop creates a new scheduled task, Skript doesn't know what number to call to stop the loop. This means that the while loop itself is the only thing that can stop it, which it does by failing the condition and not running the code inside itself, therefore not running the `wait`. **All this to say, `/sk reload` will not stop while loops.** + +However, it also comes with some benefits. Since players don't usually all join at the exact same time, the while loops running for each individual player are going to trigger at slightly different times. This helps solve our problem with `every x`, where we were getting lag spikes. + +
+ +{% hint style="info" %} +Note that we didn't change the amount of work that we were doing, we just spread that work out over multiple ticks. +{% endhint %} + +This means the `on join, while online` pattern is good for spreading work out, but comes with the downsides of a) not stopping with a reload, and b) potentially starting multiple loops for one player if you're not careful. + +It also means that for short waits, like 1 to 5 ticks, the benefits of spreading work out will be very small, and a periodical event will be your better bet. While loops also can't address sustained lag, only lag spikes. + +{% hint style="info" %} +TL/DR: + +**every x, loop all players:** + +* simple to set up +* safe +* reload-friendly +* can cause lag spikes if the work done is too much to do in one tick + +**on join, while online:** + +* can spread work over multiple ticks if the delay is long enough ( >5 ticks) +* not reload-friendly +* needs extra work to make safe (prevent multiple loops from running at once for one player) + +**conclusion:** + +prefer using `every x, loop all players` when you are working with fast timings or smaller amounts of work. + +prefer `on join, while online` when you are working with slower timings or larger amounts of work (updating scoreboards is a good example, you only need to do this at most once a second.) +{% endhint %} + diff --git a/core-concepts/variables/README.md b/core-concepts/variables/README.md index e55413b..3189415 100644 --- a/core-concepts/variables/README.md +++ b/core-concepts/variables/README.md @@ -90,7 +90,7 @@ So we make sure to surround it with `%`, so that Skript know it's an expression, ``` {% endhint %} -Now each player has a unique home variable that we can get using their uuid. Note the use of `::` in the variable name. This is used to create list variables, which are explained [here](list-basics.md), with a more in- depth explanation [here](../lists/). The main thing to understand is that using `::` means we have much more power over the variable. We can delete all homes at once, we can easily see all the homes that are set, and much more. +Now each player has a unique home variable that we can get using their uuid. Note the use of `::` in the variable name. This is used to create list variables, which are explained [here](list-basics.md), with a more in- depth explanation [here](../../unfinished/lists/). The main thing to understand is that using `::` means we have much more power over the variable. We can delete all homes at once, we can easily see all the homes that are set, and much more. ```applescript # clear all homes diff --git a/core-concepts/variables/global-and-local.md b/core-concepts/variables/global-and-local.md index 313108e..0ee9b9d 100644 --- a/core-concepts/variables/global-and-local.md +++ b/core-concepts/variables/global-and-local.md @@ -89,8 +89,22 @@ set {variable::%player's uuid%} to "hello!" ``` {% endhint %} +#### Ephemeral Variables + +Ephemeral variables, (or memory/RAM/temporary vars) are very easy to wrap your head around. Simply, they're just global variables with one difference. They don't get saved when the server stops. This means, of course, you don't get to save data over long-term, but you still get the benefits of the global scope. Plus, since they're not saved, they're also a lot gentler on the server. + +These are extremely useful for when you need to transfer information between triggers or over time, but you don't really need to keep it around for the long term. + +{% hint style="info" %} + Whenever you're using global variables, ask yourself if you really need to save this information over restarts. If you don't, try using an ephemeral variable. +{% endhint %} + +Ephemeral variables are any variable that starts with `-`: `{-test}`, `{-my::list::of::numbers::*}`, or `{-a very long name}`. Like local variables, they aren't saved over restarts, which means they are also roughly twice as fast as using a standard global variable. + ### When to Use Global vs Local Let's summarize. Local variables are great at storing data that we only need for a short time, in a specific place. We don't have to worry about using unique names, or resetting it to some starting value, or anything like that. **Local variables should be used whenever possible.** -Global variables are great for storing data in the long term, like over server restarts. They're also great for allowing us to access data from wherever. We can set the variable in one command and access it in a completely different event, even in a different file. **Global variables should be used when needed, either for long-term storage or for communication across various parts of a script or throughout time.** +Global variables are great for storing data in the long term, like over server restarts. They're also great for allowing us to access data from wherever. We can set the variable in one command and access it in a completely different event, even in a different file. **Global variables should be used for long-term storage across restarts.** + +Ephemeral variables are global, but aren't stored over restarts. **Use ephemeral variables for communication across various parts of a script or throughout time, where long-term saving isn't necessary.** diff --git a/core-concepts/variables/list-basics.md b/core-concepts/variables/list-basics.md index 5a6a7b5..571af5f 100644 --- a/core-concepts/variables/list-basics.md +++ b/core-concepts/variables/list-basics.md @@ -89,7 +89,7 @@ if {_list::*} contains "hello": We can also loop lists, which opens up even more possibilities: ```applescript -set {list::*} to "hey", "how", "are", "you" and 55 +set {_list::*} to "hey", "how", "are", "you" and 55 loop {_list::*}: send "%loop-index% - %loop-value%" to player ``` @@ -104,4 +104,4 @@ In this code, we loop through a list, sending the index and the value each time. 5 - 55 ``` -This can be really useful for things like leaderboards, for knowing what elements exist in your list, and much more. If you want to see some more advanced uses of lists, ways to best optimize them, as well as some of the quirks and trickier aspects of using them, check out the [Lists page](../lists/). +This can be really useful for things like leaderboards, for knowing what elements exist in your list, and much more. If you want to see some more advanced uses of lists, ways to best optimize them, as well as some of the quirks and trickier aspects of using them, check out the [Lists page](../../unfinished/lists/). diff --git a/core-concepts/variables/memory-variables-metadata-and-alternatives.md b/core-concepts/variables/memory-variables-metadata-and-alternatives.md index 90fbd2a..30c3989 100644 --- a/core-concepts/variables/memory-variables-metadata-and-alternatives.md +++ b/core-concepts/variables/memory-variables-metadata-and-alternatives.md @@ -1,54 +1,6 @@ -# Memory Variables, Metadata, and Alternatives +# Metadata and Alternatives -While our standard global and local variables are versatile tools and are perfectly capable on their own, there are situations where we may want to consider different ways of storing information. We have plenty of options, especially if we include addons, but I want to focus on a few main ones. Namely, Memory (or Ram) Variables and Metadata. - -## Memory Variables - -Memory variables are very easy to wrap your head around. Simply, they're just global variables with one difference. They don't get saved when the server stops. This means, of course, you don't get to save data over long-term, but you still get the benefits of the global scope. Plus, since they're not saved, they're also a lot gentler on the server. - -These are extremely useful for when you need to transfer information between triggers or over time, but you don't really need to keep it around for the long term. - -{% hint style="info" %} - Whenever you're using global variables, ask yourself if you really need to save this information over restarts. If you don't, try using a memory variable. -{% endhint %} - -Now, I haven't explained how to actually write a memory variable yet, and this is because it's not a default part of Skript. You have to specifically enable them in your `config.sk` file, and they can take whatever form you give them. The general convention is to make all variables that start with `-` memory variables, eg: `{-variable}, {-list::*}`. You can do this by opening your `config.sk` file and scrolling down to line 310 or so, where you should see the following: - -```yaml -default: - # The default "database" is a simple text file, with each variable on a separate line and the variable's name, type, and value separated by commas. - # This is the last database in this list to catch all variables that have not been saved anywhere else. - # You can modify this database freely, but make sure to know what you're doing if you don't want to loose any variables. - - type: CSV - - pattern: .* - - file: ./plugins/Skript/variables.csv - - backup interval: 2 hours - - # PS: If you don't want some variables to be saved in any database (e.g. variables that contain an %entity% which usually despawn when the server is shut down) - # you can modify the last database's pattern to not match all variables, e.g. use '(?!x_).*' to match all variables that don't start with 'x_'. - # Be very cautious when doing this however as unsaved variables cannot be recovered after the server has been stopped. - # I recommend to use a single character to denote unsaved variables (similar to local variables' '_'), e.g. '-', in which case the last database's pattern should be '(?!-).*'. -``` - -The last four lines of comments describe how to enable memory variables. In simple terms, you just replace the `pattern:` line with a new regex pattern, one that excludes variables that start with `-`. As you can see in the comments, this pattern is `(?!-).*`. - -Your edited config should look like this: - -```json - type: CSV - - pattern: (?!-).* - - file: ./plugins/Skript/variables.csv - - backup interval: 2 hours -``` - -However, know that you can set this pattern to whatever you want, which also means your memory variables can follow whatever format you want as long as you set the pattern up properly. I advise sticking with convention and using `-`. +While our standard global and local variables are versatile tools and are perfectly capable on their own, there are situations where we may want to consider different ways of storing information. We have plenty of options, especially if we include addons, but I want to focus on a few main ones. Namely, metadata. ## Metadata @@ -91,6 +43,6 @@ There are many other ways to deal with information and data in Skript. Addons al That said, here are some general rules: * Try to store the least amount of data possible for the long term. No matter your storage solution, it'll always be faster and easier if you store less information. - * In this vein, try to make use of temporary structures like local variables, metadata, or memory variables. -* When you're using a relatively slow method of storing data (databases, reading/writing files, etc), try to load all the relevant information **only when you need it**. When a player joins, for example, try to copy all their information from your long-term solution into a temporary, fast format like memory variables. Then, when they leave, write the updated information back to the slower, long-term storage. + * In this vein, try to make use of temporary structures like local variables, metadata, or ephemeral variables. +* When you're using a relatively slow method of storing data (databases, reading/writing files, etc), try to load all the relevant information **only when you need it**. When a player joins, for example, try to copy all their information from your long-term solution into a temporary, fast format like ephemeral variables. Then, when they leave, write the updated information back to the slower, long-term storage. * Prioritize usability and readability over performance. If a high-performance solution makes your code a nightmare to read and maintain, consider not making that sacrifice. Losing a few milliseconds per tick is not worth it if it saves you hours of extra work in the future when you need to modify your code. diff --git a/core-concepts/vectors/README.md b/core-concepts/vectors/README.md index c733fe4..3afe773 100644 --- a/core-concepts/vectors/README.md +++ b/core-concepts/vectors/README.md @@ -11,7 +11,7 @@ They can be a bit tricky to wrap your head around, so we'll start small and buil {% hint style="danger" %} **We highly recommend not skipping sections of this tutorial.** - Terms and concepts tend to build off of previous ones, and if you skip ahead you may find yourself a little lost and confused. +Terms and concepts tend to build off of previous ones, and if you skip ahead you may find yourself a little lost and confused. That said, if you understand the basics of what a vector is, feel free to skip to [Vectors in Skript](vectors-in-skript/). {% endhint %} @@ -24,7 +24,7 @@ That said, if you understand the basics of what a vector is, feel free to skip t A vector is a quantity with a magnitude and a direction. {% endhint %} - Doesn't that clear everything up? +Doesn't that clear everything up? While at first that definition feels vague and unhelpful, that's because the concept of a vector is very broad and can be used in many ways. We need to narrow our definition a bit in order to get something that's useful to use. @@ -76,7 +76,7 @@ Now things get a bit more interesting. With two dimensions, we have a whole plan

A 2D plane with some basic vectors

-Essentially, we now have 2 number lines, one horizontal and one vertical, and we can draw 1 dimensional vectors along both. Unfortunately, we now have to distinguish between horizontal and vertical. +Essentially, we now have 2 number lines, one horizontal and one vertical, and we can draw 1 dimensional vectors along both. Unfortunately, we now have to distinguish between horizontal and vertical. As I'm sure most of you know, we generally consider the horizontal axis to be the x-axis and the vertical one to be the y-axis, so we can say the green vector travels 5 units in the positive x direction and 0 units in the y direction, which we'll denote as `(5, 0)`. Likewise, the blue and red vectors would be `(0, 3)` and `(0, -4)` respectively. @@ -115,10 +115,10 @@ sqrt( 3^2 + 4^2 ) = sqrt( 25 ) = 5 ``` {% hint style="info" %} - This is also called the "distance formula", and will show up again in 3D. +This is also called the "distance formula", and will show up again in 3D. {% endhint %} -Direction is more complicated. I won't get into the math here, but it involves trigonometry. Basically, we'll use a compass to guide us. Pointing right (+x) will be 0 degrees, up (+y) is 90, left is 180, and down is 270, or -90. +Direction is more complicated. I won't get into the math here, but it involves trigonometry. Basically, we'll use a compass to guide us. Pointing right (+x) will be 0 degrees, up (+y) is 90, left is 180, and down is 270, or -90. Our green vector is 0 degrees, the red vector is 90, and our blue vector is a very nice 53.13 degrees. @@ -139,7 +139,7 @@ In 2D, there are now two ways to write a vector: Finally, to the good stuff! As I'm sure you have guessed by now, all we have to do to go from 2D to 3D is add a third number line, which will be called Z. Now, our vectors will look like `(x, y, z)` which I'm certain is familiar to anyone who has played Minecraft. -![A vector being created from separate components (Credit: ThatOneWizard)](../../media/vectors/comp.gif) +![A vector being created from separate components (Credit: ThatOneWizard)](../../.gitbook/assets/comp.gif) Computing length, like in 2D, involves the distance formula: @@ -147,17 +147,17 @@ Computing length, like in 2D, involves the distance formula: sqrt( x^2 + y^2 + z^2 ) = length ``` -![A gif showing the behavior of XYZ components being changed](../../media/vectors/lenandxyz.gif) +![A gif showing the behavior of XYZ components being changed](../../.gitbook/assets/lenandxyz.gif) In the above gif, you can see how the changes to the X, Y, and Z components of a vector affect its length. You can also see the direction changing, but like in 2D, it's pretty tricky to calculate. Since this is a Skript tutorial, and Skript does the math for you behind the scenes, we'll skip it like we did for 2D. ### Yaw and Pitch -Calculation aside, we need some way to describe the direction a vector points in. We can start with our compass idea from back in 2D. In general, this "compass" is called the **yaw**. It tells you the horizontal direction the vector is pointing. But for 3D, we need vertical direction too. +Calculation aside, we need some way to describe the direction a vector points in. We can start with our compass idea from back in 2D. In general, this "compass" is called the **yaw**. It tells you the horizontal direction the vector is pointing. But for 3D, we need vertical direction too. -This is where **pitch** comes in. This is the same idea, but it's the angle for how far up/down the vector is pointing. You can see a diagram below, where yaw is blue and pitch is pink. +This is where **pitch** comes in. This is the same idea, but it's the angle for how far up/down the vector is pointing. You can see a diagram below, where yaw is blue and pitch is pink. -![An image showing a sphere outlining the difference between yaw and pitch](../../media/vectors/yawpitch.png) +![An image showing a sphere outlining the difference between yaw and pitch](../../.gitbook/assets/yawpitch.png) You can view your own yaw and pitch in Minecraft via the F3 menu. Try looking around and seeing how the numbers change. @@ -166,11 +166,11 @@ Yaw and pitch let us describe a 3D vector. We still use length and yaw just like ``` In XYZ: (3, -2, 1) -Length: sqrt( 9 + 4 + 1 ) = sqrt( 13 ) = 3.61 +Length: sqrt( 9 + 4 + 1 ) = sqrt( 14 ) = 3.74 Yaw: 288.4 degrees Pitch: 32.3 degrees -(3.61, ∠288.4, ∠32.3) +(3.74, ∠288.4, ∠32.3) ``` And remember, everything that worked for 1D and 2D still works here. We can still add, subtract, multiply, and otherwise change our 3D vector in much the same ways. diff --git a/core-concepts/vectors/vectors-in-skript/README.md b/core-concepts/vectors/vectors-in-skript/README.md index 99db1b7..9180992 100644 --- a/core-concepts/vectors/vectors-in-skript/README.md +++ b/core-concepts/vectors/vectors-in-skript/README.md @@ -26,13 +26,13 @@ This is our X, Y, Z form, and it's the easiest to think about to start with. If If you were to visualize the vector `(0, 1, 0)`, it would look something like: -

A vector pointing directly up. (Credit: ThatOneWizard)

+

A vector pointing directly up. (Credit: ThatOneWizard)

The light blue arrow is the vector we just created. It's pointing straight up because we set the X and Z values to 0 and just the Y is 1. In case the concept of looking at vectors from their individual components ( XYZ ) has not quite set in, here's a visualization of how the vector changes based on its components: -

A vector being created from separate components (Credit: ThatOneWizard)

+

A vector being created from separate components (Credit: ThatOneWizard)

The aqua arrow is the resulting vector and the red, green and blue arrows are the XYZ components. @@ -80,7 +80,7 @@ set {_v} to spherical vector radius 2, yaw 22.5, pitch 45 Now with this expression, it includes the term `spherical`, which just describes how the vector is being created, essentially a vector is just being made that goes from the center of a sphere to the outer edge. -![An image showing a sphere representing yaw and pitch](../../../media/vectors/vectoryawandpitch.gif) +![An image showing a sphere representing yaw and pitch](../../../.gitbook/assets/vectoryawandpitch.gif) {% hint style="info" %} You can also create a vector of length 1 using just yaw and pitch: @@ -106,32 +106,26 @@ There are a lot of other ways to get vectors in Skript, but the above three are ## Basic Arithmetic -Just like with normal numbers, you can perform arithmetic ( math ) with vectors just as easily, the only difference is that you need to double the sign, ie `*` becomes `**.` +Just like with normal numbers, you can perform arithmetic ( math ) with vectors just as easily. For the sake of example, we will be using the vector function to define the vectors here, but these could also be variables or other vector expressions like `player's velocity`. ```vb -set {_v} to vector(1, 2, 3) ++ vector(4, 5, 6) +set {_v} to vector(1, 2, 3) + vector(4, 5, 6) # {_v} will be vector(5, 7, 9) -set {_v} to vector(1, 2, 3) -- vector(4, 5, 6) +set {_v} to vector(1, 2, 3) - vector(4, 5, 6) # {_v} will be vector(-3, -3, -3) -set {_v} to vector(1, 2, 3) ** vector(4, 5, 6) +set {_v} to vector(1, 2, 3) * vector(4, 5, 6) # {_v} will be vector(4, 10, 18) -set {_v} to vector(1, 2, 3) // vector(4, 5, 6) +set {_v} to vector(1, 2, 3) / vector(4, 5, 6) # {_v} will be vector(0.25, 0.4, 0.5) ``` -{% hint style="warning" %} -Currently the docs show that you are able to perform arithmetic with a vector and a scalar ( a single number ), which is no longer true. - -If you need to perform such operation, then simply replace the number with a vector where all 3 components are that number. For example, instead of `vector(1, 2, 3) * 5`, you would do `vector(1, 2, 3) ** vector(5, 5, 5)` -{% endhint %} - *** ## Length diff --git a/core-concepts/vectors/vectors-in-skript/other-ways-to-create-vectors.md b/core-concepts/vectors/vectors-in-skript/other-ways-to-create-vectors.md index 1b32522..ec66bdb 100644 --- a/core-concepts/vectors/vectors-in-skript/other-ways-to-create-vectors.md +++ b/core-concepts/vectors/vectors-in-skript/other-ways-to-create-vectors.md @@ -26,7 +26,7 @@ set {_v} to cylindrical vector radius 2, yaw 45, height 5 And if you were to visualize the created vector: -![An image showing a vector being made from the center to the side of a cylinder (Credit: ThatOneWizard)](../../../media/vectors/cylvector.gif) +![An image showing a vector being made from the center to the side of a cylinder (Credit: ThatOneWizard)](../../../.gitbook/assets/cylvector.gif) *** @@ -114,7 +114,7 @@ set {_v1} to vector from location(0, 64, 0) set {_v2} to vector from location(100, 32, -20) -set {_v3} to {_v2} -- {_v1} +set {_v3} to {_v2} - {_v1} ``` @@ -138,7 +138,7 @@ Along with being able to get the velocity of an entity, we are able to modify it ```vb set {_v} to velocity of player -set {_v2} to {_v} ** vector(2, 2, 2) ++ vector(1, 2, -3) +set {_v2} to {_v} * vector(2, 2, 2) + vector(1, 2, -3) set velocity of player to {_v2} ``` @@ -168,7 +168,3 @@ set {_v} to a random vector ``` As expected, every time that code is ran, `{_v}` will be a different vector every time. - -{% hint style="danger" %} -In 2.6.4, this expression isn't fully random. The 3 random numbers have a bias towards pointing to the corners of a cube, like towards 1, 1, 1. This is fixed in 2.7. -{% endhint %} diff --git a/core-concepts/vectors/working-with-vectors.md b/core-concepts/vectors/working-with-vectors.md index 71a6638..136f645 100644 --- a/core-concepts/vectors/working-with-vectors.md +++ b/core-concepts/vectors/working-with-vectors.md @@ -44,6 +44,32 @@ Feel free to try and play around with this expression. For example, try and tele Offsetting is one of the only and most common way of dealing with both locations and vectors. Get used to seeing it a lot. {% endhint %} +## Offsetting in Local Axes + +So far, we've been thinking about vectors using **global axes**, where the X, Y, and Z values are aligned to the Minecraft world, regardless of which way you're facing: X always points East, Y always points up, and Z always points South. To relate this to Minecraft commands, it's like using `/tp @s ~1 ~ ~-5` to teleport yourself. + +But sometimes, you might want to offset something relative to a player, location, or other entity, such as forward, backward, left, right, up or down from the position. This is where **local axes** can be used. + +When you use local axes, the X, Y, and Z of your vector are reinterpreted based on the yaw and pitch of the location. This means X becomes left, Z becomes forwards, and Y becomes upwards, the direction the top of your head points. To return to commands, this is like using `/tp @s ^1 ^ ^-5`. + +Since all locations in Minecraft carry a yaw and pitch, this works for any location. + +| Component | Positive | Negative | +| --------- | -------- | -------- | +| X | Left | Right | +| Y | Up | Down | +| Z | Forward | Back | + +So, a vector of `(0, 1, 5)`, using local axes, means `1 block up, and 5 blocks forward`. + +In Skript, you can apply this by appending `using local axes` to the end of the syntax you've already read about: + +```skript +player's location offset by vector(0, 1, 5) using local axes +``` + +What's great about local axes is that all of the rules & tricks of vectors you've already read about apply exactly the same here, but work locally to a specific location rather than to the world. + ## Practical Example: Particles One of the most common uses of vectors in Skript is to create particle effects. And one of the most useful shapes to create with particles is a line. And it just so happens that vectors are _really_ good at making lines. diff --git a/introduction/the-basics.md b/introduction/the-basics.md index 835c2b1..afdd3d2 100644 --- a/introduction/the-basics.md +++ b/introduction/the-basics.md @@ -1,6 +1,6 @@ # The Basics -This page will walk you through creating your first script. If this is too slow for you, feel free to jump ahead to the [Core Concepts](broken-reference/) section. This is just to get you comfortable with the very basics of Skript. +This page will walk you through creating your first script. If this is too slow for you, feel free to jump ahead to the [Core Concepts](broken-reference) section. This is just to get you comfortable with the very basics of Skript. ### Creating the Script File @@ -106,13 +106,13 @@ Technically, we could just write `send "You received some food!"` and Skript wou Notice that all the text we want to send is surrounded by `"`. Surrounding the text with `"` is important because it tells Skript that the stuff inside isn't code, it's just some text that shouldn't really be bothered with. Text that's just text and isn't part of the actual code is referred to as a `string` in programming terminology. In Skript you'll hear it referred to as `text` and `string` interchangeably. -Note that there are some rules surrounding text that might be confusing at first. If you want to use `"`, `#`, or `%` in a string, you have to type two of them in a row. This is because Skript uses these symbols for important things, and typing two in a row tells Skript to just treat it as one, normal, non-code character. +Note that there are some rules surrounding text that might be confusing at first. If you want to use `"` or `%` in a string, you have to type two of them in a row. This is because Skript uses these symbols for important things, and typing two in a row tells Skript to just treat it as one, normal, non-code character. ```applescript -send "this is a ""test"" of percent signs (%%) and hash tags (##)" to player +send "this is a ""test"" of percent signs (%%)" to player # this sends: -# this is a "test" of percent signs (%) and hash tags (#) +# this is a "test" of percent signs (%) # to the player ``` @@ -126,7 +126,7 @@ send "5 + 10 = %5 + 10%" to player # to the player ``` -You can read more about the things you can and can't do with strings [here](../core-concepts/text.md). +You can read more about the things you can and can't do with strings [here](../unfinished/text.md). {% endhint %} ### If/Else diff --git a/core-concepts/lists/README.md b/unfinished/lists/README.md similarity index 58% rename from core-concepts/lists/README.md rename to unfinished/lists/README.md index b27ea1e..5aa8d69 100644 --- a/core-concepts/lists/README.md +++ b/unfinished/lists/README.md @@ -4,7 +4,7 @@ description: In Progress # Lists -Lists are variables that can store more than one bit of information at a time. If you haven't covered variables yet, or need a refresher, here's [the link](../variables/). Also, if you haven't read [List Basics](../variables/list-basics.md) yet, I highly recommend it. This page with brush over the basics, but **if you're completely new to lists, you should read the List Basics page first.** +Lists are variables that can store more than one bit of information at a time. If you haven't covered variables yet, or need a refresher, here's [the link](../../core-concepts/variables/). Also, if you haven't read [List Basics](../../core-concepts/variables/list-basics.md) yet, I highly recommend it. This page with brush over the basics, but **if you're completely new to lists, you should read the List Basics page first.** ### Basic Overview diff --git a/core-concepts/lists/filters.md b/unfinished/lists/filters.md similarity index 100% rename from core-concepts/lists/filters.md rename to unfinished/lists/filters.md diff --git a/core-concepts/lists/indices-and-values.md b/unfinished/lists/indices-and-values.md similarity index 100% rename from core-concepts/lists/indices-and-values.md rename to unfinished/lists/indices-and-values.md diff --git a/core-concepts/text.md b/unfinished/text.md similarity index 100% rename from core-concepts/text.md rename to unfinished/text.md