diff --git a/patchwork.md b/patchwork.md index 8ebdd3df1..eee0c1131 100644 --- a/patchwork.md +++ b/patchwork.md @@ -208,3 +208,22 @@ Remove superfluous imports Hah, this is embarassing ``` + +[TODO] [M3R1-01] Code has been applied, players still dont get achievments +``` +f6160bdc57b3d9850607c2c7c2ce9734b4963478 +Fix players not getting advancements when they own turtles + +When we construct a new ServerPlayerEntity (and thus TurtlePlayer), we +get the current (global) advancement state and call .setPlayer() on it. + +As grantCriterion blocks FakePlayers from getting advancements, this +means a player will no longer receive any advancements, as the "wrong" +player object is being consulted. + +As a temporary work around, we attempt to restore the previous player to +the advancement store. I'll try to upstream something into Forge to +resolve this properly. + +Fixes #564 +``` diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index f68182c20..a0ddbe9b7 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -135,7 +135,7 @@ public interface ITurtleAccess { * * @return This turtle's owner. */ - @Nonnull + @Nullable GameProfile getOwningPlayer(); /** diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index e4327fe94..c1fdc2a5d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -19,6 +19,7 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import com.google.common.base.Objects; import com.mojang.authlib.GameProfile; @@ -341,7 +342,7 @@ public class TurtleBrain implements ITurtleAccess { } } - @Nonnull + @Nullable @Override public GameProfile getOwningPlayer() { return this.m_owningPlayer; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 41911b119..c644bb643 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -33,6 +33,7 @@ import net.minecraft.inventory.Inventory; import net.minecraft.item.ItemStack; import net.minecraft.screen.NamedScreenHandlerFactory; import net.minecraft.server.world.ServerWorld; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; @@ -42,13 +43,33 @@ import net.minecraft.util.math.Vec3d; @SuppressWarnings ("EntityConstructor") public final class TurtlePlayer extends FakePlayer { private static final GameProfile DEFAULT_PROFILE = new GameProfile(UUID.fromString("0d0c4ca0-4ff1-11e4-916c-0800200c9a66"), "[ComputerCraft]"); - - private TurtlePlayer(ITurtleAccess turtle) { - super((ServerWorld) turtle.getWorld(), getProfile(turtle.getOwningPlayer())); - this.networkHandler = new FakeNetHandler(this); - this.setState(turtle); +// TODO [M3R1-01] Fix Turtle not giving player achievement for actions + private TurtlePlayer( ServerWorld world, GameProfile name ) + { + super( world, name ); } + private static TurtlePlayer create( ITurtleAccess turtle ) + { + ServerWorld world = (ServerWorld) turtle.getWorld(); + GameProfile profile = turtle.getOwningPlayer(); + + TurtlePlayer player = new TurtlePlayer( world, getProfile( profile ) ); + player.networkHandler = new FakeNetHandler( player ); + player.setState( turtle ); + + if( profile != null && profile.getId() != null ) + { + // Constructing a player overrides the "active player" variable in advancements. As fake players cannot + // get advancements, this prevents a normal player who has placed a turtle from getting advancements. + // We try to locate the "actual" player and restore them. + ServerPlayerEntity actualPlayer = world.getServer().getPlayerManager().getPlayer(player.getUuid()); + if( actualPlayer != null ) player.getAdvancementTracker().setOwner(actualPlayer); + } + + return player; + } + private static GameProfile getProfile(@Nullable GameProfile profile) { return profile != null && profile.isComplete() ? profile : DEFAULT_PROFILE; } @@ -70,14 +91,17 @@ public final class TurtlePlayer extends FakePlayer { } public static TurtlePlayer get(ITurtleAccess access) { - if (!(access instanceof TurtleBrain)) { - return new TurtlePlayer(access); - } + ServerWorld world = (ServerWorld) access.getWorld(); + if( !(access instanceof TurtleBrain) ) return create( access ); + + /*if (!(access instanceof TurtleBrain)) { + return new TurtlePlayer(world, access.getOwningPlayer()); + }*/ TurtleBrain brain = (TurtleBrain) access; TurtlePlayer player = brain.m_cachedPlayer; if (player == null || player.getGameProfile() != getProfile(access.getOwningPlayer()) || player.getEntityWorld() != access.getWorld()) { - player = brain.m_cachedPlayer = new TurtlePlayer(brain); + player = brain.m_cachedPlayer = create(brain); } else { player.setState(access); }