Compare commits

...

4 Commits

Author SHA1 Message Date
f3578a4da5 Merge pull request 'Indium suppor + github runner' (#7) from dev into master
Some checks failed
deploy / deploy (push) Failing after 5m3s
Reviewed-on: #7
2024-03-03 21:34:52 +01:00
dccc01ef49 Added Modrinth Auto Publisher on github workflow 2024-03-03 19:33:25 +01:00
961165104d added support for indium/sodium 2024-03-03 17:43:53 +01:00
13539fd91d added some todos 2024-03-02 01:57:25 +01:00
14 changed files with 228 additions and 37 deletions

34
.github/workflows/publish.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Publish mod on Modrinth
on: [ push, workflow_dispatch ]
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: checkout repository
uses: actions/checkout@v3
- name: validate gradle wrapper
uses: https://github.com/gradle/wrapper-validation-action@v1
- name: setup jdk
uses: actions/setup-java@v3
with:
java-version: 17
distribution: 'oracle'
- name: make gradle wrapper executable
if: ${{ runner.os != 'Windows' }}
run: |
chmod +x ./gradlew
touch local.properties
- name: Generate data
run: ./gradlew runDatagen
- name: Publish Modrinth
run: ./gradlew modrinth
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}

View File

@ -3,6 +3,7 @@ import fr.altarik.CreateTag
plugins { plugins {
id "com.modrinth.minotaur" version "2.+"
id 'fabric-loom' version '1.5-SNAPSHOT' id 'fabric-loom' version '1.5-SNAPSHOT'
id 'maven-publish' id 'maven-publish'
} }
@ -72,6 +73,17 @@ repositories {
maven { maven {
url "https://maven.resourcefulbees.com/repository/maven-public/" url "https://maven.resourcefulbees.com/repository/maven-public/"
} }
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
filter {
includeGroup "maven.modrinth"
}
}
mavenCentral() mavenCentral()
// Add repositories to retrieve artifacts from in here. // Add repositories to retrieve artifacts from in here.
@ -88,6 +100,12 @@ dependencies {
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
// Indium and sodium for sodium support
modCompileOnly "maven.modrinth:indium:${project.indium_version}+mc${project.minecraft_version}"
modCompileOnly "maven.modrinth:sodium:mc${project.minecraft_version}-${project.sodium_version}"
// modRuntimeOnly "maven.modrinth:indium:${project.indium_version}+mc${project.minecraft_version}"
// modRuntimeOnly "maven.modrinth:sodium:mc${project.minecraft_version}-${project.sodium_version}"
// Athena for connected texture // Athena for connected texture
modCompileOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}" modCompileOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}"
modRuntimeOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}" modRuntimeOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}"
@ -106,6 +124,8 @@ processResources {
inputs.property "loader_version", project.loader_version inputs.property "loader_version", project.loader_version
inputs.property "mod_id", project.mod_id inputs.property "mod_id", project.mod_id
inputs.property "athena_version", project.athena_version inputs.property "athena_version", project.athena_version
inputs.property "indium_version", project.indium_version
inputs.property "sodium_version", project.sodium_version
filteringCharset "UTF-8" filteringCharset "UTF-8"
filesMatching("fabric.mod.json") { filesMatching("fabric.mod.json") {
@ -171,6 +191,23 @@ publishing {
} }
} }
// configure modrinth publication
modrinth {
token = getEnv("MODRINTH_TOKEN", local.getProperty("modrinth_token"))
projectId = project.modrinth_id
versionNumber = project.mod_version
versionName = "${project.archives_base_name} ${project.mod_version}"
versionType = project.mod_version.endsWith('SNAPSHOT') ? 'beta' : 'release'
uploadFile = remapJar
gameVersions = [project.minecraft_version]
loaders = ["fabric"]
dependencies {
required.project "fabric-api"
optional.version "b1ZV3DIJ", "${project.athena_version}"
optional.version "Orvt0mRa", "${project.indium_version}+mc${project.minecraft_version}"
}
}
tasks.register("reportToDiscord", ReportDiscord) { tasks.register("reportToDiscord", ReportDiscord) {
config.set(reportConfig) config.set(reportConfig)
} }

View File

@ -8,7 +8,8 @@ yarn_mappings=1.20.4+build.3
loader_version=0.15.6 loader_version=0.15.6
# Mod Properties # Mod Properties
mod_version = 1.3 modrinth_id = jCpoCBpn
mod_version = 1.3.1
maven_group = fr.adrien1106 maven_group = fr.adrien1106
archives_base_name = ReFramed archives_base_name = ReFramed
mod_id = reframed mod_id = reframed
@ -21,3 +22,5 @@ git_owner=Altarik
git_repo=ReFramed git_repo=ReFramed
athena_version=3.3.0 athena_version=3.3.0
sodium_version=0.5.8
indium_version=1.0.30

View File

@ -25,7 +25,7 @@ import java.util.function.BiConsumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* TODO self culling, fix other models, better connected textures * TODO self culling, fix other models, better connected textures, preload items, walking sound, state replacement
*/ */
public class ReFramed implements ModInitializer { public class ReFramed implements ModInitializer {
public static final String MODID = "reframed"; public static final String MODID = "reframed";

View File

@ -2,6 +2,8 @@ package fr.adrien1106.reframed.mixin;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo; import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
@ -12,9 +14,17 @@ import java.util.function.Supplier;
public class CompatMixinPlugin implements IMixinConfigPlugin { public class CompatMixinPlugin implements IMixinConfigPlugin {
private static final FabricLoader LOADER = FabricLoader.getInstance();
private static final Logger LOGGER = LoggerFactory.getLogger("ReFramed MIXIN");
private static final List<String> COMPAT_MOD = List.of("athena", "indium", "sodium");
private static final Map<String, Supplier<Boolean>> CONDITIONS = Map.of( private static final Map<String, Supplier<Boolean>> CONDITIONS = Map.of(
"fr.adrien1106.reframed.mixin.compat.AthenaBakedModelMixin", () -> FabricLoader.getInstance().isModLoaded("athena"), "fr.adrien1106.reframed.mixin.compat.AthenaBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)),
"fr.adrien1106.reframed.mixin.compat.AthenaWrappedGetterMixin", () -> FabricLoader.getInstance().isModLoaded("athena") "fr.adrien1106.reframed.mixin.compat.AthenaWrappedGetterMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)),
"fr.adrien1106.reframed.mixin.render.TerrainRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.render.BlockRenderInfoMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.IndiumTerrainBlockRenderInfoMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2))
); );
@ -44,12 +54,16 @@ public class CompatMixinPlugin implements IMixinConfigPlugin {
} }
@Override @Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { public void preApply(String target_class_name, ClassNode target_class, String mixin_class_name, IMixinInfo mixin_info) {
} }
@Override @Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { public void postApply(String target_class, ClassNode target, String mixin_class, IMixinInfo mixin_info) {
String mixin_class_name = mixin_class.substring(mixin_class.lastIndexOf('.') + 1);
COMPAT_MOD.forEach(mod -> {
if (mixin_class_name.toLowerCase().startsWith(mod))
LOGGER.info("Loaded compatibility mixin class for mod \"" + mod + "\" (class: " + target_class + ")");
});
} }
} }

View File

@ -27,9 +27,9 @@ import java.util.*;
@Mixin(AthenaBakedModel.class) @Mixin(AthenaBakedModel.class)
public abstract class AthenaBakedModelMixin implements DynamicBakedModel, BakedModel { public abstract class AthenaBakedModelMixin implements DynamicBakedModel, BakedModel {
@Shadow @Final private AthenaBlockModel model; @Shadow(remap = false) @Final private AthenaBlockModel model;
@Shadow @Final private Int2ObjectMap<Sprite> textures; @Shadow(remap = false) @Final private Int2ObjectMap<Sprite> textures;
/** /**
* Reuses the emitQuad method to compute the quads to be used by the frame * Reuses the emitQuad method to compute the quads to be used by the frame

View File

@ -0,0 +1,43 @@
package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.block.ReFramedBlock;
import fr.adrien1106.reframed.util.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
import link.infra.indium.renderer.render.BlockRenderInfo;
import link.infra.indium.renderer.render.TerrainBlockRenderInfo;
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(TerrainBlockRenderInfo.class)
public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo implements IBlockRenderInfoMixin {
@Unique private int theme_index = 1;
@Redirect(
method = "shouldDrawFaceInner",
at = @At(
value = "INVOKE",
target = "Lme/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache;shouldDrawSide(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;)Z"
)
)
private boolean shouldDrawCamoSide(BlockOcclusionCache instance, BlockState state, BlockView view, BlockPos pos, Direction face) {
BlockPos other_pos = pos.offset(face);
if (!(view.getBlockEntity(pos) instanceof ThemeableBlockEntity
|| view.getBlockEntity(other_pos) instanceof ThemeableBlockEntity))
return instance.shouldDrawSide(state, view, pos, face);
return ReFramedBlock.shouldDrawSide(state, view, pos, face, other_pos, theme_index);
}
@Override
public void prepareForBlock(BlockState blockState, BlockPos blockPos, long seed, boolean modelAo, int theme_index) {
this.theme_index = theme_index;
prepareForBlock(blockState, blockPos, seed, modelAo);
}
}

View File

@ -0,0 +1,42 @@
package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
import fr.adrien1106.reframed.util.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.IMultipartBakedModelMixin;
import link.infra.indium.renderer.render.AbstractBlockRenderContext;
import link.infra.indium.renderer.render.TerrainRenderContext;
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext;
import net.minecraft.client.render.model.BakedModel;
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;
import java.util.List;
@Mixin(TerrainRenderContext.class)
public abstract class IndiumTerrainRenderContextMixin extends AbstractBlockRenderContext {
@Inject(
method = "tessellateBlock",
at = @At(
value = "INVOKE",
target = "Llink/infra/indium/renderer/aocalc/AoCalculator;clear()V"
), remap = false,
cancellable = true)
private void renderMultipleModels(BlockRenderContext ctx, CallbackInfo ci) {
if (!(ctx.model() instanceof IMultipartBakedModelMixin wrapped)
|| !(wrapped.getModel(ctx.state()) instanceof MultiRetexturableModel retexturing_model)) return;
List<BakedModel> models = retexturing_model.models();
int i = 0;
for (BakedModel bakedModel : models) {
i++;
aoCalc.clear();
((IBlockRenderInfoMixin) blockInfo).prepareForBlock(ctx.state(), ctx.pos(), ctx.seed(), bakedModel.useAmbientOcclusion(), i);
bakedModel.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
}
ci.cancel();
}
}

View File

@ -0,0 +1,30 @@
package fr.adrien1106.reframed.mixin.compat;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.block.ReFramedBlock;
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
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(BlockOcclusionCache.class)
public class SodiumBlockOcclusionCacheMixin {
@Inject(
method = "shouldDrawSide",
at = @At(
value = "INVOKE_ASSIGN",
target = "Lnet/minecraft/world/BlockView;getBlockState(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/block/BlockState;",
shift = At.Shift.AFTER
), cancellable = true)
private void shouldDrawFrameNeighborSide(BlockState self_state, BlockView view, BlockPos self_pos, Direction face, CallbackInfoReturnable<Boolean> cir, @Local BlockPos.Mutable other_pos) {
if (!(view.getBlockEntity(other_pos) instanceof ThemeableBlockEntity)) return;
cir.setReturnValue(ReFramedBlock.shouldDrawSide(self_state, view, self_pos, face, other_pos, 0));
}
}

View File

@ -7,34 +7,23 @@ import fr.adrien1106.reframed.util.ThemeableBlockEntity;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo; import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView; import net.minecraft.world.BlockRenderView;
import net.minecraft.world.BlockView; import net.minecraft.world.BlockView;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BlockRenderInfo.class) @Mixin(BlockRenderInfo.class)
public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin { public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin {
@Shadow public BlockPos blockPos;
@Shadow public BlockState blockState;
@Shadow public BlockRenderView blockView;
@Shadow @Final private BlockPos.Mutable searchPos;
@Shadow public abstract void prepareForBlock(BlockState blockState, BlockPos blockPos, boolean modelAo); @Shadow public abstract void prepareForBlock(BlockState blockState, BlockPos blockPos, boolean modelAo);
@Shadow public BlockRenderView blockView;
@Unique @Unique
private int theme_index = 1; private int theme_index = 1;
@ -42,27 +31,18 @@ public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin {
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderLayers;" + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderLayers;" +
"getBlockLayer(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/RenderLayer;")) "getBlockLayer(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/RenderLayer;"))
public BlockState prepareCamoLayer(BlockState state, @Local(argsOnly = true) BlockPos pos) { public BlockState prepareCamoLayer(BlockState state, @Local(argsOnly = true) BlockPos pos) {
BlockEntity block_entity = MinecraftClient.getInstance().world.getBlockEntity(pos); BlockEntity block_entity = blockView.getBlockEntity(pos);
if (!(block_entity instanceof ThemeableBlockEntity frame_entity)) return state; if (!(block_entity instanceof ThemeableBlockEntity frame_entity)) return state;
return frame_entity.getTheme(theme_index); return frame_entity.getTheme(theme_index);
} }
@Inject(method = "shouldDrawFace",
at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/util/math/Direction;getId()I"),
cancellable = true)
private void shouldDrawCamoFace(Direction face, CallbackInfoReturnable<Boolean> cir) {
// early injection for camos themselves
BlockEntity block_entity = MinecraftClient.getInstance().world.getBlockEntity(blockPos);
if (!(block_entity instanceof ThemeableBlockEntity)) return;
cir.setReturnValue(ReFramedBlock.shouldDrawSide(blockState, blockView, blockPos, face, searchPos.set(blockPos, face), theme_index));
}
@Redirect(method = "shouldDrawFace", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;shouldDrawSide(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;Lnet/minecraft/util/math/BlockPos;)Z")) @Redirect(method = "shouldDrawFace", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;shouldDrawSide(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;Lnet/minecraft/util/math/BlockPos;)Z"))
private boolean shouldDrawAdjacentCamoSide(BlockState state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos) { private boolean shouldDrawAdjacentCamoSide(BlockState state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos) {
return ReFramedBlock.shouldDrawSide(state, world, pos, side, other_pos, theme_index); return ReFramedBlock.shouldDrawSide(state, world, pos, side, other_pos, theme_index);
} }
@Override @Override
@Unique
public void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index) { public void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index) {
this.theme_index = theme_index; this.theme_index = theme_index;
prepareForBlock(state, pos, ao); prepareForBlock(state, pos, ao);

View File

@ -21,9 +21,9 @@ public abstract class TerrainRenderContextMixin extends AbstractBlockRenderConte
@Inject(method = "tessellateBlock", at = @At( @Inject(method = "tessellateBlock", at = @At(
value = "INVOKE", value = "INVOKE",
target = "Lnet/fabricmc/fabric/impl/client/indigo/renderer/aocalc/AoCalculator;clear()V", target = "Lnet/fabricmc/fabric/impl/client/indigo/renderer/aocalc/AoCalculator;clear()V"
shift = At.Shift.AFTER ), remap = false,
), cancellable = true) cancellable = true)
private void renderMultipleModels(BlockState state, BlockPos pos, BakedModel wrapper, MatrixStack matrixStack, CallbackInfo ci) { private void renderMultipleModels(BlockState state, BlockPos pos, BakedModel wrapper, MatrixStack matrixStack, CallbackInfo ci) {
if (!(wrapper instanceof IMultipartBakedModelMixin wrapped) if (!(wrapper instanceof IMultipartBakedModelMixin wrapped)
|| !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return; || !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return;

View File

@ -6,4 +6,6 @@ import net.minecraft.util.math.BlockPos;
public interface IBlockRenderInfoMixin { public interface IBlockRenderInfoMixin {
void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index); void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index);
void prepareForBlock(BlockState state, BlockPos pos, long seed, boolean ao, int theme_index);
} }

View File

@ -31,6 +31,8 @@
"fabric-api": "*" "fabric-api": "*"
}, },
"suggest": { "suggest": {
"athena": "^${athena_version}" "athena": "^${athena_version}",
"sodium": "^${sodium_version}",
"indium": "^${indium_version}"
} }
} }

View File

@ -6,13 +6,17 @@
"mixins": [ "mixins": [
"WallBlockAccessor", "WallBlockAccessor",
"particles.MixinEntity", "particles.MixinEntity",
"particles.MixinLivingEntity" "particles.MixinLivingEntity",
"sound.LivingEntityMixin"
], ],
"client": [ "client": [
"MinecraftAccessor", "MinecraftAccessor",
"compat.AthenaBakedModelMixin", "compat.AthenaBakedModelMixin",
"compat.AthenaConnectedBlockModelMixin", "compat.AthenaConnectedBlockModelMixin",
"compat.AthenaWrappedGetterMixin", "compat.AthenaWrappedGetterMixin",
"compat.IndiumTerrainBlockRenderInfoMixin",
"compat.IndiumTerrainRenderContextMixin",
"compat.SodiumBlockOcclusionCacheMixin",
"model.WeightedBakedModelAccessor", "model.WeightedBakedModelAccessor",
"particles.AccessorParticle", "particles.AccessorParticle",
"particles.AccessorSpriteBillboardParticle", "particles.AccessorSpriteBillboardParticle",