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
+219
-64
No files matched your search
+43
-10
@@ -2932,10 +2932,13 @@ Collection of other methods that control smaller, yet still important aspects of
|
||||
|
||||
## 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
|
||||
either a block, triple of coords, or a list of thee numbers. Uses the same options as a corresponding `playsound` command.
|
||||
Plays a specific sound `name`, at block or position `pos`, with optional `volume` and modified `pitch`, and under
|
||||
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
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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.
|
||||
|
||||
### `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
|
||||
immediately and with every call, without `file` parameter, it may take up to 10 seconds for the output file
|
||||
Stores the app data associated with the app from the world `/scripts` folder. With the `file` parameter saves
|
||||
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.
|
||||
|
||||
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()`
|
||||
|
||||
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?)`
|
||||
|
||||
@@ -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.
|
||||
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
|
||||
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,
|
||||
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
|
||||
|
||||
### `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
|
||||
either a block, triple of coords, or a list of thee numbers. Uses the same options as a corresponding `playsound` command.
|
||||
Plays a specific sound `name`, at block or position `pos`, with optional `volume` and modified `pitch`, and under
|
||||
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
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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.
|
||||
|
||||
### `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
|
||||
immediately and with every call, without `file` parameter, it may take up to 10 seconds for the output file
|
||||
Stores the app data associated with the app from the world `/scripts` folder. With the `file` parameter saves
|
||||
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.
|
||||
|
||||
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()`
|
||||
|
||||
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?)`
|
||||
|
||||
@@ -143,4 +175,4 @@ 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.
|
||||
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
|
||||
it could either mean your input is wrong, or statistic has effectively a value of `0`.
|
||||
it could either mean your input is wrong, or statistic has effectively a value of `0`.
|
||||
@@ -13,6 +13,7 @@ brightness
|
||||
chunk_tickets
|
||||
create_marker
|
||||
current_dimension
|
||||
day_time
|
||||
destroy
|
||||
diamond
|
||||
drop_item
|
||||
@@ -95,4 +96,5 @@ top
|
||||
transparent
|
||||
update
|
||||
volume
|
||||
without_updates
|
||||
without_updates
|
||||
world_time
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
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
|
||||
</Keywords>
|
||||
|
||||
@@ -43,7 +43,8 @@ public class TickCommand
|
||||
c.getSource(),
|
||||
getInteger(c,"ticks"),
|
||||
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").
|
||||
executes((c) -> step(1)).
|
||||
then(argument("ticks", integer(1,72000)).
|
||||
@@ -95,15 +96,18 @@ public class TickCommand
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int toggleFreeze(ServerCommandSource source)
|
||||
private static int toggleFreeze(ServerCommandSource source, boolean isDeep)
|
||||
{
|
||||
TickSpeed.is_paused = !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
|
||||
{
|
||||
TickSpeed.deepFreeze = false;
|
||||
Messenger.m(source, "gi Game runs normally");
|
||||
}
|
||||
return 1;
|
||||
|
||||
@@ -25,6 +25,7 @@ public class TickSpeed
|
||||
public static ServerCommandSource tick_warp_sender = null;
|
||||
public static int player_active_timeout = 0;
|
||||
public static boolean process_entities = true;
|
||||
public static boolean deepFreeze = false;
|
||||
public static boolean is_paused = false;
|
||||
public static boolean is_superHot = false;
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ public class TNTLogHelper
|
||||
{
|
||||
public boolean initialized;
|
||||
private double primedX, primedY, primedZ;
|
||||
private static long lastGametime = 0;
|
||||
private static int tntCount = 0;
|
||||
private Vec3d primedAngle;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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) -> {
|
||||
switch (option)
|
||||
{
|
||||
@@ -36,6 +43,10 @@ public class TNTLogHelper
|
||||
"r E ",Messenger.dblt("r",x, y, z))};
|
||||
case "full":
|
||||
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),
|
||||
"w ",Messenger.dblf("l", primedAngle.x, primedAngle.y, primedAngle.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.profiler.startTick();
|
||||
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.waitingForNextTick = true;
|
||||
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)
|
||||
{
|
||||
if (LoggerRegistry.__tnt && logHelper != null)
|
||||
logHelper.onExploded(getX(), getY(), getZ());
|
||||
logHelper.onExploded(getX(), getY(), getZ(), this.world.getTime());
|
||||
|
||||
if (mergedTNT > 1)
|
||||
for (int i = 0; i < mergedTNT - 1; i++)
|
||||
|
||||
@@ -131,6 +131,7 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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()
|
||||
{
|
||||
this.expr.addLazyFunction("sound", -1, (c, t, lv) -> {
|
||||
@@ -2387,12 +2390,19 @@ public class CarpetExpression
|
||||
throw new InternalExpressionException("No such sound: "+soundName.getPath());
|
||||
float volume = 1.0F;
|
||||
float pitch = 1.0F;
|
||||
SoundCategory mixer = SoundCategory.MASTER;
|
||||
if (lv.size() > 0+locator.offset)
|
||||
{
|
||||
volume = (float) NumericValue.asNumber(lv.get(0+locator.offset).evalValue(c)).getDouble();
|
||||
if (lv.size() > 1+locator.offset)
|
||||
{
|
||||
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;
|
||||
@@ -2401,7 +2411,7 @@ public class CarpetExpression
|
||||
for (ServerPlayerEntity player : cc.s.getWorld().getPlayers( (p) -> p.squaredDistanceTo(vec) < d0))
|
||||
{
|
||||
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;
|
||||
return (_c, _t) -> new NumericValue(totalPlayed);
|
||||
@@ -2658,6 +2668,24 @@ public class CarpetExpression
|
||||
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) -> {
|
||||
ServerCommandSource s = ((CarpetContext)c).s;
|
||||
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) ->
|
||||
{
|
||||
String file = null;
|
||||
boolean shared = false;
|
||||
if (lv.size()>0)
|
||||
{
|
||||
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())
|
||||
{
|
||||
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)
|
||||
return (cc, tt) -> Value.NULL;
|
||||
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");
|
||||
Value val = lv.get(0).evalValue(c);
|
||||
String file = null;
|
||||
boolean shared = false;
|
||||
if (lv.size()>1)
|
||||
{
|
||||
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())
|
||||
{
|
||||
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) val
|
||||
: new NBTSerializableValue(val.getString());
|
||||
Tag tag = tagValue.getTag();
|
||||
((CarpetScriptHost)((CarpetContext)c).host).setGlobalState(tag, file);
|
||||
return (cc, tt) -> Value.NULL;
|
||||
boolean success = ((CarpetScriptHost)((CarpetContext)c).host).setGlobalState(tag, file, shared);
|
||||
return success?LazyValue.TRUE:LazyValue.FALSE;
|
||||
});
|
||||
|
||||
this.expr.addLazyFunction("statistic", 3, (c, t, lv) ->
|
||||
|
||||
@@ -361,32 +361,31 @@ public class CarpetScriptHost extends ScriptHost
|
||||
|
||||
private void dumpState()
|
||||
{
|
||||
main.saveData(null, globalState);
|
||||
Module.saveData(main, null, globalState, false);
|
||||
}
|
||||
|
||||
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)
|
||||
return main.getData(file);
|
||||
return Module.getData(main, file, isShared);
|
||||
if (parent == null)
|
||||
return 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)
|
||||
{
|
||||
main.saveData(file, tag);
|
||||
return;
|
||||
return Module.saveData(main, file, tag, isShared);
|
||||
}
|
||||
|
||||
CarpetScriptHost responsibleHost = (parent != null)?(CarpetScriptHost) parent:this;
|
||||
@@ -396,6 +395,7 @@ public class CarpetScriptHost extends ScriptHost
|
||||
responsibleHost.dumpState();
|
||||
responsibleHost.saveTimeout = 200;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
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");
|
||||
if (file_2.exists()) file_2.delete();
|
||||
@@ -90,9 +90,10 @@ public class FileModule extends Module
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (file.exists()) file.delete();
|
||||
if (!file.exists()) file_2.renameTo(file);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import carpet.CarpetServer;
|
||||
import net.minecraft.nbt.Tag;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import static carpet.script.bundled.FileModule.read;
|
||||
@@ -16,28 +15,36 @@ public abstract class Module
|
||||
public abstract String getCode();
|
||||
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;
|
||||
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 (!Files.exists(dataFile.toPath().getParent()))
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.createDirectory(dataFile.toPath().getParent());
|
||||
}
|
||||
catch (IOException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
write(globalState, dataFile);
|
||||
|
||||
if (!isShared && (module == null || module.getName() == null)) return false;
|
||||
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;
|
||||
return write(globalState, dataFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"ServerWorld_tickMixin",
|
||||
"ServerChunkManager_tickMixin",
|
||||
"ThreadedAnvilChunkStorage_tickMixin",
|
||||
"ChunkTicketManager_tickMixin",
|
||||
|
||||
"ThreadedAnvilChunkStorage_scarpetChunkCreationMixin",
|
||||
"ChunkHolder_scarpetChunkCreationMixin",
|
||||
|
||||
Reference in new issue
Block a user