a bunch of stuff (and a bit of datagen)

This commit is contained in:
moehreag 2024-07-08 20:49:40 +02:00
parent ba83b48e81
commit e3a2545963
27 changed files with 586 additions and 4 deletions

View file

@ -1,7 +1,7 @@
[versions] [versions]
minecraft = "1.21" minecraft = "1.21"
frogloader = "0.0.1-alpha.7" frogloader = "0.0.1-alpha.14"
phytotelma = "0.0.1-alpha.10" phytotelma = "0.0.1-alpha.16+local"
lombok = "8.6" lombok = "8.6"

View file

@ -0,0 +1,65 @@
package dev.frogmc.froglib.block.api;
import dev.frogmc.froglib.block.api.listener.OnPlayerDestroy;
import dev.frogmc.froglib.block.api.listener.OnRemove;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class FrogBlockBuilder {
private final BlockBehaviour.Properties properties;
private OnRemove removalListener = (block, state, level, pos, newState, movedByPiston) -> {};
private OnPlayerDestroy playerDestroy = (block, level, player, pos, state, blockEntity, tool) -> {};
private FrogBlockBuilder(BlockBehaviour.Properties properties) {
this.properties = properties;
}
public static FrogBlockBuilder of(BlockBehaviour.Properties properties) {
return new FrogBlockBuilder(properties);
}
public FrogBlockBuilder onRemove(OnRemove listener) {
removalListener = listener;
return this;
}
public FrogBlockBuilder onPlayerDestroy(OnPlayerDestroy onPlayerDestroy) {
this.playerDestroy = onPlayerDestroy;
return this;
}
public Block build() {
return new Block(properties) {
@Override
public @NotNull BlockState playerWillDestroy(@NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull Player player) {
return super.playerWillDestroy(level, pos, state, player);
}
@Override
protected void spawnDestroyParticles(@NotNull Level level, @NotNull Player player, @NotNull BlockPos pos, @NotNull BlockState state) {
super.spawnDestroyParticles(level, player, pos, state);
}
@Override
protected void onRemove(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState newState, boolean movedByPiston) {
removalListener.onRemove(this, state, level, pos, newState, movedByPiston);
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
public void playerDestroy(@NotNull Level level, @NotNull Player player, @NotNull BlockPos pos, @NotNull BlockState state, @Nullable BlockEntity blockEntity, @NotNull ItemStack tool) {
playerDestroy.onPlayerDestroy(this, level, player, pos, state, blockEntity, tool);
super.playerDestroy(level, player, pos, state, blockEntity, tool);
}
};
}
}

View file

@ -0,0 +1,66 @@
package dev.frogmc.froglib.block.api;
import java.util.HashMap;
import java.util.Map;
import com.electronwill.nightconfig.core.Config;
import com.electronwill.nightconfig.json.JsonFormat;
import dev.frogmc.froglib.block.impl.JsonProvider;
import dev.frogmc.froglib.block.impl.RuntimeDatagen;
import net.minecraft.data.models.model.ModelTemplate;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.ApiStatus;
public class FrogBlockModel implements JsonProvider {
private final String parent;
private final Map<String, String> textures;
private FrogBlockModel(String parent, Map<String, String> textures) {
this.parent = parent;
this.textures = textures;
}
/*public static FrogBlockModel.Builder ofTemplate(ModelTemplate template) {
}*/
public static FrogBlockModel.Builder builder() {
return new Builder();
}
public void register(ResourceLocation block) {
RuntimeDatagen.getInstance().addBlockModel(block, this);
}
public static class Builder {
private String parent = null;
private final Map<String, String> textures = new HashMap<>();
public Builder parent(String parent) {
this.parent = parent;
return this;
}
public Builder texture(String name, String location) {
textures.put(name, location);
return this;
}
public FrogBlockModel build() {
return new FrogBlockModel(parent, textures);
}
}
@ApiStatus.Internal
public String getJson() {
Config c = Config.inMemory();
if (parent != null) {
c.add("parent", parent);
}
if (!textures.isEmpty()) {
textures.forEach((s, s2) -> c.add("textures." + s, s2));
}
return JsonFormat.fancyInstance().createWriter().writeToString(c);
}
}

View file

@ -0,0 +1,29 @@
package dev.frogmc.froglib.block.api;
import com.electronwill.nightconfig.core.Config;
import com.electronwill.nightconfig.json.JsonFormat;
import dev.frogmc.froglib.block.impl.JsonProvider;
import net.minecraft.data.models.blockstates.BlockStateGenerator;
import org.jetbrains.annotations.ApiStatus;
public abstract class FrogBlockstate implements JsonProvider {
/*public static FrogBlockstate multipart() {
}
public static FrogBlockstate variants() {
}
public static FrogBlockstate ofGenerator(BlockStateGenerator generator) {
generator.get().toString();
}*/
@ApiStatus.Internal
public String getJson() {
Config c = Config.inMemory();
return JsonFormat.fancyInstance().createWriter().writeToString(c);
}
}

View file

@ -0,0 +1,13 @@
package dev.frogmc.froglib.block.api.listener;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
public interface OnPlayerDestroy {
void onPlayerDestroy(Block block, Level level, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, ItemStack tool);
}

View file

@ -0,0 +1,11 @@
package dev.frogmc.froglib.block.api.listener;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public interface OnRemove {
void onRemove(Block block, BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston);
}

View file

@ -0,0 +1,4 @@
package dev.frogmc.froglib.block.impl;
public class BlockImpl {
}

View file

@ -0,0 +1,5 @@
package dev.frogmc.froglib.block.impl;
public interface JsonProvider {
String getJson();
}

View file

@ -0,0 +1,94 @@
package dev.frogmc.froglib.block.impl;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import dev.frogmc.froglib.block.api.FrogBlockModel;
import dev.frogmc.froglib.block.api.FrogBlockstate;
import dev.frogmc.frogloader.api.FrogLoader;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackLocationInfo;
import net.minecraft.server.packs.PackSelectionConfig;
import net.minecraft.server.packs.PathPackResources;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.server.packs.repository.PackCompatibility;
import net.minecraft.server.packs.repository.PackSource;
import net.minecraft.world.flag.FeatureFlagSet;
import org.jetbrains.annotations.NotNull;
@Slf4j
public class RuntimeDatagen {
@Getter
private static final RuntimeDatagen instance = new RuntimeDatagen();
private final Path target = FrogLoader.getInstance().getGameDir().resolve(".frogmc").resolve("datagen");
private RuntimeDatagen(){
try {
Files.createDirectories(target);
} catch (IOException e) {
log.error("Failed to create datagen target dir!", e);
}
}
public void inject(List<Pack> packs) {
packs.add(new Pack(new PackLocationInfo("runtime_datagen", Component.literal("Generated Resources"),
new PackSource() {
@Override
public @NotNull Component decorate(@NotNull Component component) {
return component;
}
@Override
public boolean shouldAddAutomatically() {
return true;
}
}, Optional.empty()), new PathPackResources.PathResourcesSupplier(target),
new Pack.Metadata(Component.empty(), PackCompatibility.COMPATIBLE, FeatureFlagSet.of(), Collections.emptyList()),
new PackSelectionConfig(true, Pack.Position.TOP, true)));
}
public void addBlockstate(ResourceLocation target, FrogBlockstate state) {
Path file = this.target.resolve("assets")
.resolve(target.getNamespace())
.resolve("blockstates")
.resolve(target.getPath()+".json");
try {
Files.writeString(file, state.getJson());
} catch (IOException e) {
log.error("Failed to write genrated blockstate to {}!", file, e);
}
}
public void addBlockModel(ResourceLocation target, FrogBlockModel model) {
Path file = this.target.resolve("assets")
.resolve(target.getNamespace())
.resolve("models/block")
.resolve(target.getPath()+".json");
try {
Files.writeString(file, model.getJson());
} catch (IOException e) {
log.error("Failed to write genrated block model to {}!", file, e);
}
}
private void add(String type, String path, ResourceLocation loc, JsonProvider provider) {
Path file = this.target.resolve(type)
.resolve(loc.getNamespace())
.resolve(path)
.resolve(loc.getPath()+".json");
try {
Files.writeString(file, provider.getJson());
} catch (IOException e) {
log.error("Failed to write genrated block model to {}!", file, e);
}
}
}

View file

@ -0,0 +1,22 @@
package dev.frogmc.froglib.block.impl.mixin;
import java.util.Collection;
import java.util.List;
import com.llamalad7.mixinextras.sugar.Local;
import dev.frogmc.froglib.block.impl.RuntimeDatagen;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.server.packs.repository.PackRepository;
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;
@Mixin(PackRepository.class)
public class PackRepositoryMixin {
@Inject(method = "rebuildSelected", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableList;copyOf(Ljava/util/Collection;)Lcom/google/common/collect/ImmutableList;"))
private void injectModResources(Collection<String> ids, CallbackInfoReturnable<List<Pack>> cir, @Local List<Pack> packs) {
RuntimeDatagen.getInstance().inject(packs);
}
}

View file

@ -0,0 +1,21 @@
[frog]
format_version = "1.0.0"
[frog.mod]
id = "froglib_block"
name = "FrogLib Block"
version = "$version"
license = "Apache-2.0"
credits = [
{ name = "FrogMC Team", roles = ["author"] }
]
[frog.dependencies]
depends = [
{ id = "minecraft", versions = "~$game_version", name = "Minecraft" }
]
[frog.extensions]
mixin = [
"froglib.block.mixins.json",
]

View file

@ -0,0 +1,17 @@
{
"required": true,
"minVersion": "0.8",
"package": "dev.frogmc.froglib.block.impl.mixin",
"compatibilityLevel": "JAVA_21",
"mixins": [
"PackRepositoryMixin"
],
"server": [
],
"client": [
],
"injectors": {
"defaultRequire": 1
}
}

View file

@ -0,0 +1,14 @@
package dev.frogmc.froglib.datagen.api;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.models.BlockModelGenerators;
import net.minecraft.data.models.ItemModelGenerators;
public interface DatagenExtension {
default void addProviders(DataGenerator.PackGenerator pack) {}
default void generateBlockModels(BlockModelGenerators generators) {}
default void generateItemModels(ItemModelGenerators generators) {}
}

View file

@ -0,0 +1,54 @@
package dev.frogmc.froglib.datagen.impl;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.nio.file.Path;
import java.util.Objects;
import dev.frogmc.froglib.datagen.api.DatagenExtension;
import lombok.extern.slf4j.Slf4j;
import net.minecraft.SharedConstants;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.models.ModelProvider;
@Slf4j
public final class FrogDatagen {
public static final boolean ENABLED = Boolean.getBoolean("frog.datagen.enabled");
public static DatagenExtension extension;
private static final String modId = System.getProperty("frog.datagen.modid");
private static final String generatorClass = System.getProperty("frog.datagen.generator");
private static final Path output = Path.of(Objects.requireNonNull(System.getProperty("frog.datagen.output"), "No output path provided!"));
private FrogDatagen() {
}
public static void run() {
SharedConstants.tryDetectVersion();
FrogGenerator generator = new FrogGenerator(output, modId);
DataGenerator.PackGenerator pack = generator.getPackGenerator();
try {
extension = getExtension();
extension.addProviders(pack);
pack.addProvider(ModelProvider::new);
generator.run();
} catch (Throwable e) {
log.error("Failed to run datagen: ", e);
}
}
private static DatagenExtension getExtension() throws Throwable {
return (DatagenExtension) MethodHandles.lookup()
.findConstructor(Class.forName(generatorClass), MethodType.methodType(void.class))
.invoke();
}
}

View file

@ -0,0 +1,28 @@
package dev.frogmc.froglib.datagen.impl;
import java.nio.file.Path;
import net.minecraft.SharedConstants;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.PackOutput;
import org.jetbrains.annotations.NotNull;
public class FrogGenerator extends DataGenerator {
private final PackOutput output;
private final String modId;
public FrogGenerator(Path rootOutputFolder, String modId) {
super(rootOutputFolder, SharedConstants.getCurrentVersion(), true);
output = new PackOutput(rootOutputFolder);
this.modId = modId;
}
public PackGenerator getPackGenerator(){
return new PackGenerator(true, modId, output);
}
@Override
public @NotNull PackGenerator getVanillaPack(boolean toRun) {
throw new UnsupportedOperationException();
}
}

View file

@ -0,0 +1,19 @@
package dev.frogmc.froglib.datagen.impl.mixin;
import dev.frogmc.froglib.datagen.impl.FrogDatagen;
import net.minecraft.data.models.BlockModelGenerators;
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(BlockModelGenerators.class)
public class BlockModelGeneratorsMixin {
@Inject(method = "run", at = @At("HEAD"), cancellable = true)
private void generateModBlockModels(CallbackInfo ci){
FrogDatagen.extension.generateBlockModels((BlockModelGenerators)(Object)this);
ci.cancel();
}
}

View file

@ -0,0 +1,19 @@
package dev.frogmc.froglib.datagen.impl.mixin;
import dev.frogmc.froglib.datagen.impl.FrogDatagen;
import net.minecraft.data.models.ItemModelGenerators;
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(ItemModelGenerators.class)
public class ItemModelGeneratorsMixin {
@Inject(method = "run", at = @At("HEAD"), cancellable = true)
private void generateItemModels(CallbackInfo ci) {
FrogDatagen.extension.generateItemModels((ItemModelGenerators) (Object) this);
ci.cancel();
}
}

View file

@ -0,0 +1,20 @@
package dev.frogmc.froglib.datagen.impl.mixin;
import dev.frogmc.froglib.datagen.impl.FrogDatagen;
import net.minecraft.server.Main;
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(Main.class)
public class MainMixin {
@Inject(method = "main", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/Bootstrap;validate()V", shift = At.Shift.AFTER), cancellable = true)
private static void datagenHook(String[] args, CallbackInfo ci){
if (FrogDatagen.ENABLED) {
FrogDatagen.run();
ci.cancel();
}
}
}

View file

@ -0,0 +1,22 @@
[frog]
format_version = "1.0.0"
[frog.mod]
id = "froglib_datagen"
name = "FrogLib Datagen"
version = "$version"
license = "Apache-2.0"
credits = [
{ name = "FrogMC Team", roles = ["author"] }
]
[frog.dependencies]
depends = [
{ id = "minecraft", versions = "~$game_version", name = "Minecraft" }
]
[frog.extensions]
mixin = [
"froglib.datagen.mixins.json"
]
accesswidener = "froglib.datagen.accesswidener"

View file

@ -0,0 +1,11 @@
accessWidener v2 named
accessible method net/minecraft/data/DataGenerator$PackGenerator <init> (Lnet/minecraft/data/DataGenerator;ZLjava/lang/String;Lnet/minecraft/data/PackOutput;)V
# transitive-accessible class net/minecraft/data/models/BlockModelGenerators$BlockEntityModelGenerator
# transitive-accessible class net/minecraft/data/models/BlockModelGenerators$BlockFamilyProvider
# transitive-accessible class net/minecraft/data/models/BlockModelGenerators$BlockStateGeneratorSupplier
# transitive-accessible class net/minecraft/data/models/BlockModelGenerators$TintState
# transitive-accessible class net/minecraft/data/models/BlockModelGenerators$WoodProvider
### generated aws

View file

@ -0,0 +1,18 @@
{
"required": true,
"minVersion": "0.8",
"package": "dev.frogmc.froglib.datagen.impl.mixin",
"compatibilityLevel": "JAVA_21",
"mixins": [
"BlockModelGeneratorsMixin",
"ItemModelGeneratorsMixin",
"MainMixin"
],
"server": [
],
"client": [
],
"injectors": {
"defaultRequire": 1
}
}

View file

@ -16,7 +16,7 @@ depends = [
] ]
[frog.extensions] [frog.extensions]
prelaunch = "net.frogmc.froglib.gen.impl.FrogGenPrelaunch" # prelaunch = "net.frogmc.froglib.gen.impl.FrogGenPrelaunch"
mixin = [ mixin = [
"froglib.gen.mixins.json" "froglib.gen.mixins.json"
] ]

View file

@ -1,10 +1,14 @@
package dev.frogmc.froglib.registries.api; package dev.frogmc.froglib.registries.api;
import java.util.Collection; import java.util.Collection;
import java.util.function.Consumer;
import dev.frogmc.froglib.events.api.Event; import dev.frogmc.froglib.events.api.Event;
import net.minecraft.world.item.alchemy.PotionBrewing;
public final class RegistryEvents { public final class RegistryEvents {
public static final Event<Runnable> REGISTRY_INIT = Event.runnable();
public static final Event<BlockRegistration> BLOCK_REGISTRATION = Event.of(list -> () -> list.stream().map(BlockRegistration::register).flatMap(Collection::stream).toList()); public static final Event<BlockRegistration> BLOCK_REGISTRATION = Event.of(list -> () -> list.stream().map(BlockRegistration::register).flatMap(Collection::stream).toList());
public static final Event<ItemRegistration> ITEM_REGISTRATION = Event.of(list -> () -> list.stream().map(ItemRegistration::register).flatMap(Collection::stream).toList()); public static final Event<ItemRegistration> ITEM_REGISTRATION = Event.of(list -> () -> list.stream().map(ItemRegistration::register).flatMap(Collection::stream).toList());
public static final Event<Consumer<PotionBrewing.Builder>> POTION_BREWING = Event.consumer();
} }

View file

@ -1,5 +1,6 @@
package dev.frogmc.froglib.registries.impl.mixin; package dev.frogmc.froglib.registries.impl.mixin;
import dev.frogmc.froglib.registries.api.RegistryEvents;
import dev.frogmc.froglib.registries.impl.RegistrationImpl; import dev.frogmc.froglib.registries.impl.RegistrationImpl;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@ -12,6 +13,7 @@ public abstract class BuiltinRegistriesMixin {
@Inject(method = "bootStrap", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/registries/BuiltInRegistries;createContents()V")) @Inject(method = "bootStrap", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/registries/BuiltInRegistries;createContents()V"))
private static void inject(CallbackInfo ci) { private static void inject(CallbackInfo ci) {
RegistryEvents.REGISTRY_INIT.invoker().run();
RegistrationImpl.register(); RegistrationImpl.register();
} }
} }

View file

@ -0,0 +1,19 @@
package dev.frogmc.froglib.registries.impl.mixin;
import com.llamalad7.mixinextras.sugar.Local;
import dev.frogmc.froglib.registries.api.RegistryEvents;
import net.minecraft.world.flag.FeatureFlagSet;
import net.minecraft.world.item.alchemy.PotionBrewing;
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;
@Mixin(PotionBrewing.class)
public abstract class PotionBrewingMixin {
@Inject(method = "bootstrap", at = @At("TAIL"))
private static void injectPotionMixes(FeatureFlagSet enabledFeatures, CallbackInfoReturnable<PotionBrewing> cir, @Local PotionBrewing.Builder builder) {
RegistryEvents.POTION_BREWING.invoker().accept(builder);
}
}

View file

@ -4,7 +4,8 @@
"package": "dev.frogmc.froglib.registries.impl.mixin", "package": "dev.frogmc.froglib.registries.impl.mixin",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_21",
"mixins": [ "mixins": [
"BuiltinRegistriesMixin" "BuiltinRegistriesMixin",
"PotionBrewingMixin"
], ],
"server": [ "server": [
], ],

View file

@ -27,5 +27,9 @@ include("library:registries")
findProject(":library:registries")?.name = "registries" findProject(":library:registries")?.name = "registries"
include("library:player") include("library:player")
findProject(":library:player")?.name = "player" findProject(":library:player")?.name = "player"
include("library:block")
findProject(":library:block")?.name = "block"
include("library:gen") include("library:gen")
findProject(":library:gen")?.name = "gen" findProject(":library:gen")?.name = "gen"
include("library:datagen")
findProject(":library:datagen")?.name = "datagen"