Skip to content

Commit

Permalink
feat: default entity attribute attachment
Browse files Browse the repository at this point in the history
  • Loading branch information
CallMeEchoCodes committed Sep 4, 2024
1 parent 414e888 commit b5296c6
Show file tree
Hide file tree
Showing 15 changed files with 275 additions and 32 deletions.
60 changes: 32 additions & 28 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,18 @@ allprojects {
options.release = 21
}

val mod = ModInfo()
val deps = Dependencies()

group = mod.group
version = mod.version

java {
withSourcesJar()

sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}

loom {
splitEnvironmentSourceSets()
accessWidenerPath = rootDir.absoluteFile.resolve("src/main/resources/specter.accesswidener")
}
val mod = ModInfo()
val deps = Dependencies()

group = mod.group
version = mod.version

dependencies {
minecraft("com.mojang:minecraft:${deps.minecraft}")
Expand All @@ -55,18 +50,6 @@ allprojects {
modImplementation("net.fabricmc.fabric-api:fabric-api:${deps.fabricApi}")
}

for (modProject in allprojects) {
loom.mods.register(modProject.name) {
sourceSet(modProject.sourceSets.getByName("main"))
sourceSet(modProject.sourceSets.getByName("client"))
}

loom.mods.register(modProject.name + "-testmod") {
sourceSet(modProject.sourceSets.getByName("testmod"))
sourceSet(modProject.sourceSets.getByName("testmodClient"))
}
}

tasks.withType<ProcessResources> {
inputs.property("id", mod.id)
inputs.property("version", mod.version)
Expand All @@ -83,20 +66,38 @@ allprojects {
filesMatching("fabric.mod.json") { expand(map) }
}

loom {
splitEnvironmentSourceSets()
accessWidenerPath = rootDir.absoluteFile.resolve("src/main/resources/specter.accesswidener")
}

for (modProject in allprojects) {
loom.mods.register(modProject.name) {
sourceSet(modProject.sourceSets.getByName("main"))
sourceSet(modProject.sourceSets.getByName("client"))
}

loom.mods.register(modProject.name + "-testmod") {
sourceSet(modProject.sourceSets.getByName("testmod"))
sourceSet(modProject.sourceSets.getByName("testmodClient"))
}
}

tasks.withType<GenerateModuleMetadata>().configureEach {
enabled = false
}
}

tasks.javadoc {
with(options as StandardJavadocDocletOptions) {
source = "21"
encoding = "UTF-8"
charset("UTF-8")
memberLevel = JavadocMemberLevel.PACKAGE
addStringOption("Xdoclint:none", "-quiet")
}

allprojects.forEach { p -> source(p.sourceSets.main.map { it.allJava.srcDirs }) }
allprojects.forEach { proj -> source(proj.sourceSets.main.map { it.allJava.srcDirs }) }

classpath = project.files(sourceSets.main.map { it.compileClasspath })
include("**/api/**")
Expand All @@ -106,14 +107,21 @@ tasks.javadoc {
val javadocJar by tasks.registering(Jar::class) {
dependsOn(tasks.javadoc)
from(tasks.javadoc.map { it.destinationDir!! })
archiveClassifier.set("javadoc")

archiveClassifier.set("fatjavadoc")
}

tasks.assemble.configure {
dependsOn(javadocJar)
}

tasks.test.configure {
dependsOn(tasks.named("runGametest"))
}

subprojects {
version = rootProject.version

sourceSets.create("testmod") {
compileClasspath += sourceSets.main.get().compileClasspath
runtimeClasspath += sourceSets.main.get().runtimeClasspath
Expand Down Expand Up @@ -264,8 +272,4 @@ dependencies {
}
}

tasks.test {
dependsOn(":runGametest")
}

for (subproject in subprojects) tasks.remapJar.configure { dependsOn(":${subproject.name}:remapJar") }
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ include("specter-config")
include("specter-registry")
include("specter-item")
include("specter-block")
include("specter-entity")
include("specter-debug")
1 change: 1 addition & 0 deletions specter-entity/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
moduleDependencies(project, "specter-core", "specter-registry")
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"required": true,
"minVersion": "0.8",
"package": "dev.spiritstudios.specter.mixin.entity.client",
"compatibilityLevel": "JAVA_21",
"injectors": {
"defaultRequire": 1
},
"client": [
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package dev.spiritstudios.specter.api.entity;

import dev.spiritstudios.specter.api.registry.attachment.Attachment;
import dev.spiritstudios.specter.impl.entity.DataDefaultAttributeBuilder;
import net.minecraft.entity.EntityType;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;

import static dev.spiritstudios.specter.api.core.SpecterGlobals.MODID;

public final class EntityAttachments {
public static final Attachment<EntityType<?>, DataDefaultAttributeBuilder> DEFAULT_ATTRIBUTES = Attachment.builder(
Registries.ENTITY_TYPE,
Identifier.of(MODID, "default_attributes"),
DataDefaultAttributeBuilder.CODEC,
DataDefaultAttributeBuilder.PACKET_CODEC
).build();

/**
* Hacky workaround to force class loading.
*/
@SuppressWarnings("EmptyMethod")
public static void init() {
// NO-OP
}

private EntityAttachments() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package dev.spiritstudios.specter.impl.entity;

import com.mojang.serialization.Codec;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.EntityAttribute;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.entry.RegistryEntry;

import java.util.Map;

// Yes, this is a builder builder. I love codecs.
public record DataDefaultAttributeBuilder(Map<RegistryEntry<EntityAttribute>, Double> attributes) {
public DefaultAttributeContainer build() {
DefaultAttributeContainer.Builder builder = DefaultAttributeContainer.builder();
attributes.forEach(builder::add);
return builder.build();
}

public static final Codec<DataDefaultAttributeBuilder> CODEC = Codec.unboundedMap(
Registries.ATTRIBUTE.getEntryCodec(),
Codec.DOUBLE
).xmap(DataDefaultAttributeBuilder::new, DataDefaultAttributeBuilder::attributes);

public static final PacketCodec<RegistryByteBuf, DataDefaultAttributeBuilder> PACKET_CODEC = PacketCodec.tuple(
PacketCodecs.map(
Object2DoubleOpenHashMap::new,
PacketCodecs.registryEntry(RegistryKeys.ATTRIBUTE),
PacketCodecs.DOUBLE
),
DataDefaultAttributeBuilder::attributes,
DataDefaultAttributeBuilder::new
);

public static DataDefaultAttributeBuilder with(DataDefaultAttributeBuilder original, DefaultAttributeContainer attributes) {
Map<RegistryEntry<EntityAttribute>, Double> newAttributes = new Object2DoubleOpenHashMap<>();
attributes.instances.forEach((attribute, value) -> newAttributes.put(attribute, value.getBaseValue()));
newAttributes.putAll(original.attributes);
return new DataDefaultAttributeBuilder(newAttributes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.spiritstudios.specter.impl.entity;

import dev.spiritstudios.specter.api.entity.EntityAttachments;
import net.fabricmc.api.ModInitializer;

public class SpecterEntity implements ModInitializer {
@Override
public void onInitialize() {
EntityAttachments.init();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dev.spiritstudios.specter.mixin.entity;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import dev.spiritstudios.specter.api.entity.EntityAttachments;
import dev.spiritstudios.specter.impl.entity.DataDefaultAttributeBuilder;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.DefaultAttributeRegistry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import java.util.Map;
import java.util.Objects;
import java.util.Optional;

@Mixin(DefaultAttributeRegistry.class)
public class DefaultAttributeRegistryMixin {
@SuppressWarnings("unchecked")
@WrapOperation(method = "get", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;"))
private static <K, V> V get(Map<K, V> instance, Object o, Operation<V> original) {
if (!(o instanceof EntityType<?> entityType)) return original.call(instance, o);

Optional<DataDefaultAttributeBuilder> attributeBuilder = EntityAttachments.DEFAULT_ATTRIBUTES.get(entityType);
if (attributeBuilder.isEmpty()) return original.call(instance, o);

DefaultAttributeContainer originalAttributes = (DefaultAttributeContainer) original.call(instance, o);
if (originalAttributes == null) return (V) attributeBuilder.get().build();

return (V) DataDefaultAttributeBuilder.with(attributeBuilder.get(), originalAttributes).build();
}

@WrapOperation(method = "hasDefinitionFor", at = @At(value = "INVOKE", target = "Ljava/util/Map;containsKey(Ljava/lang/Object;)Z"))
private static <K, V> boolean containsKey(Map<K, V> instance, Object o, Operation<Boolean> original) {
if (!(o instanceof EntityType<?> entityType)) return original.call(instance, o);

boolean hasDefinition = Objects.nonNull(EntityAttachments.DEFAULT_ATTRIBUTES.get(entityType));
return hasDefinition || original.call(instance, o);
}
}
40 changes: 40 additions & 0 deletions specter-entity/src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"schemaVersion": 1,
"id": "specter-entity",
"version": "${version}",
"name": "Specter Entity",
"description": "Library for Spirit Studios mods (Entity module)",
"authors": [],
"contact": {
"repo": "https://github.com/SpiritGameStudios/Specter",
"issues": "https://github.com/SpiritGameStudios/Specter/issues"
},
"license": "MPL-2.0",
"environment": "*",
"entrypoints": {
"main": [
"dev.spiritstudios.specter.impl.entity.SpecterEntity"
]
},
"mixins": [
"specter-entity.mixins.json",
{
"config": "specter-entity.client.mixins.json",
"environment": "client"
}
],
"depends": {
"fabricloader": ">=${loader_version}",
"minecraft": "~${minecraft_version}",
"fabric-api": "*",
"java": ">=21"
},
"custom": {
"modmenu": {
"parent": "specter",
"badges": [
"library"
]
}
}
}
12 changes: 12 additions & 0 deletions specter-entity/src/main/resources/specter-entity.mixins.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"required": true,
"minVersion": "0.8",
"package": "dev.spiritstudios.specter.mixin.entity",
"compatibilityLevel": "JAVA_21",
"mixins": [
"DefaultAttributeRegistryMixin"
],
"injectors": {
"defaultRequire": 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"replace": false,
"values": {
"minecraft:warden": {
"minecraft:generic.max_health": 1.0
}
}
}
22 changes: 22 additions & 0 deletions specter-entity/src/testmod/resources/fabric.mod.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"schemaVersion": 1,
"id": "specter-entity-testmod",
"version": "${version}",
"name": "Specter",
"description": "Library for Spirit Studios mods (Entity module tests)",
"authors": [],
"contact": {
"repo": "https://github.com/SpiritGameStudios/Specter",
"issues": "https://github.com/SpiritGameStudios/Specter/issues"
},
"license": "MPL-2.0",
"environment": "*",
"entrypoints": {
},
"depends": {
"fabricloader": ">=${loader_version}",
"minecraft": "~${minecraft_version}",
"fabric-api": "*",
"java": ">=21"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricCodecDataProvider;
import net.minecraft.data.DataOutput;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.ApiStatus;
Expand All @@ -28,7 +28,7 @@ protected void configure(BiConsumer<Identifier, DataItemGroup> provider, Registr
new DataItemGroup(
id.toTranslationKey("item_group"),
data.icon(),
data.items().stream().map(ItemConvertible::asItem).map(Item::getDefaultStack).toList()
data.items()
)
),
lookup
Expand All @@ -42,8 +42,8 @@ public String getName() {
return "Specter Item Groups";
}

public record ItemGroupData(Identifier id, ItemConvertible icon, List<ItemConvertible> items) {
public static ItemGroupData of(Identifier id, ItemConvertible icon, List<ItemConvertible> items) {
public record ItemGroupData(Identifier id, ItemConvertible icon, List<ItemStack> items) {
public static ItemGroupData of(Identifier id, ItemConvertible icon, List<ItemStack> items) {
return new ItemGroupData(id, icon, items);
}
}
Expand Down
Loading

0 comments on commit b5296c6

Please sign in to comment.