Merge branch 'master' into display-title-additions
This commit is contained in:
88 files changed
+3088
-1017
No files matched your search
@@ -3,11 +3,13 @@ package carpet.script.api;
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.fakes.MinecraftServerInterface;
|
||||
import carpet.fakes.ServerWorldInterface;
|
||||
import carpet.fakes.StatTypeInterface;
|
||||
import carpet.fakes.ThreadedAnvilChunkStorageInterface;
|
||||
import carpet.helpers.FeatureGenerator;
|
||||
import carpet.mixins.PlayerListHeaderS2CPacketMixin;
|
||||
import carpet.script.bundled.Module;
|
||||
import carpet.script.argument.FileArgument;
|
||||
import carpet.script.CarpetContext;
|
||||
import carpet.script.CarpetEventServer;
|
||||
import carpet.script.CarpetScriptHost;
|
||||
@@ -20,7 +22,10 @@ import carpet.script.argument.FunctionArgument;
|
||||
import carpet.script.argument.Vector3Argument;
|
||||
import carpet.script.exception.ExitStatement;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.exception.ThrowStatement;
|
||||
import carpet.script.exception.Throwables;
|
||||
import carpet.script.utils.FixedCommandSource;
|
||||
import carpet.script.utils.InputValidator;
|
||||
import carpet.script.utils.ScarpetJsonDeserializer;
|
||||
import carpet.script.utils.ShapeDispatcher;
|
||||
import carpet.script.utils.WorldTools;
|
||||
@@ -36,6 +41,10 @@ import carpet.script.value.StringValue;
|
||||
import carpet.script.value.Value;
|
||||
import carpet.script.value.ValueConversions;
|
||||
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.command.DataCommandStorage;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -46,6 +55,7 @@ import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtHelper;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.nbt.StringTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.packet.s2c.play.PlaySoundIdS2CPacket;
|
||||
@@ -53,6 +63,11 @@ import net.minecraft.network.packet.s2c.play.PlayerListHeaderS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.TitleS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.TitleS2CPacket.Action;
|
||||
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.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
@@ -64,21 +79,42 @@ import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.InvalidIdentifierException;
|
||||
import net.minecraft.util.crash.CrashException;
|
||||
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.ChunkPos;
|
||||
import net.minecraft.util.math.EulerAngle;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.registry.DynamicRegistryManager;
|
||||
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.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.Triple;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
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.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -97,8 +133,9 @@ import static java.lang.Math.min;
|
||||
public class Auxiliary {
|
||||
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));
|
||||
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();
|
||||
|
||||
@Deprecated
|
||||
public static String recognizeResource(Value value, boolean isFloder)
|
||||
{
|
||||
String origfile = value.getString();
|
||||
@@ -111,28 +148,20 @@ public class Auxiliary {
|
||||
return file;
|
||||
}
|
||||
|
||||
public static Triple<String, String, Boolean> getFileDescriptor(List<LazyValue> lv, Context c, boolean isFloder)
|
||||
{
|
||||
if (lv.size() < 2) throw new InternalExpressionException("File functions require path and type as first two arguments");
|
||||
String resource = recognizeResource(lv.get(0).evalValue(c), isFloder);
|
||||
String origtype = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT);
|
||||
boolean shared = origtype.startsWith("shared_");
|
||||
String type = shared ? origtype.substring(7) : origtype; //len(shared_)
|
||||
if (!Module.supportedTypes.containsKey(type))
|
||||
throw new InternalExpressionException("Unsupported file type: "+origtype);
|
||||
if (type.equals("folder") && !isFloder)
|
||||
throw new InternalExpressionException("Folder types are no supported for this IO function");
|
||||
return Triple.of(resource, type, shared);
|
||||
}
|
||||
|
||||
public static void apply(Expression expression)
|
||||
{
|
||||
expression.addLazyFunction("sound", -1, (c, t, lv) -> {
|
||||
CarpetContext cc = (CarpetContext)c;
|
||||
Identifier soundName = new Identifier(lv.get(0).evalValue(c).getString());
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
Value ret = ListValue.wrap(Registry.SOUND_EVENT.getIds().stream().map(ValueConversions::of));
|
||||
return (_c, _t) -> ret;
|
||||
}
|
||||
String rawString = lv.get(0).evalValue(c).getString();
|
||||
Identifier soundName = new Identifier(rawString);
|
||||
Vector3Argument locator = Vector3Argument.findIn(cc, lv, 1);
|
||||
if (Registry.SOUND_EVENT.get(soundName) == null)
|
||||
throw new InternalExpressionException("No such sound: "+soundName.getPath());
|
||||
throw new ThrowStatement(rawString, Throwables.UNKNOWN_SOUND);
|
||||
float volume = 1.0F;
|
||||
float pitch = 1.0F;
|
||||
SoundCategory mixer = SoundCategory.MASTER;
|
||||
@@ -165,6 +194,12 @@ public class Auxiliary {
|
||||
expression.addLazyFunction("particle", -1, (c, t, lv) ->
|
||||
{
|
||||
CarpetContext cc = (CarpetContext)c;
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
Value ret = ListValue.wrap(Registry.PARTICLE_TYPE.getIds().stream().map(ValueConversions::of));
|
||||
return (_c, _t) -> ret;
|
||||
}
|
||||
|
||||
MinecraftServer ms = cc.s.getMinecraftServer();
|
||||
ServerWorld world = cc.s.getWorld();
|
||||
Vector3Argument locator = Vector3Argument.findIn(cc, lv, 1);
|
||||
@@ -847,39 +882,28 @@ public class Auxiliary {
|
||||
|
||||
expression.addLazyFunction("list_files", 2, (c, t, lv) ->
|
||||
{
|
||||
Triple<String, String, Boolean> fdesc = getFileDescriptor(lv, c, true);
|
||||
Stream<String> files = ((CarpetScriptHost) c.host).listFolder(fdesc.getLeft(), fdesc.getMiddle(), fdesc.getRight());
|
||||
FileArgument fdesc = FileArgument.from(lv, c, true, FileArgument.Reason.READ);
|
||||
Stream<String> files = ((CarpetScriptHost) c.host).listFolder(fdesc);
|
||||
if (files == null) return LazyValue.NULL;
|
||||
Value ret = ListValue.wrap(files.map(StringValue::of).collect(Collectors.toList()));
|
||||
return (cc, tt) -> ret;
|
||||
});
|
||||
|
||||
|
||||
expression.addLazyFunction("read_file", 2, (c, t, lv) ->
|
||||
{
|
||||
Triple<String, String, Boolean> fdesc = getFileDescriptor(lv, c, false);
|
||||
FileArgument fdesc = FileArgument.from(lv, c, false, FileArgument.Reason.READ);
|
||||
Value retVal;
|
||||
if (fdesc.getMiddle().equals("nbt"))
|
||||
if (fdesc.type == FileArgument.Type.NBT)
|
||||
{
|
||||
Tag state = ((CarpetScriptHost) c.host).readFileTag(fdesc.getLeft(), fdesc.getRight());
|
||||
Tag state = ((CarpetScriptHost) c.host).readFileTag(fdesc);
|
||||
if (state == null) return LazyValue.NULL;
|
||||
retVal = new NBTSerializableValue(state);
|
||||
}
|
||||
else if (fdesc.getMiddle().equals("json"))
|
||||
else if (fdesc.type == FileArgument.Type.JSON)
|
||||
{
|
||||
JsonElement json;
|
||||
try
|
||||
{
|
||||
json = ((CarpetScriptHost) c.host).readJsonFile(fdesc.getLeft(), fdesc.getMiddle(), fdesc.getRight());
|
||||
}
|
||||
catch (JsonParseException e)
|
||||
{
|
||||
Throwable exception = e;
|
||||
if(e.getCause() != null)
|
||||
exception = e.getCause();
|
||||
throw new InternalExpressionException("Failed to read JSON file: "+exception.getMessage());
|
||||
}
|
||||
Value parsedJson = gson.fromJson(json, Value.class);
|
||||
json = ((CarpetScriptHost) c.host).readJsonFile(fdesc);
|
||||
Value parsedJson = GSON.fromJson(json, Value.class);
|
||||
if (parsedJson == null)
|
||||
retVal = Value.NULL;
|
||||
else
|
||||
@@ -887,7 +911,7 @@ public class Auxiliary {
|
||||
}
|
||||
else
|
||||
{
|
||||
List<String> content = ((CarpetScriptHost) c.host).readTextResource(fdesc.getLeft(), fdesc.getMiddle(), fdesc.getRight());
|
||||
List<String> content = ((CarpetScriptHost) c.host).readTextResource(fdesc);
|
||||
if (content == null) return LazyValue.NULL;
|
||||
retVal = ListValue.wrap(content.stream().map(StringValue::new).collect(Collectors.toList()));
|
||||
}
|
||||
@@ -895,32 +919,29 @@ public class Auxiliary {
|
||||
});
|
||||
|
||||
expression.addLazyFunction("delete_file", 2, (c, t, lv) -> {
|
||||
Triple<String, String, Boolean> fdesc = getFileDescriptor(lv, c, false);
|
||||
return ((CarpetScriptHost) c.host).removeResourceFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle())
|
||||
? LazyValue.TRUE
|
||||
: LazyValue.FALSE;
|
||||
FileArgument fdesc = FileArgument.from(lv, c, false, FileArgument.Reason.DELETE);
|
||||
return ((CarpetScriptHost) c.host).removeResourceFile(fdesc) ? LazyValue.TRUE : LazyValue.FALSE;
|
||||
});
|
||||
|
||||
expression.addLazyFunction("write_file", -1, (c, t, lv) -> {
|
||||
if (lv.size() < 3) throw new InternalExpressionException("'write_file' requires three or more arguments");
|
||||
Triple<String, String, Boolean> fdesc = getFileDescriptor(lv, c, false);
|
||||
|
||||
FileArgument fdesc = FileArgument.from(lv, c, false, FileArgument.Reason.CREATE);
|
||||
|
||||
boolean success;
|
||||
if (fdesc.getMiddle().equals("nbt"))
|
||||
if (fdesc.type == FileArgument.Type.NBT)
|
||||
{
|
||||
Value val = lv.get(2).evalValue(c);
|
||||
NBTSerializableValue tagValue = (val instanceof NBTSerializableValue)
|
||||
? (NBTSerializableValue) val
|
||||
: new NBTSerializableValue(val.getString());
|
||||
Tag tag = tagValue.getTag();
|
||||
success = ((CarpetScriptHost) c.host).writeTagFile(tag, fdesc.getLeft(), fdesc.getRight());
|
||||
success = ((CarpetScriptHost) c.host).writeTagFile(tag, fdesc);
|
||||
}
|
||||
else if (fdesc.getMiddle().equals("json"))
|
||||
else if (fdesc.type == FileArgument.Type.JSON)
|
||||
{
|
||||
List<String> data = Collections.singletonList(gson.toJson(lv.get(2).evalValue(c).toJson()));
|
||||
((CarpetScriptHost) c.host).removeResourceFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle());
|
||||
success = ((CarpetScriptHost) c.host).appendLogFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle(), data);
|
||||
List<String> data = Collections.singletonList(GSON.toJson(lv.get(2).evalValue(c).toJson()));
|
||||
((CarpetScriptHost) c.host).removeResourceFile(fdesc);
|
||||
success = ((CarpetScriptHost) c.host).appendLogFile(fdesc, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -945,27 +966,22 @@ public class Auxiliary {
|
||||
data.add(lv.get(i).evalValue(c).getString());
|
||||
}
|
||||
}
|
||||
success = ((CarpetScriptHost) c.host).appendLogFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle(), data);
|
||||
success = ((CarpetScriptHost) c.host).appendLogFile(fdesc, data);
|
||||
}
|
||||
return success?LazyValue.TRUE:LazyValue.FALSE;
|
||||
});
|
||||
|
||||
//write_file
|
||||
|
||||
expression.addLazyFunction("load_app_data", -1, (c, t, lv) ->
|
||||
{
|
||||
String file = null;
|
||||
boolean shared = false;
|
||||
FileArgument fdesc = new FileArgument(null, FileArgument.Type.NBT, null, false, false, FileArgument.Reason.READ);
|
||||
if (lv.size()>0)
|
||||
{
|
||||
c.host.issueDeprecation("load_app_data(...) with arguments");
|
||||
file = recognizeResource(lv.get(0).evalValue(c), false);
|
||||
if (lv.size() > 1)
|
||||
{
|
||||
shared = lv.get(1).evalValue(c).getBoolean();
|
||||
}
|
||||
String resource = recognizeResource(lv.get(0).evalValue(c), false);
|
||||
boolean shared = lv.size() > 1 && lv.get(1).evalValue(c).getBoolean();
|
||||
fdesc = new FileArgument(resource, FileArgument.Type.NBT, null, false, shared, FileArgument.Reason.READ);
|
||||
}
|
||||
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).readFileTag(file, shared);
|
||||
Tag state = ((CarpetScriptHost) c.host).readFileTag(fdesc);
|
||||
if (state == null)
|
||||
return (cc, tt) -> Value.NULL;
|
||||
Value retVal = new NBTSerializableValue(state);
|
||||
@@ -977,22 +993,19 @@ public class Auxiliary {
|
||||
if (lv.size() == 0)
|
||||
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;
|
||||
FileArgument fdesc = new FileArgument(null, FileArgument.Type.NBT, null, false, false, FileArgument.Reason.CREATE);
|
||||
if (lv.size()>1)
|
||||
{
|
||||
c.host.issueDeprecation("store_app_data(...) with more than one argument");
|
||||
file = recognizeResource(lv.get(1).evalValue(c), false);
|
||||
if (lv.size() > 2)
|
||||
{
|
||||
shared = lv.get(2).evalValue(c).getBoolean();
|
||||
}
|
||||
String resource = recognizeResource(lv.get(1).evalValue(c), false);
|
||||
boolean shared = lv.size() > 2 && lv.get(2).evalValue(c).getBoolean();
|
||||
fdesc = new FileArgument(resource, FileArgument.Type.NBT, null, false, shared, FileArgument.Reason.CREATE);
|
||||
}
|
||||
NBTSerializableValue tagValue = (val instanceof NBTSerializableValue)
|
||||
? (NBTSerializableValue) val
|
||||
: new NBTSerializableValue(val.getString());
|
||||
Tag tag = tagValue.getTag();
|
||||
boolean success = ((CarpetScriptHost)((CarpetContext)c).host).writeTagFile(tag, file, shared);
|
||||
boolean success = ((CarpetScriptHost) c.host).writeTagFile(tag, fdesc);
|
||||
return success?LazyValue.TRUE:LazyValue.FALSE;
|
||||
});
|
||||
|
||||
@@ -1089,8 +1102,179 @@ public class Auxiliary {
|
||||
if (old_nbt == null) return LazyValue.NULL;
|
||||
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, ((ServerWorldInterface) server.getOverworld()).getWorldPropertiesCM());
|
||||
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)
|
||||
{
|
||||
T key = type.getRegistry().get(id);
|
||||
|
||||
@@ -6,6 +6,8 @@ import carpet.script.CarpetContext;
|
||||
import carpet.script.Expression;
|
||||
import carpet.script.LazyValue;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.exception.ThrowStatement;
|
||||
import carpet.script.exception.Throwables;
|
||||
import carpet.script.value.ListValue;
|
||||
import carpet.script.value.NBTSerializableValue;
|
||||
import carpet.script.value.NullValue;
|
||||
@@ -91,7 +93,7 @@ public class Inventories {
|
||||
Item item = NBTSerializableValue.parseItem(lv.get(0).evalValue(c).getString()).getItem();
|
||||
if (lv.size() == 1)
|
||||
{
|
||||
Value ret = ListValue.wrap(tagManager.getItems().getTagsFor(item).stream().map(ValueConversions::of).collect(Collectors.toList()));
|
||||
Value ret = ListValue.wrap(tagManager.getItems().getTags().entrySet().stream().filter(e -> e.getValue().contains(item)).map(e -> ValueConversions.of(e.getKey())).collect(Collectors.toList()));
|
||||
return (_c, _t) -> ret;
|
||||
}
|
||||
String tag = lv.get(1).evalValue(c).getString();
|
||||
@@ -119,14 +121,7 @@ public class Inventories {
|
||||
}
|
||||
}
|
||||
List<Recipe<?>> recipes;
|
||||
try
|
||||
{
|
||||
recipes = ((RecipeManagerInterface) cc.s.getMinecraftServer().getRecipeManager()).getAllMatching(type, new Identifier(recipeName));
|
||||
}
|
||||
catch (InvalidIdentifierException ignored)
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
}
|
||||
recipes = ((RecipeManagerInterface) cc.s.getMinecraftServer().getRecipeManager()).getAllMatching(type, new Identifier(recipeName));
|
||||
if (recipes.isEmpty())
|
||||
return LazyValue.NULL;
|
||||
List<Value> recipesOutput = new ArrayList<>();
|
||||
@@ -197,17 +192,9 @@ public class Inventories {
|
||||
{
|
||||
String itemStr = lv.get(0).evalValue(c).getString();
|
||||
Item item;
|
||||
try
|
||||
{
|
||||
Identifier id = new Identifier(itemStr);
|
||||
item = Registry.ITEM.get(id);
|
||||
if (item == Items.AIR && !id.getPath().equalsIgnoreCase("air"))
|
||||
throw new InvalidIdentifierException("boo");
|
||||
}
|
||||
catch (InvalidIdentifierException ignored)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect item: "+itemStr);
|
||||
}
|
||||
Identifier id = new Identifier(itemStr);
|
||||
item = Registry.ITEM.getOrEmpty(id).orElseThrow(() -> new ThrowStatement(itemStr, Throwables.UNKNOWN_ITEM));
|
||||
|
||||
if (!item.hasRecipeRemainder()) return LazyValue.NULL;
|
||||
Value ret = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.ITEM.getId(item.getRecipeRemainder())));
|
||||
return (_c, _t ) -> ret;
|
||||
|
||||
@@ -6,6 +6,8 @@ import carpet.script.CarpetContext;
|
||||
import carpet.script.Expression;
|
||||
import carpet.script.LazyValue;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.exception.ThrowStatement;
|
||||
import carpet.script.exception.Throwables;
|
||||
import carpet.script.value.EntityValue;
|
||||
import carpet.script.value.ListValue;
|
||||
import carpet.script.value.NullValue;
|
||||
@@ -33,6 +35,8 @@ import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.InvalidIdentifierException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Scoreboards {
|
||||
@@ -77,16 +81,27 @@ public class Scoreboards {
|
||||
Value ret = ListValue.wrap(scoreboard.getAllPlayerScores(objective).stream().map(s -> new StringValue(s.getPlayerName())).collect(Collectors.toList()));
|
||||
return (_c, _t) -> ret;
|
||||
}
|
||||
|
||||
String key = getScoreboardKeyFromValue(lv.get(1).evalValue(c));
|
||||
if (!scoreboard.playerHasObjective(key, objective) && lv.size()==2)
|
||||
if(lv.size()==2) {
|
||||
if(scoreboard.playerHasObjective(key, objective)) {
|
||||
return (_c,_t) -> NumericValue.of(scoreboard.getPlayerScore(key,objective).getScore());
|
||||
}
|
||||
return LazyValue.NULL;
|
||||
ScoreboardPlayerScore scoreboardPlayerScore = scoreboard.getPlayerScore(key, objective);
|
||||
Value retval = new NumericValue(scoreboardPlayerScore.getScore());
|
||||
if (lv.size() > 2)
|
||||
{
|
||||
scoreboardPlayerScore.setScore(NumericValue.asNumber(lv.get(2).evalValue(c)).getInt());
|
||||
}
|
||||
return (_c, _t) -> retval;
|
||||
|
||||
Value value = lv.get(2).evalValue(c);
|
||||
if(value.isNull()) {
|
||||
ScoreboardPlayerScore score = scoreboard.getPlayerScore(key, objective);
|
||||
scoreboard.resetPlayerScore(key,objective);
|
||||
return (_c,_t) -> NumericValue.of(score.getScore());
|
||||
}
|
||||
if (value instanceof NumericValue) {
|
||||
ScoreboardPlayerScore score = scoreboard.getPlayerScore(key, objective);
|
||||
score.setScore(NumericValue.asNumber(value).getInt());
|
||||
return (_c,_t) -> NumericValue.of(score.getScore());
|
||||
}
|
||||
throw new InternalExpressionException("'scoreboard' requires a number or null as the third parameter");
|
||||
});
|
||||
|
||||
expression.addLazyFunction("scoreboard_remove", -1, (c, t, lv)->
|
||||
@@ -131,12 +146,13 @@ public class Scoreboards {
|
||||
criterion = ScoreboardCriterion.createStatCriterion(critetionName).orElse(null);
|
||||
if (criterion==null)
|
||||
{
|
||||
throw new InternalExpressionException("Unknown scoreboard criterion: "+critetionName);
|
||||
throw new ThrowStatement(critetionName, Throwables.UNKNOWN_CRITERION);
|
||||
}
|
||||
}
|
||||
|
||||
ScoreboardObjective objective = scoreboard.getObjective(objectiveName);
|
||||
if (objective != null) {
|
||||
c.host.issueDeprecation("reading or modifying an objective's criterion with scoreboard_add");
|
||||
if(lv.size() == 1) return (_c, _t) -> StringValue.of(objective.getCriterion().getName());
|
||||
if(objective.getCriterion().equals(criterion) || lv.size() == 1) return LazyValue.NULL;
|
||||
((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().get(objective.getCriterion()).remove(objective);
|
||||
@@ -150,6 +166,72 @@ public class Scoreboards {
|
||||
return LazyValue.TRUE;
|
||||
});
|
||||
|
||||
expression.addLazyFunction("scoreboard_property", -1, (c, t, lv) ->
|
||||
{
|
||||
if(lv.size() < 2) throw new InternalExpressionException("'scoreboard_property' requires at least two parameters");
|
||||
CarpetContext cc = (CarpetContext)c;
|
||||
Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
|
||||
ScoreboardObjective objective = scoreboard.getObjective(lv.get(0).evalValue(c).getString());
|
||||
if(objective == null) return LazyValue.NULL;
|
||||
|
||||
boolean modify = lv.size() > 2;
|
||||
Value setValue = null;
|
||||
if(modify) {
|
||||
setValue = lv.get(2).evalValue(c);
|
||||
}
|
||||
String property = lv.get(1).evalValue(c).getString();
|
||||
switch (property) {
|
||||
case "criterion":
|
||||
if(modify) {
|
||||
ScoreboardCriterion criterion = ScoreboardCriterion.createStatCriterion(setValue.getString()).orElse(null);
|
||||
if (criterion==null) throw new InternalExpressionException("Unknown scoreboard criterion: "+ setValue.getString());
|
||||
if(objective.getCriterion().equals(criterion) || lv.size() == 1) return LazyValue.FALSE;
|
||||
((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().get(objective.getCriterion()).remove(objective);
|
||||
((ScoreboardObjective_scarpetMixin) objective).setCriterion(criterion);
|
||||
(((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().computeIfAbsent(criterion, (criterion1) -> Lists.newArrayList())).add(objective);
|
||||
scoreboard.updateObjective(objective);
|
||||
return LazyValue.TRUE;
|
||||
}
|
||||
return (_c, _t) -> StringValue.of(objective.getCriterion().getName());
|
||||
case "display_name":
|
||||
if(modify) {
|
||||
Text text = (setValue instanceof FormattedTextValue)?((FormattedTextValue) setValue).getText():new LiteralText(setValue.getString());
|
||||
objective.setDisplayName(text);
|
||||
return LazyValue.TRUE;
|
||||
}
|
||||
return (_c, _t) -> new FormattedTextValue(objective.getDisplayName());
|
||||
case "display_slot":
|
||||
if(modify) {
|
||||
int slotId = Scoreboard.getDisplaySlotId(setValue.getString());
|
||||
if(slotId == -1) throw new InternalExpressionException("Unknown scoreboard display slot: " + setValue.getString());
|
||||
if(objective.equals(scoreboard.getObjectiveForSlot(slotId))) {
|
||||
return LazyValue.FALSE;
|
||||
}
|
||||
scoreboard.setObjectiveSlot(slotId,objective);
|
||||
return LazyValue.TRUE;
|
||||
}
|
||||
|
||||
List<Value> slots = new ArrayList<>();
|
||||
for(int i = 0; i < 19; i++) {
|
||||
if (scoreboard.getObjectiveForSlot(i) == objective) {
|
||||
String slotName = Scoreboard.getDisplaySlotName(i);
|
||||
slots.add(StringValue.of(slotName));
|
||||
}
|
||||
}
|
||||
return (_c, _t) -> ListValue.wrap(slots);
|
||||
case "render_type":
|
||||
if(modify) {
|
||||
ScoreboardCriterion.RenderType renderType = ScoreboardCriterion.RenderType.getType(setValue.getString().toLowerCase());
|
||||
if(objective.getRenderType().equals(renderType)) return LazyValue.FALSE;
|
||||
objective.setRenderType(renderType);
|
||||
return LazyValue.TRUE;
|
||||
}
|
||||
return (_c, _t) -> StringValue.of(objective.getRenderType().getName());
|
||||
default:
|
||||
throw new InternalExpressionException("scoreboard property '" + property + "' is not a valid property");
|
||||
}
|
||||
});
|
||||
|
||||
expression.addLazyFunction("scoreboard_display", 2, (c, t, lv) ->
|
||||
{
|
||||
CarpetContext cc = (CarpetContext)c;
|
||||
@@ -408,7 +490,7 @@ public class Scoreboards {
|
||||
team.setSuffix(suffix);
|
||||
break;
|
||||
default:
|
||||
throw new InternalExpressionException("team property " + propertyVal.getString() + " is not a valid property");
|
||||
throw new InternalExpressionException("team property '" + propertyVal.getString() + "' is not a valid property");
|
||||
}
|
||||
return LazyValue.TRUE;
|
||||
});
|
||||
|
||||
@@ -19,6 +19,8 @@ import carpet.script.LazyValue;
|
||||
import carpet.script.argument.BlockArgument;
|
||||
import carpet.script.argument.Vector3Argument;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.exception.ThrowStatement;
|
||||
import carpet.script.exception.Throwables;
|
||||
import carpet.script.utils.BiomeInfo;
|
||||
import carpet.script.utils.WorldTools;
|
||||
import carpet.script.value.BlockValue;
|
||||
@@ -48,6 +50,7 @@ import net.minecraft.enchantment.Enchantments;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.FallingBlockEntity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.pathing.NavigationType;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
@@ -59,7 +62,7 @@ import net.minecraft.item.SwordItem;
|
||||
import net.minecraft.item.TridentItem;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.network.packet.s2c.play.ExplosionS2CPacket;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ChunkTicket;
|
||||
import net.minecraft.server.world.ChunkTicketType;
|
||||
@@ -78,6 +81,7 @@ import net.minecraft.util.math.BlockBox;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.Heightmap;
|
||||
import net.minecraft.world.LightType;
|
||||
@@ -87,6 +91,7 @@ import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.ChunkStatus;
|
||||
import net.minecraft.world.chunk.WorldChunk;
|
||||
import net.minecraft.world.explosion.Explosion;
|
||||
import net.minecraft.world.gen.ChunkRandom;
|
||||
import net.minecraft.world.gen.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.gen.feature.ConfiguredStructureFeature;
|
||||
@@ -95,6 +100,7 @@ import net.minecraft.world.level.ServerWorldProperties;
|
||||
import net.minecraft.world.poi.PointOfInterest;
|
||||
import net.minecraft.world.poi.PointOfInterestStorage;
|
||||
import net.minecraft.world.poi.PointOfInterestType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -106,7 +112,6 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -121,8 +126,7 @@ public class WorldAccess {
|
||||
put("unknown", ChunkTicketType.UNKNOWN); // unknown
|
||||
}};
|
||||
// dummy entity for dummy requirements in the loot tables (see snowball)
|
||||
private static FallingBlockEntity DUMMY_ENTITY = new FallingBlockEntity(EntityType.FALLING_BLOCK, null);
|
||||
|
||||
private static FallingBlockEntity DUMMY_ENTITY = null;
|
||||
private static LazyValue booleanStateTest(
|
||||
Context c,
|
||||
String name,
|
||||
@@ -336,8 +340,8 @@ public class WorldAccess {
|
||||
String poiType = lv.get(locator.offset+1).evalValue(c).getString().toLowerCase(Locale.ROOT);
|
||||
if (!"any".equals(poiType))
|
||||
{
|
||||
PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.get(new Identifier(poiType));
|
||||
if (type == PointOfInterestType.UNEMPLOYED && !"unemployed".equals(poiType)) return LazyValue.NULL;
|
||||
PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.getOrEmpty(new Identifier(poiType))
|
||||
.orElseThrow(() -> new ThrowStatement(poiType, Throwables.UNKNOWN_POI));
|
||||
condition = (tt) -> tt == type;
|
||||
}
|
||||
if (locator.offset + 2 < lv.size())
|
||||
@@ -391,9 +395,8 @@ public class WorldAccess {
|
||||
return LazyValue.FALSE;
|
||||
}
|
||||
String poiTypeString = poi.getString().toLowerCase(Locale.ROOT);
|
||||
PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.get(new Identifier(poiTypeString));
|
||||
// solving lack of null with defaulted registries
|
||||
if (type == PointOfInterestType.UNEMPLOYED && !"unemployed".equals(poiTypeString)) throw new InternalExpressionException("Unknown POI type: "+poiTypeString);
|
||||
PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.getOrEmpty(new Identifier(poiTypeString))
|
||||
.orElseThrow(() -> new ThrowStatement(poiTypeString, Throwables.UNKNOWN_POI));
|
||||
int occupancy = 0;
|
||||
if (locator.offset + 1 < lv.size())
|
||||
{
|
||||
@@ -872,9 +875,8 @@ public class WorldAccess {
|
||||
{
|
||||
playerBreak = true;
|
||||
String itemString = val.getString();
|
||||
item = Registry.ITEM.get(new Identifier(itemString));
|
||||
if (item == Items.AIR && !itemString.equals("air"))
|
||||
throw new InternalExpressionException("Incorrect item: " + itemString);
|
||||
item = Registry.ITEM.getOrEmpty(new Identifier(itemString))
|
||||
.orElseThrow(() -> new ThrowStatement(itemString, Throwables.UNKNOWN_ITEM));
|
||||
}
|
||||
}
|
||||
CompoundTag tag = null;
|
||||
@@ -932,6 +934,7 @@ public class WorldAccess {
|
||||
{
|
||||
if (how > 0)
|
||||
tool.addEnchantment(Enchantments.FORTUNE, (int) how);
|
||||
if (DUMMY_ENTITY == null) DUMMY_ENTITY = new FallingBlockEntity(EntityType.FALLING_BLOCK, null);
|
||||
Block.dropStacks(state, world, where, be, DUMMY_ENTITY, tool);
|
||||
}
|
||||
}
|
||||
@@ -972,6 +975,88 @@ public class WorldAccess {
|
||||
return success ? LazyValue.TRUE : LazyValue.FALSE;
|
||||
});
|
||||
|
||||
expression.addLazyFunction("create_explosion", -1, (c, t, lv) ->
|
||||
{
|
||||
if (lv.isEmpty())
|
||||
throw new InternalExpressionException("'create_explosion' requires at least a position to explode");
|
||||
CarpetContext cc = (CarpetContext)c;
|
||||
float powah = 4.0f;
|
||||
Explosion.DestructionType mode = Explosion.DestructionType.BREAK;
|
||||
boolean createFire = false;
|
||||
Entity source = null;
|
||||
LivingEntity attacker = null;
|
||||
Vector3Argument location = Vector3Argument.findIn(cc, lv, 0, false, true);
|
||||
Vec3d pos = location.vec;
|
||||
if (lv.size() > location.offset)
|
||||
{
|
||||
powah = NumericValue.asNumber(lv.get(location.offset).evalValue(c), "explosion power").getFloat();
|
||||
if (powah < 0) throw new InternalExpressionException("Explosion power cannot be negative");
|
||||
if (lv.size() > location.offset+1)
|
||||
{
|
||||
String strval = lv.get(location.offset+1).evalValue(c).getString();
|
||||
try {
|
||||
mode = Explosion.DestructionType.valueOf(strval.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
catch (IllegalArgumentException ile) { throw new InternalExpressionException("Illegal explosions block behaviour: "+strval); }
|
||||
if (lv.size() > location.offset+2)
|
||||
{
|
||||
createFire = lv.get(location.offset+2).evalValue(c, Context.BOOLEAN).getBoolean();
|
||||
if (lv.size() > location.offset+3)
|
||||
{
|
||||
Value enVal= lv.get(location.offset+3).evalValue(c);
|
||||
if (enVal.isNull()) {} // is null already
|
||||
else if (enVal instanceof EntityValue)
|
||||
{
|
||||
source = ((EntityValue) enVal).getEntity();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalExpressionException("Fourth parameter of the explosion has to be an entity, not "+enVal.getTypeString());
|
||||
}
|
||||
if (lv.size() > location.offset+4)
|
||||
{
|
||||
enVal = lv.get(location.offset+4).evalValue(c);
|
||||
if (enVal.isNull()) {} // is null already
|
||||
else if (enVal instanceof EntityValue)
|
||||
{
|
||||
Entity attackingEntity = ((EntityValue) enVal).getEntity();
|
||||
if (attackingEntity instanceof LivingEntity)
|
||||
{
|
||||
attacker = (LivingEntity) attackingEntity;
|
||||
}
|
||||
else throw new InternalExpressionException("Attacking entity needs to be a living thing, "+
|
||||
ValueConversions.of(Registry.ENTITY_TYPE.getId(attackingEntity.getType())).getString() +" ain't it.");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalExpressionException("Fifth parameter of the explosion has to be a living entity, not "+enVal.getTypeString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LivingEntity theAttacker = attacker;
|
||||
float thePowah = powah;
|
||||
|
||||
// copy of ServerWorld.createExplosion #TRACK#
|
||||
Explosion explosion = new Explosion(cc.s.getWorld(), source, null, null, pos.x, pos.y, pos.z, powah, createFire, mode){
|
||||
@Override
|
||||
public @Nullable LivingEntity getCausingEntity() {
|
||||
return theAttacker;
|
||||
}
|
||||
};
|
||||
explosion.collectBlocksAndDamageEntities();
|
||||
explosion.affectWorld(false);
|
||||
if (mode == Explosion.DestructionType.NONE) explosion.clearAffectedBlocks();
|
||||
cc.s.getWorld().getPlayers().forEach(spe -> {
|
||||
if (spe.squaredDistanceTo(pos) < 4096.0D)
|
||||
spe.networkHandler.sendPacket(new ExplosionS2CPacket(pos.x, pos.y, pos.z, thePowah, explosion.getAffectedBlocks(), explosion.getAffectedPlayers().get(spe)));
|
||||
});
|
||||
return LazyValue.TRUE;
|
||||
});
|
||||
|
||||
// TODO rename to use_item
|
||||
expression.addLazyFunction("place_item", -1, (c, t, lv) ->
|
||||
{
|
||||
@@ -1127,7 +1212,8 @@ public class WorldAccess {
|
||||
BlockArgument blockLocator = BlockArgument.findIn(cc, lv, 0, true);
|
||||
if (blockLocator.offset == lv.size())
|
||||
{
|
||||
Value ret = ListValue.wrap(tagManager.getBlocks().getTagsFor(blockLocator.block.getBlockState().getBlock()).stream().map(ValueConversions::of).collect(Collectors.toList()));
|
||||
Block target = blockLocator.block.getBlockState().getBlock();
|
||||
Value ret = ListValue.wrap(tagManager.getBlocks().getTags().entrySet().stream().filter(e -> e.getValue().contains(target)).map(e -> ValueConversions.of(e.getKey())).collect(Collectors.toList()));
|
||||
return (_c, _t) -> ret;
|
||||
}
|
||||
String tag = lv.get(blockLocator.offset).evalValue(c).getString();
|
||||
@@ -1151,7 +1237,7 @@ public class WorldAccess {
|
||||
if (locator.replacement != null)
|
||||
{
|
||||
biome = world.getRegistryManager().get(Registry.BIOME_KEY).get(new Identifier(locator.replacement));
|
||||
if (biome == null) return LazyValue.NULL;
|
||||
if (biome == null) throw new ThrowStatement(locator.replacement, Throwables.UNKNOWN_BIOME) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1180,9 +1266,8 @@ public class WorldAccess {
|
||||
throw new InternalExpressionException("'set_biome' needs a biome name as an argument");
|
||||
String biomeName = lv.get(locator.offset+0).evalValue(c).getString();
|
||||
// from locatebiome command code
|
||||
Biome biome = cc.s.getMinecraftServer().getRegistryManager().get(Registry.BIOME_KEY).get(new Identifier(biomeName));
|
||||
if (biome == null)
|
||||
throw new InternalExpressionException("Unknown biome: "+biomeName);
|
||||
Biome biome = cc.s.getMinecraftServer().getRegistryManager().get(Registry.BIOME_KEY).getOrEmpty(new Identifier(biomeName))
|
||||
.orElseThrow(() -> new ThrowStatement(biomeName, Throwables.UNKNOWN_BIOME));
|
||||
boolean doImmediateUpdate = true;
|
||||
if (lv.size() > locator.offset+1)
|
||||
{
|
||||
@@ -1251,8 +1336,8 @@ public class WorldAccess {
|
||||
if (!(requested instanceof NullValue))
|
||||
{
|
||||
String reqString = requested.getString();
|
||||
structure = Registry.STRUCTURE_FEATURE.get(new Identifier(reqString));
|
||||
if (structure == null) throw new InternalExpressionException("Unknown structure: " + reqString);
|
||||
structure = Registry.STRUCTURE_FEATURE.getOrEmpty(new Identifier(reqString))
|
||||
.orElseThrow(() -> new ThrowStatement(reqString, Throwables.UNKNOWN_STRUCTURE));
|
||||
}
|
||||
if (lv.size() > locator.offset+1)
|
||||
{
|
||||
@@ -1332,7 +1417,7 @@ public class WorldAccess {
|
||||
throw new InternalExpressionException("'set_structure requires at least position and a structure name");
|
||||
String structureName = lv.get(locator.offset).evalValue(c).getString().toLowerCase(Locale.ROOT);
|
||||
ConfiguredStructureFeature<?, ?> configuredStructure = FeatureGenerator.resolveConfiguredStructure(structureName, world, pos);
|
||||
if (configuredStructure == null) throw new InternalExpressionException("Unknown structure: "+structureName);
|
||||
if (configuredStructure == null) throw new ThrowStatement(structureName, Throwables.UNKNOWN_STRUCTURE);
|
||||
// good 'ol pointer
|
||||
Value[] result = new Value[]{Value.NULL};
|
||||
// technically a world modification. Even if we could let it slide, we will still park it
|
||||
@@ -1382,6 +1467,7 @@ public class WorldAccess {
|
||||
{
|
||||
if (lv.size() == 0) throw new InternalExpressionException("'custom_dimension' requires at least one argument");
|
||||
CarpetContext cc = (CarpetContext)c;
|
||||
cc.host.issueDeprecation("custom_dimension()");
|
||||
String worldKey = lv.get(0).evalValue(c).getString();
|
||||
|
||||
Long seed = null;
|
||||
|
||||
Reference in new issue
Block a user