diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index 99523a4f..a0bac5ea 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -906,8 +906,11 @@ sleep(50) ### `time()` -Returns the number of milliseconds since 'some point', like Java's `System.nanoTime()`. -It returns a float, which has 1 microsecond precision (0.001 ms) +Returns the number of milliseconds since 'some point', like Java's `System.nanoTime()`, which varies from system to +system and from Java to Java. This measure should NOT be used to determine the current (date)time, but to measure +durations of things. +it returns a float with time in milliseconds (ms) for convenience and microsecond (μs) resolution for sanity. +
 start_time = time();
@@ -1513,7 +1516,7 @@ range(5,10)  => [5, 6, 7, 8, 9]
 range(20, 10, -2)  => [20, 18, 16, 14, 12]
 
-### `element(list, index)` (deprecated) +### `element(list, index)(deprecated)` Legacy support for older method that worked only on lists. Please use `get(...)` for equivalent support, or `.` operator. Also previous unique behaviours with `put` on lists has been removed to support all type of @@ -3044,6 +3047,8 @@ __on_player_starts_sprinting(player) __on_player_stops_sprinting(player) __on_player_drops_item(player) __on_player_drops_stack(player) +__on_player_connects(player) +__on_player_disconnects(player, reason) __on_statistic(player, category, event, value) // player statistic changes @@ -3103,24 +3108,77 @@ and `voice`. `pos` can be either a block, triple of coords, or a list of thee nu ## Particles -### `particle(name, pos, count?. spread?, speed?, playername?)` +### `particle(name, pos, count?. spread?, speed?, player?)` Renders a cloud of particles `name` centered around `pos` position, by default `count` 10 of them, default `speed` of 0, and to all players nearby, but these options can be changed via optional arguments. Follow vanilla `/particle` command on details on those options. Valid particle names are for example `'angry_villager', 'item diamond', 'block stone', 'dust 0.8 0.1 0.1 4'`. -### `particle_line(name, pos, pos2, density?)` +### `particle_line(name, pos, pos2, density?, player?)` Renders a line of particles from point `pos` to `pos2` with supplied density (defaults to 1), which indicates how far -apart you would want particles to appear, so `0.1` means one every 10cm. +apart you would want particles to appear, so `0.1` means one every 10cm. If a player (or player name) is supplied, only +that player will receive particles. -### `particle_rect(name, pos, pos2, density?)` -Renders a cuboid of particles between points `pos` and `pos2` with supplied density. +### `particle_box(name, pos, pos2, density?, player?)` +### `particle_rect` (deprecated) + +Renders a cuboid of particles between points `pos` and `pos2` with supplied density. If a player (or player name) is +supplied, only that player will receive particles. ## Markers +### `draw_shape(shape, duration, key?, value?, ... )`, `draw_shape(shape, duration, l(key?, value?, ... ))`, `draw_shape(shape, duration, attribute_map)` + +Draws a shape in the world that will expire in `duration` ticks. Other attributes of the shape should be provided as +consecutive key - value argument pairs, either as next arguments, or packed in a list, or supplied as a proper key-value +`map`. Arguments may include shared shape attributes, which are all optional, as well as shape-specific attributes, that +could be either optional or required. Shapes will draw properly on all carpet clients. Other connected players that don't +have carpet installed will still be able to see the required shapes in the form of dust particles. Replacement shapes +are not required to follow all attributes precisely, but will allow vanilla clients to receive some experience of your +apps. One of the attributes that will definitely not be honored is the duration - particles will be send once +per shape and last whatever they typically last in the game. + +Shapes will fail to draw and raise a runtime error if not all its required parameters +are specified and all available shapes have some parameters that are required, so make sure to have them in place: + +On the client, shapes can recognize that they are being redrawn again with the same parameters, disregarding the +duration parameter. This updates the expiry on the drawn shape to the new value, instead of adding new shape in its +place. This can be used for toggling the shapes on and off that has been send previously with very large durations, +or simply refresh the shapes periodically in more dynamic applications. + +Optional shared shape attributes: + * `color` - integer value indicating the main color of the shape in the form of red, green, blue and alpha components + in the form of `0xRRGGBBAA`, with the default of `-1`, so white opaque, or `0xFFFFFFFF`. + * `player` - name or player entity to send the shape to. If specified, the shapes will appear only for the specified + player, otherwise it will be send to all players in the dimension. + +Available shapes: + * `'line'` - draws a straight line between two points + * Required attributes: + * `from` - triple coordinates, entity, or block value indicating one end of the line + * `to` - other end of the line, same format as `from` + * Optional attributes: + * `width` - line thickness, defaults to 2.0pt + + * `'box'` - draws a box with corners in specified points + * Required attributes: + * `from` - triple coordinates, entity, or block value indicating one corner of the box + * `to` - other corner, same format as `from` + * Optional attributes: + * `width` - mesh line thickness, defaults to 2.0pt + * `fill` - color for the box faces, defaults to no fill, use shared color attribute format + * `'sphere'` - draws a sphere + * Required attributes: + * `center` - center of the sphere + * `radius` - radius of the sphere + * Optional attributes: + * `level` - level of details, or grid size. The more the denser your sphere. Default level of 0, means that the + level of detail will be selected automatically based on radius. + * `width` - line thickness + ### `create_marker(text, pos, rotation?, block?)` Spawns a (permanent) marker entity with text or block at position. Returns that entity for further manipulations. @@ -3302,6 +3360,9 @@ Returns current dimension that the script runs in. Evaluates the expression `expr` with different dimension execution context. `smth` can be an entity, world-localized block, so not `block('stone')`, or a string representing a dimension like: `'nether'`, `'the_nether'`, `'end'` or `'overworld'`, etc. + +### `view_distance()` +Returns the view distance of the server. ### `schedule(delay, function, args...)` diff --git a/docs/scarpet/api/Auxiliary.md b/docs/scarpet/api/Auxiliary.md index 7d9da627..90860cc9 100644 --- a/docs/scarpet/api/Auxiliary.md +++ b/docs/scarpet/api/Auxiliary.md @@ -36,19 +36,54 @@ supplied, only that player will receive particles. ## Markers -### `marker_box(from, to, duration?, color?, player?)` +### `draw_shape(shape, duration, key?, value?, ... )`, `draw_shape(shape, duration, l(key?, value?, ... ))`, `draw_shape(shape, duration, attribute_map)` -Draws a box with `from` and `to` corners in the box. The boxes will dissipate after `duration` ticks (defaults to 10). -The color is an integer that indicate red, green, blue and alpha components in the form of `0xRRGGBBAA`, with the -default of `-1`, so white opaque, or `0xFFFFFFFF`. If player is specified, only displays for that player, otherwise all -players will see them. `marker_box` requires proper client synchronization to display these, and on non-supported -clients, the box will be replaced with close matching dust particles, so using of `marker_box` is safe to use for -scripts regardless who is targeted. The only consideration is that with vanilla clients, duration of particles cannot -be controlled, and last whatever the original particles do. +Draws a shape in the world that will expire in `duration` ticks. Other attributes of the shape should be provided as +consecutive key - value argument pairs, either as next arguments, or packed in a list, or supplied as a proper key-value +`map`. Arguments may include shared shape attributes, which are all optional, as well as shape-specific attributes, that +could be either optional or required. Shapes will draw properly on all carpet clients. Other connected players that don't +have carpet installed will still be able to see the required shapes in the form of dust particles. Replacement shapes +are not required to follow all attributes precisely, but will allow vanilla clients to receive some experience of your +apps. One of the attributes that will definitely not be honored is the duration - particles will be send once +per shape and last whatever they typically last in the game. -### `marker_line(from, to, duration?, color?, player?)` +Shapes will fail to draw and raise a runtime error if not all its required parameters +are specified and all available shapes have some parameters that are required, so make sure to have them in place: -Draws a marker line on client's screen. Uses similar setup as `marker_box`. +On the client, shapes can recognize that they are being redrawn again with the same parameters, disregarding the +duration parameter. This updates the expiry on the drawn shape to the new value, instead of adding new shape in its +place. This can be used for toggling the shapes on and off that has been send previously with very large durations, +or simply refresh the shapes periodically in more dynamic applications. + +Optional shared shape attributes: + * `color` - integer value indicating the main color of the shape in the form of red, green, blue and alpha components + in the form of `0xRRGGBBAA`, with the default of `-1`, so white opaque, or `0xFFFFFFFF`. + * `player` - name or player entity to send the shape to. If specified, the shapes will appear only for the specified + player, otherwise it will be send to all players in the dimension. + +Available shapes: + * `'line'` - draws a straight line between two points + * Required attributes: + * `from` - triple coordinates, entity, or block value indicating one end of the line + * `to` - other end of the line, same format as `from` + * Optional attributes: + * `width` - line thickness, defaults to 2.0pt + + * `'box'` - draws a box with corners in specified points + * Required attributes: + * `from` - triple coordinates, entity, or block value indicating one corner of the box + * `to` - other corner, same format as `from` + * Optional attributes: + * `width` - mesh line thickness, defaults to 2.0pt + * `fill` - color for the box faces, defaults to no fill, use shared color attribute format + * `'sphere'` - draws a sphere + * Required attributes: + * `center` - center of the sphere + * `radius` - radius of the sphere + * Optional attributes: + * `level` - level of details, or grid size. The more the denser your sphere. Default level of 0, means that the + level of detail will be selected automatically based on radius. + * `width` - line thickness ### `create_marker(text, pos, rotation?, block?)` @@ -231,6 +266,9 @@ Returns current dimension that the script runs in. Evaluates the expression `expr` with different dimension execution context. `smth` can be an entity, world-localized block, so not `block('stone')`, or a string representing a dimension like: `'nether'`, `'the_nether'`, `'end'` or `'overworld'`, etc. + +### `view_distance()` +Returns the view distance of the server. ### `schedule(delay, function, args...)` diff --git a/docs/scarpet/api/Events.md b/docs/scarpet/api/Events.md index 39992450..6a616f30 100644 --- a/docs/scarpet/api/Events.md +++ b/docs/scarpet/api/Events.md @@ -48,6 +48,8 @@ __on_player_starts_sprinting(player) __on_player_stops_sprinting(player) __on_player_drops_item(player) __on_player_drops_stack(player) +__on_player_connects(player) +__on_player_disconnects(player, reason) __on_statistic(player, category, event, value) // player statistic changes diff --git a/docs/scarpet/resources/editors/idea/2.txt b/docs/scarpet/resources/editors/idea/2.txt index 81803965..7e2a8d8a 100644 --- a/docs/scarpet/resources/editors/idea/2.txt +++ b/docs/scarpet/resources/editors/idea/2.txt @@ -17,6 +17,7 @@ current_dimension day_time destroy diamond +draw_shape drop_item emitted_light entity_area @@ -101,6 +102,7 @@ ticks_randomly top transparent update +view_distance volume without_updates world_time \ No newline at end of file diff --git a/docs/scarpet/resources/editors/idea/4.txt b/docs/scarpet/resources/editors/idea/4.txt index 4799c846..faf87463 100644 --- a/docs/scarpet/resources/editors/idea/4.txt +++ b/docs/scarpet/resources/editors/idea/4.txt @@ -30,4 +30,6 @@ __on_tick_nether __on_player_takes_damage __on_player_deals_damage __on_player_dies -__on_player_respawns \ No newline at end of file +__on_player_respawns +__on_player_disconnects +__on_player_connects \ No newline at end of file diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index c17b3811..33416a05 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -68,9 +68,11 @@ format logger sound particle particle_line particle_rect - run save tick_time world_time day_time last_tick_times game_tick seed current_dimension in_dimension + run save tick_time world_time day_time last_tick_times game_tick seed current_dimension in_dimension view_distance - plop harvest destroy schedule nbt create_marker remove_all_markers load_app_data store_app_data escape_nbt statistic + plop harvest destroy schedule nbt draw_shape create_marker remove_all_markers + + load_app_data store_app_data escape_nbt statistic euler pi null true false x y z p @@ -110,6 +112,8 @@ __on_player_deals_damage __on_player_dies __on_player_respawns + __on_player_disconnects + __on_player_connects $ 00' 01\ 02' 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 diff --git a/src/main/java/carpet/CarpetSettings.java b/src/main/java/carpet/CarpetSettings.java index ae2874cc..5b6ccf29 100644 --- a/src/main/java/carpet/CarpetSettings.java +++ b/src/main/java/carpet/CarpetSettings.java @@ -62,7 +62,7 @@ public class CarpetSettings @Rule( desc = "sets the language for carpet", category = FEATURE, - options = {"none", "zh_cn"}, + options = {"none", "zh_cn", "zh_tw"}, strict = false, validate = LanguageValidator.class ) diff --git a/src/main/java/carpet/mixins/PlayerManager_coreMixin.java b/src/main/java/carpet/mixins/PlayerManager_coreMixin.java index ecd2fe61..62eeefff 100644 --- a/src/main/java/carpet/mixins/PlayerManager_coreMixin.java +++ b/src/main/java/carpet/mixins/PlayerManager_coreMixin.java @@ -9,6 +9,8 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import static carpet.script.CarpetEventServer.Event.PLAYER_CONNECTS; + @Mixin(PlayerManager.class) public class PlayerManager_coreMixin { @@ -16,5 +18,6 @@ public class PlayerManager_coreMixin private void onPlayerConnected(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) { CarpetServer.onPlayerLoggedIn(player); + PLAYER_CONNECTS.onPlayerEvent(player); } } diff --git a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java index 1dfbc237..43fabd5c 100644 --- a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java +++ b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java @@ -13,6 +13,8 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import static carpet.script.CarpetEventServer.Event.PLAYER_DISCONNECTS; + @Mixin(ServerPlayNetworkHandler.class) public class ServerPlayNetworkHandler_coreMixin { @Shadow @@ -21,5 +23,6 @@ public class ServerPlayNetworkHandler_coreMixin { @Inject(method = "onDisconnected", at = @At("HEAD")) private void onPlayerDisconnect(Text reason, CallbackInfo ci) { CarpetServer.onPlayerLoggedOut(this.player); + if (PLAYER_DISCONNECTS.isNeeded()) PLAYER_DISCONNECTS.onPlayerMessage(player, reason.asString()); } } diff --git a/src/main/java/carpet/network/ClientNetworkHandler.java b/src/main/java/carpet/network/ClientNetworkHandler.java index f155040f..294bb08e 100644 --- a/src/main/java/carpet/network/ClientNetworkHandler.java +++ b/src/main/java/carpet/network/ClientNetworkHandler.java @@ -35,7 +35,7 @@ public class ClientNetworkHandler } }); put("TickRate", (p, t) -> TickSpeed.tickrate(((AbstractNumberTag)t).getFloat(), false)); - put("renderShape", (p, t) -> { + put("scShape", (p, t) -> { if (CarpetClient.shapes != null) CarpetClient.shapes.addShape((CompoundTag)t); }); diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java index 200a02f5..aa26bbb5 100644 --- a/src/main/java/carpet/script/CarpetEventServer.java +++ b/src/main/java/carpet/script/CarpetEventServer.java @@ -128,7 +128,13 @@ public class CarpetEventServer List argv = argumentSupplier.get(); // empty for onTickDone ServerCommandSource source = cmdSourceSupplier.get(); assert argv.size() == reqArgs; - callList.removeIf(call -> !CarpetServer.scriptServer.runas(source, call.host, call.function, argv)); // this actually does the calls + List fails = new ArrayList<>(); + for (Callback call: callList) + { + if (!CarpetServer.scriptServer.runas(source, call.host, call.function, argv)) + fails.add(call); + } + for (Callback call : fails) callList.remove(call); } } public boolean addEventCall(ServerCommandSource source, String hostName, String funName, Function verifier) @@ -549,6 +555,23 @@ public class CarpetEventServer ), player::getCommandSource); } }, + PLAYER_CONNECTS("player_connects", 1, false) { + @Override + public void onPlayerEvent(ServerPlayerEntity player) + { + handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource); + } + }, + PLAYER_DISCONNECTS("player_disconnects", 2, false) { + @Override + public void onPlayerMessage(ServerPlayerEntity player, String message) + { + handler.call( () -> Arrays.asList( + ((c, t) -> new EntityValue(player)), + ((c, t) -> new StringValue(message)) + ), player::getCommandSource); + } + }, STATISTICS("statistic", 4, false) { private Identifier getStatId(Stat stat) @@ -613,6 +636,7 @@ public class CarpetEventServer public void onTick() { } public void onChunkGenerated(ServerWorld world, Chunk chunk) { } public void onPlayerEvent(ServerPlayerEntity player) { } + public void onPlayerMessage(ServerPlayerEntity player, String message) { } public void onPlayerStatistic(ServerPlayerEntity player, Stat stat, int amount) { } public void onMountControls(ServerPlayerEntity player, float strafeSpeed, float forwardSpeed, boolean jumping, boolean sneaking) { } public void onItemAction(ServerPlayerEntity player, Hand enumhand, ItemStack itemstack) { } diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 67395cb6..6090184d 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -2704,7 +2704,7 @@ public class CarpetExpression ServerPlayerEntity player = null; if (params.containsKey("player")) { - player = (ServerPlayerEntity) ((EntityValue)params.get("player")).getEntity(); + player = (ServerPlayerEntity)((EntityValue)params.get("player")).getEntity(); } ShapeDispatcher.sendShape( (player==null)?cc.s.getWorld().getPlayers():Collections.singletonList(player), @@ -2987,6 +2987,12 @@ public class CarpetExpression return (cc, tt) -> retval; }); + this.expr.addLazyFunction("view_distance", 0, (c, t, lv) -> { + ServerCommandSource s = ((CarpetContext)c).s; + Value retval = new NumericValue(s.getMinecraftServer().getPlayerManager().getViewDistance()); + return (cc, tt) -> retval; + }); + this.expr.addLazyFunction("in_dimension", 2, (c, t, lv) -> { ServerCommandSource outerSource = ((CarpetContext)c).s; Value dimensionValue = lv.get(0).evalValue(c); diff --git a/src/main/java/carpet/script/CarpetScriptHost.java b/src/main/java/carpet/script/CarpetScriptHost.java index bd2b669e..94f3b2fc 100644 --- a/src/main/java/carpet/script/CarpetScriptHost.java +++ b/src/main/java/carpet/script/CarpetScriptHost.java @@ -96,7 +96,7 @@ public class CarpetScriptHost extends ScriptHost public void addUserDefinedFunction(Context ctx, Module module, String funName, FunctionValue function) { super.addUserDefinedFunction(ctx, module, funName, function); - // mcarpet + if (ctx.host.main != module) return; // not dealing with automatic imports / exports /configs / apps from imports if (funName.startsWith("__")) // potential fishy activity { if (funName.startsWith("__on_")) // here we can make a determination if we want to only accept events from main module. diff --git a/src/main/java/carpet/script/utils/ShapeDispatcher.java b/src/main/java/carpet/script/utils/ShapeDispatcher.java index 42364245..fca80136 100644 --- a/src/main/java/carpet/script/utils/ShapeDispatcher.java +++ b/src/main/java/carpet/script/utils/ShapeDispatcher.java @@ -19,6 +19,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.command.arguments.ParticleArgumentType; import net.minecraft.entity.Entity; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.IntTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; @@ -27,6 +28,7 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; import net.minecraft.world.dimension.DimensionType; @@ -39,6 +41,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; +import java.util.Random; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; @@ -59,7 +62,7 @@ public class ShapeDispatcher if (ServerNetworkHandler.validCarpetPlayers.contains(player)) { if (tag == null) tag = ExpiringShape.toTag(params); - ServerNetworkHandler.sendCustomCommand(player,"renderShape", tag); + ServerNetworkHandler.sendCustomCommand(player,"scShape", tag); } else { @@ -105,16 +108,14 @@ public class ShapeDispatcher public static ExpiringShape create(CarpetContext cc, String shapeType, Map userParams) { userParams.put("shape", new StringValue(shapeType)); - Map validatedParams = new HashMap<>(); - userParams.forEach((key, value) -> - { + userParams.keySet().forEach(key -> { Param param = Param.coders.get(key); if (param==null) throw new InternalExpressionException("Unknown feature for shape: "+key); - validatedParams.put(key, param.validate(cc, value)); + userParams.put(key, param.validate(cc, userParams.get(key))); }); Function,ExpiringShape> factory = ExpiringShape.shapeProviders.get(shapeType); if (factory == null) throw new InternalExpressionException("Unknown shape: "+shapeType); - return factory.apply(validatedParams); + return factory.apply(userParams); } // client @@ -126,7 +127,7 @@ public class ShapeDispatcher Function decoder = Param.decoders.get(key); if (decoder==null) { - CarpetSettings.LOG.error("Unknown parameter for shape: "+key); + CarpetSettings.LOG.info("Unknown parameter for shape: "+key); return null; } Value decodedValue = decoder.apply(tag.get(key)); @@ -135,13 +136,13 @@ public class ShapeDispatcher Value shapeValue = options.get("shape"); if (shapeValue == null) { - CarpetSettings.LOG.error("Shape id missing in "+ String.join(", ", tag.getKeys())); + CarpetSettings.LOG.info("Shape id missing in "+ String.join(", ", tag.getKeys())); return null; } Function,ExpiringShape> factory = ExpiringShape.shapeProviders.get(shapeValue.getString()); if (factory == null) { - CarpetSettings.LOG.error("Unknown shape: "+shapeValue.getString()); + CarpetSettings.LOG.info("Unknown shape: "+shapeValue.getString()); return null; } try @@ -150,7 +151,7 @@ public class ShapeDispatcher } catch (InternalExpressionException exc) { - CarpetSettings.LOG.error(exc.getMessage()); + CarpetSettings.LOG.info(exc.getMessage()); } return null; } @@ -160,6 +161,7 @@ public class ShapeDispatcher public static final Map,ExpiringShape>> shapeProviders = new HashMap, ExpiringShape>>(){{ put("line", creator(Line::new)); put("box", creator(Box::new)); + put("sphere", creator(Sphere::new)); }}; private static Function,ExpiringShape> creator(Supplier shapeFactory) { @@ -229,7 +231,10 @@ public class ShapeDispatcher } // list of params that need to be there private final Set required = ImmutableSet.of("duration", "shape", "dim"); - private final Map optional = ImmutableMap.of("color", new NumericValue(-1)); + private final Map optional = ImmutableMap.of( + "color", new NumericValue(-1), + "player", Value.NULL + ); protected Set requiredParams() {return required;} // list of params that can be there, with defaults protected Set optionalParams() {return optional.keySet();} @@ -238,7 +243,10 @@ public class ShapeDispatcher public static class Box extends ExpiringShape { private final Set required = ImmutableSet.of("from", "to"); - private final Map optional = ImmutableMap.of(); + private final Map optional = ImmutableMap.of( + "width", new NumericValue(2.0), + "fill", new NumericValue(0xffffff00) + ); @Override protected Set requiredParams() { return Sets.union(super.requiredParams(), required); } @Override @@ -247,6 +255,10 @@ public class ShapeDispatcher float x1, y1, z1; float x2, y2, z2; + float lineWidth; + + protected float fr, fg, fb, fa; + protected int fillColor; @Override protected void init(Map options) @@ -260,6 +272,12 @@ public class ShapeDispatcher x2 = NumericValue.asNumber(to.get(0)).getFloat(); y2 = NumericValue.asNumber(to.get(1)).getFloat(); z2 = NumericValue.asNumber(to.get(2)).getFloat(); + lineWidth = NumericValue.asNumber(options.getOrDefault("width", optional.get("width"))).getFloat(); + fillColor = NumericValue.asNumber(options.getOrDefault("fill", optional.get("fill"))).getInt(); + this.fr = (float)(fillColor >> 24 & 0xFF) / 255.0F; + this.fg = (float)(fillColor >> 16 & 0xFF) / 255.0F; + this.fb = (float)(fillColor >> 8 & 0xFF) / 255.0F; + this.fa = (float)(fillColor & 0xFF) / 255.0F; } @Override @@ -285,6 +303,8 @@ public class ShapeDispatcher hash = 31*hash + Float.hashCode(x2); hash = 31*hash + Float.hashCode(y2); hash = 31*hash + Float.hashCode(z2); + hash = 31*hash + Float.hashCode(lineWidth); + if (fa != 0.0) hash = 31*hash + fillColor; return hash; } @@ -312,7 +332,7 @@ public class ShapeDispatcher public static class Line extends ExpiringShape { private final Set required = ImmutableSet.of("from", "to"); - private final Map optional = ImmutableMap.of(); + private final Map optional = ImmutableMap.of("width", new NumericValue(2.0)); @Override protected Set requiredParams() { return Sets.union(super.requiredParams(), required); } @Override @@ -325,6 +345,7 @@ public class ShapeDispatcher float x1, y1, z1; float x2, y2, z2; + float lineWidth; @Override protected void init(Map options) @@ -338,6 +359,7 @@ public class ShapeDispatcher x2 = NumericValue.asNumber(to.get(0)).getFloat(); y2 = NumericValue.asNumber(to.get(1)).getFloat(); z2 = NumericValue.asNumber(to.get(2)).getFloat(); + lineWidth = NumericValue.asNumber(options.getOrDefault("width", optional.get("width"))).getFloat(); } @Override @@ -365,10 +387,88 @@ public class ShapeDispatcher hash = 31*hash + Float.hashCode(x2); hash = 31*hash + Float.hashCode(y2); hash = 31*hash + Float.hashCode(z2); + hash = 31*hash + Float.hashCode(lineWidth); return hash; } } + public static class Sphere extends ExpiringShape + { + private final Set required = ImmutableSet.of("center", "radius"); + private final Map optional = ImmutableMap.of("width", new NumericValue(2.0), "level", Value.ZERO); + @Override + protected Set requiredParams() { return Sets.union(super.requiredParams(), required); } + @Override + protected Set optionalParams() { return Sets.union(super.optionalParams(), optional.keySet()); } + + private Sphere() + { + super(); + } + + float cx, cy, cz; + float radius; + int level; + int subdivisions; + float lineWidth; + + @Override + protected void init(Map options) + { + super.init(options); + List from = ((ListValue)options.get("center")).getItems(); + cx = NumericValue.asNumber(from.get(0)).getFloat(); + cy = NumericValue.asNumber(from.get(1)).getFloat(); + cz = NumericValue.asNumber(from.get(2)).getFloat(); + radius = NumericValue.asNumber(options.get("radius")).getFloat(); + level = NumericValue.asNumber(options.getOrDefault("level", optional.get("level"))).getInt(); + subdivisions = level; + if (subdivisions <= 0) + { + subdivisions = Math.max(10, (int)(10*Math.sqrt(radius))); + } + lineWidth = NumericValue.asNumber(options.getOrDefault("width", optional.get("width"))).getFloat(); + } + + @Override + public Consumer alternative() { return p -> + { + String particleName = String.format(Locale.ROOT , "dust %.1f %.1f %.1f 1.0", r, g, b); + ParticleEffect particle = getParticleData(particleName); + float pihalf = (float)(Math.PI / 180.0f); + int partno = Math.min(1000,20*subdivisions); + Random rand = p.world.getRandom(); + ServerWorld world = p.getServerWorld(); + for (int i=0; i> decoders = new HashMap>(){{ @@ -378,16 +478,25 @@ public class ShapeDispatcher put("color", ShapeDispatcher::decodeInt); put("from", Vec3Param::decode); put("to", Vec3Param::decode); - + put("width", ShapeDispatcher::decodeFloat); + put("fill", ShapeDispatcher::decodeInt); + put("center", Vec3Param::decode); + put("radius", ShapeDispatcher::decodeFloat); + put("level", ShapeDispatcher::decodeInt); }}; Map coders = new HashMap(){{ - put("shape", new ShapeParam()); put("player", new PlayerParam()); + put("shape", new ShapeParam()); put("dim", new DimensionParam()); put("duration", new DurationParam()); put("color", new ColorParam()); put("from", new FromParam()); put("to", new ToParam()); + put("width", new WidthParam()); + put("fill", new FillColorParam()); + put("center", new CenterParam()); + put("radius", new RadiusParam()); + put("level", new LevelParam()); }}; Tag toTag(Value value); //validates value, returning null if not necessary to keep it and serialize Value validate(CarpetContext cc, Value value); // makes sure the value is proper @@ -448,8 +557,6 @@ public class ShapeDispatcher } public static abstract class NumericParam implements Param { - @Override - public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value).getInt()); } @Override public Value validate(CarpetContext cc, Value value) { @@ -467,15 +574,34 @@ public class ShapeDispatcher return ret; } } + public static abstract class PositiveFloatParam extends PositiveParam + { + @Override + public Tag toTag(Value value) { return FloatTag.of(NumericValue.asNumber(value).getFloat()); } + } + public static abstract class PositiveIntParam extends PositiveParam + { + @Override + public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value).getInt()); } + + } public static Value decodeInt(Tag tag) { return new NumericValue(((IntTag)tag).getInt()); } - public static class DurationParam extends PositiveParam + public static Value decodeFloat(Tag tag) { return new NumericValue(((FloatTag)tag).getFloat()); } + public static class DurationParam extends PositiveIntParam { @Override public boolean appliesTo(ExpiringShape shape) { return true; } @Override public String identify() { return "duration"; } } + public static class WidthParam extends PositiveFloatParam + { + @Override + public boolean appliesTo(ExpiringShape shape) { return shape instanceof Box || shape instanceof Line; } + @Override + public String identify() { return "width"; } + } public static abstract class Vec3Param implements Param { @@ -542,12 +668,22 @@ public class ShapeDispatcher } public static class ColorParam extends NumericParam { + @Override + public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value).getInt()); } @Override public boolean appliesTo(ExpiringShape shape) { return true; } @Override public String identify() { return "color"; } } + public static class FillColorParam extends ColorParam + { + @Override + public boolean appliesTo(ExpiringShape shape) { return shape instanceof Box; } + @Override + public String identify() { return "fill"; } + } + public static class FromParam extends Vec3Param { @Override @@ -568,6 +704,30 @@ public class ShapeDispatcher public String identify() { return "to"; } } + public static class CenterParam extends Vec3Param + { + @Override + public boolean appliesTo(ExpiringShape shape) { return (shape instanceof Sphere); } + @Override + public boolean roundsUpForBlocks() { return false; } + @Override + public String identify() { return "center"; } + } + public static class RadiusParam extends PositiveFloatParam + { + @Override + public boolean appliesTo(ExpiringShape shape) { return shape instanceof Sphere; } + @Override + public String identify() { return "radius"; } + } + public static class LevelParam extends PositiveIntParam + { + @Override + public boolean appliesTo(ExpiringShape shape) { return shape instanceof Sphere; } + @Override + public String identify() { return "level"; } + } + private static boolean isStraight(Vec3d from, Vec3d to, double density) diff --git a/src/main/java/carpet/script/utils/ShapesRenderer.java b/src/main/java/carpet/script/utils/ShapesRenderer.java index 724475af..44dcad34 100644 --- a/src/main/java/carpet/script/utils/ShapesRenderer.java +++ b/src/main/java/carpet/script/utils/ShapesRenderer.java @@ -13,6 +13,7 @@ import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.nbt.CompoundTag; import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryKey; import net.minecraft.world.World; @@ -32,6 +33,7 @@ public class ShapesRenderer {{ put("line", RenderedLine::new); put("box", RenderedBox::new); + put("sphere", RenderedSphere::new); }}; public ShapesRenderer(MinecraftClient minecraftClient) @@ -93,12 +95,9 @@ public class ShapesRenderer if (shape == null) return; BiFunction> shapeFactory; shapeFactory = renderedShapes.get(tag.getString("shape")); - - - if (shapeFactory == null) { - CarpetSettings.LOG.error("Unrecognized shape: "+tag.getString("shape")); + CarpetSettings.LOG.info("Unrecognized shape: "+tag.getString("shape")); } else { @@ -163,9 +162,9 @@ public class ShapesRenderer @Override public void render(Tessellator tessellator, BufferBuilder bufferBuilder, float cx, float cy, float cz) { - RenderSystem.lineWidth(2.0F); - bufferBuilder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); // 3 - drawBoxWireGLLines(bufferBuilder, + RenderSystem.lineWidth(shape.lineWidth); + + drawBoxWireGLLines(tessellator, bufferBuilder, shape.x1 - cx-renderEpsilon, shape.y1 - cy-renderEpsilon, shape.z1 - cz-renderEpsilon, shape.x2 - cx+renderEpsilon, shape.y2 - cy+renderEpsilon, shape.z2 - cz+renderEpsilon, shape.r, shape.g, shape.b, shape.a, shape.r, shape.g, shape.b @@ -175,14 +174,15 @@ public class ShapesRenderer @Override public void render2pass(Tessellator tessellator, BufferBuilder bufferBuilder, float cx, float cy, float cz) { + if (shape.fa == 0.0) return; RenderSystem.lineWidth(1.0F); - bufferBuilder.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR); // 3 - drawBox(bufferBuilder, + + drawBoxFaces(tessellator, bufferBuilder, shape.x1-cx-renderEpsilon, shape.y1-cy-renderEpsilon, shape.z1-cz-renderEpsilon, shape.x2-cx+renderEpsilon, shape.y2-cy+renderEpsilon, shape.z2-cz+renderEpsilon, - shape.r, shape.g, shape.b, shape.a/6 + shape.fr, shape.fg, shape.fb, shape.fa ); - tessellator.draw(); + } } @@ -195,26 +195,43 @@ public class ShapesRenderer @Override public void render(Tessellator tessellator, BufferBuilder bufferBuilder, float cx, float cy, float cz) { - RenderSystem.lineWidth(2.0F); - bufferBuilder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); // 3 - drawLine(bufferBuilder, + RenderSystem.lineWidth(shape.lineWidth); + drawLine(tessellator, bufferBuilder, shape.x1-cx-renderEpsilon, shape.y1-cy-renderEpsilon, shape.z1-cz-renderEpsilon, shape.x2-cx+renderEpsilon, shape.y2-cy+renderEpsilon, shape.z2-cz+renderEpsilon, shape.r, shape.g, shape.b, shape.a ); - tessellator.draw(); + } + } + + public static class RenderedSphere extends RenderedShape + { + public RenderedSphere(MinecraftClient client, ShapeDispatcher.ExpiringShape shape) + { + super(client, (ShapeDispatcher.Sphere)shape); + } + @Override + public void render(Tessellator tessellator, BufferBuilder bufferBuilder, float cx, float cy, float cz) + { + RenderSystem.lineWidth(shape.lineWidth); + drawSphereWireframe(tessellator, bufferBuilder, + shape.cx-cx-renderEpsilon, shape.cy-cy-renderEpsilon, shape.cz-cz-renderEpsilon, + shape.radius, shape.subdivisions, + shape.r, shape.g, shape.b, shape.a); } } // some raw shit - public static void drawLine(BufferBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2, float red1, float grn1, float blu1, float alpha) { - + public static void drawLine(Tessellator tessellator, BufferBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2, float red1, float grn1, float blu1, float alpha) { + builder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); // 3 builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next(); builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); + tessellator.draw(); } - public static void drawBoxWireGLLines(BufferBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2, float red1, float grn1, float blu1, float alpha, float red2, float grn2, float blu2) { + public static void drawBoxWireGLLines(Tessellator tessellator, BufferBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2, float red1, float grn1, float blu1, float alpha, float red2, float grn2, float blu2) { + builder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); // 3 builder.vertex(x1, y1, z1).color(red1, grn2, blu2, alpha).next(); builder.vertex(x2, y1, z1).color(red1, grn2, blu2, alpha).next(); builder.vertex(x1, y1, z1).color(red2, grn1, blu2, alpha).next(); @@ -241,7 +258,8 @@ public class ShapesRenderer builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); } - public static void drawBox(BufferBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2, float red1, float grn1, float blu1, float alpha) { + public static void drawBoxFaces(Tessellator tessellator, BufferBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2, float red1, float grn1, float blu1, float alpha) { + builder.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR); // 3 builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next(); builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); @@ -271,5 +289,44 @@ public class ShapesRenderer builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); + tessellator.draw(); + } + + public static void drawSphereWireframe(Tessellator tessellator, BufferBuilder builder, + float cx, float cy, float cz, + float r, int subd, + float red, float grn, float blu, float alpha) + { + float pihalf = (float)(Math.PI / 180.0f); + float step = 180f / (subd/2); + for (float i = 0f; i <= 360.0f; i+=step) + { + builder.begin(GL11.GL_LINE_STRIP, VertexFormats.POSITION_COLOR); + float theta = i * pihalf; + for (float j = 0f; j <= 180.0f; j+=step) { + float phi = j * pihalf; + float x = r * MathHelper.sin(phi) * MathHelper.cos(theta); + float z = r * MathHelper.sin(phi) * MathHelper.sin(theta); + float y = r * MathHelper.cos(phi); + builder.vertex(x+cx, y+cy, z+cz).color(red, grn, blu, alpha).next(); + } + tessellator.draw(); + } + for (float j = 0f; j <= 180.0f; j+=step) + { + builder.begin(GL11.GL_LINE_LOOP, VertexFormats.POSITION_COLOR); + float phi = j * pihalf; + + for (float i = 0f; i <= 360.0f; i+=step) + { + float theta = i * pihalf; + float x = r * MathHelper.sin(phi) * MathHelper.cos(theta); + float z = r * MathHelper.sin(phi) * MathHelper.sin(theta); + float y = r * MathHelper.cos(phi); + builder.vertex(x+cx, y+cy, z+cz).color(red, grn, blu, alpha).next(); + } + tessellator.draw(); + } + } } diff --git a/src/main/java/carpet/script/value/FunctionValue.java b/src/main/java/carpet/script/value/FunctionValue.java index 14f6498d..3b872ccf 100644 --- a/src/main/java/carpet/script/value/FunctionValue.java +++ b/src/main/java/carpet/script/value/FunctionValue.java @@ -5,6 +5,7 @@ import carpet.script.Expression; import carpet.script.Fluff; import carpet.script.LazyValue; import carpet.script.Tokenizer; +import carpet.script.bundled.Module; import carpet.script.exception.BreakStatement; import carpet.script.exception.ContinueStatement; import carpet.script.exception.ExitStatement; @@ -58,6 +59,8 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction return name; } + public Module getModule() {return expression.module;} + @Override public String getPrettyString() { diff --git a/src/main/resources/assets/carpet/lang/zh_tw.json b/src/main/resources/assets/carpet/lang/zh_tw.json new file mode 100644 index 00000000..a3ede4a1 --- /dev/null +++ b/src/main/resources/assets/carpet/lang/zh_tw.json @@ -0,0 +1,234 @@ +{ + "rule.antiCheatDisabled.name": "關閉伺服器作弊檢測", + "rule.antiCheatDisabled.desc": "防止玩家因為“本伺服器不允許飛行”,“移動速度過快”等原因被請出伺服器", + + "rule.carpets.name": "放置地毯顯示進階數據", + "rule.carpets.desc": "通過把地毯放置在地上取得更進階信息", + + "rule.combineXPOrbs.name": "合併小經驗球", + "rule.combineXPOrbs.desc": "會將大量的小經驗球合併成等效的大經驗球", + + "rule.commandCameramode.name": "旁觀者模式", + "rule.commandCameramode.desc": "允許玩家使用/c切換成旁觀者模式,利用/s切換回生存模式", + "rule.commandCameramode.extra.0": "/c及/s不需要op權限也可使用", + + "rule.commandDistance.name": "距離測定", + "rule.commandDistance.desc": "使用/distance指令測定兩點的距離", + "rule.commandDistance.extra.0": "可以使用放置棕色地毯來使用此功能,前提是“放置地毯顯示進階數據”已啟用", + + "rule.commandDraw.name": "繪製圖形", + "rule.commandDraw.desc": "使用/draw指令以允許繪製一些簡易圖形", + + "rule.commandInfo.name": "獲取方塊進階資訊", + "rule.commandInfo.desc": "允許使用/info指令以獲得方塊進階資訊", + "rule.commandInfo.extra.0": "可以使用放置灰色地毯來使用此功能,前提是“放置地毯顯示進階數據”已啟用", + + "rule.commandLog.name": "遊戲數據追蹤器", + "rule.commandLog.desc": "允許使用/log指令使在Tab欄位追蹤遊戲部分數據", + + "rule.commandPerimeterInfo.name": "刷怪區域追蹤器", + "rule.commandPerimeterInfo.desc": "允許使用/perimeterinfo指令以探查周圍可生怪區域", + + "rule.commandPlayer.name": "機器人控制", + "rule.commandPlayer.desc": "允許使用/player指令以控制/召喚已存在的玩家id作為機器人", + + "rule.commandScript.name": "地毯腳本控制器", + "rule.commandScript.desc": "允許使用/script相關指令", + "rule.commandScript.extra.0": "一個Scarpet程式語言的遊戲內API", + + "rule.commandSpawn.name": "刷怪追蹤器", + "rule.commandSpawn.desc": "允許使用/spawn指令用於怪物生成追蹤", + + "rule.commandTick.name": "遊戲時鐘控制器", + "rule.commandTick.desc": "允許使用/tick指令控制遊戲內的伺服器端運行速度", + + "rule.commandTrackAI.name": "AI追蹤器", + "rule.commandTrackAI.desc": "允許使用/track指令以追蹤生物的AI", + + "rule.ctrlQCraftingFix.name": "ctrlQ合成修復", + "rule.ctrlQCraftingFix.desc": "在合成時允許使用ctrl+Q快捷鍵扔出結果格內所有物品", + + "rule.customMOTD.name": "MOTD更改", + "rule.customMOTD.desc": "設置一個不同的MOTD信息", + "rule.customMOTD.extra.0": "設置成'_'時將採用默認的MOTD(從server.properties中讀取的)", + + "rule.defaultLoggers.name": "默認開啟的遊戲數據追蹤器", + "rule.defaultLoggers.desc": "為所有新加入的玩家設置部分遊戲數據追蹤器默認為開啟狀態", + "rule.defaultLoggers.extra.0": "比如設置'tps,mobcaps'最為默認遊戲數據追蹤", + + "rule.desertShrubs.name": "樹苗在沙漠中乾枯", + "rule.desertShrubs.desc": "樹苗將在附近無水源狀態的沙漠生態群系變成枯灌木", + + "rule.disableSpawnChunks.name": "允許出生點區塊被卸載", + "rule.disableSpawnChunks.desc": "允許出生點區塊被卸載", + + "rule.explosionNoBlockDamage.name": "爆炸不破壞方塊", + "rule.explosionNoBlockDamage.desc": "任何形式的爆炸都無法摧毀方塊", + + "rule.extremeBehaviours.name": "隨機參數極端化", + "rule.extremeBehaviours.desc": "大幅度提升極端情況出現的概率,僅用於測試", + "rule.extremeBehaviours.extra.0": "發射器和投擲器將使用最大隨機刻", + + "rule.fastRedstoneDust.name": "紅石粉卡頓優化", + "rule.fastRedstoneDust.desc": "紅石粉卡頓優化 作者 Theosib", + + "rule.fillLimit.name": "fill/clone上限更改", + "rule.fillLimit.desc": "將fill/clone上限更改為自己設定的值", + "rule.fillLimit.extra.0": "你必須在1-2千萬之間取一個整數值", + + "rule.fillUpdates.name": "fill更新設置", + "rule.fillUpdates.desc": "fill/clone/setblock指令以及結構方塊執行時是否產生更新", + "rule.fillUpdates.extra.0": "設置為true時有更新 設置為false時為無更新", + + "rule.flatWorldStructureSpawning.name": "特定建築怪在超平坦世界生成", + "rule.flatWorldStructureSpawning.desc": "允許特定建築的怪物在超平坦世界生成", + + "rule.flippinCactus.name": "仙人掌扳手", + "rule.flippinCactus.desc": "允許使用仙人掌調整方塊朝向,並且不會造成更新", + + "rule.hardcodeTNTangle.name": "強制TNT角度", + "rule.hardcodeTNTangle.desc": "把TNT水平隨機角度設定為固定值,可用於測試機器", + "rule.hardcodeTNTangle.extra.0": "默認為-1,必須在0與360之間,或者-1", + + "rule.hopperCounters.name": "漏斗計數器", + "rule.hopperCounters.desc": "漏斗指向的羊毛方塊會計算吸收的物品並清除", + "rule.hopperCounters.extra.0": "在羊毛方塊上放置紅色或綠色地毯,使用/counter指令可啟用", + "rule.hopperCounters.extra.1": "使用 /counter reset重置計數器,使用/counter 查詢資訊", + "rule.hopperCounters.extra.2": "在生存模式,在同色羊毛上放置綠色地毯可以查詢,放紅色地毯重置", + "rule.hopperCounters.extra.3": "數據是全伺服器玩家共享的,並且有16色可以使用", + "rule.hopperCounters.extra.4": "物品會被銷毀,每個漏斗每tick銷毀一組物品", + + "rule.huskSpawningInTemples.name": "屍殼在沙漠神殿裡生成", + "rule.huskSpawningInTemples.desc": "只有屍殼會在沙漠神殿生成", + + "rule.lagFreeSpawning.name": "延遲自然生成", + "rule.lagFreeSpawning.desc": "生物生成需要更少的CPU和RAM", + + "rule.leadFix.name": "栓繩修復", + "rule.leadFix.desc": "修復栓繩在未加載區塊中,變得不可見的問題", + + "rule.maxEntityCollisions.name": "最大實體擠壓數量", + "rule.maxEntityCollisions.desc": "設定最大實體擠壓限制,0表示無限大", + + "rule.mergeTNT.name": "合併TNT", + "rule.mergeTNT.desc": "合併靜止的點燃的tnt實體", + + "rule.missingTools.name": "工具缺失修復", + "rule.missingTools.desc": "活塞,玻璃和海綿可以使用合適的工具更快地破壞", + + "rule.movableBlockEntities.name": "容器方塊移動", + "rule.movableBlockEntities.desc": "活塞可以推動具有容器標籤的方塊,比如箱子,漏斗", + + "rule.onePlayerSleeping.name": "單個玩家睡覺跳過夜晚", + "rule.onePlayerSleeping.desc": "只要伺服器中其中一人睡覺即可跳過全伺服器夜晚", + + "rule.optimizedTNT.name": "TNT優化", + "rule.optimizedTNT.desc": "tnt在相同位置或者在流體裡,爆炸將造成更低延遲", + + "rule.persistentParrots.name": "鸚鵡停留", + "rule.persistentParrots.desc": "鸚鵡不會離開你的肩膀,除非你受到傷害", + + "rule.placementRotationFix.name": "放置旋轉問題修復", + "rule.placementRotationFix.desc": "修復玩家放置方塊時快速轉身造成的問題", + + "rule.pushLimit.name": "自訂義推動上限", + "rule.pushLimit.desc": "自訂義活塞推動上限", + "rule.pushLimit.extra.0": "你必須在1-1024中選取一個值,預設是12", + + "rule.quasiConnectivity.name": "半連接激活開關", + "rule.quasiConnectivity.desc": "活塞,發射器和投擲器在他們上方方塊激活時是否響應", + "rule.quasiConnectivity.extra.0": "設置為true為開啟 設置為false為禁用", + + "rule.railPowerLimit.name": "自訂義動力鐵軌激活距離", + "rule.railPowerLimit.desc": "動力鐵軌激活距離能在此更改", + "rule.railPowerLimit.extra.0": "你必須在1-1024中選取一個數值", + + "rule.renewableCoral.name": "可再生珊瑚", + "rule.renewableCoral.desc": "使用骨粉可催熟珊瑚以長成珊瑚方塊結構", + + "rule.renewableSponges.name": "可再生海綿", + "rule.renewableSponges.desc": "深海守衛將在被雷擊後變成遠古深海守衛", + + "rule.rotatorBlock.name": "仙人掌扳手發射器版", + "rule.rotatorBlock.desc": "發射器中的仙人掌可以旋轉方塊(盡可能以逆時針)", + + "rule.scriptsAutoload.name": "Scarpet腳本自動加載", + "rule.scriptsAutoload.desc": "在伺服器/世界加載的時候將會自動從世界文件中加載Scarpet腳本文件", + "rule.scriptsAutoload.extra.0": "/script指令必須為啟用狀態", + + "rule.shulkerSpawningInEndCities.name": "可重生界伏蚌", + "rule.shulkerSpawningInEndCities.desc": "界伏蚌將會在終界城市中重生", + + "rule.silverFishDropGravel.name": "蠹魚鑽出放塊掉落礫石", + "rule.silverFishDropGravel.desc": "蠹魚鑽出放塊時會掉落礫石", + + "rule.smoothClientAnimations.name": "更平暢玩家端動畫", + "rule.smoothClientAnimations.desc": "降低TPS設置時可以使玩家端動畫更加平暢", + "rule.smoothClientAnimations.extra.0": "僅在單人模式中生效,並且會降低玩家端運行速度", + + "rule.stackableShulkerBoxes.name": "可堆疊界伏盒", + "rule.stackableShulkerBoxes.desc": "空的界伏盒扔在地上時將會自動堆疊,直到堆疊為1組", + "rule.stackableShulkerBoxes.extra.0": "在物品GUI中,請使用shift鍵+單擊以移動整組界伏盒", + + "rule.summonNaturalLightning.name": "召喚閃電自然化", + "rule.summonNaturalLightning.desc": "召喚的閃電將具有自然生成時的特性", + + "rule.tntDoNotUpdate.name": "TNT放置時不會被更新", + "rule.tntDoNotUpdate.desc": "TNT在放置時不會產生任何方塊更新(不會激活)", + + "rule.tntPrimerMomentumRemoved.name": "移除TNT點燃時隨機動量", + "rule.tntPrimerMomentumRemoved.desc": "TNT點燃時的隨機動量將被移除", + + "rule.tntRandomRange.name": "TNT爆炸範圍設置", + "rule.tntRandomRange.desc": "設置TNT隨機爆炸範圍為一個固定的值,設為-1以禁用", + "rule.tntRandomRange.extra.0": "必須啟用optimizedTNT功能", + "rule.tntRandomRange.extra.1": "不能設置為負數,除了-1", + + "rule.unloadedEntityFix.name": "未加載實體修復", + "rule.unloadedEntityFix.desc": "進入或者被推入未加載區塊的實體不會消失", + + "rule.viewDistance.name": "自訂義視野", + "rule.viewDistance.desc": "改變伺服器端視野距離,設置為0以使用默認值", + "rule.viewDistance.extra.0": "你必須在0(使用伺服器默認設置)-32取一個整數", + + "rule.xpNoCooldown.name": "經驗球吸收無冷卻", + "rule.xpNoCooldown.desc": "玩家吸收經驗球不會有冷卻時間", + + "rule.portalSuffocationFix.name": "傳送門窒息修復", + "rule.portalSuffocationFix.desc": "使地獄傳送門正確地傳送實體", + "rule.portalSuffocationFix.extra.0": "傳送的實體將不再卡在黑曜石裡", + + "rule.portalCreativeDelay.name": "創造模式玩家地獄門傳送延遲", + "rule.portalCreativeDelay.desc": "創造模式下使用地獄傳送門將同生存時產生延遲", + + + "category.bugfix": "BUG修復", + "category.survival": "生存用", + "category.creative": "創造用", + "category.experimental": "實驗用", + "category.optimization": "優化", + "category.feature": "特性", + "category.command": "指令", + "category.tnt": "TNT", + "category.dispenser": "發射器", + "category.scarpet": "scarpet腳本程式語言", + "category.client": "玩家端", + + "ui.browse_categories": "瀏覽分類", + "ui.list_all_%(cat)s_settings": "列出所有 %s 選項", + "ui.version": "版本", + "ui.current_%(mod)s_settings": "目前啟用的 %s 選項", + "ui.switch_to": "切換至", + "ui.settings_are_locked": "選項被鎖定", + "ui.is_set_to": "被設置為", + "ui.unknown_rule": "未知的規則選項", + "ui.current_%(mod)s_startup_settings_from_%(conf)s": "目前啟用的%s選項,從%s中讀取得", + "ui.%(mod)s_settings_matching_'%(query)s'": "%s中符合\"%s\"的選項:", + "ui.all_%(mod)s_settings": "所有的%s選項", + "ui.tags": "分類", + "ui.change_permanently": "設為預設", + "ui.click_to_keep_the_settings_in_%(conf)s_to_save_across_restarts": "點擊此按鈕以使此選項保存於%s,重啟後依舊生效", + "ui.rule_%(rule)s_will_now_default_to_%(value)s": "規則%s將會被默認設置為%s", + "ui.current_value": "當前的值" + +} diff --git a/src/main/resources/assets/carpet/scripts/event_test.sc b/src/main/resources/assets/carpet/scripts/event_test.sc index 036a0e38..1659d565 100644 --- a/src/main/resources/assets/carpet/scripts/event_test.sc +++ b/src/main/resources/assets/carpet/scripts/event_test.sc @@ -229,4 +229,18 @@ __on_player_changes_dimension(player, from_pos, from_dimension, to_pos, to_dimen print(' - player: '+player); print(' - from '+from_dimension+' at '+map(from_pos, str('%.2f',_))); print(' - to '+to_dimension+if(to_pos == null, '', ' at '+map(to_pos, str('%.2f',_)))); -) +); + +__on_player_connects(player) -> +( // you will never sees it + print(''); + print('__on_player_connects(player)'); + print('Player '+player+' connects.') +); + +__on_player_disconnects(player, reason) -> +( // you will never sees it either + print(''); + print('__on_player_disconnects(player)'); + print('Player '+player+' disconnects because: '+reason) +); diff --git a/src/main/resources/assets/carpet/scripts/overlay.sc b/src/main/resources/assets/carpet/scripts/overlay.sc index 8030a10c..ee703cec 100644 --- a/src/main/resources/assets/carpet/scripts/overlay.sc +++ b/src/main/resources/assets/carpet/scripts/overlay.sc @@ -12,7 +12,7 @@ global_renderers = m( l('active', false), l('handler', '__chunk_renderer'), l('tasks', m()), - l('range', 4) + l('range', 6) )), l('shapes', m( l('active', false), @@ -99,7 +99,7 @@ __structure_renderer(player_name) -> total_size = _euclidean(from, to); density = max(10, total_size/10); //particle_box('dust 0 1 1 2', from, to+1, density); - draw_shape('box', 15, 'from', from, 'to', to+1, 'color', 0x00FFFFFF); + draw_shape('box', 15, 'from', from, 'to', to+1, 'color', 0x00FFFFFF, 'width', 3); structure_pieces = slice(sort_key(structure_pieces, _euclidean_sq((_:2+_:3)/2,ppos)), 0, config:'max_pieces'); for (structure_pieces, l(piece, direction, from, to) = _; //factor = 1- _i / config:'max_pieces' / 2; @@ -110,8 +110,8 @@ __structure_renderer(player_name) -> g = r; b = 255; a = 255; - color = a+256*(b+256*(g+256*r)); - draw_shape('box', 15, 'from', from, 'to', to+1, 'color', color); + color = 256*(b+256*(g+256*r)); // leaving out a + draw_shape('box', 15, 'from', from, 'to', to+1, 'color', color+a, 'fill', color+a/6); ) ) ); @@ -126,10 +126,9 @@ __chunk_renderer(player_name) -> // get lower corner of the chunk ppos = map(pos(p)/16, floor(_))*16; ppos:1 = 0; - - r = config:'range'; - for(range(-r,r), cx =_; - for (range(-r,r), cz = _; + rang = config:'range'; + for(range(-rang,rang), cx =_; + for (range(-rang,rang), cz = _; ref_pos = ppos + l(16*cx,0,16*cz); if(has(config:'tasks':'slime_chunks') && in_slime_chunk(ref_pos), player_distance = _euclidean(ppos, ref_pos); @@ -142,12 +141,12 @@ __chunk_renderer(player_name) -> b = 30; a = max(0, 255-player_distance); color = a+256*(b+256*(g+256*r)); - draw_shape('box', 15, 'from', top_00, 'to', top_10, 'color', color); - draw_shape('box', 15, 'from', top_10, 'to', top_11, 'color', color); - draw_shape('box', 15, 'from', top_11, 'to', top_01, 'color', color); - draw_shape('box', 15, 'from', top_01, 'to', top_00, 'color', color); - draw_shape('box', 15, 'from', top_00, 'to', top_11, 'color', color); - draw_shape('box', 15, 'from', top_01, 'to', top_10, 'color', color); + draw_shape('line', 15, 'from', top_00, 'to', top_10, 'color', color, 'width', 3); + draw_shape('line', 15, 'from', top_10, 'to', top_11, 'color', color, 'width', 3); + draw_shape('line', 15, 'from', top_11, 'to', top_01, 'color', color, 'width', 3); + draw_shape('line', 15, 'from', top_01, 'to', top_00, 'color', color, 'width', 3); + draw_shape('line', 15, 'from', top_00, 'to', top_11, 'color', color, 'width', 3); + draw_shape('line', 15, 'from', top_01, 'to', top_10, 'color', color, 'width', 3); //part = 'dust 0.2 0.8 0.2 2'; //density = 2+player_distance/2;