198 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			198 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.PoiManager;
 | |
| import net.minecraft.world.entity.ai.village.poi.PoiRecord;
 | |
| 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.level();
 | |
| 			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, PoiManager.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());
 | |
| 		}
 | |
| 	}
 | |
| }
 |