diff --git a/src/main/java/org/mvplugins/multiverse/inventories/profile/ProfileDataSource.java b/src/main/java/org/mvplugins/multiverse/inventories/profile/ProfileDataSource.java index c5ef4e59..04cf8ef5 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/profile/ProfileDataSource.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/profile/ProfileDataSource.java @@ -87,7 +87,6 @@ public sealed interface ProfileDataSource permits FlatFileProfileDataSource { * Update the file for a player's global profile. * * @param globalProfile The GlobalProfile object to update the file for. - * @return True if data successfully saved to file. */ void updateGlobalProfile(GlobalProfile globalProfile); diff --git a/src/main/java/org/mvplugins/multiverse/inventories/share/Sharables.java b/src/main/java/org/mvplugins/multiverse/inventories/share/Sharables.java index 8302273f..6a191bf4 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/share/Sharables.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/share/Sharables.java @@ -174,6 +174,31 @@ public boolean updatePlayer(Player player, PlayerProfile profile) { }).serializer(new ProfileEntry(false, DataStrings.PLAYER_OFF_HAND_ITEM), new DefaultSerializer<>(ItemStack.class)).altName("shield").build(); + /** + * Sharing Max Health. + */ + public static final Sharable MAX_HEALTH = new Sharable.Builder<>("max_hit_points", Double.class, + new SharableHandler() { + @Override + public void updateProfile(PlayerProfile profile, Player player) { + profile.set(MAX_HEALTH, getMaxHealth(player)); + } + + @Override + public boolean updatePlayer(Player player, PlayerProfile profile) { + Double value = profile.get(MAX_HEALTH); + if (value == null) { + Option.of(maxHealthAttr).map(player::getAttribute) + .peek(attr -> attr.setBaseValue(attr.getDefaultValue())); + return false; + } + Option.of(maxHealthAttr).map(player::getAttribute) + .peek(attr -> attr.setBaseValue(value)); + return true; + } + }).stringSerializer(new ProfileEntry(true, DataStrings.PLAYER_MAX_HEALTH)) + .altName("maxhealth").altName("maxhp").altName("maxhitpoints").build(); + /** * Sharing Health. */ @@ -184,9 +209,7 @@ public void updateProfile(PlayerProfile profile, Player player) { double health = player.getHealth(); // Player is dead, so health should be regained to full. if (health <= 0) { - health = Option.of(maxHealthAttr).map(player::getAttribute) - .map(AttributeInstance::getValue) - .getOrElse(PlayerStats.HEALTH); + health = getMaxHealth(player); } profile.set(HEALTH, health); } @@ -199,20 +222,31 @@ public boolean updatePlayer(Player player, PlayerProfile profile) { return false; } try { + double maxHealth = getMaxHealth(player); + // This share may handled before MAX_HEALTH. + // Thus this is needed to ensure there is no loss in health stored + if (value > maxHealth) { + Option.of(maxHealthAttr).map(player::getAttribute) + .peek(attr -> attr.setBaseValue(maxHealth)); + } player.setHealth(value); } catch (IllegalArgumentException e) { Logging.fine("Invalid value '" + value + "': " + e.getMessage()); - Option.of(maxHealthAttr).map(player::getAttribute) - .map(AttributeInstance::getValue) - .peek(player::setHealth) - .onEmpty(() -> player.setHealth(PlayerStats.HEALTH)); + player.setHealth(PlayerStats.HEALTH); return false; } return true; } + }).stringSerializer(new ProfileEntry(true, DataStrings.PLAYER_HEALTH)) .altName("health").altName("hp").altName("hitpoints").build(); + private static double getMaxHealth(Player player) { + return Option.of(maxHealthAttr).map(player::getAttribute) + .map(AttributeInstance::getValue) + .getOrElse(PlayerStats.MAX_HEALTH); + } + /** * Sharing Remaining Air. */ @@ -661,21 +695,21 @@ public boolean updatePlayer(Player player, PlayerProfile profile) { * Grouping for player health related sharables. */ public static final SharableGroup ALL_HEALTH = new SharableGroup("health", - fromSharables(HEALTH, REMAINING_AIR, MAXIMUM_AIR, FALL_DISTANCE, FIRE_TICKS)); + fromSharables(HEALTH, MAX_HEALTH, REMAINING_AIR, MAXIMUM_AIR, FALL_DISTANCE, FIRE_TICKS)); /** * Grouping for player stat related sharables not including inventory. */ public static final SharableGroup STATS = new SharableGroup("stats", - fromSharables(HEALTH, FOOD_LEVEL, SATURATION, EXHAUSTION, EXPERIENCE, TOTAL_EXPERIENCE, LEVEL, + fromSharables(HEALTH, MAX_HEALTH, FOOD_LEVEL, SATURATION, EXHAUSTION, EXPERIENCE, TOTAL_EXPERIENCE, LEVEL, REMAINING_AIR, MAXIMUM_AIR, FALL_DISTANCE, FIRE_TICKS, POTIONS)); /** * Grouping for ALL default sharables. * TODO: make this really mean all, including 3rd party. */ - public static final SharableGroup ALL_DEFAULT = new SharableGroup("all", fromSharables(HEALTH, ECONOMY, - FOOD_LEVEL, SATURATION, EXHAUSTION, EXPERIENCE, TOTAL_EXPERIENCE, LEVEL, INVENTORY, ARMOR, BED_SPAWN, + public static final SharableGroup ALL_DEFAULT = new SharableGroup("all", fromSharables(HEALTH, MAX_HEALTH, + ECONOMY, FOOD_LEVEL, SATURATION, EXHAUSTION, EXPERIENCE, TOTAL_EXPERIENCE, LEVEL, INVENTORY, ARMOR, BED_SPAWN, MAXIMUM_AIR, REMAINING_AIR, FALL_DISTANCE, FIRE_TICKS, POTIONS, LAST_LOCATION, ENDER_CHEST, OFF_HAND), "*", "everything"); diff --git a/src/main/java/org/mvplugins/multiverse/inventories/util/DataStrings.java b/src/main/java/org/mvplugins/multiverse/inventories/util/DataStrings.java index 8adeeb99..3e7be136 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/util/DataStrings.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/util/DataStrings.java @@ -57,6 +57,10 @@ public final class DataStrings { * Player profile type identifier. */ public static final String PLAYER_PROFILE_TYPE = "profileType"; + /** + * Player max health identifier. + */ + public static final String PLAYER_MAX_HEALTH = "mhp"; /** * Player health identifier. */ diff --git a/src/main/java/org/mvplugins/multiverse/inventories/util/PlayerStats.java b/src/main/java/org/mvplugins/multiverse/inventories/util/PlayerStats.java index d32a7a56..679d7db7 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/util/PlayerStats.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/util/PlayerStats.java @@ -17,6 +17,10 @@ public class PlayerStats { * Number of slots in an ender chest. */ public static final int ENDER_CHEST_SIZE = 27; + /** + * Default max health value. + */ + public static final double MAX_HEALTH = 20; /** * Default health value. */ diff --git a/src/test/java/org/mvplugins/multiverse/inventories/gameplay/GameModeChangeTest.kt b/src/test/java/org/mvplugins/multiverse/inventories/handleshare/GameModeChangeTest.kt similarity index 69% rename from src/test/java/org/mvplugins/multiverse/inventories/gameplay/GameModeChangeTest.kt rename to src/test/java/org/mvplugins/multiverse/inventories/handleshare/GameModeChangeTest.kt index 372e82c8..53a84e5a 100644 --- a/src/test/java/org/mvplugins/multiverse/inventories/gameplay/GameModeChangeTest.kt +++ b/src/test/java/org/mvplugins/multiverse/inventories/handleshare/GameModeChangeTest.kt @@ -1,4 +1,4 @@ -package org.mvplugins.multiverse.inventories.gameplay +package org.mvplugins.multiverse.inventories.handleshare import org.mvplugins.multiverse.inventories.TestWithMockBukkit diff --git a/src/test/java/org/mvplugins/multiverse/inventories/handleshare/ShareHandlingUpdaterTest.kt b/src/test/java/org/mvplugins/multiverse/inventories/handleshare/ShareHandlingUpdaterTest.kt new file mode 100644 index 00000000..7e7718bf --- /dev/null +++ b/src/test/java/org/mvplugins/multiverse/inventories/handleshare/ShareHandlingUpdaterTest.kt @@ -0,0 +1,49 @@ +package org.mvplugins.multiverse.inventories.handleshare + +import org.mockbukkit.mockbukkit.entity.PlayerMock +import org.mvplugins.multiverse.inventories.TestWithMockBukkit +import org.mvplugins.multiverse.inventories.profile.ProfileDataSource +import org.mvplugins.multiverse.inventories.profile.ProfileTypes +import org.mvplugins.multiverse.inventories.profile.container.ContainerType +import org.mvplugins.multiverse.inventories.share.Sharables +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class ShareHandlingUpdaterTest : TestWithMockBukkit() { + + private lateinit var profileDataSource: ProfileDataSource + private lateinit var player: PlayerMock + + @BeforeTest + fun setUp() { + player = server.addPlayer("benthecat10") + profileDataSource = serviceLocator.getService(ProfileDataSource::class.java).takeIf { it != null } ?: run { + throw IllegalStateException("ProfileDataSource is not available as a service") + } + } + + @Test + fun `Test updating profile`() { + player.health = 4.4 + player.maxHealth = 15.1 + + val playerProfile = profileDataSource.getPlayerData(ContainerType.WORLD, "world", ProfileTypes.SURVIVAL, player.uniqueId) + ShareHandlingUpdater.updateProfile(multiverseInventories, player, PersistingProfile(Sharables.allOf(), playerProfile)) + + assertEquals(4.4, playerProfile.get(Sharables.HEALTH)) + assertEquals(15.1, playerProfile.get(Sharables.MAX_HEALTH)) + } + + @Test + fun `Test updating player`() { + val playerProfile = profileDataSource.getPlayerData(ContainerType.WORLD, "world", ProfileTypes.SURVIVAL, player.uniqueId) + playerProfile.set(Sharables.HEALTH, 4.4) + playerProfile.set(Sharables.MAX_HEALTH, 15.1) + + ShareHandlingUpdater.updatePlayer(multiverseInventories, player, PersistingProfile(Sharables.allOf(), playerProfile)) + + assertEquals(4.4, player.health) + assertEquals(15.1, player.maxHealth) + } +} diff --git a/src/test/java/org/mvplugins/multiverse/inventories/gameplay/WorldChangeTest.kt b/src/test/java/org/mvplugins/multiverse/inventories/handleshare/WorldChangeTest.kt similarity index 97% rename from src/test/java/org/mvplugins/multiverse/inventories/gameplay/WorldChangeTest.kt rename to src/test/java/org/mvplugins/multiverse/inventories/handleshare/WorldChangeTest.kt index ad4ff9f0..6cb4b5bd 100644 --- a/src/test/java/org/mvplugins/multiverse/inventories/gameplay/WorldChangeTest.kt +++ b/src/test/java/org/mvplugins/multiverse/inventories/handleshare/WorldChangeTest.kt @@ -1,4 +1,4 @@ -package org.mvplugins.multiverse.inventories.gameplay +package org.mvplugins.multiverse.inventories.handleshare import com.dumptruckman.minecraft.util.Logging import org.bukkit.Material diff --git a/src/test/java/org/mvplugins/multiverse/inventories/gameplay/PlayerNameChangeTest.kt b/src/test/java/org/mvplugins/multiverse/inventories/profile/PlayerNameChangeTest.kt similarity index 97% rename from src/test/java/org/mvplugins/multiverse/inventories/gameplay/PlayerNameChangeTest.kt rename to src/test/java/org/mvplugins/multiverse/inventories/profile/PlayerNameChangeTest.kt index 3962b697..a34ec36a 100644 --- a/src/test/java/org/mvplugins/multiverse/inventories/gameplay/PlayerNameChangeTest.kt +++ b/src/test/java/org/mvplugins/multiverse/inventories/profile/PlayerNameChangeTest.kt @@ -1,4 +1,4 @@ -package org.mvplugins.multiverse.inventories.gameplay +package org.mvplugins.multiverse.inventories.profile import org.bukkit.Material import org.bukkit.inventory.ItemStack @@ -6,7 +6,6 @@ import org.mockbukkit.mockbukkit.entity.PlayerMock import org.mvplugins.multiverse.core.world.WorldManager import org.mvplugins.multiverse.core.world.options.CreateWorldOptions import org.mvplugins.multiverse.inventories.TestWithMockBukkit -import org.mvplugins.multiverse.inventories.profile.ProfileDataSource import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager import java.nio.file.Path import kotlin.test.BeforeTest