fix something bug

and add "void attachInit(T entity)" in ICapabilitySync
version 0.0.2
This commit is contained in:
LostInLinearPast 2025-10-18 17:43:22 +08:00
parent d496ad72c2
commit d5756d6e09
17 changed files with 115 additions and 60 deletions

View File

@ -12,7 +12,7 @@ mapping_version=2023.09.03-1.20.1
mod_id=sccore mod_id=sccore
mod_name=SnowyCrescentCore mod_name=SnowyCrescentCore
mod_license=GNU AGPL 3.0 mod_license=GNU AGPL 3.0
mod_version=1.20.1-0.0.1 mod_version=1.20.1-0.0.2
mod_group_id=com.linearpast mod_group_id=com.linearpast
mod_authors=LostInLinearPast mod_authors=LostInLinearPast
mod_description=A lib. mod_description=A lib.

View File

@ -35,7 +35,7 @@ public class CapabilityUtils {
* @param handler 网络包的handle * @param handler 网络包的handle
*/ */
public static <T extends ICapabilityPacket<?>> void registerPlayerCapabilityWithNetwork( public static <T extends ICapabilityPacket<?>> void registerPlayerCapabilityWithNetwork(
ResourceLocation key, PlayerCapabilityRegistry.CapabilityRecord<? extends ICapabilitySync> capabilityRecord, ResourceLocation key, PlayerCapabilityRegistry.CapabilityRecord<? extends ICapabilitySync<Player>> capabilityRecord,
CapabilityChannel channelRegister, CapabilityChannel channelRegister,
int cid, int cid,
Class<T> clazz, Class<T> clazz,
@ -59,7 +59,7 @@ public class CapabilityUtils {
* @param handler 网络包的handle * @param handler 网络包的handle
*/ */
public static <T extends ICapabilityPacket<?>> void registerEntityCapabilityWithNetwork( public static <T extends ICapabilityPacket<?>> void registerEntityCapabilityWithNetwork(
ResourceLocation key, EntityCapabilityRegistry.CapabilityRecord<? extends ICapabilitySync> capabilityRecord, ResourceLocation key, EntityCapabilityRegistry.CapabilityRecord<? extends ICapabilitySync<? extends Entity>> capabilityRecord,
CapabilityChannel channelRegister, CapabilityChannel channelRegister,
int cid, int cid,
Class<T> clazz, Class<T> clazz,
@ -77,7 +77,7 @@ public class CapabilityUtils {
* @param key capability的唯一name * @param key capability的唯一name
* @param capabilityRecord 使用record存储了应该注册的capability的各项数据参阅{@link PlayerCapabilityRegistry.CapabilityRecord} * @param capabilityRecord 使用record存储了应该注册的capability的各项数据参阅{@link PlayerCapabilityRegistry.CapabilityRecord}
*/ */
public static <T extends ICapabilitySync> void registerPlayerCapability(ResourceLocation key, PlayerCapabilityRegistry.CapabilityRecord<T> capabilityRecord){ public static <T extends ICapabilitySync<Player>> void registerPlayerCapability(ResourceLocation key, PlayerCapabilityRegistry.CapabilityRecord<T> capabilityRecord){
PlayerCapabilityRegistry.registerCapability(key, capabilityRecord); PlayerCapabilityRegistry.registerCapability(key, capabilityRecord);
} }
@ -87,7 +87,7 @@ public class CapabilityUtils {
* @param key capability的唯一name * @param key capability的唯一name
* @param capabilityRecord 使用record存储了应该注册的capability的各项数据参阅{@link PlayerCapabilityRegistry.CapabilityRecord} * @param capabilityRecord 使用record存储了应该注册的capability的各项数据参阅{@link PlayerCapabilityRegistry.CapabilityRecord}
*/ */
public static <T extends ICapabilitySync> void registerEntityCapability(ResourceLocation key, EntityCapabilityRegistry.CapabilityRecord<T> capabilityRecord){ public static <T extends ICapabilitySync<Entity>> void registerEntityCapability(ResourceLocation key, EntityCapabilityRegistry.CapabilityRecord<T> capabilityRecord){
EntityCapabilityRegistry.registerCapability(key, capabilityRecord); EntityCapabilityRegistry.registerCapability(key, capabilityRecord);
} }
@ -119,48 +119,72 @@ public class CapabilityUtils {
} }
/** /**
* 请通过该方法获取玩家的capability * 请通过该方法获取capability
* @param player 目标玩家 * @param entity 目标实体类型 {@code <E extends Entity>}
* @param key capability key * @param key capability的唯一名
* @param clazz 应返回的capability类型 * @param clazz 应返回的capability类型若为null则会返回 {@code ICapabilitySync<E>}
* @return 返回对应的capability * @return 返回对应的capability
*/ */
@SuppressWarnings("unchecked")
@Nullable @Nullable
public static <T extends ICapabilitySync> T getPlayerCapability(Player player, ResourceLocation key, Class<T> clazz) { public static <E extends Entity, T extends ICapabilitySync<E>> T getEntityCapability(E entity, ResourceLocation key, @Nullable Class<T> clazz) {
if(player == null) return null;
ICapabilitySync capabilitySync = player.getCapability(
PlayerCapabilityRegistry.getCapabilityMap().get(key).capability()
).resolve().orElse(null);
if(capabilitySync == null) return null;
try { try {
ICapabilitySync<?> capabilitySync = entity.getCapability(
EntityCapabilityRegistry.getCapabilityMap().get(key).capability()
).resolve().orElse(null);
if(clazz == null) return (T) capabilitySync;
if(clazz.isInstance(capabilitySync)) if(clazz.isInstance(capabilitySync))
return clazz.cast(capabilitySync); return clazz.cast(capabilitySync);
else return null; else return null;
}catch(ClassCastException e){ }catch(Exception e){
return null; return null;
} }
} }
/** /**
* 请通过该方法获取实体的capability * 请通过该方法获取capability
* @param entity 目标实体 * @param entity 目标实体类型 {@code <E extends Entity>}
* @param key capability key * @param key capability的唯一名
* @param clazz 应返回的capability类型 * @param clazz 应返回的capability类型若为null则会返回 {@code ICapabilitySync<E>}
* @return 返回对应的capability * @return 返回对应的capability
*/ */
@SuppressWarnings("unchecked")
@Nullable @Nullable
public static <T extends ICapabilitySync> T getEntityCapability(Entity entity, ResourceLocation key, Class<T> clazz) { public static <E extends Player, T extends ICapabilitySync<E>> T getPlayerCapability(E entity, ResourceLocation key, @Nullable Class<T> clazz) {
if(entity == null) return null;
ICapabilitySync capabilitySync = entity.getCapability(
EntityCapabilityRegistry.getCapabilityMap().get(key).capability()
).resolve().orElse(null);
if(capabilitySync == null) return null;
try { try {
ICapabilitySync<?> capabilitySync = entity.getCapability(
PlayerCapabilityRegistry.getCapabilityMap().get(key).capability()
).resolve().orElse(null);
if(clazz == null) return (T) capabilitySync;
if(clazz.isInstance(capabilitySync)) if(clazz.isInstance(capabilitySync))
return clazz.cast(capabilitySync); return clazz.cast(capabilitySync);
else return null; else return null;
}catch(ClassCastException e){ }catch(Exception e){
return null; return null;
} }
} }
/**
* 获取一个未转换类型的Cap
* @param entity 目标
* @param key cap的唯一名
* @return 未转换类型的cap
*/
@Nullable
public static ICapabilitySync<?> getCapability(Entity entity, ResourceLocation key) {
if(entity == null) return null;
try {
if(entity instanceof Player) {
return entity.getCapability(
PlayerCapabilityRegistry.getCapabilityMap().get(key).capability()
).resolve().orElse(null);
}
return entity.getCapability(
EntityCapabilityRegistry.getCapabilityMap().get(key).capability()
).resolve().orElse(null);
}catch(Exception e){
return null;
}
}
} }

View File

@ -7,7 +7,7 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraftforge.common.util.INBTSerializable; import net.minecraftforge.common.util.INBTSerializable;
public interface ICapabilitySync extends INBTSerializable<CompoundTag> { public interface ICapabilitySync<T extends Entity> extends INBTSerializable<CompoundTag> {
void setDirty(boolean dirty); void setDirty(boolean dirty);
boolean isDirty(); boolean isDirty();
@ -19,7 +19,7 @@ public interface ICapabilitySync extends INBTSerializable<CompoundTag> {
* @param oldData 旧数据 * @param oldData 旧数据
* @param listenDone 最后是否执行完成方法 {@link ICapabilitySync#onCopyDone()} * @param listenDone 最后是否执行完成方法 {@link ICapabilitySync#onCopyDone()}
*/ */
default void copyFrom(ICapabilitySync oldData, boolean listenDone) { default void copyFrom(ICapabilitySync<?> oldData, boolean listenDone) {
this.setDirty(oldData.isDirty()); this.setDirty(oldData.isDirty());
if(listenDone) onCopyDone(); if(listenDone) onCopyDone();
} }
@ -53,6 +53,12 @@ public interface ICapabilitySync extends INBTSerializable<CompoundTag> {
* 一般情况下你应该extends SimpleCapabilityPacket然后重写该方法返回你的子类 * 一般情况下你应该extends SimpleCapabilityPacket然后重写该方法返回你的子类
* @return 网络包类SimpleCapabilityPacket * @return 网络包类SimpleCapabilityPacket
*/ */
SimpleCapabilityPacket<? extends Entity> getDefaultPacket(); SimpleCapabilityPacket<T> getDefaultPacket();
/**
* 当玩家登录 / 实体加入世界时的cao初始化时会调用 <br>
* 必须实现但可为空方法
* @param entity 目标
*/
void attachInit(T entity);
} }

View File

@ -45,7 +45,7 @@ public class EntityCapabilityHandler {
EntityCapabilityRegistry.getCapabilityMap().forEach((key, record) -> { EntityCapabilityRegistry.getCapabilityMap().forEach((key, record) -> {
if(record.target().isInstance(entity)) { if(record.target().isInstance(entity)) {
try { try {
ICapabilitySync capabilitySync = (ICapabilitySync) record.aClass().getDeclaredConstructor().newInstance(); ICapabilitySync<?> capabilitySync = (ICapabilitySync<?>) record.aClass().getDeclaredConstructor().newInstance();
event.addCapability(key, new EntityCapabilityProvider<>(key, capabilitySync)); event.addCapability(key, new EntityCapabilityProvider<>(key, capabilitySync));
} catch (Exception e) { } catch (Exception e) {
log.error("Failed to instantiate capability sync class {}. Your capability register is wrong.", record.aClass(), e); log.error("Failed to instantiate capability sync class {}. Your capability register is wrong.", record.aClass(), e);

View File

@ -4,6 +4,7 @@ import com.linearpast.sccore.capability.data.ICapabilitySync;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraftforge.common.capabilities.AutoRegisterCapability; import net.minecraftforge.common.capabilities.AutoRegisterCapability;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.capabilities.ICapabilitySerializable;
@ -16,7 +17,7 @@ import org.jetbrains.annotations.Nullable;
* @param <C> 继承 {@link ICapabilitySync} * @param <C> 继承 {@link ICapabilitySync}
*/ */
@AutoRegisterCapability @AutoRegisterCapability
public class EntityCapabilityProvider<C extends ICapabilitySync> implements ICapabilitySerializable<CompoundTag> { public class EntityCapabilityProvider<C extends ICapabilitySync<? extends Entity>> implements ICapabilitySerializable<CompoundTag> {
private final C instance; private final C instance;
private final ResourceLocation resourceLocation; private final ResourceLocation resourceLocation;
public EntityCapabilityProvider(ResourceLocation resourceLocation, C instance) { public EntityCapabilityProvider(ResourceLocation resourceLocation, C instance) {

View File

@ -46,7 +46,7 @@ public class EntityCapabilityRegistry {
* @param interfaceClass instance类对应的实例对应的接口类比如ICapabilitySync.class * @param interfaceClass instance类对应的实例对应的接口类比如ICapabilitySync.class
* @param target capability附加的目标类型 * @param target capability附加的目标类型
*/ */
public record CapabilityRecord<T extends ICapabilitySync>(Class<?> aClass, Capability<T> capability, Class<T> interfaceClass, Class<? extends Entity> target) { public record CapabilityRecord<T extends ICapabilitySync<? extends Entity>>(Class<?> aClass, Capability<T> capability, Class<T> interfaceClass, Class<? extends Entity> target) {
} }
} }

View File

@ -20,7 +20,7 @@ public class EntityCapabilityRemainder {
public static void onEntityBeTracked(PlayerEvent.StartTracking event) { public static void onEntityBeTracked(PlayerEvent.StartTracking event) {
if (event.getEntity() instanceof ServerPlayer attacker) { if (event.getEntity() instanceof ServerPlayer attacker) {
PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> { PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> {
ICapabilitySync data = CapabilityUtils.getEntityCapability(event.getTarget(), key, ICapabilitySync.class); ICapabilitySync<?> data = CapabilityUtils.getCapability(event.getTarget(), key);
if(data == null) return; if(data == null) return;
data.sendToClient(attacker); data.sendToClient(attacker);
}); });
@ -38,7 +38,7 @@ public class EntityCapabilityRemainder {
if(!entity.level().isClientSide){ if(!entity.level().isClientSide){
if (entity.tickCount % 20 == 0) { if (entity.tickCount % 20 == 0) {
PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> { PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> {
ICapabilitySync data = CapabilityUtils.getEntityCapability(entity, key, ICapabilitySync.class); ICapabilitySync<?> data = CapabilityUtils.getCapability(entity, key);
if(data == null) return; if(data == null) return;
if(data.isDirty()) { if(data.isDirty()) {
data.setDirty(false); data.setDirty(false);
@ -57,11 +57,12 @@ public class EntityCapabilityRemainder {
Entity entity = event.getEntity(); Entity entity = event.getEntity();
if(entity.level().isClientSide) return; if(entity.level().isClientSide) return;
EntityCapabilityRegistry.getCapabilityMap().forEach((key, value) -> { EntityCapabilityRegistry.getCapabilityMap().forEach((key, value) -> {
ICapabilitySync data = CapabilityUtils.getEntityCapability(entity, key, ICapabilitySync.class); ICapabilitySync<Entity> data = CapabilityUtils.getEntityCapability(entity, key, null);
if(data == null) return; if(data == null) return;
if(data instanceof SimpleEntityCapabilitySync capabilitySync){ if(data instanceof SimpleEntityCapabilitySync<?> capabilitySync){
capabilitySync.setId(entity.getId()); capabilitySync.setId(entity.getId());
} }
data.attachInit(entity);
data.setDirty(false); data.setDirty(false);
data.sendToClient(); data.sendToClient();
}); });

View File

@ -2,6 +2,7 @@ package com.linearpast.sccore.capability.data.entity;
import com.linearpast.sccore.capability.data.ICapabilitySync; import com.linearpast.sccore.capability.data.ICapabilitySync;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.Entity;
/** /**
* 实现时建议手动添加<br> * 实现时建议手动添加<br>
@ -21,7 +22,7 @@ import net.minecraft.nbt.CompoundTag;
* </pre> * </pre>
* *
*/ */
public abstract class SimpleEntityCapabilitySync implements ICapabilitySync { public abstract class SimpleEntityCapabilitySync<T extends Entity> implements ICapabilitySync<T> {
public static final String Id = "Id"; public static final String Id = "Id";
private boolean dirty; private boolean dirty;
@ -57,8 +58,8 @@ public abstract class SimpleEntityCapabilitySync implements ICapabilitySync {
* @param listenDone 最后是否执行完成方法 {@link ICapabilitySync#onCopyDone()} * @param listenDone 最后是否执行完成方法 {@link ICapabilitySync#onCopyDone()}
*/ */
@Override @Override
public void copyFrom(ICapabilitySync oldData, boolean listenDone) { public void copyFrom(ICapabilitySync<?> oldData, boolean listenDone) {
SimpleEntityCapabilitySync data = (SimpleEntityCapabilitySync) oldData; SimpleEntityCapabilitySync<?> data = (SimpleEntityCapabilitySync<?>) oldData;
this.setId(data.getId()); this.setId(data.getId());
copyFrom(data); copyFrom(data);
ICapabilitySync.super.copyFrom(oldData, listenDone); ICapabilitySync.super.copyFrom(oldData, listenDone);
@ -68,7 +69,7 @@ public abstract class SimpleEntityCapabilitySync implements ICapabilitySync {
* 触发数据复制时会执行的方法 * 触发数据复制时会执行的方法
* @param oldData 从这个数据中复制到当前实例 * @param oldData 从这个数据中复制到当前实例
*/ */
public abstract void copyFrom(ICapabilitySync oldData); public abstract void copyFrom(ICapabilitySync<?> oldData);
/** /**
* 序列化为tag <br> * 序列化为tag <br>

View File

@ -46,7 +46,7 @@ public class PlayerCapabilityHandler {
if(event.getObject() instanceof Player) { if(event.getObject() instanceof Player) {
PlayerCapabilityRegistry.getCapabilityMap().forEach((key, record) -> { PlayerCapabilityRegistry.getCapabilityMap().forEach((key, record) -> {
try { try {
ICapabilitySync capabilitySync = (ICapabilitySync) record.aClass().getDeclaredConstructor().newInstance(); ICapabilitySync<?> capabilitySync = (ICapabilitySync<?>) record.aClass().getDeclaredConstructor().newInstance();
event.addCapability(key, new PlayerCapabilityProvider<>(key, capabilitySync)); event.addCapability(key, new PlayerCapabilityProvider<>(key, capabilitySync));
} catch (Exception e) { } catch (Exception e) {
log.error("Failed to instantiate capability sync class {}. Your capability register is wrong.", record.aClass(), e); log.error("Failed to instantiate capability sync class {}. Your capability register is wrong.", record.aClass(), e);

View File

@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@AutoRegisterCapability @AutoRegisterCapability
public class PlayerCapabilityProvider<C extends ICapabilitySync> implements ICapabilitySerializable<CompoundTag> { public class PlayerCapabilityProvider<C extends ICapabilitySync<?>> implements ICapabilitySerializable<CompoundTag> {
private final C instance; private final C instance;
private final ResourceLocation resourceLocation; private final ResourceLocation resourceLocation;
public PlayerCapabilityProvider(ResourceLocation resourceLocation, C instance) { public PlayerCapabilityProvider(ResourceLocation resourceLocation, C instance) {

View File

@ -2,6 +2,7 @@ package com.linearpast.sccore.capability.data.player;
import com.linearpast.sccore.capability.data.ICapabilitySync; import com.linearpast.sccore.capability.data.ICapabilitySync;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import java.util.HashMap; import java.util.HashMap;
@ -40,5 +41,5 @@ public class PlayerCapabilityRegistry {
* @param capability 一般情况下不需要初始化它默认CapabilityManager.get(new CapabilityToken<>(){}) * @param capability 一般情况下不需要初始化它默认CapabilityManager.get(new CapabilityToken<>(){})
* @param interfaceClass instance实例对应的接口类比如ICapabilitySync.class * @param interfaceClass instance实例对应的接口类比如ICapabilitySync.class
*/ */
public record CapabilityRecord<T extends ICapabilitySync>(Class<?> aClass, Capability<T> capability, Class<T> interfaceClass) { } public record CapabilityRecord<T extends ICapabilitySync<? extends Player>>(Class<?> aClass, Capability<T> capability, Class<T> interfaceClass) { }
} }

View File

@ -25,8 +25,8 @@ public class PlayerCapabilityRemainder {
Player original = event.getOriginal(); Player original = event.getOriginal();
original.reviveCaps(); original.reviveCaps();
PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> { PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> {
ICapabilitySync originData = CapabilityUtils.getPlayerCapability(original, key, ICapabilitySync.class); ICapabilitySync<?> originData = CapabilityUtils.getCapability(original, key);
ICapabilitySync newData = CapabilityUtils.getPlayerCapability(newPlayer, key, ICapabilitySync.class); ICapabilitySync<?> newData = CapabilityUtils.getCapability(newPlayer, key);
if(originData != null && newData != null) { if(originData != null && newData != null) {
newData.copyFrom(originData, true); newData.copyFrom(originData, true);
newData.sendToClient(); newData.sendToClient();
@ -43,7 +43,7 @@ public class PlayerCapabilityRemainder {
public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) { public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) {
if(event.getEntity() instanceof ServerPlayer newPlayer){ if(event.getEntity() instanceof ServerPlayer newPlayer){
PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> { PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> {
ICapabilitySync data = CapabilityUtils.getPlayerCapability(newPlayer, key, ICapabilitySync.class); ICapabilitySync<?> data = CapabilityUtils.getCapability(newPlayer, key);
if(data == null) return; if(data == null) return;
data.sendToClient(newPlayer); data.sendToClient(newPlayer);
}); });
@ -59,7 +59,7 @@ public class PlayerCapabilityRemainder {
public static void onEntityBeTracked(PlayerEvent.StartTracking event) { public static void onEntityBeTracked(PlayerEvent.StartTracking event) {
if (event.getTarget() instanceof Player target && event.getEntity() instanceof ServerPlayer attacker) { if (event.getTarget() instanceof Player target && event.getEntity() instanceof ServerPlayer attacker) {
PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> { PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> {
ICapabilitySync data = CapabilityUtils.getPlayerCapability(target, key, ICapabilitySync.class); ICapabilitySync<?> data = CapabilityUtils.getCapability(target, key);
if(data == null) return; if(data == null) return;
data.sendToClient(attacker); data.sendToClient(attacker);
}); });
@ -74,7 +74,7 @@ public class PlayerCapabilityRemainder {
public static void capabilitySync(TickEvent.PlayerTickEvent event) { public static void capabilitySync(TickEvent.PlayerTickEvent event) {
if(!event.player.level().isClientSide){ if(!event.player.level().isClientSide){
PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> { PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> {
ICapabilitySync data = CapabilityUtils.getPlayerCapability(event.player, key, ICapabilitySync.class); ICapabilitySync<?> data = CapabilityUtils.getCapability(event.player, key);
if(data == null) return; if(data == null) return;
if(data.isDirty()) { if(data.isDirty()) {
data.setDirty(false); data.setDirty(false);
@ -94,11 +94,12 @@ public class PlayerCapabilityRemainder {
Player player = event.getEntity(); Player player = event.getEntity();
if(!(player instanceof ServerPlayer serverPlayer)) return; if(!(player instanceof ServerPlayer serverPlayer)) return;
PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> { PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> {
ICapabilitySync data = CapabilityUtils.getPlayerCapability(player, key, ICapabilitySync.class); ICapabilitySync<Player> data = CapabilityUtils.getPlayerCapability(player, key, null);
if(data == null) return; if(data == null) return;
if(data instanceof SimplePlayerCapabilitySync capabilitySync) { if(data instanceof SimplePlayerCapabilitySync capabilitySync) {
capabilitySync.setOwnerUUID(serverPlayer.getUUID()); capabilitySync.setOwnerUUID(serverPlayer.getUUID());
} }
data.attachInit(serverPlayer);
data.setDirty(false); data.setDirty(false);
data.sendToClient(); data.sendToClient();
}); });
@ -106,7 +107,7 @@ public class PlayerCapabilityRemainder {
serverPlayers -> serverPlayers.forEach(p -> { serverPlayers -> serverPlayers.forEach(p -> {
if(!p.getUUID().equals(serverPlayer.getUUID())) { if(!p.getUUID().equals(serverPlayer.getUUID())) {
PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> { PlayerCapabilityRegistry.getCapabilityMap().forEach((key, value) -> {
ICapabilitySync data = CapabilityUtils.getPlayerCapability(player, key, ICapabilitySync.class); ICapabilitySync<?> data = CapabilityUtils.getCapability(player, key);
if(data == null) return; if(data == null) return;
data.sendToClient(serverPlayer); data.sendToClient(serverPlayer);
}); });

View File

@ -2,6 +2,7 @@ package com.linearpast.sccore.capability.data.player;
import com.linearpast.sccore.capability.data.ICapabilitySync; import com.linearpast.sccore.capability.data.ICapabilitySync;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.player.Player;
import java.util.UUID; import java.util.UUID;
@ -23,7 +24,7 @@ import java.util.UUID;
* </pre> * </pre>
* *
*/ */
public abstract class SimplePlayerCapabilitySync implements ICapabilitySync { public abstract class SimplePlayerCapabilitySync implements ICapabilitySync<Player> {
public static final String OwnerUUID = "OwnerUUID"; public static final String OwnerUUID = "OwnerUUID";
private boolean dirty; private boolean dirty;
@ -55,9 +56,10 @@ public abstract class SimplePlayerCapabilitySync implements ICapabilitySync {
* @param listenDone 最后是否执行完成方法 {@link ICapabilitySync#onCopyDone()} * @param listenDone 最后是否执行完成方法 {@link ICapabilitySync#onCopyDone()}
*/ */
@Override @Override
public void copyFrom(ICapabilitySync oldData, boolean listenDone) { public void copyFrom(ICapabilitySync<?> oldData, boolean listenDone) {
SimplePlayerCapabilitySync data = (SimplePlayerCapabilitySync) oldData; SimplePlayerCapabilitySync data = (SimplePlayerCapabilitySync) oldData;
this.setOwnerUUID(data.getOwnerUUID()); this.setOwnerUUID(data.getOwnerUUID());
copyFrom(data);
ICapabilitySync.super.copyFrom(oldData, listenDone); ICapabilitySync.super.copyFrom(oldData, listenDone);
} }
@ -65,7 +67,7 @@ public abstract class SimplePlayerCapabilitySync implements ICapabilitySync {
* 触发数据复制时会执行的方法 * 触发数据复制时会执行的方法
* @param oldData 从这个数据中复制到当前实例 * @param oldData 从这个数据中复制到当前实例
*/ */
public abstract void copyFrom(ICapabilitySync oldData); public abstract void copyFrom(ICapabilitySync<?> oldData);
/** /**
* 序列化为tag <br> * 序列化为tag <br>

View File

@ -2,6 +2,7 @@ package com.linearpast.sccore.capability.network;
import com.linearpast.sccore.capability.data.ICapabilitySync; import com.linearpast.sccore.capability.data.ICapabilitySync;
import com.linearpast.sccore.capability.data.entity.SimpleEntityCapabilitySync; import com.linearpast.sccore.capability.data.entity.SimpleEntityCapabilitySync;
import com.linearpast.sccore.capability.data.player.SimplePlayerCapabilitySync;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -33,7 +34,14 @@ public abstract class SimpleCapabilityPacket<T extends Entity> implements ICapab
ClientLevel level = instance.level; ClientLevel level = instance.level;
if (level == null) return; if (level == null) return;
CompoundTag nbt = getData(); CompoundTag nbt = getData();
Entity entity = level.getEntity(nbt.getInt(SimpleEntityCapabilitySync.Id)); Entity entity = null;
if(nbt.contains(SimpleEntityCapabilitySync.Id)){
entity = level.getEntity(nbt.getInt(SimpleEntityCapabilitySync.Id));
}
if(nbt.contains(SimplePlayerCapabilitySync.OwnerUUID)){
entity = level.getPlayerByUUID(nbt.getUUID(SimplePlayerCapabilitySync.OwnerUUID));
}
if(entity == null) return;
try { try {
ICapabilitySync data = getCapability((T) entity); ICapabilitySync data = getCapability((T) entity);
syncData(nbt, data); syncData(nbt, data);

View File

@ -14,7 +14,8 @@ import net.minecraftforge.eventbus.api.IEventBus;
public class ModCaps { public class ModCaps {
/** /**
* 注册capability的示例<br> * 注册实体capability的示例<br>
* 请参阅 {@link CapabilityUtils}
*/ */
public static void register(){ public static void register(){
//如果你想将网络包注册到你自己的mod中createChannel(INSTANCE) //如果你想将网络包注册到你自己的mod中createChannel(INSTANCE)
@ -23,6 +24,7 @@ public class ModCaps {
//不可与其他网络包重复的任意整数 //不可与其他网络包重复的任意整数
int cid = Channel.getCid(); int cid = Channel.getCid();
//注册实体cap和它的网络包 //注册实体cap和它的网络包
//若注册玩家的请用registerPlayerCapabilityWithNetwork
CapabilityUtils.registerEntityCapabilityWithNetwork( CapabilityUtils.registerEntityCapabilityWithNetwork(
//一个resourceLocation任意命名不重复即可 //一个resourceLocation任意命名不重复即可
SheepDataCapability.key, SheepDataCapability.key,

View File

@ -1,12 +1,13 @@
package com.linearpast.sccore.example.cap; package com.linearpast.sccore.example.cap;
import com.linearpast.sccore.capability.data.ICapabilitySync; import com.linearpast.sccore.capability.data.ICapabilitySync;
import net.minecraft.world.entity.animal.Sheep;
/** /**
* 接口继承ICapabilitySync是必需的但是接口是非必需的你可以在注册时直接使用cap类本身 <br> * 接口继承ICapabilitySync是必需的但是接口是非必需的你可以在注册时直接使用cap类本身 <br>
* 用于共享一些可能会用到的cap的公共方法 * 用于共享一些可能会用到的cap的公共方法
*/ */
public interface ISheepData extends ICapabilitySync { public interface ISheepData extends ICapabilitySync<Sheep> {
Integer getValue(); Integer getValue();
void setValue(Integer value); void setValue(Integer value);
} }

View File

@ -18,7 +18,7 @@ import java.util.Optional;
* 继承SimpleEntityCapabilitySync意味着自动托管一个id的同步 <br> * 继承SimpleEntityCapabilitySync意味着自动托管一个id的同步 <br>
* 实现的IsheepData仅含有属性value的getter和setter <br> * 实现的IsheepData仅含有属性value的getter和setter <br>
*/ */
public class SheepDataCapability extends SimpleEntityCapabilitySync implements ISheepData { public class SheepDataCapability extends SimpleEntityCapabilitySync<Sheep> implements ISheepData {
//代表cap的key注册获取时都需要它 //代表cap的key注册获取时都需要它
public static final ResourceLocation key = new ResourceLocation(SnowyCrescentCore.MODID, "sheep_data"); public static final ResourceLocation key = new ResourceLocation(SnowyCrescentCore.MODID, "sheep_data");
@ -59,7 +59,7 @@ public class SheepDataCapability extends SimpleEntityCapabilitySync implements I
//从旧实例中复制数据到新实例的方法 //从旧实例中复制数据到新实例的方法
@Override @Override
public void copyFrom(ICapabilitySync oldData) { public void copyFrom(ICapabilitySync<?> oldData) {
SheepDataCapability data = (SheepDataCapability) oldData; SheepDataCapability data = (SheepDataCapability) oldData;
this.value = data.getValue(); this.value = data.getValue();
} }
@ -82,7 +82,7 @@ public class SheepDataCapability extends SimpleEntityCapabilitySync implements I
//仅用在网络包内部的getCap //仅用在网络包内部的getCap
@Override @Override
public @Nullable ICapabilitySync getCapability(Sheep entity) { public @Nullable SheepDataCapability getCapability(Sheep entity) {
return SheepDataCapability.getCapability(entity).orElse(null); return SheepDataCapability.getCapability(entity).orElse(null);
} }
} }
@ -93,6 +93,13 @@ public class SheepDataCapability extends SimpleEntityCapabilitySync implements I
return new SheepCapabilityPacket(serializeNBT()); return new SheepCapabilityPacket(serializeNBT());
} }
//该方法会在cap初始化时调用比如玩家登录
//该例中当羊加入level时会调用该方法以初始化cap
@Override
public void attachInit(Sheep entity) {
}
//在其他地方需要用到cap的时候调用这个 //在其他地方需要用到cap的时候调用这个
//目的是为了简化cap utils的方法 //目的是为了简化cap utils的方法
public static Optional<SheepDataCapability> getCapability(Sheep sheep){ public static Optional<SheepDataCapability> getCapability(Sheep sheep){