Check against offline players when trying to see if a spell can modify blocks at a location. Closes #283

This commit is contained in:
Sollace 2024-03-28 17:05:04 +00:00
parent 5109b67de2
commit 10dc8ce6d7
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
4 changed files with 65 additions and 6 deletions

View file

@ -14,12 +14,14 @@ import com.minelittlepony.unicopia.entity.damage.UDamageSources;
import com.minelittlepony.unicopia.particle.ParticleSource;
import com.minelittlepony.unicopia.server.world.Ether;
import com.minelittlepony.unicopia.server.world.ModificationType;
import com.minelittlepony.unicopia.server.world.OfflinePlayerCache;
import com.minelittlepony.unicopia.util.SoundEmitter;
import com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules;
@ -67,10 +69,18 @@ public interface Caster<E extends Entity> extends
}
if (getMaster() instanceof PlayerEntity player) {
if (!asWorld().canPlayerModifyAt(player, pos)) {
if (!player.canModifyBlocks() || !asWorld().canPlayerModifyAt(player, pos)) {
return false;
}
} else {
if (asWorld() instanceof ServerWorld sw) {
@Nullable
PlayerEntity player = OfflinePlayerCache.getOfflinePlayer(sw, getMasterId().orElse(null));
if (player != null && !player.canModifyBlocks() || !sw.canPlayerModifyAt(player, pos)) {
return false;
}
}
if (!asWorld().getGameRules().getBoolean(GameRules.DO_MOB_GRIEFING)) {
return false;
}

View file

@ -61,7 +61,9 @@ public class HydrophobicSpell extends AbstractSpell {
storedFluidPositions.removeIf(entry -> {
if (!area.isPointInside(Vec3d.ofCenter(entry.pos()))) {
entry.restore(world);
if (source.canModifyAt(entry.pos())) {
entry.restore(world);
}
return true;
}
@ -72,7 +74,7 @@ public class HydrophobicSpell extends AbstractSpell {
pos = new BlockPos(pos);
BlockState state = world.getBlockState(pos);
if (state.getFluidState().isIn(affectedFluid)) {
if (source.canModifyAt(pos) && state.getFluidState().isIn(affectedFluid)) {
Block block = state.getBlock();
if (block instanceof FluidBlock) {
@ -95,7 +97,7 @@ public class HydrophobicSpell extends AbstractSpell {
source.spawnParticles(new Sphere(true, range), 10, pos -> {
BlockPos bp = BlockPos.ofFloored(pos);
if (source.asWorld().getFluidState(bp.up()).isIn(affectedFluid)) {
if (source.canModifyAt(bp) && source.asWorld().getFluidState(bp.up()).isIn(affectedFluid)) {
source.addParticle(UParticles.RAIN_DROPS, pos, Vec3d.ZERO);
}
});
@ -116,7 +118,9 @@ public class HydrophobicSpell extends AbstractSpell {
protected void onDestroyed(Caster<?> caster) {
Ether.get(caster.asWorld()).remove(this, caster);
storedFluidPositions.removeIf(entry -> {
entry.restore(caster.asWorld());
if (caster.canModifyAt(entry.pos())) {
entry.restore(caster.asWorld());
}
return true;
});
}

View file

@ -48,8 +48,9 @@ public class InfernoSpell extends FireSpell {
for (int i = 0; i < radius * 2; i++) {
if (w.random.nextInt(12) == 0) {
Vec3d vec = shape.computePoint(w.random).add(origin);
BlockPos pos = BlockPos.ofFloored(vec);
if (!applyBlocks(w, BlockPos.ofFloored(vec))) {
if (source.canModifyAt(pos) && !applyBlocks(w, pos)) {
applyEntities(source, vec);
}
}

View file

@ -0,0 +1,44 @@
package com.minelittlepony.unicopia.server.world;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.jetbrains.annotations.Nullable;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.mojang.authlib.GameProfile;
import net.fabricmc.fabric.api.entity.FakePlayer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
public class OfflinePlayerCache {
private static final LoadingCache<Key, Optional<ServerPlayerEntity>> CACHE = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.MINUTES)
.build(CacheLoader.from(key -> {
ServerPlayerEntity offlinePlayer = FakePlayer.get(key.world(), new GameProfile(key.playerId(), "[Offline Player]"));
if (key.world().getServer().getPlayerManager().loadPlayerData(offlinePlayer) != null) {
return Optional.of(offlinePlayer);
}
return Optional.empty();
}));
@Nullable
public static ServerPlayerEntity getOfflinePlayer(ServerWorld world, UUID playerId) {
ServerPlayerEntity player = (ServerPlayerEntity)world.getPlayerByUuid(playerId);
if (player == null) {
player = world.getServer().getPlayerManager().getPlayer(playerId);
}
if (player == null) {
return CACHE.getUnchecked(new Key(world, playerId)).orElse(null);
}
return player;
}
record Key (ServerWorld world, UUID playerId) {}
}