Merge branch 'master' into 1.17

# Conflicts:
#	src/main/java/carpet/script/api/Inventories.java
#	src/main/java/carpet/script/api/WorldAccess.java
#	src/main/java/carpet/script/value/EntityValue.java
This commit is contained in:
gnembon committed 2021-03-07 16:39:17 -04:00
commit a82a9a60a3
17 files changed
+353 -18

No files matched your search

+78
View File
@@ -385,6 +385,83 @@ 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`. Uses the same file structure for exclusive app data, and shared data folder as `load_app_data`.
### `create_datapack(name, data)`
Creates and loads custom datapack. The data has to be a map representing the file structure and the content of the
json files of the target pack.
Returns `null` if the pack with this name already exists or is loaded, meaning no change has been made.
Returns `false` if adding of the datapack wasn't successful.
Returns `true` if creation and loading of the datapack was successful. Loading of a datapack results in
reloading of all other datapacks (vanilla restrictions, identical to /datapack enable), however unlike with `/reload`
command, scarpet apps will not be reloaded by adding a datapack using `create_datapack`.
Currently, only json files are supported in the packs. `'pack.mcmeta'` file is added automatically.
Reloading of datapacks that define new dimensions is not implemented in vanilla. Vanilla game only loads
dimension information on server start. `create_datapack` is therefore a direct replacement of manually ploping of the specified
file structure in a datapack file and calling `/datapack enable` on the new datapack with all its quirks and sideeffects
(like no worldgen changes, reloading all other datapacks, etc.). To enable newly added custom dimensions, call much more
experimental `check_hidden_dimensions()` after adding a datapack if needed.
Synopsis:
<pre>
script run create_datapack('foo',
{
'foo' -> {
'bar.json' -> {
'c' -> true,
'd' -> false,
'e' -> {'foo' -> [1,2,3]},
'a' -> 'foobar',
'b' -> 5
}
}
})
script run create_datapack('funky_world', {
'data' -> {
'minecraft' -> {
'dimension' -> {
'custom_ow.json' -> {
'type' -> 'minecraft:the_end',
'generator' -> {
'biome_source' -> {
'seed' -> 0,
'large_biomes' -> false,
'type' -> 'minecraft:vanilla_layered'
},
'seed' -> 0,
'settings' -> 'minecraft:nether',
'type' -> 'minecraft:noise'
}
}
}
}
}
});
check_hidden_dimensions(); => ['funky_world']
</pre>
### `enable_hidden_dimensions()`
The function reads current datapack settings detecting new dimensions defined by these datapacks that have not yet been added
to the list of current dimensions and adds them so that they can be used and accessed right away. It doesn't matter how the
datapacks have been added to the game, either with 'create_datapack()' or manually by dropping a datapack file and calling
`/datapack enable` on it. Returns the list of valid dimension names / identifiers that has been added in the process.
Fine print: The function should be
considered experimental. There 'should not be' (famous last words) any side-effects if no worlds are added. Already connected
clients will not see suggestions for commands that use dimensions `/execute in <dim>` (vanilla client limitation)
but all commands should work just fine with
the new dimensions. Existing worlds that have gotten modified settings by the datapacks will not be reloaded or replaced.
The usability of the dimensions added this way has not been fully tested, but it seems it works just fine. Generator settings
for the new dimensions will not be added to `'level.dat'` but it will be added there automatically next time the game restarts by
vanilla. One could have said to use this method with caution, and the authors take no responsibility of any losses incurred due to
mis-handlilng of the temporary added dimensions, yet the feature itself (custom dimensions) is clearly experimental for Mojang
themselves, so that's about it.
### `tick_time()` ### `tick_time()`
Returns server 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.
@@ -502,6 +579,7 @@ Available options in the scarpet app space:
Relevant world related properties Relevant world related properties
* `world_name` - name of the world * `world_name` - name of the world
* `world_seed` - a numeric seed of the world * `world_seed` - a numeric seed of the world
* `world_dimensions` - a list of dimensions in the world
* `world_path` - full path to the world saves folder * `world_path` - full path to the world saves folder
* `world_folder` - name of the direct folder in the saves that holds world files * `world_folder` - name of the direct folder in the saves that holds world files
* `world_carpet_rules` - returns all Carpet rules in a map form (`rule`->`value`). Note that the values are always returned as strings, so you can't do boolean comparisons directly. Includes rules from extensions with their namespace (`namespace:rule`->`value`). You can later listen to rule changes with the `on_carpet_rule_changes(rule, newValue)` event. * `world_carpet_rules` - returns all Carpet rules in a map form (`rule`->`value`). Note that the values are always returned as strings, so you can't do boolean comparisons directly. Includes rules from extensions with their namespace (`namespace:rule`->`value`). You can later listen to rule changes with the `on_carpet_rule_changes(rule, newValue)` event.
+3 -1
View File
@@ -779,7 +779,9 @@ All generated structures will retain their properties, like mob spawning, howeve
itself has certain rules to spawn mobs, like plopping a nether fortress in the overworld will not spawn nether mobs, itself has certain rules to spawn mobs, like plopping a nether fortress in the overworld will not spawn nether mobs,
because nether mobs can spawn only in the nether, but plopped in the nether - will behave like a valid nether fortress. because nether mobs can spawn only in the nether, but plopped in the nether - will behave like a valid nether fortress.
### `custom_dimension(name, seed?)` ### (deprecated) `custom_dimension(name, seed?)`
Deprecated by `create_datapack()` which can be used to setup custom dimensions
Ensures the dimension with the given `'name'` is available and configured with the given seed. It merely sets the world Ensures the dimension with the given `'name'` is available and configured with the given seed. It merely sets the world
generator settings to the overworld, and the optional custom seed (or using current world seed, if not provided). generator settings to the overworld, and the optional custom seed (or using current world seed, if not provided).
+2 -1
View File
@@ -17,9 +17,9 @@ brightness
chunk_tickets chunk_tickets
convert_date convert_date
crafting_remaining_item crafting_remaining_item
create_datapack
create_marker create_marker
current_dimension current_dimension
custom_dimension
day_time day_time
delete_file delete_file
destroy destroy
@@ -28,6 +28,7 @@ display_title
draw_shape draw_shape
drop_item drop_item
emitted_light emitted_light
enable_hidden_dimensions
encode_nbt encode_nbt
entity_area entity_area
entity_event entity_event
@@ -55,7 +55,7 @@
set without_updates set without_updates
blocks_movement block_sound material map_colour block_state block_list block_tags block_data poi set_poi blocks_movement block_sound material map_colour block_state block_list block_tags block_data poi set_poi
place_item set_biome biome loaded_status generation_status inhabited_time spawn_potential chunk_tickets place_item set_biome biome loaded_status generation_status inhabited_time spawn_potential chunk_tickets
structure_eligibility structures structure_references set_structure reset_chunk reload_chunk custom_dimension structure_eligibility structures structure_references set_structure reset_chunk reload_chunk create_datapack enable_hidden_dimensions
add_chunk_ticket add_chunk_ticket
convert_date unix_time convert_date unix_time
@@ -1,5 +1,6 @@
package carpet.fakes; package carpet.fakes;
import net.minecraft.resource.ServerResourceManager;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.registry.RegistryKey; import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.World; import net.minecraft.world.World;
@@ -13,4 +14,5 @@ public interface MinecraftServerInterface
void forceTick(BooleanSupplier sup); void forceTick(BooleanSupplier sup);
LevelStorage.Session getCMSession(); LevelStorage.Session getCMSession();
Map<RegistryKey<World>, ServerWorld> getCMWorlds(); Map<RegistryKey<World>, ServerWorld> getCMWorlds();
ServerResourceManager getResourceManager();
} }
@@ -2,6 +2,7 @@ package carpet.mixins;
import carpet.fakes.MinecraftServerInterface; import carpet.fakes.MinecraftServerInterface;
import carpet.helpers.TickSpeed; import carpet.helpers.TickSpeed;
import net.minecraft.resource.ServerResourceManager;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerTask; import net.minecraft.server.ServerTask;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
@@ -44,6 +45,8 @@ public abstract class MinecraftServer_scarpetMixin extends ReentrantThreadExecut
@Shadow @Final private Map<RegistryKey<World>, ServerWorld> worlds; @Shadow @Final private Map<RegistryKey<World>, ServerWorld> worlds;
@Shadow private ServerResourceManager serverResourceManager;
@Override @Override
public void forceTick(BooleanSupplier isAhead) public void forceTick(BooleanSupplier isAhead)
{ {
@@ -58,6 +61,11 @@ public abstract class MinecraftServer_scarpetMixin extends ReentrantThreadExecut
return session; return session;
} }
@Override
public ServerResourceManager getResourceManager() {
return serverResourceManager;
}
@Override @Override
public Map<RegistryKey<World>, ServerWorld> getCMWorlds() public Map<RegistryKey<World>, ServerWorld> getCMWorlds()
{ {
@@ -25,10 +25,4 @@ public class PlayerManager_coreMixin
CarpetServer.onPlayerLoggedIn(player); CarpetServer.onPlayerLoggedIn(player);
PLAYER_CONNECTS.onPlayerEvent(player); PLAYER_CONNECTS.onPlayerEvent(player);
} }
@Inject(method = "onDataPacksReloaded", at = @At("HEAD"))
private void onResourcesRefreshedReloadCommand(CallbackInfo ci)
{
CarpetServer.onReload(server);
}
} }
@@ -0,0 +1,23 @@
package carpet.mixins;
import carpet.CarpetServer;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.server.command.ReloadCommand;
import net.minecraft.server.command.ServerCommandSource;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ReloadCommand.class)
public class ReloadCommand_reloadAppsMixin {
//method_13530(Lcom/mojang/brigadier/context/CommandContext;)I
// internal of register.
@SuppressWarnings("UnresolvedMixinReference")
@Inject(method = "method_13530", at = @At("TAIL"))
private static void onReload(CommandContext<ServerCommandSource> context, CallbackInfoReturnable<Integer> cir)
{
// can't fetch here the reference to the server
CarpetServer.onReload(context.getSource().getMinecraftServer());
}
}
+206 -3
View File
@@ -20,6 +20,7 @@ import carpet.script.argument.Vector3Argument;
import carpet.script.exception.ExitStatement; import carpet.script.exception.ExitStatement;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.utils.FixedCommandSource; import carpet.script.utils.FixedCommandSource;
import carpet.script.utils.InputValidator;
import carpet.script.utils.ScarpetJsonDeserializer; import carpet.script.utils.ScarpetJsonDeserializer;
import carpet.script.utils.ShapeDispatcher; import carpet.script.utils.ShapeDispatcher;
import carpet.script.utils.WorldTools; import carpet.script.utils.WorldTools;
@@ -35,6 +36,10 @@ import carpet.script.value.StringValue;
import carpet.script.value.Value; import carpet.script.value.Value;
import carpet.script.value.ValueConversions; import carpet.script.value.ValueConversions;
import carpet.utils.Messenger; import carpet.utils.Messenger;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import net.minecraft.SharedConstants;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.command.DataCommandStorage; import net.minecraft.command.DataCommandStorage;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
@@ -45,6 +50,7 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtHelper; import net.minecraft.nbt.NbtHelper;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.StringTag; import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.Packet; import net.minecraft.network.Packet;
@@ -57,6 +63,11 @@ import net.minecraft.network.packet.s2c.play.SubtitleS2CPacket;
import net.minecraft.network.packet.s2c.play.TitleFadeS2CPacket; import net.minecraft.network.packet.s2c.play.TitleFadeS2CPacket;
import net.minecraft.network.packet.s2c.play.TitleS2CPacket; import net.minecraft.network.packet.s2c.play.TitleS2CPacket;
import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleEffect;
import net.minecraft.resource.DataPackSettings;
import net.minecraft.resource.ReloadableResourceManagerImpl;
import net.minecraft.resource.ResourcePackManager;
import net.minecraft.resource.ResourcePackProfile;
import net.minecraft.resource.ServerResourceManager;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
@@ -68,13 +79,27 @@ import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.InvalidIdentifierException; import net.minecraft.util.InvalidIdentifierException;
import net.minecraft.util.Util;
import net.minecraft.util.WorldSavePath;
import net.minecraft.util.dynamic.RegistryOps;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.EulerAngle; import net.minecraft.util.math.EulerAngle;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.registry.DynamicRegistryManager; import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.SaveProperties;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.biome.source.BiomeAccess;
import net.minecraft.world.border.WorldBorderListener;
import net.minecraft.world.dimension.DimensionOptions;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.GeneratorOptions;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.level.UnmodifiableLevelProperties;
import net.minecraft.world.level.storage.LevelStorage;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple; import org.apache.commons.lang3.tuple.Triple;
@@ -83,6 +108,13 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@@ -102,7 +134,7 @@ import static java.lang.Math.min;
public class Auxiliary { public class Auxiliary {
public static final String MARKER_STRING = "__scarpet_marker"; public static final String MARKER_STRING = "__scarpet_marker";
private static final Map<String, SoundCategory> mixerMap = Arrays.stream(SoundCategory.values()).collect(Collectors.toMap(SoundCategory::getName, k -> k)); private static final Map<String, SoundCategory> mixerMap = Arrays.stream(SoundCategory.values()).collect(Collectors.toMap(SoundCategory::getName, k -> k));
public static final Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().registerTypeAdapter(Value.class, new ScarpetJsonDeserializer()).create(); public static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().registerTypeAdapter(Value.class, new ScarpetJsonDeserializer()).create();
public static String recognizeResource(Value value, boolean isFloder) public static String recognizeResource(Value value, boolean isFloder)
{ {
@@ -862,7 +894,7 @@ public class Auxiliary {
exception = e.getCause(); exception = e.getCause();
throw new InternalExpressionException("Failed to read JSON file: "+exception.getMessage()); throw new InternalExpressionException("Failed to read JSON file: "+exception.getMessage());
} }
Value parsedJson = gson.fromJson(json, Value.class); Value parsedJson = GSON.fromJson(json, Value.class);
if (parsedJson == null) if (parsedJson == null)
retVal = Value.NULL; retVal = Value.NULL;
else else
@@ -901,7 +933,7 @@ public class Auxiliary {
} }
else if (fdesc.getMiddle().equals("json")) else if (fdesc.getMiddle().equals("json"))
{ {
List<String> data = Collections.singletonList(gson.toJson(lv.get(2).evalValue(c).toJson())); List<String> data = Collections.singletonList(GSON.toJson(lv.get(2).evalValue(c).toJson()));
((CarpetScriptHost) c.host).removeResourceFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle()); ((CarpetScriptHost) c.host).removeResourceFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle());
success = ((CarpetScriptHost) c.host).appendLogFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle(), data); success = ((CarpetScriptHost) c.host).appendLogFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle(), data);
} }
@@ -1072,7 +1104,178 @@ public class Auxiliary {
if (old_nbt == null) return LazyValue.NULL; if (old_nbt == null) return LazyValue.NULL;
return (_c, _t) -> new NBTSerializableValue(old_nbt); return (_c, _t) -> new NBTSerializableValue(old_nbt);
}); });
// script run create_datapack('foo', {'foo' -> {'bar.json' -> {'c' -> true,'d' -> false,'e' -> {'foo' -> [1,2,3]},'a' -> 'foobar','b' -> 5}}})
expression.addLazyFunction("create_datapack", 2, (c, t, lv) -> {
CarpetContext cc = (CarpetContext)c;
String origName = lv.get(0).evalValue(c).getString();
String name = InputValidator.validateSimpleString(origName, true);
MinecraftServer server = cc.s.getMinecraftServer();
for (String dpName : server.getDataPackManager().getNames())
{
if (dpName.equalsIgnoreCase("file/"+name+".zip") ||
dpName.equalsIgnoreCase("file/"+name))
return LazyValue.NULL;
} }
Value dpdata = lv.get(1).evalValue(c);
if (!(dpdata instanceof MapValue))
throw new InternalExpressionException("datapack data needs to be a valid map type");
ResourcePackManager packManager = server.getDataPackManager();
Path dbFloder = server.getSavePath(WorldSavePath.DATAPACKS);
Path packFloder = dbFloder.resolve(name+".zip");
if (Files.exists(packFloder) || Files.exists(dbFloder.resolve(name))) return LazyValue.NULL;
Boolean [] successful = new Boolean[]{true};
server.submitAndJoin( () ->
{
try {
//Files.createDirectory(packFloder);
try (FileSystem zipfs = FileSystems.newFileSystem(URI.create("jar:" + packFloder.toUri().toString()), ImmutableMap.of("create", "true"))) {
Path zipRoot = zipfs.getPath("/");
zipValueToJson(zipRoot.resolve("pack.mcmeta"), MapValue.wrap(
ImmutableMap.of(StringValue.of("pack"), MapValue.wrap(ImmutableMap.of(
StringValue.of("pack_format"), new NumericValue(SharedConstants.getGameVersion().getPackVersion()),
StringValue.of("description"), StringValue.of(name),
StringValue.of("source"), StringValue.of("scarpet")
)))
));
walkTheDPMap((MapValue) dpdata, zipRoot);
}
packManager.scanPacks();
ResourcePackProfile resourcePackProfile = packManager.getProfile("file/" + name + ".zip");
if (resourcePackProfile == null || packManager.getEnabledProfiles().contains(resourcePackProfile)) {
throw new IOException();
}
List<ResourcePackProfile> list = Lists.newArrayList(packManager.getEnabledProfiles());
resourcePackProfile.getInitialPosition().insert(list, resourcePackProfile, p -> p, false);
server.reloadResources(list.stream().map(ResourcePackProfile::getName).collect(Collectors.toList())).
exceptionally(exc -> {
successful[0] = false;
return null;
}).join();
if (!successful[0]) {
throw new IOException();
}
} catch (IOException e)
{
successful[0] = false;
try {
FileUtils.forceDelete(packFloder.toFile());
} catch (IOException ignored) {
throw new InternalExpressionException("Failed to install a datapack and failed to clean up after it");
}
}
});
return successful[0]?LazyValue.TRUE:LazyValue.FALSE;
});
expression.addLazyFunction("enable_hidden_dimensions", 0, (c, t, lv) -> {
CarpetContext cc = (CarpetContext)c;
// from minecraft.server.Main.main
MinecraftServer server = cc.s.getMinecraftServer();
LevelStorage.Session session = ((MinecraftServerInterface)server).getCMSession();
DataPackSettings dataPackSettings = session.getDataPackSettings();
ResourcePackManager resourcePackManager = server.getDataPackManager();
DataPackSettings dataPackSettings2 = MinecraftServer.loadDataPacks(resourcePackManager, dataPackSettings == null ? DataPackSettings.SAFE_MODE : dataPackSettings, false);
ServerResourceManager serverRM = ((MinecraftServerInterface)server).getResourceManager();
ReloadableResourceManagerImpl resourceManager = (ReloadableResourceManagerImpl) serverRM.getResourceManager();
//believe the other one will fillup based on the datapacks only.
resourceManager.close();
resourcePackManager.createResourcePacks().forEach(resourceManager::addPack);
//not sure its needed, but doesn't seem to have a negative effect and might be used in some custom shtuff
serverRM.loadRegistryTags();
RegistryOps<Tag> registryOps = RegistryOps.of(NbtOps.INSTANCE, serverRM.getResourceManager(), (DynamicRegistryManager.Impl) server.getRegistryManager());
SaveProperties saveProperties = session.readLevelProperties(registryOps, dataPackSettings2);
if (saveProperties == null) return LazyValue.NULL;
//session.backupLevelDataFile(server.getRegistryManager(), saveProperties); // no need
// MinecraftServer.createWorlds
// save properties should now contain dimension settings
GeneratorOptions generatorOptions = saveProperties.getGeneratorOptions();
boolean bl = generatorOptions.isDebugWorld();
long l = generatorOptions.getSeed();
long m = BiomeAccess.hashSeed(l);
Map<RegistryKey<World>, ServerWorld> existing_worlds = ((MinecraftServerInterface)server).getCMWorlds();
List<Value> addeds = new ArrayList<>();
for (Map.Entry<RegistryKey<DimensionOptions>, DimensionOptions> entry : generatorOptions.getDimensions().getEntries()) {
RegistryKey<DimensionOptions> registryKey = entry.getKey();
if (!existing_worlds.containsKey(registryKey))
{
addeds.add(ValueConversions.of(registryKey.getValue()));
RegistryKey<World> registryKey2 = RegistryKey.of(Registry.DIMENSION, registryKey.getValue());
DimensionType dimensionType3 = entry.getValue().getDimensionType();
ChunkGenerator chunkGenerator3 = entry.getValue().getChunkGenerator();
UnmodifiableLevelProperties unmodifiableLevelProperties = new UnmodifiableLevelProperties(saveProperties, saveProperties.getMainWorldProperties());
ServerWorld serverWorld2 = new ServerWorld(server, Util.getMainWorkerExecutor(), session, unmodifiableLevelProperties, registryKey2, dimensionType3, WorldTools.NOOP_LISTENER, chunkGenerator3, bl, m, ImmutableList.of(), false);
server.getOverworld().getWorldBorder().addListener(new WorldBorderListener.WorldBorderSyncer(serverWorld2.getWorldBorder()));
existing_worlds.put(registryKey2, serverWorld2);
}
}
Value ret = ListValue.wrap(addeds);
return (_c, _t) -> ret;
});
}
private static void zipValueToJson(Path path, Value output) throws IOException
{
JsonElement element = output.toJson();
if (element == null)
throw new InternalExpressionException("Cannot interpret "+output.getPrettyString()+" as a json object");
String string = GSON.toJson(element);
Files.createDirectories(path.getParent());
BufferedWriter bufferedWriter = Files.newBufferedWriter(path);
Throwable incident = null;
try
{
bufferedWriter.write(string);
}
catch (Throwable shitHappened)
{
incident = shitHappened;
throw shitHappened;
}
finally
{
if (incident != null) {
try {
bufferedWriter.close();
} catch (Throwable otherShitHappened) {
incident.addSuppressed(otherShitHappened);
}
} else {
bufferedWriter.close();
}
}
}
private static void walkTheDPMap(MapValue node, Path path) throws IOException
{
Map<Value,Value> items = node.getMap();
for (Map.Entry<Value, Value> entry : items.entrySet())
{
Value val = entry.getValue();
String strkey = entry.getKey().getString();
Path child = path.resolve(strkey);
if (strkey.endsWith(".json"))
{
zipValueToJson(child, val);
}
else
{
if (!(val instanceof MapValue)) throw new InternalExpressionException("Value of "+strkey+" should be a map");
Files.createDirectory(child);
walkTheDPMap((MapValue) val, child);
}
}
}
private static <T> Stat<T> getStat(StatType<T> type, Identifier id) private static <T> Stat<T> getStat(StatType<T> type, Identifier id)
{ {
@@ -91,7 +91,7 @@ public class Inventories {
Item item = NBTSerializableValue.parseItem(lv.get(0).evalValue(c).getString()).getItem(); Item item = NBTSerializableValue.parseItem(lv.get(0).evalValue(c).getString()).getItem();
if (lv.size() == 1) if (lv.size() == 1)
{ {
Value ret = ListValue.wrap(tagManager.getOrCreateTagGroup(Registry.ITEM_KEY).getTagsFor(item).stream().map(ValueConversions::of).collect(Collectors.toList())); Value ret = ListValue.wrap(tagManager.getOrCreateTagGroup(Registry.ITEM_KEY).getTags().entrySet().stream().filter(e -> e.getValue().contains(item)).map(e -> ValueConversions.of(e.getKey())).collect(Collectors.toList()));
return (_c, _t) -> ret; return (_c, _t) -> ret;
} }
String tag = lv.get(1).evalValue(c).getString(); String tag = lv.get(1).evalValue(c).getString();
@@ -1127,7 +1127,8 @@ public class WorldAccess {
BlockArgument blockLocator = BlockArgument.findIn(cc, lv, 0, true); BlockArgument blockLocator = BlockArgument.findIn(cc, lv, 0, true);
if (blockLocator.offset == lv.size()) if (blockLocator.offset == lv.size())
{ {
Value ret = ListValue.wrap(tagManager.getOrCreateTagGroup(Registry.BLOCK_KEY).getTagsFor(blockLocator.block.getBlockState().getBlock()).stream().map(ValueConversions::of).collect(Collectors.toList())); Block target = blockLocator.block.getBlockState().getBlock();
Value ret = ListValue.wrap(tagManager.getOrCreateTagGroup(Registry.BLOCK_KEY).getTags().entrySet().stream().filter(e -> e.getValue().contains(target)).map(e -> ValueConversions.of(e.getKey())).collect(Collectors.toList()));
return (_c, _t) -> ret; return (_c, _t) -> ret;
} }
String tag = lv.get(blockLocator.offset).evalValue(c).getString(); String tag = lv.get(blockLocator.offset).evalValue(c).getString();
@@ -1382,6 +1383,7 @@ public class WorldAccess {
{ {
if (lv.size() == 0) throw new InternalExpressionException("'custom_dimension' requires at least one argument"); if (lv.size() == 0) throw new InternalExpressionException("'custom_dimension' requires at least one argument");
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
cc.host.issueDeprecation("custom_dimension()");
String worldKey = lv.get(0).evalValue(c).getString(); String worldKey = lv.get(0).evalValue(c).getString();
Long seed = null; Long seed = null;
@@ -0,0 +1,16 @@
package carpet.script.utils;
import carpet.script.exception.InternalExpressionException;
import java.util.Locale;
public class InputValidator {
public static String validateSimpleString(String input, boolean strict)
{
String simplified = input.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9+_]", "");
if (simplified.isEmpty() || (strict && !simplified.equals(input)))
throw new InternalExpressionException("simple name can only contain numbers, letter and _");
return simplified;
}
}
@@ -9,6 +9,7 @@ import carpet.script.value.MapValue;
import carpet.script.value.NumericValue; import carpet.script.value.NumericValue;
import carpet.script.value.StringValue; import carpet.script.value.StringValue;
import carpet.script.value.Value; import carpet.script.value.Value;
import carpet.script.value.ValueConversions;
import carpet.settings.ParsedRule; import carpet.settings.ParsedRule;
import carpet.settings.SettingsManager; import carpet.settings.SettingsManager;
import com.sun.management.OperatingSystemMXBean; import com.sun.management.OperatingSystemMXBean;
@@ -49,6 +50,7 @@ public class SystemInfo {
String tlf = serverPath.getName(nodeCount-2).toString(); String tlf = serverPath.getName(nodeCount-2).toString();
return StringValue.of(tlf); return StringValue.of(tlf);
}); });
put("world_dimensions", c -> ListValue.wrap(c.s.getMinecraftServer().getWorldRegistryKeys().stream().map(k -> ValueConversions.of(k.getValue())).collect(Collectors.toList())));
put("game_difficulty", c -> StringValue.of(c.s.getMinecraftServer().getSaveProperties().getDifficulty().getName())); put("game_difficulty", c -> StringValue.of(c.s.getMinecraftServer().getSaveProperties().getDifficulty().getName()));
put("game_hardcore", c -> new NumericValue(c.s.getMinecraftServer().getSaveProperties().isHardcore())); put("game_hardcore", c -> new NumericValue(c.s.getMinecraftServer().getSaveProperties().isHardcore()));
put("game_storage_format", c -> StringValue.of(c.s.getMinecraftServer().getSaveProperties().getFormatName(c.s.getMinecraftServer().getSaveProperties().getVersion()))); put("game_storage_format", c -> StringValue.of(c.s.getMinecraftServer().getSaveProperties().getFormatName(c.s.getMinecraftServer().getSaveProperties().getVersion())));
@@ -157,5 +157,5 @@ public class WorldTools
@Override public void stop() { } @Override public void stop() { }
} }
private static final WorldGenerationProgressListener NOOP_LISTENER = new NoopWorldGenerationProgressListener(); public static final WorldGenerationProgressListener NOOP_LISTENER = new NoopWorldGenerationProgressListener();
} }
@@ -444,7 +444,7 @@ public class EntityValue extends Value
put("tags", (e, a) -> ListValue.wrap(e.getScoreboardTags().stream().map(StringValue::new).collect(Collectors.toList()))); put("tags", (e, a) -> ListValue.wrap(e.getScoreboardTags().stream().map(StringValue::new).collect(Collectors.toList())));
put("scoreboard_tags", (e, a) -> ListValue.wrap(e.getScoreboardTags().stream().map(StringValue::new).collect(Collectors.toList()))); put("scoreboard_tags", (e, a) -> ListValue.wrap(e.getScoreboardTags().stream().map(StringValue::new).collect(Collectors.toList())));
put("entity_tags", (e, a) -> ListValue.wrap(e.getServer().getTagManager().getOrCreateTagGroup(Registry.ENTITY_TYPE_KEY).getTagsFor(e.getType()).stream().map(ValueConversions::of).collect(Collectors.toList()))); put("entity_tags", (e, a) -> ListValue.wrap(e.getServer().getTagManager().getOrCreateTagGroup(Registry.ENTITY_TYPE_KEY).getTags().entrySet().stream().filter(entry -> entry.getValue().contains(e.getType())).map(entry -> ValueConversions.of(entry.getKey())).collect(Collectors.toList())));
// deprecated // deprecated
put("has_tag", (e, a) -> new NumericValue(e.getScoreboardTags().contains(a.getString()))); put("has_tag", (e, a) -> new NumericValue(e.getScoreboardTags().contains(a.getString())));
@@ -7,6 +7,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -16,7 +17,7 @@ import java.util.stream.Collectors;
public class MapValue extends AbstractListValue implements ContainerValueInterface public class MapValue extends AbstractListValue implements ContainerValueInterface
{ {
private Map<Value, Value> map; private final Map<Value, Value> map;
private MapValue() private MapValue()
{ {
@@ -268,7 +269,9 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
public JsonElement toJson() public JsonElement toJson()
{ {
JsonObject jsonMap = new JsonObject(); JsonObject jsonMap = new JsonObject();
map.forEach((k, v) -> jsonMap.add(k.getString(), v.toJson())); List<Value> keys = new ArrayList<>(map.keySet());
Collections.sort(keys);
keys.forEach( k -> jsonMap.add(k.getString(), map.get(k).toJson()));
return jsonMap; return jsonMap;
} }
} }
+1
View File
@@ -178,6 +178,7 @@
"PointOfInterest_scarpetMixin", "PointOfInterest_scarpetMixin",
"ServerWorld_scarpetMixin", "ServerWorld_scarpetMixin",
"HungerManagerMixin_scarpetEventsMixin", "HungerManagerMixin_scarpetEventsMixin",
"ReloadCommand_reloadAppsMixin",
"RecipeManager_scarpetMixin", "RecipeManager_scarpetMixin",
"Ingredient_scarpetMixin", "Ingredient_scarpetMixin",