basic functioning on fabric
This commit is contained in:
techno-sam
2026-04-25 13:00:26 +02:00
parent 62ed623c1f
commit bad5f29b4e
39 changed files with 602 additions and 19 deletions
@@ -1,8 +1,11 @@
package io.github.slimeistdev.crystalline_sky.fabric;
import io.github.slimeistdev.crystalline_sky.CrystallineSkyClient;
import io.github.slimeistdev.crystalline_sky.fabric.events.RegisterMaterialAtlasesEvent;
import io.github.slimeistdev.crystalline_sky.fabric.render_tmp.SkyboxModelLoadingPlugin;
import io.github.slimeistdev.crystalline_sky.multiloader.fabric.ItemGroupRegistrationEventImpl;
import io.github.slimeistdev.crystalline_sky.registry.CrystallineBlocks;
import io.github.slimeistdev.crystalline_sky.registry.client.CrystallineAtlases;
import io.github.slimeistdev.crystalline_sky.registry.client.CrystallineRenderTypes;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.EnvType;
@@ -23,9 +26,14 @@ public class CrystallineSkyClientImpl implements ClientModInitializer {
ItemGroupRegistrationEventImpl.register();
Consumer<Block> makeSky = b -> BlockRenderLayerMap.INSTANCE.putBlock(b, CrystallineRenderTypes.SKY);
Consumer<Block> makeSkybox = b -> BlockRenderLayerMap.INSTANCE.putBlock(b, CrystallineRenderTypes.SKYBOX);
CrystallineBlocks.SKY.onRegistered(makeSky);
CrystallineBlocks.WEEPING_SKY.onRegistered(makeSky);
CrystallineBlocks.SKYBOX_TEST.onRegistered(makeSkybox);
ClientTickEvents.END_CLIENT_TICK.register(CrystallineSkyClient::onEndTick);
RegisterMaterialAtlasesEvent.EVENT.register(ctx -> CrystallineAtlases.register(ctx::addAtlas));
SkyboxModelLoadingPlugin.register();
}
}
@@ -5,8 +5,10 @@ import com.google.gson.JsonObject;
import io.github.slimeistdev.crystalline_sky.CrystallineSky;
import io.github.slimeistdev.crystalline_sky.registry.CrystallineBlocks;
import io.github.slimeistdev.crystalline_sky.registry.CrystallineItems;
import io.github.slimeistdev.crystalline_sky.registry.client.CrystallineAtlases;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.data.models.BlockModelGenerators;
import net.minecraft.data.models.ItemModelGenerators;
import net.minecraft.data.models.blockstates.MultiVariantGenerator;
@@ -24,8 +26,20 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import java.util.Locale;
import static net.minecraft.data.models.model.TexturedModel.createDefault;
@SuppressWarnings("SameParameterValue")
public class CrystallineSkyModelProvider extends FabricModelProvider {
private static ResourceLocation getSkyboxBlockTexture(Block block) {
ResourceLocation resourceLocation = BuiltInRegistries.BLOCK.getKey(block);
return resourceLocation.withPrefix("crystalline_sky_skybox/");
}
private static final TexturedModel.Provider SKYBOX_CUBE = createDefault(
block -> TextureMapping.cube(getSkyboxBlockTexture(block)),
ModelTemplates.CUBE_ALL
);
public CrystallineSkyModelProvider(FabricDataOutput output) {
super(output);
}
@@ -38,6 +52,8 @@ public class CrystallineSkyModelProvider extends FabricModelProvider {
gen.createAirLikeBlock(CrystallineBlocks.WEEPING_SKY_LIGHT.value(), CrystallineItems.WEEPING_SKY_LIGHT.value());
gen.createSimpleFlatItemModel(CrystallineItems.WEEPING_SKY_LIGHT.value());
registerSkyboxBlock(gen, CrystallineBlocks.SKYBOX_TEST.value());
}
private void registerSkyBlock(BlockModelGenerators gen, Block block) {
@@ -54,6 +70,21 @@ public class CrystallineSkyModelProvider extends FabricModelProvider {
gen.createSimpleFlatItemModel(block);
}
private void registerSkyboxBlock(BlockModelGenerators gen, Block block) {
gen.blockStateOutput.accept(BlockModelGenerators.createSimpleBlock(block, SKYBOX_CUBE.create(
block,
(id, json) -> {
gen.modelOutput.accept(id, () -> {
JsonObject root = json.get().getAsJsonObject();
root.addProperty("render_type", CrystallineSky.id("skybox").toString());
root.addProperty(CrystallineSky.id("atlas").toString(), CrystallineAtlases.SKYBOXES.texture.toString());
return root;
});
}
)));
gen.createSimpleFlatItemModel(block);
}
private void registerSkyLightBlock(BlockModelGenerators gen, Block block, Item item) {
gen.skipAutoItemBlock(block);
PropertyDispatch.C1<Integer> singleProperty = PropertyDispatch.property(BlockStateProperties.LEVEL);
@@ -0,0 +1,40 @@
package io.github.slimeistdev.crystalline_sky.fabric.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.ApiStatus;
import java.util.HashMap;
import java.util.Map;
public interface RegisterMaterialAtlasesEvent {
Event<RegisterMaterialAtlasesEvent> EVENT = EventFactory.createArrayBacked(RegisterMaterialAtlasesEvent.class, (callbacks) -> (context) -> {
for (RegisterMaterialAtlasesEvent callback : callbacks) {
callback.run(context);
}
});
@ApiStatus.Internal
static Map<ResourceLocation, ResourceLocation> gatherMaterialAtlases(Map<ResourceLocation, ResourceLocation> vanillaAtlases) {
Map<ResourceLocation, ResourceLocation> atlases = new HashMap<>(vanillaAtlases);
EVENT.invoker().run(((atlasLocation, atlasInfoLocation) -> {
ResourceLocation oldAtlasInfoLoc = atlases.putIfAbsent(atlasLocation, atlasInfoLocation);
if (oldAtlasInfoLoc != null) {
throw new IllegalStateException(String.format(
"Duplicate registration of atlas: %s (old info: %s, new info: %s)",
atlasLocation,
oldAtlasInfoLoc,
atlasInfoLocation));
}
}));
return Map.copyOf(atlases);
}
void run(Context context);
@FunctionalInterface
interface Context {
void addAtlas(ResourceLocation atlasLocation, ResourceLocation atlasInfoLocation);
}
}
@@ -0,0 +1,21 @@
package io.github.slimeistdev.crystalline_sky.fabric.mixin.client;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import io.github.slimeistdev.crystalline_sky.fabric.events.RegisterMaterialAtlasesEvent;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.model.AtlasSet;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.resources.ResourceLocation;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import java.util.Map;
@Mixin(ModelManager.class)
public class ModelManagerMixin {
@WrapOperation(method = "<init>", at = @At(value = "NEW", target = "(Ljava/util/Map;Lnet/minecraft/client/renderer/texture/TextureManager;)Lnet/minecraft/client/resources/model/AtlasSet;"))
private AtlasSet addCustomAtlases(Map<ResourceLocation, ResourceLocation> atlasMap, TextureManager textureManager, Operation<AtlasSet> original) {
return original.call(RegisterMaterialAtlasesEvent.gatherMaterialAtlases(atlasMap), textureManager);
}
}
@@ -15,7 +15,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public class ChunkRenderOverrider_AxiomChunkOverrideLayerMixin {
@Inject(method = "fromVanilla", at = @At("HEAD"), cancellable = true)
private static void unexplodeSky(RenderType layer, CallbackInfoReturnable<ChunkRenderOverrider.AxiomChunkOverrideLayer> cir) {
if (layer == CrystallineRenderTypes.SKY) {
if (layer == CrystallineRenderTypes.SKY || layer == CrystallineRenderTypes.SKYBOX) {
cir.setReturnValue(ChunkRenderOverrider.AxiomChunkOverrideLayer.CUTOUT_MIPPED);
}
}
@@ -0,0 +1,116 @@
package io.github.slimeistdev.crystalline_sky.fabric.render_tmp;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.renderer.v1.material.ShadeMode;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.api.util.TriState;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import java.util.List;
import java.util.function.Supplier;
public class SkyboxBakedModel extends ForwardingBakedModel {
private static final RenderMaterial FULL_BRIGHT_MATERIAL;
static {
Renderer renderer = RendererAccess.INSTANCE.getRenderer();
if (renderer == null) {
FULL_BRIGHT_MATERIAL = null;
} else {
FULL_BRIGHT_MATERIAL = renderer.materialFinder()
.shadeMode(ShadeMode.VANILLA)
.ambientOcclusion(TriState.FALSE)
.emissive(true)
.disableDiffuse(true)
.disableColorIndex(true)
.find();
}
}
public SkyboxBakedModel(BakedModel wrapped) {
super(wrapped);
}
@Override
public boolean useAmbientOcclusion() {
return false;
}
@Override
public boolean usesBlockLight() {
return false;
}
@Override
public boolean isVanillaAdapter() {
return false;
}
// copied from net.fabricmc.fabric.impl.renderer.VanillaModelEncoder.emitBlockQuads
@Override
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) {
/*TextureAtlasSprite sprite = getParticleIcon();
float u0 = sprite.getU0();
float v0 = sprite.getV0();
int u1 = (int) (sprite.getU1() * 0xffff);
int v1 = (int) (sprite.getV1() * 0xffff);
int color = (u1 << 16) | v1;
var emitter = context.getEmitter()
.square(Direction.UP, 0, 0, 1, 1, 0)
.material(FULLBRIGHT_MATERIAL);
for (int i = 0; i < 4; i++) {
emitter
.color(i, color)
.lightmap(i, LightTexture.FULL_BRIGHT)
.normal(i, 0, 1, 0)
.uv(i, u0, v0);
}
emitter.emit();*/
QuadEmitter emitter = context.getEmitter();
for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
final Direction cullFace = ModelHelper.faceFromIndex(i);
if (!context.hasTransform() && context.isFaceCulled(cullFace)) {
// Skip entire quad list if possible
continue;
}
final List<BakedQuad> quads = getQuads(state, cullFace, randomSupplier.get());
for (final BakedQuad q : quads) {
emitter.fromVanilla(q, FULL_BRIGHT_MATERIAL, cullFace); // fixme view bobbing breaks projection, use TextureMatrix to pass a view projection matrix along :)
TextureAtlasSprite sprite = q.getSprite();
float u0 = sprite.getU0();
float v0 = sprite.getV0();
int u1 = (int) (sprite.getU1() * 0xffff);
int v1 = (int) (sprite.getV1() * 0xffff);
int uv1 = (u1 << 16) | v1;
for (int j = 0; j < 4; j++) {
emitter.uv(j, u0, v0);
emitter.color(j, uv1);
}
emitter.emit();
}
}
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<RandomSource> randomSupplier, RenderContext context) {
super.emitItemQuads(stack, randomSupplier, context);
}
}
@@ -0,0 +1,28 @@
package io.github.slimeistdev.crystalline_sky.fabric.render_tmp;
import io.github.slimeistdev.crystalline_sky.CrystallineSky;
import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
import net.minecraft.resources.ResourceLocation;
public class SkyboxModelLoadingPlugin implements ModelLoadingPlugin {
private SkyboxModelLoadingPlugin() {}
@Override
public void onInitializeModelLoader(Context pluginContext) {
pluginContext.modifyModelAfterBake().register((model, ctx) -> {
if (model == null) return null;
ResourceLocation id = ctx.resourceId();
if (id == null) {
id = ctx.topLevelId().id();
}
if (!id.equals(CrystallineSky.id("block/skybox_test"))) return model;
return new SkyboxBakedModel(model);
});
}
public static void register() {
ModelLoadingPlugin.register(new SkyboxModelLoadingPlugin());
}
}
@@ -10,6 +10,7 @@
"mixins": [
],
"client": [
"client.ModelManagerMixin",
"client.RenderTypeMixin",
"client.compat.axiom.ChunkRenderOverrider_AxiomChunkOverrideLayerMixin"
],