From ab154908b0ce8d1c89645a5d7167b1271ff60ca3 Mon Sep 17 00:00:00 2001 From: Pyrofab Date: Mon, 2 Mar 2020 02:17:09 +0100 Subject: [PATCH] Make PAL serverside only At least for now, the library isn't made for clientside use --- README.md | 12 +- .../ladysnake/pal/impl/PlayerAbilityView.java | 3 + .../pal/impl/mixin/PlayerEntityMixin.java | 116 ------------------ .../impl/mixin/ServerPlayerEntityMixin.java | 82 ++++++++++++- .../mixins.playerabilitylib.common.json | 1 - 5 files changed, 90 insertions(+), 124 deletions(-) delete mode 100644 src/main/java/io/github/ladysnake/pal/impl/mixin/PlayerEntityMixin.java diff --git a/README.md b/README.md index e09b3ed..393e293 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,12 @@ [![Curseforge](https://curse.nikky.moe/api/img/359522?logo)](https://www.curseforge.com/projects/359522) [![](https://jitpack.io/v/Ladysnake/PlayerAbilityLib.svg)](https://jitpack.io/#Ladysnake/PlayerAbilityLib) -A lightweight library to provide compatibility between mods that make use of player abilities. +A lightweight serverside library to provide compatibility between mods that make use of player abilities. -*credits to Chloe Dawn for some of the API design* +Conflicts arise often when several mods update the same field in `PlayerAbilities`. This library exists so that +all modifications can be made from a single place, keeping track of what mod enabled what ability. + +*credits to ~~InsomniaPrincess~~ Chloe Dawn for some of the API design* ## Adding PAL to your project @@ -37,7 +40,10 @@ You can find the current version of PAL in the [releases](https://github.com/Lad You can find a couple examples in the [Test Mod](https://github.com/Ladysnake/PlayerAbilityLib/tree/master/src/testmod/java/io/github/ladysnake/paltest). -Note that player abilities can only accessed serverside. If you want to store more complex data, or to synchronize it between server and client, +**Note that PAL interfaces can only be accessed serverside, as no synchronization is done on the ability sources.** +Read accesses can still be done directly on the `PlayerAbilities` instance, both serverside and clientside. + +If you want to store more complex data, or to synchronize it between server and client, you should take a look at [Cardinal Components API](https://github.com/OnyxStudios/Cardinal-Components-API). [Item that toggles an ability](https://github.com/Ladysnake/PlayerAbilityLib/blob/master/src/testmod/java/io/github/ladysnake/paltest/AbilityToggleItem.java) : diff --git a/src/main/java/io/github/ladysnake/pal/impl/PlayerAbilityView.java b/src/main/java/io/github/ladysnake/pal/impl/PlayerAbilityView.java index 667177d..83e1838 100644 --- a/src/main/java/io/github/ladysnake/pal/impl/PlayerAbilityView.java +++ b/src/main/java/io/github/ladysnake/pal/impl/PlayerAbilityView.java @@ -42,6 +42,9 @@ public interface PlayerAbilityView { * @return a view for the player's abilities */ static PlayerAbilityView of(PlayerEntity player) { + if (player.world.isClient) { + throw new IllegalStateException("Player abilities must be accessed from the logical server !"); + } return (PlayerAbilityView) player; } diff --git a/src/main/java/io/github/ladysnake/pal/impl/mixin/PlayerEntityMixin.java b/src/main/java/io/github/ladysnake/pal/impl/mixin/PlayerEntityMixin.java deleted file mode 100644 index db4ba6b..0000000 --- a/src/main/java/io/github/ladysnake/pal/impl/mixin/PlayerEntityMixin.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * PlayerAbilityLib - * Copyright (C) 2019-2020 Ladysnake - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; If not, see . - */ -package io.github.ladysnake.pal.impl.mixin; - -import com.mojang.authlib.GameProfile; -import io.github.ladysnake.pal.AbilityTracker; -import io.github.ladysnake.pal.PlayerAbility; -import io.github.ladysnake.pal.VanillaAbilities; -import io.github.ladysnake.pal.impl.PalInternals; -import io.github.ladysnake.pal.impl.PlayerAbilityView; -import net.fabricmc.fabric.api.util.NbtType; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.player.PlayerAbilities; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.util.Identifier; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -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.LinkedHashMap; -import java.util.Map; - -@Mixin(PlayerEntity.class) -public abstract class PlayerEntityMixin extends LivingEntity implements PlayerAbilityView { - @Shadow - public abstract void sendAbilitiesUpdate(); - - @Shadow - @Final - public PlayerAbilities abilities; - @Unique - private final Map palAbilities = new LinkedHashMap<>(); - - protected PlayerEntityMixin(EntityType type, World world) { - super(type, world); - } - - @Inject(method = "", at = @At("RETURN")) - private void init(World world, GameProfile profile, CallbackInfo ci) { - PalInternals.populate((PlayerEntity) (Object) this, this.palAbilities); - } - - @Override - public Iterable listPalAbilities() { - return this.palAbilities.keySet(); - } - - @Override - public AbilityTracker get(PlayerAbility abilityId) { - return this.palAbilities.get(abilityId); - } - - @Override - public void refreshAllPalAbilities(boolean syncVanilla) { - for (PlayerAbility ability : this.listPalAbilities()) { - if (ability != VanillaAbilities.FLYING) { - this.get(ability).refresh(false); - } - } - if (syncVanilla) { - this.sendAbilitiesUpdate(); // batch vanilla abilities updates - } - } - - @Inject(method = "writeCustomDataToTag", at = @At("RETURN")) - private void writeAbilitiesToTag(CompoundTag tag, CallbackInfo ci) { - ListTag list = new ListTag(); - for (Map.Entry entry : this.palAbilities.entrySet()) { - CompoundTag abilityTag = new CompoundTag(); - abilityTag.putString("ability_id", entry.getKey().toString()); - entry.getValue().save(abilityTag); - list.add(abilityTag); - } - tag.put("playerabilitylib:abilities", list); - } - - @Inject(method = "readCustomDataFromTag", at = @At("RETURN")) - private void readAbilitiesFromTag(CompoundTag tag, CallbackInfo ci) { - for (Tag t : tag.getList("playerabilitylib:abilities", NbtType.COMPOUND)) { - CompoundTag abilityTag = ((CompoundTag) t); - if (abilityTag.contains("ability_id")) { - Identifier abilityId = Identifier.tryParse(abilityTag.getString("ability_id")); - if (abilityId != null) { - AbilityTracker ability = this.palAbilities.get(PalInternals.getAbility(abilityId)); - if (ability != null) { - ability.load(abilityTag); - } - } - } - } - } -} diff --git a/src/main/java/io/github/ladysnake/pal/impl/mixin/ServerPlayerEntityMixin.java b/src/main/java/io/github/ladysnake/pal/impl/mixin/ServerPlayerEntityMixin.java index 6de5d1f..f58e4f8 100644 --- a/src/main/java/io/github/ladysnake/pal/impl/mixin/ServerPlayerEntityMixin.java +++ b/src/main/java/io/github/ladysnake/pal/impl/mixin/ServerPlayerEntityMixin.java @@ -17,22 +17,69 @@ */ package io.github.ladysnake.pal.impl.mixin; +import com.mojang.authlib.GameProfile; import io.github.ladysnake.pal.AbilityTracker; import io.github.ladysnake.pal.PlayerAbility; import io.github.ladysnake.pal.VanillaAbilities; +import io.github.ladysnake.pal.impl.PalInternals; import io.github.ladysnake.pal.impl.PlayerAbilityView; import io.github.ladysnake.pal.impl.VanillaAbilityTracker; +import net.fabricmc.fabric.api.util.NbtType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.network.ServerPlayerInteractionManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Identifier; +import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; 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.LinkedHashMap; +import java.util.Map; + @Mixin(ServerPlayerEntity.class) -public abstract class ServerPlayerEntityMixin implements PlayerAbilityView { - @Shadow - public abstract void sendAbilitiesUpdate(); +public abstract class ServerPlayerEntityMixin extends PlayerEntity implements PlayerAbilityView { + + @Unique + private final Map palAbilities = new LinkedHashMap<>(); + + public ServerPlayerEntityMixin(World world, GameProfile profile) { + super(world, profile); + } + + @Inject(method = "", at = @At("RETURN")) + private void init(MinecraftServer server, ServerWorld world, GameProfile profile, ServerPlayerInteractionManager interactionManager, CallbackInfo ci) { + PalInternals.populate(this, this.palAbilities); + } + + @Override + public Iterable listPalAbilities() { + return this.palAbilities.keySet(); + } + + @Override + public AbilityTracker get(PlayerAbility abilityId) { + return this.palAbilities.get(abilityId); + } + + @Override + public void refreshAllPalAbilities(boolean syncVanilla) { + for (PlayerAbility ability : this.listPalAbilities()) { + if (ability != VanillaAbilities.FLYING) { + this.get(ability).refresh(false); + } + } + if (syncVanilla) { + this.sendAbilitiesUpdate(); // batch vanilla abilities updates + } + } @Inject(method = "sendAbilitiesUpdate", at = @At(value = "NEW", target = "net/minecraft/client/network/packet/PlayerAbilitiesS2CPacket")) private void checkAbilityConsistency(CallbackInfo ci) { @@ -44,4 +91,31 @@ private void checkAbilityConsistency(CallbackInfo ci) { } } + @Inject(method = "writeCustomDataToTag", at = @At("RETURN")) + private void writeAbilitiesToTag(CompoundTag tag, CallbackInfo ci) { + ListTag list = new ListTag(); + for (Map.Entry entry : this.palAbilities.entrySet()) { + CompoundTag abilityTag = new CompoundTag(); + abilityTag.putString("ability_id", entry.getKey().toString()); + entry.getValue().save(abilityTag); + list.add(abilityTag); + } + tag.put("playerabilitylib:abilities", list); + } + + @Inject(method = "readCustomDataFromTag", at = @At("RETURN")) + private void readAbilitiesFromTag(CompoundTag tag, CallbackInfo ci) { + for (Tag t : tag.getList("playerabilitylib:abilities", NbtType.COMPOUND)) { + CompoundTag abilityTag = ((CompoundTag) t); + if (abilityTag.contains("ability_id")) { + Identifier abilityId = Identifier.tryParse(abilityTag.getString("ability_id")); + if (abilityId != null) { + AbilityTracker ability = this.palAbilities.get(PalInternals.getAbility(abilityId)); + if (ability != null) { + ability.load(abilityTag); + } + } + } + } + } } diff --git a/src/main/resources/mixins.playerabilitylib.common.json b/src/main/resources/mixins.playerabilitylib.common.json index 1b6c2bf..57bbd27 100644 --- a/src/main/resources/mixins.playerabilitylib.common.json +++ b/src/main/resources/mixins.playerabilitylib.common.json @@ -4,7 +4,6 @@ "compatibilityLevel": "JAVA_8", "minVersion": "0.7.11-SNAPSHOT", "mixins": [ - "PlayerEntityMixin", "ServerPlayerEntityMixin", "ServerPlayerInteractionManagerMixin" ],