This commit is contained in:
gnembon committed 2024-02-29 11:05:15 +01:00
1 parent 2dd8674ea6
commit 4e57eecf2d
37 files changed
+534 -481

No files matched your search

+2 -2
View File
@@ -3,8 +3,8 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties # Fabric Properties
# check https://fabricmc.net/develop/ # check https://fabricmc.net/develop/
minecraft_version=24w07a minecraft_version=24w09a
loader_version=0.15.6 loader_version=0.15.7
jsr305_version=3.0.2 jsr305_version=3.0.2
fabric_version=0.91.1+1.20.3 fabric_version=0.91.1+1.20.3
@@ -16,6 +16,7 @@ import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.SharedConstants;
import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.arguments.DimensionArgument; import net.minecraft.commands.arguments.DimensionArgument;
@@ -304,7 +305,7 @@ public class PlayerCommand
private static int maxNameLength(MinecraftServer server) private static int maxNameLength(MinecraftServer server)
{ {
return server.getPort() >= 0 ? Player.MAX_NAME_LENGTH : 40; return server.getPort() >= 0 ? SharedConstants.MAX_PLAYER_NAME_LENGTH : 40;
} }
private static int manipulate(CommandContext<CommandSourceStack> context, Consumer<EntityPlayerActionPack> action) private static int manipulate(CommandContext<CommandSourceStack> context, Consumer<EntityPlayerActionPack> action)
@@ -1,8 +1,7 @@
package carpet.fakes; package carpet.fakes;
import com.mojang.datafixers.util.Either;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkResult;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
@@ -10,5 +9,5 @@ import net.minecraft.world.level.chunk.ChunkAccess;
public interface ChunkHolderInterface public interface ChunkHolderInterface
{ {
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> setDefaultProtoChunk(ChunkPos chpos, BlockableEventLoop<Runnable> executor, ServerLevel world); CompletableFuture<ChunkResult<ChunkAccess>> setDefaultProtoChunk(ChunkPos chpos, BlockableEventLoop<Runnable> executor, ServerLevel world);
} }
@@ -1,8 +1,9 @@
package carpet.mixins; package carpet.mixins;
import carpet.fakes.ChunkHolderInterface; import carpet.fakes.ChunkHolderInterface;
import com.mojang.datafixers.util.Either;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.server.level.ChunkResult;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@@ -14,23 +15,22 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.UpgradeData;
@Mixin(ChunkHolder.class) @Mixin(ChunkHolder.class)
public abstract class ChunkHolder_scarpetChunkCreationMixin implements ChunkHolderInterface public abstract class ChunkHolder_scarpetChunkCreationMixin implements ChunkHolderInterface
{ {
@Shadow protected abstract void updateChunkToSave(CompletableFuture<? extends Either<? extends ChunkAccess, ChunkHolder.ChunkLoadingFailure>> newChunkFuture, String type); @Shadow protected abstract void updateChunkToSave(CompletableFuture<? extends ChunkResult<? extends ChunkAccess>> newChunkFuture, String type);
@Shadow @Final private AtomicReferenceArray<CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>> futures; @Shadow @Final private AtomicReferenceArray<CompletableFuture<ChunkResult<ChunkAccess>>> futures;
@Override @Override
public CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> setDefaultProtoChunk(ChunkPos chpos, BlockableEventLoop<Runnable> executor, ServerLevel world) public CompletableFuture<ChunkResult<ChunkAccess>> setDefaultProtoChunk(ChunkPos chpos, BlockableEventLoop<Runnable> executor, ServerLevel world)
{ {
int i = ChunkStatus.EMPTY.getIndex(); int i = ChunkStatus.EMPTY.getIndex();
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completableFuture2 = CompletableFuture.supplyAsync( CompletableFuture<ChunkResult<ChunkAccess>> completableFuture2 = CompletableFuture.supplyAsync(
() -> Either.left(new ProtoChunk(chpos, UpgradeData.EMPTY, world, world.registryAccess().registryOrThrow(Registries.BIOME), null)), // todo figure out what that does - maybe add an option to reset with blending enabled..? () -> ChunkResult.of(new ProtoChunk(chpos, UpgradeData.EMPTY, world, world.registryAccess().registryOrThrow(Registries.BIOME), null)), // todo figure out what that does - maybe add an option to reset with blending enabled..?
executor executor
); );
updateChunkToSave(completableFuture2, "unfull"); // possible debug data updateChunkToSave(completableFuture2, "unfull"); // possible debug data
@@ -19,9 +19,9 @@ import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.TickTask; import net.minecraft.server.TickTask;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkHolder.ChunkLoadingFailure;
import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ChunkMap.DistanceManager; import net.minecraft.server.level.ChunkMap.DistanceManager;
import net.minecraft.server.level.ChunkResult;
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter; import net.minecraft.server.level.ChunkTaskPriorityQueueSorter;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.ThreadedLevelLightEngine;
@@ -32,8 +32,8 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.storage.RegionFile; import net.minecraft.world.level.chunk.storage.RegionFile;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
@@ -44,8 +44,6 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.mojang.datafixers.util.Either;
import carpet.fakes.ChunkHolderInterface; import carpet.fakes.ChunkHolderInterface;
import carpet.fakes.ChunkTicketManagerInterface; import carpet.fakes.ChunkTicketManagerInterface;
import carpet.fakes.ServerLightingProviderInterface; import carpet.fakes.ServerLightingProviderInterface;
@@ -104,7 +102,8 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
protected abstract Iterable<ChunkHolder> getChunks(); protected abstract Iterable<ChunkHolder> getChunks();
@Shadow protected abstract CompletableFuture<Either<List<ChunkAccess>, ChunkLoadingFailure>> getChunkRangeFuture(final ChunkHolder chunkHolder, final int i, final IntFunction<ChunkStatus> intFunction); @Shadow
protected abstract CompletableFuture<ChunkResult<List<ChunkAccess>>> getChunkRangeFuture(ChunkHolder chunkHolder, int i, IntFunction<ChunkStatus> intFunction);
//@Shadow protected abstract void postLoadProtoChunk(final ServerLevel serverLevel, final List<CompoundTag> list); //@Shadow protected abstract void postLoadProtoChunk(final ServerLevel serverLevel, final List<CompoundTag> list);
@@ -112,8 +111,8 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
// in protoChunkToFullChunk // in protoChunkToFullChunk
// fancier version of the one below, ensuring that the event is triggered when the chunk is actually loaded. // fancier version of the one below, ensuring that the event is triggered when the chunk is actually loaded.
@Inject(method = "method_20460", at = @At("HEAD"), remap = false) @Inject(method = "method_17227", at = @At("HEAD"), remap = false)
private void onChunkGeneratedStart(ChunkHolder chunkHolder, Either<ChunkAccess, ChunkLoadingFailure> chunk, CallbackInfoReturnable<CompletableFuture<Either<ChunkAccess, ChunkLoadingFailure>>> cir) private void onChunkGeneratedStart(ChunkHolder chunkHolder, ChunkAccess chunkAccess, CallbackInfoReturnable<ChunkAccess> cir)
{ {
if (CHUNK_GENERATED.isNeeded() || CHUNK_LOADED.isNeeded()) if (CHUNK_GENERATED.isNeeded() || CHUNK_LOADED.isNeeded())
{ {
@@ -125,27 +124,31 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
} }
} }
@Inject(method = "method_20460", at = @At("RETURN"), remap = false) @Inject(method = "method_17227", at = @At("RETURN"), remap = false)
private void onChunkGeneratedEnd(ChunkHolder chunkHolder, Either<ChunkAccess, ChunkLoadingFailure> chunk, CallbackInfoReturnable<CompletableFuture<Either<ChunkAccess, ChunkLoadingFailure>>> cir) private void onChunkGeneratedEnd(ChunkHolder chunkHolder, ChunkAccess chunk, CallbackInfoReturnable<CompletableFuture<ChunkResult<ChunkAccess>>> cir)
{ {
Boolean localGenerated= generated.get(); Boolean localGenerated = generated.get();
if (localGenerated != null) if (localGenerated != null)
{ {
MinecraftServer server = this.level.getServer(); MinecraftServer server = this.level.getServer();
int ticks = server.getTickCount(); int ticks = server.getTickCount();
ChunkPos chpos = chunkHolder.getPos(); ChunkPos chpos = chunkHolder.getPos();
// need to send these because if an app does something with that event, it may lock the thread // need to send these because if an app does something with that event, it may lock the thread
// so better be safe and schedule it for later, aSaP // so better be safe and schedule it for later, aSaP
if (CHUNK_GENERATED.isNeeded() && localGenerated) if (CHUNK_GENERATED.isNeeded() && localGenerated)
server.tell(new TickTask(ticks, () -> CHUNK_GENERATED.onChunkEvent(this.level, chpos, true))); {
server.tell(new TickTask(ticks, () -> CHUNK_GENERATED.onChunkEvent(this.level, chpos, true)));
}
if (CHUNK_LOADED.isNeeded()) if (CHUNK_LOADED.isNeeded())
server.tell(new TickTask(ticks, () -> CHUNK_LOADED.onChunkEvent(this.level, chpos, localGenerated))); {
server.tell(new TickTask(ticks, () -> CHUNK_LOADED.onChunkEvent(this.level, chpos, localGenerated)));
}
} }
} }
/* simple but a version that doesn't guarantee that the chunk is actually loaded /* simple but a version that doesn't guarantee that the chunk is actually loaded
@Inject(method = "convertToFullChunk", at = @At("HEAD")) @Inject(method = "convertToFullChunk", at = @At("HEAD"))
private void onChunkGeneratedEnd(ChunkHolder chunkHolder, CallbackInfoReturnable<CompletableFuture<Either<Chunk, Unloaded>>> cir) private void onChunkGeneratedEnd(ChunkHolder chunkHolder, CallbackInfoReturnable<CompletableFuture<ChunkResult<ChunkAccess>>> cir)
{ {
if (CHUNK_GENERATED.isNeeded() && chunkHolder.getCurrentChunk().getStatus() != ChunkStatus.FULL) if (CHUNK_GENERATED.isNeeded() && chunkHolder.getCurrentChunk().getStatus() != ChunkStatus.FULL)
{ {
@@ -162,29 +165,29 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
*/ */
@Unique @Unique
private void addTicket(final ChunkPos pos, final ChunkStatus status) private void addTicket(ChunkPos pos, ChunkStatus status)
{ // UNKNOWN { // UNKNOWN
this.distanceManager.addTicket(TicketType.UNKNOWN, pos, 33 + ChunkStatus.getDistance(status), pos); this.distanceManager.addTicket(TicketType.UNKNOWN, pos, 33 + ChunkStatus.getDistance(status), pos);
} }
@Unique @Unique
private void addTicket(final ChunkPos pos) private void addTicket(ChunkPos pos)
{ {
this.addTicket(pos, ChunkStatus.EMPTY); this.addTicket(pos, ChunkStatus.EMPTY);
} }
@Unique @Unique
private void addRelightTicket(final ChunkPos pos) private void addRelightTicket(ChunkPos pos)
{ {
this.distanceManager.addRegionTicket(TicketType.LIGHT, pos, 1, pos); this.distanceManager.addRegionTicket(TicketType.LIGHT, pos, 1, pos);
} }
@Override @Override
public void releaseRelightTicket(final ChunkPos pos) public void releaseRelightTicket(ChunkPos pos)
{ {
this.mainThreadExecutor.tell(Util.name( this.mainThreadExecutor.tell(Util.name(
() -> this.distanceManager.removeRegionTicket(TicketType.LIGHT, pos, 1, pos), () -> this.distanceManager.removeRegionTicket(TicketType.LIGHT, pos, 1, pos),
() -> "release relight ticket " + pos () -> "release relight ticket " + pos
)); ));
} }
@@ -195,57 +198,69 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
} }
@Unique @Unique
private Set<ChunkPos> getExistingChunks(final Set<ChunkPos> requestedChunks) private Set<ChunkPos> getExistingChunks(Set<ChunkPos> requestedChunks)
{ {
final Map<String, RegionFile> regionCache = new HashMap<>(); Map<String, RegionFile> regionCache = new HashMap<>();
final Set<ChunkPos> ret = new HashSet<>(); Set<ChunkPos> ret = new HashSet<>();
for (final ChunkPos pos : requestedChunks) for (ChunkPos pos : requestedChunks)
{
if (WorldTools.canHasChunk(this.level, pos, regionCache, true)) if (WorldTools.canHasChunk(this.level, pos, regionCache, true))
{
ret.add(pos); ret.add(pos);
}
}
return ret; return ret;
} }
@Unique @Unique
private Set<ChunkPos> loadExistingChunksFromDisk(final Set<ChunkPos> requestedChunks) private Set<ChunkPos> loadExistingChunksFromDisk(Set<ChunkPos> requestedChunks)
{ {
final Set<ChunkPos> existingChunks = this.getExistingChunks(requestedChunks); Set<ChunkPos> existingChunks = this.getExistingChunks(requestedChunks);
for (final ChunkPos pos : existingChunks) for (ChunkPos pos : existingChunks)
{
this.updatingChunkMap.get(pos.toLong()).getOrScheduleFuture(ChunkStatus.EMPTY, (ChunkMap) (Object) this); this.updatingChunkMap.get(pos.toLong()).getOrScheduleFuture(ChunkStatus.EMPTY, (ChunkMap) (Object) this);
}
return existingChunks; return existingChunks;
} }
@Unique @Unique
private Set<ChunkPos> loadExistingChunks(final Set<ChunkPos> requestedChunks, final Object2IntMap<String> report) private Set<ChunkPos> loadExistingChunks(Set<ChunkPos> requestedChunks, Object2IntMap<String> report)
{ {
if (report != null) if (report != null)
{
report.put("requested_chunks", requestedChunks.size()); report.put("requested_chunks", requestedChunks.size());
}
// Load all relevant ChunkHolders into this.currentChunkHolders // Load all relevant ChunkHolders into this.currentChunkHolders
// This will not trigger loading from disk yet // This will not trigger loading from disk yet
for (final ChunkPos pos : requestedChunks) for (ChunkPos pos : requestedChunks)
{
this.addTicket(pos); this.addTicket(pos);
}
this.tickTicketManager(); this.tickTicketManager();
// Fetch all currently loaded chunks // Fetch all currently loaded chunks
final Set<ChunkPos> loadedChunks = requestedChunks.stream().filter( Set<ChunkPos> loadedChunks = requestedChunks.stream().filter(
pos -> this.updatingChunkMap.get(pos.toLong()).getLastAvailable() != null // all relevant ChunkHolders exist pos -> this.updatingChunkMap.get(pos.toLong()).getLastAvailable() != null // all relevant ChunkHolders exist
).collect(Collectors.toSet()); ).collect(Collectors.toSet());
if (report != null) if (report != null)
{
report.put("loaded_chunks", loadedChunks.size()); report.put("loaded_chunks", loadedChunks.size());
}
// Load remaining chunks from disk // Load remaining chunks from disk
final Set<ChunkPos> unloadedChunks = new HashSet<>(requestedChunks); Set<ChunkPos> unloadedChunks = new HashSet<>(requestedChunks);
unloadedChunks.removeAll(loadedChunks); unloadedChunks.removeAll(loadedChunks);
final Set<ChunkPos> existingChunks = this.loadExistingChunksFromDisk(unloadedChunks); Set<ChunkPos> existingChunks = this.loadExistingChunksFromDisk(unloadedChunks);
existingChunks.addAll(loadedChunks); existingChunks.addAll(loadedChunks);
@@ -253,27 +268,27 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
} }
@Unique @Unique
private Set<ChunkPos> loadExistingChunks(final Set<ChunkPos> requestedChunks) private Set<ChunkPos> loadExistingChunks(Set<ChunkPos> requestedChunks)
{ {
return this.loadExistingChunks(requestedChunks, null); return this.loadExistingChunks(requestedChunks, null);
} }
@Unique @Unique
private void waitFor(final Future<?> future) private void waitFor(Future<?> future)
{ {
this.mainThreadExecutor.managedBlock(future::isDone); this.mainThreadExecutor.managedBlock(future::isDone);
} }
@Unique @Unique
private void waitFor(final List<? extends CompletableFuture<?>> futures) private void waitFor(List<? extends CompletableFuture<?>> futures)
{ {
this.waitFor(Util.sequenceFailFast(futures)); this.waitFor(Util.sequenceFailFast(futures));
} }
@Unique @Unique
private ChunkAccess getCurrentChunk(final ChunkPos pos) private ChunkAccess getCurrentChunk(ChunkPos pos)
{ {
final CompletableFuture<ChunkAccess> future = this.updatingChunkMap.get(pos.toLong()).getChunkToSave(); CompletableFuture<ChunkAccess> future = this.updatingChunkMap.get(pos.toLong()).getChunkToSave();
this.waitFor(future); this.waitFor(future);
return future.join(); return future.join();
@@ -285,95 +300,125 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
this.addTicket(pos); this.addTicket(pos);
this.tickTicketManager(); this.tickTicketManager();
if (this.updatingChunkMap.get(pos.toLong()).getLastAvailable() == null) // chunk unloaded if (this.updatingChunkMap.get(pos.toLong()).getLastAvailable() == null) // chunk unloaded
{
if (WorldTools.canHasChunk(this.level, pos, null, true)) if (WorldTools.canHasChunk(this.level, pos, null, true))
{
this.updatingChunkMap.get(pos.toLong()).getOrScheduleFuture(ChunkStatus.EMPTY, (ChunkMap) (Object) this); this.updatingChunkMap.get(pos.toLong()).getOrScheduleFuture(ChunkStatus.EMPTY, (ChunkMap) (Object) this);
final ChunkAccess chunk = this.getCurrentChunk(pos); }
if (!(chunk.getStatus().isOrAfter(ChunkStatus.LIGHT.getParent()))) return; }
ChunkAccess chunk = this.getCurrentChunk(pos);
if (!(chunk.getStatus().isOrAfter(ChunkStatus.LIGHT.getParent())))
{
return;
}
((ServerLightingProviderInterface) this.lightEngine).removeLightData(chunk); ((ServerLightingProviderInterface) this.lightEngine).removeLightData(chunk);
this.addRelightTicket(pos); this.addRelightTicket(pos);
ChunkHolder chunkHolder = this.updatingChunkMap.get(pos.toLong()); ChunkHolder chunkHolder = this.updatingChunkMap.get(pos.toLong());
final CompletableFuture<?> lightFuture = this.getChunkRangeFuture(chunkHolder, 1, (pos_) -> ChunkStatus.LIGHT) CompletableFuture<?> lightFuture = this.getChunkRangeFuture(chunkHolder, 1, (pos_) -> ChunkStatus.LIGHT)
.thenCompose( .thenCompose(results -> {
either -> either.map( List<ChunkAccess> depList = results.orElse(null);
list -> ((ServerLightingProviderInterface) this.lightEngine).relight(chunk), if (depList == null)
unloaded -> { {
this.releaseRelightTicket(pos); this.releaseRelightTicket(pos);
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(ChunkResult.error(results::getError));
} }
) ((ServerLightingProviderInterface) this.lightEngine).relight(chunk);
return CompletableFuture.completedFuture(ChunkResult.of(depList));
}
); );
this.waitFor(lightFuture); this.waitFor(lightFuture);
} }
@Override @Override
public Map<String, Integer> regenerateChunkRegion(final List<ChunkPos> requestedChunksList) public Map<String, Integer> regenerateChunkRegion(List<ChunkPos> requestedChunksList)
{ {
final Object2IntMap<String> report = new Object2IntOpenHashMap<>(); Object2IntMap<String> report = new Object2IntOpenHashMap<>();
final Set<ChunkPos> requestedChunks = new HashSet<>(requestedChunksList); Set<ChunkPos> requestedChunks = new HashSet<>(requestedChunksList);
// Load requested chunks // Load requested chunks
final Set<ChunkPos> existingChunks = this.loadExistingChunks(requestedChunks, report); Set<ChunkPos> existingChunks = this.loadExistingChunks(requestedChunks, report);
// Finish pending generation stages // Finish pending generation stages
// This ensures that no generation events will be put back on the main thread after the chunks have been deleted // This ensures that no generation events will be put back on the main thread after the chunks have been deleted
final Set<ChunkAccess> affectedChunks = new HashSet<>(); Set<ChunkAccess> affectedChunks = new HashSet<>();
for (final ChunkPos pos : existingChunks) for (ChunkPos pos : existingChunks)
{
affectedChunks.add(this.getCurrentChunk(pos)); affectedChunks.add(this.getCurrentChunk(pos));
}
report.put("affected_chunks", affectedChunks.size()); report.put("affected_chunks", affectedChunks.size());
// Load neighbors for light removal // Load neighbors for light removal
final Set<ChunkPos> neighbors = new HashSet<>(); Set<ChunkPos> neighbors = new HashSet<>();
for (final ChunkAccess chunk : affectedChunks) for (ChunkAccess chunk : affectedChunks)
{ {
final ChunkPos pos = chunk.getPos(); ChunkPos pos = chunk.getPos();
for (int x = -1; x <= 1; ++x) for (int x = -1; x <= 1; ++x)
{
for (int z = -1; z <= 1; ++z) for (int z = -1; z <= 1; ++z)
{
if (x != 0 || z != 0) if (x != 0 || z != 0)
{ {
final ChunkPos nPos = new ChunkPos(pos.x + x, pos.z + z); ChunkPos nPos = new ChunkPos(pos.x + x, pos.z + z);
if (!requestedChunks.contains(nPos)) if (!requestedChunks.contains(nPos))
{
neighbors.add(nPos); neighbors.add(nPos);
}
} }
}
}
} }
this.loadExistingChunks(neighbors); this.loadExistingChunks(neighbors);
// Determine affected neighbors // Determine affected neighbors
final Set<ChunkAccess> affectedNeighbors = new HashSet<>(); Set<ChunkAccess> affectedNeighbors = new HashSet<>();
for (final ChunkPos pos : neighbors) for (ChunkPos pos : neighbors)
{ {
final ChunkAccess chunk = this.getCurrentChunk(pos); ChunkAccess chunk = this.getCurrentChunk(pos);
if (chunk.getStatus().isOrAfter(ChunkStatus.LIGHT.getParent())) if (chunk.getStatus().isOrAfter(ChunkStatus.LIGHT.getParent()))
{
affectedNeighbors.add(chunk); affectedNeighbors.add(chunk);
}
} }
// Unload affected chunks // Unload affected chunks
for (final ChunkAccess chunk : affectedChunks) for (ChunkAccess chunk : affectedChunks)
{ {
final ChunkPos pos = chunk.getPos(); ChunkPos pos = chunk.getPos();
// remove entities // remove entities
long longPos = pos.toLong(); long longPos = pos.toLong();
if (this.entitiesInLevel.contains(longPos) && chunk instanceof LevelChunk) if (this.entitiesInLevel.contains(longPos) && chunk instanceof LevelChunk)
((SimpleEntityLookupInterface<Entity>)((ServerWorldInterface)level).getEntityLookupCMPublic()).getChunkEntities(pos).forEach(entity -> { if (!(entity instanceof Player)) entity.discard();}); {
((SimpleEntityLookupInterface<Entity>) ((ServerWorldInterface) level).getEntityLookupCMPublic()).getChunkEntities(pos).forEach(entity -> {
if (!(entity instanceof Player))
{
entity.discard();
}
});
}
if (chunk instanceof LevelChunk) if (chunk instanceof LevelChunk)
{
((LevelChunk) chunk).setLoaded(false); ((LevelChunk) chunk).setLoaded(false);
}
if (this.entitiesInLevel.remove(pos.toLong()) && chunk instanceof LevelChunk) if (this.entitiesInLevel.remove(pos.toLong()) && chunk instanceof LevelChunk)
{
this.level.unload((LevelChunk) chunk); // block entities only this.level.unload((LevelChunk) chunk); // block entities only
}
((ServerLightingProviderInterface) this.lightEngine).invokeUpdateChunkStatus(pos); ((ServerLightingProviderInterface) this.lightEngine).invokeUpdateChunkStatus(pos);
((ServerLightingProviderInterface) this.lightEngine).removeLightData(chunk); ((ServerLightingProviderInterface) this.lightEngine).removeLightData(chunk);
@@ -383,13 +428,13 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
// Replace ChunkHolders // Replace ChunkHolders
for (final ChunkAccess chunk : affectedChunks) for (ChunkAccess chunk : affectedChunks)
{ {
final ChunkPos cPos = chunk.getPos(); ChunkPos cPos = chunk.getPos();
final long pos = cPos.toLong(); long pos = cPos.toLong();
final ChunkHolder oldHolder = this.updatingChunkMap.remove(pos); ChunkHolder oldHolder = this.updatingChunkMap.remove(pos);
final ChunkHolder newHolder = new ChunkHolder(cPos, oldHolder.getTicketLevel(), level, this.lightEngine, this.queueSorter, (ChunkHolder.PlayerProvider) this); ChunkHolder newHolder = new ChunkHolder(cPos, oldHolder.getTicketLevel(), level, this.lightEngine, this.queueSorter, (ChunkHolder.PlayerProvider) this);
((ChunkHolderInterface) newHolder).setDefaultProtoChunk(cPos, this.mainThreadExecutor, level); // enable chunk blending? ((ChunkHolderInterface) newHolder).setDefaultProtoChunk(cPos, this.mainThreadExecutor, level); // enable chunk blending?
this.updatingChunkMap.put(pos, newHolder); this.updatingChunkMap.put(pos, newHolder);
@@ -400,50 +445,54 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
this.promoteChunkMap(); this.promoteChunkMap();
// Force generation to previous states // Force generation to previous states
// This ensures that the world is in a consistent state after this method // This ensures that the world is in a consistent state after this method
// Also, this is needed to ensure chunks are saved to disk // Also, this is needed to ensure chunks are saved to disk
final Map<ChunkPos, ChunkStatus> targetGenerationStatus = affectedChunks.stream().collect( Map<ChunkPos, ChunkStatus> targetGenerationStatus = affectedChunks.stream().collect(
Collectors.toMap(ChunkAccess::getPos, ChunkAccess::getStatus) Collectors.toMap(ChunkAccess::getPos, ChunkAccess::getStatus)
); );
for (final Entry<ChunkPos, ChunkStatus> entry : targetGenerationStatus.entrySet()) for (Entry<ChunkPos, ChunkStatus> entry : targetGenerationStatus.entrySet())
{
this.addTicket(entry.getKey(), entry.getValue()); this.addTicket(entry.getKey(), entry.getValue());
}
this.tickTicketManager(); this.tickTicketManager();
final List<Pair<ChunkStatus, CompletableFuture<?>>> targetGenerationFutures = new ArrayList<>(); List<Pair<ChunkStatus, CompletableFuture<?>>> targetGenerationFutures = new ArrayList<>();
for (final Entry<ChunkPos, ChunkStatus> entry : targetGenerationStatus.entrySet()) for (Entry<ChunkPos, ChunkStatus> entry : targetGenerationStatus.entrySet())
{
targetGenerationFutures.add(Pair.of( targetGenerationFutures.add(Pair.of(
entry.getValue(), entry.getValue(),
this.updatingChunkMap.get(entry.getKey().toLong()).getOrScheduleFuture(entry.getValue(), (ChunkMap) (Object) this) this.updatingChunkMap.get(entry.getKey().toLong()).getOrScheduleFuture(entry.getValue(), (ChunkMap) (Object) this)
)); ));
}
final Map<ChunkStatus, List<CompletableFuture<?>>> targetGenerationFuturesGrouped = targetGenerationFutures.stream().collect( Map<ChunkStatus, List<CompletableFuture<?>>> targetGenerationFuturesGrouped = targetGenerationFutures.stream().collect(
Collectors.groupingBy( Collectors.groupingBy(
Pair::getKey, Pair::getKey,
Collectors.mapping( Collectors.mapping(
Entry::getValue, Entry::getValue,
Collectors.toList() Collectors.toList()
)
) )
)
); );
for (final ChunkStatus status : ChunkStatus.getStatusList()) for (ChunkStatus status : ChunkStatus.getStatusList())
{ {
final List<CompletableFuture<?>> futures = targetGenerationFuturesGrouped.get(status); List<CompletableFuture<?>> futures = targetGenerationFuturesGrouped.get(status);
if (futures == null) if (futures == null)
{
continue; continue;
}
String statusName = BuiltInRegistries.CHUNK_STATUS.getKey(status).getPath(); String statusName = BuiltInRegistries.CHUNK_STATUS.getKey(status).getPath();
report.put("layer_count_" + statusName, futures.size()); report.put("layer_count_" + statusName, futures.size());
final long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
this.waitFor(futures); this.waitFor(futures);
@@ -451,42 +500,46 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
} }
report.put("relight_count", affectedNeighbors.size()); report.put("relight_count", affectedNeighbors.size());
// Remove light for affected neighbors // Remove light for affected neighbors
for (final ChunkAccess chunk : affectedNeighbors) for (ChunkAccess chunk : affectedNeighbors)
{
((ServerLightingProviderInterface) this.lightEngine).removeLightData(chunk); ((ServerLightingProviderInterface) this.lightEngine).removeLightData(chunk);
}
// Schedule relighting of neighbors // Schedule relighting of neighbors
for (final ChunkAccess chunk : affectedNeighbors) for (ChunkAccess chunk : affectedNeighbors)
{
this.addRelightTicket(chunk.getPos()); this.addRelightTicket(chunk.getPos());
}
this.tickTicketManager(); this.tickTicketManager();
final List<CompletableFuture<?>> lightFutures = new ArrayList<>(); List<CompletableFuture<?>> lightFutures = new ArrayList<>();
for (final ChunkAccess chunk : affectedNeighbors) for (ChunkAccess chunk : affectedNeighbors)
{ {
final ChunkPos pos = chunk.getPos(); ChunkPos pos = chunk.getPos();
lightFutures.add(this.getChunkRangeFuture (this.updatingChunkMap.get(pos.toLong()), 1, (pos_) -> ChunkStatus.LIGHT).thenCompose( lightFutures.add(this.getChunkRangeFuture(this.updatingChunkMap.get(pos.toLong()), 1, (pos_) -> ChunkStatus.LIGHT).thenCompose(
either -> either.map( results -> {
list -> ((ServerLightingProviderInterface) this.lightEngine).relight(chunk), List<ChunkAccess> depList = results.orElse(null);
unloaded -> { if (depList == null)
this.releaseRelightTicket(pos); {
return CompletableFuture.completedFuture(null); this.releaseRelightTicket(pos);
} return CompletableFuture.completedFuture(ChunkResult.error(results::getError));
) }
((ServerLightingProviderInterface) this.lightEngine).relight(chunk);
return CompletableFuture.completedFuture(ChunkResult.of(depList));
}
)); ));
} }
final long relightStart = System.currentTimeMillis(); long relightStart = System.currentTimeMillis();
this.waitFor(lightFutures); this.waitFor(lightFutures);
@@ -496,7 +549,8 @@ public abstract class ChunkMap_scarpetChunkCreationMixin implements ThreadedAnvi
} }
@Override @Override
public Iterable<ChunkHolder> getChunksCM() { public Iterable<ChunkHolder> getChunksCM()
{
return getChunks(); return getChunks();
} }
} }
@@ -11,7 +11,6 @@ import static carpet.script.CarpetEventServer.Event.PLAYER_PICKS_UP_ITEM;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@Mixin(Inventory.class) @Mixin(Inventory.class)
@@ -27,13 +26,11 @@ public abstract class Inventory_scarpetEventMixin
{ {
if (!PLAYER_PICKS_UP_ITEM.isNeeded() || !(player instanceof ServerPlayer)) if (!PLAYER_PICKS_UP_ITEM.isNeeded() || !(player instanceof ServerPlayer))
return playerInventory.add(-1, stack); return playerInventory.add(-1, stack);
Item item = stack.getItem();
int count = stack.getCount(); int count = stack.getCount();
boolean res = playerInventory.add(-1, stack); boolean res = playerInventory.add(-1, stack);
if (count != stack.getCount()) // res returns false for larger item adding to a almost full ineventory if (count != stack.getCount()) // res returns false for larger item adding to a almost full ineventory
{ {
ItemStack diffStack = new ItemStack(item, count - stack.getCount()); ItemStack diffStack = stack.copyWithCount(count - stack.getCount());
diffStack.setTag(stack.getTag());
PLAYER_PICKS_UP_ITEM.onItemAction((ServerPlayer) player, null, diffStack); PLAYER_PICKS_UP_ITEM.onItemAction((ServerPlayer) player, null, diffStack);
} }
return res; return res;
@@ -15,8 +15,8 @@ import org.spongepowered.asm.mixin.Mixin;
public class PickaxeItem_missingToolsMixin extends DiggerItem public class PickaxeItem_missingToolsMixin extends DiggerItem
{ {
protected PickaxeItem_missingToolsMixin(float attackDamage, float attackSpeed, Tier material, TagKey<Block> tag, Properties settings) { protected PickaxeItem_missingToolsMixin(Tier material, TagKey<Block> tag, Properties settings) {
super(attackDamage, attackSpeed, material, tag, settings); super(material, tag, settings);
} }
@Override @Override
@@ -106,7 +106,7 @@ public class CarpetClient
ListTag outputTag = (ListTag) tag.get("output"); ListTag outputTag = (ListTag) tag.get("output");
for (int i = 0; i < outputTag.size(); i++) for (int i = 0; i < outputTag.size(); i++)
{ {
CarpetSettings.LOG.info(" - response: " + Component.Serializer.fromJson(outputTag.getString(i)).getString()); CarpetSettings.LOG.info(" - response: " + Component.Serializer.fromJson(outputTag.getString(i), clientPlayer.registryAccess()).getString());
} }
} }
} }
@@ -102,7 +102,7 @@ public class ServerNetworkHandler
ListTag outputResult = new ListTag(); ListTag outputResult = new ListTag();
for (Component line : output) for (Component line : output)
{ {
outputResult.add(StringTag.valueOf(Component.Serializer.toJson(line))); outputResult.add(StringTag.valueOf(Component.Serializer.toJson(line, player.registryAccess())));
} }
if (!output.isEmpty()) if (!output.isEmpty())
{ {
@@ -15,6 +15,8 @@ import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import carpet.script.CarpetContext;
import net.minecraft.core.RegistryAccess;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.ClassUtils;
@@ -32,31 +34,31 @@ import carpet.script.value.Value;
/** /**
* <p>This class parses methods annotated with the {@link ScarpetFunction} annotation in a given {@link Class}, generating * <p>This class parses methods annotated with the {@link ScarpetFunction} annotation in a given {@link Class}, generating
* fully-featured, automatically parsed and converted functions to be used in the Scarpet language.</p> * fully-featured, automatically parsed and converted functions to be used in the Scarpet language.</p>
* *
* <p>This class and the rest in this package will try to ensure that the annotated method receives the proper parameters * <p>This class and the rest in this package will try to ensure that the annotated method receives the proper parameters
* directly, without all the always-repeated code of evaluating {@link Value}s, checking and casting them to their respective * directly, without all the always-repeated code of evaluating {@link Value}s, checking and casting them to their respective
* types, and converting them to the final needed object.</p> * types, and converting them to the final needed object.</p>
* *
* <p>To do that, functions will save a list of {@link ValueConverter}s to convert all their parameters. {@link ValueConverter}s * <p>To do that, functions will save a list of {@link ValueConverter}s to convert all their parameters. {@link ValueConverter}s
* are able to convert from any compatible {@link Value} instance into the requested parameter type, as long as they are registered * are able to convert from any compatible {@link Value} instance into the requested parameter type, as long as they are registered
* using their respective {@code register} functions.</p> * using their respective {@code register} functions.</p>
* *
* <p>Built-in {@link ValueConverter}s include but are not limited to converters to convert {@link List}s to actual Java lists while also * <p>Built-in {@link ValueConverter}s include but are not limited to converters to convert {@link List}s to actual Java lists while also
* converting every item inside of the {@link List} to the specified generic parameter ({@code <>}), with the same applying for maps</p> * converting every item inside of the {@link List} to the specified generic parameter ({@code <>}), with the same applying for maps</p>
* *
* <p>Parameters can be given the annotations (present in the {@link Locator} and {@link Param} interfaces) in order to restrict them or * <p>Parameters can be given the annotations (present in the {@link Locator} and {@link Param} interfaces) in order to restrict them or
* make them more permissive to accept types, such as {@link Param.AllowSingleton} for lists.</p> * make them more permissive to accept types, such as {@link Param.AllowSingleton} for lists.</p>
* *
* <p>You can also declare optional parameters by using Java's {@link Optional} as the type of one of your parameters, though it must be * <p>You can also declare optional parameters by using Java's {@link Optional} as the type of one of your parameters, though it must be
* at the end of the function, just before varargs if present and/or any other {@link Optional} parameters.</p> * at the end of the function, just before varargs if present and/or any other {@link Optional} parameters.</p>
* *
* <p>Output of the annotated methods will also be converted to a compatible {@link LazyValue} using the registered {@link OutputConverter}s, * <p>Output of the annotated methods will also be converted to a compatible {@link LazyValue} using the registered {@link OutputConverter}s,
* allowing to remove the need of explicitly converting to a {@link Value} and then to a {@link LazyValue} just to end the method (though you can * allowing to remove the need of explicitly converting to a {@link Value} and then to a {@link LazyValue} just to end the method (though you can
* return a {@link LazyValue} if you want.</p> * return a {@link LazyValue} if you want.</p>
* *
* <p>For a variable argument count, the Java varargs notation can be used in the last parameter, converting the function into a variable argument * <p>For a variable argument count, the Java varargs notation can be used in the last parameter, converting the function into a variable argument
* function that will pass all the rest of parameters to that last varargs parameter, also converted into the specified type.</p> * function that will pass all the rest of parameters to that last varargs parameter, also converted into the specified type.</p>
* *
* <p>To begin, use the {@link #parseFunctionClass(Class)} method in a class with methods annotated with the {@link ScarpetFunction} annotation.</p> * <p>To begin, use the {@link #parseFunctionClass(Class)} method in a class with methods annotated with the {@link ScarpetFunction} annotation.</p>
* *
* @see ScarpetFunction * @see ScarpetFunction
@@ -83,26 +85,26 @@ public final class AnnotationParser
/** /**
* <p>Parses a given {@link Class} and registers its annotated methods, the ones with the {@link ScarpetFunction} annotation, * <p>Parses a given {@link Class} and registers its annotated methods, the ones with the {@link ScarpetFunction} annotation,
* to be used in the Scarpet language.</p> * to be used in the Scarpet language.</p>
* *
* <p><b>Only call this method once per class per lifetime of the JVM!</b> (for example, at {@link carpet.CarpetExtension#onGameStarted()} or * <p><b>Only call this method once per class per lifetime of the JVM!</b> (for example, at {@link carpet.CarpetExtension#onGameStarted()} or
* {@link net.fabricmc.api.ModInitializer#onInitialize()}).</p> * {@link net.fabricmc.api.ModInitializer#onInitialize()}).</p>
* *
* <p>There is a set of requirements for the class and its methods:</p> * <p>There is a set of requirements for the class and its methods:</p>
* <ul> * <ul>
* <li>Annotated methods must not throw checked exceptions. They can throw regular {@link RuntimeException}s (including but not limited to * <li>Annotated methods must not throw checked exceptions. They can throw regular {@link RuntimeException}s (including but not limited to
* {@link InternalExpressionException}). * {@link InternalExpressionException}).
* Basically, it's fine as long as you don't add a {@code throws} declaration to your methods.</li> * Basically, it's fine as long as you don't add a {@code throws} declaration to your methods.</li>
* <li>Varargs (or effectively varargs) annotated methods must explicitly declare a maximum number of parameters to ingest in the {@link ScarpetFunction} * <li>Varargs (or effectively varargs) annotated methods must explicitly declare a maximum number of parameters to ingest in the {@link ScarpetFunction}
* annotation. They can still declare an unlimited amount by setting that maximum to {@link ScarpetFunction#UNLIMITED_PARAMS}. "Effectively varargs" * annotation. They can still declare an unlimited amount by setting that maximum to {@link ScarpetFunction#UNLIMITED_PARAMS}. "Effectively varargs"
* means a function that has at least a parameter requiring a {@link ValueConverter} that has declared {@link ValueConverter#consumesVariableArgs()}.</li> * means a function that has at least a parameter requiring a {@link ValueConverter} that has declared {@link ValueConverter#consumesVariableArgs()}.</li>
* <li>Annotated methods must not have a parameter with generics as the varargs parameter. This is just because it was painful for me (altrisi) and * <li>Annotated methods must not have a parameter with generics as the varargs parameter. This is just because it was painful for me (altrisi) and
* didn't want to support it. Those will crash with a {@code ClassCastException}</li> * didn't want to support it. Those will crash with a {@code ClassCastException}</li>
* </ul> * </ul>
* <p>Additionally, if the class contains annotated instance (non-static) methods, the class must be concrete and provide a no-arg constructor * <p>Additionally, if the class contains annotated instance (non-static) methods, the class must be concrete and provide a no-arg constructor
* to instantiate it.</p> * to instantiate it.</p>
* *
* @see ScarpetFunction
* @param clazz The class to parse * @param clazz The class to parse
* @see ScarpetFunction
*/ */
public static void parseFunctionClass(Class<?> clazz) public static void parseFunctionClass(Class<?> clazz)
{ {
@@ -119,7 +121,7 @@ public final class AnnotationParser
catch (ReflectiveOperationException e) catch (ReflectiveOperationException e)
{ {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Couldn't create instance of given " + clazz + ". This is needed for non-static methods. Make sure default constructor is available", e); "Couldn't create instance of given " + clazz + ". This is needed for non-static methods. Make sure default constructor is available", e);
} }
}); });
Method[] methodz = clazz.getDeclaredMethods(); Method[] methodz = clazz.getDeclaredMethods();
@@ -132,7 +134,7 @@ public final class AnnotationParser
if (method.getExceptionTypes().length != 0) if (method.getExceptionTypes().length != 0)
{ {
throw new IllegalArgumentException("Annotated method '" + method.getName() +"', provided in '"+clazz+"' must not declare checked exceptions"); throw new IllegalArgumentException("Annotated method '" + method.getName() + "', provided in '" + clazz + "' must not declare checked exceptions");
} }
ParsedFunction function = new ParsedFunction(method, clazz, instanceSupplier); ParsedFunction function = new ParsedFunction(method, clazz, instanceSupplier);
@@ -143,7 +145,7 @@ public final class AnnotationParser
/** /**
* <p>Adds all parsed functions to the given {@link Expression}.</p> * <p>Adds all parsed functions to the given {@link Expression}.</p>
* <p>This is handled automatically by Carpet</p> * <p>This is handled automatically by Carpet</p>
* *
* @param expr The expression to add every function to * @param expr The expression to add every function to
*/ */
public static void apply(Expression expr) public static void apply(Expression expr)
@@ -190,7 +192,7 @@ public final class AnnotationParser
} }
Class<?> originalVarArgsType = isMethodVarArgs ? methodParameters[methodParamCount - 1].getType().getComponentType() : null; Class<?> originalVarArgsType = isMethodVarArgs ? methodParameters[methodParamCount - 1].getType().getComponentType() : null;
this.varArgsType = ClassUtils.primitiveToWrapper(originalVarArgsType); // Primitive array cannot be cast to Obj[] this.varArgsType = ClassUtils.primitiveToWrapper(originalVarArgsType); // Primitive array cannot be cast to Obj[]
this.primitiveVarArgs = originalVarArgsType != null && originalVarArgsType.isPrimitive(); this.primitiveVarArgs = originalVarArgsType != null && originalVarArgsType.isPrimitive();
this.varArgsConverter = isMethodVarArgs ? ValueConverter.fromAnnotatedType(methodParameters[methodParamCount - 1].getAnnotatedType()) : null; this.varArgsConverter = isMethodVarArgs ? ValueConverter.fromAnnotatedType(methodParameters[methodParamCount - 1].getAnnotatedType()) : null;
@SuppressWarnings("unchecked") // Yes. Making a T is not worth @SuppressWarnings("unchecked") // Yes. Making a T is not worth
OutputConverter<Object> converter = OutputConverter.get((Class<Object>) method.getReturnType()); OutputConverter<Object> converter = OutputConverter.get((Class<Object>) method.getReturnType());
@@ -233,7 +235,8 @@ public final class AnnotationParser
MethodHandle tempHandle = MethodHandles.publicLookup().unreflect(method).asFixedArity().asSpreader(Object[].class, this.methodParamCount); MethodHandle tempHandle = MethodHandles.publicLookup().unreflect(method).asFixedArity().asSpreader(Object[].class, this.methodParamCount);
tempHandle = tempHandle.asType(tempHandle.type().changeReturnType(Object.class)); tempHandle = tempHandle.asType(tempHandle.type().changeReturnType(Object.class));
this.handle = Modifier.isStatic(method.getModifiers()) ? tempHandle : tempHandle.bindTo(instance.get()); this.handle = Modifier.isStatic(method.getModifiers()) ? tempHandle : tempHandle.bindTo(instance.get());
} catch (IllegalAccessException e) }
catch (IllegalAccessException e)
{ {
throw new IllegalArgumentException(e); throw new IllegalArgumentException(e);
} }
@@ -245,6 +248,8 @@ public final class AnnotationParser
@Override @Override
public LazyValue apply(Context context, Context.Type t, List<LazyValue> lazyValues) public LazyValue apply(Context context, Context.Type t, List<LazyValue> lazyValues)
{ {
// yes we are making a minecraft dependency, because of the stupid registry access required to parse stuff
RegistryAccess regs = ((CarpetContext) context).registryAccess();
List<Value> lv = AbstractLazyFunction.unpackLazy(lazyValues, context, contextType); List<Value> lv = AbstractLazyFunction.unpackLazy(lazyValues, context, contextType);
if (isEffectivelyVarArgs) if (isEffectivelyVarArgs)
{ {
@@ -262,7 +267,7 @@ public final class AnnotationParser
Object[] params = getMethodParams(lv, context, t); Object[] params = getMethodParams(lv, context, t);
try try
{ {
Value result = outputConverter.convert(handle.invokeExact(params)); Value result = outputConverter.convert(handle.invokeExact(params), regs);
return (cc, tt) -> result; return (cc, tt) -> result;
} }
catch (Throwable e) catch (Throwable e)
@@ -306,8 +311,9 @@ public final class AnnotationParser
} }
varArgsList.add(obj); varArgsList.add(obj);
} }
varArgs = varArgsList.toArray((Object[])Array.newInstance(varArgsType, 0)); varArgs = varArgsList.toArray((Object[]) Array.newInstance(varArgsType, 0));
} else }
else
{ {
varArgs = (Object[]) Array.newInstance(varArgsType, remaining / varArgsConverter.valueConsumption()); varArgs = (Object[]) Array.newInstance(varArgsType, remaining / varArgsConverter.valueConsumption());
for (int i = 0; lvIterator.hasNext(); i++) for (int i = 0; lvIterator.hasNext(); i++)
@@ -337,7 +343,8 @@ public final class AnnotationParser
builder.append(", "); builder.append(", ");
builder.append(varArgsConverter.getTypeName()); builder.append(varArgsConverter.getTypeName());
builder.append("s...)"); builder.append("s...)");
} else }
else
{ {
builder.append(')'); builder.append(')');
} }
@@ -346,5 +353,7 @@ public final class AnnotationParser
} }
} }
private AnnotationParser() {} private AnnotationParser()
{
}
} }
@@ -3,9 +3,11 @@ package carpet.script.annotation;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.GlobalPos; import net.minecraft.core.GlobalPos;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@@ -29,43 +31,43 @@ import javax.annotation.Nullable;
* <p>A converter from a given {@link Object} of type T into a {@link Value}, used in order to convert the outputs of methods into usable Scarpet * <p>A converter from a given {@link Object} of type T into a {@link Value}, used in order to convert the outputs of methods into usable Scarpet
* values.</p> * values.</p>
* *
* @see #register(Class, Function) * @see #register(Class, BiFunction)
* @param <T> The type to convert from into a {@link Value} * @param <T> The type to convert from into a {@link Value}
*/ */
public final class OutputConverter<T> public final class OutputConverter<T>
{ {
private static final Map<Class<?>, OutputConverter<?>> byResult = new HashMap<>(); private static final Map<Class<?>, OutputConverter<?>> byResult = new HashMap<>();
private static final OutputConverter<Value> VALUE = new OutputConverter<>(Function.identity()); private static final OutputConverter<Value> VALUE = new OutputConverter<>((v, regs) -> v);
static static
{ {
// Primitives are handled. Things are boxed in the process anyway, therefore would recommend boxed outputs, so you can use null // Primitives are handled. Things are boxed in the process anyway, therefore would recommend boxed outputs, so you can use null
register(Void.TYPE, v -> Value.NULL); register(Void.TYPE, v -> Value.NULL);
register(Boolean.class, BooleanValue::of); register(Boolean.class, BooleanValue::of);
register(Integer.class, NumericValue::new); register(Integer.class, (v, r) -> new NumericValue(v));
register(Double.class, NumericValue::of); register(Double.class, NumericValue::of);
register(Float.class, NumericValue::of); register(Float.class, NumericValue::of);
register(Long.class, NumericValue::new); register(Long.class, (v, r) -> new NumericValue(v));
register(String.class, StringValue::new); register(String.class, StringValue::new);
register(Entity.class, EntityValue::new); register(Entity.class, EntityValue::new);
register(Component.class, FormattedTextValue::new); register(Component.class, FormattedTextValue::new);
register(Tag.class, NBTSerializableValue::new); register(Tag.class, NBTSerializableValue::new);
register(BlockPos.class, ValueConversions::of); register(BlockPos.class, (v, r) -> ValueConversions.of(v));
register(Vec3.class, ValueConversions::of); register(Vec3.class, (v, r) -> ValueConversions.of(v));
register(ItemStack.class, ValueConversions::of); register(ItemStack.class, (v, r) -> ValueConversions.of(v, r));
register(ResourceLocation.class, ValueConversions::of); register(ResourceLocation.class, (v, r) -> ValueConversions.of(v));
register(GlobalPos.class, ValueConversions::of); register(GlobalPos.class, (v, r) -> ValueConversions.of(v));
} }
private final Function<T, Value> converter; private final BiFunction<T, RegistryAccess, Value> converter;
private OutputConverter(Function<T, Value> converter) private OutputConverter(BiFunction<T, RegistryAccess, Value> converter)
{ {
this.converter = converter; this.converter = converter;
} }
/** /**
* <p>Returns the {@link OutputConverter} for the specified returnType.</p> * <p>Returns the {@link OutputConverter} for the specified returnType.</p>
* *
* @param <T> The type of the {@link OutputConverter} you are looking for * @param <T> The type of the {@link OutputConverter} you are looking for
* @param returnType The class that the returned {@link OutputConverter} converts from * @param returnType The class that the returned {@link OutputConverter} converts from
* @return The {@link OutputConverter} for the specified returnType * @return The {@link OutputConverter} for the specified returnType
@@ -85,26 +87,26 @@ public final class OutputConverter<T>
/** /**
* <p>Converts the given input object into a {@link Value}, to be used in return values of Scarpet functions</p> * <p>Converts the given input object into a {@link Value}, to be used in return values of Scarpet functions</p>
* *
* <p>Returns {@link Value#NULL} if passed a {@code null} input</p> * <p>Returns {@link Value#NULL} if passed a {@code null} input</p>
* *
* @param input The value to convert * @param input The value to convert
* @return The converted value * @return The converted value
*/ */
public Value convert(@Nullable T input) public Value convert(@Nullable T input, RegistryAccess regs)
{ {
return input == null ? Value.NULL : converter.apply(input); return input == null ? Value.NULL : converter.apply(input, regs);
} }
/** /**
* <p>Registers a new type to be able to be used as the return value of methods, converting from inputType to a {@link Value} * <p>Registers a new type to be able to be used as the return value of methods, converting from inputType to a {@link Value}
* using the given function.</p> * using the given function.</p>
* *
* @param <T> The type of the input type * @param <T> The type of the input type
* @param inputType The class of T * @param inputType The class of T
* @param converter The function that converts the instance of T to a {@link Value} * @param converter The function that converts the instance of T to a {@link Value}
*/ */
public static <T> void register(Class<T> inputType, Function<T, Value> converter) public static <T> void register(Class<T> inputType, BiFunction<T, RegistryAccess, Value> converter)
{ {
OutputConverter<T> instance = new OutputConverter<>(converter); OutputConverter<T> instance = new OutputConverter<>(converter);
if (byResult.containsKey(inputType)) if (byResult.containsKey(inputType))
@@ -113,15 +115,24 @@ public final class OutputConverter<T>
} }
byResult.put(inputType, instance); byResult.put(inputType, instance);
} }
public static <T> void register(Class<T> inputType, Function<T, Value> converter)
{
register(inputType, (v, regs) -> converter.apply(v));
}
/** /**
* @see #register(Class, Function) * @see #register(Class, BiFunction)
* *
* @deprecated Just use {@link #register(Class, Function)}, it now does the same as this * @deprecated Just use {@link #register(Class, BiFunction)}, it now does the same as this
*/ */
@Deprecated @Deprecated
public static <T> void registerToValue(Class<T> inputType, Function<T, Value> converter) public static <T> void registerToValue(Class<T> inputType, BiFunction<T, RegistryAccess, Value> converter)
{ {
register(inputType, converter); register(inputType, converter);
} }
@Deprecated
public static <T> void registerToValue(Class<T> inputType, Function<T, Value> converter)
{
register(inputType, (v, regs) -> converter.apply(v));
}
} }
@@ -14,8 +14,6 @@ import carpet.script.argument.FunctionArgument;
import carpet.script.argument.Vector3Argument; 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.exception.ThrowStatement;
import carpet.script.exception.Throwables;
import carpet.script.external.Carpet; import carpet.script.external.Carpet;
import carpet.script.utils.SnoopyCommandSource; import carpet.script.utils.SnoopyCommandSource;
import carpet.script.utils.SystemInfo; import carpet.script.utils.SystemInfo;
@@ -348,7 +346,7 @@ public class Auxiliary
ShapeDispatcher.sendShape( ShapeDispatcher.sendShape(
(playerTargets.isEmpty()) ? cc.level().players() : playerTargets, (playerTargets.isEmpty()) ? cc.level().players() : playerTargets,
shapes shapes, cc.registryAccess()
); );
return Value.TRUE; return Value.TRUE;
}); });
@@ -475,7 +473,7 @@ public class Auxiliary
return BooleanValue.of(NbtUtils.compareNbt(match, source, numParam == 2 || lv.get(2).getBoolean())); return BooleanValue.of(NbtUtils.compareNbt(match, source, numParam == 2 || lv.get(2).getBoolean()));
}); });
expression.addFunction("encode_nbt", lv -> { expression.addContextFunction("encode_nbt", -1, (c, t, lv) -> {
int argSize = lv.size(); int argSize = lv.size();
if (argSize == 0 || argSize > 2) if (argSize == 0 || argSize > 2)
{ {
@@ -486,7 +484,7 @@ public class Auxiliary
Tag tag; Tag tag;
try try
{ {
tag = v.toTag(force); tag = v.toTag(force, ((CarpetContext)c).registryAccess());
} }
catch (NBTSerializableValue.IncompatibleTypeException exception) catch (NBTSerializableValue.IncompatibleTypeException exception)
{ {
@@ -19,16 +19,15 @@ import carpet.script.value.ScreenValue;
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.script.value.ValueConversions;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set; import java.util.Set;
import net.minecraft.commands.arguments.item.ItemInput;
import net.minecraft.core.HolderSet; import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
@@ -111,7 +110,7 @@ public class Inventories
type = cc.registry(Registries.RECIPE_TYPE).get(InputValidator.identifierOf(recipeType)); type = cc.registry(Registries.RECIPE_TYPE).get(InputValidator.identifierOf(recipeType));
if (type == null) if (type == null)
{ {
throw new InternalExpressionException("Unknown recipe type: "+recipeType); throw new InternalExpressionException("Unknown recipe type: " + recipeType);
} }
} }
List<Recipe<?>> recipes = Vanilla.RecipeManager_getAllMatching(cc.server().getRecipeManager(), type, InputValidator.identifierOf(recipeName), cc.registryAccess()); List<Recipe<?>> recipes = Vanilla.RecipeManager_getAllMatching(cc.server().getRecipeManager(), type, InputValidator.identifierOf(recipeName), cc.registryAccess());
@@ -125,7 +124,7 @@ public class Inventories
{ {
ItemStack result = recipe.getResultItem(regs); ItemStack result = recipe.getResultItem(regs);
List<Value> ingredientValue = new ArrayList<>(); List<Value> ingredientValue = new ArrayList<>();
recipe.getIngredients().forEach( ingredient -> { recipe.getIngredients().forEach(ingredient -> {
// I am flattening ingredient lists per slot. // I am flattening ingredient lists per slot.
// consider recipe_data('wooden_sword','crafting') and ('iron_nugget', 'blasting') and notice difference // consider recipe_data('wooden_sword','crafting') and ('iron_nugget', 'blasting') and notice difference
// in depths of lists. // in depths of lists.
@@ -142,7 +141,7 @@ public class Inventories
} }
}); });
Value recipeSpec; Value recipeSpec;
if (recipe instanceof final ShapedRecipe shapedRecipe) if (recipe instanceof ShapedRecipe shapedRecipe)
{ {
recipeSpec = ListValue.of( recipeSpec = ListValue.of(
new StringValue("shaped"), new StringValue("shaped"),
@@ -154,7 +153,7 @@ public class Inventories
{ {
recipeSpec = ListValue.of(new StringValue("shapeless")); recipeSpec = ListValue.of(new StringValue("shapeless"));
} }
else if (recipe instanceof final AbstractCookingRecipe abstractCookingRecipe) else if (recipe instanceof AbstractCookingRecipe abstractCookingRecipe)
{ {
recipeSpec = ListValue.of( recipeSpec = ListValue.of(
new StringValue("smelting"), new StringValue("smelting"),
@@ -249,9 +248,15 @@ public class Inventories
{ {
return Value.NULL; return Value.NULL;
} }
int count = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset() + 1)).getLong(); OptionalInt count = OptionalInt.empty();
Value countVal = lv.get(inventoryLocator.offset() + 1);
if (!countVal.isNull())
{
count = OptionalInt.of((int) NumericValue.asNumber(countVal).getLong());
}
RegistryAccess regs = cc.registryAccess(); RegistryAccess regs = cc.registryAccess();
if (count == 0) if (count.isPresent() && count.getAsInt() == 0)
{ {
// clear slot // clear slot
ItemStack removedStack = inventoryLocator.inventory().removeItemNoUpdate(slot); ItemStack removedStack = inventoryLocator.inventory().removeItemNoUpdate(slot);
@@ -262,16 +267,16 @@ public class Inventories
{ {
ItemStack previousStack = inventoryLocator.inventory().getItem(slot); ItemStack previousStack = inventoryLocator.inventory().getItem(slot);
ItemStack newStack = previousStack.copy(); ItemStack newStack = previousStack.copy();
newStack.setCount(count); count.ifPresent(newStack::setCount);
inventoryLocator.inventory().setItem(slot, newStack); inventoryLocator.inventory().setItem(slot, newStack);
syncPlayerInventory(inventoryLocator); syncPlayerInventory(inventoryLocator);
return ValueConversions.of(previousStack, regs); return ValueConversions.of(previousStack, regs);
} }
CompoundTag nbt = null; // skipping one argument CompoundTag nbt = null; // skipping one argument, item name
if (lv.size() > inventoryLocator.offset() + 3) if (lv.size() > inventoryLocator.offset() + 3)
{ {
Value nbtValue = lv.get(inventoryLocator.offset() + 3); Value nbtValue = lv.get(inventoryLocator.offset() + 3);
if (nbtValue instanceof final NBTSerializableValue nbtsv) if (nbtValue instanceof NBTSerializableValue nbtsv)
{ {
nbt = nbtsv.getCompoundTag(); nbt = nbtsv.getCompoundTag();
} }
@@ -280,17 +285,12 @@ public class Inventories
nbt = new NBTSerializableValue(nbtValue.getString()).getCompoundTag(); nbt = new NBTSerializableValue(nbtValue.getString()).getCompoundTag();
} }
} }
ItemInput newitem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset() + 2).getString(), nbt, cc.registryAccess()); ItemStack newitem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset() + 2).getString(), nbt, cc.registryAccess());
count.ifPresent(newitem::setCount);
ItemStack previousStack = inventoryLocator.inventory().getItem(slot); ItemStack previousStack = inventoryLocator.inventory().getItem(slot);
try inventoryLocator.inventory().setItem(slot, newitem);
{ syncPlayerInventory(inventoryLocator);
inventoryLocator.inventory().setItem(slot, newitem.createItemStack(count, false));
syncPlayerInventory(inventoryLocator);
}
catch (CommandSyntaxException e)
{
throw new InternalExpressionException(e.getMessage());
}
return ValueConversions.of(previousStack, regs); return ValueConversions.of(previousStack, regs);
}); });
@@ -303,7 +303,7 @@ public class Inventories
{ {
return Value.NULL; return Value.NULL;
} }
ItemInput itemArg = null; ItemStack itemArg = null;
if (lv.size() > inventoryLocator.offset()) if (lv.size() > inventoryLocator.offset())
{ {
Value secondArg = lv.get(inventoryLocator.offset()); Value secondArg = lv.get(inventoryLocator.offset());
@@ -342,7 +342,7 @@ public class Inventories
{ {
throw new InternalExpressionException("'inventory_remove' requires at least an item to be removed"); throw new InternalExpressionException("'inventory_remove' requires at least an item to be removed");
} }
ItemInput searchItem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset()).getString(), cc.registryAccess()); ItemStack searchItem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset()).getString(), cc.registryAccess());
int amount = 1; int amount = 1;
if (lv.size() > inventoryLocator.offset() + 1) if (lv.size() > inventoryLocator.offset() + 1)
{ {
@@ -424,7 +424,7 @@ public class Inventories
} }
Object owner = inventoryLocator.owner(); Object owner = inventoryLocator.owner();
ItemEntity item; ItemEntity item;
if (owner instanceof final Player player) if (owner instanceof Player player)
{ {
item = player.drop(droppedStack, false, true); item = player.drop(droppedStack, false, true);
if (item == null) if (item == null)
@@ -478,7 +478,7 @@ public class Inventories
expression.addContextFunction("close_screen", 1, (c, t, lv) -> expression.addContextFunction("close_screen", 1, (c, t, lv) ->
{ {
Value value = lv.get(0); Value value = lv.get(0);
if (!(value instanceof final ScreenValue screenValue)) if (!(value instanceof ScreenValue screenValue))
{ {
throw new InternalExpressionException("'close_screen' requires a screen value as the first argument."); throw new InternalExpressionException("'close_screen' requires a screen value as the first argument.");
} }
@@ -496,7 +496,7 @@ public class Inventories
{ {
throw new InternalExpressionException("'screen_property' requires at least a screen and a property name"); throw new InternalExpressionException("'screen_property' requires at least a screen and a property name");
} }
if (!(lv.get(0) instanceof final ScreenValue screenValue)) if (!(lv.get(0) instanceof ScreenValue screenValue))
{ {
throw new InternalExpressionException("'screen_property' requires a screen value as the first argument"); throw new InternalExpressionException("'screen_property' requires a screen value as the first argument");
} }
@@ -38,6 +38,7 @@ import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet; import net.minecraft.core.HolderSet;
import net.minecraft.core.QuartPos; import net.minecraft.core.QuartPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
@@ -51,6 +52,7 @@ import net.minecraft.sounds.SoundEvents;
import net.minecraft.tags.TagKey; import net.minecraft.tags.TagKey;
import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.levelgen.DensityFunction; import net.minecraft.world.level.levelgen.DensityFunction;
import net.minecraft.world.level.levelgen.DensityFunctions; import net.minecraft.world.level.levelgen.DensityFunctions;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
@@ -121,7 +123,6 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.WorldgenRandom; import net.minecraft.world.level.levelgen.WorldgenRandom;
@@ -840,6 +841,7 @@ public class WorldAccess
expression.addContextFunction("destroy", -1, (c, t, lv) -> expression.addContextFunction("destroy", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
RegistryAccess regs = cc.registryAccess();
ServerLevel world = cc.level(); ServerLevel world = cc.level();
BlockArgument locator = BlockArgument.findIn(cc, lv, 0); BlockArgument locator = BlockArgument.findIn(cc, lv, 0);
BlockState state = locator.block.getBlockState(); BlockState state = locator.block.getBlockState();
@@ -882,11 +884,14 @@ public class WorldAccess
: NBTSerializableValue.parseStringOrFail(tagValue.getString()).getCompoundTag(); : NBTSerializableValue.parseStringOrFail(tagValue.getString()).getCompoundTag();
} }
} }
ItemStack tool;
ItemStack tool = new ItemStack(item, 1);
if (tag != null) if (tag != null)
{ {
tool.setTag(tag); tool = ItemStack.parseOptional(regs, tag);
}
else
{
tool = new ItemStack(item, 1);
} }
if (playerBreak && state.getDestroySpeed(world, where) < 0.0) if (playerBreak && state.getDestroySpeed(world, where) < 0.0)
{ {
@@ -950,8 +955,7 @@ public class WorldAccess
{ {
return Value.NULL; return Value.NULL;
} }
Tag outtag = tool.getTag(); return new NBTSerializableValue(() -> tool.saveOptional(regs));
return outtag == null ? Value.TRUE : new NBTSerializableValue(() -> outtag);
}); });
@@ -1106,7 +1110,7 @@ public class WorldAccess
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
String itemString = lv.get(0).getString(); String itemString = lv.get(0).getString();
Vector3Argument locator = Vector3Argument.findIn(lv, 1); Vector3Argument locator = Vector3Argument.findIn(lv, 1);
ItemInput stackArg = NBTSerializableValue.parseItem(itemString, cc.registryAccess()); ItemStack stackArg = NBTSerializableValue.parseItem(itemString, cc.registryAccess());
BlockPos where = BlockPos.containing(locator.vec); BlockPos where = BlockPos.containing(locator.vec);
// Paintings throw an exception if their direction is vertical, therefore we change the default here // Paintings throw an exception if their direction is vertical, therefore we change the default here
String facing = lv.size() > locator.offset String facing = lv.size() > locator.offset
@@ -1118,15 +1122,7 @@ public class WorldAccess
sneakPlace = lv.get(locator.offset + 1).getBoolean(); sneakPlace = lv.get(locator.offset + 1).getBoolean();
} }
BlockValue.PlacementContext ctx; BlockValue.PlacementContext ctx = BlockValue.PlacementContext.from(cc.level(), where, facing, sneakPlace, stackArg);
try
{
ctx = BlockValue.PlacementContext.from(cc.level(), where, facing, sneakPlace, stackArg.createItemStack(1, false));
}
catch (CommandSyntaxException e)
{
throw new InternalExpressionException(e.getMessage());
}
if (!(stackArg.getItem() instanceof final BlockItem blockItem)) if (!(stackArg.getItem() instanceof final BlockItem blockItem))
{ {
@@ -1160,7 +1156,7 @@ public class WorldAccess
expression.addContextFunction("blocks_movement", -1, (c, t, lv) -> expression.addContextFunction("blocks_movement", -1, (c, t, lv) ->
booleanStateTest(c, "blocks_movement", lv, (s, p) -> booleanStateTest(c, "blocks_movement", lv, (s, p) ->
!s.isPathfindable(((CarpetContext) c).level(), p, PathComputationType.LAND))); !s.isPathfindable(PathComputationType.LAND)));
expression.addContextFunction("block_sound", -1, (c, t, lv) -> expression.addContextFunction("block_sound", -1, (c, t, lv) ->
stateStringQuery(c, "block_sound", lv, (s, p) -> stateStringQuery(c, "block_sound", lv, (s, p) ->
@@ -144,7 +144,7 @@ public class ShapeDispatcher
return new ShapeWithConfig(ShapeDispatcher.create(server, shapeType, params), params); return new ShapeWithConfig(ShapeDispatcher.create(server, shapeType, params), params);
} }
public static void sendShape(Collection<ServerPlayer> players, List<ShapeWithConfig> shapes) public static void sendShape(Collection<ServerPlayer> players, List<ShapeWithConfig> shapes, RegistryAccess regs)
{ {
List<ServerPlayer> clientPlayers = new ArrayList<>(); List<ServerPlayer> clientPlayers = new ArrayList<>();
List<ServerPlayer> alternativePlayers = new ArrayList<>(); List<ServerPlayer> alternativePlayers = new ArrayList<>();
@@ -158,7 +158,7 @@ public class ShapeDispatcher
int tagcount = 0; int tagcount = 0;
for (ShapeWithConfig s : shapes) for (ShapeWithConfig s : shapes)
{ {
tag.add(ExpiringShape.toTag(s.config())); // 4000 shapes limit boxes tag.add(ExpiringShape.toTag(s.config(), regs)); // 4000 shapes limit boxes
if (tagcount++ > 1000) if (tagcount++ > 1000)
{ {
tagcount = 0; tagcount = 0;
@@ -312,11 +312,11 @@ public class ShapeDispatcher
{ {
} }
public static CompoundTag toTag(Map<String, Value> params) public static CompoundTag toTag(Map<String, Value> params, RegistryAccess regs)
{ {
CompoundTag tag = new CompoundTag(); CompoundTag tag = new CompoundTag();
params.forEach((k, v) -> { params.forEach((k, v) -> {
Tag valTag = Param.of.get(k).toTag(v); Tag valTag = Param.of.get(k).toTag(v, regs);
if (valTag != null) if (valTag != null)
{ {
tag.put(k, valTag); tag.put(k, valTag);
@@ -724,7 +724,7 @@ public class ShapeDispatcher
} }
else else
{ {
this.item = ItemStack.of(((NBTSerializableValue) options.get("item")).getCompoundTag()); this.item = ItemStack.parseOptional(regs, ((NBTSerializableValue) options.get("item")).getCompoundTag());
} }
blockLight = NumericValue.asNumber(options.getOrDefault("blocklight", optional.get("blocklight"))).getInt(); blockLight = NumericValue.asNumber(options.getOrDefault("blocklight", optional.get("blocklight"))).getInt();
if (blockLight > 15) if (blockLight > 15)
@@ -1532,7 +1532,7 @@ public class ShapeDispatcher
} }
@Nullable @Nullable
public abstract Tag toTag(Value value); //validates value, returning null if not necessary to keep it and serialize public abstract Tag toTag(Value value, final RegistryAccess regs); //validates value, returning null if not necessary to keep it and serialize
public abstract Value validate(Map<String, Value> options, MinecraftServer server, Value value); // makes sure the value is proper public abstract Value validate(Map<String, Value> options, MinecraftServer server, Value value); // makes sure the value is proper
@@ -1547,9 +1547,9 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return value.toTag(true); return value.toTag(true, regs);
} }
@Override @Override
@@ -1589,7 +1589,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return StringTag.valueOf(value.getString()); return StringTag.valueOf(value.getString());
} }
@@ -1621,7 +1621,7 @@ public class ShapeDispatcher
@Nullable @Nullable
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
if (value instanceof final BlockValue blv) if (value instanceof final BlockValue blv)
{ {
@@ -1661,11 +1661,11 @@ public class ShapeDispatcher
public Value validate(Map<String, Value> options, MinecraftServer server, Value value) public Value validate(Map<String, Value> options, MinecraftServer server, Value value)
{ {
ItemStack item = ValueConversions.getItemStackFromValue(value, true, server.registryAccess()); ItemStack item = ValueConversions.getItemStackFromValue(value, true, server.registryAccess());
return new NBTSerializableValue(item.save(new CompoundTag())); return new NBTSerializableValue(item.save(server.registryAccess()));
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return ((NBTSerializableValue) value).getTag(); return ((NBTSerializableValue) value).getTag();
} }
@@ -1710,19 +1710,19 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
if (!(value instanceof FormattedTextValue)) if (!(value instanceof FormattedTextValue))
{ {
value = new FormattedTextValue(Component.literal(value.getString())); value = new FormattedTextValue(Component.literal(value.getString()));
} }
return StringTag.valueOf(((FormattedTextValue) value).serialize()); return StringTag.valueOf(((FormattedTextValue) value).serialize(regs));
} }
@Override @Override
public Value decode(Tag tag, Level level) public Value decode(Tag tag, Level level)
{ {
return FormattedTextValue.deserialize(tag.getAsString()); return FormattedTextValue.deserialize(tag.getAsString(), level.registryAccess());
} }
} }
@@ -1808,7 +1808,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return ByteTag.valueOf(value.getBoolean()); return ByteTag.valueOf(value.getBoolean());
} }
@@ -1834,7 +1834,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return FloatTag.valueOf(NumericValue.asNumber(value, id).getFloat()); return FloatTag.valueOf(NumericValue.asNumber(value, id).getFloat());
} }
@@ -1873,7 +1873,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return FloatTag.valueOf(NumericValue.asNumber(value, id).getFloat()); return FloatTag.valueOf(NumericValue.asNumber(value, id).getFloat());
} }
@@ -1894,7 +1894,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return IntTag.valueOf(NumericValue.asNumber(value, id).getInt()); return IntTag.valueOf(NumericValue.asNumber(value, id).getInt());
} }
@@ -1915,7 +1915,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return IntTag.valueOf(NumericValue.asNumber(value, id).getInt()); return IntTag.valueOf(NumericValue.asNumber(value, id).getInt());
} }
@@ -1946,7 +1946,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return FloatTag.valueOf(NumericValue.asNumber(value, id).getFloat()); return FloatTag.valueOf(NumericValue.asNumber(value, id).getFloat());
} }
@@ -2041,7 +2041,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
List<Value> lv = ((ListValue) value).getItems(); List<Value> lv = ((ListValue) value).getItems();
ListTag tag = new ListTag(); ListTag tag = new ListTag();
@@ -2092,7 +2092,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value pointsValue) public Tag toTag(Value pointsValue, final RegistryAccess regs)
{ {
List<Value> lv = ((ListValue) pointsValue).getItems(); List<Value> lv = ((ListValue) pointsValue).getItems();
ListTag ltag = new ListTag(); ListTag ltag = new ListTag();
@@ -2124,7 +2124,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return IntTag.valueOf(NumericValue.asNumber(value, id).getInt()); return IntTag.valueOf(NumericValue.asNumber(value, id).getInt());
} }
@@ -2139,7 +2139,7 @@ public class ShapeDispatcher
} }
@Override @Override
public Tag toTag(Value value) public Tag toTag(Value value, final RegistryAccess regs)
{ {
return IntTag.valueOf(NumericValue.asNumber(value, id).getInt()); return IntTag.valueOf(NumericValue.asNumber(value, id).getInt());
} }
@@ -23,8 +23,8 @@ import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.biome.MultiNoiseBiomeSource; import net.minecraft.world.level.biome.MultiNoiseBiomeSource;
import net.minecraft.world.level.border.BorderChangeListener; import net.minecraft.world.level.border.BorderChangeListener;
import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.storage.RegionFile; import net.minecraft.world.level.chunk.storage.RegionFile;
import net.minecraft.world.level.chunk.storage.RegionStorageInfo; import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.DimensionType;
@@ -21,6 +21,7 @@ import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.Axis;
import net.minecraft.core.GlobalPos; import net.minecraft.core.GlobalPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.StringTag; import net.minecraft.nbt.StringTag;
@@ -41,7 +42,6 @@ import net.minecraft.world.phys.Vec3;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static carpet.script.value.NBTSerializableValue.nameFromRegistryId;
import static carpet.script.value.NBTSerializableValue.nameFromResource; import static carpet.script.value.NBTSerializableValue.nameFromResource;
public class BlockValue extends Value public class BlockValue extends Value
@@ -240,7 +240,7 @@ public class BlockValue extends Value
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
if (!force) if (!force)
{ {
@@ -2,6 +2,7 @@ package carpet.script.value;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.ByteTag; import net.minecraft.nbt.ByteTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
@@ -54,7 +55,7 @@ public class BooleanValue extends NumericValue
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
return ByteTag.valueOf(boolValue); return ByteTag.valueOf(boolValue);
} }
+120 -119
View File
@@ -131,7 +131,7 @@ public class EntityValue extends Value
public Entity getEntity() public Entity getEntity()
{ {
if (entity instanceof final ServerPlayer serverPlayer && Vanilla.ServerPlayer_isInvalidEntityObject(serverPlayer)) if (entity instanceof ServerPlayer serverPlayer && Vanilla.ServerPlayer_isInvalidEntityObject(serverPlayer))
{ {
ServerPlayer newPlayer = entity.getServer().getPlayerList().getPlayer(entity.getUUID()); ServerPlayer newPlayer = entity.getServer().getPlayerList().getPlayer(entity.getUUID());
if (newPlayer != null) if (newPlayer != null)
@@ -144,7 +144,7 @@ public class EntityValue extends Value
public static ServerPlayer getPlayerByValue(MinecraftServer server, Value value) public static ServerPlayer getPlayerByValue(MinecraftServer server, Value value)
{ {
if (value instanceof final EntityValue ev && ev.getEntity() instanceof final ServerPlayer sp) if (value instanceof EntityValue ev && ev.getEntity() instanceof ServerPlayer sp)
{ {
return sp; return sp;
} }
@@ -158,7 +158,7 @@ public class EntityValue extends Value
public static String getPlayerNameByValue(Value value) public static String getPlayerNameByValue(Value value)
{ {
if (value instanceof final EntityValue ev && ev.getEntity() instanceof final ServerPlayer sp) if (value instanceof EntityValue ev && ev.getEntity() instanceof ServerPlayer sp)
{ {
return sp.getScoreboardName(); return sp.getScoreboardName();
} }
@@ -184,7 +184,7 @@ public class EntityValue extends Value
@Override @Override
public boolean equals(Object v) public boolean equals(Object v)
{ {
if (v instanceof final EntityValue ev) if (v instanceof EntityValue ev)
{ {
return getEntity().getId() == ev.getEntity().getId(); return getEntity().getId() == ev.getEntity().getId();
} }
@@ -194,7 +194,7 @@ public class EntityValue extends Value
@Override @Override
public Value in(Value v) public Value in(Value v)
{ {
if (v instanceof final ListValue lv) if (v instanceof ListValue lv)
{ {
List<Value> values = lv.getItems(); List<Value> values = lv.getItems();
String what = values.get(0).getString(); String what = values.get(0).getString();
@@ -478,7 +478,7 @@ public class EntityValue extends Value
put("yaw", (e, a) -> new NumericValue(e.getYRot())); put("yaw", (e, a) -> new NumericValue(e.getYRot()));
put("head_yaw", (e, a) -> e instanceof LivingEntity ? new NumericValue(e.getYHeadRot()) : Value.NULL); put("head_yaw", (e, a) -> e instanceof LivingEntity ? new NumericValue(e.getYHeadRot()) : Value.NULL);
put("body_yaw", (e, a) -> e instanceof final LivingEntity le ? new NumericValue(le.yBodyRot) : Value.NULL); put("body_yaw", (e, a) -> e instanceof LivingEntity le ? new NumericValue(le.yBodyRot) : Value.NULL);
put("pitch", (e, a) -> new NumericValue(e.getXRot())); put("pitch", (e, a) -> new NumericValue(e.getXRot()));
put("look", (e, a) -> { put("look", (e, a) -> {
@@ -500,19 +500,19 @@ public class EntityValue extends Value
put("width", (e, a) -> new NumericValue(e.getDimensions(Pose.STANDING).width())); put("width", (e, a) -> new NumericValue(e.getDimensions(Pose.STANDING).width()));
put("eye_height", (e, a) -> new NumericValue(e.getEyeHeight())); put("eye_height", (e, a) -> new NumericValue(e.getEyeHeight()));
put("age", (e, a) -> new NumericValue(e.tickCount)); put("age", (e, a) -> new NumericValue(e.tickCount));
put("breeding_age", (e, a) -> e instanceof final AgeableMob am ? new NumericValue(am.getAge()) : Value.NULL); put("breeding_age", (e, a) -> e instanceof AgeableMob am ? new NumericValue(am.getAge()) : Value.NULL);
put("despawn_timer", (e, a) -> e instanceof final LivingEntity le ? new NumericValue(le.getNoActionTime()) : Value.NULL); put("despawn_timer", (e, a) -> e instanceof LivingEntity le ? new NumericValue(le.getNoActionTime()) : Value.NULL);
put("blue_skull", (e, a) -> e instanceof final WitherSkull w ? BooleanValue.of(w.isDangerous()) : Value.NULL); put("blue_skull", (e, a) -> e instanceof WitherSkull w ? BooleanValue.of(w.isDangerous()) : Value.NULL);
put("offering_flower", (e, a) -> e instanceof final IronGolem ig ? BooleanValue.of(ig.getOfferFlowerTick() > 0) : Value.NULL); put("offering_flower", (e, a) -> e instanceof IronGolem ig ? BooleanValue.of(ig.getOfferFlowerTick() > 0) : Value.NULL);
put("item", (e, a) -> e instanceof final ItemEntity ie ? ValueConversions.of(ie.getItem(), e.getServer().registryAccess()) : e instanceof final ItemFrame frame ? ValueConversions.of(frame.getItem(), e.getServer().registryAccess()) : Value.NULL); put("item", (e, a) -> e instanceof ItemEntity ie ? ValueConversions.of(ie.getItem(), e.getServer().registryAccess()) : e instanceof ItemFrame frame ? ValueConversions.of(frame.getItem(), e.getServer().registryAccess()) : Value.NULL);
put("count", (e, a) -> (e instanceof final ItemEntity ie) ? new NumericValue(ie.getItem().getCount()) : Value.NULL); put("count", (e, a) -> (e instanceof ItemEntity ie) ? new NumericValue(ie.getItem().getCount()) : Value.NULL);
put("pickup_delay", (e, a) -> (e instanceof final ItemEntity ie) ? new NumericValue(Vanilla.ItemEntity_getPickupDelay(ie)) : Value.NULL); put("pickup_delay", (e, a) -> (e instanceof ItemEntity ie) ? new NumericValue(Vanilla.ItemEntity_getPickupDelay(ie)) : Value.NULL);
put("portal_cooldown", (e, a) -> new NumericValue(Vanilla.Entity_getPublicNetherPortalCooldown(e))); put("portal_cooldown", (e, a) -> new NumericValue(Vanilla.Entity_getPublicNetherPortalCooldown(e)));
put("portal_timer", (e, a) -> new NumericValue(Vanilla.Entity_getPortalTimer(e))); put("portal_timer", (e, a) -> new NumericValue(Vanilla.Entity_getPortalTimer(e)));
// ItemEntity -> despawn timer via ssGetAge // ItemEntity -> despawn timer via ssGetAge
put("is_baby", (e, a) -> (e instanceof final LivingEntity le) ? BooleanValue.of(le.isBaby()) : Value.NULL); put("is_baby", (e, a) -> (e instanceof LivingEntity le) ? BooleanValue.of(le.isBaby()) : Value.NULL);
put("target", (e, a) -> { put("target", (e, a) -> {
if (e instanceof final Mob mob) if (e instanceof Mob mob)
{ {
LivingEntity target = mob.getTarget(); // there is also getAttacking in living.... LivingEntity target = mob.getTarget(); // there is also getAttacking in living....
if (target != null) if (target != null)
@@ -522,9 +522,9 @@ public class EntityValue extends Value
} }
return Value.NULL; return Value.NULL;
}); });
put("home", (e, a) -> e instanceof final Mob mob ? (mob.getRestrictRadius() > 0) ? new BlockValue(null, (ServerLevel) e.level(), mob.getRestrictCenter()) : Value.FALSE : Value.NULL); put("home", (e, a) -> e instanceof Mob mob ? (mob.getRestrictRadius() > 0) ? new BlockValue(null, (ServerLevel) e.level(), mob.getRestrictCenter()) : Value.FALSE : Value.NULL);
put("spawn_point", (e, a) -> { put("spawn_point", (e, a) -> {
if (e instanceof final ServerPlayer spe) if (e instanceof ServerPlayer spe)
{ {
if (spe.getRespawnPosition() == null) if (spe.getRespawnPosition() == null)
{ {
@@ -543,22 +543,22 @@ public class EntityValue extends Value
put("sneaking", (e, a) -> e.isShiftKeyDown() ? Value.TRUE : Value.FALSE); put("sneaking", (e, a) -> e.isShiftKeyDown() ? Value.TRUE : Value.FALSE);
put("sprinting", (e, a) -> e.isSprinting() ? Value.TRUE : Value.FALSE); put("sprinting", (e, a) -> e.isSprinting() ? Value.TRUE : Value.FALSE);
put("swimming", (e, a) -> e.isSwimming() ? Value.TRUE : Value.FALSE); put("swimming", (e, a) -> e.isSwimming() ? Value.TRUE : Value.FALSE);
put("swinging", (e, a) -> e instanceof final LivingEntity le ? BooleanValue.of(le.swinging) : Value.NULL); put("swinging", (e, a) -> e instanceof LivingEntity le ? BooleanValue.of(le.swinging) : Value.NULL);
put("air", (e, a) -> new NumericValue(e.getAirSupply())); put("air", (e, a) -> new NumericValue(e.getAirSupply()));
put("language", (e, a) -> !(e instanceof final ServerPlayer p) ? NULL : StringValue.of(Vanilla.ServerPlayer_getLanguage(p))); put("language", (e, a) -> !(e instanceof ServerPlayer p) ? NULL : StringValue.of(Vanilla.ServerPlayer_getLanguage(p)));
put("persistence", (e, a) -> e instanceof final Mob mob ? BooleanValue.of(mob.isPersistenceRequired()) : Value.NULL); put("persistence", (e, a) -> e instanceof Mob mob ? BooleanValue.of(mob.isPersistenceRequired()) : Value.NULL);
put("hunger", (e, a) -> e instanceof final Player player ? new NumericValue(player.getFoodData().getFoodLevel()) : Value.NULL); put("hunger", (e, a) -> e instanceof Player player ? new NumericValue(player.getFoodData().getFoodLevel()) : Value.NULL);
put("saturation", (e, a) -> e instanceof final Player player ? new NumericValue(player.getFoodData().getSaturationLevel()) : Value.NULL); put("saturation", (e, a) -> e instanceof Player player ? new NumericValue(player.getFoodData().getSaturationLevel()) : Value.NULL);
put("exhaustion", (e, a) -> e instanceof final Player player ? new NumericValue(player.getFoodData().getExhaustionLevel()) : Value.NULL); put("exhaustion", (e, a) -> e instanceof Player player ? new NumericValue(player.getFoodData().getExhaustionLevel()) : Value.NULL);
put("absorption", (e, a) -> e instanceof final Player player ? new NumericValue(player.getAbsorptionAmount()) : Value.NULL); put("absorption", (e, a) -> e instanceof Player player ? new NumericValue(player.getAbsorptionAmount()) : Value.NULL);
put("xp", (e, a) -> e instanceof final Player player ? new NumericValue(player.totalExperience) : Value.NULL); put("xp", (e, a) -> e instanceof Player player ? new NumericValue(player.totalExperience) : Value.NULL);
put("xp_level", (e, a) -> e instanceof final Player player ? new NumericValue(player.experienceLevel) : Value.NULL); put("xp_level", (e, a) -> e instanceof Player player ? new NumericValue(player.experienceLevel) : Value.NULL);
put("xp_progress", (e, a) -> e instanceof final Player player ? new NumericValue(player.experienceProgress) : Value.NULL); put("xp_progress", (e, a) -> e instanceof Player player ? new NumericValue(player.experienceProgress) : Value.NULL);
put("score", (e, a) -> e instanceof final Player player ? new NumericValue(player.getScore()) : Value.NULL); put("score", (e, a) -> e instanceof Player player ? new NumericValue(player.getScore()) : Value.NULL);
put("jumping", (e, a) -> e instanceof final LivingEntity le ? Vanilla.LivingEntity_isJumping(le) ? Value.TRUE : Value.FALSE : Value.NULL); put("jumping", (e, a) -> e instanceof LivingEntity le ? Vanilla.LivingEntity_isJumping(le) ? Value.TRUE : Value.FALSE : Value.NULL);
put("gamemode", (e, a) -> e instanceof final ServerPlayer sp ? new StringValue(sp.gameMode.getGameModeForPlayer().getName()) : Value.NULL); put("gamemode", (e, a) -> e instanceof ServerPlayer sp ? new StringValue(sp.gameMode.getGameModeForPlayer().getName()) : Value.NULL);
put("path", (e, a) -> { put("path", (e, a) -> {
if (e instanceof final Mob mob) if (e instanceof Mob mob)
{ {
Path path = mob.getNavigation().getPath(); Path path = mob.getNavigation().getPath();
if (path == null) if (path == null)
@@ -577,7 +577,7 @@ public class EntityValue extends Value
{ {
return Value.NULL; return Value.NULL;
} }
if (e instanceof final LivingEntity livingEntity) if (e instanceof LivingEntity livingEntity)
{ {
Brain<?> brain = livingEntity.getBrain(); Brain<?> brain = livingEntity.getBrain();
Map<MemoryModuleType<?>, Optional<? extends ExpirableValue<?>>> memories = brain.getMemories(); Map<MemoryModuleType<?>, Optional<? extends ExpirableValue<?>>> memories = brain.getMemories();
@@ -591,9 +591,9 @@ public class EntityValue extends Value
} }
return Value.NULL; return Value.NULL;
}); });
put("gamemode_id", (e, a) -> e instanceof final ServerPlayer sp ? new NumericValue(sp.gameMode.getGameModeForPlayer().getId()) : Value.NULL); put("gamemode_id", (e, a) -> e instanceof ServerPlayer sp ? new NumericValue(sp.gameMode.getGameModeForPlayer().getId()) : Value.NULL);
put("permission_level", (e, a) -> { put("permission_level", (e, a) -> {
if (e instanceof final ServerPlayer spe) if (e instanceof ServerPlayer spe)
{ {
for (int i = 4; i >= 0; i--) for (int i = 4; i >= 0; i--)
{ {
@@ -609,7 +609,7 @@ public class EntityValue extends Value
}); });
put("player_type", (e, a) -> { put("player_type", (e, a) -> {
if (e instanceof final Player p) if (e instanceof Player p)
{ {
String moddedType = Carpet.isModdedPlayer(p); String moddedType = Carpet.isModdedPlayer(p);
if (moddedType != null) if (moddedType != null)
@@ -637,15 +637,15 @@ public class EntityValue extends Value
return Value.NULL; return Value.NULL;
}); });
put("client_brand", (e, a) -> e instanceof final ServerPlayer sp ? StringValue.of(Carpet.getPlayerStatus(sp)) : Value.NULL); put("client_brand", (e, a) -> e instanceof ServerPlayer sp ? StringValue.of(Carpet.getPlayerStatus(sp)) : Value.NULL);
put("team", (e, a) -> e.getTeam() == null ? Value.NULL : new StringValue(e.getTeam().getName())); put("team", (e, a) -> e.getTeam() == null ? Value.NULL : new StringValue(e.getTeam().getName()));
put("ping", (e, a) -> e instanceof final ServerPlayer sp ? new NumericValue(sp.connection.latency()) : Value.NULL); put("ping", (e, a) -> e instanceof ServerPlayer sp ? new NumericValue(sp.connection.latency()) : Value.NULL);
//spectating_entity //spectating_entity
// isGlowing // isGlowing
put("effect", (e, a) -> put("effect", (e, a) ->
{ {
if (!(e instanceof final LivingEntity le)) if (!(e instanceof LivingEntity le))
{ {
return Value.NULL; return Value.NULL;
} }
@@ -663,7 +663,7 @@ public class EntityValue extends Value
return ListValue.wrap(effects); return ListValue.wrap(effects);
} }
String effectName = a.getString(); String effectName = a.getString();
Holder<MobEffect> potion = BuiltInRegistries.MOB_EFFECT.getHolder(ResourceKey.create(Registries.MOB_EFFECT, InputValidator.identifierOf(effectName))).orElseThrow( () -> new InternalExpressionException("No such an effect: " + effectName)); Holder<MobEffect> potion = BuiltInRegistries.MOB_EFFECT.getHolder(ResourceKey.create(Registries.MOB_EFFECT, InputValidator.identifierOf(effectName))).orElseThrow(() -> new InternalExpressionException("No such an effect: " + effectName));
if (!le.hasEffect(potion)) if (!le.hasEffect(potion))
{ {
return Value.NULL; return Value.NULL;
@@ -672,13 +672,13 @@ public class EntityValue extends Value
return ListValue.of(new NumericValue(pe.getAmplifier()), new NumericValue(pe.getDuration())); return ListValue.of(new NumericValue(pe.getAmplifier()), new NumericValue(pe.getDuration()));
}); });
put("health", (e, a) -> e instanceof final LivingEntity le ? new NumericValue(le.getHealth()) : Value.NULL); put("health", (e, a) -> e instanceof LivingEntity le ? new NumericValue(le.getHealth()) : Value.NULL);
put("may_fly", (e, a) -> e instanceof final ServerPlayer player ? BooleanValue.of(player.getAbilities().mayfly) : Value.NULL); put("may_fly", (e, a) -> e instanceof ServerPlayer player ? BooleanValue.of(player.getAbilities().mayfly) : Value.NULL);
put("flying", (e, v) -> e instanceof final ServerPlayer player ? BooleanValue.of(player.getAbilities().flying) : Value.NULL); put("flying", (e, v) -> e instanceof ServerPlayer player ? BooleanValue.of(player.getAbilities().flying) : Value.NULL);
put("may_build", (e, v) -> e instanceof final ServerPlayer player ? BooleanValue.of(player.getAbilities().mayBuild) : Value.NULL); put("may_build", (e, v) -> e instanceof ServerPlayer player ? BooleanValue.of(player.getAbilities().mayBuild) : Value.NULL);
put("insta_build", (e, v) -> e instanceof final ServerPlayer player ? BooleanValue.of(player.getAbilities().instabuild) : Value.NULL); put("insta_build", (e, v) -> e instanceof ServerPlayer player ? BooleanValue.of(player.getAbilities().instabuild) : Value.NULL);
put("fly_speed", (e, v) -> e instanceof final ServerPlayer player ? NumericValue.of(player.getAbilities().getFlyingSpeed()) : Value.NULL); put("fly_speed", (e, v) -> e instanceof ServerPlayer player ? NumericValue.of(player.getAbilities().getFlyingSpeed()) : Value.NULL);
put("walk_speed", (e, v) -> e instanceof final ServerPlayer player ? NumericValue.of(player.getAbilities().getWalkingSpeed()) : Value.NULL); put("walk_speed", (e, v) -> e instanceof ServerPlayer player ? NumericValue.of(player.getAbilities().getWalkingSpeed()) : Value.NULL);
put("holds", (e, a) -> { put("holds", (e, a) -> {
EquipmentSlot where = EquipmentSlot.MAINHAND; EquipmentSlot where = EquipmentSlot.MAINHAND;
if (a != null) if (a != null)
@@ -689,17 +689,17 @@ public class EntityValue extends Value
{ {
throw new InternalExpressionException("Unknown inventory slot: " + a.getString()); throw new InternalExpressionException("Unknown inventory slot: " + a.getString());
} }
if (e instanceof final LivingEntity le) if (e instanceof LivingEntity le)
{ {
return ValueConversions.of(le.getItemBySlot(where), e.getServer().registryAccess()); return ValueConversions.of(le.getItemBySlot(where), e.getServer().registryAccess());
} }
return Value.NULL; return Value.NULL;
}); });
put("selected_slot", (e, a) -> e instanceof final Player p ? new NumericValue(p.getInventory().selected) : Value.NULL); put("selected_slot", (e, a) -> e instanceof Player p ? new NumericValue(p.getInventory().selected) : Value.NULL);
put("active_block", (e, a) -> { put("active_block", (e, a) -> {
if (e instanceof final ServerPlayer sp) if (e instanceof ServerPlayer sp)
{ {
BlockPos pos = Vanilla.ServerPlayerGameMode_getCurrentBlockPosition(sp.gameMode); BlockPos pos = Vanilla.ServerPlayerGameMode_getCurrentBlockPosition(sp.gameMode);
if (pos == null) if (pos == null)
@@ -712,9 +712,9 @@ public class EntityValue extends Value
}); });
put("breaking_progress", (e, a) -> { put("breaking_progress", (e, a) -> {
if (e instanceof final ServerPlayer sp) if (e instanceof ServerPlayer sp)
{ {
int progress = Vanilla.ServerPlayerGameMode_getCurrentBlockBreakingProgress (sp.gameMode); int progress = Vanilla.ServerPlayerGameMode_getCurrentBlockBreakingProgress(sp.gameMode);
return progress < 0 ? Value.NULL : new NumericValue(progress); return progress < 0 ? Value.NULL : new NumericValue(progress);
} }
return Value.NULL; return Value.NULL;
@@ -745,7 +745,7 @@ public class EntityValue extends Value
if (a != null) if (a != null)
{ {
if (!(a instanceof final ListValue lv)) if (!(a instanceof ListValue lv))
{ {
reach = (float) NumericValue.asNumber(a).getDouble(); reach = (float) NumericValue.asNumber(a).getDouble();
} }
@@ -789,7 +789,7 @@ public class EntityValue extends Value
} }
} }
} }
else if (e instanceof final ServerPlayer sp && sp.gameMode.isCreative()) else if (e instanceof ServerPlayer sp && sp.gameMode.isCreative())
{ {
reach = 5.0f; reach = 5.0f;
} }
@@ -829,7 +829,7 @@ public class EntityValue extends Value
}); });
put("attribute", (e, a) -> { put("attribute", (e, a) -> {
if (!(e instanceof final LivingEntity el)) if (!(e instanceof LivingEntity el))
{ {
return Value.NULL; return Value.NULL;
} }
@@ -896,7 +896,7 @@ public class EntityValue extends Value
{ {
return; return;
} }
if (e instanceof final ServerPlayer sp) if (e instanceof ServerPlayer sp)
{ {
// this forces position but doesn't angles for some reason. Need both in the API in the future. // this forces position but doesn't angles for some reason. Need both in the API in the future.
EnumSet<RelativeMovement> set = EnumSet.noneOf(RelativeMovement.class); EnumSet<RelativeMovement> set = EnumSet.noneOf(RelativeMovement.class);
@@ -909,7 +909,7 @@ public class EntityValue extends Value
e.moveTo(x, y, z, yaw, pitch); e.moveTo(x, y, z, yaw, pitch);
// we were sending to players for not-living entites, that were untracked. Living entities should be tracked. // we were sending to players for not-living entites, that were untracked. Living entities should be tracked.
//((ServerWorld) e.getEntityWorld()).getChunkManager().sendToNearbyPlayers(e, new EntityS2CPacket.(e)); //((ServerWorld) e.getEntityWorld()).getChunkManager().sendToNearbyPlayers(e, new EntityS2CPacket.(e));
if (e instanceof final LivingEntity le) if (e instanceof LivingEntity le)
{ {
le.yBodyRotO = le.yRotO = yaw; le.yBodyRotO = le.yRotO = yaw;
le.yHeadRotO = le.yHeadRot = yaw; le.yHeadRotO = le.yHeadRot = yaw;
@@ -939,7 +939,7 @@ public class EntityValue extends Value
put("age", (e, v) -> e.tickCount = Math.abs((int) NumericValue.asNumber(v).getLong())); put("age", (e, v) -> e.tickCount = Math.abs((int) NumericValue.asNumber(v).getLong()));
put("health", (e, v) -> { put("health", (e, v) -> {
float health = (float) NumericValue.asNumber(v).getDouble(); float health = (float) NumericValue.asNumber(v).getDouble();
if (health <= 0f && e instanceof final ServerPlayer player) if (health <= 0f && e instanceof ServerPlayer player)
{ {
if (player.containerMenu != null) if (player.containerMenu != null)
{ {
@@ -950,7 +950,7 @@ public class EntityValue extends Value
} }
((LivingEntity) e).setHealth(health); ((LivingEntity) e).setHealth(health);
} }
if (e instanceof final LivingEntity le) if (e instanceof LivingEntity le)
{ {
le.setHealth(health); le.setHealth(health);
} }
@@ -958,7 +958,7 @@ public class EntityValue extends Value
put("may_fly", (e, v) -> { put("may_fly", (e, v) -> {
boolean mayFly = v.getBoolean(); boolean mayFly = v.getBoolean();
if (e instanceof final ServerPlayer player) if (e instanceof ServerPlayer player)
{ {
player.getAbilities().mayfly = mayFly; player.getAbilities().mayfly = mayFly;
if (!mayFly && player.getAbilities().flying) if (!mayFly && player.getAbilities().flying)
@@ -971,7 +971,7 @@ public class EntityValue extends Value
put("flying", (e, v) -> { put("flying", (e, v) -> {
boolean flying = v.getBoolean(); boolean flying = v.getBoolean();
if (e instanceof final ServerPlayer player) if (e instanceof ServerPlayer player)
{ {
player.getAbilities().flying = flying; player.getAbilities().flying = flying;
player.onUpdateAbilities(); player.onUpdateAbilities();
@@ -980,7 +980,7 @@ public class EntityValue extends Value
put("may_build", (e, v) -> { put("may_build", (e, v) -> {
boolean mayBuild = v.getBoolean(); boolean mayBuild = v.getBoolean();
if (e instanceof final ServerPlayer player) if (e instanceof ServerPlayer player)
{ {
player.getAbilities().mayBuild = mayBuild; player.getAbilities().mayBuild = mayBuild;
player.onUpdateAbilities(); player.onUpdateAbilities();
@@ -989,7 +989,7 @@ public class EntityValue extends Value
put("insta_build", (e, v) -> { put("insta_build", (e, v) -> {
boolean instaBuild = v.getBoolean(); boolean instaBuild = v.getBoolean();
if (e instanceof final ServerPlayer player) if (e instanceof ServerPlayer player)
{ {
player.getAbilities().instabuild = instaBuild; player.getAbilities().instabuild = instaBuild;
player.onUpdateAbilities(); player.onUpdateAbilities();
@@ -998,7 +998,7 @@ public class EntityValue extends Value
put("fly_speed", (e, v) -> { put("fly_speed", (e, v) -> {
float flySpeed = NumericValue.asNumber(v).getFloat(); float flySpeed = NumericValue.asNumber(v).getFloat();
if (e instanceof final ServerPlayer player) if (e instanceof ServerPlayer player)
{ {
player.getAbilities().setFlyingSpeed(flySpeed); player.getAbilities().setFlyingSpeed(flySpeed);
player.onUpdateAbilities(); player.onUpdateAbilities();
@@ -1007,7 +1007,7 @@ public class EntityValue extends Value
put("walk_speed", (e, v) -> { put("walk_speed", (e, v) -> {
float walkSpeed = NumericValue.asNumber(v).getFloat(); float walkSpeed = NumericValue.asNumber(v).getFloat();
if (e instanceof final ServerPlayer player) if (e instanceof ServerPlayer player)
{ {
player.getAbilities().setWalkingSpeed(walkSpeed); player.getAbilities().setWalkingSpeed(walkSpeed);
player.onUpdateAbilities(); player.onUpdateAbilities();
@@ -1016,7 +1016,7 @@ public class EntityValue extends Value
put("selected_slot", (e, v) -> put("selected_slot", (e, v) ->
{ {
if (e instanceof final ServerPlayer player) if (e instanceof ServerPlayer player)
{ {
int slot = NumericValue.asNumber(v).getInt(); int slot = NumericValue.asNumber(v).getInt();
player.connection.send(new ClientboundSetCarriedItemPacket(slot)); player.connection.send(new ClientboundSetCarriedItemPacket(slot));
@@ -1041,7 +1041,7 @@ public class EntityValue extends Value
put("kill", (e, v) -> e.kill()); put("kill", (e, v) -> e.kill());
put("location", (e, v) -> put("location", (e, v) ->
{ {
if (!(v instanceof final ListValue lv)) if (!(v instanceof ListValue lv))
{ {
throw new InternalExpressionException("Expected a list of 5 parameters as a second argument"); throw new InternalExpressionException("Expected a list of 5 parameters as a second argument");
} }
@@ -1056,7 +1056,7 @@ public class EntityValue extends Value
}); });
put("pos", (e, v) -> put("pos", (e, v) ->
{ {
if (!(v instanceof final ListValue lv)) if (!(v instanceof ListValue lv))
{ {
throw new InternalExpressionException("Expected a list of 3 parameters as a second argument"); throw new InternalExpressionException("Expected a list of 3 parameters as a second argument");
} }
@@ -1091,7 +1091,7 @@ public class EntityValue extends Value
put("pitch", (e, v) -> updatePosition(e, e.getX(), e.getY(), e.getZ(), e.getYRot(), Mth.clamp((float) NumericValue.asNumber(v).getDouble(), -90, 90))); put("pitch", (e, v) -> updatePosition(e, e.getX(), e.getY(), e.getZ(), e.getYRot(), Mth.clamp((float) NumericValue.asNumber(v).getDouble(), -90, 90)));
put("look", (e, v) -> { put("look", (e, v) -> {
if (!(v instanceof final ListValue lv)) if (!(v instanceof ListValue lv))
{ {
throw new InternalExpressionException("Expected a list of 3 parameters as a second argument"); throw new InternalExpressionException("Expected a list of 3 parameters as a second argument");
} }
@@ -1117,7 +1117,7 @@ public class EntityValue extends Value
put("move", (e, v) -> put("move", (e, v) ->
{ {
if (!(v instanceof final ListValue lv)) if (!(v instanceof ListValue lv))
{ {
throw new InternalExpressionException("Expected a list of 3 parameters as a second argument"); throw new InternalExpressionException("Expected a list of 3 parameters as a second argument");
} }
@@ -1133,7 +1133,7 @@ public class EntityValue extends Value
put("motion", (e, v) -> put("motion", (e, v) ->
{ {
if (!(v instanceof final ListValue lv)) if (!(v instanceof ListValue lv))
{ {
throw new InternalExpressionException("Expected a list of 3 parameters as a second argument"); throw new InternalExpressionException("Expected a list of 3 parameters as a second argument");
} }
@@ -1168,7 +1168,7 @@ public class EntityValue extends Value
put("accelerate", (e, v) -> put("accelerate", (e, v) ->
{ {
if (!(v instanceof final ListValue lv)) if (!(v instanceof ListValue lv))
{ {
throw new InternalExpressionException("Expected a list of 3 parameters as a second argument"); throw new InternalExpressionException("Expected a list of 3 parameters as a second argument");
} }
@@ -1189,7 +1189,7 @@ public class EntityValue extends Value
return; return;
} }
boolean showName = false; boolean showName = false;
if (v instanceof final ListValue lv) if (v instanceof ListValue lv)
{ {
showName = lv.getItems().get(1).getBoolean(); showName = lv.getItems().get(1).getBoolean();
v = lv.getItems().get(0); v = lv.getItems().get(0);
@@ -1200,7 +1200,7 @@ public class EntityValue extends Value
put("persistence", (e, v) -> put("persistence", (e, v) ->
{ {
if (!(e instanceof final Mob mob)) if (!(e instanceof Mob mob))
{ {
return; return;
} }
@@ -1213,11 +1213,11 @@ public class EntityValue extends Value
put("dismount", (e, v) -> e.stopRiding()); put("dismount", (e, v) -> e.stopRiding());
put("mount", (e, v) -> { put("mount", (e, v) -> {
if (v instanceof final EntityValue ev) if (v instanceof EntityValue ev)
{ {
e.startRiding(ev.getEntity(), true); e.startRiding(ev.getEntity(), true);
} }
if (e instanceof final ServerPlayer sp) if (e instanceof ServerPlayer sp)
{ {
sp.connection.send(new ClientboundSetPassengersPacket(e)); sp.connection.send(new ClientboundSetPassengersPacket(e));
} }
@@ -1229,15 +1229,15 @@ public class EntityValue extends Value
{ {
throw new InternalExpressionException("'mount_passengers' needs entities to ride"); throw new InternalExpressionException("'mount_passengers' needs entities to ride");
} }
if (v instanceof final EntityValue ev) if (v instanceof EntityValue ev)
{ {
ev.getEntity().startRiding(e); ev.getEntity().startRiding(e);
} }
else if (v instanceof final ListValue lv) else if (v instanceof ListValue lv)
{ {
for (Value element : lv.getItems()) for (Value element : lv.getItems())
{ {
if (element instanceof final EntityValue ev) if (element instanceof EntityValue ev)
{ {
ev.getEntity().startRiding(e); ev.getEntity().startRiding(e);
} }
@@ -1249,7 +1249,7 @@ public class EntityValue extends Value
{ {
throw new InternalExpressionException("'tag' requires parameters"); throw new InternalExpressionException("'tag' requires parameters");
} }
if (v instanceof final ListValue lv) if (v instanceof ListValue lv)
{ {
for (Value element : lv.getItems()) for (Value element : lv.getItems())
{ {
@@ -1266,7 +1266,7 @@ public class EntityValue extends Value
{ {
throw new InternalExpressionException("'clear_tag' requires parameters"); throw new InternalExpressionException("'clear_tag' requires parameters");
} }
if (v instanceof final ListValue lv) if (v instanceof ListValue lv)
{ {
for (Value element : lv.getItems()) for (Value element : lv.getItems())
{ {
@@ -1288,20 +1288,20 @@ public class EntityValue extends Value
//}); //});
put("breeding_age", (e, v) -> put("breeding_age", (e, v) ->
{ {
if (e instanceof final AgeableMob am) if (e instanceof AgeableMob am)
{ {
am.setAge((int) NumericValue.asNumber(v).getLong()); am.setAge((int) NumericValue.asNumber(v).getLong());
} }
}); });
put("talk", (e, v) -> { put("talk", (e, v) -> {
// attacks indefinitely // attacks indefinitely
if (e instanceof final Mob mob) if (e instanceof Mob mob)
{ {
mob.playAmbientSound(); mob.playAmbientSound();
} }
}); });
put("home", (e, v) -> { put("home", (e, v) -> {
if (!(e instanceof final PathfinderMob ec)) if (!(e instanceof PathfinderMob ec))
{ {
return; return;
} }
@@ -1321,7 +1321,7 @@ public class EntityValue extends Value
BlockPos pos; BlockPos pos;
int distance = 16; int distance = 16;
if (v instanceof final BlockValue bv) if (v instanceof BlockValue bv)
{ {
pos = bv.getPos(); pos = bv.getPos();
if (pos == null) if (pos == null)
@@ -1329,7 +1329,7 @@ public class EntityValue extends Value
throw new InternalExpressionException("Block is not positioned in the world"); throw new InternalExpressionException("Block is not positioned in the world");
} }
} }
else if (v instanceof final ListValue lv) else if (v instanceof ListValue lv)
{ {
List<Value> list = lv.getItems(); List<Value> list = lv.getItems();
Vector3Argument locator = Vector3Argument.findIn(list, 0, false, false); Vector3Argument locator = Vector3Argument.findIn(list, 0, false, false);
@@ -1355,7 +1355,7 @@ public class EntityValue extends Value
}); //requires mixing }); //requires mixing
put("spawn_point", (e, a) -> { put("spawn_point", (e, a) -> {
if (!(e instanceof final ServerPlayer spe)) if (!(e instanceof ServerPlayer spe))
{ {
return; return;
} }
@@ -1363,7 +1363,7 @@ public class EntityValue extends Value
{ {
spe.setRespawnPosition(null, null, 0, false, false); spe.setRespawnPosition(null, null, 0, false, false);
} }
else if (a instanceof final ListValue lv) else if (a instanceof ListValue lv)
{ {
List<Value> params = lv.getItems(); List<Value> params = lv.getItems();
Vector3Argument blockLocator = Vector3Argument.findIn(params, 0, false, false); Vector3Argument blockLocator = Vector3Argument.findIn(params, 0, false, false);
@@ -1373,7 +1373,7 @@ public class EntityValue extends Value
boolean forced = false; boolean forced = false;
if (params.size() > blockLocator.offset) if (params.size() > blockLocator.offset)
{ {
Value worldValue = params.get(blockLocator.offset + 0); Value worldValue = params.get(blockLocator.offset);
world = ValueConversions.dimFromValue(worldValue, spe.getServer()).dimension(); world = ValueConversions.dimFromValue(worldValue, spe.getServer()).dimension();
if (params.size() > blockLocator.offset + 1) if (params.size() > blockLocator.offset + 1)
{ {
@@ -1386,7 +1386,7 @@ public class EntityValue extends Value
} }
spe.setRespawnPosition(world, pos, angle, forced, false); spe.setRespawnPosition(world, pos, angle, forced, false);
} }
else if (a instanceof final BlockValue bv) else if (a instanceof BlockValue bv)
{ {
if (bv.getPos() == null || bv.getWorld() == null) if (bv.getPos() == null || bv.getWorld() == null)
{ {
@@ -1406,7 +1406,7 @@ public class EntityValue extends Value
put("pickup_delay", (e, v) -> put("pickup_delay", (e, v) ->
{ {
if (e instanceof final ItemEntity ie) if (e instanceof ItemEntity ie)
{ {
ie.setPickUpDelay((int) NumericValue.asNumber(v).getLong()); ie.setPickUpDelay((int) NumericValue.asNumber(v).getLong());
} }
@@ -1414,7 +1414,7 @@ public class EntityValue extends Value
put("despawn_timer", (e, v) -> put("despawn_timer", (e, v) ->
{ {
if (e instanceof final LivingEntity le) if (e instanceof LivingEntity le)
{ {
le.setNoActionTime((int) NumericValue.asNumber(v).getLong()); le.setNoActionTime((int) NumericValue.asNumber(v).getLong());
} }
@@ -1440,7 +1440,7 @@ public class EntityValue extends Value
put("ai", (e, v) -> put("ai", (e, v) ->
{ {
if (e instanceof final Mob mob) if (e instanceof Mob mob)
{ {
mob.setNoAi(!v.getBoolean()); mob.setNoAi(!v.getBoolean());
} }
@@ -1459,7 +1459,7 @@ public class EntityValue extends Value
}); });
put("effect", (e, v) -> put("effect", (e, v) ->
{ {
if (!(e instanceof final LivingEntity le)) if (!(e instanceof LivingEntity le))
{ {
return; return;
} }
@@ -1468,13 +1468,13 @@ public class EntityValue extends Value
le.removeAllEffects(); le.removeAllEffects();
return; return;
} }
else if (v instanceof final ListValue lv) else if (v instanceof ListValue lv)
{ {
List<Value> list = lv.getItems(); List<Value> list = lv.getItems();
if (list.size() >= 1 && list.size() <= 6) if (list.size() >= 1 && list.size() <= 6)
{ {
String effectName = list.get(0).getString(); String effectName = list.get(0).getString();
Holder<MobEffect> effect = BuiltInRegistries.MOB_EFFECT.getHolder(InputValidator.identifierOf(effectName)).orElseThrow( () -> new InternalExpressionException("No such an effect: " + effectName)); Holder<MobEffect> effect = BuiltInRegistries.MOB_EFFECT.getHolder(InputValidator.identifierOf(effectName)).orElseThrow(() -> new InternalExpressionException("No such an effect: " + effectName));
if (list.size() == 1) if (list.size() == 1)
{ {
le.removeEffect(effect); le.removeEffect(effect);
@@ -1486,7 +1486,8 @@ public class EntityValue extends Value
le.removeEffect(effect); le.removeEffect(effect);
return; return;
} }
if (duration < 0){ if (duration < 0)
{
duration = -1; duration = -1;
} }
int amplifier = 0; int amplifier = 0;
@@ -1516,7 +1517,7 @@ public class EntityValue extends Value
else else
{ {
String effectName = v.getString(); String effectName = v.getString();
Holder<MobEffect> effect = BuiltInRegistries.MOB_EFFECT.getHolder(InputValidator.identifierOf(effectName)).orElseThrow( () -> new InternalExpressionException("No such an effect: " + effectName)); Holder<MobEffect> effect = BuiltInRegistries.MOB_EFFECT.getHolder(InputValidator.identifierOf(effectName)).orElseThrow(() -> new InternalExpressionException("No such an effect: " + effectName));
le.removeEffect(effect); le.removeEffect(effect);
return; return;
} }
@@ -1524,7 +1525,7 @@ public class EntityValue extends Value
}); });
put("gamemode", (e, v) -> { put("gamemode", (e, v) -> {
if (!(e instanceof final ServerPlayer sp)) if (!(e instanceof ServerPlayer sp))
{ {
return; return;
} }
@@ -1538,7 +1539,7 @@ public class EntityValue extends Value
}); });
put("jumping", (e, v) -> { put("jumping", (e, v) -> {
if (!(e instanceof final LivingEntity le)) if (!(e instanceof LivingEntity le))
{ {
return; return;
} }
@@ -1546,7 +1547,7 @@ public class EntityValue extends Value
}); });
put("jump", (e, v) -> { put("jump", (e, v) -> {
if (e instanceof final LivingEntity le) if (e instanceof LivingEntity le)
{ {
Vanilla.LivingEntity_setJumping(le); Vanilla.LivingEntity_setJumping(le);
} }
@@ -1557,7 +1558,7 @@ public class EntityValue extends Value
}); });
put("swing", (e, v) -> { put("swing", (e, v) -> {
if (e instanceof final LivingEntity le) if (e instanceof LivingEntity le)
{ {
InteractionHand hand = InteractionHand.MAIN_HAND; InteractionHand hand = InteractionHand.MAIN_HAND;
if (v != null) if (v != null)
@@ -1578,7 +1579,7 @@ public class EntityValue extends Value
put("invulnerable", (e, v) -> { put("invulnerable", (e, v) -> {
boolean invulnerable = v.getBoolean(); boolean invulnerable = v.getBoolean();
if (e instanceof final ServerPlayer player) if (e instanceof ServerPlayer player)
{ {
player.getAbilities().invulnerable = invulnerable; player.getAbilities().invulnerable = invulnerable;
player.onUpdateAbilities(); player.onUpdateAbilities();
@@ -1593,49 +1594,49 @@ public class EntityValue extends Value
put("frost", (e, v) -> e.setTicksFrozen((int) NumericValue.asNumber(v).getLong())); put("frost", (e, v) -> e.setTicksFrozen((int) NumericValue.asNumber(v).getLong()));
put("hunger", (e, v) -> { put("hunger", (e, v) -> {
if (e instanceof final Player p) if (e instanceof Player p)
{ {
p.getFoodData().setFoodLevel((int) NumericValue.asNumber(v).getLong()); p.getFoodData().setFoodLevel((int) NumericValue.asNumber(v).getLong());
} }
}); });
put("exhaustion", (e, v) -> { put("exhaustion", (e, v) -> {
if (e instanceof final Player p) if (e instanceof Player p)
{ {
p.getFoodData().setExhaustion(NumericValue.asNumber(v).getFloat()); p.getFoodData().setExhaustion(NumericValue.asNumber(v).getFloat());
} }
}); });
put("add_exhaustion", (e, v) -> { put("add_exhaustion", (e, v) -> {
if (e instanceof final Player p) if (e instanceof Player p)
{ {
p.getFoodData().addExhaustion(NumericValue.asNumber(v).getFloat()); p.getFoodData().addExhaustion(NumericValue.asNumber(v).getFloat());
} }
}); });
put("absorption", (e, v) -> { put("absorption", (e, v) -> {
if (e instanceof final Player p) if (e instanceof Player p)
{ {
p.setAbsorptionAmount(NumericValue.asNumber(v, "absorbtion").getFloat()); p.setAbsorptionAmount(NumericValue.asNumber(v, "absorbtion").getFloat());
} }
}); });
put("add_xp", (e, v) -> { put("add_xp", (e, v) -> {
if (e instanceof final Player p) if (e instanceof Player p)
{ {
p.giveExperiencePoints(NumericValue.asNumber(v, "add_xp").getInt()); p.giveExperiencePoints(NumericValue.asNumber(v, "add_xp").getInt());
} }
}); });
put("xp_level", (e, v) -> { put("xp_level", (e, v) -> {
if (e instanceof final Player p) if (e instanceof Player p)
{ {
p.giveExperienceLevels(NumericValue.asNumber(v, "xp_level").getInt() - p.experienceLevel); p.giveExperienceLevels(NumericValue.asNumber(v, "xp_level").getInt() - p.experienceLevel);
} }
}); });
put("xp_progress", (e, v) -> { put("xp_progress", (e, v) -> {
if (e instanceof final ServerPlayer p) if (e instanceof ServerPlayer p)
{ {
p.experienceProgress = NumericValue.asNumber(v, "xp_progress").getFloat(); p.experienceProgress = NumericValue.asNumber(v, "xp_progress").getFloat();
p.connection.send(new ClientboundSetExperiencePacket(p.experienceProgress, p.totalExperience, p.experienceLevel)); p.connection.send(new ClientboundSetExperiencePacket(p.experienceProgress, p.totalExperience, p.experienceLevel));
@@ -1643,14 +1644,14 @@ public class EntityValue extends Value
}); });
put("xp_score", (e, v) -> { put("xp_score", (e, v) -> {
if (e instanceof final Player p) if (e instanceof Player p)
{ {
p.setScore(NumericValue.asNumber(v, "xp_score").getInt()); p.setScore(NumericValue.asNumber(v, "xp_score").getInt());
} }
}); });
put("saturation", (e, v) -> { put("saturation", (e, v) -> {
if (e instanceof final Player p) if (e instanceof Player p)
{ {
p.getFoodData().setSaturation(NumericValue.asNumber(v, "saturation").getFloat()); p.getFoodData().setSaturation(NumericValue.asNumber(v, "saturation").getFloat());
} }
@@ -1659,7 +1660,7 @@ public class EntityValue extends Value
put("air", (e, v) -> e.setAirSupply(NumericValue.asNumber(v, "air").getInt())); put("air", (e, v) -> e.setAirSupply(NumericValue.asNumber(v, "air").getInt()));
put("breaking_progress", (e, a) -> { put("breaking_progress", (e, a) -> {
if (e instanceof final ServerPlayer sp) if (e instanceof ServerPlayer sp)
{ {
int progress = (a == null || a.isNull()) ? -1 : NumericValue.asNumber(a).getInt(); int progress = (a == null || a.isNull()) ? -1 : NumericValue.asNumber(a).getInt();
Vanilla.ServerPlayerGameMode_setBlockBreakingProgress(sp.gameMode, progress); Vanilla.ServerPlayerGameMode_setBlockBreakingProgress(sp.gameMode, progress);
@@ -1671,7 +1672,7 @@ public class EntityValue extends Value
{ {
UUID uUID = e.getUUID(); UUID uUID = e.getUUID();
Value tagValue = NBTSerializableValue.fromValue(v); Value tagValue = NBTSerializableValue.fromValue(v);
if (tagValue instanceof final NBTSerializableValue nbtsv) if (tagValue instanceof NBTSerializableValue nbtsv)
{ {
e.load(nbtsv.getCompoundTag()); e.load(nbtsv.getCompoundTag());
e.setUUID(uUID); e.setUUID(uUID);
@@ -1683,7 +1684,7 @@ public class EntityValue extends Value
{ {
UUID uUID = e.getUUID(); UUID uUID = e.getUUID();
Value tagValue = NBTSerializableValue.fromValue(v); Value tagValue = NBTSerializableValue.fromValue(v);
if (tagValue instanceof final NBTSerializableValue nbtsv) if (tagValue instanceof NBTSerializableValue nbtsv)
{ {
CompoundTag nbttagcompound = e.saveWithoutId((new CompoundTag())); CompoundTag nbttagcompound = e.saveWithoutId((new CompoundTag()));
nbttagcompound.merge(nbtsv.getCompoundTag()); nbttagcompound.merge(nbtsv.getCompoundTag());
@@ -1694,14 +1695,14 @@ public class EntityValue extends Value
}); });
put("blue_skull", (e, v) -> { put("blue_skull", (e, v) -> {
if (e instanceof final WitherSkull w) if (e instanceof WitherSkull w)
{ {
w.setDangerous(v.getBoolean()); w.setDangerous(v.getBoolean());
} }
}); });
put("offering_flower", (e, v) -> { put("offering_flower", (e, v) -> {
if (e instanceof final IronGolem ig) if (e instanceof IronGolem ig)
{ {
ig.offerFlower(v.getBoolean()); ig.offerFlower(v.getBoolean());
} }
@@ -1709,11 +1710,11 @@ public class EntityValue extends Value
}); });
put("item", (e, v) -> { put("item", (e, v) -> {
ItemStack item = ValueConversions.getItemStackFromValue(v, true, e.level().registryAccess()); ItemStack item = ValueConversions.getItemStackFromValue(v, true, e.level().registryAccess());
if (e instanceof final ItemEntity itementity) if (e instanceof ItemEntity itementity)
{ {
itementity.setItem(item); itementity.setItem(item);
} }
if (e instanceof final ItemFrame itemframe) if (e instanceof ItemFrame itemframe)
{ {
itemframe.setItem(item); itemframe.setItem(item);
} }
@@ -1734,7 +1735,7 @@ public class EntityValue extends Value
} }
@Override @Override
public net.minecraft.nbt.Tag toTag(boolean force) public net.minecraft.nbt.Tag toTag(boolean force, RegistryAccess regs)
{ {
if (!force) if (!force)
{ {
@@ -1,6 +1,6 @@
package carpet.script.value; package carpet.script.value;
import com.google.gson.JsonElement; import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.StringTag; import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
@@ -19,7 +19,7 @@ public class FormattedTextValue extends StringValue
public static Value combine(Value left, Value right) public static Value combine(Value left, Value right)
{ {
MutableComponent text; MutableComponent text;
if (left instanceof final FormattedTextValue ftv) if (left instanceof FormattedTextValue ftv)
{ {
text = ftv.getText().copy(); text = ftv.getText().copy();
} }
@@ -32,7 +32,7 @@ public class FormattedTextValue extends StringValue
text = Component.literal(left.getString()); text = Component.literal(left.getString());
} }
if (right instanceof final FormattedTextValue ftv) if (right instanceof FormattedTextValue ftv)
{ {
text.append(ftv.getText().copy()); text.append(ftv.getText().copy());
return new FormattedTextValue(text); return new FormattedTextValue(text);
@@ -80,19 +80,13 @@ public class FormattedTextValue extends StringValue
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
if (!force) if (!force)
{ {
throw new NBTSerializableValue.IncompatibleTypeException(this); throw new NBTSerializableValue.IncompatibleTypeException(this);
} }
return StringTag.valueOf(Component.Serializer.toJson(text)); return StringTag.valueOf(Component.Serializer.toJson(text, regs));
}
@Override
public JsonElement toJson()
{
return Component.Serializer.toJsonTree(text);
} }
@Override @Override
@@ -101,19 +95,19 @@ public class FormattedTextValue extends StringValue
return combine(this, o); return combine(this, o);
} }
public String serialize() public String serialize(RegistryAccess regs)
{ {
return Component.Serializer.toJson(text); return Component.Serializer.toJson(text, regs);
} }
public static FormattedTextValue deserialize(String serialized) public static FormattedTextValue deserialize(String serialized, RegistryAccess regs)
{ {
return new FormattedTextValue(Component.Serializer.fromJson(serialized)); return new FormattedTextValue(Component.Serializer.fromJson(serialized, regs));
} }
public static Component getTextByValue(Value value) public static Component getTextByValue(Value value)
{ {
return (value instanceof final FormattedTextValue ftv) ? ftv.getText() : Component.literal(value.getString()); return (value instanceof FormattedTextValue ftv) ? ftv.getText() : Component.literal(value.getString());
} }
} }
@@ -1,5 +1,6 @@
package carpet.script.value; package carpet.script.value;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
public abstract class FrameworkValue extends Value public abstract class FrameworkValue extends Value
@@ -29,7 +30,7 @@ public abstract class FrameworkValue extends Value
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
throw new UnsupportedOperationException("Scarpet language component cannot be serialized to the tag"); throw new UnsupportedOperationException("Scarpet language component cannot be serialized to the tag");
} }
@@ -1,6 +1,7 @@
package carpet.script.value; package carpet.script.value;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
public class FunctionAnnotationValue extends Value public class FunctionAnnotationValue extends Value
@@ -41,7 +42,7 @@ public class FunctionAnnotationValue extends Value
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
throw new UnsupportedOperationException("Global value cannot be serialized to the tag"); throw new UnsupportedOperationException("Global value cannot be serialized to the tag");
} }
@@ -19,6 +19,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.StringTag; import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
@@ -112,13 +113,13 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {
return o instanceof final FunctionValue fv && name.equals(fv.name) && variant == fv.variant; return o instanceof FunctionValue fv && name.equals(fv.name) && variant == fv.variant;
} }
@Override @Override
public int compareTo(Value o) public int compareTo(Value o)
{ {
if (o instanceof final FunctionValue fv) if (o instanceof FunctionValue fv)
{ {
int nameSame = this.name.compareTo(fv.name); int nameSame = this.name.compareTo(fv.name);
return nameSame != 0 ? nameSame : (int) (variant - fv.variant); return nameSame != 0 ? nameSame : (int) (variant - fv.variant);
@@ -303,7 +304,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
if (!force) if (!force)
{ {
@@ -7,6 +7,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.StringTag; import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
@@ -238,7 +239,7 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
if (!force) if (!force)
{ {
@@ -16,6 +16,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.DoubleTag; import net.minecraft.nbt.DoubleTag;
import net.minecraft.nbt.IntTag; import net.minecraft.nbt.IntTag;
@@ -129,7 +130,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
public Value add(Value other) public Value add(Value other)
{ {
ListValue output = new ListValue(); ListValue output = new ListValue();
if (other instanceof final ListValue list) if (other instanceof ListValue list)
{ {
List<Value> otherItems = list.items; List<Value> otherItems = list.items;
if (otherItems.size() == items.size()) if (otherItems.size() == items.size())
@@ -164,7 +165,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
public Value subtract(Value other) public Value subtract(Value other)
{ {
ListValue output = new ListValue(); ListValue output = new ListValue();
if (other instanceof final ListValue list) if (other instanceof ListValue list)
{ {
List<Value> otherItems = list.items; List<Value> otherItems = list.items;
if (otherItems.size() == items.size()) if (otherItems.size() == items.size())
@@ -199,7 +200,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
public Value multiply(Value other) public Value multiply(Value other)
{ {
ListValue output = new ListValue(); ListValue output = new ListValue();
if (other instanceof final ListValue list) if (other instanceof ListValue list)
{ {
List<Value> otherItems = list.items; List<Value> otherItems = list.items;
if (otherItems.size() == items.size()) if (otherItems.size() == items.size())
@@ -228,7 +229,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
public Value divide(Value other) public Value divide(Value other)
{ {
ListValue output = new ListValue(); ListValue output = new ListValue();
if (other instanceof final ListValue list) if (other instanceof ListValue list)
{ {
List<Value> otherItems = list.items; List<Value> otherItems = list.items;
if (otherItems.size() == items.size()) if (otherItems.size() == items.size())
@@ -256,7 +257,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
@Override @Override
public int compareTo(Value o) public int compareTo(Value o)
{ {
if (o instanceof final ListValue ol) if (o instanceof ListValue ol)
{ {
int size = this.getItems().size(); int size = this.getItems().size();
int otherSize = ol.getItems().size(); int otherSize = ol.getItems().size();
@@ -284,7 +285,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {
return o instanceof final ListValue list && getItems().equals(list.getItems()); return o instanceof ListValue list && getItems().equals(list.getItems());
} }
public List<Value> getItems() public List<Value> getItems()
@@ -555,7 +556,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
int argSize = items.size(); int argSize = items.size();
if (argSize == 0) if (argSize == 0)
@@ -565,12 +566,12 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
ListTag tag = new ListTag(); ListTag tag = new ListTag();
if (argSize == 1) if (argSize == 1)
{ {
tag.add(items.get(0).toTag(force)); tag.add(items.get(0).toTag(force, regs));
return tag; return tag;
} }
// figuring out the types // figuring out the types
List<Tag> tags = new ArrayList<>(); List<Tag> tags = new ArrayList<>();
items.forEach(v -> tags.add(v.toTag(force))); items.forEach(v -> tags.add(v.toTag(force, regs)));
Set<TagTypeCompat> cases = EnumSet.noneOf(TagTypeCompat.class); Set<TagTypeCompat> cases = EnumSet.noneOf(TagTypeCompat.class);
tags.forEach(t -> cases.add(TagTypeCompat.getType(t))); tags.forEach(t -> cases.add(TagTypeCompat.getType(t)));
if (cases.size() == 1) // well, one type of items if (cases.size() == 1) // well, one type of items
@@ -13,6 +13,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
@@ -104,11 +105,11 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
public Value add(Value o) public Value add(Value o)
{ {
Map<Value, Value> newItems = new HashMap<>(map); Map<Value, Value> newItems = new HashMap<>(map);
if (o instanceof final MapValue mapValue) if (o instanceof MapValue mapValue)
{ {
newItems.putAll(mapValue.map); newItems.putAll(mapValue.map);
} }
else if (o instanceof final AbstractListValue alv) else if (o instanceof AbstractListValue alv)
{ {
for (Value value : alv) for (Value value : alv)
{ {
@@ -142,7 +143,7 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
public void put(Value v) public void put(Value v)
{ {
if (!(v instanceof final ListValue pair)) if (!(v instanceof ListValue pair))
{ {
map.put(v, Value.NULL); map.put(v, Value.NULL);
return; return;
@@ -169,7 +170,7 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {
return o instanceof final MapValue mapValue && map.equals(mapValue.map); return o instanceof MapValue mapValue && map.equals(mapValue.map);
} }
public Map<Value, Value> getMap() public Map<Value, Value> getMap()
@@ -249,7 +250,7 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
CompoundTag tag = new CompoundTag(); CompoundTag tag = new CompoundTag();
map.forEach((k, v) -> map.forEach((k, v) ->
@@ -258,7 +259,7 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
{ {
throw new NBTSerializableValue.IncompatibleTypeException(k); throw new NBTSerializableValue.IncompatibleTypeException(k);
} }
tag.put(k.getString(), v.toTag(force)); tag.put(k.getString(), v.toTag(force, regs));
}); });
return tag; return tag;
} }
@@ -25,7 +25,7 @@ import net.minecraft.commands.arguments.item.ItemParser;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries; import net.minecraft.core.particles.ItemParticleOption;
import net.minecraft.nbt.CollectionTag; import net.minecraft.nbt.CollectionTag;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.EndTag; import net.minecraft.nbt.EndTag;
@@ -104,15 +104,11 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
nbtSupplier = tagSupplier; nbtSupplier = tagSupplier;
} }
public static Value fromStack(ItemStack stack) public static Value fromStack(ItemStack stack, RegistryAccess regs)
{ {
if (stack.hasTag()) NBTSerializableValue value = new NBTSerializableValue();
{ value.nbtSupplier = () -> stack.saveOptional(regs);
NBTSerializableValue value = new NBTSerializableValue(); return value;
value.nbtSupplier = stack::getTag;
return value;
}
return Value.NULL;
} }
public static Value nameFromRegistryId(@Nullable ResourceLocation id) public static Value nameFromRegistryId(@Nullable ResourceLocation id)
@@ -341,29 +337,32 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
private static final Map<String, ItemInput> itemCache = new HashMap<>(); private static final Map<String, ItemInput> itemCache = new HashMap<>();
public static ItemInput parseItem(String itemString, RegistryAccess regs) public static ItemStack parseItem(String itemString, RegistryAccess regs)
{ {
return parseItem(itemString, null, regs); return parseItem(itemString, null, regs);
} }
public static ItemInput parseItem(String itemString, @Nullable CompoundTag customTag, RegistryAccess regs) public static ItemStack parseItem(String itemString, @Nullable CompoundTag customTag, RegistryAccess regs)
{ {
if (customTag != null) {
return ItemStack.parseOptional(regs, customTag);
}
try try
{ {
ItemInput res = itemCache.get(itemString); // [SCARY SHIT] persistent caches over server reloads ItemInput res = itemCache.get(itemString); // [SCARY SHIT] persistent caches over server reloads
if (res != null) if (res != null)
{ {
return customTag == null ? res : new ItemInput(Holder.direct(res.getItem()), customTag); return res.createItemStack(1, false);
} }
ItemParser.ItemResult parser = (new ItemParser(regs)).parse(new StringReader(itemString)); ItemParser.ItemResult parser = (new ItemParser(regs)).parse(new StringReader(itemString));
res = new ItemInput(parser.item(), parser.nbt()); res = new ItemInput(parser.item(), parser.components());
itemCache.put(itemString, res); itemCache.put(itemString, res);
if (itemCache.size() > 64000) if (itemCache.size() > 64000)
{ {
itemCache.clear(); itemCache.clear();
} }
return customTag == null ? res : new ItemInput(Holder.direct(res.getItem()), customTag); return res.createItemStack(1, false);
} }
catch (CommandSyntaxException e) catch (CommandSyntaxException e)
{ {
@@ -764,7 +763,7 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
if (!force) if (!force)
{ {
@@ -2,6 +2,7 @@ package carpet.script.value;
import java.util.ArrayList; import java.util.ArrayList;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.StringTag; import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
@@ -89,7 +90,7 @@ public class NullValue extends NumericValue // TODO check nonsingleton code
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
if (!force) if (!force)
{ {
@@ -3,6 +3,7 @@ package carpet.script.value;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import net.minecraft.core.RegistryAccess;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -27,7 +28,7 @@ public class NumericValue extends Value
public static NumericValue asNumber(Value v1, String id) public static NumericValue asNumber(Value v1, String id)
{ {
if (v1 instanceof final NumericValue nv) if (v1 instanceof NumericValue nv)
{ {
return nv; return nv;
} }
@@ -36,7 +37,7 @@ public class NumericValue extends Value
public static NumericValue asNumber(Value v1) public static NumericValue asNumber(Value v1)
{ {
if (v1 instanceof final NumericValue nv) if (v1 instanceof NumericValue nv)
{ {
return nv; return nv;
} }
@@ -129,7 +130,7 @@ public class NumericValue extends Value
@Override @Override
public Value add(Value v) public Value add(Value v)
{ // TODO test if definintn add(NumericVlaue) woud solve the casting { // TODO test if definintn add(NumericVlaue) woud solve the casting
if (v instanceof final NumericValue nv) if (v instanceof NumericValue nv)
{ {
return longValue != null && nv.longValue != null ? new NumericValue(longValue + nv.longValue) : new NumericValue(value + nv.value); return longValue != null && nv.longValue != null ? new NumericValue(longValue + nv.longValue) : new NumericValue(value + nv.value);
} }
@@ -139,7 +140,7 @@ public class NumericValue extends Value
@Override @Override
public Value subtract(Value v) public Value subtract(Value v)
{ // TODO test if definintn add(NumericVlaue) woud solve the casting { // TODO test if definintn add(NumericVlaue) woud solve the casting
if (v instanceof final NumericValue nv) if (v instanceof NumericValue nv)
{ {
return longValue != null && nv.longValue != null ? new NumericValue(longValue - nv.longValue) : new NumericValue(value - nv.value); return longValue != null && nv.longValue != null ? new NumericValue(longValue - nv.longValue) : new NumericValue(value - nv.value);
} }
@@ -149,7 +150,7 @@ public class NumericValue extends Value
@Override @Override
public Value multiply(Value v) public Value multiply(Value v)
{ {
if (v instanceof final NumericValue nv) if (v instanceof NumericValue nv)
{ {
return longValue != null && nv.longValue != null ? new NumericValue(longValue * nv.longValue) : new NumericValue(value * nv.value); return longValue != null && nv.longValue != null ? new NumericValue(longValue * nv.longValue) : new NumericValue(value * nv.value);
} }
@@ -159,7 +160,7 @@ public class NumericValue extends Value
@Override @Override
public Value divide(Value v) public Value divide(Value v)
{ {
return v instanceof final NumericValue nv ? new NumericValue(getDouble() / nv.getDouble()) : super.divide(v); return v instanceof NumericValue nv ? new NumericValue(getDouble() / nv.getDouble()) : super.divide(v);
} }
@Override @Override
@@ -175,7 +176,7 @@ public class NumericValue extends Value
{ {
return -o.compareTo(this); return -o.compareTo(this);
} }
if (o instanceof final NumericValue no) if (o instanceof NumericValue no)
{ {
return longValue != null && no.longValue != null ? longValue.compareTo(no.longValue) : Double.compare(value, no.value); return longValue != null && no.longValue != null ? longValue.compareTo(no.longValue) : Double.compare(value, no.value);
} }
@@ -185,13 +186,13 @@ public class NumericValue extends Value
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {
if (o instanceof final Value otherValue) if (o instanceof Value otherValue)
{ {
if (otherValue.isNull()) if (otherValue.isNull())
{ {
return o.equals(this); return o.equals(this);
} }
if (o instanceof final NumericValue no) if (o instanceof NumericValue no)
{ {
if (longValue != null && no.longValue != null) if (longValue != null && no.longValue != null)
{ {
@@ -279,7 +280,7 @@ public class NumericValue extends Value
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
if (longValue != null) if (longValue != null)
{ {
@@ -17,6 +17,7 @@ import java.util.Map;
import java.util.OptionalInt; import java.util.OptionalInt;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
@@ -373,18 +374,25 @@ public class ScreenValue extends Value
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
if (this.screenHandler == null) if (this.screenHandler == null)
{ {
return Value.NULL.toTag(true); return Value.NULL.toTag(true, regs);
} }
ListTag nbtList = new ListTag(); ListTag nbtList = new ListTag();
for (int i = 0; i < this.screenHandler.slots.size(); i++) for (int i = 0; i < this.screenHandler.slots.size(); i++)
{ {
ItemStack itemStack = this.screenHandler.getSlot(i).getItem(); ItemStack itemStack = this.screenHandler.getSlot(i).getItem();
nbtList.add(itemStack.save(new CompoundTag())); if (itemStack.isEmpty())
{
nbtList.add(new CompoundTag());
}
else
{
nbtList.add(itemStack.save(regs));
}
} }
return nbtList; return nbtList;
} }
@@ -1,5 +1,6 @@
package carpet.script.value; package carpet.script.value;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.StringTag; import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
@@ -46,7 +47,7 @@ public class StringValue extends Value
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
return StringTag.valueOf(str); return StringTag.valueOf(str);
} }
@@ -16,6 +16,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
public class ThreadValue extends LazyListValue public class ThreadValue extends LazyListValue
@@ -108,13 +109,13 @@ public class ThreadValue extends LazyListValue
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {
return o instanceof final ThreadValue tv && tv.id == this.id; return o instanceof ThreadValue tv && tv.id == this.id;
} }
@Override @Override
public int compareTo(Value o) public int compareTo(Value o)
{ {
if (!(o instanceof final ThreadValue tv)) if (!(o instanceof ThreadValue tv))
{ {
throw new InternalExpressionException("Cannot compare tasks to other types"); throw new InternalExpressionException("Cannot compare tasks to other types");
} }
@@ -128,13 +129,13 @@ public class ThreadValue extends LazyListValue
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
if (!force) if (!force)
{ {
throw new NBTSerializableValue.IncompatibleTypeException(this); throw new NBTSerializableValue.IncompatibleTypeException(this);
} }
return getValue().toTag(true); return getValue().toTag(true, regs);
} }
@Override @Override
@@ -2,6 +2,7 @@ package carpet.script.value;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
public class UndefValue extends NullValue public class UndefValue extends NullValue
@@ -87,7 +88,7 @@ public class UndefValue extends NullValue
} }
@Override @Override
public Tag toTag(boolean force) public Tag toTag(boolean force, RegistryAccess regs)
{ {
throw getError(); throw getError();
} }
+4 -3
View File
@@ -12,6 +12,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -97,7 +98,7 @@ public abstract class Value implements Comparable<Value>, Cloneable
public Value divide(Value v) public Value divide(Value v)
{ {
if (v instanceof final NumericValue number) if (v instanceof NumericValue number)
{ {
String lstr = getString(); String lstr = getString();
return new StringValue(lstr.substring(0, (int) (lstr.length() / number.getDouble()))); return new StringValue(lstr.substring(0, (int) (lstr.length() / number.getDouble())));
@@ -121,7 +122,7 @@ public abstract class Value implements Comparable<Value>, Cloneable
@Override // for hashmap key access, and == operator @Override // for hashmap key access, and == operator
public boolean equals(Object o) public boolean equals(Object o)
{ {
if (o instanceof final Value v) if (o instanceof Value v)
{ {
return this.compareTo(v) == 0; return this.compareTo(v) == 0;
} }
@@ -254,7 +255,7 @@ public abstract class Value implements Comparable<Value>, Cloneable
} }
} }
public abstract Tag toTag(boolean force); public abstract Tag toTag(boolean force, RegistryAccess regs);
public JsonElement toJson() public JsonElement toJson()
{ {
@@ -8,14 +8,12 @@ import carpet.script.utils.Colors;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.advancements.critereon.MinMaxBounds; import net.minecraft.advancements.critereon.MinMaxBounds;
import net.minecraft.commands.arguments.item.ItemInput;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.GlobalPos; import net.minecraft.core.GlobalPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.core.Vec3i; import net.minecraft.core.Vec3i;
import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
@@ -58,8 +56,6 @@ import java.util.UUID;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class ValueConversions public class ValueConversions
@@ -97,22 +93,12 @@ public class ValueConversions
); );
} }
@Deprecated
public static Value of(ItemStack stack)
{
return stack == null || stack.isEmpty() ? Value.NULL : ListValue.of(
of(BuiltInRegistries.ITEM.getKey(stack.getItem())),
new NumericValue(stack.getCount()),
NBTSerializableValue.fromStack(stack)
);
}
public static Value of(ItemStack stack, RegistryAccess regs) public static Value of(ItemStack stack, RegistryAccess regs)
{ {
return stack == null || stack.isEmpty() ? Value.NULL : ListValue.of( return stack == null || stack.isEmpty() ? Value.NULL : ListValue.of(
of(regs.registryOrThrow(Registries.ITEM).getKey(stack.getItem())), of(regs.registryOrThrow(Registries.ITEM).getKey(stack.getItem())),
new NumericValue(stack.getCount()), new NumericValue(stack.getCount()),
NBTSerializableValue.fromStack(stack) NBTSerializableValue.fromStack(stack, regs)
); );
} }
@@ -503,22 +489,9 @@ public class ValueConversions
{ {
name = value.getString(); name = value.getString();
} }
ItemInput itemInput = NBTSerializableValue.parseItem(name, nbtTag, regs); ItemStack itemInput = NBTSerializableValue.parseItem(name, nbtTag, regs);
try itemInput.setCount(count);
{ return itemInput;
return itemInput.createItemStack(count, false);
}
catch (CommandSyntaxException cse)
{
if (!withCount)
{
throw new IllegalStateException("Unexpected exception while creating item stack of " + name + ". All items should be able to stack to one", cse);
}
else
{
throw new ThrowStatement(count + " stack size of " + name, Throwables.UNKNOWN_ITEM);
}
}
} }
public static Value guess(ServerLevel serverWorld, Object o) public static Value guess(ServerLevel serverWorld, Object o)
+3 -3
View File
@@ -55,9 +55,9 @@ public class BlockInfo
//lst.add(Messenger.s(String.format(" - Picks neighbour light value: %s", state.useNeighborBrightness(world, pos)))); //lst.add(Messenger.s(String.format(" - Picks neighbour light value: %s", state.useNeighborBrightness(world, pos))));
lst.add(Messenger.s("")); lst.add(Messenger.s(""));
lst.add(Messenger.s(String.format(" - Causes suffocation: %s", state.isSuffocating(world, pos)))); //canSuffocate lst.add(Messenger.s(String.format(" - Causes suffocation: %s", state.isSuffocating(world, pos)))); //canSuffocate
lst.add(Messenger.s(String.format(" - Blocks movement on land: %s", !state.isPathfindable(world,pos, PathComputationType.LAND)))); lst.add(Messenger.s(String.format(" - Blocks movement on land: %s", !state.isPathfindable(PathComputationType.LAND))));
lst.add(Messenger.s(String.format(" - Blocks movement in air: %s", !state.isPathfindable(world,pos, PathComputationType.AIR)))); lst.add(Messenger.s(String.format(" - Blocks movement in air: %s", !state.isPathfindable(PathComputationType.AIR))));
lst.add(Messenger.s(String.format(" - Blocks movement in liquids: %s", !state.isPathfindable(world,pos, PathComputationType.WATER)))); lst.add(Messenger.s(String.format(" - Blocks movement in liquids: %s", !state.isPathfindable(PathComputationType.WATER))));
lst.add(Messenger.s(String.format(" - Can burn: %s", state.ignitedByLava()))); lst.add(Messenger.s(String.format(" - Can burn: %s", state.ignitedByLava())));
lst.add(Messenger.s(String.format(" - Hardness: %.2f", state.getDestroySpeed(world, pos)))); lst.add(Messenger.s(String.format(" - Hardness: %.2f", state.getDestroySpeed(world, pos))));
lst.add(Messenger.s(String.format(" - Blast resistance: %.2f", block.getExplosionResistance()))); lst.add(Messenger.s(String.format(" - Blast resistance: %.2f", block.getExplosionResistance())));
@@ -13,7 +13,7 @@ import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.level.StructureManager; import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.biome.MobSpawnSettings; import net.minecraft.world.level.biome.MobSpawnSettings;
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.levelgen.structure.BuiltinStructures; import net.minecraft.world.level.levelgen.structure.BuiltinStructures;
import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructureSpawnOverride; import net.minecraft.world.level.levelgen.structure.StructureSpawnOverride;