Add mob drop viewer to item list
This commit is contained in:
@@ -73,6 +73,15 @@ repositories {
|
|||||||
maven("https://maven.notenoughupdates.org/releases")
|
maven("https://maven.notenoughupdates.org/releases")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets.all {
|
||||||
|
languageSettings {
|
||||||
|
// languageVersion = "2.0"
|
||||||
|
enableLanguageFeature("BreakContinueInInlineLambdas")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val shadowMe by configurations.creating {
|
val shadowMe by configurations.creating {
|
||||||
exclude(group = "org.jetbrains.kotlin")
|
exclude(group = "org.jetbrains.kotlin")
|
||||||
exclude(group = "org.jetbrains.kotlinx")
|
exclude(group = "org.jetbrains.kotlinx")
|
||||||
@@ -109,8 +118,10 @@ dependencies {
|
|||||||
modImplementation(libs.modmenu)
|
modImplementation(libs.modmenu)
|
||||||
modImplementation(libs.libgui)
|
modImplementation(libs.libgui)
|
||||||
modImplementation(libs.moulconfig)
|
modImplementation(libs.moulconfig)
|
||||||
|
modImplementation(libs.manninghamMills)
|
||||||
modCompileOnly(libs.explosiveenhancement)
|
modCompileOnly(libs.explosiveenhancement)
|
||||||
include(libs.libgui)
|
include(libs.libgui)
|
||||||
|
include(libs.manninghamMills)
|
||||||
include(libs.moulconfig)
|
include(libs.moulconfig)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ jarvis = "1.1.1"
|
|||||||
nealisp = "1.0.0"
|
nealisp = "1.0.0"
|
||||||
explosiveenhancement = "1.2.2-1.20.x"
|
explosiveenhancement = "1.2.2-1.20.x"
|
||||||
moulconfig = "3.0.0-beta.5"
|
moulconfig = "3.0.0-beta.5"
|
||||||
|
manninghamMills = "2.4.1"
|
||||||
|
notenoughanimations = "ZLjUeuU8"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
|
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
|
||||||
@@ -46,8 +47,9 @@ jarvis_api = { module = "moe.nea.jarvis:jarvis-api", version.ref = "jarvis" }
|
|||||||
jarvis_fabric = { module = "moe.nea.jarvis:jarvis-fabric", version.ref = "jarvis" }
|
jarvis_fabric = { module = "moe.nea.jarvis:jarvis-fabric", version.ref = "jarvis" }
|
||||||
nealisp = { module = "moe.nea:nealisp", version.ref = "nealisp" }
|
nealisp = { module = "moe.nea:nealisp", version.ref = "nealisp" }
|
||||||
explosiveenhancement = { module = "maven.modrinth:explosive-enhancement", version.ref = "explosiveenhancement" }
|
explosiveenhancement = { module = "maven.modrinth:explosive-enhancement", version.ref = "explosiveenhancement" }
|
||||||
|
manninghamMills = { module = "me.shedaniel:mm", version.ref = "manninghamMills" }
|
||||||
# Runtime:
|
# Runtime:
|
||||||
|
notenoughanimations = { module = "maven.modrinth:not-enough-animations", version.ref = "notenoughanimations" }
|
||||||
hotswap = { module = "virtual.github.hotswapagent:hotswap-agent", version.ref = "hotswap_agent" }
|
hotswap = { module = "virtual.github.hotswapagent:hotswap-agent", version.ref = "hotswap_agent" }
|
||||||
architectury_fabric = { module = "dev.architectury:architectury-fabric", version.ref = "architectury" }
|
architectury_fabric = { module = "dev.architectury:architectury-fabric", version.ref = "architectury" }
|
||||||
rei_fabric = { module = "me.shedaniel:RoughlyEnoughItems-fabric", version.ref = "rei" }
|
rei_fabric = { module = "me.shedaniel:RoughlyEnoughItems-fabric", version.ref = "rei" }
|
||||||
@@ -61,7 +63,12 @@ freecammod = { module = "maven.modrinth:freecam", version.ref = "freecammod" }
|
|||||||
|
|
||||||
[bundles]
|
[bundles]
|
||||||
dbus = ["dbus_java_core", "dbus_java_unixsocket"]
|
dbus = ["dbus_java_core", "dbus_java_unixsocket"]
|
||||||
runtime_required = ["architectury_fabric", "rei_fabric"]
|
runtime_required = [
|
||||||
|
"architectury_fabric",
|
||||||
|
"rei_fabric",
|
||||||
|
"notenoughanimations",
|
||||||
|
|
||||||
|
]
|
||||||
runtime_optional = [
|
runtime_optional = [
|
||||||
"devauth",
|
"devauth",
|
||||||
# "freecammod",
|
# "freecammod",
|
||||||
|
|||||||
78
src/main/java/moe/nea/firmament/init/EarlyRiser.java
Normal file
78
src/main/java/moe/nea/firmament/init/EarlyRiser.java
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.init;
|
||||||
|
|
||||||
|
import me.shedaniel.mm.api.ClassTinkerers;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.fabricmc.loader.api.MappingResolver;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.tree.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class EarlyRiser implements Runnable {
|
||||||
|
MappingResolver remapper = FabricLoader.getInstance().getMappingResolver();
|
||||||
|
String PlayerEntity = remapper.mapClassName("intermediary", "net.minecraft.class_1657");
|
||||||
|
String World = remapper.mapClassName("intermediary", "net.minecraft.class_1937");
|
||||||
|
String GameProfile = "com.mojang.authlib.GameProfile";
|
||||||
|
String BlockPos = remapper.mapClassName("intermediary", "net.minecraft.class_2338");
|
||||||
|
String AbstractClientPlayerEntity = remapper.mapClassName("intermediary", "net.minecraft.class_742");
|
||||||
|
String GuiPlayer = "moe.nea.firmament.gui.entity.GuiPlayer";
|
||||||
|
// World world, BlockPos pos, float yaw, GameProfile gameProfile
|
||||||
|
Type constructorDescriptor = Type.getMethodType(Type.VOID_TYPE, getTypeForClassName(World), getTypeForClassName(BlockPos), Type.FLOAT_TYPE, getTypeForClassName(GameProfile));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
ClassTinkerers.addTransformation(AbstractClientPlayerEntity, it -> mapClassNode(it, getTypeForClassName(PlayerEntity)));
|
||||||
|
ClassTinkerers.addTransformation(GuiPlayer, it -> mapClassNode(it, getTypeForClassName(AbstractClientPlayerEntity)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mapClassNode(ClassNode classNode, Type superClass) {
|
||||||
|
for (MethodNode method : classNode.methods) {
|
||||||
|
if (Objects.equals(method.name, "<init>") && Type.getMethodType(method.desc).equals(constructorDescriptor)) {
|
||||||
|
modifyConstructor(method, superClass);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var node = new MethodNode(Opcodes.ASM9, "<init>", constructorDescriptor.getDescriptor(), null, null);
|
||||||
|
classNode.methods.add(node);
|
||||||
|
modifyConstructor(node, superClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type getTypeForClassName(String className) {
|
||||||
|
return Type.getObjectType(className.replace('.', '/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void modifyConstructor(MethodNode method, Type superClass) {
|
||||||
|
method.access = (method.access | Modifier.PUBLIC) & ~Modifier.PRIVATE & ~Modifier.PROTECTED;
|
||||||
|
if (method.instructions.size() != 0) return; // Some other mod has already made a constructor here
|
||||||
|
|
||||||
|
// World world, BlockPos pos, float yaw, GameProfile gameProfile
|
||||||
|
// ALOAD this
|
||||||
|
method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||||
|
|
||||||
|
// ALOAD World
|
||||||
|
method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
|
||||||
|
|
||||||
|
// ALOAD BlockPos
|
||||||
|
method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 2));
|
||||||
|
|
||||||
|
// ALOAD yaw
|
||||||
|
method.instructions.add(new VarInsnNode(Opcodes.FLOAD, 3));
|
||||||
|
|
||||||
|
// ALOAD gameProfile
|
||||||
|
method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 4));
|
||||||
|
|
||||||
|
// Call super
|
||||||
|
method.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, superClass.getInternalName(), "<init>", constructorDescriptor.getDescriptor(), false));
|
||||||
|
|
||||||
|
// Return
|
||||||
|
method.instructions.add(new InsnNode(Opcodes.RETURN));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.mixins;
|
||||||
|
|
||||||
|
import moe.nea.firmament.repo.RepoModResourcePack;
|
||||||
|
import net.fabricmc.fabric.api.resource.ModResourcePack;
|
||||||
|
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackUtil;
|
||||||
|
import net.minecraft.resource.ResourceType;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
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(ModResourcePackUtil.class)
|
||||||
|
public class AppendRepoAsResourcePack {
|
||||||
|
@Inject(method = "appendModResourcePacks", at = @At("TAIL"))
|
||||||
|
private static void onAppendModResourcePack(
|
||||||
|
List<ModResourcePack> packs,
|
||||||
|
ResourceType type,
|
||||||
|
@Nullable String subPath,
|
||||||
|
CallbackInfo ci
|
||||||
|
) {
|
||||||
|
RepoModResourcePack.Companion.append(packs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.mixins.accessor;
|
||||||
|
|
||||||
|
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||||
|
import net.minecraft.client.network.PlayerListEntry;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
@Mixin(AbstractClientPlayerEntity.class)
|
||||||
|
public interface AccessorAbstractClientPlayerEntity {
|
||||||
|
@Accessor("playerListEntry")
|
||||||
|
void setPlayerListEntry_firmament(PlayerListEntry playerListEntry);
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
@@ -52,7 +53,12 @@ fun firmamentCommand() = literal("firmament") {
|
|||||||
|
|
||||||
val configObj = AllConfigsGui.allConfigs.find { it.name == config }
|
val configObj = AllConfigsGui.allConfigs.find { it.name == config }
|
||||||
if (configObj == null) {
|
if (configObj == null) {
|
||||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.command.toggle.no-config-found", config))
|
source.sendFeedback(
|
||||||
|
Text.stringifiedTranslatable(
|
||||||
|
"firmament.command.toggle.no-config-found",
|
||||||
|
config
|
||||||
|
)
|
||||||
|
)
|
||||||
return@thenExecute
|
return@thenExecute
|
||||||
}
|
}
|
||||||
val propertyObj = configObj.allOptions[property]
|
val propertyObj = configObj.allOptions[property]
|
||||||
@@ -72,9 +78,11 @@ fun firmamentCommand() = literal("firmament") {
|
|||||||
propertyObj.value = !propertyObj.value
|
propertyObj.value = !propertyObj.value
|
||||||
configObj.save()
|
configObj.save()
|
||||||
source.sendFeedback(
|
source.sendFeedback(
|
||||||
Text.stringifiedTranslatable("firmament.command.toggle.toggled",configObj.labelText,
|
Text.stringifiedTranslatable(
|
||||||
propertyObj.labelText,
|
"firmament.command.toggle.toggled", configObj.labelText,
|
||||||
Text.translatable("firmament.toggle.${propertyObj.value}"))
|
propertyObj.labelText,
|
||||||
|
Text.translatable("firmament.toggle.${propertyObj.value}")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,22 +152,37 @@ fun firmamentCommand() = literal("firmament") {
|
|||||||
Text.stringifiedTranslatable("firmament.price.bazaar.productid", bazaarData.productId.bazaarId)
|
Text.stringifiedTranslatable("firmament.price.bazaar.productid", bazaarData.productId.bazaarId)
|
||||||
)
|
)
|
||||||
source.sendFeedback(
|
source.sendFeedback(
|
||||||
Text.stringifiedTranslatable("firmament.price.bazaar.buy.price", FirmFormatters.formatCurrency(bazaarData.quickStatus.buyPrice, 1))
|
Text.stringifiedTranslatable(
|
||||||
|
"firmament.price.bazaar.buy.price",
|
||||||
|
FirmFormatters.formatCurrency(bazaarData.quickStatus.buyPrice, 1)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
source.sendFeedback(
|
source.sendFeedback(
|
||||||
Text.stringifiedTranslatable("firmament.price.bazaar.buy.order", bazaarData.quickStatus.buyOrders)
|
Text.stringifiedTranslatable(
|
||||||
|
"firmament.price.bazaar.buy.order",
|
||||||
|
bazaarData.quickStatus.buyOrders
|
||||||
|
)
|
||||||
)
|
)
|
||||||
source.sendFeedback(
|
source.sendFeedback(
|
||||||
Text.stringifiedTranslatable("firmament.price.bazaar.sell.price", FirmFormatters.formatCurrency(bazaarData.quickStatus.sellPrice, 1))
|
Text.stringifiedTranslatable(
|
||||||
|
"firmament.price.bazaar.sell.price",
|
||||||
|
FirmFormatters.formatCurrency(bazaarData.quickStatus.sellPrice, 1)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
source.sendFeedback(
|
source.sendFeedback(
|
||||||
Text.stringifiedTranslatable("firmament.price.bazaar.sell.order", bazaarData.quickStatus.sellOrders)
|
Text.stringifiedTranslatable(
|
||||||
|
"firmament.price.bazaar.sell.order",
|
||||||
|
bazaarData.quickStatus.sellOrders
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val lowestBin = HypixelStaticData.lowestBin[itemName]
|
val lowestBin = HypixelStaticData.lowestBin[itemName]
|
||||||
if (lowestBin != null) {
|
if (lowestBin != null) {
|
||||||
source.sendFeedback(
|
source.sendFeedback(
|
||||||
Text.stringifiedTranslatable("firmament.price.lowestbin", FirmFormatters.formatCurrency(lowestBin, 1))
|
Text.stringifiedTranslatable(
|
||||||
|
"firmament.price.lowestbin",
|
||||||
|
FirmFormatters.formatCurrency(lowestBin, 1)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
|
||||||
|
fun interface EntityModifier {
|
||||||
|
fun apply(entity: LivingEntity, info: JsonObject): LivingEntity
|
||||||
|
}
|
||||||
202
src/main/kotlin/moe/nea/firmament/gui/entity/EntityRenderer.kt
Normal file
202
src/main/kotlin/moe/nea/firmament/gui/entity/EntityRenderer.kt
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import org.joml.Quaternionf
|
||||||
|
import org.joml.Vector3f
|
||||||
|
import kotlin.math.atan
|
||||||
|
import net.minecraft.client.gui.DrawContext
|
||||||
|
import net.minecraft.client.gui.screen.ingame.InventoryScreen
|
||||||
|
import net.minecraft.entity.Entity
|
||||||
|
import net.minecraft.entity.EntityType
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import moe.nea.firmament.util.MC
|
||||||
|
import moe.nea.firmament.util.assertNotNullOr
|
||||||
|
import moe.nea.firmament.util.iterate
|
||||||
|
import moe.nea.firmament.util.openFirmamentResource
|
||||||
|
import moe.nea.firmament.util.render.enableScissorWithTranslation
|
||||||
|
|
||||||
|
object EntityRenderer {
|
||||||
|
val fakeWorld = FakeWorld()
|
||||||
|
private fun <T : Entity> t(entityType: EntityType<T>): () -> T {
|
||||||
|
return { entityType.create(fakeWorld)!! }
|
||||||
|
}
|
||||||
|
|
||||||
|
val entityIds: Map<String, () -> LivingEntity> = mapOf(
|
||||||
|
"Zombie" to t(EntityType.ZOMBIE),
|
||||||
|
"Chicken" to t(EntityType.CHICKEN),
|
||||||
|
"Slime" to t(EntityType.SLIME),
|
||||||
|
"Wolf" to t(EntityType.WOLF),
|
||||||
|
"Skeleton" to t(EntityType.SKELETON),
|
||||||
|
"Creeper" to t(EntityType.CREEPER),
|
||||||
|
"Ocelot" to t(EntityType.OCELOT),
|
||||||
|
"Blaze" to t(EntityType.BLAZE),
|
||||||
|
"Rabbit" to t(EntityType.RABBIT),
|
||||||
|
"Sheep" to t(EntityType.SHEEP),
|
||||||
|
"Horse" to t(EntityType.HORSE),
|
||||||
|
"Eisengolem" to t(EntityType.IRON_GOLEM),
|
||||||
|
"Silverfish" to t(EntityType.SILVERFISH),
|
||||||
|
"Witch" to t(EntityType.WITCH),
|
||||||
|
"Endermite" to t(EntityType.ENDERMITE),
|
||||||
|
"Snowman" to t(EntityType.SNOW_GOLEM),
|
||||||
|
"Villager" to t(EntityType.VILLAGER),
|
||||||
|
"Guardian" to t(EntityType.GUARDIAN),
|
||||||
|
"ArmorStand" to t(EntityType.ARMOR_STAND),
|
||||||
|
"Squid" to t(EntityType.SQUID),
|
||||||
|
"Bat" to t(EntityType.BAT),
|
||||||
|
"Spider" to t(EntityType.SPIDER),
|
||||||
|
"CaveSpider" to t(EntityType.CAVE_SPIDER),
|
||||||
|
"Pigman" to t(EntityType.ZOMBIFIED_PIGLIN),
|
||||||
|
"Ghast" to t(EntityType.GHAST),
|
||||||
|
"MagmaCube" to t(EntityType.MAGMA_CUBE),
|
||||||
|
"Wither" to t(EntityType.WITHER),
|
||||||
|
"Enderman" to t(EntityType.ENDERMAN),
|
||||||
|
"Mooshroom" to t(EntityType.MOOSHROOM),
|
||||||
|
"WitherSkeleton" to t(EntityType.WITHER_SKELETON),
|
||||||
|
"Cow" to t(EntityType.COW),
|
||||||
|
"Dragon" to t(EntityType.ENDER_DRAGON),
|
||||||
|
"Player" to { makeGuiPlayer(fakeWorld) },
|
||||||
|
"Pig" to t(EntityType.PIG),
|
||||||
|
"Giant" to t(EntityType.GIANT),
|
||||||
|
)
|
||||||
|
val entityModifiers: Map<String, EntityModifier> = mapOf(
|
||||||
|
"playerdata" to ModifyPlayerSkin,
|
||||||
|
"equipment" to ModifyEquipment,
|
||||||
|
"riding" to ModifyRiding,
|
||||||
|
"charged" to ModifyCharged,
|
||||||
|
"witherdata" to ModifyWither,
|
||||||
|
"invisible" to ModifyInvisible,
|
||||||
|
"age" to ModifyAge,
|
||||||
|
"horse" to ModifyHorse,
|
||||||
|
"name" to ModifyName,
|
||||||
|
)
|
||||||
|
|
||||||
|
val logger = LogManager.getLogger("Firmament.Entity")
|
||||||
|
fun applyModifiers(entityId: String, modifiers: List<JsonObject>): LivingEntity? {
|
||||||
|
val entityType = assertNotNullOr(entityIds[entityId]) {
|
||||||
|
logger.error("Could not create entity with id $entityId")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
var entity = entityType()
|
||||||
|
for (modifierJson in modifiers) {
|
||||||
|
val modifier = assertNotNullOr(modifierJson["type"]?.asString?.let(entityModifiers::get)) {
|
||||||
|
logger.error("Unknown modifier $modifierJson")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
entity = modifier.apply(entity, modifierJson)
|
||||||
|
}
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
|
||||||
|
fun constructEntity(info: JsonObject): LivingEntity? {
|
||||||
|
val modifiers = (info["modifiers"] as JsonArray?)?.map { it.asJsonObject } ?: emptyList()
|
||||||
|
val entityType = assertNotNullOr(info["entity"]?.asString) {
|
||||||
|
logger.error("Missing entity type on entity object")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return applyModifiers(entityType, modifiers)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val gson = Gson()
|
||||||
|
fun constructEntity(location: Identifier): LivingEntity? {
|
||||||
|
return constructEntity(
|
||||||
|
gson.fromJson(
|
||||||
|
location.openFirmamentResource().bufferedReader(), JsonObject::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun renderEntity(
|
||||||
|
entity: LivingEntity,
|
||||||
|
renderContext: DrawContext,
|
||||||
|
posX: Int,
|
||||||
|
posY: Int,
|
||||||
|
mouseX: Float,
|
||||||
|
mouseY: Float
|
||||||
|
) {
|
||||||
|
var bottomOffset = 0.0F
|
||||||
|
var currentEntity = entity
|
||||||
|
val maxSize = entity.iterate { it.firstPassenger as? LivingEntity }
|
||||||
|
.map { it.height }
|
||||||
|
.sum()
|
||||||
|
while (true) {
|
||||||
|
currentEntity.age = MC.player?.age ?: 0
|
||||||
|
drawEntity(
|
||||||
|
renderContext,
|
||||||
|
posX,
|
||||||
|
posY,
|
||||||
|
posX + 50,
|
||||||
|
posY + 80,
|
||||||
|
(2F / maxSize * 30).toInt(),
|
||||||
|
-bottomOffset,
|
||||||
|
mouseX,
|
||||||
|
mouseY,
|
||||||
|
currentEntity
|
||||||
|
)
|
||||||
|
val next = currentEntity.firstPassenger as? LivingEntity ?: break
|
||||||
|
bottomOffset += currentEntity.getPassengerRidingPos(next).y.toFloat() * 0.75F
|
||||||
|
currentEntity = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun drawEntity(
|
||||||
|
context: DrawContext,
|
||||||
|
x1: Int,
|
||||||
|
y1: Int,
|
||||||
|
x2: Int,
|
||||||
|
y2: Int,
|
||||||
|
size: Int,
|
||||||
|
bottomOffset: Float,
|
||||||
|
mouseX: Float,
|
||||||
|
mouseY: Float,
|
||||||
|
entity: LivingEntity
|
||||||
|
) {
|
||||||
|
context.enableScissorWithTranslation(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat())
|
||||||
|
val centerX = (x1 + x2) / 2f
|
||||||
|
val centerY = (y1 + y2) / 2f
|
||||||
|
val targetYaw = atan(((centerX - mouseX) / 40.0f).toDouble()).toFloat()
|
||||||
|
val targetPitch = atan(((centerY - mouseY) / 40.0f).toDouble()).toFloat()
|
||||||
|
val rotateToFaceTheFront = Quaternionf().rotateZ(Math.PI.toFloat())
|
||||||
|
val rotateToFaceTheCamera = Quaternionf().rotateX(targetPitch * 20.0f * (Math.PI.toFloat() / 180))
|
||||||
|
rotateToFaceTheFront.mul(rotateToFaceTheCamera)
|
||||||
|
val oldBodyYaw = entity.bodyYaw
|
||||||
|
val oldYaw = entity.yaw
|
||||||
|
val oldPitch = entity.pitch
|
||||||
|
val oldPrevHeadYaw = entity.prevHeadYaw
|
||||||
|
val oldHeadYaw = entity.headYaw
|
||||||
|
entity.bodyYaw = 180.0f + targetYaw * 20.0f
|
||||||
|
entity.yaw = 180.0f + targetYaw * 40.0f
|
||||||
|
entity.pitch = -targetPitch * 20.0f
|
||||||
|
entity.headYaw = entity.yaw
|
||||||
|
entity.prevHeadYaw = entity.yaw
|
||||||
|
val vector3f = Vector3f(0.0f, entity.height / 2.0f + bottomOffset, 0.0f)
|
||||||
|
InventoryScreen.drawEntity(
|
||||||
|
context,
|
||||||
|
centerX,
|
||||||
|
centerY,
|
||||||
|
size,
|
||||||
|
vector3f,
|
||||||
|
rotateToFaceTheFront,
|
||||||
|
rotateToFaceTheCamera,
|
||||||
|
entity
|
||||||
|
)
|
||||||
|
entity.bodyYaw = oldBodyYaw
|
||||||
|
entity.yaw = oldYaw
|
||||||
|
entity.pitch = oldPitch
|
||||||
|
entity.prevHeadYaw = oldPrevHeadYaw
|
||||||
|
entity.headYaw = oldHeadYaw
|
||||||
|
context.disableScissor()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
40
src/main/kotlin/moe/nea/firmament/gui/entity/EntityWidget.kt
Normal file
40
src/main/kotlin/moe/nea/firmament/gui/entity/EntityWidget.kt
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import me.shedaniel.math.Dimension
|
||||||
|
import me.shedaniel.math.Point
|
||||||
|
import me.shedaniel.math.Rectangle
|
||||||
|
import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds
|
||||||
|
import net.minecraft.client.gui.DrawContext
|
||||||
|
import net.minecraft.client.gui.Element
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
|
||||||
|
class EntityWidget(val entity: LivingEntity, val point: Point) : WidgetWithBounds() {
|
||||||
|
override fun children(): List<Element> {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasErrored = false
|
||||||
|
|
||||||
|
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||||
|
try {
|
||||||
|
if (!hasErrored)
|
||||||
|
EntityRenderer.renderEntity(entity, context, point.x, point.y, mouseX.toFloat(), mouseY.toFloat())
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
EntityRenderer.logger.error("Failed to render constructed entity: $entity", ex)
|
||||||
|
hasErrored = true
|
||||||
|
}
|
||||||
|
if (hasErrored) {
|
||||||
|
context.fill(point.x, point.y, point.x + 50, point.y + 80, 0xFFAA2222.toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBounds(): Rectangle {
|
||||||
|
return Rectangle(point, Dimension(50, 80))
|
||||||
|
}
|
||||||
|
}
|
||||||
491
src/main/kotlin/moe/nea/firmament/gui/entity/FakeWorld.kt
Normal file
491
src/main/kotlin/moe/nea/firmament/gui/entity/FakeWorld.kt
Normal file
@@ -0,0 +1,491 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Pair
|
||||||
|
import com.mojang.serialization.Lifecycle
|
||||||
|
import java.util.*
|
||||||
|
import java.util.function.BooleanSupplier
|
||||||
|
import java.util.function.Consumer
|
||||||
|
import java.util.stream.Stream
|
||||||
|
import kotlin.jvm.optionals.getOrNull
|
||||||
|
import kotlin.streams.asSequence
|
||||||
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.client.world.ClientWorld
|
||||||
|
import net.minecraft.entity.Entity
|
||||||
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
import net.minecraft.fluid.Fluid
|
||||||
|
import net.minecraft.item.map.MapState
|
||||||
|
import net.minecraft.recipe.RecipeManager
|
||||||
|
import net.minecraft.registry.BuiltinRegistries
|
||||||
|
import net.minecraft.registry.DynamicRegistryManager
|
||||||
|
import net.minecraft.registry.Registry
|
||||||
|
import net.minecraft.registry.RegistryKey
|
||||||
|
import net.minecraft.registry.RegistryKeys
|
||||||
|
import net.minecraft.registry.RegistryWrapper
|
||||||
|
import net.minecraft.registry.entry.RegistryEntry
|
||||||
|
import net.minecraft.registry.entry.RegistryEntryList
|
||||||
|
import net.minecraft.registry.entry.RegistryEntryOwner
|
||||||
|
import net.minecraft.registry.tag.TagKey
|
||||||
|
import net.minecraft.resource.featuretoggle.FeatureFlag
|
||||||
|
import net.minecraft.resource.featuretoggle.FeatureFlags
|
||||||
|
import net.minecraft.resource.featuretoggle.FeatureSet
|
||||||
|
import net.minecraft.scoreboard.Scoreboard
|
||||||
|
import net.minecraft.sound.SoundCategory
|
||||||
|
import net.minecraft.sound.SoundEvent
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.TypeFilter
|
||||||
|
import net.minecraft.util.function.LazyIterationConsumer
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.util.math.Box
|
||||||
|
import net.minecraft.util.math.ChunkPos
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
import net.minecraft.util.math.Vec3d
|
||||||
|
import net.minecraft.util.math.random.Random
|
||||||
|
import net.minecraft.util.profiler.DummyProfiler
|
||||||
|
import net.minecraft.world.BlockView
|
||||||
|
import net.minecraft.world.Difficulty
|
||||||
|
import net.minecraft.world.GameRules
|
||||||
|
import net.minecraft.world.MutableWorldProperties
|
||||||
|
import net.minecraft.world.World
|
||||||
|
import net.minecraft.world.biome.Biome
|
||||||
|
import net.minecraft.world.biome.BiomeKeys
|
||||||
|
import net.minecraft.world.chunk.Chunk
|
||||||
|
import net.minecraft.world.chunk.ChunkManager
|
||||||
|
import net.minecraft.world.chunk.ChunkStatus
|
||||||
|
import net.minecraft.world.chunk.EmptyChunk
|
||||||
|
import net.minecraft.world.chunk.light.LightingProvider
|
||||||
|
import net.minecraft.world.entity.EntityLookup
|
||||||
|
import net.minecraft.world.event.GameEvent
|
||||||
|
import net.minecraft.world.tick.OrderedTick
|
||||||
|
import net.minecraft.world.tick.QueryableTickScheduler
|
||||||
|
import net.minecraft.world.tick.TickManager
|
||||||
|
|
||||||
|
fun <T> makeRegistry(registryWrapper: RegistryWrapper.Impl<T>, key: RegistryKey<out Registry<T>>): Registry<T> {
|
||||||
|
val inverseLookup = registryWrapper.streamEntries()
|
||||||
|
.asSequence().map { it.value() to it.registryKey() }
|
||||||
|
.toMap()
|
||||||
|
val idLookup = registryWrapper.streamEntries()
|
||||||
|
.asSequence()
|
||||||
|
.map { it.registryKey() }
|
||||||
|
.withIndex()
|
||||||
|
.associate { it.value to it.index }
|
||||||
|
val map = registryWrapper.streamEntries().asSequence().map { it.registryKey() to it.value() }.toMap(mutableMapOf())
|
||||||
|
val inverseIdLookup = idLookup.asIterable().associate { (k, v) -> v to k }
|
||||||
|
return object : Registry<T> {
|
||||||
|
override fun get(key: RegistryKey<T>?): T? {
|
||||||
|
return registryWrapper.getOptional(key).getOrNull()?.value()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iterator(): MutableIterator<T> {
|
||||||
|
return object : MutableIterator<T> {
|
||||||
|
val iterator = registryWrapper.streamEntries().iterator()
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
return iterator.hasNext()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun next(): T {
|
||||||
|
return iterator.next().value()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove() {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRawId(value: T?): Int {
|
||||||
|
return idLookup[inverseLookup[value ?: return -1] ?: return -1] ?: return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(id: Identifier?): T? {
|
||||||
|
return get(RegistryKey.of(key, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(index: Int): T? {
|
||||||
|
return get(inverseIdLookup[index] ?: return null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun size(): Int {
|
||||||
|
return idLookup.size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getKey(): RegistryKey<out Registry<T>> {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLifecycle(): Lifecycle {
|
||||||
|
return Lifecycle.stable()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIds(): MutableSet<Identifier> {
|
||||||
|
return idLookup.keys.mapTo(mutableSetOf()) { it.value }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEntrySet(): MutableSet<MutableMap.MutableEntry<RegistryKey<T>, T>> {
|
||||||
|
return map.entries
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getKeys(): MutableSet<RegistryKey<T>> {
|
||||||
|
return map.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRandom(random: Random?): Optional<RegistryEntry.Reference<T>> {
|
||||||
|
return registryWrapper.streamEntries().findFirst()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun containsId(id: Identifier?): Boolean {
|
||||||
|
return idLookup.containsKey(RegistryKey.of(key, id ?: return false))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun freeze(): Registry<T> {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEntry(rawId: Int): Optional<RegistryEntry.Reference<T>> {
|
||||||
|
val x = inverseIdLookup[rawId] ?: return Optional.empty()
|
||||||
|
return Optional.of(RegistryEntry.Reference.standAlone(registryWrapper, x))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun streamEntries(): Stream<RegistryEntry.Reference<T>> {
|
||||||
|
return registryWrapper.streamEntries()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun streamTagsAndEntries(): Stream<Pair<TagKey<T>, RegistryEntryList.Named<T>>> {
|
||||||
|
return streamTags().map { Pair(it, getOrCreateEntryList(it)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun streamTags(): Stream<TagKey<T>> {
|
||||||
|
return registryWrapper.streamTagKeys()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearTags() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEntryOwner(): RegistryEntryOwner<T> {
|
||||||
|
return registryWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getReadOnlyWrapper(): RegistryWrapper.Impl<T> {
|
||||||
|
return registryWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun populateTags(tagEntries: MutableMap<TagKey<T>, MutableList<RegistryEntry<T>>>?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOrCreateEntryList(tag: TagKey<T>?): RegistryEntryList.Named<T> {
|
||||||
|
return getEntryList(tag).orElseGet { RegistryEntryList.of(registryWrapper, tag) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEntryList(tag: TagKey<T>?): Optional<RegistryEntryList.Named<T>> {
|
||||||
|
return registryWrapper.getOptional(tag ?: return Optional.empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEntry(value: T): RegistryEntry<T> {
|
||||||
|
return registryWrapper.getOptional(inverseLookup[value]!!).get()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEntry(key: RegistryKey<T>?): Optional<RegistryEntry.Reference<T>> {
|
||||||
|
return registryWrapper.getOptional(key ?: return Optional.empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createEntry(value: T): RegistryEntry.Reference<T> {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun contains(key: RegistryKey<T>?): Boolean {
|
||||||
|
return getEntry(key).isPresent
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEntryLifecycle(entry: T): Lifecycle {
|
||||||
|
return Lifecycle.stable()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getId(value: T): Identifier? {
|
||||||
|
return (inverseLookup[value] ?: return null).value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getKey(entry: T): Optional<RegistryKey<T>> {
|
||||||
|
return Optional.ofNullable(inverseLookup[entry ?: return Optional.empty()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createDynamicRegistry(): DynamicRegistryManager.Immutable {
|
||||||
|
val wrapperLookup = BuiltinRegistries.createWrapperLookup()
|
||||||
|
return object : DynamicRegistryManager.Immutable {
|
||||||
|
override fun <E : Any?> getOptional(key: RegistryKey<out Registry<out E>>): Optional<Registry<E>> {
|
||||||
|
val lookup = wrapperLookup.getOptionalWrapper(key).getOrNull() ?: return Optional.empty()
|
||||||
|
val registry = makeRegistry(lookup, key as RegistryKey<out Registry<E>>)
|
||||||
|
return Optional.of(registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> entry(reg: RegistryKey<out Registry<T>>): DynamicRegistryManager.Entry<T> {
|
||||||
|
return DynamicRegistryManager.Entry(reg, getOptional(reg).get())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun streamAllRegistries(): Stream<DynamicRegistryManager.Entry<*>> {
|
||||||
|
return wrapperLookup.streamAllRegistryKeys()
|
||||||
|
.map { entry(it as RegistryKey<out Registry<Any>>) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeWorld(registries: DynamicRegistryManager.Immutable = createDynamicRegistry()) : World(
|
||||||
|
Properties,
|
||||||
|
RegistryKey.of(RegistryKeys.WORLD, Identifier.of("firmament", "fakeworld")),
|
||||||
|
registries,
|
||||||
|
registries[RegistryKeys.DIMENSION_TYPE].entryOf(
|
||||||
|
RegistryKey.of(
|
||||||
|
RegistryKeys.DIMENSION_TYPE,
|
||||||
|
Identifier("minecraft", "overworld")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
{ DummyProfiler.INSTANCE },
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
0, 0
|
||||||
|
) {
|
||||||
|
object Properties : MutableWorldProperties {
|
||||||
|
override fun getSpawnX(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSpawnY(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSpawnZ(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSpawnAngle(): Float {
|
||||||
|
return 0F
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTime(): Long {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTimeOfDay(): Long {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isThundering(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isRaining(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setRaining(raining: Boolean) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isHardcore(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getGameRules(): GameRules {
|
||||||
|
return GameRules()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDifficulty(): Difficulty {
|
||||||
|
return Difficulty.HARD
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isDifficultyLocked(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setSpawnX(spawnX: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setSpawnY(spawnY: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setSpawnZ(spawnZ: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setSpawnAngle(spawnAngle: Float) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPlayers(): List<PlayerEntity> {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBrightness(direction: Direction?, shaded: Boolean): Float {
|
||||||
|
return 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getGeneratorStoredBiome(biomeX: Int, biomeY: Int, biomeZ: Int): RegistryEntry<Biome> {
|
||||||
|
return registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEnabledFeatures(): FeatureSet {
|
||||||
|
return FeatureFlags.VANILLA_FEATURES
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeTickScheduler<T> : QueryableTickScheduler<T> {
|
||||||
|
override fun scheduleTick(orderedTick: OrderedTick<T>?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isQueued(pos: BlockPos?, type: T): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTickCount(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isTicking(pos: BlockPos?, type: T): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBlockTickScheduler(): QueryableTickScheduler<Block> {
|
||||||
|
return FakeTickScheduler()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFluidTickScheduler(): QueryableTickScheduler<Fluid> {
|
||||||
|
return FakeTickScheduler()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FakeChunkManager(val world: FakeWorld) : ChunkManager() {
|
||||||
|
override fun getChunk(x: Int, z: Int, leastStatus: ChunkStatus?, create: Boolean): Chunk {
|
||||||
|
return EmptyChunk(world, ChunkPos(x,z), world.registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getWorld(): BlockView {
|
||||||
|
return world
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick(shouldKeepTicking: BooleanSupplier?, tickChunks: Boolean) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDebugString(): String {
|
||||||
|
return "FakeChunkManager"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLoadedChunkCount(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLightingProvider(): LightingProvider {
|
||||||
|
return FakeLightingProvider(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeLightingProvider(chunkManager: FakeChunkManager) : LightingProvider(chunkManager, false, false)
|
||||||
|
|
||||||
|
override fun getChunkManager(): ChunkManager {
|
||||||
|
return FakeChunkManager(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun playSound(
|
||||||
|
source: PlayerEntity?,
|
||||||
|
x: Double,
|
||||||
|
y: Double,
|
||||||
|
z: Double,
|
||||||
|
sound: RegistryEntry<SoundEvent>?,
|
||||||
|
category: SoundCategory?,
|
||||||
|
volume: Float,
|
||||||
|
pitch: Float,
|
||||||
|
seed: Long
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun syncWorldEvent(player: PlayerEntity?, eventId: Int, pos: BlockPos?, data: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun emitGameEvent(event: GameEvent?, emitterPos: Vec3d?, emitter: GameEvent.Emitter?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateListeners(pos: BlockPos?, oldState: BlockState?, newState: BlockState?, flags: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun playSoundFromEntity(
|
||||||
|
source: PlayerEntity?,
|
||||||
|
entity: Entity?,
|
||||||
|
sound: RegistryEntry<SoundEvent>?,
|
||||||
|
category: SoundCategory?,
|
||||||
|
volume: Float,
|
||||||
|
pitch: Float,
|
||||||
|
seed: Long
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun asString(): String {
|
||||||
|
return "FakeWorld"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEntityById(id: Int): Entity? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTickManager(): TickManager {
|
||||||
|
return TickManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMapState(id: String?): MapState? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun putMapState(id: String?, state: MapState?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNextMapId(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setBlockBreakingInfo(entityId: Int, pos: BlockPos?, progress: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getScoreboard(): Scoreboard {
|
||||||
|
return Scoreboard()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRecipeManager(): RecipeManager {
|
||||||
|
return RecipeManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
object FakeEntityLookup : EntityLookup<Entity> {
|
||||||
|
override fun get(id: Int): Entity? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(uuid: UUID?): Entity? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iterate(): MutableIterable<Entity> {
|
||||||
|
return mutableListOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <U : Entity?> forEachIntersects(
|
||||||
|
filter: TypeFilter<Entity, U>?,
|
||||||
|
box: Box?,
|
||||||
|
consumer: LazyIterationConsumer<U>?
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun forEachIntersects(box: Box?, action: Consumer<Entity>?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <U : Entity?> forEach(filter: TypeFilter<Entity, U>?, consumer: LazyIterationConsumer<U>?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEntityLookup(): EntityLookup<Entity> {
|
||||||
|
return FakeEntityLookup
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/main/kotlin/moe/nea/firmament/gui/entity/GuiPlayer.kt
Normal file
55
src/main/kotlin/moe/nea/firmament/gui/entity/GuiPlayer.kt
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.mojang.authlib.GameProfile
|
||||||
|
import java.util.*
|
||||||
|
import net.minecraft.client.network.AbstractClientPlayerEntity
|
||||||
|
import net.minecraft.client.util.DefaultSkinHelper
|
||||||
|
import net.minecraft.client.util.SkinTextures
|
||||||
|
import net.minecraft.client.util.SkinTextures.Model
|
||||||
|
import net.minecraft.client.world.ClientWorld
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.world.World
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see moe.nea.firmament.init.EarlyRiser
|
||||||
|
*/
|
||||||
|
fun makeGuiPlayer(world: FakeWorld): GuiPlayer {
|
||||||
|
val constructor = GuiPlayer::class.java.getDeclaredConstructor(
|
||||||
|
World::class.java,
|
||||||
|
BlockPos::class.java,
|
||||||
|
Float::class.javaPrimitiveType,
|
||||||
|
GameProfile::class.java
|
||||||
|
)
|
||||||
|
return constructor.newInstance(world, BlockPos.ORIGIN, 0F, GameProfile(UUID.randomUUID(), "Linnea"))
|
||||||
|
}
|
||||||
|
|
||||||
|
class GuiPlayer(world: ClientWorld?, profile: GameProfile?) : AbstractClientPlayerEntity(world, profile) {
|
||||||
|
override fun isSpectator(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isCreative(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var skinTexture: Identifier = DefaultSkinHelper.getSkinTextures(this.getUuid()).texture
|
||||||
|
var capeTexture: Identifier? = null
|
||||||
|
var model: Model = Model.WIDE
|
||||||
|
override fun getSkinTextures(): SkinTextures {
|
||||||
|
return SkinTextures(
|
||||||
|
skinTexture,
|
||||||
|
null,
|
||||||
|
capeTexture,
|
||||||
|
null,
|
||||||
|
model,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/main/kotlin/moe/nea/firmament/gui/entity/ModifyAge.kt
Normal file
30
src/main/kotlin/moe/nea/firmament/gui/entity/ModifyAge.kt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
import net.minecraft.entity.decoration.ArmorStandEntity
|
||||||
|
import net.minecraft.entity.mob.ZombieEntity
|
||||||
|
import net.minecraft.entity.passive.PassiveEntity
|
||||||
|
|
||||||
|
object ModifyAge : EntityModifier {
|
||||||
|
override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity {
|
||||||
|
val isBaby = info["baby"]?.asBoolean ?: false
|
||||||
|
if (entity is PassiveEntity) {
|
||||||
|
entity.breedingAge = if (isBaby) -1 else 1
|
||||||
|
} else if (entity is ZombieEntity) {
|
||||||
|
entity.isBaby = isBaby
|
||||||
|
} else if (entity is ArmorStandEntity) {
|
||||||
|
entity.isSmall = isBaby
|
||||||
|
} else {
|
||||||
|
error("Cannot set age for $entity")
|
||||||
|
}
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
import net.minecraft.entity.mob.CreeperEntity
|
||||||
|
|
||||||
|
object ModifyCharged : EntityModifier {
|
||||||
|
override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity {
|
||||||
|
require(entity is CreeperEntity)
|
||||||
|
entity.dataTracker.set(CreeperEntity.CHARGED, true)
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import net.minecraft.entity.EquipmentSlot
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
import net.minecraft.item.DyeableArmorItem
|
||||||
|
import net.minecraft.item.Item
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.item.Items
|
||||||
|
import moe.nea.firmament.rei.SBItemStack
|
||||||
|
import moe.nea.firmament.util.SkyblockId
|
||||||
|
import moe.nea.firmament.util.item.setEncodedSkullOwner
|
||||||
|
import moe.nea.firmament.util.item.zeroUUID
|
||||||
|
|
||||||
|
object ModifyEquipment : EntityModifier {
|
||||||
|
val names = mapOf(
|
||||||
|
"hand" to EquipmentSlot.MAINHAND,
|
||||||
|
"helmet" to EquipmentSlot.HEAD,
|
||||||
|
"chestplate" to EquipmentSlot.CHEST,
|
||||||
|
"leggings" to EquipmentSlot.LEGS,
|
||||||
|
"feet" to EquipmentSlot.FEET,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity {
|
||||||
|
names.forEach { (key, slot) ->
|
||||||
|
info[key]?.let {
|
||||||
|
entity.equipStack(slot, createItem(it.asString))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createItem(item: String): ItemStack {
|
||||||
|
val split = item.split("#")
|
||||||
|
if (split.size != 2) return SBItemStack(SkyblockId(item)).asImmutableItemStack()
|
||||||
|
val (type, data) = split
|
||||||
|
return when (type) {
|
||||||
|
"SKULL" -> ItemStack(Items.PLAYER_HEAD).also { it.setEncodedSkullOwner(zeroUUID, data) }
|
||||||
|
"LEATHER_LEGGINGS" -> coloredLeatherArmor(Items.LEATHER_LEGGINGS, data)
|
||||||
|
"LEATHER_BOOTS" -> coloredLeatherArmor(Items.LEATHER_BOOTS, data)
|
||||||
|
"LEATHER_HELMET" -> coloredLeatherArmor(Items.LEATHER_HELMET, data)
|
||||||
|
"LEATHER_CHESTPLATE" -> coloredLeatherArmor(Items.LEATHER_CHESTPLATE, data)
|
||||||
|
else -> error("Unknown leather piece: $type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun coloredLeatherArmor(leatherArmor: Item, data: String): ItemStack {
|
||||||
|
require(leatherArmor is DyeableArmorItem)
|
||||||
|
val stack = ItemStack(leatherArmor)
|
||||||
|
leatherArmor.setColor(stack, data.toInt(16))
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
}
|
||||||
66
src/main/kotlin/moe/nea/firmament/gui/entity/ModifyHorse.kt
Normal file
66
src/main/kotlin/moe/nea/firmament/gui/entity/ModifyHorse.kt
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.JsonNull
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import kotlin.experimental.and
|
||||||
|
import kotlin.experimental.inv
|
||||||
|
import kotlin.experimental.or
|
||||||
|
import net.minecraft.entity.EntityType
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
import net.minecraft.entity.passive.AbstractHorseEntity
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.item.Items
|
||||||
|
import moe.nea.firmament.gui.entity.EntityRenderer.fakeWorld
|
||||||
|
|
||||||
|
object ModifyHorse : EntityModifier {
|
||||||
|
override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity {
|
||||||
|
require(entity is AbstractHorseEntity)
|
||||||
|
var entity: AbstractHorseEntity = entity
|
||||||
|
info["kind"]?.let {
|
||||||
|
entity = when (it.asString) {
|
||||||
|
"skeleton" -> EntityType.SKELETON_HORSE.create(fakeWorld)!!
|
||||||
|
"zombie" -> EntityType.ZOMBIE_HORSE.create(fakeWorld)!!
|
||||||
|
"mule" -> EntityType.MULE.create(fakeWorld)!!
|
||||||
|
"donkey" -> EntityType.DONKEY.create(fakeWorld)!!
|
||||||
|
"horse" -> EntityType.HORSE.create(fakeWorld)!!
|
||||||
|
else -> error("Unknown horse kind $it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info["armor"]?.let {
|
||||||
|
if (it is JsonNull) {
|
||||||
|
entity.setHorseArmor(ItemStack.EMPTY)
|
||||||
|
} else {
|
||||||
|
when (it.asString) {
|
||||||
|
"iron" -> entity.setHorseArmor(ItemStack(Items.IRON_HORSE_ARMOR))
|
||||||
|
"golden" -> entity.setHorseArmor(ItemStack(Items.GOLDEN_HORSE_ARMOR))
|
||||||
|
"diamond" -> entity.setHorseArmor(ItemStack(Items.DIAMOND_HORSE_ARMOR))
|
||||||
|
else -> error("Unknown horse armor $it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info["saddled"]?.let {
|
||||||
|
entity.setIsSaddled(it.asBoolean)
|
||||||
|
}
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun AbstractHorseEntity.setIsSaddled(shouldBeSaddled: Boolean) {
|
||||||
|
val oldFlag = dataTracker.get(AbstractHorseEntity.HORSE_FLAGS)
|
||||||
|
dataTracker.set(
|
||||||
|
AbstractHorseEntity.HORSE_FLAGS,
|
||||||
|
if (shouldBeSaddled) oldFlag or AbstractHorseEntity.SADDLED_FLAG.toByte()
|
||||||
|
else oldFlag and AbstractHorseEntity.SADDLED_FLAG.toByte().inv()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun AbstractHorseEntity.setHorseArmor(itemStack: ItemStack) {
|
||||||
|
items.setStack(1, itemStack)
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
|
||||||
|
object ModifyInvisible : EntityModifier {
|
||||||
|
override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity {
|
||||||
|
entity.isInvisible = info.get("invisible")?.asBoolean ?: true
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
19
src/main/kotlin/moe/nea/firmament/gui/entity/ModifyName.kt
Normal file
19
src/main/kotlin/moe/nea/firmament/gui/entity/ModifyName.kt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
|
||||||
|
object ModifyName : EntityModifier {
|
||||||
|
override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity {
|
||||||
|
entity.customName = Text.literal(info.get("name").asString)
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import net.minecraft.client.util.SkinTextures
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
|
||||||
|
object ModifyPlayerSkin : EntityModifier {
|
||||||
|
override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity {
|
||||||
|
require(entity is GuiPlayer)
|
||||||
|
info["cape"]?.let {
|
||||||
|
entity.capeTexture = Identifier(it.asString)
|
||||||
|
}
|
||||||
|
info["skin"]?.let {
|
||||||
|
entity.skinTexture = Identifier(it.asString)
|
||||||
|
}
|
||||||
|
info["slim"]?.let {
|
||||||
|
entity.model = if (it.asBoolean) SkinTextures.Model.SLIM else SkinTextures.Model.WIDE
|
||||||
|
}
|
||||||
|
info["parts"]?.let {
|
||||||
|
// TODO: support parts
|
||||||
|
}
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
20
src/main/kotlin/moe/nea/firmament/gui/entity/ModifyRiding.kt
Normal file
20
src/main/kotlin/moe/nea/firmament/gui/entity/ModifyRiding.kt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
|
||||||
|
object ModifyRiding : EntityModifier {
|
||||||
|
override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity {
|
||||||
|
val newEntity = EntityRenderer.constructEntity(info)
|
||||||
|
require(newEntity != null)
|
||||||
|
newEntity.startRiding(entity, true)
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
25
src/main/kotlin/moe/nea/firmament/gui/entity/ModifyWither.kt
Normal file
25
src/main/kotlin/moe/nea/firmament/gui/entity/ModifyWither.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.gui.entity
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import net.minecraft.entity.LivingEntity
|
||||||
|
import net.minecraft.entity.boss.WitherEntity
|
||||||
|
|
||||||
|
object ModifyWither : EntityModifier {
|
||||||
|
override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity {
|
||||||
|
require(entity is WitherEntity)
|
||||||
|
info["tiny"]?.let {
|
||||||
|
entity.setInvulTimer(if (it.asBoolean) 800 else 0)
|
||||||
|
}
|
||||||
|
info["armored"]?.let {
|
||||||
|
entity.health = if (it.asBoolean) 1F else entity.maxHealth
|
||||||
|
}
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
@@ -31,6 +32,7 @@ import net.minecraft.client.gui.screen.ingame.HandledScreen
|
|||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
import moe.nea.firmament.rei.recipes.SBMobDropRecipe
|
||||||
|
|
||||||
|
|
||||||
class FirmamentReiPlugin : REIClientPlugin {
|
class FirmamentReiPlugin : REIClientPlugin {
|
||||||
@@ -62,6 +64,7 @@ class FirmamentReiPlugin : REIClientPlugin {
|
|||||||
override fun registerCategories(registry: CategoryRegistry) {
|
override fun registerCategories(registry: CategoryRegistry) {
|
||||||
registry.add(SBCraftingRecipe.Category)
|
registry.add(SBCraftingRecipe.Category)
|
||||||
registry.add(SBForgeRecipe.Category)
|
registry.add(SBForgeRecipe.Category)
|
||||||
|
registry.add(SBMobDropRecipe.Category)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerExclusionZones(zones: ExclusionZones) {
|
override fun registerExclusionZones(zones: ExclusionZones) {
|
||||||
@@ -77,6 +80,7 @@ class FirmamentReiPlugin : REIClientPlugin {
|
|||||||
SBForgeRecipe.Category.categoryIdentifier,
|
SBForgeRecipe.Category.categoryIdentifier,
|
||||||
SkyblockForgeRecipeDynamicGenerator
|
SkyblockForgeRecipeDynamicGenerator
|
||||||
)
|
)
|
||||||
|
registry.registerDisplayGenerator(SBMobDropRecipe.Category.categoryIdentifier, SkyblockMobDropRecipeDynamicGenerator)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerCollapsibleEntries(registry: CollapsibleEntryRegistry) {
|
override fun registerCollapsibleEntries(registry: CollapsibleEntryRegistry) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
@@ -30,6 +31,7 @@ import moe.nea.firmament.repo.RepoManager
|
|||||||
import moe.nea.firmament.util.FirmFormatters
|
import moe.nea.firmament.util.FirmFormatters
|
||||||
import moe.nea.firmament.util.HypixelPetInfo
|
import moe.nea.firmament.util.HypixelPetInfo
|
||||||
import moe.nea.firmament.util.SkyblockId
|
import moe.nea.firmament.util.SkyblockId
|
||||||
|
import moe.nea.firmament.util.appendLore
|
||||||
import moe.nea.firmament.util.petData
|
import moe.nea.firmament.util.petData
|
||||||
import moe.nea.firmament.util.skyBlockId
|
import moe.nea.firmament.util.skyBlockId
|
||||||
|
|
||||||
@@ -54,6 +56,7 @@ data class SBItemStack(
|
|||||||
val neuItem: NEUItem?,
|
val neuItem: NEUItem?,
|
||||||
val stackSize: Int,
|
val stackSize: Int,
|
||||||
val petData: PetData?,
|
val petData: PetData?,
|
||||||
|
val extraLore: List<Text> = emptyList(),
|
||||||
) {
|
) {
|
||||||
constructor(skyblockId: SkyblockId, petData: PetData) : this(
|
constructor(skyblockId: SkyblockId, petData: PetData) : this(
|
||||||
skyblockId,
|
skyblockId,
|
||||||
@@ -102,12 +105,13 @@ data class SBItemStack(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val itemStack by lazy(LazyThreadSafetyMode.NONE) {
|
private val itemStack: ItemStack by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
if (skyblockId == SkyblockId.COINS)
|
if (skyblockId == SkyblockId.COINS)
|
||||||
return@lazy ItemCache.coinItem(stackSize)
|
return@lazy ItemCache.coinItem(stackSize).also { it.appendLore(extraLore) }
|
||||||
val replacementData = mutableMapOf<String, String>()
|
val replacementData = mutableMapOf<String, String>()
|
||||||
injectReplacementDataForPets(replacementData)
|
injectReplacementDataForPets(replacementData)
|
||||||
return@lazy neuItem.asItemStack(idHint = skyblockId, replacementData).copyWithCount(stackSize)
|
return@lazy neuItem.asItemStack(idHint = skyblockId, replacementData).copyWithCount(stackSize)
|
||||||
|
.also { it.appendLore(extraLore) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun asImmutableItemStack(): ItemStack {
|
fun asImmutableItemStack(): ItemStack {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
@@ -8,6 +9,7 @@ package moe.nea.firmament.rei
|
|||||||
|
|
||||||
import io.github.moulberry.repo.data.NEUCraftingRecipe
|
import io.github.moulberry.repo.data.NEUCraftingRecipe
|
||||||
import io.github.moulberry.repo.data.NEUForgeRecipe
|
import io.github.moulberry.repo.data.NEUForgeRecipe
|
||||||
|
import io.github.moulberry.repo.data.NEUMobDropRecipe
|
||||||
import io.github.moulberry.repo.data.NEURecipe
|
import io.github.moulberry.repo.data.NEURecipe
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator
|
import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator
|
||||||
@@ -16,6 +18,7 @@ import me.shedaniel.rei.api.common.display.Display
|
|||||||
import me.shedaniel.rei.api.common.entry.EntryStack
|
import me.shedaniel.rei.api.common.entry.EntryStack
|
||||||
import moe.nea.firmament.rei.recipes.SBCraftingRecipe
|
import moe.nea.firmament.rei.recipes.SBCraftingRecipe
|
||||||
import moe.nea.firmament.rei.recipes.SBForgeRecipe
|
import moe.nea.firmament.rei.recipes.SBForgeRecipe
|
||||||
|
import moe.nea.firmament.rei.recipes.SBMobDropRecipe
|
||||||
import moe.nea.firmament.repo.RepoManager
|
import moe.nea.firmament.repo.RepoManager
|
||||||
|
|
||||||
|
|
||||||
@@ -27,6 +30,10 @@ val SkyblockForgeRecipeDynamicGenerator = neuDisplayGenerator<SBForgeRecipe, NEU
|
|||||||
SBForgeRecipe(it)
|
SBForgeRecipe(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val SkyblockMobDropRecipeDynamicGenerator = neuDisplayGenerator<SBMobDropRecipe, NEUMobDropRecipe> {
|
||||||
|
SBMobDropRecipe(it)
|
||||||
|
}
|
||||||
|
|
||||||
inline fun <D : Display, reified T : NEURecipe> neuDisplayGenerator(noinline mapper: (T) -> D) =
|
inline fun <D : Display, reified T : NEURecipe> neuDisplayGenerator(noinline mapper: (T) -> D) =
|
||||||
object : DynamicDisplayGenerator<D> {
|
object : DynamicDisplayGenerator<D> {
|
||||||
override fun getRecipeFor(entry: EntryStack<*>): Optional<List<D>> {
|
override fun getRecipeFor(entry: EntryStack<*>): Optional<List<D>> {
|
||||||
|
|||||||
113
src/main/kotlin/moe/nea/firmament/rei/recipes/SBMobDropRecipe.kt
Normal file
113
src/main/kotlin/moe/nea/firmament/rei/recipes/SBMobDropRecipe.kt
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.rei.recipes
|
||||||
|
|
||||||
|
import io.github.moulberry.repo.data.NEUMobDropRecipe
|
||||||
|
import me.shedaniel.math.Point
|
||||||
|
import me.shedaniel.math.Rectangle
|
||||||
|
import me.shedaniel.rei.api.client.gui.Renderer
|
||||||
|
import me.shedaniel.rei.api.client.gui.widgets.Widget
|
||||||
|
import me.shedaniel.rei.api.client.gui.widgets.Widgets
|
||||||
|
import me.shedaniel.rei.api.client.registry.display.DisplayCategory
|
||||||
|
import me.shedaniel.rei.api.common.category.CategoryIdentifier
|
||||||
|
import me.shedaniel.rei.api.common.util.EntryStacks
|
||||||
|
import net.minecraft.block.Blocks
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import moe.nea.firmament.Firmament
|
||||||
|
import moe.nea.firmament.gui.entity.EntityRenderer
|
||||||
|
import moe.nea.firmament.gui.entity.EntityWidget
|
||||||
|
import moe.nea.firmament.rei.SBItemEntryDefinition
|
||||||
|
|
||||||
|
class SBMobDropRecipe(override val neuRecipe: NEUMobDropRecipe) : SBRecipe() {
|
||||||
|
override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier
|
||||||
|
|
||||||
|
object Category : DisplayCategory<SBMobDropRecipe> {
|
||||||
|
override fun getCategoryIdentifier(): CategoryIdentifier<SBMobDropRecipe> =
|
||||||
|
CategoryIdentifier.of(Firmament.MOD_ID, "mob_drop_recipe")
|
||||||
|
|
||||||
|
override fun getTitle(): Text = Text.literal("Mob Drops")
|
||||||
|
override fun getDisplayHeight(): Int {
|
||||||
|
return 100
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIcon(): Renderer = EntryStacks.of(Blocks.ANVIL)
|
||||||
|
override fun setupDisplay(display: SBMobDropRecipe, bounds: Rectangle): List<Widget> {
|
||||||
|
return buildList {
|
||||||
|
add(Widgets.createRecipeBase(bounds))
|
||||||
|
val source = display.neuRecipe.render
|
||||||
|
val entity = if (source.startsWith("@")) {
|
||||||
|
EntityRenderer.constructEntity(Identifier(source.substring(1)))
|
||||||
|
} else {
|
||||||
|
EntityRenderer.applyModifiers(source, listOf())
|
||||||
|
}
|
||||||
|
if (entity != null) {
|
||||||
|
val level = display.neuRecipe.level
|
||||||
|
val fullMobName =
|
||||||
|
if (level > 0) Text.translatable("firmament.recipe.mobs.name", level, display.neuRecipe.name)
|
||||||
|
else Text.translatable("firmament.recipe.mobs.name.nolevel", display.neuRecipe.name)
|
||||||
|
val tt = mutableListOf<Text>()
|
||||||
|
tt.add((fullMobName))
|
||||||
|
tt.add(Text.literal(""))
|
||||||
|
if (display.neuRecipe.coins > 0) {
|
||||||
|
tt.add(Text.stringifiedTranslatable("firmament.recipe.mobs.coins", display.neuRecipe.coins))
|
||||||
|
}
|
||||||
|
if (display.neuRecipe.combatExperience > 0) {
|
||||||
|
tt.add(
|
||||||
|
Text.stringifiedTranslatable(
|
||||||
|
"firmament.recipe.mobs.combat",
|
||||||
|
display.neuRecipe.combatExperience
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (display.neuRecipe.enchantingExperience > 0) {
|
||||||
|
tt.add(
|
||||||
|
Text.stringifiedTranslatable(
|
||||||
|
"firmament.recipe.mobs.exp",
|
||||||
|
display.neuRecipe.enchantingExperience
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (display.neuRecipe.extra != null)
|
||||||
|
display.neuRecipe.extra.mapTo(tt) { Text.literal(it) }
|
||||||
|
if (tt.size == 2)
|
||||||
|
tt.removeAt(1)
|
||||||
|
add(
|
||||||
|
Widgets.withTooltip(
|
||||||
|
EntityWidget(entity, Point(bounds.minX + 5, bounds.minY + 15)),
|
||||||
|
tt
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
add(
|
||||||
|
Widgets.createLabel(Point(bounds.minX + 15, bounds.minY + 5), Text.literal(display.neuRecipe.name))
|
||||||
|
.leftAligned()
|
||||||
|
)
|
||||||
|
var x = bounds.minX + 60
|
||||||
|
var y = bounds.minY + 20
|
||||||
|
for (drop in display.neuRecipe.drops) {
|
||||||
|
val lore = drop.extra.mapTo(mutableListOf()) { Text.literal(it) }
|
||||||
|
if (drop.chance != null) {
|
||||||
|
lore += listOf(Text.translatable("firmament.recipe.mobs.drops", drop.chance))
|
||||||
|
}
|
||||||
|
val item = SBItemEntryDefinition.getEntry(drop.dropItem)
|
||||||
|
.value.copy(extraLore = lore)
|
||||||
|
add(
|
||||||
|
Widgets.createSlot(Point(x, y)).markOutput()
|
||||||
|
.entries(listOf(SBItemEntryDefinition.getEntry(item)))
|
||||||
|
)
|
||||||
|
x += 18
|
||||||
|
if (x > bounds.maxX - 30) {
|
||||||
|
x = bounds.minX + 60
|
||||||
|
y += 18
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
101
src/main/kotlin/moe/nea/firmament/repo/RepoModResourcePack.kt
Normal file
101
src/main/kotlin/moe/nea/firmament/repo/RepoModResourcePack.kt
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.repo
|
||||||
|
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
import net.fabricmc.fabric.api.resource.ModResourcePack
|
||||||
|
import net.fabricmc.loader.api.FabricLoader
|
||||||
|
import net.fabricmc.loader.api.metadata.ModMetadata
|
||||||
|
import kotlin.io.path.exists
|
||||||
|
import kotlin.io.path.isRegularFile
|
||||||
|
import kotlin.io.path.relativeTo
|
||||||
|
import kotlin.streams.asSequence
|
||||||
|
import net.minecraft.resource.AbstractFileResourcePack
|
||||||
|
import net.minecraft.resource.InputSupplier
|
||||||
|
import net.minecraft.resource.ResourcePack
|
||||||
|
import net.minecraft.resource.ResourceType
|
||||||
|
import net.minecraft.resource.metadata.ResourceMetadataReader
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.PathUtil
|
||||||
|
|
||||||
|
class RepoModResourcePack(val basePath: Path) : ModResourcePack {
|
||||||
|
companion object {
|
||||||
|
fun append(packs: MutableList<in ModResourcePack>) {
|
||||||
|
packs.add(RepoModResourcePack(RepoDownloadManager.repoSavedLocation))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openRoot(vararg segments: String): InputSupplier<InputStream>? {
|
||||||
|
return getFile(segments)?.let { InputSupplier.create(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFile(segments: Array<out String>): Path? {
|
||||||
|
PathUtil.validatePath(*segments)
|
||||||
|
val path = segments.fold(basePath, Path::resolve)
|
||||||
|
if (!path.isRegularFile()) return null
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun open(type: ResourceType?, id: Identifier): InputSupplier<InputStream>? {
|
||||||
|
if (type != ResourceType.CLIENT_RESOURCES) return null
|
||||||
|
if (id.namespace != "neurepo") return null
|
||||||
|
val file = getFile(id.path.split("/").toTypedArray())
|
||||||
|
return file?.let { InputSupplier.create(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findResources(
|
||||||
|
type: ResourceType?,
|
||||||
|
namespace: String,
|
||||||
|
prefix: String,
|
||||||
|
consumer: ResourcePack.ResultConsumer
|
||||||
|
) {
|
||||||
|
if (namespace != "neurepo") return
|
||||||
|
if (type != ResourceType.CLIENT_RESOURCES) return
|
||||||
|
|
||||||
|
val prefixPath = basePath.resolve(prefix)
|
||||||
|
if (!prefixPath.exists())
|
||||||
|
return
|
||||||
|
Files.walk(prefixPath)
|
||||||
|
.asSequence()
|
||||||
|
.map { it.relativeTo(basePath) }
|
||||||
|
.forEach {
|
||||||
|
consumer.accept(Identifier.of("neurepo", it.toString()), InputSupplier.create(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNamespaces(type: ResourceType?): Set<String> {
|
||||||
|
if (type != ResourceType.CLIENT_RESOURCES) return emptySet()
|
||||||
|
return setOf("neurepo")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T> parseMetadata(metaReader: ResourceMetadataReader<T>): T? {
|
||||||
|
return AbstractFileResourcePack.parseMetadata(
|
||||||
|
metaReader, """
|
||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"pack_format": 12,
|
||||||
|
"description": "NEU Repo Resources"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent().byteInputStream()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(): String {
|
||||||
|
return "NEU Repo Resources"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFabricModMetadata(): ModMetadata {
|
||||||
|
return FabricLoader.getInstance().getModContainer("firmament")
|
||||||
|
.get().metadata
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
@@ -14,6 +15,7 @@ import net.minecraft.text.Text
|
|||||||
|
|
||||||
|
|
||||||
fun ItemStack.appendLore(args: List<Text>) {
|
fun ItemStack.appendLore(args: List<Text>) {
|
||||||
|
if (args.isEmpty()) return
|
||||||
val compoundTag = getOrCreateSubNbt("display")
|
val compoundTag = getOrCreateSubNbt("display")
|
||||||
val loreList = compoundTag.getOrCreateList("Lore", NbtString.STRING_TYPE)
|
val loreList = compoundTag.getOrCreateList("Lore", NbtString.STRING_TYPE)
|
||||||
for (arg in args) {
|
for (arg in args) {
|
||||||
|
|||||||
25
src/main/kotlin/moe/nea/firmament/util/LoadResource.kt
Normal file
25
src/main/kotlin/moe/nea/firmament/util/LoadResource.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
|
import java.io.InputStream
|
||||||
|
import kotlin.io.path.inputStream
|
||||||
|
import kotlin.jvm.optionals.getOrNull
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import moe.nea.firmament.repo.RepoDownloadManager
|
||||||
|
|
||||||
|
|
||||||
|
fun Identifier.openFirmamentResource(): InputStream {
|
||||||
|
val resource = MC.resourceManager.getResource(this).getOrNull()
|
||||||
|
if (resource == null) {
|
||||||
|
if (namespace == "neurepo")
|
||||||
|
return RepoDownloadManager.repoSavedLocation.resolve(path).inputStream()
|
||||||
|
error("Could not read resource $this")
|
||||||
|
}
|
||||||
|
return resource.inputStream
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
@@ -18,8 +19,13 @@ import kotlinx.serialization.Serializable
|
|||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import net.minecraft.client.texture.PlayerSkinProvider
|
import net.minecraft.block.entity.SkullBlockEntity
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.item.Items
|
||||||
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.nbt.NbtHelper
|
||||||
import moe.nea.firmament.Firmament
|
import moe.nea.firmament.Firmament
|
||||||
|
import moe.nea.firmament.repo.set
|
||||||
import moe.nea.firmament.util.assertTrueOr
|
import moe.nea.firmament.util.assertTrueOr
|
||||||
import moe.nea.firmament.util.json.DashlessUUIDSerializer
|
import moe.nea.firmament.util.json.DashlessUUIDSerializer
|
||||||
import moe.nea.firmament.util.json.InstantAsLongSerializer
|
import moe.nea.firmament.util.json.InstantAsLongSerializer
|
||||||
@@ -46,6 +52,38 @@ fun GameProfile.setTextures(textures: MinecraftTexturesPayloadKt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val propertyTextures = "textures"
|
private val propertyTextures = "textures"
|
||||||
|
fun String.padBase64(): String {
|
||||||
|
return this + "=".repeat((4 - (this.length % 4)) % 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ItemStack.setEncodedSkullOwner(uuid: UUID, encodedData: String) {
|
||||||
|
assert(this.item == Items.PLAYER_HEAD)
|
||||||
|
val gameProfile = GameProfile(uuid, "LameGuy123")
|
||||||
|
gameProfile.properties.put(propertyTextures, Property(propertyTextures, encodedData.padBase64()))
|
||||||
|
val nbt: NbtCompound = this.orCreateNbt
|
||||||
|
nbt[SkullBlockEntity.SKULL_OWNER_KEY] = NbtHelper.writeGameProfile(
|
||||||
|
NbtCompound(),
|
||||||
|
gameProfile
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val zeroUUID = UUID.fromString("d3cb85e2-3075-48a1-b213-a9bfb62360c1")
|
||||||
|
fun ItemStack.setSkullOwner(uuid: UUID, url: String) {
|
||||||
|
assert(this.item == Items.PLAYER_HEAD)
|
||||||
|
val gameProfile = GameProfile(uuid, "LameGuy123")
|
||||||
|
gameProfile.setTextures(
|
||||||
|
MinecraftTexturesPayloadKt(
|
||||||
|
mapOf(MinecraftProfileTexture.Type.SKIN to MinecraftProfileTextureKt(url))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val nbt: NbtCompound = this.orCreateNbt
|
||||||
|
nbt[SkullBlockEntity.SKULL_OWNER_KEY] = NbtHelper.writeGameProfile(
|
||||||
|
NbtCompound(),
|
||||||
|
gameProfile
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun decodeProfileTextureProperty(property: Property): MinecraftTexturesPayloadKt? {
|
fun decodeProfileTextureProperty(property: Property): MinecraftTexturesPayloadKt? {
|
||||||
assertTrueOr(property.name == propertyTextures) { return null }
|
assertTrueOr(property.name == propertyTextures) { return null }
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package moe.nea.firmament.util.render
|
||||||
|
|
||||||
|
import org.joml.Vector4f
|
||||||
|
import net.minecraft.client.gui.DrawContext
|
||||||
|
|
||||||
|
fun DrawContext.enableScissorWithTranslation(x1: Float, y1: Float, x2: Float, y2: Float) {
|
||||||
|
val pMat = matrices.peek().positionMatrix
|
||||||
|
val target = Vector4f()
|
||||||
|
|
||||||
|
target.set(x1, y1, 0f, 1f)
|
||||||
|
target.mul(pMat)
|
||||||
|
val scissorX1 = target.x
|
||||||
|
val scissorY1 = target.y
|
||||||
|
|
||||||
|
target.set(x2, y2, 0f, 1f)
|
||||||
|
target.mul(pMat)
|
||||||
|
val scissorX2 = target.x
|
||||||
|
val scissorY2 = target.y
|
||||||
|
|
||||||
|
enableScissor(scissorX1.toInt(), scissorY1.toInt(), scissorX2.toInt(), scissorY2.toInt())
|
||||||
|
}
|
||||||
@@ -80,6 +80,12 @@
|
|||||||
"firmament.config.waypoints": "Waypoints",
|
"firmament.config.waypoints": "Waypoints",
|
||||||
"firmament.config.waypoints.temp-waypoint-duration": "Temporary Waypoint Duration",
|
"firmament.config.waypoints.temp-waypoint-duration": "Temporary Waypoint Duration",
|
||||||
"firmament.recipe.forge.time": "Forging Time: %s",
|
"firmament.recipe.forge.time": "Forging Time: %s",
|
||||||
|
"firmament.recipe.mobs.drops": "§e§lDrop Chance: %s",
|
||||||
|
"firmament.recipe.mobs.name": "§8[§7Lv %d§8] §c%s",
|
||||||
|
"firmament.recipe.mobs.name.nolevel": "§c%s",
|
||||||
|
"firmament.recipe.mobs.coins": "§eCoins: %s",
|
||||||
|
"firmament.recipe.mobs.combat": "§bCombat Experience: %s",
|
||||||
|
"firmament.recipe.mobs.exp": "§6Experience: %s",
|
||||||
"firmament.pv.skills": "Skills",
|
"firmament.pv.skills": "Skills",
|
||||||
"firmament.pv.skills.farming": "Farming",
|
"firmament.pv.skills.farming": "Farming",
|
||||||
"firmament.pv.skills.foraging": "Foraging",
|
"firmament.pv.skills.foraging": "Foraging",
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
"main": [
|
"main": [
|
||||||
"moe.nea.firmament.Firmament::onInitialize"
|
"moe.nea.firmament.Firmament::onInitialize"
|
||||||
],
|
],
|
||||||
|
"mm_shedaniel:early_risers": [
|
||||||
|
"moe.nea.firmament.init.EarlyRiser"
|
||||||
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"moe.nea.firmament.Firmament::onClientInitialize"
|
"moe.nea.firmament.Firmament::onClientInitialize"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -4,9 +4,13 @@ accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters
|
|||||||
accessible class net/minecraft/client/font/TextRenderer$Drawer
|
accessible class net/minecraft/client/font/TextRenderer$Drawer
|
||||||
accessible class net/minecraft/client/render/model/ModelLoader$BakerImpl
|
accessible class net/minecraft/client/render/model/ModelLoader$BakerImpl
|
||||||
accessible method net/minecraft/client/render/model/ModelLoader$BakerImpl <init> (Lnet/minecraft/client/render/model/ModelLoader;Ljava/util/function/BiFunction;Lnet/minecraft/util/Identifier;)V
|
accessible method net/minecraft/client/render/model/ModelLoader$BakerImpl <init> (Lnet/minecraft/client/render/model/ModelLoader;Ljava/util/function/BiFunction;Lnet/minecraft/util/Identifier;)V
|
||||||
#accessible field net/minecraft/client/texture/PlayerSkinProvider TEXTURES Ljava/lang/String;
|
|
||||||
accessible field net/minecraft/client/network/ClientPlayNetworkHandler lastSeenMessagesCollector Lnet/minecraft/network/message/LastSeenMessagesCollector;
|
accessible field net/minecraft/client/network/ClientPlayNetworkHandler lastSeenMessagesCollector Lnet/minecraft/network/message/LastSeenMessagesCollector;
|
||||||
accessible field net/minecraft/client/gui/hud/InGameHud SCOREBOARD_ENTRY_COMPARATOR Ljava/util/Comparator;
|
accessible field net/minecraft/client/gui/hud/InGameHud SCOREBOARD_ENTRY_COMPARATOR Ljava/util/Comparator;
|
||||||
|
|
||||||
accessible class net/minecraft/client/render/model/json/ModelOverride$Deserializer
|
accessible class net/minecraft/client/render/model/json/ModelOverride$Deserializer
|
||||||
accessible class net/minecraft/client/render/model/json/ModelOverrideList$BakedOverride
|
accessible class net/minecraft/client/render/model/json/ModelOverrideList$BakedOverride
|
||||||
|
accessible field net/minecraft/entity/mob/CreeperEntity CHARGED Lnet/minecraft/entity/data/TrackedData;
|
||||||
|
accessible method net/minecraft/entity/decoration/ArmorStandEntity setSmall (Z)V
|
||||||
|
accessible field net/minecraft/entity/passive/AbstractHorseEntity items Lnet/minecraft/inventory/SimpleInventory;
|
||||||
|
accessible field net/minecraft/entity/passive/AbstractHorseEntity SADDLED_FLAG I
|
||||||
|
accessible field net/minecraft/entity/passive/AbstractHorseEntity HORSE_FLAGS Lnet/minecraft/entity/data/TrackedData;
|
||||||
|
|||||||
Reference in New Issue
Block a user