263 lines
12 KiB
Java
263 lines
12 KiB
Java
/*
|
|
* Ex Deorum
|
|
* Copyright (c) 2024 thedarkcolour
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package thedarkcolour.exdeorum.event;
|
|
|
|
import net.minecraft.Util;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.registries.Registries;
|
|
import net.minecraft.data.worldgen.features.TreeFeatures;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.resources.ResourceKey;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.server.level.ServerPlayer;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.util.Unit;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.level.GameRules;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.levelgen.Heightmap;
|
|
import net.minecraft.world.level.levelgen.XoroshiroRandomSource;
|
|
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
|
|
import net.minecraftforge.api.distmarker.Dist;
|
|
import net.minecraftforge.client.event.ClientChatEvent;
|
|
import net.minecraftforge.common.ForgeMod;
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.event.AddReloadListenerEvent;
|
|
import net.minecraftforge.event.OnDatapackSyncEvent;
|
|
import net.minecraftforge.event.TickEvent;
|
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
|
import net.minecraftforge.event.level.LevelEvent;
|
|
import net.minecraftforge.event.server.ServerStoppingEvent;
|
|
import net.minecraftforge.fluids.FluidInteractionRegistry;
|
|
import net.minecraftforge.fml.DistExecutor;
|
|
import net.minecraftforge.fml.InterModComms;
|
|
import net.minecraftforge.fml.ModList;
|
|
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
|
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
|
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
|
import net.minecraftforge.fml.loading.FMLEnvironment;
|
|
import thedarkcolour.exdeorum.ExDeorum;
|
|
import thedarkcolour.exdeorum.blockentity.helper.ItemHelper;
|
|
import thedarkcolour.exdeorum.client.CompostColors;
|
|
import thedarkcolour.exdeorum.compat.ModIds;
|
|
import thedarkcolour.exdeorum.compat.top.ExDeorumTopCompat;
|
|
import thedarkcolour.exdeorum.config.EConfig;
|
|
import thedarkcolour.exdeorum.item.WateringCanItem;
|
|
import thedarkcolour.exdeorum.network.NetworkHandler;
|
|
import thedarkcolour.exdeorum.network.VisualUpdateTracker;
|
|
import thedarkcolour.exdeorum.recipe.RecipeUtil;
|
|
import thedarkcolour.exdeorum.registry.EFluids;
|
|
import thedarkcolour.exdeorum.registry.EItems;
|
|
import thedarkcolour.exdeorum.tag.EBiomeTags;
|
|
import thedarkcolour.exdeorum.voidworld.VoidChunkGenerator;
|
|
|
|
import java.util.HashSet;
|
|
import java.util.Locale;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
|
|
public final class EventHandler {
|
|
public static void register() {
|
|
var fmlBus = MinecraftForge.EVENT_BUS;
|
|
var modBus = FMLJavaModLoadingContext.get().getModEventBus();
|
|
|
|
fmlBus.addListener(EventHandler::onPlayerLogin);
|
|
fmlBus.addListener(EventHandler::onDataSynced);
|
|
fmlBus.addListener(EventHandler::addReloadListeners);
|
|
fmlBus.addListener(EventHandler::createSpawnTree);
|
|
modBus.addListener(EventHandler::interModEnqueue);
|
|
modBus.addListener(EventHandler::onCommonSetup);
|
|
fmlBus.addListener(EventHandler::serverShutdown);
|
|
fmlBus.addListener(EventHandler::serverTick);
|
|
|
|
if (ExDeorum.DEBUG) {
|
|
fmlBus.addListener(EventHandler::handleDebugCommands);
|
|
}
|
|
}
|
|
|
|
private static void serverShutdown(ServerStoppingEvent event) {
|
|
RecipeUtil.unload();
|
|
}
|
|
|
|
private static void handleDebugCommands(ClientChatEvent event) {
|
|
if (event.getMessage().equals(".compost_colors")) {
|
|
event.setCanceled(true);
|
|
|
|
try {
|
|
CompostColors.loadColors();
|
|
var player = Minecraft.getInstance().player;
|
|
if (player != null) {
|
|
player.displayClientMessage(Component.literal("Reloaded " + CompostColors.COLORS.size() + " compost colors!"), false);
|
|
}
|
|
} catch (Exception e) {
|
|
ExDeorum.LOGGER.error("Failed to load vanilla compost colors", e);
|
|
}
|
|
} else if (event.getMessage().equals(".breakpoint")) {
|
|
event.setCanceled(true);
|
|
}
|
|
}
|
|
|
|
private static void createSpawnTree(LevelEvent.CreateSpawnPosition event) {
|
|
if (event.getLevel() instanceof ServerLevel level && level.getChunkSource().getGenerator() instanceof VoidChunkGenerator) {
|
|
var rand = new XoroshiroRandomSource(level.getSeed());
|
|
var pos = new BlockPos.MutableBlockPos(rand.nextIntBetweenInclusive(-200, 200), 64, rand.nextIntBetweenInclusive(-200, 200));
|
|
level.setBlock(pos, Blocks.DIRT.defaultBlockState(), 2);
|
|
pos.move(0, 1, 0);
|
|
|
|
// grow tree, has 5% chance to spawn bees based on world seed
|
|
var configuredFeatureRegistry = level.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE);
|
|
var defaultTreeFeature = TreeFeatures.OAK_BEES_005;
|
|
var defaultTreeFeatureLoc = ResourceLocation.tryParse(EConfig.SERVER.defaultSpawnTreeFeature.get());
|
|
|
|
Holder<ConfiguredFeature<?, ?>> holder = configuredFeatureRegistry.getHolder(defaultTreeFeature).orElse(null);
|
|
|
|
if (defaultTreeFeatureLoc != null) {
|
|
var value = configuredFeatureRegistry.getHolder(ResourceKey.create(Registries.CONFIGURED_FEATURE, defaultTreeFeatureLoc)).orElse(null);
|
|
if (value != null) {
|
|
holder = value;
|
|
}
|
|
}
|
|
|
|
if (EConfig.SERVER.useBiomeAppropriateTree.get()) {
|
|
var biome = level.getBiome(pos);
|
|
|
|
for (var entry : EBiomeTags.TREE_TAGS.entrySet()) {
|
|
if (biome.is(entry.getKey())) {
|
|
var optional = entry.getValue().getHolder();
|
|
|
|
if (optional.isPresent()) {
|
|
holder = (optional.get());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (holder == null || !holder.value().place(level, level.getChunkSource().getGenerator(), rand, pos)) {
|
|
ExDeorum.LOGGER.error("Failed to generate spawn tree :(");
|
|
} else {
|
|
ExDeorum.LOGGER.debug("Generated spawn tree at {}", pos);
|
|
}
|
|
|
|
event.setCanceled(true);
|
|
event.getSettings().setSpawn(level.getHeightmapPos(Heightmap.Types.WORLD_SURFACE_WG, pos), 90.0F);
|
|
level.getGameRules().getRule(GameRules.RULE_SPAWN_RADIUS).set(0, level.getServer());
|
|
}
|
|
}
|
|
|
|
private static void onCommonSetup(FMLCommonSetupEvent event) {
|
|
event.enqueueWork(() -> {
|
|
FluidInteractionRegistry.addInteraction(ForgeMod.LAVA_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
|
|
EFluids.WITCH_WATER_TYPE.get(),
|
|
fluidState -> fluidState.isSource() ? Blocks.OBSIDIAN.defaultBlockState() : (EConfig.SERVER.witchWaterNetherrackGenerator.get() ? Blocks.NETHERRACK.defaultBlockState() : Blocks.COBBLESTONE.defaultBlockState())
|
|
));
|
|
var dirtVariants = new BlockState[]{Blocks.DIRT.defaultBlockState(), Blocks.PODZOL.defaultBlockState(), Blocks.COARSE_DIRT.defaultBlockState()};
|
|
var rng = RandomSource.create();
|
|
FluidInteractionRegistry.addInteraction(EFluids.WITCH_WATER_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
|
|
(level, pos, relative, state) -> level.getFluidState(relative).getFluidType() == ForgeMod.WATER_TYPE.get() && EConfig.SERVER.witchWaterDirtGenerator.get(),
|
|
fluidState -> Util.getRandom(dirtVariants, rng)
|
|
));
|
|
});
|
|
}
|
|
|
|
private static void onDataSynced(OnDatapackSyncEvent event) {
|
|
UUID excludedUUID = null;
|
|
|
|
if (FMLEnvironment.dist == Dist.CLIENT) {
|
|
// since event code is turned into ASM, we need this to prevent ASM trying to load the LocalPlayer class
|
|
Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> ClientsideCode::getLocalPlayer);
|
|
if (player == null) {
|
|
return;
|
|
} else {
|
|
excludedUUID = player.getUUID();
|
|
}
|
|
}
|
|
|
|
// A player who is first connecting isn't yet included in the server's player list, so include them.
|
|
Set<ServerPlayer> players = new HashSet<>(event.getPlayerList().getPlayers());
|
|
if (event.getPlayer() != null) {
|
|
players.add(event.getPlayer());
|
|
}
|
|
|
|
for (var player : players) {
|
|
if (!player.getUUID().equals(excludedUUID)) {
|
|
NetworkHandler.sendRecipeCacheReset(player);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) {
|
|
if (event.getEntity() instanceof ServerPlayer player) {
|
|
var generator = player.serverLevel().getChunkSource().getGenerator();
|
|
|
|
// tries to account for other SkyBlock generator mods like SkyBlockBuilder
|
|
if (generator instanceof VoidChunkGenerator || generator.getClass().getName().toLowerCase(Locale.ROOT).contains("skyblock")) {
|
|
NetworkHandler.sendVoidWorld(player);
|
|
var advancement = player.server.getAdvancements().getAdvancement(new ResourceLocation(ExDeorum.ID, "core/root"));
|
|
|
|
if (advancement != null) {
|
|
if (!player.getAdvancements().getOrStartProgress(advancement).isDone()) {
|
|
player.getAdvancements().award(advancement, "in_void_world");
|
|
if (EConfig.SERVER.startingTorch.get()) {
|
|
player.getInventory().add(new ItemStack(Items.TORCH));
|
|
}
|
|
if (EConfig.SERVER.startingWateringCan.get()) {
|
|
player.getInventory().add(WateringCanItem.getFull(EItems.WOODEN_WATERING_CAN));
|
|
}
|
|
}
|
|
} else {
|
|
ExDeorum.LOGGER.error("Unable to grant player the Void World advancement. Ex Deorum advancements will not show");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Send messages to other mods
|
|
private static void interModEnqueue(InterModEnqueueEvent event) {
|
|
if (ModList.get().isLoaded(ModIds.THE_ONE_PROBE)) {
|
|
InterModComms.sendTo(ModIds.THE_ONE_PROBE, "getTheOneProbe", ExDeorumTopCompat::new);
|
|
}
|
|
if (ModList.get().isLoaded(ModIds.INVENTORY_SORTER)) {
|
|
InterModComms.sendTo(ModIds.INVENTORY_SORTER, "slotblacklist", ItemHelper.Slot.class::getName);
|
|
}
|
|
}
|
|
|
|
private static void addReloadListeners(AddReloadListenerEvent event) {
|
|
var recipes = event.getServerResources().getRecipeManager();
|
|
event.addListener((prepBarrier, resourceManager, prepProfiler, reloadProfiler, backgroundExecutor, gameExecutor) -> {
|
|
return prepBarrier.wait(Unit.INSTANCE).thenRunAsync(() -> {
|
|
RecipeUtil.reload(recipes);
|
|
}, gameExecutor);
|
|
});
|
|
}
|
|
|
|
private static void serverTick(TickEvent.ServerTickEvent event) {
|
|
if (event.phase == TickEvent.Phase.END) {
|
|
VisualUpdateTracker.syncVisualUpdates();
|
|
}
|
|
}
|
|
}
|