Merge branch 'master' into 1.17
This commit is contained in:
commit
91bff6a513
10 files changed
+261
-115
No files matched your search
+28
-10
@@ -151,9 +151,10 @@ have memory and act like objects so to speak. Check `outer(var)` for details.
|
||||
## Code delivery, line indicators
|
||||
|
||||
Note that this should only apply to pasting your code to execute with commandblock. Scarpet recommends placing
|
||||
your code in apps (files with `.sc` extension that can be placed inside "/scripts" folder in the world files and
|
||||
loaded as a scarpet app with command `/script load [app_name]`. Scarpet apps loaded from disk should only
|
||||
contain code, no need to start with "/script run" prefix
|
||||
your code in apps (files with `.sc` extension that can be placed inside `/scripts` folder in the world files
|
||||
or as a globally available app in singleplayer in the `.minecraft/config/carpet/scripts` folder and loaded
|
||||
as a Scarpet app with the command `/script load [app_name]`. Scarpet apps loaded from disk should only
|
||||
contain code, no need to start with `/script run` prefix.
|
||||
|
||||
The following is the code that could be provided in a `foo.sc` app file located in world `/scripts` folder
|
||||
|
||||
@@ -1705,7 +1706,8 @@ Here is the gist of the Minecraft related functions. Otherwise the CarpetScript
|
||||
## App structure
|
||||
|
||||
The main delivery method for scarpet programs into the game is in the form of apps in `*.sc` files located in the world `scripts`
|
||||
folder. When loaded (via `/script load` command, etc.), the game will run the content of the app once, regardless of its scope
|
||||
folder. In singleplayer, you can also save apps in `.minecraft/config/carpet/scripts` for them to be available in any world.
|
||||
When loaded (via `/script load` command, etc.), the game will run the content of the app once, regardless of its scope
|
||||
(more about the app scopes below), without executing of any functions, unless called directly, and with the exception of the
|
||||
`__config()` function, if present, which will be executed once. Loading the app will also bind specific
|
||||
events to the event system (check Events section for details).
|
||||
@@ -1739,7 +1741,7 @@ running anything in the global scope for a `'player'` scoped app is not recommen
|
||||
stay loaded after startup. Otherwise, after reading the app the first time, and fetching the config, server will drop them down.
|
||||
This is to allow to store multiple apps on the server/world and selectively decide which one should be running at
|
||||
startup. WARNING: all apps will run once at startup anyways, so be aware that their actions that are called
|
||||
statically, will be performed once anyways.
|
||||
statically, will be performed once anyways. Only apps present in the world's `scripts` folder will be autoloaded.
|
||||
* `'legacy_command_type_support'` - if `true`, and the app defines the legacy command system via `__command()` function,
|
||||
all parameters of command functions will be interpreted and used using brigadier / vanilla style argument parser and their type
|
||||
will be inferred from their names, otherwise
|
||||
@@ -1904,6 +1906,20 @@ Here is a list of built-in types, with their return value formats, as well as a
|
||||
* `'pos'`: block position as a triple of coordinates. Customized with `'loaded'`, if true requiring the position
|
||||
to be loaded.
|
||||
* `'block'`: a valid block state wrapped in a block value (including block properties and data)
|
||||
* `'blockpredicate`': returns a 4-tuple indicating conditions of a block to match: block name, block tag,
|
||||
map of required state properties, and tag to match. Either block name or block tag are `null` but not both.
|
||||
Property map is always specified, but its empty for no conditions, and matching nbt tag can be `null` indicating
|
||||
no requirements. Technically the 'all-matching' predicate would be `[null, null, {}, null]`, but
|
||||
block name or block tag is always specified. One can use the following routine to match a block agains this predicate:
|
||||
```
|
||||
block_to_match = block(x,y,z);
|
||||
[block_name, block_tag, properties, nbt_tag] = block_predicate;
|
||||
|
||||
(block_name == null || block_name == block_to_match) &&
|
||||
(block_tag == null || block_tags(block_to_match, block_tag)) &&
|
||||
all(properties, block_state(block_to_match, _) == properties:_) &&
|
||||
(!tag || tag_matches(block_data(block_to_match), tag))
|
||||
```
|
||||
* `'teamcolor'`: name of a team, and an integer color value of one of 16 valid team colors.
|
||||
* `'columnpos'`: a pair of x and z coordinates.
|
||||
* `'dimension'`: string representing a valid dimension in the world.
|
||||
@@ -4795,13 +4811,15 @@ to simulate running commands in a different scope.
|
||||
|
||||
# `/script load / unload <app> (global?)`, `/script in <app>` commands
|
||||
|
||||
`load / unload` commands allow for very conventient way of writing your code, providing it to the game and
|
||||
distribute with your worlds without the need of use of commandblocks. Just place your scarpet code in the
|
||||
/scripts folder of your world files and make sure it ends with `.sc` extension. The good thing about editing that
|
||||
code is that you can no only use normal editing without the need of marking of newlines,
|
||||
`load / unload` commands allow for very convenient way of writing your code, providing it to the game and
|
||||
distribute with your worlds without the need of use of commandblocks. Just place your Scarpet code in the
|
||||
`/scripts` folder of your world files and make sure it ends with `.sc` extension. In singleplayer, you can
|
||||
also save your scripts in `.minecraft/config/carpet/scripts` to make them available in any world.
|
||||
|
||||
The good thing about editing that code is that you can not only use normal editing without the need of marking of newlines,
|
||||
but you can also use comments in your code.
|
||||
|
||||
a comment is anything that starts with a double slash, and continues to the end of the line:
|
||||
A comment is anything that starts with a double slash, and continues to the end of the line:
|
||||
|
||||
<pre>
|
||||
foo = 1;
|
||||
|
||||
@@ -6,7 +6,8 @@ Here is the gist of the Minecraft related functions. Otherwise the CarpetScript
|
||||
## App structure
|
||||
|
||||
The main delivery method for scarpet programs into the game is in the form of apps in `*.sc` files located in the world `scripts`
|
||||
folder. When loaded (via `/script load` command, etc.), the game will run the content of the app once, regardless of its scope
|
||||
folder. In singleplayer, you can also save apps in `.minecraft/config/carpet/scripts` for them to be available in any world.
|
||||
When loaded (via `/script load` command, etc.), the game will run the content of the app once, regardless of its scope
|
||||
(more about the app scopes below), without executing of any functions, unless called directly, and with the exception of the
|
||||
`__config()` function, if present, which will be executed once. Loading the app will also bind specific
|
||||
events to the event system (check Events section for details).
|
||||
@@ -40,7 +41,7 @@ running anything in the global scope for a `'player'` scoped app is not recommen
|
||||
stay loaded after startup. Otherwise, after reading the app the first time, and fetching the config, server will drop them down.
|
||||
This is to allow to store multiple apps on the server/world and selectively decide which one should be running at
|
||||
startup. WARNING: all apps will run once at startup anyways, so be aware that their actions that are called
|
||||
statically, will be performed once anyways.
|
||||
statically, will be performed once anyways. Only apps present in the world's `scripts` folder will be autoloaded.
|
||||
* `'legacy_command_type_support'` - if `true`, and the app defines the legacy command system via `__command()` function,
|
||||
all parameters of command functions will be interpreted and used using brigadier / vanilla style argument parser and their type
|
||||
will be inferred from their names, otherwise
|
||||
@@ -205,6 +206,20 @@ Here is a list of built-in types, with their return value formats, as well as a
|
||||
* `'pos'`: block position as a triple of coordinates. Customized with `'loaded'`, if true requiring the position
|
||||
to be loaded.
|
||||
* `'block'`: a valid block state wrapped in a block value (including block properties and data)
|
||||
* `'blockpredicate`': returns a 4-tuple indicating conditions of a block to match: block name, block tag,
|
||||
map of required state properties, and tag to match. Either block name or block tag are `null` but not both.
|
||||
Property map is always specified, but its empty for no conditions, and matching nbt tag can be `null` indicating
|
||||
no requirements. Technically the 'all-matching' predicate would be `[null, null, {}, null]`, but
|
||||
block name or block tag is always specified. One can use the following routine to match a block agains this predicate:
|
||||
```
|
||||
block_to_match = block(x,y,z);
|
||||
[block_name, block_tag, properties, nbt_tag] = block_predicate;
|
||||
|
||||
(block_name == null || block_name == block_to_match) &&
|
||||
(block_tag == null || block_tags(block_to_match, block_tag)) &&
|
||||
all(properties, block_state(block_to_match, _) == properties:_) &&
|
||||
(!tag || tag_matches(block_data(block_to_match), tag))
|
||||
```
|
||||
* `'teamcolor'`: name of a team, and an integer color value of one of 16 valid team colors.
|
||||
* `'columnpos'`: a pair of x and z coordinates.
|
||||
* `'dimension'`: string representing a valid dimension in the world.
|
||||
|
||||
@@ -8,13 +8,15 @@ to simulate running commands in a different scope.
|
||||
|
||||
# `/script load / unload <app> (global?)`, `/script in <app>` commands
|
||||
|
||||
`load / unload` commands allow for very conventient way of writing your code, providing it to the game and
|
||||
distribute with your worlds without the need of use of commandblocks. Just place your scarpet code in the
|
||||
/scripts folder of your world files and make sure it ends with `.sc` extension. The good thing about editing that
|
||||
code is that you can no only use normal editing without the need of marking of newlines,
|
||||
`load / unload` commands allow for very convenient way of writing your code, providing it to the game and
|
||||
distribute with your worlds without the need of use of commandblocks. Just place your Scarpet code in the
|
||||
`/scripts` folder of your world files and make sure it ends with `.sc` extension. In singleplayer, you can
|
||||
also save your scripts in `.minecraft/config/carpet/scripts` to make them available in any world.
|
||||
|
||||
The good thing about editing that code is that you can not only use normal editing without the need of marking of newlines,
|
||||
but you can also use comments in your code.
|
||||
|
||||
a comment is anything that starts with a double slash, and continues to the end of the line:
|
||||
A comment is anything that starts with a double slash, and continues to the end of the line:
|
||||
|
||||
<pre>
|
||||
foo = 1;
|
||||
|
||||
@@ -151,9 +151,10 @@ have memory and act like objects so to speak. Check `outer(var)` for details.
|
||||
## Code delivery, line indicators
|
||||
|
||||
Note that this should only apply to pasting your code to execute with commandblock. Scarpet recommends placing
|
||||
your code in apps (files with `.sc` extension that can be placed inside "/scripts" folder in the world files and
|
||||
loaded as a scarpet app with command `/script load [app_name]`. Scarpet apps loaded from disk should only
|
||||
contain code, no need to start with "/script run" prefix
|
||||
your code in apps (files with `.sc` extension that can be placed inside `/scripts` folder in the world files
|
||||
or as a globally available app in singleplayer in the `.minecraft/config/carpet/scripts` folder and loaded
|
||||
as a Scarpet app with the command `/script load [app_name]`. Scarpet apps loaded from disk should only
|
||||
contain code, no need to start with `/script run` prefix.
|
||||
|
||||
The following is the code that could be provided in a `foo.sc` app file located in world `/scripts` folder
|
||||
|
||||
|
||||
@@ -120,4 +120,10 @@ public class EntityPlayerMPFake extends ServerPlayerEntity
|
||||
this.hungerManager = new HungerManager();
|
||||
kill();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIp()
|
||||
{
|
||||
return "127.0.0.1";
|
||||
}
|
||||
}
|
||||
@@ -16,19 +16,25 @@ import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.WorldSavePath;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -127,20 +133,32 @@ public class CarpetScriptServer
|
||||
|
||||
public Module getModule(String name, boolean allowLibraries)
|
||||
{
|
||||
File folder = server.getSavePath(WorldSavePath.ROOT).resolve("scripts").toFile();
|
||||
File[] listOfFiles = folder.listFiles();
|
||||
if (listOfFiles != null)
|
||||
for (File script : listOfFiles)
|
||||
try {
|
||||
Path folder = server.getSavePath(WorldSavePath.ROOT).resolve("scripts");
|
||||
Files.createDirectories(folder);
|
||||
Optional<Path>
|
||||
scriptPath = Files.walk(folder)
|
||||
.filter(script ->
|
||||
script.getFileName().toString().equalsIgnoreCase(name+".sc") ||
|
||||
(allowLibraries && script.getFileName().toString().equalsIgnoreCase(name+".scl"))
|
||||
).findFirst();
|
||||
if (scriptPath.isPresent())
|
||||
return new FileModule(scriptPath.get());
|
||||
|
||||
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT)
|
||||
{
|
||||
if (script.getName().equalsIgnoreCase(name+".sc"))
|
||||
{
|
||||
return new FileModule(script);
|
||||
}
|
||||
if (allowLibraries && script.getName().equalsIgnoreCase(name+".scl"))
|
||||
{
|
||||
return new FileModule(script);
|
||||
}
|
||||
Path globalFolder = FabricLoader.getInstance().getConfigDir().resolve("carpet/scripts");
|
||||
Files.createDirectories(globalFolder);
|
||||
scriptPath = Files.walk(globalFolder)
|
||||
.filter(script -> script.getFileName().toString().equalsIgnoreCase(name + ".sc") ||
|
||||
(allowLibraries && script.getFileName().toString().equalsIgnoreCase(name + ".scl")))
|
||||
.findFirst();
|
||||
if (scriptPath.isPresent())
|
||||
return new FileModule(scriptPath.get());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
CarpetSettings.LOG.error("Exception while loading the app: ", e);
|
||||
}
|
||||
for (Module moduleData : bundledModuleData)
|
||||
{
|
||||
if (moduleData.getName().equalsIgnoreCase(name) && (allowLibraries || !moduleData.isLibrary()))
|
||||
@@ -173,17 +191,23 @@ public class CarpetScriptServer
|
||||
if (!mi.isLibrary() && !mi.getName().endsWith("_beta")) moduleNames.add(mi.getName());
|
||||
}
|
||||
}
|
||||
File folder = server.getSavePath(WorldSavePath.ROOT).resolve("scripts").toFile();
|
||||
File[] listOfFiles = folder.listFiles();
|
||||
if (listOfFiles == null)
|
||||
return moduleNames;
|
||||
for (File script : listOfFiles)
|
||||
{
|
||||
if (script.getName().endsWith(".sc"))
|
||||
try {
|
||||
Path worldScripts = server.getSavePath(WorldSavePath.ROOT).resolve("scripts");
|
||||
Files.createDirectories(worldScripts);
|
||||
Files.walk(worldScripts)
|
||||
.filter(f -> f.toString().endsWith(".sc"))
|
||||
.forEach(f -> moduleNames.add(f.getFileName().toString().replaceFirst("\\.sc$","").toLowerCase(Locale.ROOT)));
|
||||
|
||||
if (includeBuiltIns && (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT))
|
||||
{
|
||||
String name = script.getName().replaceFirst("\\.sc","").toLowerCase(Locale.ROOT);
|
||||
moduleNames.add(name);
|
||||
Path globalScripts = FabricLoader.getInstance().getConfigDir().resolve("carpet/scripts");
|
||||
Files.createDirectories(globalScripts);
|
||||
Files.walk(globalScripts)
|
||||
.filter(f -> f.toString().endsWith(".sc"))
|
||||
.forEach(f -> moduleNames.add(f.getFileName().toString().replaceFirst("\\.sc$","").toLowerCase(Locale.ROOT)));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
CarpetSettings.LOG.error("Exception while searching for apps: ", e);
|
||||
}
|
||||
return moduleNames;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -26,13 +27,13 @@ public class FileModule extends Module
|
||||
private String name;
|
||||
private String code;
|
||||
private boolean library;
|
||||
public FileModule(File sourceFile)
|
||||
public FileModule(Path sourcePath)
|
||||
{
|
||||
library = sourceFile.getName().endsWith(".scl");
|
||||
library = sourcePath.getFileName().toString().endsWith(".scl");
|
||||
try
|
||||
{
|
||||
name = sourceFile.getName().replaceFirst("\\.scl?","").toLowerCase(Locale.ROOT);
|
||||
code = new String(Files.readAllBytes(sourceFile.toPath()), StandardCharsets.UTF_8);
|
||||
name = sourcePath.getFileName().toString().replaceFirst("\\.scl?","").toLowerCase(Locale.ROOT);
|
||||
code = new String(Files.readAllBytes(sourcePath), StandardCharsets.UTF_8);
|
||||
}
|
||||
catch ( IOException e)
|
||||
{
|
||||
|
||||
@@ -63,6 +63,7 @@ import net.minecraft.command.argument.RotationArgumentType;
|
||||
import net.minecraft.command.argument.ScoreHolderArgumentType;
|
||||
import net.minecraft.command.argument.ScoreboardSlotArgumentType;
|
||||
import net.minecraft.command.argument.SwizzleArgumentType;
|
||||
import net.minecraft.command.argument.TeamArgumentType;
|
||||
import net.minecraft.command.argument.TimeArgumentType;
|
||||
import net.minecraft.command.argument.UuidArgumentType;
|
||||
import net.minecraft.command.argument.Vec2ArgumentType;
|
||||
@@ -130,7 +131,6 @@ public abstract class CommandArgument
|
||||
new VanillaUnconfigurableArgument( "blockpredicate", BlockPredicateArgumentType::blockPredicate,
|
||||
(c, p) -> ValueConversions.ofBlockPredicate(c.getSource().getMinecraftServer().getTagManager(), BlockPredicateArgumentType.getBlockPredicate(c, p)), false
|
||||
),
|
||||
// block_predicate todo - not sure about the returned format. Needs to match block tags used in the API (future)
|
||||
new VanillaUnconfigurableArgument("teamcolor", ColorArgumentType::color,
|
||||
(c, p) -> {
|
||||
Formatting format = ColorArgumentType.getColor(c, p);
|
||||
@@ -165,7 +165,6 @@ public abstract class CommandArgument
|
||||
(c, p) -> ValueConversions.of(Registry.ENCHANTMENT.getId(ItemEnchantmentArgumentType.getEnchantment(c, p))), false
|
||||
),
|
||||
// item_predicate ?? //same as item but accepts tags, not sure right now
|
||||
// slot // item_slot
|
||||
new SlotArgument(),
|
||||
new VanillaUnconfigurableArgument("item", ItemStackArgumentType::itemStack,
|
||||
(c, p) -> ValueConversions.of(ItemStackArgumentType.getItemStackArgument(c, p).createStack(1, false)), false
|
||||
@@ -241,7 +240,9 @@ public abstract class CommandArgument
|
||||
new VanillaUnconfigurableArgument("swizzle", SwizzleArgumentType::swizzle,
|
||||
(c, p) -> StringValue.of(SwizzleArgumentType.getSwizzle(c, p).stream().map(Direction.Axis::asString).collect(Collectors.joining())), true
|
||||
),
|
||||
// team
|
||||
new VanillaUnconfigurableArgument("team", TeamArgumentType::team,
|
||||
(c, p) -> StringValue.of(TeamArgumentType.getTeam(c, p).getName()), false
|
||||
),
|
||||
new VanillaUnconfigurableArgument("time", TimeArgumentType::time,
|
||||
(c, p) -> new NumericValue(IntegerArgumentType.getInteger(c, p)), false
|
||||
),
|
||||
@@ -437,7 +438,7 @@ public abstract class CommandArgument
|
||||
if (config.containsKey("options"))
|
||||
{
|
||||
Value optionsValue = config.get("options");
|
||||
if (!(optionsValue instanceof ListValue)) throw new InternalExpressionException("Custom sting type requires options passed as a list");
|
||||
if (!(optionsValue instanceof ListValue)) throw new InternalExpressionException("Custom string type requires options passed as a list");
|
||||
validOptions = ((ListValue) optionsValue).getItems().stream()
|
||||
.map(v -> caseSensitive?v.getString():(v.getString().toLowerCase(Locale.ROOT)))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
@@ -1,91 +1,158 @@
|
||||
import('math','_euclidean','_manhattan','_round');
|
||||
|
||||
global_display_modes = ['chat', 'line', 'centered_sphere', 'box'];
|
||||
|
||||
__config()->{
|
||||
'commands'->{
|
||||
'from <start>'->'set_start',
|
||||
'from <start> to <end>'->'_calculate',
|
||||
'to <end>'->_(end_pos)->(_calculate(null,end_pos)),
|
||||
'toggle_line'->'_toggle_line'
|
||||
'from <start> to <end>'-> _(start, end) -> (global_current_start = start; calculate(end)),
|
||||
'to <end>'-> 'calculate',
|
||||
'clear' -> _() -> global_display_shapes = [],
|
||||
'clear last' -> _() -> if(global_display_shapes, delete(global_display_shapes, -1)),
|
||||
'display <mode>' -> 'set_mode',
|
||||
'assist <assist>' -> 'set_assist',
|
||||
'assist none' -> _() -> set_assist(null),
|
||||
},
|
||||
'arguments' -> {
|
||||
'start' -> {'type' -> 'location'},
|
||||
'end' -> {'type' -> 'location'}
|
||||
'end' -> {'type' -> 'location'},
|
||||
'mode' -> {'type' -> 'term', 'options' -> global_display_modes },
|
||||
'assist' -> {'type' -> 'block', 'suggest' -> ['brown_carpet']},
|
||||
}
|
||||
};
|
||||
|
||||
global_start=null;
|
||||
global_end=null;
|
||||
global_current_start = null;
|
||||
global_display_shapes = [];
|
||||
global_renderer_running = false;
|
||||
global_current_mode = 'chat';
|
||||
|
||||
global_show_line=false;
|
||||
global_assist_block = null;
|
||||
|
||||
set_assist(block) ->
|
||||
(
|
||||
|
||||
if (block == null,
|
||||
global_assist_block = null;
|
||||
handle_event('player_places_block', null);
|
||||
handle_event('player_uses_item', null);
|
||||
|
||||
,
|
||||
global_assist_block = str(block);
|
||||
handle_event('player_places_block', 'on_player_places_block');
|
||||
handle_event('player_uses_item', 'on_player_uses_item');
|
||||
)
|
||||
);
|
||||
|
||||
global_generators = {
|
||||
'line' -> _(from, to) -> [
|
||||
['line', 'from',from,'to',to]
|
||||
],
|
||||
'centered_sphere' -> _(from, to) -> [
|
||||
['line', 'from',from,'to',to, 'line', 5, 'color', 0x88888888],
|
||||
['sphere', 'center',from,'radius',_euclidean(from,to)]
|
||||
],
|
||||
'box' -> _(from, to) -> [
|
||||
['line', 'from',from,'to',to, 'line', 5, 'color', 0x88888888],
|
||||
['box', 'from',from,'to',to]
|
||||
],
|
||||
};
|
||||
|
||||
_create_shapes(mode, from, to) ->
|
||||
(
|
||||
shapes = call(global_generators:mode, from+[0, 0.07, 0], to+[0, 0.07, 0]);
|
||||
shapes += ['label', 'pos',to+[0,0.2,0], 'align', 'right', 'indent', -1.5, 'text',format('rb Cylindrical:')];
|
||||
shapes += ['label', 'pos',to+[0,0.2,0], 'align', 'left', 'text',_round(_euclidean(from, [to:0, from:1, to:2]), 0.001)];
|
||||
shapes += ['label', 'pos',to+[0,0.2,0], 'height', 1, 'align', 'right', 'indent', -1.5, 'text',format('rb Manhattan:')];
|
||||
shapes += ['label', 'pos',to+[0,0.2,0], 'height', 1, 'align', 'left', 'text',_round(_manhattan(from,to),0.001)];
|
||||
shapes += ['label', 'pos',to+[0,0.2,0], 'height', 2, 'align', 'right', 'indent', -1.5, 'text',format('rb Euclidian:')];
|
||||
shapes += ['label', 'pos',to+[0,0.2,0], 'height', 2, 'align', 'left', 'text',_round(_euclidean(from,to),0.001)];
|
||||
map(shapes, put(_, 1, [20, 'player', player()], 'extend'); _);
|
||||
);
|
||||
|
||||
__mktp(pos) -> str('!/tp %.6f %.6f %.6f', pos);
|
||||
|
||||
set_start(pos)->(
|
||||
global_start = pos;
|
||||
global_end = null;
|
||||
global_current_start = pos;
|
||||
print(player(),format('gi Initial point set to: ', 'g '+pos, __mktp(pos)))
|
||||
);
|
||||
|
||||
_toggle_line()->(
|
||||
global_show_line= !global_show_line;
|
||||
if(global_show_line,
|
||||
print('Toggled lines on');
|
||||
_draw_line()
|
||||
, // else
|
||||
print('Toggled lines off')
|
||||
);
|
||||
);
|
||||
|
||||
_calculate(start_pos, end_pos)->(
|
||||
if(start_pos!=null,
|
||||
set_start(start_pos);
|
||||
calculate(end_pos)
|
||||
, // else
|
||||
if(global_start,
|
||||
calculate(end_pos),
|
||||
print(player(),format('r There was no initial point for '+player()));
|
||||
set_start(end_pos)
|
||||
)
|
||||
set_mode(mode)->(
|
||||
if (global_display_modes ~ mode,
|
||||
global_current_mode = mode
|
||||
)
|
||||
);
|
||||
|
||||
__on_player_places_block(player, item_tuple, hand, block) ->(
|
||||
if(block=='brown_carpet' && system_info('world_carpet_rules'):'carpets'=='true',
|
||||
calculate(end)->(
|
||||
if(global_current_start != null,
|
||||
measure(end)
|
||||
, // else
|
||||
print(player(),format('r No initial point selected'));
|
||||
)
|
||||
);
|
||||
|
||||
_carpets() -> system_info('world_carpet_rules'):'carpets'=='true';
|
||||
|
||||
|
||||
on_player_places_block(player, item_tuple, hand, block) ->
|
||||
(
|
||||
if(block==global_assist_block && _carpets(),
|
||||
effective_pos = pos(block)+[0.5, 0, 0.5];
|
||||
if(global_start==null||player~'sneaking',//wont complain for first carpet
|
||||
set_start(effective_pos),
|
||||
_calculate(null, effective_pos)
|
||||
if(global_current_start==null||player~'sneaking',//wont complain for first carpet
|
||||
set_start(effective_pos)
|
||||
, // else
|
||||
calculate(effective_pos)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
calculate(end_pos)->(
|
||||
global_end = end_pos;
|
||||
manhattan = _round(_manhattan(global_start, global_end),0.001);//rounding to nearest 0.01 for precision, but not ridiculous decimal places
|
||||
spherical = _round(_euclidean(global_start, global_end), 0.001);
|
||||
//useful for chunk distances etc.
|
||||
cylindrical = _round(_euclidean(global_start, [global_end:0, global_start:1, global_end:2]), 0.001);
|
||||
|
||||
|
||||
print(player(),format(
|
||||
'w Distance between ',
|
||||
'c '+str('[%.1f, %.1f, %.1f]', global_start), __mktp(global_start),
|
||||
'w and ',
|
||||
'c '+str('[%.1f, %.1f, %.1f]', global_end), __mktp(global_end), 'w :\n',
|
||||
'w - Spherical: ', 'wb '+spherical+'\n',
|
||||
'w - Cylindrical: ', 'wb '+cylindrical+'\n',
|
||||
'w - Manhattan: ', 'wb '+manhattan
|
||||
));
|
||||
|
||||
schedule(0,'_draw_line');
|
||||
);
|
||||
|
||||
_draw_line()->(
|
||||
if(global_show_line,//It will always draw from the global positions, so it will turn on if there is a line
|
||||
if ( global_start && global_end,
|
||||
draw_shape('line',20,'from',global_start,'to',global_end, 'player',player());
|
||||
draw_shape('label',20,'pos',global_end,'text',_round(_euclidean(global_start,global_end),0.001));
|
||||
);
|
||||
schedule(20,'_draw_line')
|
||||
on_player_uses_item(player, item_tuple, hand) ->
|
||||
(
|
||||
if (item_tuple:0 == global_assist_block && hand == 'mainhand' && _carpets(),
|
||||
if (player ~'sneaking',
|
||||
global_current_mode = global_display_modes:(global_display_modes ~ global_current_mode + 1);
|
||||
display_title(player, 'actionbar', format('w Distance mode: ','e '+global_current_mode));
|
||||
,
|
||||
if(global_display_shapes, delete(global_display_shapes, -1))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
measure(end)->
|
||||
(
|
||||
if (global_current_start == null, return());
|
||||
start = global_current_start;
|
||||
if (global_current_mode == 'chat',
|
||||
manhattan = _round(_manhattan(start, end),0.001);//rounding to nearest 0.01 for precision, but not ridiculous decimal places
|
||||
spherical = _round(_euclidean(start, end), 0.001);
|
||||
//useful for chunk distances etc.
|
||||
cylindrical = _round(_euclidean(start, [end:0, start:1, end:2]), 0.001);
|
||||
|
||||
print(player(),format(
|
||||
'w Distance between ',
|
||||
'c '+str('[%.1f, %.1f, %.1f]', start), __mktp(start),
|
||||
'w and ',
|
||||
'c '+str('[%.1f, %.1f, %.1f]', end), __mktp(end), 'w :\n',
|
||||
'w - Spherical: ', 'wb '+spherical+'\n',
|
||||
'w - Cylindrical: ', 'wb '+cylindrical+'\n',
|
||||
'w - Manhattan: ', 'wb '+manhattan
|
||||
));
|
||||
, // else
|
||||
global_display_shapes += _create_shapes(global_current_mode, start, end);
|
||||
for (global_display_shapes, draw_shape(_) );
|
||||
if (!global_renderer_running,
|
||||
global_renderer_running = true;
|
||||
render()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
render()->(
|
||||
if (!global_display_shapes,
|
||||
global_renderer_running = false;
|
||||
return();
|
||||
);
|
||||
for (global_display_shapes,
|
||||
draw_shape(_);
|
||||
);
|
||||
schedule(20,'render')
|
||||
);
|
||||
@@ -20,7 +20,7 @@ __config() -> {
|
||||
'arguments'->{
|
||||
'center'->{'type'->'pos', 'loaded'->'true'},
|
||||
'radius'->{'type'->'int', 'suggest'->[], 'min'->0},//to avoid default suggestions
|
||||
'replacement'->{'type'->'block'},
|
||||
'replacement'->{'type'->'blockpredicate'},
|
||||
'height'->{'type'->'int', 'suggest'->[],'min'->0},
|
||||
'orientation'->{'type'->'term', 'suggest'->['x','y','z']},
|
||||
'pointing'->{'type'->'term','suggest'->['up','down']},
|
||||
@@ -32,9 +32,20 @@ __config() -> {
|
||||
|
||||
//"Boilerplate" code
|
||||
|
||||
_block_matches(existing, block_predicate) ->
|
||||
(
|
||||
[name, block_tag, properties, nbt] = block_predicate;
|
||||
|
||||
(name == null || name == existing) &&
|
||||
(block_tag == null || block_tags(existing, block_tag)) &&
|
||||
all(properties, block_state(existing, _) == properties:_) &&
|
||||
(!tag || tag_matches(block_data(existing), tag))
|
||||
);
|
||||
|
||||
set_block(x, y, z, block, replacement)-> (
|
||||
if(block != block(x, y, z),
|
||||
without_updates( if (set([x, y, z],block),
|
||||
existing = block(x, y, z);
|
||||
if(block != existing && (replacement && _block_matches(existing, replacement) ),
|
||||
without_updates( if (set(existing,block),
|
||||
global_affected += [x, y, z];
|
||||
));
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user