@@ -174,6 +174,31 @@ public boolean updatePlayer(Player player, PlayerProfile profile) {
174174 }).serializer (new ProfileEntry (false , DataStrings .PLAYER_OFF_HAND_ITEM ),
175175 new DefaultSerializer <>(ItemStack .class )).altName ("shield" ).build ();
176176
177+ /**
178+ * Sharing Max Health.
179+ */
180+ public static final Sharable <Double > MAX_HEALTH = new Sharable .Builder <>("max_hit_points" , Double .class ,
181+ new SharableHandler <Double >() {
182+ @ Override
183+ public void updateProfile (PlayerProfile profile , Player player ) {
184+ profile .set (MAX_HEALTH , getMaxHealth (player ));
185+ }
186+
187+ @ Override
188+ public boolean updatePlayer (Player player , PlayerProfile profile ) {
189+ Double value = profile .get (MAX_HEALTH );
190+ if (value == null ) {
191+ Option .of (maxHealthAttr ).map (player ::getAttribute )
192+ .peek (attr -> attr .setBaseValue (attr .getDefaultValue ()));
193+ return false ;
194+ }
195+ Option .of (maxHealthAttr ).map (player ::getAttribute )
196+ .peek (attr -> attr .setBaseValue (value ));
197+ return true ;
198+ }
199+ }).stringSerializer (new ProfileEntry (true , DataStrings .PLAYER_MAX_HEALTH ))
200+ .altName ("maxhealth" ).altName ("maxhp" ).altName ("maxhitpoints" ).build ();
201+
177202 /**
178203 * Sharing Health.
179204 */
@@ -184,9 +209,7 @@ public void updateProfile(PlayerProfile profile, Player player) {
184209 double health = player .getHealth ();
185210 // Player is dead, so health should be regained to full.
186211 if (health <= 0 ) {
187- health = Option .of (maxHealthAttr ).map (player ::getAttribute )
188- .map (AttributeInstance ::getValue )
189- .getOrElse (PlayerStats .HEALTH );
212+ health = getMaxHealth (player );
190213 }
191214 profile .set (HEALTH , health );
192215 }
@@ -199,20 +222,31 @@ public boolean updatePlayer(Player player, PlayerProfile profile) {
199222 return false ;
200223 }
201224 try {
225+ double maxHealth = getMaxHealth (player );
226+ // This share may handled before MAX_HEALTH.
227+ // Thus this is needed to ensure there is no loss in health stored
228+ if (value > maxHealth ) {
229+ Option .of (maxHealthAttr ).map (player ::getAttribute )
230+ .peek (attr -> attr .setBaseValue (maxHealth ));
231+ }
202232 player .setHealth (value );
203233 } catch (IllegalArgumentException e ) {
204234 Logging .fine ("Invalid value '" + value + "': " + e .getMessage ());
205- Option .of (maxHealthAttr ).map (player ::getAttribute )
206- .map (AttributeInstance ::getValue )
207- .peek (player ::setHealth )
208- .onEmpty (() -> player .setHealth (PlayerStats .HEALTH ));
235+ player .setHealth (PlayerStats .HEALTH );
209236 return false ;
210237 }
211238 return true ;
212239 }
240+
213241 }).stringSerializer (new ProfileEntry (true , DataStrings .PLAYER_HEALTH ))
214242 .altName ("health" ).altName ("hp" ).altName ("hitpoints" ).build ();
215243
244+ private static double getMaxHealth (Player player ) {
245+ return Option .of (maxHealthAttr ).map (player ::getAttribute )
246+ .map (AttributeInstance ::getValue )
247+ .getOrElse (PlayerStats .MAX_HEALTH );
248+ }
249+
216250 /**
217251 * Sharing Remaining Air.
218252 */
@@ -661,21 +695,21 @@ public boolean updatePlayer(Player player, PlayerProfile profile) {
661695 * Grouping for player health related sharables.
662696 */
663697 public static final SharableGroup ALL_HEALTH = new SharableGroup ("health" ,
664- fromSharables (HEALTH , REMAINING_AIR , MAXIMUM_AIR , FALL_DISTANCE , FIRE_TICKS ));
698+ fromSharables (HEALTH , MAX_HEALTH , REMAINING_AIR , MAXIMUM_AIR , FALL_DISTANCE , FIRE_TICKS ));
665699
666700 /**
667701 * Grouping for player stat related sharables not including inventory.
668702 */
669703 public static final SharableGroup STATS = new SharableGroup ("stats" ,
670- fromSharables (HEALTH , FOOD_LEVEL , SATURATION , EXHAUSTION , EXPERIENCE , TOTAL_EXPERIENCE , LEVEL ,
704+ fromSharables (HEALTH , MAX_HEALTH , FOOD_LEVEL , SATURATION , EXHAUSTION , EXPERIENCE , TOTAL_EXPERIENCE , LEVEL ,
671705 REMAINING_AIR , MAXIMUM_AIR , FALL_DISTANCE , FIRE_TICKS , POTIONS ));
672706
673707 /**
674708 * Grouping for ALL default sharables.
675709 * TODO: make this really mean all, including 3rd party.
676710 */
677- public static final SharableGroup ALL_DEFAULT = new SharableGroup ("all" , fromSharables (HEALTH , ECONOMY ,
678- FOOD_LEVEL , SATURATION , EXHAUSTION , EXPERIENCE , TOTAL_EXPERIENCE , LEVEL , INVENTORY , ARMOR , BED_SPAWN ,
711+ public static final SharableGroup ALL_DEFAULT = new SharableGroup ("all" , fromSharables (HEALTH , MAX_HEALTH ,
712+ ECONOMY , FOOD_LEVEL , SATURATION , EXHAUSTION , EXPERIENCE , TOTAL_EXPERIENCE , LEVEL , INVENTORY , ARMOR , BED_SPAWN ,
679713 MAXIMUM_AIR , REMAINING_AIR , FALL_DISTANCE , FIRE_TICKS , POTIONS , LAST_LOCATION , ENDER_CHEST , OFF_HAND ),
680714 "*" , "everything" );
681715
0 commit comments