Merge branch 'master' into 1.16
# Conflicts: # src/main/java/carpet/script/bundled/Module.java
This commit is contained in:
commit
a757c6f88a
15 files changed
+217
-62
No files matched your search
+43
-10
@@ -2932,10 +2932,13 @@ Collection of other methods that control smaller, yet still important aspects of
|
|||||||
|
|
||||||
## Sounds
|
## Sounds
|
||||||
|
|
||||||
### `sound(name, pos, volume?, pitch?)`
|
### `sound(name, pos, volume?, pitch?, mixer?)`
|
||||||
|
|
||||||
Plays a specific sound `name`, at block or position `pos`, with optional `volume` and modified `pitch`. `pos` can be
|
Plays a specific sound `name`, at block or position `pos`, with optional `volume` and modified `pitch`, and under
|
||||||
either a block, triple of coords, or a list of thee numbers. Uses the same options as a corresponding `playsound` command.
|
optional `mixer`. Default values for `volume`, `pitch` and `mixer` are `1.0`, `1.0`, and `master`.
|
||||||
|
Valid mixer options are `master`, `music`, `record`, `weather`, `block`, `hostile`,`neutral`, `player`, `ambient`
|
||||||
|
and `voice`. `pos` can be either a block, triple of coords, or a list of thee numbers. Uses the same options as a
|
||||||
|
corresponding `playsound` command.
|
||||||
|
|
||||||
## Particles
|
## Particles
|
||||||
|
|
||||||
@@ -3004,23 +3007,52 @@ run('give @s stone 4') -> 1 // this operation was successful once
|
|||||||
Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled due to
|
Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled due to
|
||||||
performance reasons and saves the world only on demand.
|
performance reasons and saves the world only on demand.
|
||||||
|
|
||||||
### `load_app_data(), load_app_data(file)`
|
### `load_app_data(), load_app_data(file), load_app_data(file, shared?)`
|
||||||
|
|
||||||
Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
||||||
managed and buffered / throttled NBT tag. With a file name - reads explicitly a file with that name from the
|
managed and buffered / throttled NBT tag. With a file name - reads explicitly a file with that name from the
|
||||||
scripts folder.
|
scripts folder that belongs exclusively to the app. if `shared` is true, the file location is not exclusive
|
||||||
|
to the app anymore, but located in a shared app space.
|
||||||
|
|
||||||
|
File descriptor can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
||||||
|
from the name before saving/loading. Empty descriptors are invalid.
|
||||||
|
|
||||||
|
Function returns nbt value with the file content, or `null` if the file is missing or there were problems
|
||||||
|
with retrieving the data.
|
||||||
|
|
||||||
|
The default no-name app, via `/script run` command can only save/load file from the shared data location.
|
||||||
|
|
||||||
|
If the app's name is `'foo'`, the script location would
|
||||||
|
be `world/scripts/foo.sc`, system-managed default app data storage is in `world/scripts/foo.data.nbt`, app
|
||||||
|
specific data directory is under `world/scripts/foo.data/bar/../baz.nbt`, and shared data space is under
|
||||||
|
`world/scripts/shared/bar/../baz.nbt`.
|
||||||
|
|
||||||
You can use app data to save non-vanilla information separately from the world and other scripts.
|
You can use app data to save non-vanilla information separately from the world and other scripts.
|
||||||
|
|
||||||
### `store_app_data(tag), store_app_data(tag, file)`
|
### `store_app_data(tag), store_app_data(tag, file), store_app_data(tag, file, shared?)`
|
||||||
|
|
||||||
Stores the app data associated with the app from the world /scripts folder. With the `file` parameter saves
|
Stores the app data associated with the app from the world `/scripts` folder. With the `file` parameter saves
|
||||||
immediately and with every call, without `file` parameter, it may take up to 10 seconds for the output file
|
immediately and with every call to a specific file defined by the `file`, either in app space, or in the scripts
|
||||||
|
shared space if `shared` is true. Without `file` parameter, it may take up to 10
|
||||||
|
seconds for the output file
|
||||||
to sync preventing flickering in case this tag changes frequently. It will be synced when server closes.
|
to sync preventing flickering in case this tag changes frequently. It will be synced when server closes.
|
||||||
|
|
||||||
|
Returns `true` if the file was saved successfully, `false` otherwise.
|
||||||
|
|
||||||
|
Uses the same file structure for exclusive app data, and shared data folder as `load_app_data`.
|
||||||
|
|
||||||
### `tick_time()`
|
### `tick_time()`
|
||||||
|
|
||||||
Returns game tick counter. Can be used to run certain operations every n-th ticks, or to count in-game time
|
Returns server tick counter. Can be used to run certain operations every n-th ticks, or to count in-game time.
|
||||||
|
|
||||||
|
### `world_time()`
|
||||||
|
|
||||||
|
Returns dimension-specific tick counter.
|
||||||
|
|
||||||
|
### `day_time(new_time?)`
|
||||||
|
|
||||||
|
Returns current daytime clock value. If `new_time` is specified, sets a new clock
|
||||||
|
to that value. Daytime clocks are shared between all dimensions.
|
||||||
|
|
||||||
### `game_tick(mstime?)`
|
### `game_tick(mstime?)`
|
||||||
|
|
||||||
@@ -3071,7 +3103,8 @@ For the options of `entry`, consult your statistics page, or give it a guess.
|
|||||||
The call will return `null` if the statistics options are incorrect, or player didn't get these in their history.
|
The call will return `null` if the statistics options are incorrect, or player didn't get these in their history.
|
||||||
If the player encountered the statistic, or game created for him empty one, it will return a number.
|
If the player encountered the statistic, or game created for him empty one, it will return a number.
|
||||||
Scarpet will not affect the entries of the statistics, even if it is just creating empty ones. With `null` response
|
Scarpet will not affect the entries of the statistics, even if it is just creating empty ones. With `null` response
|
||||||
it could either mean your input is wrong, or statistic has effectively a value of `0`.# `/script run` command
|
it could either mean your input is wrong, or statistic has effectively a value of `0`.
|
||||||
|
# `/script run` command
|
||||||
|
|
||||||
Primary way to input commands. The command executes in the context, position, and dimension of the executing player,
|
Primary way to input commands. The command executes in the context, position, and dimension of the executing player,
|
||||||
commandblock, etc... The command receives 4 variables, `x`, `y`, `z` and `p` indicating position and
|
commandblock, etc... The command receives 4 variables, `x`, `y`, `z` and `p` indicating position and
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ Collection of other methods that control smaller, yet still important aspects of
|
|||||||
|
|
||||||
## Sounds
|
## Sounds
|
||||||
|
|
||||||
### `sound(name, pos, volume?, pitch?)`
|
### `sound(name, pos, volume?, pitch?, mixer?)`
|
||||||
|
|
||||||
Plays a specific sound `name`, at block or position `pos`, with optional `volume` and modified `pitch`. `pos` can be
|
Plays a specific sound `name`, at block or position `pos`, with optional `volume` and modified `pitch`, and under
|
||||||
either a block, triple of coords, or a list of thee numbers. Uses the same options as a corresponding `playsound` command.
|
optional `mixer`. Default values for `volume`, `pitch` and `mixer` are `1.0`, `1.0`, and `master`.
|
||||||
|
Valid mixer options are `master`, `music`, `record`, `weather`, `block`, `hostile`,`neutral`, `player`, `ambient`
|
||||||
|
and `voice`. `pos` can be either a block, triple of coords, or a list of thee numbers. Uses the same options as a
|
||||||
|
corresponding `playsound` command.
|
||||||
|
|
||||||
## Particles
|
## Particles
|
||||||
|
|
||||||
@@ -76,23 +79,52 @@ run('give @s stone 4') -> 1 // this operation was successful once
|
|||||||
Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled due to
|
Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled due to
|
||||||
performance reasons and saves the world only on demand.
|
performance reasons and saves the world only on demand.
|
||||||
|
|
||||||
### `load_app_data(), load_app_data(file)`
|
### `load_app_data(), load_app_data(file), load_app_data(file, shared?)`
|
||||||
|
|
||||||
Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
||||||
managed and buffered / throttled NBT tag. With a file name - reads explicitly a file with that name from the
|
managed and buffered / throttled NBT tag. With a file name - reads explicitly a file with that name from the
|
||||||
scripts folder.
|
scripts folder that belongs exclusively to the app. if `shared` is true, the file location is not exclusive
|
||||||
|
to the app anymore, but located in a shared app space.
|
||||||
|
|
||||||
|
File descriptor can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
||||||
|
from the name before saving/loading. Empty descriptors are invalid.
|
||||||
|
|
||||||
|
Function returns nbt value with the file content, or `null` if the file is missing or there were problems
|
||||||
|
with retrieving the data.
|
||||||
|
|
||||||
|
The default no-name app, via `/script run` command can only save/load file from the shared data location.
|
||||||
|
|
||||||
|
If the app's name is `'foo'`, the script location would
|
||||||
|
be `world/scripts/foo.sc`, system-managed default app data storage is in `world/scripts/foo.data.nbt`, app
|
||||||
|
specific data directory is under `world/scripts/foo.data/bar/../baz.nbt`, and shared data space is under
|
||||||
|
`world/scripts/shared/bar/../baz.nbt`.
|
||||||
|
|
||||||
You can use app data to save non-vanilla information separately from the world and other scripts.
|
You can use app data to save non-vanilla information separately from the world and other scripts.
|
||||||
|
|
||||||
### `store_app_data(tag), store_app_data(tag, file)`
|
### `store_app_data(tag), store_app_data(tag, file), store_app_data(tag, file, shared?)`
|
||||||
|
|
||||||
Stores the app data associated with the app from the world /scripts folder. With the `file` parameter saves
|
Stores the app data associated with the app from the world `/scripts` folder. With the `file` parameter saves
|
||||||
immediately and with every call, without `file` parameter, it may take up to 10 seconds for the output file
|
immediately and with every call to a specific file defined by the `file`, either in app space, or in the scripts
|
||||||
|
shared space if `shared` is true. Without `file` parameter, it may take up to 10
|
||||||
|
seconds for the output file
|
||||||
to sync preventing flickering in case this tag changes frequently. It will be synced when server closes.
|
to sync preventing flickering in case this tag changes frequently. It will be synced when server closes.
|
||||||
|
|
||||||
|
Returns `true` if the file was saved successfully, `false` otherwise.
|
||||||
|
|
||||||
|
Uses the same file structure for exclusive app data, and shared data folder as `load_app_data`.
|
||||||
|
|
||||||
### `tick_time()`
|
### `tick_time()`
|
||||||
|
|
||||||
Returns game tick counter. Can be used to run certain operations every n-th ticks, or to count in-game time
|
Returns server tick counter. Can be used to run certain operations every n-th ticks, or to count in-game time.
|
||||||
|
|
||||||
|
### `world_time()`
|
||||||
|
|
||||||
|
Returns dimension-specific tick counter.
|
||||||
|
|
||||||
|
### `day_time(new_time?)`
|
||||||
|
|
||||||
|
Returns current daytime clock value. If `new_time` is specified, sets a new clock
|
||||||
|
to that value. Daytime clocks are shared between all dimensions.
|
||||||
|
|
||||||
### `game_tick(mstime?)`
|
### `game_tick(mstime?)`
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ brightness
|
|||||||
chunk_tickets
|
chunk_tickets
|
||||||
create_marker
|
create_marker
|
||||||
current_dimension
|
current_dimension
|
||||||
|
day_time
|
||||||
destroy
|
destroy
|
||||||
diamond
|
diamond
|
||||||
drop_item
|
drop_item
|
||||||
@@ -96,3 +97,4 @@ transparent
|
|||||||
update
|
update
|
||||||
volume
|
volume
|
||||||
without_updates
|
without_updates
|
||||||
|
world_time
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
|
|
||||||
logger sound particle particle_line particle_rect
|
logger sound particle particle_line particle_rect
|
||||||
|
|
||||||
run save tick_time game_tick seed current_dimension in_dimension
|
run save tick_time world_time day_time game_tick seed current_dimension in_dimension
|
||||||
|
|
||||||
plop harvest destroy schedule nbt create_marker remove_all_markers load_app_data store_app_data escape_nbt statistic
|
plop harvest destroy schedule nbt create_marker remove_all_markers load_app_data store_app_data escape_nbt statistic
|
||||||
</Keywords>
|
</Keywords>
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ public class TickCommand
|
|||||||
c.getSource(),
|
c.getSource(),
|
||||||
getInteger(c,"ticks"),
|
getInteger(c,"ticks"),
|
||||||
getString(c, "tail command")))))).
|
getString(c, "tail command")))))).
|
||||||
then(literal("freeze").executes( (c)-> toggleFreeze(c.getSource()))).
|
then(literal("freeze").executes( (c)-> toggleFreeze(c.getSource(), false)).
|
||||||
|
then(literal("deep").executes( (c)-> toggleFreeze(c.getSource(), true)))).
|
||||||
then(literal("step").
|
then(literal("step").
|
||||||
executes((c) -> step(1)).
|
executes((c) -> step(1)).
|
||||||
then(argument("ticks", integer(1,72000)).
|
then(argument("ticks", integer(1,72000)).
|
||||||
@@ -95,15 +96,18 @@ public class TickCommand
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int toggleFreeze(ServerCommandSource source)
|
private static int toggleFreeze(ServerCommandSource source, boolean isDeep)
|
||||||
{
|
{
|
||||||
TickSpeed.is_paused = !TickSpeed.is_paused;
|
TickSpeed.is_paused = !TickSpeed.is_paused;
|
||||||
if (TickSpeed.is_paused)
|
if (TickSpeed.is_paused)
|
||||||
{
|
{
|
||||||
Messenger.m(source, "gi Game is paused");
|
TickSpeed.deepFreeze = isDeep;
|
||||||
|
Messenger.m(source, "gi Game is "+(isDeep?"deeply ":"")+"frozen");
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
TickSpeed.deepFreeze = false;
|
||||||
Messenger.m(source, "gi Game runs normally");
|
Messenger.m(source, "gi Game runs normally");
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public class TickSpeed
|
|||||||
public static ServerCommandSource tick_warp_sender = null;
|
public static ServerCommandSource tick_warp_sender = null;
|
||||||
public static int player_active_timeout = 0;
|
public static int player_active_timeout = 0;
|
||||||
public static boolean process_entities = true;
|
public static boolean process_entities = true;
|
||||||
|
public static boolean deepFreeze = false;
|
||||||
public static boolean is_paused = false;
|
public static boolean is_paused = false;
|
||||||
public static boolean is_superHot = false;
|
public static boolean is_superHot = false;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ public class TNTLogHelper
|
|||||||
{
|
{
|
||||||
public boolean initialized;
|
public boolean initialized;
|
||||||
private double primedX, primedY, primedZ;
|
private double primedX, primedY, primedZ;
|
||||||
|
private static long lastGametime = 0;
|
||||||
|
private static int tntCount = 0;
|
||||||
private Vec3d primedAngle;
|
private Vec3d primedAngle;
|
||||||
/**
|
/**
|
||||||
* Runs when the TNT is primed. Expects the position and motion angle of the TNT.
|
* Runs when the TNT is primed. Expects the position and motion angle of the TNT.
|
||||||
@@ -24,8 +26,13 @@ public class TNTLogHelper
|
|||||||
/**
|
/**
|
||||||
* Runs when the TNT explodes. Expects the position of the TNT.
|
* Runs when the TNT explodes. Expects the position of the TNT.
|
||||||
*/
|
*/
|
||||||
public void onExploded(double x, double y, double z)
|
public void onExploded(double x, double y, double z, long gametime)
|
||||||
{
|
{
|
||||||
|
if (!(lastGametime == gametime)){
|
||||||
|
tntCount = 0;
|
||||||
|
lastGametime = gametime;
|
||||||
|
}
|
||||||
|
tntCount++;
|
||||||
LoggerRegistry.getLogger("tnt").log( (option) -> {
|
LoggerRegistry.getLogger("tnt").log( (option) -> {
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
@@ -36,6 +43,10 @@ public class TNTLogHelper
|
|||||||
"r E ",Messenger.dblt("r",x, y, z))};
|
"r E ",Messenger.dblt("r",x, y, z))};
|
||||||
case "full":
|
case "full":
|
||||||
return new BaseText[]{Messenger.c(
|
return new BaseText[]{Messenger.c(
|
||||||
|
"g #" + String.valueOf(tntCount),
|
||||||
|
"m @" + String.valueOf(gametime),
|
||||||
|
"g : ",
|
||||||
|
"g #" + String.valueOf(tntCount) + ": ",
|
||||||
"l P ",Messenger.dblf("l",primedX,primedY,primedZ),
|
"l P ",Messenger.dblf("l",primedX,primedY,primedZ),
|
||||||
"w ",Messenger.dblf("l", primedAngle.x, primedAngle.y, primedAngle.z),
|
"w ",Messenger.dblf("l", primedAngle.x, primedAngle.y, primedAngle.z),
|
||||||
"r E ",Messenger.dblf("r",x, y, z))};
|
"r E ",Messenger.dblf("r",x, y, z))};
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package carpet.mixins;
|
||||||
|
|
||||||
|
import carpet.helpers.TickSpeed;
|
||||||
|
import net.minecraft.server.world.ChunkTicketManager;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(ChunkTicketManager.class)
|
||||||
|
public class ChunkTicketManager_tickMixin
|
||||||
|
{
|
||||||
|
@Shadow private long age;
|
||||||
|
|
||||||
|
@Inject(method = "purge", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void pauseTicketSystem(CallbackInfo ci)
|
||||||
|
{
|
||||||
|
// pausing expiry of tickets
|
||||||
|
// that will prevent also chunks from unloading, so require a deep frozen state
|
||||||
|
if (!TickSpeed.process_entities && TickSpeed.deepFreeze) age--;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -117,7 +117,7 @@ public abstract class MinecraftServer_tickspeedMixin extends ReentrantThreadExec
|
|||||||
this.startMonitor(tickDurationMonitor);
|
this.startMonitor(tickDurationMonitor);
|
||||||
this.profiler.startTick();
|
this.profiler.startTick();
|
||||||
this.profiler.push("tick");
|
this.profiler.push("tick");
|
||||||
this.tick(TickSpeed.time_warp_start_time != 0 ? ()->true : this::shouldKeepTicking);
|
this.tick(TickSpeed.time_warp_start_time != 0 ? ()->!hasRunningTasks() : this::shouldKeepTicking);
|
||||||
this.profiler.swap("nextTickWait");
|
this.profiler.swap("nextTickWait");
|
||||||
this.waitingForNextTick = true;
|
this.waitingForNextTick = true;
|
||||||
this.field_19248 = Math.max(Util.getMeasuringTimeMs() + /*50L*/ msThisTick, this.timeReference);
|
this.field_19248 = Math.max(Util.getMeasuringTimeMs() + /*50L*/ msThisTick, this.timeReference);
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public abstract class TntEntityMixin extends Entity implements TntEntityInterfac
|
|||||||
private void onExplode(CallbackInfo ci)
|
private void onExplode(CallbackInfo ci)
|
||||||
{
|
{
|
||||||
if (LoggerRegistry.__tnt && logHelper != null)
|
if (LoggerRegistry.__tnt && logHelper != null)
|
||||||
logHelper.onExploded(getX(), getY(), getZ());
|
logHelper.onExploded(getX(), getY(), getZ(), this.world.getTime());
|
||||||
|
|
||||||
if (mergedTNT > 1)
|
if (mergedTNT > 1)
|
||||||
for (int i = 0; i < mergedTNT - 1; i++)
|
for (int i = 0; i < mergedTNT - 1; i++)
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ import java.util.Optional;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collector;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static carpet.script.utils.WorldTools.canHasChunk;
|
import static carpet.script.utils.WorldTools.canHasChunk;
|
||||||
@@ -2377,6 +2378,8 @@ public class CarpetExpression
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Map<String,SoundCategory> mixerMap = Arrays.stream(SoundCategory.values()).collect(Collectors.toMap(SoundCategory::getName, k -> k));
|
||||||
|
|
||||||
private void API_AuxiliaryAspects()
|
private void API_AuxiliaryAspects()
|
||||||
{
|
{
|
||||||
this.expr.addLazyFunction("sound", -1, (c, t, lv) -> {
|
this.expr.addLazyFunction("sound", -1, (c, t, lv) -> {
|
||||||
@@ -2387,12 +2390,19 @@ public class CarpetExpression
|
|||||||
throw new InternalExpressionException("No such sound: "+soundName.getPath());
|
throw new InternalExpressionException("No such sound: "+soundName.getPath());
|
||||||
float volume = 1.0F;
|
float volume = 1.0F;
|
||||||
float pitch = 1.0F;
|
float pitch = 1.0F;
|
||||||
|
SoundCategory mixer = SoundCategory.MASTER;
|
||||||
if (lv.size() > 0+locator.offset)
|
if (lv.size() > 0+locator.offset)
|
||||||
{
|
{
|
||||||
volume = (float) NumericValue.asNumber(lv.get(0+locator.offset).evalValue(c)).getDouble();
|
volume = (float) NumericValue.asNumber(lv.get(0+locator.offset).evalValue(c)).getDouble();
|
||||||
if (lv.size() > 1+locator.offset)
|
if (lv.size() > 1+locator.offset)
|
||||||
{
|
{
|
||||||
pitch = (float) NumericValue.asNumber(lv.get(1+locator.offset).evalValue(c)).getDouble();
|
pitch = (float) NumericValue.asNumber(lv.get(1+locator.offset).evalValue(c)).getDouble();
|
||||||
|
if (lv.size() > 2+locator.offset)
|
||||||
|
{
|
||||||
|
String mixerName = lv.get(2+locator.offset).evalValue(c).getString();
|
||||||
|
mixer = mixerMap.get(mixerName.toLowerCase(Locale.ROOT));
|
||||||
|
if (mixer == null) throw new InternalExpressionException(mixerName +" is not a valid mixer name");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Vec3d vec = locator.vec;
|
Vec3d vec = locator.vec;
|
||||||
@@ -2401,7 +2411,7 @@ public class CarpetExpression
|
|||||||
for (ServerPlayerEntity player : cc.s.getWorld().getPlayers( (p) -> p.squaredDistanceTo(vec) < d0))
|
for (ServerPlayerEntity player : cc.s.getWorld().getPlayers( (p) -> p.squaredDistanceTo(vec) < d0))
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
player.networkHandler.sendPacket(new PlaySoundIdS2CPacket(soundName, SoundCategory.PLAYERS, vec, volume, pitch));
|
player.networkHandler.sendPacket(new PlaySoundIdS2CPacket(soundName, mixer, vec, volume, pitch));
|
||||||
}
|
}
|
||||||
int totalPlayed = count;
|
int totalPlayed = count;
|
||||||
return (_c, _t) -> new NumericValue(totalPlayed);
|
return (_c, _t) -> new NumericValue(totalPlayed);
|
||||||
@@ -2658,6 +2668,24 @@ public class CarpetExpression
|
|||||||
return (cc, tt) -> time;
|
return (cc, tt) -> time;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.expr.addLazyFunction("world_time", 0, (c, t, lv) ->
|
||||||
|
{
|
||||||
|
Value time = new NumericValue(((CarpetContext) c).s.getWorld().getTime());
|
||||||
|
return (cc, tt) -> time;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.expr.addLazyFunction("day_time", -1, (c, t, lv) ->
|
||||||
|
{
|
||||||
|
Value time = new NumericValue(((CarpetContext) c).s.getWorld().getTimeOfDay());
|
||||||
|
if (lv.size() > 0)
|
||||||
|
{
|
||||||
|
long newTime = NumericValue.asNumber(lv.get(0).evalValue(c)).getLong();
|
||||||
|
if (newTime < 0) newTime = 0;
|
||||||
|
((CarpetContext) c).s.getWorld().setTimeOfDay(newTime);
|
||||||
|
}
|
||||||
|
return (cc, tt) -> time;
|
||||||
|
});
|
||||||
|
|
||||||
this.expr.addLazyFunction("game_tick", -1, (c, t, lv) -> {
|
this.expr.addLazyFunction("game_tick", -1, (c, t, lv) -> {
|
||||||
ServerCommandSource s = ((CarpetContext)c).s;
|
ServerCommandSource s = ((CarpetContext)c).s;
|
||||||
if (!s.getMinecraftServer().isOnThread()) throw new InternalExpressionException("Unable to run ticks from threads");
|
if (!s.getMinecraftServer().isOnThread()) throw new InternalExpressionException("Unable to run ticks from threads");
|
||||||
@@ -2794,16 +2822,22 @@ public class CarpetExpression
|
|||||||
this.expr.addLazyFunction("load_app_data", -1, (c, t, lv) ->
|
this.expr.addLazyFunction("load_app_data", -1, (c, t, lv) ->
|
||||||
{
|
{
|
||||||
String file = null;
|
String file = null;
|
||||||
|
boolean shared = false;
|
||||||
if (lv.size()>0)
|
if (lv.size()>0)
|
||||||
{
|
{
|
||||||
String origfile = lv.get(0).evalValue(c).getString();
|
String origfile = lv.get(0).evalValue(c).getString();
|
||||||
file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9]", "");
|
file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9/]", "");
|
||||||
|
file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/"));
|
||||||
if (file.isEmpty())
|
if (file.isEmpty())
|
||||||
{
|
{
|
||||||
throw new InternalExpressionException("Cannot use "+file+" as resource name - must have some letters and numbers");
|
throw new InternalExpressionException("Cannot use "+origfile+" as resource name - must have at least some letters and numbers");
|
||||||
|
}
|
||||||
|
if (lv.size() > 1)
|
||||||
|
{
|
||||||
|
shared = lv.get(1).evalValue(c).getBoolean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).getGlobalState(file);
|
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).getGlobalState(file, shared);
|
||||||
if (state == null)
|
if (state == null)
|
||||||
return (cc, tt) -> Value.NULL;
|
return (cc, tt) -> Value.NULL;
|
||||||
Value retVal = new NBTSerializableValue(state);
|
Value retVal = new NBTSerializableValue(state);
|
||||||
@@ -2816,21 +2850,27 @@ public class CarpetExpression
|
|||||||
throw new InternalExpressionException("'store_app_data' needs NBT tag and an optional file");
|
throw new InternalExpressionException("'store_app_data' needs NBT tag and an optional file");
|
||||||
Value val = lv.get(0).evalValue(c);
|
Value val = lv.get(0).evalValue(c);
|
||||||
String file = null;
|
String file = null;
|
||||||
|
boolean shared = false;
|
||||||
if (lv.size()>1)
|
if (lv.size()>1)
|
||||||
{
|
{
|
||||||
String origfile = lv.get(1).evalValue(c).getString();
|
String origfile = lv.get(1).evalValue(c).getString();
|
||||||
file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9]", "");
|
file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9/]", "");
|
||||||
|
file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/"));
|
||||||
if (file.isEmpty())
|
if (file.isEmpty())
|
||||||
{
|
{
|
||||||
throw new InternalExpressionException("Cannot use "+file+" as resource name - must have some letters and numbers");
|
throw new InternalExpressionException("Cannot use "+origfile+" as resource name - must have some letters and numbers");
|
||||||
|
}
|
||||||
|
if (lv.size() > 2)
|
||||||
|
{
|
||||||
|
shared = lv.get(2).evalValue(c).getBoolean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NBTSerializableValue tagValue = (val instanceof NBTSerializableValue)
|
NBTSerializableValue tagValue = (val instanceof NBTSerializableValue)
|
||||||
? (NBTSerializableValue) val
|
? (NBTSerializableValue) val
|
||||||
: new NBTSerializableValue(val.getString());
|
: new NBTSerializableValue(val.getString());
|
||||||
Tag tag = tagValue.getTag();
|
Tag tag = tagValue.getTag();
|
||||||
((CarpetScriptHost)((CarpetContext)c).host).setGlobalState(tag, file);
|
boolean success = ((CarpetScriptHost)((CarpetContext)c).host).setGlobalState(tag, file, shared);
|
||||||
return (cc, tt) -> Value.NULL;
|
return success?LazyValue.TRUE:LazyValue.FALSE;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.expr.addLazyFunction("statistic", 3, (c, t, lv) ->
|
this.expr.addLazyFunction("statistic", 3, (c, t, lv) ->
|
||||||
|
|||||||
@@ -361,32 +361,31 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
|
|
||||||
private void dumpState()
|
private void dumpState()
|
||||||
{
|
{
|
||||||
main.saveData(null, globalState);
|
Module.saveData(main, null, globalState, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tag loadState()
|
private Tag loadState()
|
||||||
{
|
{
|
||||||
return main.getData(null);
|
return Module.getData(main, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tag getGlobalState(String file)
|
public Tag getGlobalState(String file, boolean isShared)
|
||||||
{
|
{
|
||||||
if (getName() == null ) return null;
|
if (getName() == null && !isShared) return null;
|
||||||
if (file != null)
|
if (file != null)
|
||||||
return main.getData(file);
|
return Module.getData(main, file, isShared);
|
||||||
if (parent == null)
|
if (parent == null)
|
||||||
return globalState;
|
return globalState;
|
||||||
return ((CarpetScriptHost)parent).globalState;
|
return ((CarpetScriptHost)parent).globalState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGlobalState(Tag tag, String file)
|
public boolean setGlobalState(Tag tag, String file, boolean isShared)
|
||||||
{
|
{
|
||||||
if (getName() == null ) return;
|
if (getName() == null && !isShared) return false; // if belongs to an app, cannot be default host.
|
||||||
|
|
||||||
if (file!= null)
|
if (file!= null)
|
||||||
{
|
{
|
||||||
main.saveData(file, tag);
|
return Module.saveData(main, file, tag, isShared);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CarpetScriptHost responsibleHost = (parent != null)?(CarpetScriptHost) parent:this;
|
CarpetScriptHost responsibleHost = (parent != null)?(CarpetScriptHost) parent:this;
|
||||||
@@ -396,6 +395,7 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
responsibleHost.dumpState();
|
responsibleHost.dumpState();
|
||||||
responsibleHost.saveTimeout = 200;
|
responsibleHost.saveTimeout = 200;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick()
|
public void tick()
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class FileModule extends Module
|
|||||||
}
|
}
|
||||||
|
|
||||||
//copied private method from net.minecraft.nbt.NbtIo.write() and client method safe_write
|
//copied private method from net.minecraft.nbt.NbtIo.write() and client method safe_write
|
||||||
public static void write(Tag tag_1, File file)
|
public static boolean write(Tag tag_1, File file)
|
||||||
{
|
{
|
||||||
File file_2 = new File(file.getAbsolutePath() + "_tmp");
|
File file_2 = new File(file.getAbsolutePath() + "_tmp");
|
||||||
if (file_2.exists()) file_2.delete();
|
if (file_2.exists()) file_2.delete();
|
||||||
@@ -90,9 +90,10 @@ public class FileModule extends Module
|
|||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (file.exists()) file.delete();
|
if (file.exists()) file.delete();
|
||||||
if (!file.exists()) file_2.renameTo(file);
|
if (!file.exists()) file_2.renameTo(file);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,6 @@ import carpet.CarpetServer;
|
|||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
|
||||||
import static carpet.script.bundled.FileModule.read;
|
import static carpet.script.bundled.FileModule.read;
|
||||||
@@ -16,28 +15,36 @@ public abstract class Module
|
|||||||
public abstract String getCode();
|
public abstract String getCode();
|
||||||
public abstract boolean isLibrary();
|
public abstract boolean isLibrary();
|
||||||
|
|
||||||
public Tag getData(String file)
|
private static String getDescriptor(Module module, String file, boolean isShared)
|
||||||
{
|
{
|
||||||
File dataFile = CarpetServer.minecraft_server.method_27050().resolve("scripts/"+getName()+".data"+(file==null?"":"."+file)+".nbt").toFile();
|
if (isShared)
|
||||||
|
{
|
||||||
|
return "shared/"+file;
|
||||||
|
}
|
||||||
|
else if (module != null && module.getName() != null) // appdata
|
||||||
|
{
|
||||||
|
return module.getName()+".data"+(file==null?"":"/"+file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Invalid file descriptor: "+file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tag getData(Module module, String file, boolean isShared)
|
||||||
|
{
|
||||||
|
if (!isShared && (module == null || module.getName() == null)) return null;
|
||||||
|
File dataFile = CarpetServer.minecraft_server.method_27050().resolve("scripts/"+getDescriptor(module, file, isShared)+".nbt").toFile();
|
||||||
if (!Files.exists(dataFile.toPath()) || !(dataFile.isFile())) return null;
|
if (!Files.exists(dataFile.toPath()) || !(dataFile.isFile())) return null;
|
||||||
return read(dataFile);
|
return read(dataFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveData(String file, Tag globalState)
|
public static boolean saveData(Module module, String file, Tag globalState, boolean isShared)
|
||||||
{
|
{
|
||||||
File dataFile =CarpetServer.minecraft_server.method_27050().resolve("scripts/"+getName()+".data"+(file==null?"":"."+file)+".nbt").toFile();
|
if (!isShared && (module == null || module.getName() == null)) return false;
|
||||||
if (!Files.exists(dataFile.toPath().getParent()))
|
File dataFile =CarpetServer.minecraft_server.method_27050().resolve("scripts/"+getDescriptor(module, file, isShared)+".nbt").toFile();
|
||||||
{
|
if (!Files.exists(dataFile.toPath().getParent()) && !dataFile.getParentFile().mkdirs()) return false;
|
||||||
try
|
return write(globalState, dataFile);
|
||||||
{
|
|
||||||
Files.createDirectory(dataFile.toPath().getParent());
|
|
||||||
}
|
|
||||||
catch (IOException ignored)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write(globalState, dataFile);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
"ServerWorld_tickMixin",
|
"ServerWorld_tickMixin",
|
||||||
"ServerChunkManager_tickMixin",
|
"ServerChunkManager_tickMixin",
|
||||||
"ThreadedAnvilChunkStorage_tickMixin",
|
"ThreadedAnvilChunkStorage_tickMixin",
|
||||||
|
"ChunkTicketManager_tickMixin",
|
||||||
|
|
||||||
"ThreadedAnvilChunkStorage_scarpetChunkCreationMixin",
|
"ThreadedAnvilChunkStorage_scarpetChunkCreationMixin",
|
||||||
"ChunkHolder_scarpetChunkCreationMixin",
|
"ChunkHolder_scarpetChunkCreationMixin",
|
||||||
|
|||||||
Reference in new issue
Block a user