Капабилити

Версия Minecraft
1.20+
API
Forge
84
5
6
Доброго времени суток

Есть капа:

Cap:
package com.mr_toad.ex.common.caps;

public interface Cap {
     int getValue();

     void setValue(int vn);
}


CapClass:
package com.mr_toad.ex.common.caps;

public class CapClass implements Cap {
          
    private int v = 0;

    @Override
    public int getValue() {
         return this.v;
    }

    @Override
    public void setValue(int vn) {
        this.v = vn;
    }

}

CapProvider:
package com.mr_toad.ex.common.caps;

import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.CapabilityToken;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class CapProvider implements ICapabilitySerializable<Tag> {

        private CapClass capability = null;
        private final LazyOptional<Cap> holder = LazyOptional.of(this::create);
        public static final Capability<Cap> CAPA = CapabilityManager.get(new CapabilityToken<>(){});


        @Override
        public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
            if (cap == CAPA) {
                return this.holder.cast();
            }

            return LazyOptional.empty();
        }

        @Override
        public Tag serializeNBT() {
            Cap cap = this.create();
            CompoundTag nbt = new CompoundTag();
            nbt.putInt("Value", cap.getValue());
            return nbt;
        }

        @Override
        public void deserializeNBT(Tag nbt) {
            Cap cap = this.create();
            if (nbt instanceof CompoundTag compoundNbt) {
                cap.setValue(compoundNbt.getInt("Value"));
            }
        }

        private CapClass create() {
            if(this.capability == null) {
                this.capability = new CapClass();
            }

            return this.capability;
        }

    }


///

Добавление, регистрация и тест:
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.LivingEntity;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.common.Mod;

@Mod.EventBusSubscriber(modid = Ex.MODID)
public class Events {   
    @SubscribeEvent
    public static void registerCapabilities(RegisterCapabilitiesEvent event) {
        event.register(Cap.class);
    }

    @SubscribeEvent
    public static void attachCapability(AttachCapabilitiesEvent<LivingEntity> event) {
        if (event.getObject() instanceof Player player && player.getCapability(CapProvider.CAPA).resolve().isEmpty()) {
            event.addCapability(new ResourceLocation(Ex.MODID, "test"), new CapProvider());
        }
    }

    @SubscribeEvent
    public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
        if(event.side == LogicalSide.SERVER && event.player.getRandom().nextInt(5) == 0) {
            event.player.getCapability(CapProvider.CAPA).resolve().ifPresentOrElse(c -> Ex.LOGGER.info("Cap : {} present", c)), () -> Ex.LOGGER.error("Cap : {} empty", c));
        }
    }
}

Выводит [времячетотам] [логгерчетотам/ERROR] "Cap {...} empty"

Я уже много что пробывал и другой тест и т.д все равно капы нету

Прошу помочь

В действительности капа другая но ошибка та же....
Код этой капы может содержать ошибки.....
 
нужно вызвать CapabilityManager.INSTANCE.register() где-то в процессе установки твоего мода.

проблема в регистрации возможностей и прикреплении их к сущностям. Класс CapProvider имеет статический метод, который регистрирует возможности, но из основного класса мода не вызывается событие для фактической регистрации его в фордже
 
84
5
6
84
5
6
стоп што в смысле не смог найти?? тут поподробнее
CapabilityManager:
package net.minecraftforge.common.capabilities;

import net.minecraftforge.fml.Logging;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.forgespi.language.ModFileScanData;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.Type;

import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.List;

public enum CapabilityManager
{
    INSTANCE;
    static final Logger LOGGER = LogManager.getLogger();


    public static <T> Capability<T> get(CapabilityToken<T> type)
    {
        return INSTANCE.get(type.getType(), false);
    }

    @SuppressWarnings("unchecked")
    <T> Capability<T> get(String realName, boolean registering)
    {
        Capability<T> cap;

        synchronized (providers)
        {
            realName = realName.intern();
            cap = (Capability<T>)providers.computeIfAbsent(realName, Capability::new);
        }


        if (registering)
        {
            synchronized (cap)
            {
                if (cap.isRegistered())
                {
                    LOGGER.error(Logging.CAPABILITIES, "Cannot register capability implementation multiple times : {}", realName);
                    throw new IllegalArgumentException("Cannot register a capability implementation multiple times : "+ realName);
                }
                else
                {
                    cap.onRegister();
                }
            }
        }

        return cap;
    }

    // INTERNAL
    private static final Type AUTO_REGISTER = Type.getType(AutoRegisterCapability.class);
    private final IdentityHashMap<String, Capability<?>> providers = new IdentityHashMap<>();
    public void injectCapabilities(List<ModFileScanData> data)
    {
        var autos = data.stream()
            .flatMap(e -> e.getAnnotations().stream())
            .filter(a -> AUTO_REGISTER.equals(a.annotationType()))
            .map(a -> a.clazz())
            .distinct()
            .sorted(Comparator.comparing(Type::toString))
            .toList();

        for (var auto : autos)
        {
            LOGGER.debug(Logging.CAPABILITIES, "Attempting to automatically register: " + auto);
            get(auto.getInternalName(), true);
        }

        var event = new RegisterCapabilitiesEvent();
        ModLoader.get().postEvent(event);
    }

Кажется я кое что нашел, если это и есть решение то позже напишу...
 
84
5
6
attachCapability:
    @SubscribeEvent
    public static void attachCapability(AttachCapabilitiesEvent<LivingEntity> event) {
        if (event.getObject() instanceof Player player && player.getCapability(MMCapabilities.MORPHING).resolve().isEmpty()) {
            event.addCapability(MovieMaker.createRl("morphing"), new MorphingCapabilityProvider());
        }
    }

отладка вроде как показала что метод не используется...

Не правильно выразился брик поинт, которым я отметил метод вообще не реагирует...

и да
че кинуть то?

журнал?
 
Последнее редактирование:
Сверху