Merge branch 'master' into 1.16

This commit is contained in:
gnembon committed 2020-06-03 03:47:55 -03:00
commit bf2d412a66
19 files changed
+690 -78

No files matched your search

+69 -8
View File
@@ -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.
<pre>
start_time = time();
@@ -1513,7 +1516,7 @@ range(5,10) => [5, 6, 7, 8, 9]
range(20, 10, -2) => [20, 18, 16, 14, 12]
</pre>
### `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
</pre>
@@ -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...)`
+48 -10
View File
@@ -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...)`
+2
View File
@@ -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
</pre>
@@ -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
+3 -1
View File
@@ -30,4 +30,6 @@ __on_tick_nether
__on_player_takes_damage
__on_player_deals_damage
__on_player_dies
__on_player_respawns
__on_player_respawns
__on_player_disconnects
__on_player_connects
@@ -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
</Keywords>
<Keywords name="Keywords3">euler pi null true false</Keywords>
<Keywords name="Keywords4">x y z p</Keywords>
@@ -110,6 +112,8 @@
__on_player_deals_damage
__on_player_dies
__on_player_respawns
__on_player_disconnects
__on_player_connects
</Keywords>
<Keywords name="Keywords8">$</Keywords>
<Keywords name="Delimiters">00&apos; 01\ 02&apos; 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23</Keywords>
+1 -1
View File
@@ -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
)
@@ -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);
}
}
@@ -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());
}
}
@@ -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);
});
@@ -128,7 +128,13 @@ public class CarpetEventServer
List<LazyValue> 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<Callback> 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<ScriptHost, Boolean> 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 <T> Identifier getStatId(Stat<T> 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) { }
@@ -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);
@@ -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.
@@ -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<String, Value> userParams)
{
userParams.put("shape", new StringValue(shapeType));
Map<String, Value> 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<Map<String, Value>,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<Tag, Value> 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<Map<String, Value>,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<String, Function<Map<String, Value>,ExpiringShape>> shapeProviders = new HashMap<String, Function<Map<String, Value>, ExpiringShape>>(){{
put("line", creator(Line::new));
put("box", creator(Box::new));
put("sphere", creator(Sphere::new));
}};
private static Function<Map<String, Value>,ExpiringShape> creator(Supplier<ExpiringShape> shapeFactory)
{
@@ -229,7 +231,10 @@ public class ShapeDispatcher
}
// list of params that need to be there
private final Set<String> required = ImmutableSet.of("duration", "shape", "dim");
private final Map<String, Value> optional = ImmutableMap.of("color", new NumericValue(-1));
private final Map<String, Value> optional = ImmutableMap.of(
"color", new NumericValue(-1),
"player", Value.NULL
);
protected Set<String> requiredParams() {return required;}
// list of params that can be there, with defaults
protected Set<String> optionalParams() {return optional.keySet();}
@@ -238,7 +243,10 @@ public class ShapeDispatcher
public static class Box extends ExpiringShape
{
private final Set<String> required = ImmutableSet.of("from", "to");
private final Map<String, Value> optional = ImmutableMap.of();
private final Map<String, Value> optional = ImmutableMap.of(
"width", new NumericValue(2.0),
"fill", new NumericValue(0xffffff00)
);
@Override
protected Set<String> 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<String, Value> 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<String> required = ImmutableSet.of("from", "to");
private final Map<String, Value> optional = ImmutableMap.of();
private final Map<String, Value> optional = ImmutableMap.of("width", new NumericValue(2.0));
@Override
protected Set<String> 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<String, Value> 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<String> required = ImmutableSet.of("center", "radius");
private final Map<String, Value> optional = ImmutableMap.of("width", new NumericValue(2.0), "level", Value.ZERO);
@Override
protected Set<String> requiredParams() { return Sets.union(super.requiredParams(), required); }
@Override
protected Set<String> 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<String, Value> options)
{
super.init(options);
List<Value> 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<ServerPlayerEntity> 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<partno; i++)
{
float theta = 360.0f*rand.nextFloat()*pihalf;
float phi = 180f*rand.nextFloat()*pihalf;
float x = radius * MathHelper.sin(phi) * MathHelper.cos(theta);
float y = radius * MathHelper.sin(phi) * MathHelper.sin(theta);
float z = radius * MathHelper.cos(phi);
world.spawnParticles(p, particle, true,
x+cx, y+cy, z+cz, 1,
0.0, 0.0, 0.0, 0.0);
}
};}
@Override
public int calcKey()
{
int hash = super.calcKey();
hash = 31*hash + 3;
hash = 31*hash + Float.hashCode(cx);
hash = 31*hash + Float.hashCode(cy);
hash = 31*hash + Float.hashCode(cz);
hash = 31*hash + Float.hashCode(radius);
hash = 31*hash + level;
hash = 31*hash + Float.hashCode(lineWidth);
return hash;
}
}
public interface Param
{
Map<String, Function<Tag, Value>> decoders = new HashMap<String, Function<Tag, Value>>(){{
@@ -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<String, Param> coders = new HashMap<String, Param>(){{
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)
@@ -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<MinecraftClient, ShapeDispatcher.ExpiringShape, RenderedShape<? extends ShapeDispatcher.ExpiringShape >> 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<ShapeDispatcher.Sphere>
{
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();
}
}
}
@@ -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()
{
@@ -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 <color?> reset重置計數器,使用/counter <color?>查詢資訊",
"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": "當前的值"
}
@@ -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)
);
@@ -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;