minecraft-src/net/minecraft/world/entity/raid/Raids.java
2025-07-04 03:45:38 +03:00

196 lines
5.9 KiB
Java

package net.minecraft.world.entity.raid;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
import java.util.Iterator;
import java.util.List;
import java.util.OptionalInt;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.PoiTypeTags;
import net.minecraft.util.datafix.DataFixTypes;
import net.minecraft.world.entity.ai.village.poi.PoiRecord;
import net.minecraft.world.entity.ai.village.poi.PoiManager.Occupancy;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.dimension.BuiltinDimensionTypes;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.saveddata.SavedData;
import net.minecraft.world.level.saveddata.SavedDataType;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
public class Raids extends SavedData {
private static final String RAID_FILE_ID = "raids";
public static final Codec<Raids> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
Raids.RaidWithId.CODEC
.listOf()
.optionalFieldOf("raids", List.of())
.forGetter(raids -> raids.raidMap.int2ObjectEntrySet().stream().map(Raids.RaidWithId::from).toList()),
Codec.INT.fieldOf("next_id").forGetter(raids -> raids.nextId),
Codec.INT.fieldOf("tick").forGetter(raids -> raids.tick)
)
.apply(instance, Raids::new)
);
public static final SavedDataType<Raids> TYPE = new SavedDataType<>("raids", Raids::new, CODEC, DataFixTypes.SAVED_DATA_RAIDS);
public static final SavedDataType<Raids> TYPE_END = new SavedDataType<>("raids_end", Raids::new, CODEC, DataFixTypes.SAVED_DATA_RAIDS);
private final Int2ObjectMap<Raid> raidMap = new Int2ObjectOpenHashMap<>();
private int nextId = 1;
private int tick;
public static SavedDataType<Raids> getType(Holder<DimensionType> dimension) {
return dimension.is(BuiltinDimensionTypes.END) ? TYPE_END : TYPE;
}
public Raids() {
this.setDirty();
}
private Raids(List<Raids.RaidWithId> raids, int nextId, int tick) {
for (Raids.RaidWithId raidWithId : raids) {
this.raidMap.put(raidWithId.id, raidWithId.raid);
}
this.nextId = nextId;
this.tick = tick;
}
@Nullable
public Raid get(int id) {
return this.raidMap.get(id);
}
public OptionalInt getId(Raid raid) {
for (Entry<Raid> entry : this.raidMap.int2ObjectEntrySet()) {
if (entry.getValue() == raid) {
return OptionalInt.of(entry.getIntKey());
}
}
return OptionalInt.empty();
}
public void tick(ServerLevel level) {
this.tick++;
Iterator<Raid> iterator = this.raidMap.values().iterator();
while (iterator.hasNext()) {
Raid raid = (Raid)iterator.next();
if (level.getGameRules().getBoolean(GameRules.RULE_DISABLE_RAIDS)) {
raid.stop();
}
if (raid.isStopped()) {
iterator.remove();
this.setDirty();
} else {
raid.tick(level);
}
}
if (this.tick % 200 == 0) {
this.setDirty();
}
DebugPackets.sendRaids(level, this.raidMap.values());
}
public static boolean canJoinRaid(Raider raider) {
return raider.isAlive() && raider.canJoinRaid() && raider.getNoActionTime() <= 2400;
}
@Nullable
public Raid createOrExtendRaid(ServerPlayer player, BlockPos pos) {
if (player.isSpectator()) {
return null;
} else {
ServerLevel serverLevel = player.serverLevel();
if (serverLevel.getGameRules().getBoolean(GameRules.RULE_DISABLE_RAIDS)) {
return null;
} else {
DimensionType dimensionType = serverLevel.dimensionType();
if (!dimensionType.hasRaids()) {
return null;
} else {
List<PoiRecord> list = serverLevel.getPoiManager().getInRange(holder -> holder.is(PoiTypeTags.VILLAGE), pos, 64, Occupancy.IS_OCCUPIED).toList();
int i = 0;
Vec3 vec3 = Vec3.ZERO;
for (PoiRecord poiRecord : list) {
BlockPos blockPos = poiRecord.getPos();
vec3 = vec3.add(blockPos.getX(), blockPos.getY(), blockPos.getZ());
i++;
}
BlockPos blockPos2;
if (i > 0) {
vec3 = vec3.scale(1.0 / i);
blockPos2 = BlockPos.containing(vec3);
} else {
blockPos2 = pos;
}
Raid raid = this.getOrCreateRaid(serverLevel, blockPos2);
if (!raid.isStarted() && !this.raidMap.containsValue(raid)) {
this.raidMap.put(this.getUniqueId(), raid);
}
if (!raid.isStarted() || raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel()) {
raid.absorbRaidOmen(player);
}
this.setDirty();
return raid;
}
}
}
}
private Raid getOrCreateRaid(ServerLevel serverLevel, BlockPos pos) {
Raid raid = serverLevel.getRaidAt(pos);
return raid != null ? raid : new Raid(pos, serverLevel.getDifficulty());
}
public static Raids load(CompoundTag tag) {
return (Raids)CODEC.parse(NbtOps.INSTANCE, tag).resultOrPartial().orElseGet(Raids::new);
}
private int getUniqueId() {
return ++this.nextId;
}
@Nullable
public Raid getNearbyRaid(BlockPos pos, int distance) {
Raid raid = null;
double d = distance;
for (Raid raid2 : this.raidMap.values()) {
double e = raid2.getCenter().distSqr(pos);
if (raid2.isActive() && e < d) {
raid = raid2;
d = e;
}
}
return raid;
}
record RaidWithId(int id, Raid raid) {
public static final Codec<Raids.RaidWithId> CODEC = RecordCodecBuilder.create(
instance -> instance.group(Codec.INT.fieldOf("id").forGetter(Raids.RaidWithId::id), Raid.MAP_CODEC.forGetter(Raids.RaidWithId::raid))
.apply(instance, Raids.RaidWithId::new)
);
public static Raids.RaidWithId from(Entry<Raid> entry) {
return new Raids.RaidWithId(entry.getIntKey(), (Raid)entry.getValue());
}
}
}