mew let mep spawn
This commit is contained in:
parent
9b44fcf4e0
commit
8cfc27cb70
@ -1,135 +1,42 @@
|
|||||||
package net.Chipperfluff.chipi;
|
package net.Chipperfluff.chipi;
|
||||||
|
|
||||||
import net.Chipperfluff.chipi.advancement.ModCriteria;
|
import net.Chipperfluff.chipi.advancement.ModCriteria;
|
||||||
import net.Chipperfluff.chipi.block.ChipperPortalBlock;
|
|
||||||
import net.Chipperfluff.chipi.block.ModBlocks;
|
import net.Chipperfluff.chipi.block.ModBlocks;
|
||||||
import net.Chipperfluff.chipi.command.ChpCommand;
|
import net.Chipperfluff.chipi.command.CommandHandler;
|
||||||
import net.Chipperfluff.chipi.effect.ChipiBlessingEvents;
|
import net.Chipperfluff.chipi.effect.ChipiBlessingEvents;
|
||||||
import net.Chipperfluff.chipi.effect.ChipiHungerHandler;
|
import net.Chipperfluff.chipi.effect.ChipiHungerHandler;
|
||||||
import net.Chipperfluff.chipi.effect.ModEffects;
|
import net.Chipperfluff.chipi.effect.ModEffects;
|
||||||
import net.Chipperfluff.chipi.entity.ModEntities;
|
import net.Chipperfluff.chipi.entity.ModEntities;
|
||||||
|
import net.Chipperfluff.chipi.entity.SpawnLogic;
|
||||||
import net.Chipperfluff.chipi.entity.custom.MepEntity;
|
import net.Chipperfluff.chipi.entity.custom.MepEntity;
|
||||||
import net.Chipperfluff.chipi.item.ModItemGroups;
|
import net.Chipperfluff.chipi.item.ModItemGroups;
|
||||||
import net.Chipperfluff.chipi.item.ModItems;
|
import net.Chipperfluff.chipi.item.ModItems;
|
||||||
import net.Chipperfluff.chipi.world.gen.ChipiDungeonGenerator;
|
import net.Chipperfluff.chipi.server.ChipiServerEvents;
|
||||||
|
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
|
|
||||||
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
|
|
||||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
|
|
||||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
|
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
|
||||||
import net.minecraft.registry.RegistryKey;
|
|
||||||
import net.minecraft.registry.RegistryKeys;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.world.ServerWorld;
|
|
||||||
import net.minecraft.structure.StructurePlacementData;
|
|
||||||
import net.minecraft.structure.StructureTemplate;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.world.GameRules;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
import net.minecraft.world.gen.GenerationStep;
|
|
||||||
import net.Chipperfluff.chipi.command.CommandHandler;
|
|
||||||
|
|
||||||
public class ChipiMod implements ModInitializer {
|
public class ChipiMod implements ModInitializer {
|
||||||
|
|
||||||
public static final String MOD_ID = "chipi";
|
public static final String MOD_ID = "chipi";
|
||||||
|
|
||||||
public static final RegistryKey<World> CHIPI_DIMENSION_KEY = RegistryKey.of(RegistryKeys.WORLD, new Identifier("chipi", "chipi_dimension"));
|
|
||||||
|
|
||||||
private static final Identifier SPAWN_STRUCTURE = new Identifier("chipi", "spawn");
|
|
||||||
|
|
||||||
private static MinecraftServer SERVER;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
|
|
||||||
ModBlocks.register();
|
ModBlocks.register();
|
||||||
ModItems.register();
|
ModItems.register();
|
||||||
ModItemGroups.register();
|
ModItemGroups.register();
|
||||||
ModCriteria.register();
|
|
||||||
ModEntities.register();
|
|
||||||
ModEffects.register();
|
ModEffects.register();
|
||||||
|
ModCriteria.register();
|
||||||
|
|
||||||
ChipiBlessingEvents.register();
|
ChipiBlessingEvents.register();
|
||||||
ChipiHungerHandler.register();
|
ChipiHungerHandler.register();
|
||||||
|
SpawnLogic.register();
|
||||||
|
|
||||||
CommandHandler.register();
|
CommandHandler.register();
|
||||||
|
|
||||||
FabricDefaultAttributeRegistry.register(ModEntities.MEP, MepEntity.createMepAttributes());
|
FabricDefaultAttributeRegistry.register(ModEntities.MEP, MepEntity.createMepAttributes());
|
||||||
|
|
||||||
BiomeModifications.addFeature(
|
ChipiServerEvents.register();
|
||||||
BiomeSelectors.foundInOverworld(),
|
|
||||||
GenerationStep.Feature.UNDERGROUND_ORES,
|
|
||||||
RegistryKey.of(RegistryKeys.PLACED_FEATURE, new Identifier("chipi", "chipper_ore"))
|
|
||||||
);
|
|
||||||
|
|
||||||
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
|
|
||||||
SERVER = server;
|
|
||||||
});
|
|
||||||
|
|
||||||
ServerTickEvents.END_WORLD_TICK.register(world -> {
|
|
||||||
if (!world.getRegistryKey().equals(CHIPI_DIMENSION_KEY)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (PlayerEntity player : world.getPlayers()) {
|
|
||||||
if (player.getBlockY() >= 50) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChipperPortalBlock.teleportToChipiSpawn(world, player);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ServerWorldEvents.LOAD.register((server, world) -> {
|
|
||||||
if (!world.getRegistryKey().equals(CHIPI_DIMENSION_KEY)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
world.setTimeOfDay(18000);
|
|
||||||
world.getGameRules()
|
|
||||||
.get(GameRules.DO_DAYLIGHT_CYCLE)
|
|
||||||
.set(false, server);
|
|
||||||
|
|
||||||
SpawnPlacedState state = world.getPersistentStateManager().getOrCreate(
|
|
||||||
SpawnPlacedState::fromNbt,
|
|
||||||
SpawnPlacedState::new,
|
|
||||||
"chipi_spawn"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (state.placed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StructureTemplate spawnTemplate = world.getStructureTemplateManager().getTemplate(SPAWN_STRUCTURE).orElse(null);
|
|
||||||
|
|
||||||
if (spawnTemplate == null) {
|
|
||||||
System.err.println("[CHIPI] spawn.nbt not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockPos spawnCenter = new BlockPos(0, 80, 0);
|
|
||||||
|
|
||||||
spawnTemplate.place(world, spawnCenter, spawnCenter, new StructurePlacementData(), world.getRandom(), 2);
|
|
||||||
|
|
||||||
world.setSpawnPos(spawnCenter.up(), 0.0f);
|
|
||||||
|
|
||||||
ChipiDungeonGenerator.generateInitialLayout(world, spawnCenter);
|
|
||||||
|
|
||||||
state.placed = true;
|
|
||||||
state.markDirty();
|
|
||||||
|
|
||||||
System.out.println("[CHIPI] Spawn + initial dungeon generated");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ServerWorld getChipiWorld() {
|
|
||||||
if (SERVER == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SERVER.getWorld(CHIPI_DIMENSION_KEY);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,10 @@ public class ChipperPortalBlock extends Block {
|
|||||||
public static void teleportToChipiSpawn(ServerWorld targetWorld, PlayerEntity player) {
|
public static void teleportToChipiSpawn(ServerWorld targetWorld, PlayerEntity player) {
|
||||||
BlockPos spawn = resolveSafeSpawn(targetWorld);
|
BlockPos spawn = resolveSafeSpawn(targetWorld);
|
||||||
|
|
||||||
|
player.setVelocity(0.0, 0.0, 0.0);
|
||||||
|
player.fallDistance = 0.0f;
|
||||||
|
player.setOnGround(true);
|
||||||
|
|
||||||
player.teleport(
|
player.teleport(
|
||||||
targetWorld,
|
targetWorld,
|
||||||
spawn.getX() + 0.5,
|
spawn.getX() + 0.5,
|
||||||
@ -59,9 +63,15 @@ public class ChipperPortalBlock extends Block {
|
|||||||
spawn.getZ() + 0.5,
|
spawn.getZ() + 0.5,
|
||||||
EnumSet.noneOf(PositionFlag.class),
|
EnumSet.noneOf(PositionFlag.class),
|
||||||
player.getYaw(),
|
player.getYaw(),
|
||||||
player.getPitch());
|
player.getPitch()
|
||||||
|
);
|
||||||
|
|
||||||
|
player.setVelocity(0.0, 0.0, 0.0);
|
||||||
|
player.fallDistance = 0.0f;
|
||||||
|
player.setOnGround(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static BlockPos resolveSafeSpawn(ServerWorld targetWorld) {
|
public static BlockPos resolveSafeSpawn(ServerWorld targetWorld) {
|
||||||
BlockPos spawn = DEFAULT_SPAWN;
|
BlockPos spawn = DEFAULT_SPAWN;
|
||||||
BlockPos under = spawn.down();
|
BlockPos under = spawn.down();
|
||||||
|
|||||||
@ -12,5 +12,6 @@ public class ChipiClient implements ClientModInitializer {
|
|||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
BlockRenderLayerMap.INSTANCE.putBlock(ModBlocks.CHIPPER_PORTAL, RenderLayer.getTranslucent());
|
BlockRenderLayerMap.INSTANCE.putBlock(ModBlocks.CHIPPER_PORTAL, RenderLayer.getTranslucent());
|
||||||
ModEntityRenderers.register();
|
ModEntityRenderers.register();
|
||||||
|
ModTooltips.register();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
63
src/main/java/net/Chipperfluff/chipi/client/ModTooltips.java
Normal file
63
src/main/java/net/Chipperfluff/chipi/client/ModTooltips.java
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package net.Chipperfluff.chipi.client;
|
||||||
|
|
||||||
|
import net.Chipperfluff.chipi.block.ModBlocks;
|
||||||
|
import net.Chipperfluff.chipi.item.ModItems;
|
||||||
|
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
public final class ModTooltips {
|
||||||
|
|
||||||
|
private ModTooltips() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
|
||||||
|
ItemTooltipCallback.EVENT.register((stack, context, lines) -> {
|
||||||
|
|
||||||
|
// ===== BLOCK ITEMS =====
|
||||||
|
if (stack.isOf(ModBlocks.VOID_BLOCK.asItem()))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.void_block"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModBlocks.CHIPPER_FRAME.asItem()))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.chipper_frame"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModBlocks.CHIPPER_PORTAL.asItem()))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.chipper_portal"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModBlocks.CHIPPER_ORE.asItem()))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.chipper_ore"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModBlocks.CHIPPER_ALLOY_BLOCK.asItem()))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.chipper_alloy_block"));
|
||||||
|
|
||||||
|
// ===== ITEMS =====
|
||||||
|
if (stack.isOf(ModItems.NUT))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.nut"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModItems.RAW_CHIPPER_ORE))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.raw_chipper_ore"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModItems.CHIPPER_INGOT))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.chipper_ingot"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModItems.CHIPPER_ALLOY))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.chipper_alloy"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModItems.MEP_SPAWN_EGG))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.mep_spawn_egg"));
|
||||||
|
|
||||||
|
// ===== ARMOR =====
|
||||||
|
if (stack.isOf(ModItems.CHIPPER_HELMET))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.chipper_helmet"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModItems.CHIPPER_CHESTPLATE))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.chipper_chestplate"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModItems.CHIPPER_LEGGINGS))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.chipper_leggings"));
|
||||||
|
|
||||||
|
if (stack.isOf(ModItems.CHIPPER_BOOTS))
|
||||||
|
lines.add(Text.translatable("tooltip.chipi.chipper_boots"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,26 +1,28 @@
|
|||||||
package net.Chipperfluff.chipi.entity;
|
package net.Chipperfluff.chipi.entity;
|
||||||
|
|
||||||
import net.Chipperfluff.chipi.ChipiMod;
|
|
||||||
import net.Chipperfluff.chipi.entity.custom.MepEntity;
|
import net.Chipperfluff.chipi.entity.custom.MepEntity;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
|
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
|
||||||
|
|
||||||
import net.minecraft.entity.EntityDimensions;
|
import net.minecraft.entity.EntityDimensions;
|
||||||
|
import net.minecraft.entity.SpawnGroup;
|
||||||
import net.minecraft.entity.EntityType;
|
import net.minecraft.entity.EntityType;
|
||||||
import net.minecraft.registry.Registries;
|
import net.minecraft.registry.Registries;
|
||||||
import net.minecraft.registry.Registry;
|
import net.minecraft.registry.Registry;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
public class ModEntities {
|
public final class ModEntities {
|
||||||
|
|
||||||
public static final EntityType<MepEntity> MEP = Registry.register(
|
public static final EntityType<MepEntity> MEP =
|
||||||
|
Registry.register(
|
||||||
Registries.ENTITY_TYPE,
|
Registries.ENTITY_TYPE,
|
||||||
new Identifier(ChipiMod.MOD_ID, "mep"),
|
new Identifier("chipi", "mep"),
|
||||||
FabricEntityTypeBuilder.createMob()
|
FabricEntityTypeBuilder
|
||||||
.entityFactory(MepEntity::new)
|
.create(SpawnGroup.CREATURE, MepEntity::new)
|
||||||
.dimensions(EntityDimensions.fixed(0.6f, 1.95f))
|
.dimensions(EntityDimensions.fixed(0.6f, 1.95f))
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
public static void register() {
|
private ModEntities() {
|
||||||
// called from mod init
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
61
src/main/java/net/Chipperfluff/chipi/entity/SpawnLogic.java
Normal file
61
src/main/java/net/Chipperfluff/chipi/entity/SpawnLogic.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package net.Chipperfluff.chipi.entity;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
|
||||||
|
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.SpawnGroup;
|
||||||
|
import net.minecraft.entity.SpawnReason;
|
||||||
|
import net.minecraft.entity.SpawnRestriction;
|
||||||
|
import net.minecraft.entity.mob.MobEntity;
|
||||||
|
import net.minecraft.registry.RegistryKey;
|
||||||
|
import net.minecraft.registry.RegistryKeys;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.world.Heightmap;
|
||||||
|
import net.minecraft.world.ServerWorldAccess;
|
||||||
|
import net.minecraft.world.biome.Biome;
|
||||||
|
|
||||||
|
public final class SpawnLogic {
|
||||||
|
|
||||||
|
private static final RegistryKey<Biome> VOID_BIOME =
|
||||||
|
RegistryKey.of(RegistryKeys.BIOME, new Identifier("chipi", "void"));
|
||||||
|
|
||||||
|
private SpawnLogic() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
|
||||||
|
BiomeModifications.addSpawn(
|
||||||
|
BiomeSelectors.includeByKey(VOID_BIOME),
|
||||||
|
SpawnGroup.MONSTER,
|
||||||
|
ModEntities.MEP,
|
||||||
|
10,
|
||||||
|
1,
|
||||||
|
4
|
||||||
|
);
|
||||||
|
|
||||||
|
SpawnRestriction.register(
|
||||||
|
ModEntities.MEP,
|
||||||
|
SpawnRestriction.Location.ON_GROUND,
|
||||||
|
Heightmap.Type.MOTION_BLOCKING_NO_LEAVES,
|
||||||
|
SpawnLogic::canSpawn
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean canSpawn(EntityType<? extends MobEntity> type, ServerWorldAccess world, SpawnReason reason, BlockPos pos, Random random) {
|
||||||
|
int y = pos.getY();
|
||||||
|
if (y < 87 || y > 90) return false;
|
||||||
|
if (pos.getZ() < 18) return false;
|
||||||
|
|
||||||
|
BlockState below = world.getBlockState(pos.down());
|
||||||
|
boolean can_spawn = below.isOf(Blocks.POLISHED_BLACKSTONE_BRICKS);
|
||||||
|
|
||||||
|
System.out.println("[MEP ENTITY] spawn check pos=" + pos + " below=" + below.getBlock());
|
||||||
|
|
||||||
|
return can_spawn;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -22,7 +22,10 @@ import net.minecraft.world.World;
|
|||||||
|
|
||||||
public class MepEntity extends PathAwareEntity {
|
public class MepEntity extends PathAwareEntity {
|
||||||
|
|
||||||
|
private static final int FORGET_TARGET_AFTER_TICKS = 100;
|
||||||
|
|
||||||
private boolean angryAtPlayer = false;
|
private boolean angryAtPlayer = false;
|
||||||
|
private int ticksSinceLastSeen = 0;
|
||||||
|
|
||||||
public MepEntity(EntityType<? extends PathAwareEntity> entityType, World world) {
|
public MepEntity(EntityType<? extends PathAwareEntity> entityType, World world) {
|
||||||
super(entityType, world);
|
super(entityType, world);
|
||||||
@ -42,7 +45,7 @@ public class MepEntity extends PathAwareEntity {
|
|||||||
this,
|
this,
|
||||||
PlayerEntity.class,
|
PlayerEntity.class,
|
||||||
true,
|
true,
|
||||||
target -> target instanceof PlayerEntity player && (angryAtPlayer || !isPlayerProtected(player))
|
target -> target instanceof PlayerEntity player && !isPlayerProtected(player)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -51,13 +54,15 @@ public class MepEntity extends PathAwareEntity {
|
|||||||
return PathAwareEntity.createMobAttributes()
|
return PathAwareEntity.createMobAttributes()
|
||||||
.add(EntityAttributes.GENERIC_MAX_HEALTH, 20.0)
|
.add(EntityAttributes.GENERIC_MAX_HEALTH, 20.0)
|
||||||
.add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 4.0)
|
.add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 4.0)
|
||||||
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25);
|
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25)
|
||||||
|
.add(EntityAttributes.GENERIC_FOLLOW_RANGE, 32.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean damage(DamageSource source, float amount) {
|
public boolean damage(DamageSource source, float amount) {
|
||||||
if (source.getAttacker() instanceof PlayerEntity) {
|
if (source.getAttacker() instanceof PlayerEntity) {
|
||||||
angryAtPlayer = true;
|
angryAtPlayer = true;
|
||||||
|
ticksSinceLastSeen = 0;
|
||||||
}
|
}
|
||||||
return super.damage(source, amount);
|
return super.damage(source, amount);
|
||||||
}
|
}
|
||||||
@ -68,19 +73,40 @@ public class MepEntity extends PathAwareEntity {
|
|||||||
|
|
||||||
LivingEntity target = this.getTarget();
|
LivingEntity target = this.getTarget();
|
||||||
|
|
||||||
if (angryAtPlayer) {
|
if (!(target instanceof PlayerEntity player)) {
|
||||||
if (!(target instanceof PlayerEntity) || !this.canSee(target)) {
|
ticksSinceLastSeen = 0;
|
||||||
angryAtPlayer = false;
|
angryAtPlayer = false;
|
||||||
this.setTarget(null);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target instanceof PlayerEntity player && isPlayerProtected(player)) {
|
// Protected players instantly cancel targeting
|
||||||
|
if (isPlayerProtected(player)) {
|
||||||
|
clearTarget();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.canSee(player)) {
|
||||||
|
ticksSinceLastSeen = 0;
|
||||||
|
angryAtPlayer = true;
|
||||||
|
this.getNavigation().startMovingTo(player, 1.2D);
|
||||||
|
} else {
|
||||||
|
ticksSinceLastSeen++;
|
||||||
|
|
||||||
|
// Keep chasing for a while even without LOS
|
||||||
|
if (ticksSinceLastSeen <= FORGET_TARGET_AFTER_TICKS) {
|
||||||
|
this.getNavigation().startMovingTo(player, 1.2D);
|
||||||
|
} else {
|
||||||
|
clearTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearTarget() {
|
||||||
|
angryAtPlayer = false;
|
||||||
|
ticksSinceLastSeen = 0;
|
||||||
this.setTarget(null);
|
this.setTarget(null);
|
||||||
this.getNavigation().stop();
|
this.getNavigation().stop();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isPlayerProtected(PlayerEntity player) {
|
private static boolean isPlayerProtected(PlayerEntity player) {
|
||||||
BlockPos pos = player.getBlockPos();
|
BlockPos pos = player.getBlockPos();
|
||||||
@ -90,6 +116,19 @@ public class MepEntity extends PathAwareEntity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.getBlock() instanceof StairsBlock || state.getBlock() instanceof SlabBlock;
|
return state.getBlock() instanceof StairsBlock
|
||||||
|
|| state.getBlock() instanceof SlabBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Despawn prevention ===
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean cannotDespawn() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canImmediatelyDespawn(double distanceSquared) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,115 @@
|
|||||||
|
package net.Chipperfluff.chipi.server;
|
||||||
|
|
||||||
|
import net.Chipperfluff.chipi.block.ChipperPortalBlock;
|
||||||
|
import net.Chipperfluff.chipi.world.gen.ChipiDungeonGenerator;
|
||||||
|
import net.Chipperfluff.chipi.SpawnPlacedState;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.registry.RegistryKey;
|
||||||
|
import net.minecraft.registry.RegistryKeys;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.structure.StructurePlacementData;
|
||||||
|
import net.minecraft.structure.StructureTemplate;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.GameRules;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public final class ChipiServerEvents {
|
||||||
|
|
||||||
|
public static final RegistryKey<World> CHIPI_DIMENSION_KEY =
|
||||||
|
RegistryKey.of(RegistryKeys.WORLD, new Identifier("chipi", "chipi_dimension"));
|
||||||
|
|
||||||
|
private static final Identifier SPAWN_STRUCTURE =
|
||||||
|
new Identifier("chipi", "spawn");
|
||||||
|
|
||||||
|
private static MinecraftServer SERVER;
|
||||||
|
|
||||||
|
private ChipiServerEvents() {}
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
|
||||||
|
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
|
||||||
|
SERVER = server;
|
||||||
|
});
|
||||||
|
|
||||||
|
ServerTickEvents.END_WORLD_TICK.register(ChipiServerEvents::handleVoidFailsafe);
|
||||||
|
|
||||||
|
ServerWorldEvents.LOAD.register(ChipiServerEvents::onWorldLoad);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Tick logic
|
||||||
|
// ============================================================
|
||||||
|
private static void handleVoidFailsafe(ServerWorld world) {
|
||||||
|
if (!world.getRegistryKey().equals(CHIPI_DIMENSION_KEY)) return;
|
||||||
|
|
||||||
|
for (PlayerEntity player : world.getPlayers()) {
|
||||||
|
if (player.getBlockY() >= 50) continue;
|
||||||
|
ChipperPortalBlock.teleportToChipiSpawn(world, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// World init
|
||||||
|
// ============================================================
|
||||||
|
private static void onWorldLoad(MinecraftServer server, ServerWorld world) {
|
||||||
|
if (!world.getRegistryKey().equals(CHIPI_DIMENSION_KEY)) return;
|
||||||
|
|
||||||
|
world.setTimeOfDay(18000);
|
||||||
|
world.getGameRules()
|
||||||
|
.get(GameRules.DO_DAYLIGHT_CYCLE)
|
||||||
|
.set(false, server);
|
||||||
|
|
||||||
|
SpawnPlacedState state = world.getPersistentStateManager().getOrCreate(
|
||||||
|
SpawnPlacedState::fromNbt,
|
||||||
|
SpawnPlacedState::new,
|
||||||
|
"chipi_spawn"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (state.placed) return;
|
||||||
|
|
||||||
|
StructureTemplate spawnTemplate =
|
||||||
|
world.getStructureTemplateManager()
|
||||||
|
.getTemplate(SPAWN_STRUCTURE)
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (spawnTemplate == null) {
|
||||||
|
System.err.println("[CHIPI] spawn.nbt not found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPos spawnCenter = new BlockPos(0, 80, 0);
|
||||||
|
|
||||||
|
spawnTemplate.place(
|
||||||
|
world,
|
||||||
|
spawnCenter,
|
||||||
|
spawnCenter,
|
||||||
|
new StructurePlacementData(),
|
||||||
|
world.getRandom(),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
|
||||||
|
world.setSpawnPos(spawnCenter.up(), 0.0f);
|
||||||
|
|
||||||
|
ChipiDungeonGenerator.generateInitialLayout(world, spawnCenter);
|
||||||
|
|
||||||
|
state.placed = true;
|
||||||
|
state.markDirty();
|
||||||
|
|
||||||
|
System.out.println("[CHIPI] Spawn + initial dungeon generated");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Access
|
||||||
|
// ============================================================
|
||||||
|
public static ServerWorld getChipiWorld() {
|
||||||
|
if (SERVER == null) return null;
|
||||||
|
return SERVER.getWorld(CHIPI_DIMENSION_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
"effect.chipi.chipi_blessing": "Chipi's Blessing",
|
"effect.chipi.chipi_blessing": "Chipi's Blessing",
|
||||||
|
|
||||||
|
"entity.chipi.mep": "Merp :3",
|
||||||
|
|
||||||
"block.chipi.void_block": "Void Block",
|
"block.chipi.void_block": "Void Block",
|
||||||
"block.chipi.chipper_frame": "Chipper Frame",
|
"block.chipi.chipper_frame": "Chipper Frame",
|
||||||
"block.chipi.chipper_portal": "Chipper Portal",
|
"block.chipi.chipper_portal": "Chipper Portal",
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"downfall": 0,
|
"downfall": 0,
|
||||||
"has_precipitation": false,
|
"has_precipitation": false,
|
||||||
"temperature_modifier": "frozen",
|
"temperature_modifier": "frozen",
|
||||||
"creature_spawn_probability": 0,
|
"creature_spawn_probability": 0.1,
|
||||||
"effects": {
|
"effects": {
|
||||||
"sky_color": 0,
|
"sky_color": 0,
|
||||||
"fog_color": 0,
|
"fog_color": 0,
|
||||||
@ -13,7 +13,15 @@
|
|||||||
"foliage_color": 0,
|
"foliage_color": 0,
|
||||||
"grass_color_modifier": "none"
|
"grass_color_modifier": "none"
|
||||||
},
|
},
|
||||||
"spawners": {},
|
"spawners": {
|
||||||
|
"monster": [],
|
||||||
|
"creature": [],
|
||||||
|
"ambient": [],
|
||||||
|
"axolotls": [],
|
||||||
|
"underground_water_creature": [],
|
||||||
|
"water_creature": [],
|
||||||
|
"water_ambient": []
|
||||||
|
},
|
||||||
"spawn_costs": {},
|
"spawn_costs": {},
|
||||||
"carvers": {},
|
"carvers": {},
|
||||||
"features": []
|
"features": []
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user