*WIP*: Merge commit 'ce4cb8974f
' into 1.18
This commit is contained in:
commit
c6a7a1d4f7
76 changed files with 2754 additions and 738 deletions
|
@ -13,7 +13,6 @@ import ru.bclib.api.dataexchange.handler.autosync.HelloClient;
|
|||
import ru.bclib.api.dataexchange.handler.autosync.HelloServer;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.RequestFiles;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.SendFiles;
|
||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||
import ru.bclib.config.Configs;
|
||||
import ru.bclib.recipes.CraftingRecipes;
|
||||
import ru.bclib.registry.BaseBlockEntities;
|
||||
|
@ -53,8 +52,7 @@ public class BCLib implements ModInitializer {
|
|||
Chunker.DESCRIPTOR
|
||||
));
|
||||
|
||||
DataFixerAPI.registerPatch(() -> new BCLibPatch());
|
||||
|
||||
BCLibPatch.register();
|
||||
Configs.save();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,23 @@
|
|||
package ru.bclib;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import ru.bclib.api.datafixer.DataFixerAPI;
|
||||
import ru.bclib.api.datafixer.Patch;
|
||||
import ru.bclib.api.datafixer.PatchFunction;
|
||||
|
||||
public final class BCLibPatch extends Patch {
|
||||
|
||||
|
||||
public final class BCLibPatch {
|
||||
public static void register(){
|
||||
DataFixerAPI.registerPatch(BiomeSourcePatch::new);
|
||||
}
|
||||
}
|
||||
|
||||
final class BiomeSourcePatch extends Patch {
|
||||
private static final String NETHER_BIOME_SOURCE = "bclib:nether_biome_source";
|
||||
private static final String END_BIOME_SOURCE = "bclib:end_biome_source";
|
||||
|
||||
protected BCLibPatch() {
|
||||
protected BiomeSourcePatch() {
|
||||
super(BCLib.MOD_ID, "0.4.0");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +1,42 @@
|
|||
package ru.bclib.api;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.biome.v1.NetherBiomes;
|
||||
import net.fabricmc.fabric.impl.biome.NetherBiomeData;
|
||||
import net.fabricmc.fabric.impl.biome.TheEndBiomeData;
|
||||
import net.fabricmc.fabric.impl.biome.InternalBiomeData;
|
||||
import net.fabricmc.fabric.mixin.biome.modification.GenerationSettingsAccessor;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.data.BuiltinRegistries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.Biome.ClimateParameters;
|
||||
import net.minecraft.world.level.biome.BiomeSource;
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
import net.minecraft.world.level.biome.Climate;
|
||||
import net.minecraft.world.level.levelgen.GenerationStep.Decoration;
|
||||
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.bclib.util.MHelper;
|
||||
import ru.bclib.world.biomes.BCLBiome;
|
||||
import ru.bclib.world.biomes.FabricBiomesData;
|
||||
import ru.bclib.world.features.BCLFeature;
|
||||
import ru.bclib.world.generator.BiomePicker;
|
||||
import ru.bclib.world.structures.BCLStructureFeature;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class BiomeAPI {
|
||||
/**
|
||||
|
@ -39,6 +53,9 @@ public class BiomeAPI {
|
|||
private static final Map<Biome, BCLBiome> CLIENT = Maps.newHashMap();
|
||||
private static Registry<Biome> biomeRegistry;
|
||||
|
||||
private static final Map<ResourceKey, List<BiConsumer<ResourceLocation, Biome>>> MODIFICATIONS = Maps.newHashMap();
|
||||
private static final Set<ResourceLocation> MODIFIED_BIOMES = Sets.newHashSet();
|
||||
|
||||
public static final BCLBiome NETHER_WASTES_BIOME = registerNetherBiome(getFromRegistry(Biomes.NETHER_WASTES));
|
||||
public static final BCLBiome CRIMSON_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.CRIMSON_FOREST));
|
||||
public static final BCLBiome WARPED_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.WARPED_FOREST));
|
||||
|
@ -325,4 +342,143 @@ public class BiomeAPI {
|
|||
private static boolean pickerHasBiome(BiomePicker picker, ResourceLocation key) {
|
||||
return picker.getBiomes().stream().filter(biome -> biome.getID().equals(key)).findFirst().isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers new biome modification for specified dimension. Will work both for mod and datapack biomes.
|
||||
* @param dimensionID {@link ResourceLocation} dimension ID, example: Level.OVERWORLD or "minecraft:overworld".
|
||||
* @param modification {@link BiConsumer} with {@link ResourceKey} biome ID and {@link Biome} parameters.
|
||||
*/
|
||||
public static void registerBiomeModification(ResourceKey dimensionID, BiConsumer<ResourceLocation, Biome> modification) {
|
||||
List<BiConsumer<ResourceLocation, Biome>> modifications = MODIFICATIONS.get(dimensionID);
|
||||
if (modifications == null) {
|
||||
modifications = Lists.newArrayList();
|
||||
MODIFICATIONS.put(dimensionID, modifications);
|
||||
}
|
||||
modifications.add(modification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers new biome modification for the Overworld. Will work both for mod and datapack biomes.
|
||||
* @param modification {@link BiConsumer} with {@link ResourceLocation} biome ID and {@link Biome} parameters.
|
||||
*/
|
||||
public static void registerOverworldBiomeModification(BiConsumer<ResourceLocation, Biome> modification) {
|
||||
registerBiomeModification(Level.OVERWORLD, modification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers new biome modification for the Nether. Will work both for mod and datapack biomes.
|
||||
* @param modification {@link BiConsumer} with {@link ResourceLocation} biome ID and {@link Biome} parameters.
|
||||
*/
|
||||
public static void registerNetherBiomeModification(BiConsumer<ResourceLocation, Biome> modification) {
|
||||
registerBiomeModification(Level.NETHER, modification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers new biome modification for the End. Will work both for mod and datapack biomes.
|
||||
* @param modification {@link BiConsumer} with {@link ResourceLocation} biome ID and {@link Biome} parameters.
|
||||
*/
|
||||
public static void registerEndBiomeModification(BiConsumer<ResourceLocation, Biome> modification) {
|
||||
registerBiomeModification(Level.END, modification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will apply biome modifications to world, internal usage only.
|
||||
* @param level
|
||||
*/
|
||||
public static void applyModifications(ServerLevel level) {
|
||||
List<BiConsumer<ResourceLocation, Biome>> modifications = MODIFICATIONS.get(level.dimension());
|
||||
if (modifications == null) {
|
||||
return;
|
||||
}
|
||||
BiomeSource source = level.getChunkSource().getGenerator().getBiomeSource();
|
||||
List<Biome> biomes = source.possibleBiomes();
|
||||
|
||||
biomes.forEach(biome -> {
|
||||
ResourceLocation biomeID = getBiomeID(biome);
|
||||
boolean modify = isDatapackBiome(biomeID);
|
||||
if (!modify && !MODIFIED_BIOMES.contains(biomeID)) {
|
||||
MODIFIED_BIOMES.add(biomeID);
|
||||
modify = true;
|
||||
}
|
||||
if (modify) {
|
||||
modifications.forEach(consumer -> {
|
||||
consumer.accept(biomeID, biome);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new features to existing biome.
|
||||
* @param biome {@link Biome} to add features in.
|
||||
* @param feature {@link ConfiguredFeature} to add.
|
||||
* @param step a {@link Decoration} step for the feature.
|
||||
*/
|
||||
public static void addBiomeFeature(Biome biome, ConfiguredFeature feature, Decoration step) {
|
||||
GenerationSettingsAccessor accessor = (GenerationSettingsAccessor) biome.getGenerationSettings();
|
||||
List<List<Supplier<ConfiguredFeature<?, ?>>>> biomeFeatures = getMutableList(accessor.fabric_getFeatures());
|
||||
int index = step.ordinal();
|
||||
if (biomeFeatures.size() < index) {
|
||||
for (int i = biomeFeatures.size(); i <= index; i++) {
|
||||
biomeFeatures.add(Lists.newArrayList());
|
||||
}
|
||||
}
|
||||
List<Supplier<ConfiguredFeature<?, ?>>> list = getMutableList(biomeFeatures.get(index));
|
||||
list.add(() -> feature);
|
||||
accessor.fabric_setFeatures(biomeFeatures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new features to existing biome.
|
||||
* @param biome {@link Biome} to add features in.
|
||||
* @param features array of {@link BCLFeature} to add.
|
||||
*/
|
||||
public static void addBiomeFeatures(Biome biome, BCLFeature... features) {
|
||||
GenerationSettingsAccessor accessor = (GenerationSettingsAccessor) biome.getGenerationSettings();
|
||||
List<List<Supplier<ConfiguredFeature<?, ?>>>> biomeFeatures = getMutableList(accessor.fabric_getFeatures());
|
||||
for (BCLFeature feature: features) {
|
||||
int index = feature.getFeatureStep().ordinal();
|
||||
if (biomeFeatures.size() < index) {
|
||||
for (int i = biomeFeatures.size(); i <= index; i++) {
|
||||
biomeFeatures.add(Lists.newArrayList());
|
||||
}
|
||||
}
|
||||
List<Supplier<ConfiguredFeature<?, ?>>> list = getMutableList(biomeFeatures.get(index));
|
||||
list.add(feature::getFeatureConfigured);
|
||||
}
|
||||
accessor.fabric_setFeatures(biomeFeatures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new structure feature to existing biome.
|
||||
* @param biome {@link Biome} to add structure feature in.
|
||||
* @param structure {@link ConfiguredStructureFeature} to add.
|
||||
*/
|
||||
public static void addBiomeStructure(Biome biome, ConfiguredStructureFeature structure) {
|
||||
GenerationSettingsAccessor accessor = (GenerationSettingsAccessor) biome.getGenerationSettings();
|
||||
List<Supplier<ConfiguredStructureFeature<?, ?>>> biomeStructures = getMutableList(accessor.fabric_getStructureFeatures());
|
||||
biomeStructures.add(() -> structure);
|
||||
accessor.fabric_setStructureFeatures(biomeStructures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new structure features to existing biome.
|
||||
* @param biome {@link Biome} to add structure features in.
|
||||
* @param structures array of {@link BCLStructureFeature} to add.
|
||||
*/
|
||||
public static void addBiomeStructures(Biome biome, BCLStructureFeature... structures) {
|
||||
GenerationSettingsAccessor accessor = (GenerationSettingsAccessor) biome.getGenerationSettings();
|
||||
List<Supplier<ConfiguredStructureFeature<?, ?>>> biomeStructures = getMutableList(accessor.fabric_getStructureFeatures());
|
||||
for (BCLStructureFeature structure: structures) {
|
||||
biomeStructures.add(structure::getFeatureConfigured);
|
||||
}
|
||||
accessor.fabric_setStructureFeatures(biomeStructures);
|
||||
}
|
||||
|
||||
private static <T extends Object> List<T> getMutableList(List<T> input) {
|
||||
if (input instanceof ImmutableList) {
|
||||
return Lists.newArrayList(input);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,16 @@ public class TagAPI {
|
|||
public static final Tag.Named<Block> BLOCK_END_GROUND = makeBlockTag(BCLib.MOD_ID, "end_ground");
|
||||
|
||||
public static final Tag.Named<Block> BLOCK_CHEST = makeCommonBlockTag("chest");
|
||||
public static final Tag.Named<Block> BLOCK_WOODEN_CHEST = makeCommonBlockTag("wooden_chests");
|
||||
public static final Tag.Named<Block> BLOCK_BARREL = makeCommonBlockTag("barrel");
|
||||
public static final Tag.Named<Block> BLOCK_WOODEN_BARREL = makeCommonBlockTag("wooden_barrels");
|
||||
public static final Tag.Named<Block> BLOCK_END_STONES = makeCommonBlockTag("end_stones");
|
||||
public static final Tag.Named<Block> BLOCK_NETHER_STONES = makeCommonBlockTag("nether_stones");
|
||||
public static final Tag.Named<Block> BLOCK_WORKBENCHES = makeCommonBlockTag("workbenches");
|
||||
public static final Tag.Named<Block> BLOCK_NETHER_PORTAL_FRAME = makeCommonBlockTag("nether_pframe");
|
||||
public static final Tag.Named<Block> BLOCK_WORKBENCHES = makeCommonBlockTag("workbench");
|
||||
public static final Tag.Named<Block> BLOCK_SAPLINGS = makeCommonBlockTag("saplings");
|
||||
public static final Tag.Named<Block> BLOCK_LEAVES = makeCommonBlockTag("leaves");
|
||||
public static final Tag.Named<Block> BLOCK_IMMOBILE = makeCommonBlockTag("immobile");
|
||||
|
||||
public static final Tag.Named<Block> BLOCK_DRAGON_IMMUNE = getMCBlockTag("dragon_immune");
|
||||
|
||||
|
@ -47,11 +54,19 @@ public class TagAPI {
|
|||
|
||||
// Item Tags
|
||||
public static final Tag.Named<Item> ITEM_CHEST = makeCommonItemTag("chest");
|
||||
public static final Tag.Named<Item> ITEM_WOODEN_CHEST = makeCommonItemTag("wooden_chests");
|
||||
public static final Tag.Named<Item> ITEM_BARREL = makeCommonItemTag("barrel");
|
||||
public static final Tag.Named<Item> ITEM_WOODEN_BARREL = makeCommonItemTag("wooden_barrels");
|
||||
public static final Tag.Named<Item> ITEM_IRON_INGOTS = makeCommonItemTag("iron_ingots");
|
||||
public static final Tag.Named<Item> ITEM_FURNACES = makeCommonItemTag("furnaces");
|
||||
public static final Tag.Named<Item> ITEM_WORKBENCHES = makeCommonItemTag("workbenches");
|
||||
public static final Tag.Named<Item> ITEM_WORKBENCHES = makeCommonItemTag("workbench");
|
||||
public final static Tag.Named<Item> ITEM_HAMMERS = makeCommonItemTag("hammers");
|
||||
|
||||
public static final Tag.Named<Item> ITEM_SAPLINGS = makeCommonItemTag("saplings");
|
||||
public static final Tag.Named<Item> ITEM_LEAVES = makeCommonItemTag("leaves");
|
||||
public static final Tag.Named<Item> ITEM_SHEARS = getMCItemTag("shears");
|
||||
public static final Tag.Named<Item> ITEM_COMMON_SHEARS = makeCommonItemTag("shears");
|
||||
|
||||
|
||||
/**
|
||||
* Get or create {@link Tag.Named}.
|
||||
*
|
||||
|
@ -122,6 +137,18 @@ public class TagAPI {
|
|||
return tag == null ? (Named<Block>) TagFactory.BLOCK.create(id): (Named<Block>) tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create Minecraft {@link Item} {@link Tag.Named}.
|
||||
*
|
||||
* @param name - {@link String} tag name.
|
||||
* @return {@link Item} {@link Tag.Named}.
|
||||
*/
|
||||
public static Tag.Named<Item> getMCItemTag(String name) {
|
||||
ResourceLocation id = new ResourceLocation(name);
|
||||
Tag<Item> tag = ItemTags.getAllTags().getTag(id);
|
||||
return tag == null ? (Named<Item>) TagRegistry.item(id) : (Named<Item>) tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@link Block} to NETHER_GROUND and GEN_TERRAIN tags to process it properly in terrain generators and block logic.
|
||||
*
|
||||
|
|
|
@ -135,7 +135,7 @@ public class AutoSync {
|
|||
}
|
||||
|
||||
private static boolean didRegisterAdditionalMods = false;
|
||||
//we call this from HelloClient on the Srérver to prepare transfer
|
||||
//we call this from HelloClient on the Server to prepare transfer
|
||||
protected static void loadSyncFolder() {
|
||||
if (Configs.SERVER_CONFIG.isOfferingFiles()) {
|
||||
syncFolderDescriptions.forEach(desc -> desc.loadCache());
|
||||
|
|
|
@ -4,10 +4,10 @@ import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
|||
import net.fabricmc.fabric.api.networking.v1.PacketSender;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.ProgressListener;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.ProgressListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.bclib.BCLib;
|
||||
|
|
|
@ -16,6 +16,7 @@ import ru.bclib.api.dataexchange.DataHandlerDescriptor;
|
|||
import ru.bclib.api.dataexchange.handler.autosync.AutoSyncID.WithContentOverride;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.SyncFolderDescriptor.SubFile;
|
||||
import ru.bclib.config.Configs;
|
||||
import ru.bclib.config.ServerConfig;
|
||||
import ru.bclib.gui.screens.ModListScreen;
|
||||
import ru.bclib.gui.screens.ProgressScreen;
|
||||
import ru.bclib.gui.screens.SyncFilesScreen;
|
||||
|
@ -91,6 +92,11 @@ public class HelloClient extends DataHandler.FromServer {
|
|||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
mods = mods
|
||||
.stream()
|
||||
.filter(entry -> !Configs.SERVER_CONFIG.get(ServerConfig.EXCLUDED_MODS).contains(entry))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
//write Plugin Versions
|
||||
buf.writeInt(mods.size());
|
||||
|
@ -394,6 +400,9 @@ public class HelloClient extends DataHandler.FromServer {
|
|||
requestBCLibDownload();
|
||||
|
||||
this.onCloseSyncFilesScreen();
|
||||
} else {
|
||||
Minecraft.getInstance()
|
||||
.setScreen(null);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ import ru.bclib.api.WorldDataAPI;
|
|||
import ru.bclib.config.Configs;
|
||||
import ru.bclib.gui.screens.AtomicProgressListener;
|
||||
import ru.bclib.gui.screens.ConfirmFixScreen;
|
||||
import ru.bclib.gui.screens.LevelFixErrorScreen;
|
||||
import ru.bclib.gui.screens.LevelFixErrorScreen.Listener;
|
||||
import ru.bclib.gui.screens.ProgressScreen;
|
||||
import ru.bclib.util.Logger;
|
||||
|
||||
|
@ -39,6 +41,7 @@ import java.util.function.BiConsumer;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
/**
|
||||
* API to manage Patches that need to get applied to a world
|
||||
|
@ -47,6 +50,24 @@ public class DataFixerAPI {
|
|||
static final Logger LOGGER = new Logger("DataFixerAPI");
|
||||
static class State {
|
||||
public boolean didFail = false;
|
||||
protected ArrayList<String> errors = new ArrayList<>();
|
||||
|
||||
public void addError(String s){
|
||||
errors.add(s);
|
||||
}
|
||||
|
||||
public boolean hasError(){
|
||||
return errors.size()>0;
|
||||
}
|
||||
|
||||
public String getErrorMessage(){
|
||||
return errors.stream().reduce("", (a, b) -> a + " - " + b + "\n");
|
||||
}
|
||||
|
||||
public String[] getErrorMessages(){
|
||||
String[] res = new String[errors.size()];
|
||||
return errors.toArray(res);
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
|
@ -200,30 +221,48 @@ public class DataFixerAPI {
|
|||
progress = null;
|
||||
}
|
||||
|
||||
Runnable runner = () -> {
|
||||
Supplier<State> runner = () -> {
|
||||
if (createBackup) {
|
||||
progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.waitbackup"));
|
||||
EditWorldScreen.makeBackupAndShowToast(Minecraft.getInstance().getLevelSource(), levelID);
|
||||
}
|
||||
|
||||
if (applyFixes) {
|
||||
runDataFixes(dir, profile, progress);
|
||||
return runDataFixes(dir, profile, progress);
|
||||
}
|
||||
|
||||
return new State();
|
||||
};
|
||||
|
||||
if (showUI) {
|
||||
Thread fixerThread = new Thread(() -> {
|
||||
runner.run();
|
||||
|
||||
Minecraft.getInstance().execute(() -> {
|
||||
if (profile != null && showUI) {
|
||||
onResume.accept(applyFixes);
|
||||
}
|
||||
});
|
||||
final State state = runner.get();
|
||||
|
||||
Minecraft.getInstance()
|
||||
.execute(() -> {
|
||||
if (profile != null && showUI) {
|
||||
//something went wrong, show the user our error
|
||||
if (state.didFail || state.hasError()){
|
||||
showLevelFixErrorScreen(state, (markFixed)->{
|
||||
if (markFixed) {
|
||||
profile.markApplied();
|
||||
}
|
||||
onResume.accept(applyFixes);
|
||||
});
|
||||
} else {
|
||||
onResume.accept(applyFixes);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
fixerThread.start();
|
||||
} else {
|
||||
runner.run();
|
||||
State state = runner.get();
|
||||
if (state.hasError()){
|
||||
LOGGER.error("There were Errors while fixing the Level:");
|
||||
LOGGER.error(state.getErrorMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -240,6 +279,11 @@ public class DataFixerAPI {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
@Environment(EnvType.CLIENT)
|
||||
private static void showLevelFixErrorScreen(State state, Listener onContinue){
|
||||
Minecraft.getInstance()
|
||||
.setScreen(new LevelFixErrorScreen(Minecraft.getInstance().screen, state.getErrorMessages(), onContinue));
|
||||
}
|
||||
|
||||
private static MigrationProfile loadProfileIfNeeded(File levelBaseDir){
|
||||
if (!Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_PATCH_CATEGORY, "applyPatches", true)) {
|
||||
|
@ -270,7 +314,7 @@ public class DataFixerAPI {
|
|||
Minecraft.getInstance().setScreen(new ConfirmFixScreen((Screen) null, whenFinished::accept));
|
||||
}
|
||||
|
||||
private static void runDataFixes(File dir, MigrationProfile profile, AtomicProgressListener progress) {
|
||||
private static State runDataFixes(File dir, MigrationProfile profile, AtomicProgressListener progress) {
|
||||
State state = new State();
|
||||
progress.resetAtomic();
|
||||
|
||||
|
@ -295,6 +339,7 @@ public class DataFixerAPI {
|
|||
profile.patchWorldData();
|
||||
} catch (PatchDidiFailException e){
|
||||
state.didFail = true;
|
||||
state.addError("Failed fixing worldconfig (" + e.getMessage() + ")");
|
||||
BCLib.LOGGER.error(e.getMessage());
|
||||
}
|
||||
progress.incAtomic(maxProgress);
|
||||
|
@ -313,6 +358,8 @@ public class DataFixerAPI {
|
|||
progress.incAtomic(maxProgress);
|
||||
|
||||
progress.stop();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private static void fixLevel(MigrationProfile profile, State state, File levelBaseDir) {
|
||||
|
@ -342,15 +389,17 @@ public class DataFixerAPI {
|
|||
}
|
||||
catch (Exception e) {
|
||||
BCLib.LOGGER.error("Failed fixing Level-Data.");
|
||||
state.addError("Failed fixing Level-Data in level.dat (" + e.getMessage() + ")");
|
||||
state.didFail = true;
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void fixPlayer(MigrationProfile data, State state, File file) {
|
||||
try {
|
||||
LOGGER.info("Inspecting " + file);
|
||||
CompoundTag player = NbtIo.readCompressed(file);
|
||||
|
||||
CompoundTag player = readNbt(file);
|
||||
boolean[] changed = { false };
|
||||
fixPlayerNbt(player, changed, data);
|
||||
|
||||
|
@ -361,11 +410,12 @@ public class DataFixerAPI {
|
|||
}
|
||||
catch (Exception e) {
|
||||
BCLib.LOGGER.error("Failed fixing Player-Data.");
|
||||
state.addError("Failed fixing Player-Data in " + file.getName() + " (" + e.getMessage() + ")");
|
||||
state.didFail = true;
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void fixPlayerNbt(CompoundTag player, boolean[] changed, MigrationProfile data) {
|
||||
//Checking Inventory
|
||||
ListTag inventory = player.getList("Inventory", Tag.TAG_COMPOUND);
|
||||
|
@ -416,7 +466,7 @@ public class DataFixerAPI {
|
|||
for (int z = 0; z < 32; z++) {
|
||||
ChunkPos pos = new ChunkPos(x, z);
|
||||
changed[0] = false;
|
||||
if (region.hasChunk(pos)) {
|
||||
if (region.hasChunk(pos) && !state.didFail) {
|
||||
DataInputStream input = region.getChunkDataInputStream(pos);
|
||||
CompoundTag root = NbtIo.read(input);
|
||||
// if ((root.toString().contains("betternether:chest") || root.toString().contains("bclib:chest"))) {
|
||||
|
@ -442,6 +492,17 @@ public class DataFixerAPI {
|
|||
CompoundTag blockTagCompound = ((CompoundTag) blockTag);
|
||||
changed[0] |= data.replaceStringFromIDs(blockTagCompound, "Name");
|
||||
});
|
||||
|
||||
try {
|
||||
changed[0] |= data.patchBlockState(palette, ((CompoundTag) tag).getList("BlockStates", Tag.TAG_LONG));
|
||||
}
|
||||
catch (PatchDidiFailException e) {
|
||||
BCLib.LOGGER.error("Failed fixing BlockState in " + pos);
|
||||
state.addError("Failed fixing BlockState in " + pos + " (" + e.getMessage() + ")");
|
||||
state.didFail = true;
|
||||
changed[0] = false;
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
if (changed[0]) {
|
||||
|
@ -450,7 +511,6 @@ public class DataFixerAPI {
|
|||
DataOutputStream output = region.getChunkDataOutputStream(pos);
|
||||
NbtIo.write(root, output);
|
||||
output.close();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -458,12 +518,13 @@ public class DataFixerAPI {
|
|||
region.close();
|
||||
}
|
||||
catch (Exception e) {
|
||||
BCLib.LOGGER.error("Failed fixing Player Data.");
|
||||
BCLib.LOGGER.error("Failed fixing Region.");
|
||||
state.addError("Failed fixing Region in " + file.getName() + " (" + e.getMessage() + ")");
|
||||
state.didFail = true;
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static CompoundTag patchConfTag = null;
|
||||
static CompoundTag getPatchData(){
|
||||
if (patchConfTag==null) {
|
||||
|
@ -540,4 +601,12 @@ public class DataFixerAPI {
|
|||
Patch.getALL().add(patch.get());
|
||||
}
|
||||
|
||||
private static CompoundTag readNbt(File file) throws IOException {
|
||||
try {
|
||||
return NbtIo.readCompressed(file);
|
||||
} catch (ZipException e){
|
||||
return NbtIo.read(file);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
47
src/main/java/ru/bclib/api/datafixer/ForcedLevelPatch.java
Normal file
47
src/main/java/ru/bclib/api/datafixer/ForcedLevelPatch.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
package ru.bclib.api.datafixer;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* A Patch for level.dat that is always executed no matter what Patchlevel is set in a world.
|
||||
*/
|
||||
public abstract class ForcedLevelPatch extends Patch {
|
||||
protected ForcedLevelPatch(@NotNull String modID, String version) {
|
||||
super(modID, version, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Map<String, String> getIDReplacements() {
|
||||
return new HashMap<String, String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final PatchFunction<CompoundTag, Boolean> getWorldDataPatcher() { return null; }
|
||||
|
||||
@Override
|
||||
public final PatchBiFunction<ListTag, ListTag, Boolean> getBlockStatePatcher() { return null; }
|
||||
|
||||
@Override
|
||||
public final List<String> getWorldDataIDPaths() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PatchFunction<CompoundTag, Boolean> getLevelDatPatcher() { return this::runLevelDatPatch; }
|
||||
|
||||
/**
|
||||
* Called with the contents of level.dat in {@code root}
|
||||
* @param root The contents of level.dat
|
||||
* @param profile The active migration profile
|
||||
* @return true, if the run did change the contents of root
|
||||
*/
|
||||
abstract protected Boolean runLevelDatPatch(CompoundTag root, MigrationProfile profile);
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import ru.bclib.util.ModUtil;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
|
@ -23,6 +24,7 @@ public class MigrationProfile {
|
|||
final Set<String> mods;
|
||||
final Map<String, String> idReplacements;
|
||||
final List<PatchFunction<CompoundTag, Boolean>> levelPatchers;
|
||||
final List<PatchBiFunction<ListTag, ListTag, Boolean>> statePatchers;
|
||||
final List<Patch> worldDataPatchers;
|
||||
final Map<String, List<String>> worldDataIDPaths;
|
||||
|
||||
|
@ -33,7 +35,7 @@ public class MigrationProfile {
|
|||
private boolean didRunPrePatch;
|
||||
private Exception prePatchException;
|
||||
|
||||
MigrationProfile(CompoundTag config) {
|
||||
MigrationProfile(CompoundTag config, boolean applyAll) {
|
||||
this.config = config;
|
||||
|
||||
this.mods = Collections.unmodifiableSet(Patch.getALL()
|
||||
|
@ -44,6 +46,7 @@ public class MigrationProfile {
|
|||
HashMap<String, String> replacements = new HashMap<String, String>();
|
||||
List<PatchFunction<CompoundTag, Boolean>> levelPatches = new LinkedList<>();
|
||||
List<Patch> worldDataPatches = new LinkedList<>();
|
||||
List<PatchBiFunction<ListTag, ListTag, Boolean>> statePatches = new LinkedList<>();
|
||||
HashMap<String, List<String>> worldDataIDPaths = new HashMap<>();
|
||||
for (String modID : mods) {
|
||||
|
||||
|
@ -54,12 +57,14 @@ public class MigrationProfile {
|
|||
List<String> paths = patch.getWorldDataIDPaths();
|
||||
if (paths!=null) worldDataIDPaths.put(modID, paths);
|
||||
|
||||
if (currentPatchLevel(modID) < patch.level) {
|
||||
if (applyAll || currentPatchLevel(modID) < patch.level || patch.alwaysApply) {
|
||||
replacements.putAll(patch.getIDReplacements());
|
||||
if (patch.getLevelDatPatcher()!=null)
|
||||
levelPatches.add(patch.getLevelDatPatcher());
|
||||
if (patch.getWorldDataPatcher()!=null)
|
||||
worldDataPatches.add(patch);
|
||||
if (patch.getBlockStatePatcher()!=null)
|
||||
statePatches.add(patch.getBlockStatePatcher());
|
||||
DataFixerAPI.LOGGER.info("Applying " + patch);
|
||||
}
|
||||
else {
|
||||
|
@ -72,6 +77,54 @@ public class MigrationProfile {
|
|||
this.idReplacements = Collections.unmodifiableMap(replacements);
|
||||
this.levelPatchers = Collections.unmodifiableList(levelPatches);
|
||||
this.worldDataPatchers = Collections.unmodifiableList(worldDataPatches);
|
||||
this.statePatchers = Collections.unmodifiableList(statePatches);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is supposed to be used by developers to apply id-patches to custom nbt structures. It is only
|
||||
* available in Developer-Mode
|
||||
*
|
||||
*/
|
||||
public static void fixCustomFolder(File dir){
|
||||
if (!BCLib.isDevEnvironment()) return;
|
||||
MigrationProfile profile = Patch.createMigrationData();
|
||||
List<File> nbts = getAllNbts(dir, null);
|
||||
nbts.parallelStream().forEach((file) -> {
|
||||
DataFixerAPI.LOGGER.info("Loading NBT " + file);
|
||||
try {
|
||||
CompoundTag root = NbtIo.readCompressed(file);
|
||||
boolean[] changed = {false};
|
||||
if (root.contains("palette")){
|
||||
ListTag items = root.getList("palette", Tag.TAG_COMPOUND);
|
||||
items.forEach(inTag -> {
|
||||
CompoundTag tag = (CompoundTag)inTag;
|
||||
changed[0] |= profile.replaceStringFromIDs(tag, "Name");
|
||||
});
|
||||
}
|
||||
|
||||
if (changed[0]){
|
||||
DataFixerAPI.LOGGER.info("Writing NBT " + file);
|
||||
NbtIo.writeCompressed(root, file);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static List<File> getAllNbts(File dir, List<File> list) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
for (File file : dir.listFiles()) {
|
||||
if (file.isDirectory()) {
|
||||
getAllNbts(file, list);
|
||||
} else if (file.isFile() && file.getName().endsWith(".nbt")) {
|
||||
list.add(file);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
final public CompoundTag getLevelDat(File levelBaseDir){
|
||||
|
@ -124,12 +177,13 @@ public class MigrationProfile {
|
|||
final public void markApplied() {
|
||||
for (String modID : mods) {
|
||||
DataFixerAPI.LOGGER.info("Updating Patch-Level for '{}' from {} to {}", modID, ModUtil.convertModVersion(currentPatchLevel(modID)), ModUtil.convertModVersion(Patch.maxPatchLevel(modID)));
|
||||
config.putString(modID, Patch.maxPatchVersion(modID));
|
||||
if (config!=null)
|
||||
config.putString(modID, Patch.maxPatchVersion(modID));
|
||||
}
|
||||
}
|
||||
|
||||
public String currentPatchVersion(@NotNull String modID) {
|
||||
if (!config.contains(modID)) return "0.0.0";
|
||||
if (config==null || !config.contains(modID)) return "0.0.0";
|
||||
return config.getString(modID);
|
||||
}
|
||||
|
||||
|
@ -255,4 +309,12 @@ public class MigrationProfile {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean patchBlockState(ListTag palette, ListTag states) throws PatchDidiFailException{
|
||||
boolean changed = false;
|
||||
for (PatchBiFunction<ListTag, ListTag, Boolean> f : statePatchers) {
|
||||
changed |= f.apply(palette, states, this);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ru.bclib.api.datafixer;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import ru.bclib.util.ModUtil;
|
||||
|
||||
|
@ -30,6 +31,11 @@ public abstract class Patch {
|
|||
@NotNull
|
||||
public final String modID;
|
||||
|
||||
/**
|
||||
* This Mod is tested for each level start
|
||||
*/
|
||||
public final boolean alwaysApply;
|
||||
|
||||
static List<Patch> getALL() {
|
||||
return ALL;
|
||||
}
|
||||
|
@ -81,6 +87,19 @@ public abstract class Patch {
|
|||
* {@link Patch#maxPatchVersion(String)}
|
||||
*/
|
||||
protected Patch(@NotNull String modID, String version) {
|
||||
this(modID, version, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal Constructor used to create patches that can allways run (no matter what patchlevel a level has)
|
||||
* @param modID The ID of the Mod
|
||||
* @param version The mod-version that introduces the patch. When {@Code runAllways} is set, this version will
|
||||
* determine the patchlevel that is written to the level
|
||||
* @param alwaysApply When true, this patch is always active, no matter the patchlevel of the world.
|
||||
* This should be used sparingly and just for patches that apply to level.dat (as they only take
|
||||
* effect when changes are detected). Use {@link ForcedLevelPatch} to instatiate.
|
||||
*/
|
||||
Patch(@NotNull String modID, String version, boolean alwaysApply) {
|
||||
//Patchlevels need to be unique and registered in ascending order
|
||||
if (modID == null || "".equals(modID)) {
|
||||
throw new RuntimeException("[INTERNAL ERROR] Patches need a valid modID!");
|
||||
|
@ -91,6 +110,7 @@ public abstract class Patch {
|
|||
}
|
||||
|
||||
this.version = version;
|
||||
this.alwaysApply = alwaysApply;
|
||||
this.level = ModUtil.convertModVersion(version);
|
||||
if (!ALL.stream()
|
||||
.filter(p -> p.modID
|
||||
|
@ -145,22 +165,46 @@ public abstract class Patch {
|
|||
*/
|
||||
public PatchFunction<CompoundTag, Boolean> getWorldDataPatcher() { return null; }
|
||||
|
||||
/**
|
||||
* Return a {@link PatchBiFunction} that is called with pallette and blockstate of
|
||||
* each chunk in every region. This method is called AFTER all ID replacements
|
||||
* from {@link #getIDReplacements()} were applied to the pallete.
|
||||
*
|
||||
* The first parameter is the palette and the second is the blockstate.
|
||||
*
|
||||
* The function needs to return {@code true}, if changes were made to the data.
|
||||
* If an error occurs, the method should throw a {@link PatchDidiFailException}
|
||||
*
|
||||
* The default implementation of this method returns null.
|
||||
*
|
||||
* @return {@code true} if changes were applied and we need to save the data
|
||||
*/
|
||||
public PatchBiFunction<ListTag, ListTag, Boolean> getBlockStatePatcher() { return null; }
|
||||
|
||||
/**
|
||||
* Generates ready to use data for all currently registered patches. The list of
|
||||
* patches is selected by the current patch-level of the world.
|
||||
* <p>
|
||||
* A {@link #Patch} with a given {@link #level} is only included if the patch-level of the
|
||||
* world is less
|
||||
* @param config The current patch-level configuration
|
||||
* @param levelBaseDir The location of the level
|
||||
* @param config The current patch-level configuration*
|
||||
* @return a new {@link MigrationProfile} Object.
|
||||
*/
|
||||
static MigrationProfile createMigrationData(CompoundTag config) {
|
||||
return new MigrationProfile(config);
|
||||
return new MigrationProfile(config, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is supposed to be used by developers to apply id-patches to custom nbt structures. It is only
|
||||
* available in Developer-Mode
|
||||
*
|
||||
*/
|
||||
static MigrationProfile createMigrationData() {
|
||||
return new MigrationProfile(null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of paths,where your mod may IDs in your {@link ru.bclib.api.WorldDataAPI}-File.
|
||||
* Returns a list of paths where your mod stores IDs in your {@link ru.bclib.api.WorldDataAPI}-File.
|
||||
* <p>
|
||||
* {@link DataFixerAPI} will use information from the latest patch that returns a non-null-result. This list is used
|
||||
* to automatically fix changed IDs from all active patches (see {@link Patch#getIDReplacements()}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package ru.bclib.api.datafixer;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface PatchBiFunction<U, V, R> {
|
||||
R apply(U t, V v, MigrationProfile profile) throws PatchDidiFailException;
|
||||
}
|
|
@ -25,7 +25,7 @@ import java.util.List;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
public class BaseLeavesBlock extends LeavesBlock implements BlockModelProvider, RenderLayerProvider {
|
||||
private final Block sapling;
|
||||
protected final Block sapling;
|
||||
|
||||
private static FabricBlockSettings makeLeaves(MaterialColor color) {
|
||||
return FabricBlockSettings.copyOf(Blocks.OAK_LEAVES)
|
||||
|
@ -37,12 +37,12 @@ public class BaseLeavesBlock extends LeavesBlock implements BlockModelProvider,
|
|||
.suffocates((state, world, pos) -> false)
|
||||
.blockVision((state, world, pos) -> false);
|
||||
}
|
||||
|
||||
|
||||
public BaseLeavesBlock(Block sapling, MaterialColor color, Consumer<FabricBlockSettings> customizeProperties) {
|
||||
super(BaseBlock.acceptAndReturn(customizeProperties, makeLeaves(color)));
|
||||
this.sapling = sapling;
|
||||
}
|
||||
|
||||
|
||||
public BaseLeavesBlock(Block sapling, MaterialColor color, int light, Consumer<FabricBlockSettings> customizeProperties) {
|
||||
super(BaseBlock.acceptAndReturn(customizeProperties, makeLeaves(color).luminance(light)));
|
||||
this.sapling = sapling;
|
||||
|
|
|
@ -9,6 +9,7 @@ import net.minecraft.world.item.Item;
|
|||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.world.item.enchantment.Enchantments;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.block.OreBlock;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
@ -28,11 +29,16 @@ public class BaseOreBlock extends OreBlock implements BlockModelProvider {
|
|||
private final int maxCount;
|
||||
|
||||
public BaseOreBlock(Item drop, int minCount, int maxCount, int experience) {
|
||||
super(FabricBlockSettings.of(Material.STONE, MaterialColor.SAND)
|
||||
this(drop, minCount, maxCount, experience, FabricBlockSettings.of(Material.STONE, MaterialColor.SAND)
|
||||
.hardness(3F)
|
||||
.resistance(9F)
|
||||
.requiresCorrectToolForDrops()
|
||||
.sound(SoundType.STONE), UniformInt.of(1, experience));
|
||||
.sound(SoundType.STONE));
|
||||
|
||||
}
|
||||
|
||||
public BaseOreBlock(Item drop, int minCount, int maxCount, int experience, Properties properties) {
|
||||
super(properties, UniformInt.of(experience>0?1:0, experience));
|
||||
this.dropItem = drop;
|
||||
this.minCount = minCount;
|
||||
this.maxCount = maxCount;
|
||||
|
@ -41,10 +47,14 @@ public class BaseOreBlock extends OreBlock implements BlockModelProvider {
|
|||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||
return getDroppedItems(this, dropItem, maxCount, minCount, state, builder);
|
||||
}
|
||||
|
||||
public static List<ItemStack> getDroppedItems(ItemLike block, Item dropItem, int maxCount, int minCount, BlockState state, LootContext.Builder builder) {
|
||||
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||
if (tool != null && tool.isCorrectToolForDrops(state)) {
|
||||
if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0) {
|
||||
return Collections.singletonList(new ItemStack(this));
|
||||
return Collections.singletonList(new ItemStack(block));
|
||||
}
|
||||
int count;
|
||||
int enchantment = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BLOCK_FORTUNE, tool);
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package ru.bclib.blocks;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
public abstract class FeatureHangingSaplingBlock extends FeatureSaplingBlockCommon{
|
||||
private static final VoxelShape SHAPE = Block.box(4, 2, 4, 12, 16, 12);
|
||||
public FeatureHangingSaplingBlock() {
|
||||
super();
|
||||
}
|
||||
|
||||
public FeatureHangingSaplingBlock(int light) {
|
||||
super(light);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSurvive(BlockState blockState, LevelReader levelReader, BlockPos blockPos) {
|
||||
final BlockPos target = blockPos.above();
|
||||
return this.mayPlaceOn(levelReader.getBlockState(target), levelReader, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||
return SHAPE;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,134 +1,26 @@
|
|||
package ru.bclib.blocks;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.SaplingBlock;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.material.Material;
|
||||
import net.minecraft.world.level.storage.loot.LootContext;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.bclib.client.models.BasePatterns;
|
||||
import ru.bclib.client.models.ModelsHelper;
|
||||
import ru.bclib.client.models.PatternsHelper;
|
||||
import ru.bclib.client.render.BCLRenderLayer;
|
||||
import ru.bclib.interfaces.BlockModelProvider;
|
||||
import ru.bclib.interfaces.RenderLayerProvider;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class FeatureSaplingBlock extends SaplingBlock implements RenderLayerProvider, BlockModelProvider {
|
||||
public abstract class FeatureSaplingBlock extends FeatureSaplingBlockCommon {
|
||||
private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12);
|
||||
|
||||
public FeatureSaplingBlock() {
|
||||
super(
|
||||
null,
|
||||
FabricBlockSettings.of(Material.PLANT)
|
||||
.breakByHand(true)
|
||||
.collidable(false)
|
||||
.instabreak()
|
||||
.sound(SoundType.GRASS)
|
||||
.randomTicks()
|
||||
);
|
||||
super();
|
||||
}
|
||||
|
||||
public FeatureSaplingBlock(int light) {
|
||||
super(
|
||||
null,
|
||||
FabricBlockSettings.of(Material.PLANT)
|
||||
.breakByHand(true)
|
||||
.collidable(false)
|
||||
.luminance(light)
|
||||
.instabreak()
|
||||
.sound(SoundType.GRASS)
|
||||
.randomTicks()
|
||||
);
|
||||
}
|
||||
|
||||
protected abstract Feature<?> getFeature();
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||
return Collections.singletonList(new ItemStack(this));
|
||||
super(light);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
|
||||
return SHAPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||
if (!canSurvive(state, world, pos)) return Blocks.AIR.defaultBlockState();
|
||||
else return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) {
|
||||
return random.nextInt(16) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void advanceTree(ServerLevel world, BlockPos pos, BlockState blockState, Random random) {
|
||||
FeaturePlaceContext context = new FeaturePlaceContext(
|
||||
Optional.empty(),
|
||||
world,
|
||||
world.getChunkSource().getGenerator(),
|
||||
random,
|
||||
pos,
|
||||
null
|
||||
);
|
||||
getFeature().place(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||
this.tick(state, world, pos, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||
super.tick(state, world, pos, random);
|
||||
if (isBonemealSuccess(world, random, pos, state)) {
|
||||
performBonemeal(world, random, pos, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BCLRenderLayer getRenderLayer() {
|
||||
return BCLRenderLayer.CUTOUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||
return ModelsHelper.createBlockItem(resourceLocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||
Optional<String> pattern = PatternsHelper.createJson(BasePatterns.BLOCK_CROSS, resourceLocation);
|
||||
return ModelsHelper.fromPattern(pattern);
|
||||
}
|
||||
}
|
||||
|
|
129
src/main/java/ru/bclib/blocks/FeatureSaplingBlockCommon.java
Normal file
129
src/main/java/ru/bclib/blocks/FeatureSaplingBlockCommon.java
Normal file
|
@ -0,0 +1,129 @@
|
|||
package ru.bclib.blocks;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.SaplingBlock;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.material.Material;
|
||||
import net.minecraft.world.level.storage.loot.LootContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.bclib.client.models.BasePatterns;
|
||||
import ru.bclib.client.models.ModelsHelper;
|
||||
import ru.bclib.client.models.PatternsHelper;
|
||||
import ru.bclib.client.render.BCLRenderLayer;
|
||||
import ru.bclib.interfaces.BlockModelProvider;
|
||||
import ru.bclib.interfaces.RenderLayerProvider;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
abstract class FeatureSaplingBlockCommon extends SaplingBlock implements RenderLayerProvider, BlockModelProvider {
|
||||
public FeatureSaplingBlockCommon() {
|
||||
super(
|
||||
null,
|
||||
FabricBlockSettings.of(Material.PLANT)
|
||||
.breakByHand(true)
|
||||
.collidable(false)
|
||||
.instabreak()
|
||||
.sound(SoundType.GRASS)
|
||||
.randomTicks()
|
||||
);
|
||||
}
|
||||
|
||||
public FeatureSaplingBlockCommon(int light) {
|
||||
super(
|
||||
null,
|
||||
FabricBlockSettings.of(Material.PLANT)
|
||||
.breakByHand(true)
|
||||
.collidable(false)
|
||||
.luminance(light)
|
||||
.instabreak()
|
||||
.sound(SoundType.GRASS)
|
||||
.randomTicks()
|
||||
);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
/**
|
||||
* Override {@link #getFeature(BlockState)} directly. Will be removed in 5.x
|
||||
*/
|
||||
protected Feature<?> getFeature() { return null; }
|
||||
|
||||
protected Feature<?> getFeature(BlockState state){
|
||||
return getFeature();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
|
||||
return Collections.singletonList(new ItemStack(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
|
||||
if (!canSurvive(state, world, pos)) return Blocks.AIR.defaultBlockState();
|
||||
else return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) {
|
||||
return random.nextInt(16) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void advanceTree(ServerLevel world, BlockPos pos, BlockState blockState, Random random) {
|
||||
FeaturePlaceContext context = new FeaturePlaceContext(
|
||||
world,
|
||||
world.getChunkSource().getGenerator(),
|
||||
random,
|
||||
pos,
|
||||
null
|
||||
);
|
||||
getFeature(blockState).place(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||
this.tick(state, world, pos, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
|
||||
super.tick(state, world, pos, random);
|
||||
if (isBonemealSuccess(world, random, pos, state)) {
|
||||
performBonemeal(world, random, pos, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BCLRenderLayer getRenderLayer() {
|
||||
return BCLRenderLayer.CUTOUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public BlockModel getItemModel(ResourceLocation resourceLocation) {
|
||||
return ModelsHelper.createBlockItem(resourceLocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) {
|
||||
Optional<String> pattern = PatternsHelper.createJson(BasePatterns.BLOCK_CROSS, resourceLocation);
|
||||
return ModelsHelper.fromPattern(pattern);
|
||||
}
|
||||
}
|
16
src/main/java/ru/bclib/blocks/LeveledAnvilBlock.java
Normal file
16
src/main/java/ru/bclib/blocks/LeveledAnvilBlock.java
Normal file
|
@ -0,0 +1,16 @@
|
|||
package ru.bclib.blocks;
|
||||
|
||||
import net.minecraft.world.level.material.MaterialColor;
|
||||
|
||||
public class LeveledAnvilBlock extends BaseAnvilBlock{
|
||||
protected final int level;
|
||||
|
||||
public LeveledAnvilBlock(MaterialColor color, int level) {
|
||||
super(color);
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public int getCraftingLevel() {
|
||||
return level;
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
|||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.material.Material;
|
||||
import net.minecraft.world.level.material.MaterialColor;
|
||||
import ru.bclib.api.TagAPI;
|
||||
import ru.bclib.client.render.BCLRenderLayer;
|
||||
import ru.bclib.interfaces.RenderLayerProvider;
|
||||
|
||||
|
@ -17,6 +18,8 @@ public class SimpleLeavesBlock extends BaseBlockNotFull implements RenderLayerPr
|
|||
.isValidSpawn((state, world, pos, type) -> false)
|
||||
.isSuffocating((state, world, pos) -> false)
|
||||
.isViewBlocking((state, world, pos) -> false));
|
||||
|
||||
TagAPI.addTags(this, TagAPI.BLOCK_LEAVES);
|
||||
}
|
||||
|
||||
public SimpleLeavesBlock(MaterialColor color, int light) {
|
||||
|
@ -29,6 +32,8 @@ public class SimpleLeavesBlock extends BaseBlockNotFull implements RenderLayerPr
|
|||
.isValidSpawn((state, world, pos, type) -> false)
|
||||
.isSuffocating((state, world, pos) -> false)
|
||||
.isViewBlocking((state, world, pos) -> false));
|
||||
|
||||
TagAPI.addTags(this, TagAPI.BLOCK_LEAVES);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -88,18 +88,21 @@ public class ModelsHelper {
|
|||
|
||||
public static class MultiPartBuilder {
|
||||
|
||||
private final static MultiPartBuilder BUILDER = new MultiPartBuilder();
|
||||
//private final static MultiPartBuilder BUILDER = new MultiPartBuilder();
|
||||
|
||||
public static MultiPartBuilder create(StateDefinition<Block, BlockState> stateDefinition) {
|
||||
BUILDER.stateDefinition = stateDefinition;
|
||||
BUILDER.modelParts.clear();
|
||||
return BUILDER;
|
||||
// BUILDER.stateDefinition = stateDefinition;
|
||||
//BUILDER.modelParts.clear();
|
||||
// return BUILDER;
|
||||
return new MultiPartBuilder(stateDefinition);
|
||||
}
|
||||
|
||||
private final List<ModelPart> modelParts = Lists.newArrayList();
|
||||
private StateDefinition<Block, BlockState> stateDefinition;
|
||||
|
||||
private MultiPartBuilder() {}
|
||||
private MultiPartBuilder(StateDefinition<Block, BlockState> stateDefinition) {
|
||||
this.stateDefinition = stateDefinition;
|
||||
}
|
||||
|
||||
public ModelPart part(ResourceLocation modelId) {
|
||||
ModelPart part = new ModelPart(modelId);
|
||||
|
|
|
@ -3,6 +3,7 @@ package ru.bclib.client.render;
|
|||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.renderer.FogRenderer;
|
||||
import net.minecraft.client.renderer.FogRenderer.FogMode;
|
||||
import net.minecraft.core.BlockPos.MutableBlockPos;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
|
@ -22,46 +23,77 @@ public class CustomBackgroundRenderer {
|
|||
private static final MutableBlockPos MUT_POS = new MutableBlockPos();
|
||||
private static final float[] FOG_DENSITY = new float[8];
|
||||
private static final int GRID_SIZE = 32;
|
||||
private static float fogStart = 0;
|
||||
private static float fogEnd = 192;
|
||||
|
||||
public static boolean applyFogDensity(Camera camera, FogRenderer.FogMode fogMode, float viewDistance, boolean thickFog) {
|
||||
Entity entity = camera.getEntity();
|
||||
FogType fogType = camera.getFluidInCamera();
|
||||
if (fogType != FogType.WATER) {
|
||||
if (shouldIgnore(entity.level, (int) entity.getX(), (int) entity.getEyeY(), (int) entity.getZ())) {
|
||||
return false;
|
||||
}
|
||||
float fog = getFogDensity(entity.level, entity.getX(), entity.getEyeY(), entity.getZ());
|
||||
BackgroundInfo.fogDensity = fog;
|
||||
float start = viewDistance * 0.75F / fog;
|
||||
float end = viewDistance / fog;
|
||||
|
||||
if (entity instanceof LivingEntity) {
|
||||
LivingEntity livingEntity = (LivingEntity) entity;
|
||||
MobEffectInstance effect = livingEntity.getEffect(MobEffects.BLINDNESS);
|
||||
if (effect != null) {
|
||||
int duration = effect.getDuration();
|
||||
if (duration > 20) {
|
||||
start = 0;
|
||||
end *= 0.03F;
|
||||
BackgroundInfo.blindness = 1;
|
||||
}
|
||||
else {
|
||||
float delta = (float) duration / 20F;
|
||||
BackgroundInfo.blindness = delta;
|
||||
start = Mth.lerp(delta, start, 0);
|
||||
end = Mth.lerp(delta, end, end * 0.03F);
|
||||
}
|
||||
|
||||
if (fogType == FogType.WATER || fogType == FogType.LAVA || fogMode != FogMode.FOG_SKY) {
|
||||
BackgroundInfo.fogDensity = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
Entity entity = camera.getEntity();
|
||||
|
||||
if (!isForcedDimension(entity.level) && shouldIgnoreArea(entity.level, (int) entity.getX(), (int) entity.getEyeY(), (int) entity.getZ())) {
|
||||
BackgroundInfo.fogDensity = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
float fog = getFogDensity(entity.level, entity.getX(), entity.getEyeY(), entity.getZ());
|
||||
BackgroundInfo.fogDensity = fog;
|
||||
|
||||
if (thickFog) {
|
||||
fogStart = viewDistance * 0.05F / fog;
|
||||
fogEnd = Math.min(viewDistance, 192.0F) * 0.5F / fog;
|
||||
}
|
||||
else {
|
||||
fogStart = viewDistance * 0.75F / fog;
|
||||
fogEnd = viewDistance / fog;
|
||||
}
|
||||
|
||||
if (entity instanceof LivingEntity) {
|
||||
LivingEntity livingEntity = (LivingEntity) entity;
|
||||
MobEffectInstance effect = livingEntity.getEffect(MobEffects.BLINDNESS);
|
||||
if (effect != null) {
|
||||
int duration = effect.getDuration();
|
||||
if (duration > 20) {
|
||||
fogStart = 0;
|
||||
fogEnd *= 0.03F;
|
||||
BackgroundInfo.blindness = 1;
|
||||
}
|
||||
else {
|
||||
BackgroundInfo.blindness = 0;
|
||||
float delta = (float) duration / 20F;
|
||||
BackgroundInfo.blindness = delta;
|
||||
fogStart = Mth.lerp(delta, fogStart, 0);
|
||||
fogEnd = Mth.lerp(delta, fogEnd, fogEnd * 0.03F);
|
||||
}
|
||||
}
|
||||
|
||||
RenderSystem.setShaderFogStart(start);
|
||||
RenderSystem.setShaderFogEnd(end);
|
||||
return true;
|
||||
else {
|
||||
BackgroundInfo.blindness = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
RenderSystem.setShaderFogStart(fogStart);
|
||||
RenderSystem.setShaderFogEnd(fogEnd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isForcedDimension(Level level) {
|
||||
return level.dimension() == Level.END || level.dimension() == Level.NETHER;
|
||||
}
|
||||
|
||||
private static boolean shouldIgnoreArea(Level level, int x, int y, int z) {
|
||||
for (int i = -8; i <= 8; i += 8) {
|
||||
for (int j = -8; j <= 8; j += 8) {
|
||||
if (!shouldIgnore(level, x + i, y, z + j)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean shouldIgnore(Level level, int x, int y, int z) {
|
||||
|
|
|
@ -39,358 +39,372 @@ import ru.bclib.complexmaterials.entry.RecipeEntry;
|
|||
import ru.bclib.recipes.GridRecipe;
|
||||
|
||||
public class WoodenComplexMaterial extends ComplexMaterial {
|
||||
public static final ResourceLocation MATERIAL_ID = BCLib.makeID("wooden_material");
|
||||
|
||||
public static final String BLOCK_CRAFTING_TABLE = "crafting_table";
|
||||
public static final String BLOCK_STRIPPED_BARK = "stripped_bark";
|
||||
public static final String BLOCK_STRIPPED_LOG = "stripped_log";
|
||||
public static final String BLOCK_PRESSURE_PLATE = "plate";
|
||||
public static final String BLOCK_BOOKSHELF = "bookshelf";
|
||||
public static final String BLOCK_COMPOSTER = "composter";
|
||||
public static final String BLOCK_TRAPDOOR = "trapdoor";
|
||||
public static final String BLOCK_BARREL = "barrel";
|
||||
public static final String BLOCK_BUTTON = "button";
|
||||
public static final String BLOCK_LADDER = "ladder";
|
||||
public static final String BLOCK_PLANKS = "planks";
|
||||
public static final String BLOCK_STAIRS = "stairs";
|
||||
public static final String BLOCK_CHEST = "chest";
|
||||
public static final String BLOCK_FENCE = "fence";
|
||||
public static final String BLOCK_BARK = "bark";
|
||||
public static final String BLOCK_DOOR = "door";
|
||||
public static final String BLOCK_GATE = "gate";
|
||||
public static final String BLOCK_SIGN = "sign";
|
||||
public static final String BLOCK_SLAB = "slab";
|
||||
public static final String BLOCK_LOG = "log";
|
||||
|
||||
public static final String TAG_LOGS = "logs";
|
||||
|
||||
public final MaterialColor planksColor;
|
||||
public final MaterialColor woodColor;
|
||||
|
||||
public WoodenComplexMaterial(String modID, String baseName, String receipGroupPrefix, MaterialColor woodColor, MaterialColor planksColor) {
|
||||
super(modID, baseName, receipGroupPrefix);
|
||||
this.planksColor = planksColor;
|
||||
this.woodColor = woodColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FabricBlockSettings getBlockSettings() {
|
||||
return FabricBlockSettings.copyOf(Blocks.OAK_PLANKS).mapColor(planksColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getMaterialID() {
|
||||
return MATERIAL_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initTags() {
|
||||
addBlockTag(TagAPI.makeBlockTag(getModID(), getBaseName() + "_logs"));
|
||||
addItemTag(TagAPI.makeItemTag(getModID(), getBaseName() + "_logs"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initDefault(FabricBlockSettings blockSettings, FabricItemSettings itemSettings) {
|
||||
initBase(blockSettings, itemSettings);
|
||||
initStorage(blockSettings, itemSettings);
|
||||
initDecorations(blockSettings, itemSettings);
|
||||
}
|
||||
|
||||
final protected void initBase(FabricBlockSettings blockSettings, FabricItemSettings itemSettings) {
|
||||
Tag.Named<Block> tagBlockLog = getBlockTag(TAG_LOGS);
|
||||
Tag.Named<Item> tagItemLog = getItemTag(TAG_LOGS);
|
||||
|
||||
addBlockEntry(
|
||||
new BlockEntry(BLOCK_STRIPPED_LOG, (complexMaterial, settings) -> {
|
||||
return new BaseRotatedPillarBlock(settings);
|
||||
})
|
||||
.setBlockTags(BlockTags.LOGS, BlockTags.LOGS_THAT_BURN, tagBlockLog)
|
||||
.setItemTags(ItemTags.LOGS, ItemTags.LOGS_THAT_BURN, tagItemLog)
|
||||
);
|
||||
addBlockEntry(
|
||||
new BlockEntry(BLOCK_STRIPPED_BARK, (complexMaterial, settings) -> {
|
||||
return new BaseBarkBlock(settings);
|
||||
})
|
||||
.setBlockTags(BlockTags.LOGS, BlockTags.LOGS_THAT_BURN, tagBlockLog)
|
||||
.setItemTags(ItemTags.LOGS, ItemTags.LOGS_THAT_BURN, tagItemLog)
|
||||
);
|
||||
|
||||
addBlockEntry(
|
||||
new BlockEntry(BLOCK_LOG, (complexMaterial, settings) -> {
|
||||
return new BaseStripableLogBlock(woodColor, getBlock(BLOCK_STRIPPED_LOG));
|
||||
})
|
||||
.setBlockTags(BlockTags.LOGS, BlockTags.LOGS_THAT_BURN, tagBlockLog)
|
||||
.setItemTags(ItemTags.LOGS, ItemTags.LOGS_THAT_BURN, tagItemLog)
|
||||
);
|
||||
addBlockEntry(
|
||||
new BlockEntry(BLOCK_BARK, (complexMaterial, settings) -> {
|
||||
return new StripableBarkBlock(woodColor, getBlock(BLOCK_STRIPPED_BARK));
|
||||
})
|
||||
.setBlockTags(BlockTags.LOGS, BlockTags.LOGS_THAT_BURN, tagBlockLog)
|
||||
.setItemTags(ItemTags.LOGS, ItemTags.LOGS_THAT_BURN, tagItemLog)
|
||||
);
|
||||
addBlockEntry(new BlockEntry(BLOCK_PLANKS, (complexMaterial, settings) -> {
|
||||
return new BaseBlock(settings);
|
||||
}).setBlockTags(BlockTags.PLANKS).setItemTags(ItemTags.PLANKS));
|
||||
|
||||
addBlockEntry(new BlockEntry(BLOCK_STAIRS, (complexMaterial, settings) -> {
|
||||
return new BaseStairsBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.WOODEN_STAIRS, BlockTags.STAIRS).setItemTags(ItemTags.WOODEN_STAIRS, ItemTags.STAIRS));
|
||||
addBlockEntry(new BlockEntry(BLOCK_SLAB, (complexMaterial, settings) -> {
|
||||
return new BaseSlabBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.WOODEN_SLABS, BlockTags.SLABS).setItemTags(ItemTags.WOODEN_SLABS, ItemTags.SLABS));
|
||||
addBlockEntry(new BlockEntry(BLOCK_FENCE, (complexMaterial, settings) -> {
|
||||
return new BaseFenceBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.FENCES, BlockTags.WOODEN_FENCES).setItemTags(ItemTags.FENCES, ItemTags.WOODEN_FENCES));
|
||||
addBlockEntry(new BlockEntry(BLOCK_GATE, (complexMaterial, settings) -> {
|
||||
return new BaseGateBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.FENCE_GATES));
|
||||
addBlockEntry(new BlockEntry(BLOCK_BUTTON, (complexMaterial, settings) -> {
|
||||
return new BaseWoodenButtonBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.BUTTONS, BlockTags.WOODEN_BUTTONS).setItemTags(ItemTags.BUTTONS, ItemTags.WOODEN_BUTTONS));
|
||||
addBlockEntry(new BlockEntry(BLOCK_PRESSURE_PLATE, (complexMaterial, settings) -> {
|
||||
return new WoodenPressurePlateBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.PRESSURE_PLATES, BlockTags.WOODEN_PRESSURE_PLATES).setItemTags(ItemTags.WOODEN_PRESSURE_PLATES));
|
||||
addBlockEntry(new BlockEntry(BLOCK_TRAPDOOR, (complexMaterial, settings) -> {
|
||||
return new BaseTrapdoorBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.TRAPDOORS, BlockTags.WOODEN_TRAPDOORS).setItemTags(ItemTags.TRAPDOORS, ItemTags.WOODEN_TRAPDOORS));
|
||||
addBlockEntry(new BlockEntry(BLOCK_DOOR, (complexMaterial, settings) -> {
|
||||
return new BaseDoorBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.DOORS, BlockTags.WOODEN_DOORS).setItemTags(ItemTags.DOORS, ItemTags.WOODEN_DOORS));
|
||||
|
||||
|
||||
addBlockEntry(new BlockEntry(BLOCK_LADDER, (complexMaterial, settings) -> {
|
||||
return new BaseLadderBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.CLIMBABLE));
|
||||
addBlockEntry(new BlockEntry(BLOCK_SIGN, (complexMaterial, settings) -> {
|
||||
return new BaseSignBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.SIGNS).setItemTags(ItemTags.SIGNS));
|
||||
|
||||
|
||||
}
|
||||
|
||||
final protected void initStorage(FabricBlockSettings blockSettings, FabricItemSettings itemSettings){
|
||||
addBlockEntry(new BlockEntry(BLOCK_CHEST, (complexMaterial, settings) -> {
|
||||
return new BaseChestBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(TagAPI.BLOCK_CHEST).setItemTags(TagAPI.ITEM_CHEST));
|
||||
addBlockEntry(new BlockEntry(BLOCK_BARREL, (complexMaterial, settings) -> {
|
||||
return new BaseBarrelBlock(getBlock(BLOCK_PLANKS));
|
||||
}));
|
||||
}
|
||||
|
||||
final protected void initDecorations(FabricBlockSettings blockSettings, FabricItemSettings itemSettings){
|
||||
addBlockEntry(new BlockEntry(BLOCK_CRAFTING_TABLE, (complexMaterial, settings) -> {
|
||||
return new BaseCraftingTableBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(TagAPI.BLOCK_WORKBENCHES).setItemTags(TagAPI.ITEM_WORKBENCHES));
|
||||
|
||||
addBlockEntry(new BlockEntry(BLOCK_BOOKSHELF, (complexMaterial, settings) -> {
|
||||
return new BaseBookshelfBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(TagAPI.BLOCK_BOOKSHELVES));
|
||||
|
||||
addBlockEntry(new BlockEntry(BLOCK_COMPOSTER, (complexMaterial, settings) -> {
|
||||
return new BaseComposterBlock(getBlock(BLOCK_PLANKS));
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initFlammable(FlammableBlockRegistry registry) {
|
||||
getBlocks().forEach(block -> {
|
||||
registry.add(block, 5, 20);
|
||||
});
|
||||
|
||||
registry.add(getBlock(BLOCK_LOG), 5, 5);
|
||||
registry.add(getBlock(BLOCK_BARK), 5, 5);
|
||||
registry.add(getBlock(BLOCK_STRIPPED_LOG), 5, 5);
|
||||
registry.add(getBlock(BLOCK_STRIPPED_BARK), 5, 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initDefaultRecipes() {
|
||||
Block planks = getBlock(BLOCK_PLANKS);
|
||||
addRecipeEntry(new RecipeEntry("planks", (material, config, id) -> {
|
||||
Block log_stripped = getBlock(BLOCK_STRIPPED_LOG);
|
||||
Block bark_stripped = getBlock(BLOCK_STRIPPED_BARK);
|
||||
Block log = getBlock(BLOCK_LOG);
|
||||
Block bark = getBlock(BLOCK_BARK);
|
||||
GridRecipe.make(id, planks)
|
||||
.checkConfig(config)
|
||||
.setOutputCount(4)
|
||||
.setList("#")
|
||||
.addMaterial('#', log, bark, log_stripped, bark_stripped)
|
||||
.setGroup(receipGroupPrefix +"_planks")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("stairs", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_STAIRS))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(4)
|
||||
.setShape("# ", "## ", "###")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix +"_planks_stairs")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("slab", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_SLAB))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(6)
|
||||
.setShape("###")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix +"_planks_slabs")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("fence", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_FENCE))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(3)
|
||||
.setShape("#I#", "#I#")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('I', Items.STICK)
|
||||
.setGroup(receipGroupPrefix +"_planks_fences")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("gate", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_GATE))
|
||||
.checkConfig(config)
|
||||
.setShape("I#I", "I#I")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('I', Items.STICK)
|
||||
.setGroup(receipGroupPrefix +"_planks_gates")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("button", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_BUTTON))
|
||||
.checkConfig(config)
|
||||
.setList("#")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix +"_planks_buttons")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("pressure_plate", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_PRESSURE_PLATE))
|
||||
.checkConfig(config)
|
||||
.setShape("##")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix +"_planks_plates")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("trapdoor", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_TRAPDOOR))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(2)
|
||||
.setShape("###", "###")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix +"_trapdoors")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("door", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_DOOR))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(3)
|
||||
.setShape("##", "##", "##")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix +"_doors")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("crafting_table", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_CRAFTING_TABLE))
|
||||
.checkConfig(config)
|
||||
.setShape("##", "##")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix +"_tables")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("ladder", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_LADDER))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(3)
|
||||
.setShape("I I", "I#I", "I I")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('I', Items.STICK)
|
||||
.setGroup(receipGroupPrefix +"_ladders")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("sign", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_SIGN))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(3)
|
||||
.setShape("###", "###", " I ")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('I', Items.STICK)
|
||||
.setGroup(receipGroupPrefix +"_signs")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("chest", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_CHEST))
|
||||
.checkConfig(config)
|
||||
.setShape("###", "# #", "###")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix +"_chests")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("barrel", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_BARREL))
|
||||
.checkConfig(config)
|
||||
.setShape("#S#", "# #", "#S#")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('S', getBlock(BLOCK_SLAB))
|
||||
.setGroup(receipGroupPrefix +"_barrels")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("bookshelf", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_BOOKSHELF))
|
||||
.checkConfig(config)
|
||||
.setShape("###", "PPP", "###")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('P', Items.BOOK)
|
||||
.setGroup(receipGroupPrefix +"_bookshelves")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("bark", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_BARK))
|
||||
.checkConfig(config)
|
||||
.setShape("##", "##")
|
||||
.addMaterial('#', getBlock(BLOCK_LOG))
|
||||
.setOutputCount(3)
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("log", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_LOG))
|
||||
.checkConfig(config)
|
||||
.setShape("##", "##")
|
||||
.addMaterial('#', getBlock(BLOCK_BARK))
|
||||
.setOutputCount(3)
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("stripped_bark", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_STRIPPED_BARK))
|
||||
.checkConfig(config)
|
||||
.setShape("##", "##")
|
||||
.addMaterial('#', getBlock(BLOCK_STRIPPED_LOG))
|
||||
.setOutputCount(3)
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("stripped_log", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_STRIPPED_LOG))
|
||||
.checkConfig(config)
|
||||
.setShape("##", "##")
|
||||
.addMaterial('#', getBlock(BLOCK_STRIPPED_BARK))
|
||||
.setOutputCount(3)
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("composter", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_COMPOSTER))
|
||||
.checkConfig(config)
|
||||
.setShape("# #", "# #", "###")
|
||||
.addMaterial('#', getBlock(BLOCK_SLAB))
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("shulker", (material, config, id) -> {
|
||||
GridRecipe.make(id, Blocks.SHULKER_BOX)
|
||||
.checkConfig(config)
|
||||
.setShape("S", "#", "S")
|
||||
.addMaterial('S', Items.SHULKER_SHELL)
|
||||
.addMaterial('#', getBlock(BLOCK_CHEST))
|
||||
.build();
|
||||
}));
|
||||
}
|
||||
public static final ResourceLocation MATERIAL_ID = BCLib.makeID("wooden_material");
|
||||
|
||||
public static final String BLOCK_CRAFTING_TABLE = "crafting_table";
|
||||
public static final String BLOCK_STRIPPED_BARK = "stripped_bark";
|
||||
public static final String BLOCK_STRIPPED_LOG = "stripped_log";
|
||||
public static final String BLOCK_PRESSURE_PLATE = "plate";
|
||||
public static final String BLOCK_BOOKSHELF = "bookshelf";
|
||||
public static final String BLOCK_COMPOSTER = "composter";
|
||||
public static final String BLOCK_TRAPDOOR = "trapdoor";
|
||||
public static final String BLOCK_BARREL = "barrel";
|
||||
public static final String BLOCK_BUTTON = "button";
|
||||
public static final String BLOCK_LADDER = "ladder";
|
||||
public static final String BLOCK_PLANKS = "planks";
|
||||
public static final String BLOCK_STAIRS = "stairs";
|
||||
public static final String BLOCK_CHEST = "chest";
|
||||
public static final String BLOCK_FENCE = "fence";
|
||||
public static final String BLOCK_BARK = "bark";
|
||||
public static final String BLOCK_DOOR = "door";
|
||||
public static final String BLOCK_GATE = "gate";
|
||||
public static final String BLOCK_SIGN = "sign";
|
||||
public static final String BLOCK_SLAB = "slab";
|
||||
public static final String BLOCK_LOG = "log";
|
||||
|
||||
public static final String TAG_LOGS = "logs";
|
||||
|
||||
public final MaterialColor planksColor;
|
||||
public final MaterialColor woodColor;
|
||||
|
||||
public WoodenComplexMaterial(String modID, String baseName, String receipGroupPrefix, MaterialColor woodColor, MaterialColor planksColor) {
|
||||
super(modID, baseName, receipGroupPrefix);
|
||||
this.planksColor = planksColor;
|
||||
this.woodColor = woodColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FabricBlockSettings getBlockSettings() {
|
||||
return FabricBlockSettings.copyOf(Blocks.OAK_PLANKS)
|
||||
.materialColor(planksColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getMaterialID() {
|
||||
return MATERIAL_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initTags() {
|
||||
addBlockTag(TagAPI.makeBlockTag(getModID(), getBaseName() + "_logs"));
|
||||
addItemTag(TagAPI.makeItemTag(getModID(), getBaseName() + "_logs"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initDefault(FabricBlockSettings blockSettings, FabricItemSettings itemSettings) {
|
||||
initBase(blockSettings, itemSettings);
|
||||
initStorage(blockSettings, itemSettings);
|
||||
initDecorations(blockSettings, itemSettings);
|
||||
}
|
||||
|
||||
final protected void initBase(FabricBlockSettings blockSettings, FabricItemSettings itemSettings) {
|
||||
Tag.Named<Block> tagBlockLog = getBlockTag(TAG_LOGS);
|
||||
Tag.Named<Item> tagItemLog = getItemTag(TAG_LOGS);
|
||||
|
||||
addBlockEntry(
|
||||
new BlockEntry(BLOCK_STRIPPED_LOG, (complexMaterial, settings) -> {
|
||||
return new BaseRotatedPillarBlock(settings);
|
||||
})
|
||||
.setBlockTags(BlockTags.LOGS, BlockTags.LOGS_THAT_BURN, tagBlockLog)
|
||||
.setItemTags(ItemTags.LOGS, ItemTags.LOGS_THAT_BURN, tagItemLog)
|
||||
);
|
||||
addBlockEntry(
|
||||
new BlockEntry(BLOCK_STRIPPED_BARK, (complexMaterial, settings) -> {
|
||||
return new BaseBarkBlock(settings);
|
||||
})
|
||||
.setBlockTags(BlockTags.LOGS, BlockTags.LOGS_THAT_BURN, tagBlockLog)
|
||||
.setItemTags(ItemTags.LOGS, ItemTags.LOGS_THAT_BURN, tagItemLog)
|
||||
);
|
||||
|
||||
addBlockEntry(
|
||||
new BlockEntry(BLOCK_LOG, (complexMaterial, settings) -> {
|
||||
return new BaseStripableLogBlock(woodColor, getBlock(BLOCK_STRIPPED_LOG));
|
||||
})
|
||||
.setBlockTags(BlockTags.LOGS, BlockTags.LOGS_THAT_BURN, tagBlockLog)
|
||||
.setItemTags(ItemTags.LOGS, ItemTags.LOGS_THAT_BURN, tagItemLog)
|
||||
);
|
||||
addBlockEntry(
|
||||
new BlockEntry(BLOCK_BARK, (complexMaterial, settings) -> {
|
||||
return new StripableBarkBlock(woodColor, getBlock(BLOCK_STRIPPED_BARK));
|
||||
})
|
||||
.setBlockTags(BlockTags.LOGS, BlockTags.LOGS_THAT_BURN, tagBlockLog)
|
||||
.setItemTags(ItemTags.LOGS, ItemTags.LOGS_THAT_BURN, tagItemLog)
|
||||
);
|
||||
addBlockEntry(new BlockEntry(BLOCK_PLANKS, (complexMaterial, settings) -> {
|
||||
return new BaseBlock(settings);
|
||||
}).setBlockTags(BlockTags.PLANKS)
|
||||
.setItemTags(ItemTags.PLANKS));
|
||||
|
||||
addBlockEntry(new BlockEntry(BLOCK_STAIRS, (complexMaterial, settings) -> {
|
||||
return new BaseStairsBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.WOODEN_STAIRS, BlockTags.STAIRS)
|
||||
.setItemTags(ItemTags.WOODEN_STAIRS, ItemTags.STAIRS));
|
||||
addBlockEntry(new BlockEntry(BLOCK_SLAB, (complexMaterial, settings) -> {
|
||||
return new BaseSlabBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.WOODEN_SLABS, BlockTags.SLABS)
|
||||
.setItemTags(ItemTags.WOODEN_SLABS, ItemTags.SLABS));
|
||||
addBlockEntry(new BlockEntry(BLOCK_FENCE, (complexMaterial, settings) -> {
|
||||
return new BaseFenceBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.FENCES, BlockTags.WOODEN_FENCES)
|
||||
.setItemTags(ItemTags.FENCES, ItemTags.WOODEN_FENCES));
|
||||
addBlockEntry(new BlockEntry(BLOCK_GATE, (complexMaterial, settings) -> {
|
||||
return new BaseGateBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.FENCE_GATES));
|
||||
addBlockEntry(new BlockEntry(BLOCK_BUTTON, (complexMaterial, settings) -> {
|
||||
return new BaseWoodenButtonBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.BUTTONS, BlockTags.WOODEN_BUTTONS)
|
||||
.setItemTags(ItemTags.BUTTONS, ItemTags.WOODEN_BUTTONS));
|
||||
addBlockEntry(new BlockEntry(BLOCK_PRESSURE_PLATE, (complexMaterial, settings) -> {
|
||||
return new WoodenPressurePlateBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.PRESSURE_PLATES, BlockTags.WOODEN_PRESSURE_PLATES)
|
||||
.setItemTags(ItemTags.WOODEN_PRESSURE_PLATES));
|
||||
addBlockEntry(new BlockEntry(BLOCK_TRAPDOOR, (complexMaterial, settings) -> {
|
||||
return new BaseTrapdoorBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.TRAPDOORS, BlockTags.WOODEN_TRAPDOORS)
|
||||
.setItemTags(ItemTags.TRAPDOORS, ItemTags.WOODEN_TRAPDOORS));
|
||||
addBlockEntry(new BlockEntry(BLOCK_DOOR, (complexMaterial, settings) -> {
|
||||
return new BaseDoorBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.DOORS, BlockTags.WOODEN_DOORS)
|
||||
.setItemTags(ItemTags.DOORS, ItemTags.WOODEN_DOORS));
|
||||
|
||||
|
||||
addBlockEntry(new BlockEntry(BLOCK_LADDER, (complexMaterial, settings) -> {
|
||||
return new BaseLadderBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.CLIMBABLE));
|
||||
addBlockEntry(new BlockEntry(BLOCK_SIGN, (complexMaterial, settings) -> {
|
||||
return new BaseSignBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(BlockTags.SIGNS)
|
||||
.setItemTags(ItemTags.SIGNS));
|
||||
|
||||
|
||||
}
|
||||
|
||||
final protected void initStorage(FabricBlockSettings blockSettings, FabricItemSettings itemSettings) {
|
||||
addBlockEntry(new BlockEntry(BLOCK_CHEST, (complexMaterial, settings) -> {
|
||||
return new BaseChestBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(TagAPI.BLOCK_CHEST, TagAPI.BLOCK_WOODEN_CHEST)
|
||||
.setItemTags(TagAPI.ITEM_CHEST, TagAPI.ITEM_WOODEN_CHEST));
|
||||
|
||||
addBlockEntry(new BlockEntry(BLOCK_BARREL, (complexMaterial, settings) -> {
|
||||
return new BaseBarrelBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(TagAPI.BLOCK_BARREL, TagAPI.BLOCK_WOODEN_BARREL)
|
||||
.setItemTags(TagAPI.ITEM_BARREL, TagAPI.ITEM_WOODEN_BARREL));
|
||||
}
|
||||
|
||||
final protected void initDecorations(FabricBlockSettings blockSettings, FabricItemSettings itemSettings) {
|
||||
addBlockEntry(new BlockEntry(BLOCK_CRAFTING_TABLE, (complexMaterial, settings) -> {
|
||||
return new BaseCraftingTableBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(TagAPI.BLOCK_WORKBENCHES)
|
||||
.setItemTags(TagAPI.ITEM_WORKBENCHES));
|
||||
|
||||
addBlockEntry(new BlockEntry(BLOCK_BOOKSHELF, (complexMaterial, settings) -> {
|
||||
return new BaseBookshelfBlock(getBlock(BLOCK_PLANKS));
|
||||
}).setBlockTags(TagAPI.BLOCK_BOOKSHELVES));
|
||||
|
||||
addBlockEntry(new BlockEntry(BLOCK_COMPOSTER, (complexMaterial, settings) -> {
|
||||
return new BaseComposterBlock(getBlock(BLOCK_PLANKS));
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initFlammable(FlammableBlockRegistry registry) {
|
||||
getBlocks().forEach(block -> {
|
||||
registry.add(block, 5, 20);
|
||||
});
|
||||
|
||||
registry.add(getBlock(BLOCK_LOG), 5, 5);
|
||||
registry.add(getBlock(BLOCK_BARK), 5, 5);
|
||||
registry.add(getBlock(BLOCK_STRIPPED_LOG), 5, 5);
|
||||
registry.add(getBlock(BLOCK_STRIPPED_BARK), 5, 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initDefaultRecipes() {
|
||||
Block planks = getBlock(BLOCK_PLANKS);
|
||||
addRecipeEntry(new RecipeEntry("planks", (material, config, id) -> {
|
||||
Block log_stripped = getBlock(BLOCK_STRIPPED_LOG);
|
||||
Block bark_stripped = getBlock(BLOCK_STRIPPED_BARK);
|
||||
Block log = getBlock(BLOCK_LOG);
|
||||
Block bark = getBlock(BLOCK_BARK);
|
||||
GridRecipe.make(id, planks)
|
||||
.checkConfig(config)
|
||||
.setOutputCount(4)
|
||||
.setList("#")
|
||||
.addMaterial('#', log, bark, log_stripped, bark_stripped)
|
||||
.setGroup(receipGroupPrefix + "_planks")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("stairs", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_STAIRS))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(4)
|
||||
.setShape("# ", "## ", "###")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix + "_planks_stairs")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("slab", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_SLAB))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(6)
|
||||
.setShape("###")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix + "_planks_slabs")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("fence", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_FENCE))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(3)
|
||||
.setShape("#I#", "#I#")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('I', Items.STICK)
|
||||
.setGroup(receipGroupPrefix + "_planks_fences")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("gate", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_GATE))
|
||||
.checkConfig(config)
|
||||
.setShape("I#I", "I#I")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('I', Items.STICK)
|
||||
.setGroup(receipGroupPrefix + "_planks_gates")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("button", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_BUTTON))
|
||||
.checkConfig(config)
|
||||
.setList("#")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix + "_planks_buttons")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("pressure_plate", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_PRESSURE_PLATE))
|
||||
.checkConfig(config)
|
||||
.setShape("##")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix + "_planks_plates")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("trapdoor", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_TRAPDOOR))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(2)
|
||||
.setShape("###", "###")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix + "_trapdoors")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("door", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_DOOR))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(3)
|
||||
.setShape("##", "##", "##")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix + "_doors")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("crafting_table", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_CRAFTING_TABLE))
|
||||
.checkConfig(config)
|
||||
.setShape("##", "##")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix + "_tables")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("ladder", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_LADDER))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(3)
|
||||
.setShape("I I", "I#I", "I I")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('I', Items.STICK)
|
||||
.setGroup(receipGroupPrefix + "_ladders")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("sign", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_SIGN))
|
||||
.checkConfig(config)
|
||||
.setOutputCount(3)
|
||||
.setShape("###", "###", " I ")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('I', Items.STICK)
|
||||
.setGroup(receipGroupPrefix + "_signs")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("chest", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_CHEST))
|
||||
.checkConfig(config)
|
||||
.setShape("###", "# #", "###")
|
||||
.addMaterial('#', planks)
|
||||
.setGroup(receipGroupPrefix + "_chests")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("barrel", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_BARREL))
|
||||
.checkConfig(config)
|
||||
.setShape("#S#", "# #", "#S#")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('S', getBlock(BLOCK_SLAB))
|
||||
.setGroup(receipGroupPrefix + "_barrels")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("bookshelf", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_BOOKSHELF))
|
||||
.checkConfig(config)
|
||||
.setShape("###", "PPP", "###")
|
||||
.addMaterial('#', planks)
|
||||
.addMaterial('P', Items.BOOK)
|
||||
.setGroup(receipGroupPrefix + "_bookshelves")
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("bark", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_BARK))
|
||||
.checkConfig(config)
|
||||
.setShape("##", "##")
|
||||
.addMaterial('#', getBlock(BLOCK_LOG))
|
||||
.setOutputCount(3)
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("log", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_LOG))
|
||||
.checkConfig(config)
|
||||
.setShape("##", "##")
|
||||
.addMaterial('#', getBlock(BLOCK_BARK))
|
||||
.setOutputCount(3)
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("stripped_bark", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_STRIPPED_BARK))
|
||||
.checkConfig(config)
|
||||
.setShape("##", "##")
|
||||
.addMaterial('#', getBlock(BLOCK_STRIPPED_LOG))
|
||||
.setOutputCount(3)
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("stripped_log", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_STRIPPED_LOG))
|
||||
.checkConfig(config)
|
||||
.setShape("##", "##")
|
||||
.addMaterial('#', getBlock(BLOCK_STRIPPED_BARK))
|
||||
.setOutputCount(3)
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("composter", (material, config, id) -> {
|
||||
GridRecipe.make(id, getBlock(BLOCK_COMPOSTER))
|
||||
.checkConfig(config)
|
||||
.setShape("# #", "# #", "###")
|
||||
.addMaterial('#', getBlock(BLOCK_SLAB))
|
||||
.build();
|
||||
}));
|
||||
addRecipeEntry(new RecipeEntry("shulker", (material, config, id) -> {
|
||||
GridRecipe.make(id, Blocks.SHULKER_BOX)
|
||||
.checkConfig(config)
|
||||
.setShape("S", "#", "S")
|
||||
.addMaterial('S', Items.SHULKER_SHELL)
|
||||
.addMaterial('#', getBlock(BLOCK_CHEST))
|
||||
.build();
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ package ru.bclib.complexmaterials.entry;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
import ru.bclib.complexmaterials.ComplexMaterial;
|
||||
import ru.bclib.config.PathConfig;
|
||||
import ru.bclib.util.TriConsumer;
|
||||
import ru.bclib.interfaces.TriConsumer;
|
||||
|
||||
public class RecipeEntry extends ComplexMaterialEntry {
|
||||
final TriConsumer<ComplexMaterial, PathConfig, ResourceLocation> initFunction;
|
||||
|
|
|
@ -12,7 +12,7 @@ public class Configs {
|
|||
public static final ServerConfig SERVER_CONFIG = new ServerConfig();
|
||||
|
||||
|
||||
public static final PathConfig GENERATOR_CONFIG = new PathConfig(BCLib.MOD_ID, "generator");
|
||||
public static final PathConfig GENERATOR_CONFIG = new PathConfig(BCLib.MOD_ID, "generator", false);
|
||||
public static final PathConfig MAIN_CONFIG = new PathConfig(BCLib.MOD_ID, "main", true, true);
|
||||
public static final String MAIN_PATCH_CATEGORY = "patches";
|
||||
|
||||
|
@ -23,5 +23,6 @@ public class Configs {
|
|||
public static void save() {
|
||||
MAIN_CONFIG.saveChanges();
|
||||
RECIPE_CONFIG.saveChanges();
|
||||
GENERATOR_CONFIG.saveChanges();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,11 @@ public class ServerConfig extends NamedPathConfig {
|
|||
public static final DependendConfigToken<Boolean> OFFER_FILES = DependendConfigToken.Boolean(true, "offerFiles", AutoSync.SYNC_CATEGORY, (config) -> config.get(ENABLED));
|
||||
public static final DependendConfigToken<Boolean> OFFER_MODS = DependendConfigToken.Boolean(true, "offerMods", AutoSync.SYNC_CATEGORY, (config) -> config.get(ENABLED));
|
||||
public static final DependendConfigToken<Boolean> OFFER_ALL_MODS = DependendConfigToken.Boolean(false, "offerAllMods", AutoSync.SYNC_CATEGORY, (config) -> config.get(OFFER_MODS));
|
||||
public static final DependendConfigToken<Boolean> SEND_ALL_MOD_INFO = DependendConfigToken.Boolean(true, "sendAllModInfo", AutoSync.SYNC_CATEGORY, (config) -> config.get(ENABLED));
|
||||
public static final DependendConfigToken<Boolean> SEND_ALL_MOD_INFO = DependendConfigToken.Boolean(false, "sendAllModInfo", AutoSync.SYNC_CATEGORY, (config) -> config.get(ENABLED));
|
||||
|
||||
|
||||
public static final ConfigToken<List<String>> ADDITIONAL_MODS = ConfigToken.StringArray(new ArrayList<>(0), "additionalMods", AutoSync.SYNC_CATEGORY);
|
||||
public static final ConfigToken<List<String>> EXCLUDED_MODS = ConfigToken.StringArray(new ArrayList<>(0), "excludeMods", AutoSync.SYNC_CATEGORY);
|
||||
|
||||
|
||||
public ServerConfig() {
|
||||
|
@ -45,8 +46,5 @@ public class ServerConfig extends NamedPathConfig {
|
|||
public boolean isOfferingInfosForMods() {
|
||||
return get(SEND_ALL_MOD_INFO) /*&& isAllowingAutoSync()*/;
|
||||
}
|
||||
|
||||
public String[] additionalModsForSync() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package ru.bclib.gui.gridlayout;
|
|||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import ru.bclib.util.TriConsumer;
|
||||
import ru.bclib.interfaces.TriConsumer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
|
|
@ -5,8 +5,8 @@ import net.fabricmc.api.EnvType;
|
|||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import ru.bclib.gui.gridlayout.GridLayout.GridValueType;
|
||||
import ru.bclib.interfaces.TriConsumer;
|
||||
import ru.bclib.util.Pair;
|
||||
import ru.bclib.util.TriConsumer;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -88,6 +88,7 @@ public class GridLayout extends GridColumn {
|
|||
public static final int COLOR_RED = 0xFFDB1F48;
|
||||
public static final int COLOR_CYAN = 0xFF01949A;
|
||||
public static final int COLOR_GREEN = 0xFF00FF00;
|
||||
public static final int COLOR_DARK_GREEN = 0xFF007F00;
|
||||
public static final int COLOR_YELLOW = 0xFFFAD02C;
|
||||
public static final int COLOR_BLUE = 0xFF0000FF;
|
||||
public static final int COLOR_GRAY = 0xFF7F7F7F;
|
||||
|
|
|
@ -9,8 +9,6 @@ import com.mojang.blaze3d.vertex.VertexFormat;
|
|||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.components.AbstractSelectionList;
|
||||
import net.minecraft.client.gui.components.OptionsList;
|
||||
import net.minecraft.client.gui.components.Widget;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package ru.bclib.gui.screens;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
|
|
60
src/main/java/ru/bclib/gui/screens/LevelFixErrorScreen.java
Normal file
60
src/main/java/ru/bclib/gui/screens/LevelFixErrorScreen.java
Normal file
|
@ -0,0 +1,60 @@
|
|||
package ru.bclib.gui.screens;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.CommonComponents;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import ru.bclib.gui.gridlayout.GridColumn;
|
||||
import ru.bclib.gui.gridlayout.GridLayout;
|
||||
import ru.bclib.gui.gridlayout.GridRow;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class LevelFixErrorScreen extends BCLibScreen {
|
||||
private final String[] errors;
|
||||
final Listener onContinue;
|
||||
|
||||
public LevelFixErrorScreen(Screen parent, String[] errors, Listener onContinue) {
|
||||
super(parent, new TranslatableComponent("title.bclib.datafixer.error"), 10, true);
|
||||
this.errors = errors;
|
||||
this.onContinue = onContinue;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
grid.addSpacerRow();
|
||||
grid.addRow().addMessage(new TranslatableComponent("message.bclib.datafixer.error"), font, GridLayout.Alignment.CENTER);
|
||||
grid.addSpacerRow(8);
|
||||
|
||||
GridRow row = grid.addRow();
|
||||
row.addSpacer(10);
|
||||
GridColumn col = row.addColumn(300, GridLayout.GridValueType.CONSTANT);
|
||||
for (String error : errors){
|
||||
TextComponent dash = new TextComponent("-");
|
||||
row = col.addRow();
|
||||
row.addString(dash, this);
|
||||
|
||||
row.addSpacer(4);
|
||||
row.addString(new TextComponent(error), this);
|
||||
}
|
||||
|
||||
grid.addSpacerRow(8);
|
||||
row = grid.addRow();
|
||||
row.addFiller();
|
||||
row.addButton(new TranslatableComponent("title.bclib.datafixer.error.continue"), 0.5f, 20, font, (n)-> {
|
||||
onClose();
|
||||
onContinue.doContinue(true);
|
||||
});
|
||||
row.addSpacer();
|
||||
row.addButton(CommonComponents.GUI_CANCEL, 20, font, (n)-> {
|
||||
this.minecraft.setScreen(null);
|
||||
});
|
||||
row.addFiller();
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public interface Listener {
|
||||
void doContinue(boolean markFixed);
|
||||
}
|
||||
}
|
|
@ -73,13 +73,14 @@ public class ModListScreen extends BCLibScreen {
|
|||
|
||||
|
||||
public static void addModDesc(GridColumn grid, java.util.List<ModUtil.ModInfo> mods, HelloClient.IServerModMap serverInfo, GridScreen parent) {
|
||||
final int STATE_OK = 0;
|
||||
final int STATE_MISSING = 1;
|
||||
final int STATE_SERVER_MISSING = 2;
|
||||
final int STATE_VERSION = 3;
|
||||
final int STATE_SERVER_MISSING_CLIENT_MOD = 4;
|
||||
final int STATE_VERSION_NOT_OFFERED = 5;
|
||||
final int STATE_MISSING_NOT_OFFERED = 6;
|
||||
final int STATE_OK = 6;
|
||||
final int STATE_SERVER_MISSING_CLIENT_MOD = 5;
|
||||
final int STATE_MISSING_NOT_OFFERED = 4;
|
||||
final int STATE_VERSION_NOT_OFFERED = 3;
|
||||
final int STATE_VERSION = 2;
|
||||
final int STATE_SERVER_MISSING = 1;
|
||||
final int STATE_MISSING = 0;
|
||||
|
||||
|
||||
List<Triple<String, Integer, String>> items = new LinkedList<>();
|
||||
if (serverInfo!=null) {
|
||||
|
@ -141,7 +142,7 @@ public class ModListScreen extends BCLibScreen {
|
|||
});
|
||||
|
||||
items.stream()
|
||||
.sorted(Comparator.comparing(a -> a.first.toLowerCase(Locale.ROOT)))
|
||||
.sorted(Comparator.comparing(a -> a.second + a.first.toLowerCase(Locale.ROOT)))
|
||||
.forEach(t -> {
|
||||
final String name = t.first;
|
||||
final int state = t.second;
|
||||
|
@ -160,12 +161,14 @@ public class ModListScreen extends BCLibScreen {
|
|||
color = GridLayout.COLOR_YELLOW;
|
||||
}
|
||||
} else if (state==STATE_SERVER_MISSING || state == STATE_SERVER_MISSING_CLIENT_MOD) {
|
||||
typeText = "[NOT ON SERVER]";
|
||||
if (state == STATE_SERVER_MISSING_CLIENT_MOD) {
|
||||
color = GridLayout.COLOR_YELLOW;
|
||||
color = GridLayout.COLOR_CYAN;
|
||||
typeText = "[OK]";
|
||||
} else {
|
||||
typeText = "[NOT ON SERVER]";
|
||||
}
|
||||
} else {
|
||||
color = GridLayout.COLOR_CYAN;
|
||||
color = GridLayout.COLOR_DARK_GREEN;
|
||||
typeText = "[OK]";
|
||||
}
|
||||
TextComponent dash = new TextComponent("-");
|
||||
|
@ -208,7 +211,6 @@ public class ModListScreen extends BCLibScreen {
|
|||
row.addFiller();
|
||||
row.addButton(buttonTitle, 20, font, (n)-> {
|
||||
onClose();
|
||||
System.out.println("Closing");
|
||||
});
|
||||
row.addFiller();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import net.minecraft.network.chat.Component;
|
|||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import ru.bclib.gui.gridlayout.GridLayout.Alignment;
|
||||
import ru.bclib.gui.gridlayout.GridRow;
|
||||
import ru.bclib.gui.gridlayout.GridScreen;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class WarnBCLibVersionMismatch extends BCLibScreen {
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package ru.bclib.interfaces;
|
||||
|
||||
|
||||
import ru.bclib.recipes.AnvilRecipe;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AnvilScreenHandlerExtended {
|
||||
void be_updateCurrentRecipe(AnvilRecipe recipe);
|
||||
|
||||
AnvilRecipe be_getCurrentRecipe();
|
||||
|
||||
List<AnvilRecipe> be_getRecipes();
|
||||
|
||||
default void be_nextRecipe() {
|
||||
List<AnvilRecipe> recipes = be_getRecipes();
|
||||
if (recipes.size() < 2) return;
|
||||
AnvilRecipe current = be_getCurrentRecipe();
|
||||
int i = recipes.indexOf(current) + 1;
|
||||
if (i >= recipes.size()) {
|
||||
i = 0;
|
||||
}
|
||||
be_updateCurrentRecipe(recipes.get(i));
|
||||
}
|
||||
|
||||
default void be_previousRecipe() {
|
||||
List<AnvilRecipe> recipes = be_getRecipes();
|
||||
if (recipes.size() < 2) return;
|
||||
AnvilRecipe current = be_getCurrentRecipe();
|
||||
int i = recipes.indexOf(current) - 1;
|
||||
if (i <= 0) {
|
||||
i = recipes.size() - 1;
|
||||
}
|
||||
be_updateCurrentRecipe(recipes.get(i));
|
||||
}
|
||||
}
|
8
src/main/java/ru/bclib/interfaces/BiomeSetter.java
Normal file
8
src/main/java/ru/bclib/interfaces/BiomeSetter.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
package ru.bclib.interfaces;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
|
||||
public interface BiomeSetter {
|
||||
public void bclib_setBiome(Biome biome, BlockPos pos);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package ru.bclib.util;
|
||||
package ru.bclib.interfaces;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface TriConsumer<A, B, C> {
|
|
@ -0,0 +1,4 @@
|
|||
package ru.bclib.interfaces;
|
||||
|
||||
public interface UnknownReceipBookCategory {
|
||||
}
|
21
src/main/java/ru/bclib/items/tool/BaseShearsItem.java
Normal file
21
src/main/java/ru/bclib/items/tool/BaseShearsItem.java
Normal file
|
@ -0,0 +1,21 @@
|
|||
package ru.bclib.items.tool;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.ShearsItem;
|
||||
import ru.bclib.api.TagAPI;
|
||||
|
||||
public class BaseShearsItem extends ShearsItem {
|
||||
public BaseShearsItem(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
public static boolean isShear(ItemStack itemStack, Item item){
|
||||
if (item == Items.SHEARS){
|
||||
return itemStack.is(item) | itemStack.is(TagAPI.ITEM_COMMON_SHEARS) || itemStack.is(TagAPI.ITEM_SHEARS);
|
||||
} else {
|
||||
return itemStack.is(item);
|
||||
}
|
||||
}
|
||||
}
|
95
src/main/java/ru/bclib/mixin/client/AnvilScreenMixin.java
Normal file
95
src/main/java/ru/bclib/mixin/client/AnvilScreenMixin.java
Normal file
|
@ -0,0 +1,95 @@
|
|||
package ru.bclib.mixin.client;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.components.EditBox;
|
||||
import net.minecraft.client.gui.screens.inventory.AnvilScreen;
|
||||
import net.minecraft.client.gui.screens.inventory.ItemCombinerScreen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.AnvilMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import ru.bclib.interfaces.AnvilScreenHandlerExtended;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(AnvilScreen.class)
|
||||
public class AnvilScreenMixin extends ItemCombinerScreen<AnvilMenu> {
|
||||
|
||||
@Shadow
|
||||
private EditBox name;
|
||||
|
||||
private final List<AbstractWidget> be_buttons = Lists.newArrayList();
|
||||
|
||||
public AnvilScreenMixin(AnvilMenu handler, Inventory playerInventory, Component title, ResourceLocation texture) {
|
||||
super(handler, playerInventory, title, texture);
|
||||
}
|
||||
|
||||
@Inject(method = "subInit", at = @At("TAIL"))
|
||||
protected void be_subInit(CallbackInfo info) {
|
||||
int x = (width - imageWidth) / 2;
|
||||
int y = (height - imageHeight) / 2;
|
||||
be_buttons.clear();
|
||||
be_buttons.add(new Button(x + 8, y + 45, 15, 20, new TextComponent("<"), b -> be_previousRecipe()));
|
||||
be_buttons.add(new Button(x + 154, y + 45, 15, 20, new TextComponent(">"), b -> be_nextRecipe()));
|
||||
}
|
||||
|
||||
@Inject(method = "renderFg", at = @At("TAIL"))
|
||||
protected void be_renderForeground(PoseStack matrices, int mouseX, int mouseY, float delta, CallbackInfo info) {
|
||||
be_buttons.forEach(button -> {
|
||||
button.render(matrices, mouseX, mouseY, delta);
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "slotChanged", at = @At("HEAD"), cancellable = true)
|
||||
public void be_onSlotUpdate(AbstractContainerMenu handler, int slotId, ItemStack stack, CallbackInfo info) {
|
||||
AnvilScreenHandlerExtended anvilHandler = (AnvilScreenHandlerExtended) handler;
|
||||
if (anvilHandler.be_getCurrentRecipe() != null) {
|
||||
if (anvilHandler.be_getRecipes().size() > 1) {
|
||||
be_buttons.forEach(button -> button.visible = true);
|
||||
}
|
||||
else {
|
||||
be_buttons.forEach(button -> button.visible = false);
|
||||
}
|
||||
name.setValue("");
|
||||
info.cancel();
|
||||
}
|
||||
else {
|
||||
be_buttons.forEach(button -> button.visible = false);
|
||||
}
|
||||
}
|
||||
|
||||
private void be_nextRecipe() {
|
||||
((AnvilScreenHandlerExtended) menu).be_nextRecipe();
|
||||
}
|
||||
|
||||
private void be_previousRecipe() {
|
||||
((AnvilScreenHandlerExtended) menu).be_previousRecipe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
if (minecraft != null) {
|
||||
for (AbstractWidget elem : be_buttons) {
|
||||
if (elem.visible && elem.mouseClicked(mouseX, mouseY, button)) {
|
||||
if (minecraft.gameMode != null) {
|
||||
int i = be_buttons.indexOf(elem);
|
||||
minecraft.gameMode.handleInventoryButtonClick(menu.containerId, i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.mouseClicked(mouseX, mouseY, button);
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ public class BackgroundRendererMixin {
|
|||
private static final MutableBlockPos BCLIB_LAST_POS = new MutableBlockPos(0, -100, 0);
|
||||
private static final MutableBlockPos BCLIB_MUT_POS = new MutableBlockPos();
|
||||
private static final float[] BCLIB_FOG_DENSITY = new float[8];
|
||||
//private static boolean isEnd;
|
||||
|
||||
@Shadow
|
||||
private static float fogRed;
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
package ru.bclib.mixin.client;public class ClientLevelMixin {
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package ru.bclib.mixin.client;
|
||||
|
||||
import net.minecraft.client.ClientRecipeBook;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import ru.bclib.interfaces.UnknownReceipBookCategory;
|
||||
|
||||
@Mixin(ClientRecipeBook.class)
|
||||
public abstract class ClientRecipeBookMixin {
|
||||
@Inject(method = "getCategory", at = @At("HEAD"), cancellable = true)
|
||||
private static void be_getGroupForRecipe(Recipe<?> recipe, CallbackInfoReturnable<RecipeBookCategories> info) {
|
||||
if (recipe instanceof UnknownReceipBookCategory) {
|
||||
info.setReturnValue(RecipeBookCategories.UNKNOWN);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package ru.bclib.mixin.client;
|
||||
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.network.protocol.game.ClientboundLoginPacket;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ClientboundLoginPacket.class)
|
||||
public abstract class ClientboundLoginPacketMixin {
|
||||
@Inject(method = "handle", cancellable = true, at=@At("HEAD"))
|
||||
public void bclib_handle(ClientGamePacketListener clientGamePacketListener, CallbackInfo ci){
|
||||
//cLevel.setBCLibDidSendHello();
|
||||
// DataExchangeAPI.sendOnEnter();
|
||||
// ci.cancel();
|
||||
}
|
||||
}
|
|
@ -100,8 +100,7 @@ public abstract class MinecraftMixin {
|
|||
DataExchangeAPI.prepareServerside();
|
||||
|
||||
if (DataFixerAPI.fixData(this.levelSource, levelID, true, (appliedFixes) -> {
|
||||
bclib_doLoadLevel_BACKUP(levelID, RegistryAccess.builtin(), Minecraft::loadDataPacks, Minecraft::loadWorldData, false);
|
||||
//this.doLoadLevel(levelID, RegistryAccess.builtin(), Minecraft::loadDataPacks, Minecraft::loadWorldData, false, Minecraft.ExperimentalDialogType.BACKUP);
|
||||
this.doLoadLevel(levelID, RegistryAccess.builtin(), Minecraft::loadDataPacks, Minecraft::loadWorldData, false, appliedFixes?ExperimentalDialogType.NONE:ExperimentalDialogType.BACKUP);
|
||||
})) {
|
||||
ci.cancel();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import net.minecraft.world.inventory.DataSlot;
|
|||
import net.minecraft.world.inventory.ItemCombinerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
|
@ -17,10 +19,22 @@ import org.spongepowered.asm.mixin.Shadow;
|
|||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import ru.bclib.blocks.BaseAnvilBlock;
|
||||
import ru.bclib.blocks.LeveledAnvilBlock;
|
||||
import ru.bclib.interfaces.AnvilScreenHandlerExtended;
|
||||
import ru.bclib.recipes.AnvilRecipe;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(AnvilMenu.class)
|
||||
public abstract class AnvilMenuMixin extends ItemCombinerMenu {
|
||||
public abstract class AnvilMenuMixin extends ItemCombinerMenu implements AnvilScreenHandlerExtended {
|
||||
private List<AnvilRecipe> be_recipes = Collections.emptyList();
|
||||
private AnvilRecipe be_currentRecipe;
|
||||
private DataSlot anvilLevel;
|
||||
|
||||
@Shadow
|
||||
private int repairItemCountCost;
|
||||
|
||||
|
@ -31,9 +45,64 @@ public abstract class AnvilMenuMixin extends ItemCombinerMenu {
|
|||
public AnvilMenuMixin(@Nullable MenuType<?> menuType, int i, Inventory inventory, ContainerLevelAccess containerLevelAccess) {
|
||||
super(menuType, i, inventory, containerLevelAccess);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/inventory/ContainerLevelAccess;)V", at = @At("TAIL"))
|
||||
public void be_initAnvilLevel(int syncId, Inventory inventory, ContainerLevelAccess context, CallbackInfo info) {
|
||||
this.anvilLevel = addDataSlot(DataSlot.standalone());
|
||||
if (context != ContainerLevelAccess.NULL) {
|
||||
int level = context.evaluate((world, blockPos) -> {
|
||||
Block anvilBlock = world.getBlockState(blockPos).getBlock();
|
||||
if (anvilBlock instanceof LeveledAnvilBlock) {
|
||||
return ((LeveledAnvilBlock) anvilBlock).getCraftingLevel();
|
||||
}
|
||||
return 1;
|
||||
}, 1);
|
||||
anvilLevel.set(level);
|
||||
}
|
||||
else {
|
||||
anvilLevel.set(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public abstract void createResult();
|
||||
|
||||
@Inject(method = "mayPickup", at = @At("HEAD"), cancellable = true)
|
||||
protected void be_canTakeOutput(Player player, boolean present, CallbackInfoReturnable<Boolean> info) {
|
||||
if (be_currentRecipe != null) {
|
||||
info.setReturnValue(be_currentRecipe.checkHammerDurability(inputSlots, player));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "onTake", at = @At("HEAD"), cancellable = true)
|
||||
protected void bclib_onTakeAnvilOutput(Player player, ItemStack stack, CallbackInfo info) {
|
||||
if (be_currentRecipe != null) {
|
||||
inputSlots.getItem(0).shrink(be_currentRecipe.getInputCount());
|
||||
stack = be_currentRecipe.craft(inputSlots, player);
|
||||
slotsChanged(inputSlots);
|
||||
access.execute((world, blockPos) -> {
|
||||
final BlockState anvilState = world.getBlockState(blockPos);
|
||||
final Block anvilBlock = anvilState.getBlock();
|
||||
if (anvilBlock instanceof BaseAnvilBlock) {
|
||||
final BaseAnvilBlock anvil = (BaseAnvilBlock) anvilBlock;
|
||||
if (!player.getAbilities().instabuild && anvilState.is(BlockTags.ANVIL) && player.getRandom().nextDouble() < 0.1) {
|
||||
BlockState damagedState = anvil.damageAnvilUse(anvilState, player.getRandom());
|
||||
if (damagedState == null) {
|
||||
world.removeBlock(blockPos, false);
|
||||
world.levelEvent(1029, blockPos, 0);
|
||||
} else {
|
||||
world.setBlock(blockPos, damagedState, 2);
|
||||
world.levelEvent(1030, blockPos, 0);
|
||||
}
|
||||
} else {
|
||||
world.levelEvent(1030, blockPos, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
info.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
this.access.execute((level, blockPos) -> {
|
||||
BlockState blockState = level.getBlockState(blockPos);
|
||||
if (blockState.getBlock() instanceof BaseAnvilBlock) {
|
||||
|
@ -77,4 +146,68 @@ public abstract class AnvilMenuMixin extends ItemCombinerMenu {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "createResult", at = @At("HEAD"), cancellable = true)
|
||||
public void be_updateOutput(CallbackInfo info) {
|
||||
RecipeManager recipeManager = this.player.level.getRecipeManager();
|
||||
be_recipes = recipeManager.getRecipesFor(AnvilRecipe.TYPE, inputSlots, player.level);
|
||||
if (be_recipes.size() > 0) {
|
||||
int anvilLevel = this.anvilLevel.get();
|
||||
be_recipes = be_recipes.stream()
|
||||
.filter(recipe -> anvilLevel >= recipe.getAnvilLevel())
|
||||
.collect(Collectors.toList());
|
||||
if (be_recipes.size() > 0) {
|
||||
if (be_currentRecipe == null || !be_recipes.contains(be_currentRecipe)) {
|
||||
be_currentRecipe = be_recipes.get(0);
|
||||
}
|
||||
be_updateResult();
|
||||
info.cancel();
|
||||
}
|
||||
else {
|
||||
be_currentRecipe = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "setItemName", at = @At("HEAD"), cancellable = true)
|
||||
public void be_setNewItemName(String string, CallbackInfo info) {
|
||||
if (be_currentRecipe != null) {
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clickMenuButton(Player player, int id) {
|
||||
if (id == 0) {
|
||||
be_previousRecipe();
|
||||
return true;
|
||||
}
|
||||
else if (id == 1) {
|
||||
be_nextRecipe();
|
||||
return true;
|
||||
}
|
||||
return super.clickMenuButton(player, id);
|
||||
}
|
||||
|
||||
private void be_updateResult() {
|
||||
if (be_currentRecipe == null) return;
|
||||
resultSlots.setItem(0, be_currentRecipe.assemble(inputSlots));
|
||||
broadcastChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void be_updateCurrentRecipe(AnvilRecipe recipe) {
|
||||
this.be_currentRecipe = recipe;
|
||||
be_updateResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnvilRecipe be_getCurrentRecipe() {
|
||||
return be_currentRecipe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AnvilRecipe> be_getRecipes() {
|
||||
return be_recipes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
package ru.bclib.mixin.common;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.BitStorage;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.chunk.ChunkBiomeContainer;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import ru.bclib.BCLib;
|
||||
import ru.bclib.interfaces.BiomeSetter;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
@Mixin(ChunkBiomeContainer.class)
|
||||
public class ChunkBiomeContainerMixin implements BiomeSetter {
|
||||
private static boolean bclib_hasHydrogen = FabricLoader.getInstance().isModLoaded("hydrogen");
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private Biome[] biomes;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private static int WIDTH_BITS;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private static int HORIZONTAL_MASK;
|
||||
|
||||
@Override
|
||||
public void bclib_setBiome(Biome biome, BlockPos pos) {
|
||||
int biomeX = pos.getX() >> 2;
|
||||
int biomeY = pos.getY() >> 2;
|
||||
int biomeZ = pos.getZ() >> 2;
|
||||
int index = be_getArrayIndex(biomeX, biomeY, biomeZ);
|
||||
|
||||
if (bclib_hasHydrogen && be_shouldWriteToHydrogen()) {
|
||||
try {
|
||||
ChunkBiomeContainer self = (ChunkBiomeContainer) (Object) this;
|
||||
BitStorage storage = be_getHydrogenStorage(self);
|
||||
Biome[] palette = be_getHydrogenPalette(self);
|
||||
int paletteIndex = be_getHydrogenPaletteIndex(biome, palette);
|
||||
if (paletteIndex == -1) {
|
||||
Biome[] newPalette = new Biome[palette.length + 1];
|
||||
System.arraycopy(palette, 0, newPalette, 0, palette.length);
|
||||
paletteIndex = palette.length;
|
||||
palette = newPalette;
|
||||
palette[paletteIndex] = biome;
|
||||
be_setHydrogenPalette(self, palette);
|
||||
}
|
||||
try {
|
||||
storage.set(index, paletteIndex);
|
||||
}
|
||||
catch (Exception e) {
|
||||
int size = storage.getSize();
|
||||
int bits = Mth.ceillog2(palette.length);
|
||||
BitStorage newStorage = new BitStorage(bits, size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
newStorage.set(i, storage.get(i));
|
||||
}
|
||||
storage = newStorage;
|
||||
storage.set(index, paletteIndex);
|
||||
be_setHydrogenStorage(self, storage);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
BCLib.LOGGER.warning(e.getLocalizedMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
biomes[index] = biome;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private int quartMinY;
|
||||
@Shadow
|
||||
@Final
|
||||
private int quartHeight;
|
||||
|
||||
private boolean be_shouldWriteToHydrogen() {
|
||||
try {
|
||||
Field field = ChunkBiomeContainer.class.getDeclaredField("intArray");
|
||||
return field != null;
|
||||
}
|
||||
catch (NoSuchFieldException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private int be_getArrayIndex(int biomeX, int biomeY, int biomeZ) {
|
||||
int i = biomeX & HORIZONTAL_MASK;
|
||||
int j = Mth.clamp(biomeY - this.quartMinY, 0, this.quartHeight);
|
||||
int k = biomeZ & HORIZONTAL_MASK;
|
||||
return j << WIDTH_BITS + WIDTH_BITS | k << WIDTH_BITS | i;
|
||||
}
|
||||
|
||||
private Field be_getField(String name) throws Exception {
|
||||
Field field = ChunkBiomeContainer.class.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
}
|
||||
|
||||
private BitStorage be_getHydrogenStorage(ChunkBiomeContainer container) throws Exception {
|
||||
return (BitStorage) be_getField("intArray").get(container);
|
||||
}
|
||||
|
||||
private Biome[] be_getHydrogenPalette(ChunkBiomeContainer container) throws Exception {
|
||||
return (Biome[]) be_getField("palette").get(container);
|
||||
}
|
||||
|
||||
private int be_getHydrogenPaletteIndex(Biome biome, Biome[] palette) {
|
||||
int index = -1;
|
||||
for (int i = 0; i < palette.length; i++) {
|
||||
if (palette[i] == biome) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private void be_setHydrogenPalette(ChunkBiomeContainer container, Biome[] palette) throws Exception {
|
||||
be_getField("palette").set(container, palette);
|
||||
}
|
||||
|
||||
private void be_setHydrogenStorage(ChunkBiomeContainer container, BitStorage storage) throws Exception {
|
||||
be_getField("intArray").set(container, storage);
|
||||
}
|
||||
}
|
31
src/main/java/ru/bclib/mixin/common/CraftingMenuMixin.java
Normal file
31
src/main/java/ru/bclib/mixin/common/CraftingMenuMixin.java
Normal file
|
@ -0,0 +1,31 @@
|
|||
package ru.bclib.mixin.common;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.ContainerLevelAccess;
|
||||
import net.minecraft.world.inventory.CraftingMenu;
|
||||
import net.minecraft.world.level.block.CraftingTableBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import ru.bclib.api.TagAPI;
|
||||
|
||||
@Mixin(CraftingMenu.class)
|
||||
public abstract class CraftingMenuMixin {
|
||||
@Final
|
||||
@Shadow
|
||||
private ContainerLevelAccess access;
|
||||
|
||||
@Inject(method = "stillValid", at = @At("HEAD"), cancellable = true)
|
||||
private void bclib_stillValid(Player player, CallbackInfoReturnable<Boolean> info) {
|
||||
if (access.evaluate((world, pos) -> {
|
||||
BlockState state = world.getBlockState(pos);
|
||||
return state.getBlock() instanceof CraftingTableBlock || state.is(TagAPI.BLOCK_WORKBENCHES);
|
||||
}, true)) {
|
||||
info.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,24 +12,29 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import ru.bclib.world.generator.BCLibEndBiomeSource;
|
||||
import ru.bclib.world.generator.BCLibNetherBiomeSource;
|
||||
import ru.bclib.world.generator.GeneratorOptions;
|
||||
|
||||
@Mixin(value = DimensionType.class, priority = 100)
|
||||
public class DimensionTypeMixin {
|
||||
@Inject(method = "defaultNetherGenerator", at = @At("HEAD"), cancellable = true)
|
||||
private static void be_replaceNetherBiomeSource(Registry<Biome> biomeRegistry, Registry<NoiseGeneratorSettings> chunkGeneratorSettingsRegistry, long seed, CallbackInfoReturnable<ChunkGenerator> info) {
|
||||
info.setReturnValue(new NoiseBasedChunkGenerator(
|
||||
new BCLibNetherBiomeSource(biomeRegistry, seed),
|
||||
seed,
|
||||
() -> chunkGeneratorSettingsRegistry.getOrThrow(NoiseGeneratorSettings.NETHER)
|
||||
));
|
||||
if (GeneratorOptions.customNetherBiomeSource()) {
|
||||
info.setReturnValue(new NoiseBasedChunkGenerator(
|
||||
new BCLibNetherBiomeSource(biomeRegistry, seed),
|
||||
seed,
|
||||
() -> chunkGeneratorSettingsRegistry.getOrThrow(NoiseGeneratorSettings.NETHER)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "defaultEndGenerator", at = @At("HEAD"), cancellable = true)
|
||||
private static void be_replaceEndBiomeSource(Registry<Biome> biomeRegistry, Registry<NoiseGeneratorSettings> chunkGeneratorSettingsRegistry, long seed, CallbackInfoReturnable<ChunkGenerator> info) {
|
||||
info.setReturnValue(new NoiseBasedChunkGenerator(
|
||||
new BCLibEndBiomeSource(biomeRegistry, seed),
|
||||
seed,
|
||||
() -> chunkGeneratorSettingsRegistry.getOrThrow(NoiseGeneratorSettings.END)
|
||||
));
|
||||
if (GeneratorOptions.customEndBiomeSource()) {
|
||||
info.setReturnValue(new NoiseBasedChunkGenerator(
|
||||
new BCLibEndBiomeSource(biomeRegistry, seed),
|
||||
seed,
|
||||
() -> chunkGeneratorSettingsRegistry.getOrThrow(NoiseGeneratorSettings.END)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package ru.bclib.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.piston.PistonBaseBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import ru.bclib.api.TagAPI;
|
||||
|
||||
@Mixin(PistonBaseBlock.class)
|
||||
public class PistonBaseBlockMixin {
|
||||
@Inject(method="isPushable", at=@At("HEAD"), cancellable = true)
|
||||
private static void bclib_isPushable(BlockState blockState, Level level, BlockPos blockPos, Direction direction, boolean bl, Direction direction2, CallbackInfoReturnable<Boolean> cir){
|
||||
if (blockState.is(TagAPI.BLOCK_IMMOBILE)){
|
||||
cir.setReturnValue(false);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
}
|
33
src/main/java/ru/bclib/mixin/common/PortalShapeMixin.java
Normal file
33
src/main/java/ru/bclib/mixin/common/PortalShapeMixin.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
package ru.bclib.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour.StatePredicate;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.portal.PortalShape;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import ru.bclib.api.TagAPI;
|
||||
|
||||
@Mixin(PortalShape.class)
|
||||
public class PortalShapeMixin {
|
||||
@Redirect(method="getDistanceUntilEdgeAboveFrame", at=@At(value="INVOKE", target="Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;test(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z"))
|
||||
private boolean be_getDistanceUntilEdgeAboveFrame(StatePredicate statePredicate, BlockState blockState, BlockGetter blockGetter, BlockPos blockPos){
|
||||
return be_FRAME(statePredicate, blockState, blockGetter, blockPos);
|
||||
}
|
||||
|
||||
@Redirect(method="hasTopFrame", at=@At(value="INVOKE", target="Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;test(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z"))
|
||||
private boolean be_hasTopFrame(StatePredicate statePredicate, BlockState blockState, BlockGetter blockGetter, BlockPos blockPos){
|
||||
return be_FRAME(statePredicate, blockState, blockGetter, blockPos);
|
||||
}
|
||||
|
||||
@Redirect(method="getDistanceUntilTop", at=@At(value="INVOKE", target="Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;test(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z"))
|
||||
private boolean be_getDistanceUntilTop(StatePredicate statePredicate, BlockState blockState, BlockGetter blockGetter, BlockPos blockPos){
|
||||
return be_FRAME(statePredicate, blockState, blockGetter, blockPos);
|
||||
}
|
||||
|
||||
private static boolean be_FRAME(StatePredicate FRAME, BlockState state, BlockGetter getter, BlockPos pos){
|
||||
return state.is(TagAPI.BLOCK_NETHER_PORTAL_FRAME) || FRAME.test(state, getter, pos);
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ public abstract class ServerLevelMixin extends Level {
|
|||
@Inject(method = "<init>*", at = @At("TAIL"))
|
||||
private void bclib_onServerWorldInit(MinecraftServer server, Executor workerExecutor, LevelStorageSource.LevelStorageAccess session, ServerLevelData properties, ResourceKey<Level> registryKey, DimensionType dimensionType, ChunkProgressListener worldGenerationProgressListener, ChunkGenerator chunkGenerator, boolean debugWorld, long l, List<CustomSpawner> list, boolean bl, CallbackInfo info) {
|
||||
BiomeAPI.initRegistry(server);
|
||||
BiomeAPI.applyModifications(ServerLevel.class.cast(this));
|
||||
|
||||
if (bclib_lastWorld != null && bclib_lastWorld.equals(session.getLevelId())) {
|
||||
return;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package ru.bclib.mixin.common.shears;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.BeehiveBlock;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import ru.bclib.items.tool.BaseShearsItem;
|
||||
|
||||
@Mixin(BeehiveBlock.class)
|
||||
public class BeehiveBlockMixin {
|
||||
@Redirect(method="use", at=@At(value="INVOKE", target="Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z"))
|
||||
public boolean bn_useProxy(ItemStack itemStack, Item item){
|
||||
return BaseShearsItem.isShear(itemStack, item);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package ru.bclib.mixin.common.shears;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.enchantment.DiggingEnchantment;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import ru.bclib.items.tool.BaseShearsItem;
|
||||
|
||||
@Mixin(DiggingEnchantment.class)
|
||||
public class DiggingEnchantmentMixin {
|
||||
@Redirect(method="canEnchant", at=@At(value="INVOKE", target="Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z"))
|
||||
public boolean bn_mobInteractProxy(ItemStack itemStack, Item item){
|
||||
return BaseShearsItem.isShear(itemStack, item);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package ru.bclib.mixin.common.shears;
|
||||
|
||||
import net.minecraft.world.entity.animal.MushroomCow;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import ru.bclib.items.tool.BaseShearsItem;
|
||||
|
||||
@Mixin(MushroomCow.class)
|
||||
public class MushroomCowMixin {
|
||||
@Redirect(method="mobInteract", at=@At(value="INVOKE", target="Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z"))
|
||||
public boolean bn_mobInteractProxy(ItemStack itemStack, Item item){
|
||||
return BaseShearsItem.isShear(itemStack, item);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package ru.bclib.mixin.common.shears;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.PumpkinBlock;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import ru.bclib.items.tool.BaseShearsItem;
|
||||
|
||||
@Mixin(PumpkinBlock.class)
|
||||
public abstract class PumpkinBlockMixin {
|
||||
@Redirect(method="use", at=@At(value="INVOKE", target="Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z"))
|
||||
public boolean bn_useProxy(ItemStack itemStack, Item item){
|
||||
return BaseShearsItem.isShear(itemStack, item);
|
||||
}
|
||||
}
|
17
src/main/java/ru/bclib/mixin/common/shears/SheepMixin.java
Normal file
17
src/main/java/ru/bclib/mixin/common/shears/SheepMixin.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package ru.bclib.mixin.common.shears;
|
||||
|
||||
import net.minecraft.world.entity.animal.Sheep;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import ru.bclib.items.tool.BaseShearsItem;
|
||||
|
||||
@Mixin(Sheep.class)
|
||||
public class SheepMixin {
|
||||
@Redirect(method="mobInteract", at=@At(value="INVOKE", target="Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z"))
|
||||
public boolean bn_mobInteractProxy(ItemStack itemStack, Item item){
|
||||
return BaseShearsItem.isShear(itemStack, item);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package ru.bclib.mixin.common.shears;
|
||||
|
||||
import net.minecraft.world.entity.animal.SnowGolem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import ru.bclib.items.tool.BaseShearsItem;
|
||||
|
||||
@Mixin(SnowGolem.class)
|
||||
public class SnowGolemMixin {
|
||||
@Redirect(method="mobInteract", at=@At(value="INVOKE", target="Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z"))
|
||||
public boolean bn_mobInteractProxy(ItemStack itemStack, Item item){
|
||||
return BaseShearsItem.isShear(itemStack, item);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package ru.bclib.mixin.common.shears;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.TripWireBlock;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import ru.bclib.items.tool.BaseShearsItem;
|
||||
|
||||
@Mixin(TripWireBlock.class)
|
||||
public class TripWireBlockMixin {
|
||||
@Redirect(method="playerWillDestroy", at=@At(value="INVOKE", target="Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z"))
|
||||
public boolean bn_useProxy(ItemStack itemStack, Item item){
|
||||
return BaseShearsItem.isShear(itemStack, item);
|
||||
}
|
||||
}
|
334
src/main/java/ru/bclib/recipes/AnvilRecipe.java
Normal file
334
src/main/java/ru/bclib/recipes/AnvilRecipe.java
Normal file
|
@ -0,0 +1,334 @@
|
|||
package ru.bclib.recipes;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.TagParser;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.Tag;
|
||||
import net.minecraft.util.GsonHelper;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TieredItem;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
import net.minecraft.world.item.crafting.RecipeType;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.Level;
|
||||
import ru.bclib.BCLib;
|
||||
import ru.bclib.api.TagAPI;
|
||||
import ru.bclib.config.PathConfig;
|
||||
import ru.bclib.interfaces.UnknownReceipBookCategory;
|
||||
import ru.bclib.util.ItemUtil;
|
||||
import ru.bclib.util.RecipeHelper;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class AnvilRecipe implements Recipe<Container>, UnknownReceipBookCategory {
|
||||
public final static String GROUP = "smithing";
|
||||
public final static RecipeType<AnvilRecipe> TYPE = BCLRecipeManager.registerType(BCLib.MOD_ID, GROUP);
|
||||
public final static Serializer SERIALIZER = BCLRecipeManager.registerSerializer(
|
||||
BCLib.MOD_ID,
|
||||
GROUP,
|
||||
new Serializer()
|
||||
);
|
||||
public final static ResourceLocation ID = BCLib.makeID(GROUP);
|
||||
|
||||
private final ResourceLocation id;
|
||||
private final Ingredient input;
|
||||
private final ItemStack output;
|
||||
private final int damage;
|
||||
private final int toolLevel;
|
||||
private final int anvilLevel;
|
||||
private final int inputCount;
|
||||
|
||||
public AnvilRecipe(ResourceLocation identifier, Ingredient input, ItemStack output, int inputCount, int toolLevel, int anvilLevel, int damage) {
|
||||
this.id = identifier;
|
||||
this.input = input;
|
||||
this.output = output;
|
||||
this.toolLevel = toolLevel;
|
||||
this.anvilLevel = anvilLevel;
|
||||
this.inputCount = inputCount;
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
public static Builder create(String id) {
|
||||
return create(BCLib.makeID(id));
|
||||
}
|
||||
|
||||
public static Builder create(ResourceLocation id) {
|
||||
Builder.INSTANCE.id = id;
|
||||
Builder.INSTANCE.input = null;
|
||||
Builder.INSTANCE.output = null;
|
||||
Builder.INSTANCE.inputCount = 1;
|
||||
Builder.INSTANCE.toolLevel = 1;
|
||||
Builder.INSTANCE.anvilLevel = 1;
|
||||
Builder.INSTANCE.damage = 1;
|
||||
Builder.INSTANCE.alright = true;
|
||||
Builder.INSTANCE.exist = true;
|
||||
|
||||
return Builder.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeSerializer<?> getSerializer() {
|
||||
return SERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getResultItem() {
|
||||
return this.output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Container craftingInventory, Level world) {
|
||||
return this.matches(craftingInventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack assemble(Container craftingInventory) {
|
||||
return this.output.copy();
|
||||
}
|
||||
|
||||
public ItemStack craft(Container craftingInventory, Player player) {
|
||||
if (!player.isCreative()) {
|
||||
if (!checkHammerDurability(craftingInventory, player)) return ItemStack.EMPTY;
|
||||
ItemStack hammer = craftingInventory.getItem(1);
|
||||
hammer.hurtAndBreak(this.damage, player, entity -> entity.broadcastBreakEvent((InteractionHand) null));
|
||||
}
|
||||
return this.assemble(craftingInventory);
|
||||
}
|
||||
|
||||
public boolean checkHammerDurability(Container craftingInventory, Player player) {
|
||||
if (player.isCreative()) return true;
|
||||
ItemStack hammer = craftingInventory.getItem(1);
|
||||
int damage = hammer.getDamageValue() + this.damage;
|
||||
return damage < hammer.getMaxDamage();
|
||||
}
|
||||
|
||||
public boolean matches(Container craftingInventory) {
|
||||
ItemStack hammer = craftingInventory.getItem(1);
|
||||
if (hammer.isEmpty() || !TagAPI.ITEM_HAMMERS.contains(hammer.getItem())) {
|
||||
return false;
|
||||
}
|
||||
ItemStack material = craftingInventory.getItem(0);
|
||||
int materialCount = material.getCount();
|
||||
int level = ((TieredItem) hammer.getItem()).getTier().getLevel();
|
||||
return this.input.test(craftingInventory.getItem(0)) && materialCount >= this.inputCount && level >= this.toolLevel;
|
||||
}
|
||||
|
||||
public int getDamage() {
|
||||
return this.damage;
|
||||
}
|
||||
|
||||
public int getInputCount() {
|
||||
return this.inputCount;
|
||||
}
|
||||
|
||||
public int getAnvilLevel() {
|
||||
return this.anvilLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NonNullList<Ingredient> getIngredients() {
|
||||
NonNullList<Ingredient> defaultedList = NonNullList.create();
|
||||
defaultedList.add(Ingredient.of(TagAPI.ITEM_HAMMERS.getValues()
|
||||
.stream()
|
||||
.filter(hammer -> ((TieredItem) hammer).getTier()
|
||||
.getLevel() >= toolLevel)
|
||||
.map(ItemStack::new)));
|
||||
defaultedList.add(input);
|
||||
|
||||
return defaultedList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public boolean canCraftInDimensions(int width, int height) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeType<?> getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSpecial() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
AnvilRecipe that = (AnvilRecipe) o;
|
||||
return damage == that.damage && toolLevel == that.toolLevel && id.equals(that.id) && input.equals(that.input) && output
|
||||
.equals(that.output);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, input, output, damage, toolLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AnvilRecipe [" + id + "]";
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final static Builder INSTANCE = new Builder();
|
||||
|
||||
private ResourceLocation id;
|
||||
private Ingredient input;
|
||||
private ItemStack output;
|
||||
private int inputCount = 1;
|
||||
private int toolLevel = 1;
|
||||
private int anvilLevel = 1;
|
||||
private int damage = 1;
|
||||
private boolean alright;
|
||||
private boolean exist;
|
||||
|
||||
private Builder() { }
|
||||
|
||||
public Builder setInput(ItemLike... inputItems) {
|
||||
this.alright &= RecipeHelper.exists(inputItems);
|
||||
this.setInput(Ingredient.of(inputItems));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setInput(Tag<Item> inputTag) {
|
||||
this.setInput(Ingredient.of(inputTag));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setInput(Ingredient ingredient) {
|
||||
this.input = ingredient;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setInputCount(int count) {
|
||||
this.inputCount = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setOutput(ItemLike output) {
|
||||
return this.setOutput(output, 1);
|
||||
}
|
||||
|
||||
public Builder setOutput(ItemLike output, int amount) {
|
||||
this.alright &= RecipeHelper.exists(output);
|
||||
this.output = new ItemStack(output, amount);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setToolLevel(int level) {
|
||||
this.toolLevel = level;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAnvilLevel(int level) {
|
||||
this.anvilLevel = level;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDamage(int damage) {
|
||||
this.damage = damage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder checkConfig(PathConfig config) {
|
||||
exist |= config.getBoolean("anvil", id.getPath(), true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void build() {
|
||||
if (exist) {
|
||||
if (input == null) {
|
||||
BCLib.LOGGER.warning("Input for Anvil recipe can't be 'null', recipe {} will be ignored!", id);
|
||||
return;
|
||||
}
|
||||
if (output == null) {
|
||||
BCLib.LOGGER.warning("Output for Anvil recipe can't be 'null', recipe {} will be ignored!", id);
|
||||
return;
|
||||
}
|
||||
if (BCLRecipeManager.getRecipe(TYPE, id) != null) {
|
||||
BCLib.LOGGER.warning("Can't add Anvil recipe! Id {} already exists!", id);
|
||||
return;
|
||||
}
|
||||
if (!alright) {
|
||||
BCLib.LOGGER.debug("Can't add Anvil recipe {}! Ingeredient or output not exists.", id);
|
||||
return;
|
||||
}
|
||||
BCLRecipeManager.addRecipe(
|
||||
TYPE,
|
||||
new AnvilRecipe(id, input, output, inputCount, toolLevel, anvilLevel, damage)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Serializer implements RecipeSerializer<AnvilRecipe> {
|
||||
@Override
|
||||
public AnvilRecipe fromJson(ResourceLocation id, JsonObject json) {
|
||||
Ingredient input = Ingredient.fromJson(json.get("input"));
|
||||
JsonObject result = GsonHelper.getAsJsonObject(json, "result");
|
||||
ItemStack output = ItemUtil.fromJsonRecipe(result);
|
||||
if (output == null) {
|
||||
throw new IllegalStateException("Output item does not exists!");
|
||||
}
|
||||
if (result.has("nbt")) {
|
||||
try {
|
||||
String nbtData = GsonHelper.getAsString(result, "nbt");
|
||||
CompoundTag nbt = TagParser.parseTag(nbtData);
|
||||
output.setTag(nbt);
|
||||
}
|
||||
catch (CommandSyntaxException ex) {
|
||||
BCLib.LOGGER.warning("Error parse nbt data for output.", ex);
|
||||
}
|
||||
}
|
||||
int inputCount = GsonHelper.getAsInt(json, "inputCount", 1);
|
||||
int toolLevel = GsonHelper.getAsInt(json, "toolLevel", 1);
|
||||
int anvilLevel = GsonHelper.getAsInt(json, "anvilLevel", 1);
|
||||
int damage = GsonHelper.getAsInt(json, "damage", 1);
|
||||
|
||||
return new AnvilRecipe(id, input, output, inputCount, toolLevel, anvilLevel, damage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnvilRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf packetBuffer) {
|
||||
Ingredient input = Ingredient.fromNetwork(packetBuffer);
|
||||
ItemStack output = packetBuffer.readItem();
|
||||
int inputCount = packetBuffer.readVarInt();
|
||||
int toolLevel = packetBuffer.readVarInt();
|
||||
int anvilLevel = packetBuffer.readVarInt();
|
||||
int damage = packetBuffer.readVarInt();
|
||||
|
||||
return new AnvilRecipe(id, input, output, inputCount, toolLevel, anvilLevel, damage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toNetwork(FriendlyByteBuf packetBuffer, AnvilRecipe recipe) {
|
||||
recipe.input.toNetwork(packetBuffer);
|
||||
packetBuffer.writeItem(recipe.output);
|
||||
packetBuffer.writeVarInt(recipe.inputCount);
|
||||
packetBuffer.writeVarInt(recipe.toolLevel);
|
||||
packetBuffer.writeVarInt(recipe.anvilLevel);
|
||||
packetBuffer.writeVarInt(recipe.damage);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,37 +3,55 @@ package ru.bclib.registry;
|
|||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.Items;
|
||||
import ru.bclib.BCLib;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import ru.bclib.config.PathConfig;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class BaseRegistry<T> {
|
||||
private static final List<BaseRegistry<?>> REGISTRIES = Lists.newArrayList();
|
||||
private static final Map<String, List<Item>> MOD_BLOCKS = Maps.newHashMap();
|
||||
private static final Map<String, List<Item>> MOD_BLOCK_ITEMS = Maps.newHashMap();
|
||||
private static final Map<String, List<Block>> MOD_BLOCKS = Maps.newHashMap();
|
||||
private static final Map<String, List<Item>> MOD_ITEMS = Maps.newHashMap();
|
||||
|
||||
protected final CreativeModeTab creativeTab;
|
||||
protected final PathConfig config;
|
||||
|
||||
protected BaseRegistry(CreativeModeTab creativeTab, PathConfig config) {
|
||||
this.creativeTab = creativeTab;
|
||||
this.config = config;
|
||||
REGISTRIES.add(this);
|
||||
}
|
||||
|
||||
public abstract T register(ResourceLocation objId, T obj);
|
||||
|
||||
public abstract void registerItem(ResourceLocation id, Item item);
|
||||
|
||||
public FabricItemSettings makeItemSettings() {
|
||||
FabricItemSettings properties = new FabricItemSettings();
|
||||
return (FabricItemSettings) properties.tab(creativeTab);
|
||||
}
|
||||
|
||||
private void registerInternal() {}
|
||||
|
||||
public static Map<String, List<Item>> getRegisteredBlocks() {
|
||||
return MOD_BLOCKS;
|
||||
return MOD_BLOCK_ITEMS;
|
||||
}
|
||||
|
||||
public static Map<String, List<Item>> getRegisteredItems() {
|
||||
return MOD_ITEMS;
|
||||
}
|
||||
|
||||
public static List<Item> getModBlocks(String modId) {
|
||||
if (MOD_BLOCKS.containsKey(modId)) {
|
||||
return MOD_BLOCKS.get(modId);
|
||||
public static List<Item> getModBlockItems(String modId) {
|
||||
if (MOD_BLOCK_ITEMS.containsKey(modId)) {
|
||||
return MOD_BLOCK_ITEMS.get(modId);
|
||||
}
|
||||
List<Item> modBlocks = Lists.newArrayList();
|
||||
MOD_BLOCKS.put(modId, modBlocks);
|
||||
MOD_BLOCK_ITEMS.put(modId, modBlocks);
|
||||
return modBlocks;
|
||||
}
|
||||
|
||||
|
@ -46,36 +64,16 @@ public abstract class BaseRegistry<T> {
|
|||
return modBlocks;
|
||||
}
|
||||
|
||||
public static List<Block> getModBlocks(String modId) {
|
||||
if (MOD_BLOCKS.containsKey(modId)) {
|
||||
return MOD_BLOCKS.get(modId);
|
||||
}
|
||||
List<Block> modBlocks = Lists.newArrayList();
|
||||
MOD_BLOCKS.put(modId, modBlocks);
|
||||
return modBlocks;
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
REGISTRIES.forEach(BaseRegistry::registerInternal);
|
||||
}
|
||||
|
||||
protected BaseRegistry(CreativeModeTab creativeTab) {
|
||||
this.creativeTab = creativeTab;
|
||||
REGISTRIES.add(this);
|
||||
}
|
||||
|
||||
public T register(String name, T obj) {
|
||||
return register(createModId(name), obj);
|
||||
}
|
||||
|
||||
public abstract T register(ResourceLocation objId, T obj);
|
||||
|
||||
public ResourceLocation createModId(String name) {
|
||||
return BCLib.makeID(name);
|
||||
}
|
||||
|
||||
public void registerItem(ResourceLocation id, Item item, List<Item> registry) {
|
||||
if (item != Items.AIR) {
|
||||
Registry.register(Registry.ITEM, id, item);
|
||||
registry.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public FabricItemSettings makeItemSettings() {
|
||||
FabricItemSettings properties = new FabricItemSettings();
|
||||
return (FabricItemSettings) properties.tab(creativeTab);
|
||||
}
|
||||
|
||||
private void registerInternal() {}
|
||||
}
|
||||
|
|
|
@ -6,16 +6,25 @@ import net.minecraft.resources.ResourceLocation;
|
|||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import ru.bclib.api.TagAPI;
|
||||
import ru.bclib.blocks.BaseLeavesBlock;
|
||||
import ru.bclib.blocks.FeatureSaplingBlock;
|
||||
import ru.bclib.config.PathConfig;
|
||||
import ru.bclib.interfaces.CustomItemProvider;
|
||||
|
||||
public abstract class BlockRegistry extends BaseRegistry<Block> {
|
||||
protected BlockRegistry(CreativeModeTab creativeTab) {
|
||||
super(creativeTab);
|
||||
public class BlockRegistry extends BaseRegistry<Block> {
|
||||
public BlockRegistry(CreativeModeTab creativeTab, PathConfig config) {
|
||||
super(creativeTab, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block register(ResourceLocation id, Block block) {
|
||||
if (!config.getBooleanRoot(id.getNamespace(), true)) {
|
||||
return block;
|
||||
}
|
||||
|
||||
BlockItem item = null;
|
||||
if (block instanceof CustomItemProvider) {
|
||||
item = ((CustomItemProvider) block).getCustomItem(id, makeItemSettings());
|
||||
|
@ -24,20 +33,46 @@ public abstract class BlockRegistry extends BaseRegistry<Block> {
|
|||
item = new BlockItem(block, makeItemSettings());
|
||||
}
|
||||
registerBlockItem(id, item);
|
||||
if (block.defaultBlockState().getMaterial().isFlammable() && FlammableBlockRegistry.getDefaultInstance()
|
||||
.get(block)
|
||||
.getBurnChance() == 0) {
|
||||
if (block.defaultBlockState().getMaterial().isFlammable() && FlammableBlockRegistry.getDefaultInstance().get(block).getBurnChance() == 0) {
|
||||
FlammableBlockRegistry.getDefaultInstance().add(block, 5, 5);
|
||||
}
|
||||
return Registry.register(Registry.BLOCK, id, block);
|
||||
|
||||
block = Registry.register(Registry.BLOCK, id, block);
|
||||
getModBlocks(id.getNamespace()).add(block);
|
||||
|
||||
if (block instanceof BaseLeavesBlock){
|
||||
TagAPI.addTags(block, TagAPI.BLOCK_LEAVES);
|
||||
if (item != null){
|
||||
TagAPI.addTags(item, TagAPI.ITEM_LEAVES);
|
||||
}
|
||||
} else if (block instanceof FeatureSaplingBlock){
|
||||
TagAPI.addTags(block, TagAPI.BLOCK_SAPLINGS);
|
||||
if (item != null){
|
||||
TagAPI.addTags(item, TagAPI.ITEM_SAPLINGS);
|
||||
}
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
public Block registerBlockOnly(ResourceLocation id, Block block) {
|
||||
if (!config.getBooleanRoot(id.getNamespace(), true)) {
|
||||
return block;
|
||||
}
|
||||
getModBlocks(id.getNamespace()).add(block);
|
||||
return Registry.register(Registry.BLOCK, id, block);
|
||||
}
|
||||
|
||||
private Item registerBlockItem(ResourceLocation id, Item item) {
|
||||
registerItem(id, item, BaseRegistry.getModBlocks(id.getNamespace()));
|
||||
registerItem(id, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerItem(ResourceLocation id, Item item) {
|
||||
if (item != null && item != Items.AIR) {
|
||||
Registry.register(Registry.ITEM, id, item);
|
||||
getModBlockItems(id.getNamespace()).add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ package ru.bclib.registry;
|
|||
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||
import net.minecraft.core.BlockSource;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
|
||||
import net.minecraft.core.dispenser.ShearsDispenseItemBehavior;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.tags.Tag;
|
||||
|
@ -15,12 +17,13 @@ import net.minecraft.world.food.FoodProperties;
|
|||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.ShovelItem;
|
||||
import net.minecraft.world.item.SpawnEggItem;
|
||||
import net.minecraft.world.item.SwordItem;
|
||||
import net.minecraft.world.item.TieredItem;
|
||||
import net.minecraft.world.level.block.DispenserBlock;
|
||||
import ru.bclib.api.TagAPI;
|
||||
import ru.bclib.config.PathConfig;
|
||||
import ru.bclib.items.BaseDiscItem;
|
||||
import ru.bclib.items.BaseDrinkItem;
|
||||
import ru.bclib.items.BaseSpawnEggItem;
|
||||
|
@ -28,30 +31,44 @@ import ru.bclib.items.ModelProviderItem;
|
|||
import ru.bclib.items.tool.BaseAxeItem;
|
||||
import ru.bclib.items.tool.BaseHoeItem;
|
||||
import ru.bclib.items.tool.BasePickaxeItem;
|
||||
import ru.bclib.items.tool.BaseShearsItem;
|
||||
|
||||
public abstract class ItemRegistry extends BaseRegistry<Item> {
|
||||
|
||||
protected ItemRegistry(CreativeModeTab creativeTab) {
|
||||
super(creativeTab);
|
||||
public class ItemRegistry extends BaseRegistry<Item> {
|
||||
public ItemRegistry(CreativeModeTab creativeTab, PathConfig config) {
|
||||
super(creativeTab, config);
|
||||
}
|
||||
|
||||
public Item registerDisc(String name, int power, SoundEvent sound) {
|
||||
return register(name, new BaseDiscItem(power, sound, makeItemSettings().stacksTo(1)));
|
||||
public Item registerDisc(ResourceLocation itemId, int power, SoundEvent sound) {
|
||||
BaseDiscItem item = new BaseDiscItem(power, sound, makeItemSettings().stacksTo(1));
|
||||
|
||||
if (!config.getBoolean("musicDiscs", itemId.getPath(), true)) {
|
||||
return item;
|
||||
}
|
||||
|
||||
return register(itemId, new BaseDiscItem(power, sound, makeItemSettings().stacksTo(1)));
|
||||
}
|
||||
|
||||
public Item registerItem(String name) {
|
||||
return register(name, new ModelProviderItem(makeItemSettings()));
|
||||
public Item register(ResourceLocation itemId) {
|
||||
return register(itemId, new ModelProviderItem(makeItemSettings()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item register(ResourceLocation itemId, Item item) {
|
||||
registerItem(itemId, item, BaseRegistry.getModItems(itemId.getNamespace()));
|
||||
if (!config.getBoolean("items", itemId.getPath(), true)) {
|
||||
return item;
|
||||
}
|
||||
|
||||
registerItem(itemId, item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public TieredItem registerTool(String name, TieredItem item) {
|
||||
ResourceLocation id = createModId(name);
|
||||
registerItem(id, item, BaseRegistry.getModItems(id.getNamespace()));
|
||||
public Item registerTool(ResourceLocation itemId, Item item) {
|
||||
if (!config.getBoolean("tools", itemId.getPath(), true)) {
|
||||
return item;
|
||||
}
|
||||
|
||||
registerItem(itemId, item);
|
||||
|
||||
if (item instanceof ShovelItem) {
|
||||
TagAPI.addTag((Tag.Named<Item>) FabricToolTags.SHOVELS, item);
|
||||
|
@ -68,12 +85,21 @@ public abstract class ItemRegistry extends BaseRegistry<Item> {
|
|||
else if (item instanceof BaseHoeItem) {
|
||||
TagAPI.addTag((Tag.Named<Item>) FabricToolTags.HOES, item);
|
||||
}
|
||||
else if (item instanceof BaseShearsItem) {
|
||||
TagAPI.addTags(item, (Tag.Named<Item>) FabricToolTags.SHEARS, TagAPI.ITEM_SHEARS, TagAPI.ITEM_COMMON_SHEARS);
|
||||
DispenserBlock.registerBehavior(item.asItem(), new ShearsDispenseItemBehavior());
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public Item registerEgg(String name, EntityType<? extends Mob> type, int background, int dots) {
|
||||
public Item registerEgg(ResourceLocation itemId, EntityType<? extends Mob> type, int background, int dots) {
|
||||
SpawnEggItem item = new BaseSpawnEggItem(type, background, dots, makeItemSettings());
|
||||
|
||||
if (!config.getBoolean("spawnEggs", itemId.getPath(), true)) {
|
||||
return item;
|
||||
}
|
||||
|
||||
DefaultDispenseItemBehavior behavior = new DefaultDispenseItemBehavior() {
|
||||
public ItemStack execute(BlockSource pointer, ItemStack stack) {
|
||||
Direction direction = pointer.getBlockState().getValue(DispenserBlock.FACING);
|
||||
|
@ -92,31 +118,42 @@ public abstract class ItemRegistry extends BaseRegistry<Item> {
|
|||
}
|
||||
};
|
||||
DispenserBlock.registerBehavior(item, behavior);
|
||||
return register(name, item);
|
||||
return register(itemId, item);
|
||||
}
|
||||
|
||||
public Item registerFood(String name, int hunger, float saturation, MobEffectInstance... effects) {
|
||||
public Item registerFood(ResourceLocation itemId, int hunger, float saturation, MobEffectInstance... effects) {
|
||||
FoodProperties.Builder builder = new FoodProperties.Builder().nutrition(hunger).saturationMod(saturation);
|
||||
for (MobEffectInstance effect : effects) {
|
||||
builder.effect(effect, 1F);
|
||||
}
|
||||
return registerFood(name, builder.build());
|
||||
return registerFood(itemId, builder.build());
|
||||
}
|
||||
|
||||
public Item registerFood(String name, FoodProperties foodComponent) {
|
||||
return register(name, new ModelProviderItem(makeItemSettings().food(foodComponent)));
|
||||
public Item registerFood(ResourceLocation itemId, FoodProperties foodComponent) {
|
||||
return register(itemId, new ModelProviderItem(makeItemSettings().food(foodComponent)));
|
||||
}
|
||||
|
||||
public Item registerDrink(String name) {
|
||||
return register(name, new BaseDrinkItem(makeItemSettings().stacksTo(1)));
|
||||
public Item registerDrink(ResourceLocation itemId, FoodProperties foodComponent) {
|
||||
return register(itemId, new BaseDrinkItem(makeItemSettings().stacksTo(1).food(foodComponent)));
|
||||
}
|
||||
|
||||
public Item registerDrink(String name, FoodProperties foodComponent) {
|
||||
return register(name, new BaseDrinkItem(makeItemSettings().stacksTo(1).food(foodComponent)));
|
||||
}
|
||||
|
||||
public Item registerDrink(String name, int hunger, float saturation) {
|
||||
public Item registerDrink(ResourceLocation itemId, int hunger, float saturation) {
|
||||
FoodProperties.Builder builder = new FoodProperties.Builder().nutrition(hunger).saturationMod(saturation);
|
||||
return registerDrink(name, builder.build());
|
||||
return registerDrink(itemId, builder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerItem(ResourceLocation id, Item item) {
|
||||
if (item != null && item != Items.AIR) {
|
||||
Registry.register(Registry.ITEM, id, item);
|
||||
getModItems(id.getNamespace()).add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public Item register(ResourceLocation itemId, Item item, String category) {
|
||||
if (config.getBoolean(category, itemId.getPath(), true)) {
|
||||
registerItem(itemId, item);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
|
74
src/main/java/ru/bclib/util/ItemUtil.java
Normal file
74
src/main/java/ru/bclib/util/ItemUtil.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
package ru.bclib.util;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.GsonHelper;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.bclib.BCLib;
|
||||
|
||||
public class ItemUtil {
|
||||
|
||||
public static String toStackString(@NotNull ItemStack stack) {
|
||||
try {
|
||||
if (stack == null) {
|
||||
throw new IllegalStateException("Stack can't be null!");
|
||||
}
|
||||
Item item = stack.getItem();
|
||||
return Registry.ITEM.getKey(item) + ":" + stack.getCount();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
BCLib.LOGGER.error("ItemStack serialization error!", ex);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ItemStack fromStackString(String stackString) {
|
||||
if (stackString == null || stackString.equals("")) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String[] parts = stackString.split(":");
|
||||
if (parts.length < 2) return null;
|
||||
if (parts.length == 2) {
|
||||
ResourceLocation itemId = new ResourceLocation(stackString);
|
||||
Item item = Registry.ITEM.getOptional(itemId).orElseThrow(() -> {
|
||||
return new IllegalStateException("Output item " + itemId + " does not exists!");
|
||||
});
|
||||
return new ItemStack(item);
|
||||
}
|
||||
ResourceLocation itemId = new ResourceLocation(parts[0], parts[1]);
|
||||
Item item = Registry.ITEM.getOptional(itemId).orElseThrow(() -> {
|
||||
return new IllegalStateException("Output item " + itemId + " does not exists!");
|
||||
});
|
||||
return new ItemStack(item, Integer.valueOf(parts[2]));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
BCLib.LOGGER.error("ItemStack deserialization error!", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ItemStack fromJsonRecipe(JsonObject recipe) {
|
||||
try {
|
||||
if (!recipe.has("item")) {
|
||||
throw new IllegalStateException("Invalid JsonObject. Entry 'item' does not exists!");
|
||||
}
|
||||
ResourceLocation itemId = new ResourceLocation(GsonHelper.getAsString(recipe, "item"));
|
||||
Item item = Registry.ITEM.getOptional(itemId).orElseThrow(() -> {
|
||||
return new IllegalStateException("Output item " + itemId + " does not exists!");
|
||||
});
|
||||
int count = GsonHelper.getAsInt(recipe, "count", 1);
|
||||
return new ItemStack(item, count);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
BCLib.LOGGER.error("ItemStack deserialization error!", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,22 +1,35 @@
|
|||
package ru.bclib.util;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.fabricmc.loader.api.SemanticVersion;
|
||||
import net.fabricmc.loader.api.Version;
|
||||
import net.fabricmc.loader.api.VersionParsingException;
|
||||
import net.fabricmc.loader.api.metadata.ContactInformation;
|
||||
import net.fabricmc.loader.api.metadata.CustomValue;
|
||||
import net.fabricmc.loader.api.metadata.ModDependency;
|
||||
import net.fabricmc.loader.api.metadata.ModEnvironment;
|
||||
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||
import net.fabricmc.loader.impl.metadata.ModMetadataParser;
|
||||
import net.fabricmc.loader.impl.metadata.ParseMetadataException;
|
||||
import net.fabricmc.loader.api.metadata.Person;
|
||||
import net.fabricmc.loader.util.version.SemanticVersionImpl;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import ru.bclib.BCLib;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Locale;
|
||||
|
@ -59,17 +72,19 @@ public class ModUtil {
|
|||
Path modMetaFile = fs.getPath("fabric.mod.json");
|
||||
if (modMetaFile != null) {
|
||||
try (InputStream is = Files.newInputStream(modMetaFile)) {
|
||||
ModMetadata mc = ModMetadataParser.parseMetadata(is, uri.toString(), new LinkedList<String>());
|
||||
mods.put(mc.getId(), new ModInfo(mc, file));
|
||||
//ModMetadata mc = ModMetadataParser.parseMetadata(is, uri.toString(), new LinkedList<String>());
|
||||
ModMetadata mc = readJSON(is, uri.toString());
|
||||
if (mc!=null){
|
||||
mods.put(mc.getId(), new ModInfo(mc, file));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} catch (ParseMetadataException e) {
|
||||
} catch (Exception e) {
|
||||
BCLib.LOGGER.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
catch (Exception e) {
|
||||
BCLib.LOGGER.error(e.getMessage());
|
||||
}
|
||||
}));
|
||||
|
@ -77,6 +92,176 @@ public class ModUtil {
|
|||
return mods;
|
||||
}
|
||||
|
||||
private static ModMetadata readJSON(InputStream is, String sourceFile) throws IOException {
|
||||
try (com.google.gson.stream.JsonReader reader = new JsonReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
|
||||
JsonObject data = new JsonParser().parse(reader).getAsJsonObject();
|
||||
Version ver;
|
||||
try {
|
||||
ver = new SemanticVersionImpl(data.get("version").getAsString(), false);
|
||||
}
|
||||
catch (VersionParsingException e) {
|
||||
BCLib.LOGGER.error("Unable to parse Version in " + sourceFile);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (data.get("id") == null){
|
||||
BCLib.LOGGER.error("Unable to read ID in " + sourceFile);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (data.get("name") == null){
|
||||
BCLib.LOGGER.error("Unable to read name in " + sourceFile);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ModMetadata() {
|
||||
@Override
|
||||
public Version getVersion() {
|
||||
return ver;
|
||||
}
|
||||
@Override
|
||||
public String getType() {
|
||||
return "fabric";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return data.get("id").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getProvides() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModEnvironment getEnvironment() {
|
||||
JsonElement env = data.get("environment");
|
||||
if (env==null) {
|
||||
BCLib.LOGGER.error("No environment specified in " + sourceFile);
|
||||
return ModEnvironment.UNIVERSAL;
|
||||
}
|
||||
final String environment = env.getAsString().toLowerCase(Locale.ROOT);
|
||||
|
||||
if (environment.isEmpty() || environment.equals("*") || environment.equals("common")) {
|
||||
JsonElement entrypoints = data.get("entrypoints");
|
||||
boolean hasClient = true;
|
||||
|
||||
//check if there is an actual client entrypoint
|
||||
if (entrypoints!=null && entrypoints.isJsonObject()){
|
||||
JsonElement client = entrypoints.getAsJsonObject().get("client");
|
||||
if (client!=null && client.isJsonArray()){
|
||||
hasClient = client.getAsJsonArray().size() > 0;
|
||||
} else if (client==null || !client.isJsonPrimitive()){
|
||||
hasClient = false;
|
||||
} else if (!client.getAsJsonPrimitive().isString()){
|
||||
hasClient = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasClient == false) return ModEnvironment.SERVER;
|
||||
return ModEnvironment.UNIVERSAL;
|
||||
} else if (environment.equals("client")) {
|
||||
return ModEnvironment.CLIENT;
|
||||
} else if (environment.equals("server")) {
|
||||
return ModEnvironment.SERVER;
|
||||
} else {
|
||||
BCLib.LOGGER.error("Unable to read environment in " + sourceFile);
|
||||
return ModEnvironment.UNIVERSAL;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ModDependency> getDepends() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ModDependency> getRecommends() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ModDependency> getSuggests() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ModDependency> getConflicts() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ModDependency> getBreaks() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public Collection<ModDependency> getDependencies() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return data.get("name").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Person> getAuthors() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Person> getContributors() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactInformation getContact() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getLicense() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getIconPath(int size) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsCustomValue(String key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomValue getCustomValue(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, CustomValue> getCustomValues() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsCustomElement(String key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public JsonElement getCustomElement(String key) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ModInfo} or {@code null} if the mod was not found.
|
||||
* <p>
|
||||
|
|
25
src/main/java/ru/bclib/util/RecipeHelper.java
Normal file
25
src/main/java/ru/bclib/util/RecipeHelper.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
package ru.bclib.util;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
public class RecipeHelper {
|
||||
public static boolean exists(ItemLike item) {
|
||||
if (item instanceof Block) {
|
||||
return Registry.BLOCK.getKey((Block) item) != Registry.BLOCK.getDefaultKey();
|
||||
}
|
||||
else {
|
||||
return Registry.ITEM.getKey(item.asItem()) != Registry.ITEM.getDefaultKey();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean exists(ItemLike... items) {
|
||||
for (ItemLike item : items) {
|
||||
if (!exists(item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ public class TranslationHelper {
|
|||
|
||||
Gson gson = new Gson();
|
||||
InputStream inputStream = TranslationHelper.class.getResourceAsStream("/assets/" + modID + "/lang/" + languageCode + ".json");
|
||||
JsonObject translation = gson.fromJson(new InputStreamReader(inputStream), JsonObject.class);
|
||||
JsonObject translation = inputStream == null ? new JsonObject() : gson.fromJson(new InputStreamReader(inputStream), JsonObject.class);
|
||||
|
||||
Registry.BLOCK.forEach(block -> {
|
||||
if (Registry.BLOCK.getKey(block).getNamespace().equals(modID)) {
|
||||
|
|
|
@ -70,6 +70,7 @@ public class BCLBiomeDef {
|
|||
private int waterFogColor = 329011;
|
||||
private int waterColor = 4159204;
|
||||
private int fogColor = 10518688;
|
||||
private int skyColor = 0;
|
||||
private float fogDensity = 1F;
|
||||
private float depth = 0.1F;
|
||||
|
||||
|
@ -247,11 +248,24 @@ public class BCLBiomeDef {
|
|||
return ColorUtil.color(r, g, b);
|
||||
}
|
||||
|
||||
public BCLBiomeDef setFogColor(int r, int g, int b) {
|
||||
this.fogColor = getColor(r, g, b);
|
||||
public BCLBiomeDef setSkyColor(int rgb) {
|
||||
this.skyColor = rgb;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BCLBiomeDef setSkyColor(int r, int g, int b) {
|
||||
return setSkyColor(getColor(r, g, b));
|
||||
}
|
||||
|
||||
public BCLBiomeDef setFogColor(int rgb) {
|
||||
this.fogColor = rgb;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BCLBiomeDef setFogColor(int r, int g, int b) {
|
||||
return setFogColor(getColor(r, g, b));
|
||||
}
|
||||
|
||||
public BCLBiomeDef setFogDensity(float density) {
|
||||
this.fogDensity = density;
|
||||
return this;
|
||||
|
@ -333,7 +347,7 @@ public class BCLBiomeDef {
|
|||
|
||||
addCustomToBuild(generationSettings);
|
||||
|
||||
effects.skyColor(0)
|
||||
effects.skyColor(skyColor)
|
||||
.waterColor(waterColor)
|
||||
.waterFogColor(waterFogColor)
|
||||
.fogColor(fogColor)
|
||||
|
@ -380,9 +394,9 @@ public class BCLBiomeDef {
|
|||
ConfiguredFeature<?, ?> feature;
|
||||
}
|
||||
|
||||
private static final class CarverInfo {
|
||||
private static final class CarverInfo <C extends CarverConfiguration> {
|
||||
Carving carverStep;
|
||||
ConfiguredWorldCarver<CarverConfiguration> carver;
|
||||
ConfiguredWorldCarver<C> carver;
|
||||
}
|
||||
|
||||
public ResourceLocation getID() {
|
||||
|
@ -401,7 +415,7 @@ public class BCLBiomeDef {
|
|||
return edgeSize;
|
||||
}
|
||||
|
||||
public BCLBiomeDef addCarver(Carving carverStep, ConfiguredWorldCarver<CarverConfiguration> carver) {
|
||||
public <C extends CarverConfiguration> BCLBiomeDef addCarver(Carving carverStep, ConfiguredWorldCarver<C> carver) {
|
||||
CarverInfo info = new CarverInfo();
|
||||
info.carverStep = carverStep;
|
||||
info.carver = carver;
|
||||
|
|
|
@ -29,6 +29,7 @@ public class BCLibNetherBiomeSource extends BiomeSource {
|
|||
private BiomeMap biomeMap;
|
||||
private final long seed;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
public static final List<Consumer<BCLibNetherBiomeSource>> onInit = new LinkedList<>();
|
||||
|
||||
public BCLibNetherBiomeSource(Registry<Biome> biomeRegistry, long seed) {
|
||||
|
|
|
@ -12,11 +12,15 @@ public class GeneratorOptions {
|
|||
private static int biomeSizeEndVoid;
|
||||
private static Function<Point, Boolean> endLandFunction;
|
||||
private static boolean farEndBiomes = true;
|
||||
private static boolean customNetherBiomeSource = true;
|
||||
private static boolean customEndBiomeSource = true;
|
||||
|
||||
public static void init() {
|
||||
biomeSizeNether = Configs.GENERATOR_CONFIG.getInt("nether.biomeMap", "biomeSize", 256);
|
||||
biomeSizeEndLand = Configs.GENERATOR_CONFIG.getInt("end.biomeMap", "biomeSizeLand", 256);
|
||||
biomeSizeEndVoid = Configs.GENERATOR_CONFIG.getInt("end.biomeMap", "biomeSizeVoid", 256);
|
||||
customNetherBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options", "customNetherBiomeSource", true);
|
||||
customEndBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options", "customEndBiomeSource", true);
|
||||
}
|
||||
|
||||
public static int getBiomeSizeNether() {
|
||||
|
@ -46,4 +50,12 @@ public class GeneratorOptions {
|
|||
public static void setFarEndBiomes(boolean farEndBiomes) {
|
||||
GeneratorOptions.farEndBiomes = farEndBiomes;
|
||||
}
|
||||
|
||||
public static boolean customNetherBiomeSource() {
|
||||
return customNetherBiomeSource;
|
||||
}
|
||||
|
||||
public static boolean customEndBiomeSource() {
|
||||
return customEndBiomeSource;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue