diff --git a/SpongeAPI b/SpongeAPI index 8cc54c797e0..b51e2a0d89b 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 8cc54c797e0979c8070109889996b98637db505d +Subproject commit b51e2a0d89bd3c79681b4e8261e426a8048d0304 diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/scores/ObjectiveAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/scores/ObjectiveAccessor.java deleted file mode 100644 index b15342b682d..00000000000 --- a/src/accessors/java/org/spongepowered/common/accessor/world/scores/ObjectiveAccessor.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.accessor.world.scores; - -import net.minecraft.world.scores.Objective; -import net.minecraft.world.scores.Scoreboard; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(Objective.class) -public interface ObjectiveAccessor { - - @Accessor("scoreboard") Scoreboard accessor$scoreboard(); - -} diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/scores/ScoreAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/scores/ScoreAccessor.java deleted file mode 100644 index ba0b8b7e91e..00000000000 --- a/src/accessors/java/org/spongepowered/common/accessor/world/scores/ScoreAccessor.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.accessor.world.scores; - -import net.minecraft.world.scores.Objective; -import net.minecraft.world.scores.Score; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(Score.class) -public interface ScoreAccessor { - - @Accessor("objective") Objective accessor$objective(); - - @Accessor("count") int accessor$count(); - - @Accessor("count") void accessor$count(final int count); - - @Accessor("forceUpdate") boolean accessor$forceUpdate(); - - @Accessor("forceUpdate") void accessor$forceUpdate(final boolean forceUpdate); - -} diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/scores/ScoreboardAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/scores/ScoreboardAccessor.java index 3b3cad9d0c2..122dfa2ca10 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/scores/ScoreboardAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/scores/ScoreboardAccessor.java @@ -24,10 +24,12 @@ */ package org.spongepowered.common.accessor.world.scores; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; import net.minecraft.world.scores.DisplaySlot; import net.minecraft.world.scores.Objective; +import net.minecraft.world.scores.PlayerScores; import net.minecraft.world.scores.PlayerTeam; -import net.minecraft.world.scores.Score; import net.minecraft.world.scores.Scoreboard; import net.minecraft.world.scores.criteria.ObjectiveCriteria; import org.spongepowered.asm.mixin.Mixin; @@ -39,16 +41,16 @@ @Mixin(Scoreboard.class) public interface ScoreboardAccessor { - @Accessor("objectivesByName") Map accessor$objectivesByName(); + @Accessor("objectivesByName") Object2ObjectMap accessor$objectivesByName(); - @Accessor("objectivesByCriteria") Map> accessor$objectivesByCriteria(); + @Accessor("objectivesByCriteria") Reference2ObjectMap> accessor$objectivesByCriteria(); - @Accessor("playerScores") Map> accessor$playerScores(); + @Accessor("playerScores") Map accessor$playerScores(); @Accessor("displayObjectives") Map accessor$displayObjectives(); - @Accessor("teamsByName") Map accessor$teamsByName(); + @Accessor("teamsByName") Object2ObjectMap accessor$teamsByName(); - @Accessor("teamsByPlayer") Map accessor$teamsByPlayer(); + @Accessor("teamsByPlayer") Object2ObjectMap accessor$teamsByPlayer(); } diff --git a/src/accessors/resources/mixins.sponge.accessors.json b/src/accessors/resources/mixins.sponge.accessors.json index f5a50601004..e78c9b3c410 100644 --- a/src/accessors/resources/mixins.sponge.accessors.json +++ b/src/accessors/resources/mixins.sponge.accessors.json @@ -182,9 +182,7 @@ "world.level.storage.LevelStorageSource_LevelStorageAccessAccessor", "world.level.storage.PlayerDataStorageAccessor", "world.phys.AABBAccessor", - "world.scores.ObjectiveAccessor", "world.scores.PlayerTeamAccessor", - "world.scores.ScoreAccessor", "world.entity.decoration.PaintingAccessor", "world.scores.ScoreboardAccessor", "world.level.biome.MobSpawnSettingsAccessor", diff --git a/src/main/java/org/spongepowered/common/bridge/world/scores/ScoreBridge.java b/src/main/java/org/spongepowered/common/bridge/world/scores/ScoreBridge.java deleted file mode 100644 index 5cefaf862e8..00000000000 --- a/src/main/java/org/spongepowered/common/bridge/world/scores/ScoreBridge.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.bridge.world.scores; - -import org.spongepowered.common.scoreboard.SpongeScore; - -public interface ScoreBridge { - - void bridge$setSpongeScore(SpongeScore score); - - SpongeScore bridge$getSpongeScore(); -} diff --git a/src/main/java/org/spongepowered/common/scoreboard/SpongeObjective.java b/src/main/java/org/spongepowered/common/scoreboard/SpongeObjective.java index c2f3a5db4c0..f4cccb76709 100644 --- a/src/main/java/org/spongepowered/common/scoreboard/SpongeObjective.java +++ b/src/main/java/org/spongepowered/common/scoreboard/SpongeObjective.java @@ -27,6 +27,9 @@ import com.google.common.collect.Maps; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.minecraft.network.chat.numbers.NumberFormat; +import net.minecraft.world.scores.ScoreAccess; +import net.minecraft.world.scores.ScoreHolder; import net.minecraft.world.scores.criteria.ObjectiveCriteria; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.scoreboard.Score; @@ -35,8 +38,6 @@ import org.spongepowered.api.scoreboard.objective.Objective; import org.spongepowered.api.scoreboard.objective.displaymode.ObjectiveDisplayMode; import org.spongepowered.api.scoreboard.objective.displaymode.ObjectiveDisplayModes; -import org.spongepowered.common.accessor.world.scores.ObjectiveAccessor; -import org.spongepowered.common.accessor.world.scores.ScoreAccessor; import org.spongepowered.common.accessor.world.scores.ScoreboardAccessor; import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.bridge.world.scores.ObjectiveBridge; @@ -55,11 +56,13 @@ public final class SpongeObjective implements Objective { private final String name; private final Criterion criterion; - private final Map scores = new HashMap<>(); + private final Map scores = new HashMap<>(); private final Map objectives; private Component displayName; private ObjectiveDisplayMode displayMode; + private boolean displayAutoUpdate; // TODO make this do stuff + private NumberFormat numberFormat; // TODO make this do stuff public SpongeObjective(final String name, final Criterion criterion) { this.name = name; @@ -111,36 +114,40 @@ public void storeDisplayMode(final ObjectiveDisplayMode displayMode) { } @Override - public Map scores() { + public Map scores() { return new HashMap<>(this.scores); } @Override - public boolean hasScore(final Component name) { + public boolean hasScore(final String name) { return this.scores.containsKey(name); } @Override public void addScore(final Score score) throws IllegalArgumentException { if (this.scores.containsKey(score.name())) { - throw new IllegalArgumentException(String.format("A score with the name %s already exists!", - LegacyComponentSerializer.legacySection().serialize(score.name()))); + throw new IllegalArgumentException(String.format("A score with the name %s already exists!", score.name())); } this.scores.put(score.name(), score); final SpongeScore spongeScore = (SpongeScore) score; - for (final net.minecraft.world.scores.Objective objective: this.objectives.values()) { - this.addScoreToScoreboard(((ObjectiveAccessor) objective).accessor$scoreboard(), spongeScore.getScoreFor(objective)); + for (final net.minecraft.world.scores.Scoreboard scoreboard : this.objectives.keySet()) { + final net.minecraft.world.scores.Objective mcObjective = scoreboard.getObjective(this.name); + for (final ScoreHolder holder : scoreboard.getTrackedPlayers()) { + final ScoreAccess accessor = scoreboard.getOrCreatePlayerScore(holder, mcObjective); + spongeScore.registerAndUpdate(mcObjective, accessor); + // TODO set values + } } } @Override - public Optional findScore(final Component name) { + public Optional findScore(final String name) { return Optional.ofNullable(this.scores.get(name)); } @Override - public Score findOrCreateScore(final Component name) { + public Score findOrCreateScore(final String name) { if (this.scores.containsKey(name)) { return this.scores.get(name); } @@ -152,33 +159,33 @@ public Score findOrCreateScore(final Component name) { @Override public boolean removeScore(final Score spongeScore) { - final String name = ((SpongeScore) spongeScore).legacyName; + final ScoreHolder holder = ((SpongeScore) spongeScore).holder; if (!this.scores.containsKey(spongeScore.name())) { return false; } for (final net.minecraft.world.scores.Objective objective: this.objectives.values()) { - final net.minecraft.world.scores.Scoreboard scoreboard = ((ObjectiveAccessor) objective).accessor$scoreboard(); + final net.minecraft.world.scores.Scoreboard scoreboard = objective.getScoreboard(); - final Map map = ((ScoreboardAccessor) scoreboard).accessor$playerScores().get(name); + final Map map = ((ScoreboardAccessor) scoreboard).accessor$playerScores().get(holder); if (map != null) { final net.minecraft.world.scores.Score score = (net.minecraft.world.scores.Score) map.remove(objective); if (map.size() < 1) { - final Map map1 = ((ScoreboardAccessor) scoreboard).accessor$playerScores().remove(name); + final Map map1 = ((ScoreboardAccessor) scoreboard).accessor$playerScores().remove(holder); if (map1 != null) { - scoreboard.onPlayerRemoved(name); + scoreboard.onPlayerRemoved(holder); } } else if (score != null) { - scoreboard.onPlayerScoreRemoved(name, objective); + scoreboard.onPlayerScoreRemoved(holder, objective); } } - ((SpongeScore) spongeScore).removeScoreFor(objective); + ((SpongeScore) spongeScore).unregister(objective); } this.scores.remove(spongeScore.name()); @@ -186,7 +193,7 @@ public boolean removeScore(final Score spongeScore) { } @Override - public boolean removeScore(final Component name) { + public boolean removeScore(final String name) { final Optional score = this.findScore(name); return score.filter(this::removeScore).isPresent(); } @@ -211,6 +218,12 @@ private void updateDisplayName() { public void updateScores(final net.minecraft.world.scores.Scoreboard scoreboard) { final net.minecraft.world.scores.Objective objective = this.getObjectiveFor(scoreboard); + for (final ScoreHolder holder : scoreboard.getTrackedPlayers()) { + // TODO probably need to go through PlayerScores instead + final ScoreAccess access = scoreboard.getOrCreatePlayerScore(holder, objective); + + } + for (final Score score: this.scores().values()) { final SpongeScore spongeScore = (SpongeScore) score; this.addScoreToScoreboard(scoreboard, spongeScore.getScoreFor(objective)); @@ -234,7 +247,7 @@ public net.minecraft.world.scores.Objective getObjectiveFor(final net.minecraft. return this.objectives.get(scoreboard); } final net.minecraft.world.scores.Objective objective = new net.minecraft.world.scores.Objective(scoreboard, this.name, (ObjectiveCriteria) this.criterion, - SpongeAdventure.asVanilla(this.displayName), (ObjectiveCriteria.RenderType) (Object) this.displayMode); + SpongeAdventure.asVanilla(this.displayName), (ObjectiveCriteria.RenderType) (Object) this.displayMode, this.displayAutoUpdate, this.numberFormat); ((ObjectiveBridge) objective).bridge$setSpongeObjective(this); this.objectives.put(scoreboard, objective); return objective; @@ -250,6 +263,22 @@ public Collection getObjectives() { return this.objectives.values(); } + public boolean displayAutoUpdate() { + return displayAutoUpdate; + } + + public NumberFormat numberFormat() { + return numberFormat; + } + + public void setDisplayAutoUpdate(final boolean displayAutoUpdate) { + this.displayAutoUpdate = displayAutoUpdate; + } + + public void setNumberFormat(final NumberFormat numberFormat) { + this.numberFormat = numberFormat; + } + public static final class Builder implements Objective.Builder { private static final int MAX_NAME_LENGTH = 16; diff --git a/src/main/java/org/spongepowered/common/scoreboard/SpongeScore.java b/src/main/java/org/spongepowered/common/scoreboard/SpongeScore.java index 6ce230cd07c..bd3341aca3d 100644 --- a/src/main/java/org/spongepowered/common/scoreboard/SpongeScore.java +++ b/src/main/java/org/spongepowered/common/scoreboard/SpongeScore.java @@ -25,39 +25,41 @@ package org.spongepowered.common.scoreboard; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.minecraft.network.chat.numbers.NumberFormat; +import net.minecraft.world.scores.ScoreAccess; +import net.minecraft.world.scores.ScoreHolder; import org.spongepowered.api.scoreboard.Score; import org.spongepowered.api.scoreboard.objective.Objective; -import org.spongepowered.common.accessor.world.scores.ObjectiveAccessor; -import org.spongepowered.common.accessor.world.scores.ScoreAccessor; +import org.spongepowered.common.adventure.SpongeAdventure; import org.spongepowered.common.bridge.world.scores.ObjectiveBridge; -import org.spongepowered.common.bridge.world.scores.ScoreBridge; -import org.spongepowered.common.util.Constants; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; +import java.util.Optional; import java.util.Set; +import javax.annotation.Nullable; + public final class SpongeScore implements Score { - private final Component name; - public String legacyName; + private final String name; + public ScoreHolder holder; private int score; private boolean locked; - private final Map scores = new HashMap<>(); + @Nullable + private net.minecraft.network.chat.Component display; + @Nullable + private NumberFormat numberFormat; + + private Set objectives = new HashSet<>(); - public SpongeScore(final Component name) { + public SpongeScore(final String name) { this.name = name; - this.legacyName = LegacyComponentSerializer.legacySection().serialize(name); - if (this.legacyName.length() > Constants.Scoreboards.SCORE_NAME_LENGTH) { - throw new IllegalArgumentException(String.format("The score name %s is too long! It must be at most %s characters.", this.legacyName, Constants.Scoreboards.SCORE_NAME_LENGTH)); - } + this.holder = ScoreHolder.forNameOnly(name); } @Override - public Component name() { + public String name() { return this.name; } @@ -80,17 +82,26 @@ public boolean isLocked() { @Override public void setLocked(final boolean locked) { this.locked = locked; + this.updateScore(); + } + + @Override + public void setDisplay(final Component display) { + this.display = SpongeAdventure.asVanilla(display); + this.updateScore(); + } + + @Override + public Optional display() { + return Optional.ofNullable(SpongeAdventure.asAdventure(this.display)); } private void updateScore() { - for (final net.minecraft.world.scores.Score score : this.scores.values()) { - final int j = ((ScoreAccessor) score).accessor$count(); - ((ScoreAccessor) score).accessor$count(this.score); - - if (j != this.score || ((ScoreAccessor) score).accessor$forceUpdate()) - { - ((ScoreAccessor) score).accessor$forceUpdate(false); - score.getScoreboard().onScoreChanged(score); + for (final net.minecraft.world.scores.Objective objective : this.objectives) { + var scoreboard = objective.getScoreboard(); + for (final ScoreHolder holder : scoreboard.getTrackedPlayers()) { + final ScoreAccess access = scoreboard.getOrCreatePlayerScore(holder, objective); + this.registerAndUpdate(objective, access); } } } @@ -98,33 +109,83 @@ private void updateScore() { @Override public Set objectives() { final Set objectives = new HashSet<>(); - for (final net.minecraft.world.scores.Objective objective: this.scores.keySet()) { + for (final net.minecraft.world.scores.Objective objective: this.objectives) { objectives.add(((ObjectiveBridge) objective).bridge$getSpongeObjective()); } return objectives; } - @SuppressWarnings("ConstantConditions") - public net.minecraft.world.scores.Score getScoreFor(final net.minecraft.world.scores.Objective objective) { - if (this.scores.containsKey(objective)) { - return this.scores.get(objective); + public void registerAndUpdate(net.minecraft.world.scores.Objective objective, final ScoreAccess accessor) { + this.objectives.add(objective); + accessor.set(this.score); + accessor.display(this.display); + if (this.locked) { + accessor.lock(); + } else { + accessor.unlock(); } - final net.minecraft.world.scores.Score score = new net.minecraft.world.scores.Score(((ObjectiveAccessor) objective).accessor$scoreboard(), objective, this.legacyName); + } - // We deliberately set the fields here instead of using the methods. - // Since a new score is being created here, we want to avoid - // sending packets until everything is in the proper state. - ((ScoreAccessor) score).accessor$count(this.score); + public void unregister(net.minecraft.world.scores.Objective objective) { + this.objectives.remove(objective); + } - ((ScoreBridge) score).bridge$setSpongeScore(this); - this.scores.put(objective, score); + public record SpongeScoreAccess(ScoreHolder holder, net.minecraft.world.scores.Objective objective, ScoreAccess access) implements ScoreAccess { - return score; - } + @Override + public int get() { + return this.access.get(); + } + + @Override + public boolean locked() { + return this.access.locked(); + } + + @Nullable @Override + public net.minecraft.network.chat.Component display() { + return this.access.display(); + } + + @Override + public void set(final int var1) { + final SpongeObjective spongeObjective = ((ObjectiveBridge) objective).bridge$getSpongeObjective(); + // TODO maybe stackoverflow issue + spongeObjective.findScore(holder.getScoreboardName()).ifPresent(spongeScore -> spongeScore.setScore(var1)); + + this.access.set(var1); + } + + @Override + public void unlock() { + final SpongeObjective spongeObjective = ((ObjectiveBridge) objective).bridge$getSpongeObjective(); + // TODO maybe stackoverflow issue + spongeObjective.findScore(holder.getScoreboardName()).ifPresent(spongeScore -> spongeScore.setLocked(false)); + + this.access.unlock(); + } + + @Override + public void lock() { + final SpongeObjective spongeObjective = ((ObjectiveBridge) objective).bridge$getSpongeObjective(); + // TODO maybe stackoverflow issue + spongeObjective.findScore(holder.getScoreboardName()).ifPresent(spongeScore -> spongeScore.setLocked(true)); + + this.access.lock(); + } + + @Override + public void display(@Nullable final net.minecraft.network.chat.Component var1) { + final SpongeObjective spongeObjective = ((ObjectiveBridge) objective).bridge$getSpongeObjective(); + // TODO maybe stackoverflow issue + spongeObjective.findScore(holder.getScoreboardName()).ifPresent(spongeScore -> spongeScore.setDisplay(SpongeAdventure.asAdventure(var1))); + + this.access.display(var1); + } - public void removeScoreFor(final net.minecraft.world.scores.Objective objective) { - if (this.scores.remove(objective) == null) { - throw new IllegalStateException("Attempting to remove an score without an entry!"); + @Override + public void numberFormatOverride(@Nullable final NumberFormat var1) { + this.access.numberFormatOverride(var1); } } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/ServerScoreboardMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/ServerScoreboardMixin.java index 85cccaad434..56f0436ca53 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/ServerScoreboardMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/ServerScoreboardMixin.java @@ -24,8 +24,10 @@ */ package org.spongepowered.common.mixin.core.server; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.minecraft.network.chat.numbers.NumberFormat; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket; import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket; @@ -53,6 +55,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.common.SpongeCommon; +import org.spongepowered.common.accessor.world.scores.ObjectiveAccessor; import org.spongepowered.common.accessor.world.scores.PlayerTeamAccessor; import org.spongepowered.common.accessor.world.scores.ScoreboardAccessor; import org.spongepowered.common.adventure.SpongeAdventure; @@ -99,11 +102,24 @@ public abstract class ServerScoreboardMixin extends Scoreboard implements Server @Override public void bridge$addObjective(final Objective objective) { + if (objective instanceof SpongeObjective so) { + var mcObjective = this.addObjective(objective.name(), + (ObjectiveCriteria) objective.criterion(), + SpongeAdventure.asVanilla(objective.displayName()), + (ObjectiveCriteria.RenderType) (Object) objective.displayMode(), + so.displayAutoUpdate(), + so.numberFormat()); + ((ObjectiveBridge) mcObjective).bridge$setSpongeObjective(so); + } + final net.minecraft.world.scores.Objective nmsObjective = this.getObjective(objective.name()); if (nmsObjective != null) { throw new IllegalArgumentException(String.format("An objective with the name '%s' already exists!", objective.name())); } + + + final net.minecraft.world.scores.Objective scoreObjective = ((SpongeObjective) objective).getObjectiveFor(this); List objectives = ((ScoreboardAccessor) this).accessor$objectivesByCriteria().get(objective.criterion()); if (objectives == null) { @@ -118,6 +134,28 @@ public abstract class ServerScoreboardMixin extends Scoreboard implements Server ((SpongeObjective) objective).updateScores(this); } + @Override + public net.minecraft.world.scores.Objective addObjective( + final String name, + final ObjectiveCriteria criteria, + final net.minecraft.network.chat.Component text, + final ObjectiveCriteria.RenderType type, + final boolean displayAutoUpdate, + @org.jetbrains.annotations.Nullable final NumberFormat numberFormat) { + final SpongeObjective objective = new SpongeObjective(name, (Criterion) criteria); + objective.setDisplayMode((ObjectiveDisplayMode) (Object) type); + objective.setDisplayName(SpongeAdventure.asAdventure(text)); + objective.setDisplayAutoUpdate(displayAutoUpdate); + objective.setNumberFormat(numberFormat); + + // Redirect to our registration + this.bridge$addObjective(objective); + + // Return registered objective + return this.getObjective(objective.name()); + } + + @Override public Optional bridge$getObjective(final String name) { final net.minecraft.world.scores.Objective objective = this.getObjective(name); @@ -218,12 +256,13 @@ public abstract class ServerScoreboardMixin extends Scoreboard implements Server player.connection.send(new ClientboundSetDisplayObjectivePacket(displaySlot, objective)); } }); - for (final Score score : this.getPlayerScores(objective)) { + for (final var score : this.listPlayerScores(objective)) { final ClientboundSetScorePacket packetIn = new ClientboundSetScorePacket( - Method.CHANGE, - score.getObjective().getName(), - score.getOwner(), - score.getScore()); + score.owner(), + objective.getName(), + score.value(), + score.display(), + score.numberFormatOverride()); player.connection.send(packetIn); } } @@ -238,16 +277,6 @@ public abstract class ServerScoreboardMixin extends Scoreboard implements Server } } - @Override - public net.minecraft.world.scores.Objective addObjective(final String name, final ObjectiveCriteria criteria, final net.minecraft.network.chat.Component text, - final ObjectiveCriteria.RenderType type) { - final SpongeObjective objective = new SpongeObjective(name, (Criterion) criteria); - objective.setDisplayMode((ObjectiveDisplayMode) (Object) type); - objective.setDisplayName(SpongeAdventure.asAdventure(text)); - ((org.spongepowered.api.scoreboard.Scoreboard) this).addObjective(objective); - return objective.getObjectiveFor(this); - } - @Override public void removeObjective(final net.minecraft.world.scores.Objective objective) { this.bridge$removeObjective(((ObjectiveBridge) objective).bridge$getSpongeObjective()); @@ -259,12 +288,6 @@ public void removePlayerTeam(final PlayerTeam team) { ((PlayerTeamAccessor) team).accessor$scoreboard(null); } - @Override - public Score getOrCreatePlayerScore(final String name, final net.minecraft.world.scores.Objective objective) { - return ((SpongeScore) ((ObjectiveBridge) objective).bridge$getSpongeObjective().findOrCreateScore(LegacyComponentSerializer.legacySection().deserialize(name))) - .getScoreFor(objective); - } - @Override public void resetPlayerScore(final String name, final net.minecraft.world.scores.Objective objective) { final LegacyComponentSerializer lcs = LegacyComponentSerializer.legacySection(); diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/scores/ScoreMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/scores/ScoreMixin.java deleted file mode 100644 index 8500da22cd6..00000000000 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/scores/ScoreMixin.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is part of Sponge, licensed under the MIT License (MIT). - * - * Copyright (c) SpongePowered - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.spongepowered.common.mixin.core.world.scores; - -import net.minecraft.world.scores.Score; -import net.minecraft.world.scores.Scoreboard; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.common.SpongeCommon; -import org.spongepowered.common.bridge.world.scores.ScoreBridge; -import org.spongepowered.common.bridge.world.scores.ScoreboardBridge; -import org.spongepowered.common.scoreboard.SpongeScore; - -@Mixin(Score.class) -public abstract class ScoreMixin implements ScoreBridge { - - @Shadow @Final private Scoreboard scoreboard; - - @Nullable private SpongeScore impl$spongeScore; - - @Override - public SpongeScore bridge$getSpongeScore() { - return this.impl$spongeScore; - } - - @Override - public void bridge$setSpongeScore(final SpongeScore score) { - this.impl$spongeScore = score; - } - - @Inject(method = "setScore", at = @At("HEAD"), cancellable = true) - private void impl$sUpdateSpongeScore(final int points, final CallbackInfo ci) { - if (this.scoreboard != null && ((ScoreboardBridge) this.scoreboard).bridge$isClient()) { - return; // Let the normal logic take over. - } - if (this.impl$spongeScore == null) { - SpongeCommon.logger().warn("Returning score because null score!"); - ci.cancel(); - return; - } - this.impl$spongeScore.setScore(points); - ci.cancel(); - } - - @Inject(method = "setLocked", at = @At("HEAD"), cancellable = true) - private void impl$sUpdateSpongeScoreLocked(final boolean locked, final CallbackInfo ci) { - if (this.scoreboard != null && ((ScoreboardBridge) this.scoreboard).bridge$isClient()) { - return; // Let the normal logic take over. - } - if (this.impl$spongeScore == null) { - SpongeCommon.logger().warn("Returning score because null score!"); - ci.cancel(); - return; - } - this.impl$spongeScore.setLocked(locked); - ci.cancel(); - } - -} diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/scores/ScoreboardMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/scores/ScoreboardMixin.java index 5d3a4ebe05d..fad59344f2a 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/scores/ScoreboardMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/scores/ScoreboardMixin.java @@ -25,12 +25,17 @@ package org.spongepowered.common.mixin.core.world.scores; import net.minecraft.server.ServerScoreboard; +import net.minecraft.world.scores.Objective; +import net.minecraft.world.scores.ScoreAccess; +import net.minecraft.world.scores.ScoreHolder; import net.minecraft.world.scores.Scoreboard; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.bridge.world.scores.ScoreboardBridge; +import org.spongepowered.common.scoreboard.SpongeScore; @SuppressWarnings("ConstantConditions") @Mixin(Scoreboard.class) @@ -47,4 +52,10 @@ public abstract class ScoreboardMixin implements ScoreboardBridge { private void impl$setIsClient(final CallbackInfo ci) { this.impl$isClient = !((Scoreboard) (Object) this instanceof ServerScoreboard); } + + @Inject(method = "getOrCreatePlayerScore(Lnet/minecraft/world/scores/ScoreHolder;Lnet/minecraft/world/scores/Objective;Z)Lnet/minecraft/world/scores/ScoreAccess;", at = @At("RETURN")) + private void onGetScoreAccess(final ScoreHolder $$0, final Objective $$1, final boolean $$2, final CallbackInfoReturnable cir) { + // wrap to intercept setting data + cir.setReturnValue(new SpongeScore.SpongeScoreAccess($$0, $$1, cir.getReturnValue())); + } } diff --git a/src/mixins/resources/mixins.sponge.core.json b/src/mixins/resources/mixins.sponge.core.json index cf1c4235481..a00bd2744b8 100644 --- a/src/mixins/resources/mixins.sponge.core.json +++ b/src/mixins/resources/mixins.sponge.core.json @@ -238,7 +238,6 @@ "world.scores.ObjectiveMixin", "world.scores.PlayerTeamMixin", "world.scores.ScoreboardMixin", - "world.scores.ScoreMixin", "world.ticks.LevelTicksMixin", "world.ticks.ScheduledTickMixin", "world.item.crafting.SmithingTransformRecipeMixin",