weak reference utils, migrate villager prep code into central location

This commit is contained in:
yrsegal@gmail.com 2022-06-02 12:23:24 -04:00
parent af64fa4363
commit c4dceeeede
6 changed files with 69 additions and 103 deletions

View file

@ -12,10 +12,13 @@ import net.minecraft.world.InteractionHand
import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import java.lang.ref.WeakReference
import java.util.*
import kotlin.math.absoluteValue
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt
import kotlin.reflect.KProperty
const val TAU = Math.PI * 2.0
const val SQRT_3 = 1.7320508f
@ -168,6 +171,34 @@ val String.asTranslatedComponent get() = TranslatableComponent(this)
fun String.asTranslatedComponent(vararg args: Any) = TranslatableComponent(this, *args)
interface WeakValue<T> {
var value: T?
}
private class WeakReferencedValue<T>(var reference: WeakReference<T>?) : WeakValue<T> {
override var value: T?
get() = reference?.get()
set(value) { reference = value?.let { WeakReference(it) } }
}
private class WeakMappedValue<K, T>(val keyGen: (T) -> K) : WeakValue<T> {
val reference = WeakHashMap<K, T>()
override var value: T?
get() = reference.values.firstOrNull()
set(value) { if (value != null) reference[keyGen(value)] = value else reference.clear() }
}
fun <T> weakReference(value: T? = null): WeakValue<T> = WeakReferencedValue(value?.let { WeakReference(it) })
fun <T, K> weakMapped(keyGen: (T) -> K): WeakValue<T> = WeakMappedValue(keyGen)
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> WeakValue<T>.getValue(thisRef: Any?, property: KProperty<*>): T? = value
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> WeakValue<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T?) { this.value = value }
fun Iterable<SpellDatum<*>>.serializeToNBT(): ListTag {
val tag = ListTag()
for (elt in this)

View file

@ -4,7 +4,11 @@ package at.petrak.hexcasting.client
import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.utils.TAU
import at.petrak.hexcasting.api.utils.getValue
import at.petrak.hexcasting.api.utils.setValue
import at.petrak.hexcasting.api.utils.weakMapped
import at.petrak.hexcasting.client.gui.GuiSpellcasting
import at.petrak.hexcasting.common.recipe.ingredient.VillagerIngredient
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.PoseStack
@ -16,9 +20,14 @@ import net.minecraft.client.Minecraft
import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.core.BlockPos
import net.minecraft.core.Registry
import net.minecraft.util.FastColor
import net.minecraft.util.Mth
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.npc.Villager
import net.minecraft.world.entity.npc.VillagerProfession
import net.minecraft.world.entity.npc.VillagerType
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.levelgen.XoroshiroRandomSource
@ -286,6 +295,29 @@ fun transferMsToGl(ms: PoseStack, toRun: Runnable) {
RenderSystem.applyModelViewMatrix()
}
private var villager: Villager? by weakMapped { it.level }
fun prepareVillagerForRendering(ingredient: VillagerIngredient, level: Level): Villager {
val profession: VillagerProfession = Registry.VILLAGER_PROFESSION.getOptional(ingredient.profession())
.orElse(VillagerProfession.TOOLSMITH)
val biome: VillagerType = Registry.VILLAGER_TYPE.getOptional(ingredient.biome())
.orElse(VillagerType.PLAINS)
val minLevel: Int = ingredient.minLevel()
val instantiatedVillager = villager ?: run {
val newVillager = Villager(EntityType.VILLAGER, level)
villager = newVillager
newVillager
}
instantiatedVillager.villagerData = instantiatedVillager.villagerData
.setProfession(profession)
.setType(biome)
.setLevel(minLevel)
return instantiatedVillager
}
@JvmOverloads
fun renderEntity(
ms: PoseStack, entity: Entity, world: Level, x: Float, y: Float, rotation: Float,

View file

@ -1,6 +1,7 @@
package at.petrak.hexcasting.fabric.interop.emi;
import at.petrak.hexcasting.client.ClientTickCounter;
import at.petrak.hexcasting.client.RenderLib;
import at.petrak.hexcasting.client.shader.FakeBufferSource;
import at.petrak.hexcasting.client.shader.HexRenderTypes;
import at.petrak.hexcasting.common.recipe.ingredient.VillagerIngredient;
@ -21,8 +22,6 @@ import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerType;
import java.util.ArrayList;
import java.util.List;
@ -130,28 +129,13 @@ public class VillagerEmiStack extends EmiStack {
return ingredient.name();
}
// Used for rendering
private static Villager villager;
@Override
public void render(PoseStack poseStack, int x, int y, float delta, int flags) {
if ((flags & RENDER_ICON) != 0) {
Minecraft mc = Minecraft.getInstance();
ClientLevel level = mc.level;
if (level != null) {
VillagerProfession profession = Registry.VILLAGER_PROFESSION.getOptional(ingredient.profession())
.orElse(VillagerProfession.TOOLSMITH);
VillagerType biome = Registry.VILLAGER_TYPE.getOptional(ingredient.biome())
.orElse(VillagerType.PLAINS);
int minLevel = ingredient.minLevel();
if (villager == null) {
villager = new Villager(EntityType.VILLAGER, level);
}
villager.setVillagerData(villager.getVillagerData()
.setProfession(profession)
.setType(biome)
.setLevel(minLevel));
Villager villager = RenderLib.prepareVillagerForRendering(ingredient, level);
RenderSystem.enableBlend();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);

View file

@ -1,6 +1,7 @@
package at.petrak.hexcasting.fabric.interop.rei;
import at.petrak.hexcasting.client.ClientTickCounter;
import at.petrak.hexcasting.client.RenderLib;
import at.petrak.hexcasting.common.recipe.ingredient.VillagerIngredient;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
@ -10,11 +11,7 @@ import me.shedaniel.rei.api.client.gui.widgets.Widget;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.Registry;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerType;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
@ -27,8 +24,6 @@ public class VillagerWidget extends Widget {
private final int x;
private final int y;
private Villager displayVillager;
public VillagerWidget(VillagerIngredient villager, int x, int y) {
this.villager = villager;
this.x = x;
@ -39,19 +34,7 @@ public class VillagerWidget extends Widget {
public void render(@NotNull PoseStack poseStack, int mouseX, int mouseY, float delta) {
ClientLevel level = Minecraft.getInstance().level;
if (level != null) {
VillagerProfession profession = Registry.VILLAGER_PROFESSION.getOptional(villager.profession())
.orElse(VillagerProfession.TOOLSMITH);
VillagerType biome = Registry.VILLAGER_TYPE.getOptional(villager.biome())
.orElse(VillagerType.PLAINS);
int minLevel = villager.minLevel();
if (displayVillager == null) {
displayVillager = new Villager(EntityType.VILLAGER, level);
}
displayVillager.setVillagerData(displayVillager.getVillagerData()
.setProfession(profession)
.setType(biome)
.setLevel(minLevel));
Villager displayVillager = RenderLib.prepareVillagerForRendering(villager, level);
RenderSystem.enableBlend();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);

View file

@ -1,6 +1,7 @@
package at.petrak.hexcasting.forge.interop.jei;
import at.petrak.hexcasting.client.ClientTickCounter;
import at.petrak.hexcasting.client.RenderLib;
import at.petrak.hexcasting.common.recipe.BrainsweepRecipe;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
@ -15,23 +16,17 @@ import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.Registry;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerType;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import static at.petrak.hexcasting.api.HexAPI.modLoc;
import static at.petrak.hexcasting.client.RenderLib.renderEntity;
@ -78,27 +73,12 @@ public class BrainsweepRecipeCategory implements IRecipeCategory<BrainsweepRecip
return Collections.emptyList();
}
private Villager villager;
@Override
public void draw(@NotNull BrainsweepRecipe recipe, @NotNull IRecipeSlotsView recipeSlotsView,
@NotNull PoseStack stack, double mouseX, double mouseY) {
ClientLevel level = Minecraft.getInstance().level;
if (level != null) {
VillagerProfession profession = Objects.requireNonNullElse(
ForgeRegistries.PROFESSIONS.getValue(recipe.villagerIn().profession()),
VillagerProfession.TOOLSMITH);
VillagerType biome = Objects.requireNonNullElse(Registry.VILLAGER_TYPE.get(recipe.villagerIn().biome()),
VillagerType.PLAINS);
int minLevel = recipe.villagerIn().minLevel();
if (villager == null) {
villager = new Villager(EntityType.VILLAGER, level);
}
villager.setVillagerData(villager.getVillagerData()
.setProfession(profession)
.setType(biome)
.setLevel(minLevel));
Villager villager = RenderLib.prepareVillagerForRendering(recipe.villagerIn(), level);
RenderSystem.enableBlend();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);

View file

@ -1,44 +0,0 @@
package at.petrak.hexcasting.forge.misc;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import java.util.Map;
import java.util.WeakHashMap;
public final class PlayerPositionRecorder {
private static final Map<Player, Vec3> LAST_SECOND_POSITION_MAP = new WeakHashMap<>();
private static final Map<Player, Vec3> LAST_POSITION_MAP = new WeakHashMap<>();
@SubscribeEvent
public static void onEntityUpdate(TickEvent.WorldTickEvent evt) {
if (evt.phase == TickEvent.Phase.END && evt.world instanceof ServerLevel world) {
for (ServerPlayer player : world.players()) {
var prev = LAST_POSITION_MAP.get(player);
if (prev != null) {
LAST_SECOND_POSITION_MAP.put(player, prev);
}
LAST_POSITION_MAP.put(player, player.position());
}
}
}
public static Vec3 getMotion(ServerPlayer player) {
Vec3 vec = LAST_POSITION_MAP.get(player);
Vec3 prev = LAST_SECOND_POSITION_MAP.get(player);
if (vec == null) {
return Vec3.ZERO;
}
if (prev == null) {
return player.position().subtract(vec);
}
return vec.subtract(prev);
}
}