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
This commit is contained in:
SquidDev 2020-10-31 10:59:24 +00:00
parent 6aae4e5766
commit f6160bdc57
4 changed files with 30 additions and 9 deletions

View File

@ -9,7 +9,7 @@
} }
dependencies { dependencies {
classpath 'com.google.code.gson:gson:2.8.1' classpath 'com.google.code.gson:gson:2.8.1'
classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.179' classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.187'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
} }

View File

@ -139,7 +139,7 @@ public interface ITurtleAccess
* *
* @return This turtle's owner. * @return This turtle's owner.
*/ */
@Nonnull @Nullable
GameProfile getOwningPlayer(); GameProfile getOwningPlayer();
/** /**

View File

@ -45,6 +45,7 @@
import net.minecraftforge.items.wrapper.InvWrapper; import net.minecraftforge.items.wrapper.InvWrapper;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -598,7 +599,7 @@ public void setOwningPlayer( GameProfile profile )
m_owningPlayer = profile; m_owningPlayer = profile;
} }
@Nonnull @Nullable
@Override @Override
public GameProfile getOwningPlayer() public GameProfile getOwningPlayer()
{ {

View File

@ -17,6 +17,7 @@
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.Pose; import net.minecraft.entity.Pose;
import net.minecraft.entity.passive.horse.AbstractHorseEntity; import net.minecraft.entity.passive.horse.AbstractHorseEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.IInventory; import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -41,11 +42,30 @@ public final class TurtlePlayer extends FakePlayer
"[ComputerCraft]" "[ComputerCraft]"
); );
private TurtlePlayer( ITurtleAccess turtle ) private TurtlePlayer( ServerWorld world, GameProfile name )
{ {
super( (ServerWorld) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) ); super( world, name );
this.connection = new FakeNetHandler( this ); }
setState( turtle );
private static TurtlePlayer create( ITurtleAccess turtle )
{
ServerWorld world = (ServerWorld) turtle.getWorld();
GameProfile profile = turtle.getOwningPlayer();
TurtlePlayer player = new TurtlePlayer( world, getProfile( profile ) );
player.connection = 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().getPlayerList().getPlayerByUUID( profile.getId() );
if( actualPlayer != null ) player.getAdvancements().setPlayer( actualPlayer );
}
return player;
} }
private static GameProfile getProfile( @Nullable GameProfile profile ) private static GameProfile getProfile( @Nullable GameProfile profile )
@ -72,14 +92,14 @@ private void setState( ITurtleAccess turtle )
public static TurtlePlayer get( ITurtleAccess access ) public static TurtlePlayer get( ITurtleAccess access )
{ {
if( !(access instanceof TurtleBrain) ) return new TurtlePlayer( access ); if( !(access instanceof TurtleBrain) ) return create( access );
TurtleBrain brain = (TurtleBrain) access; TurtleBrain brain = (TurtleBrain) access;
TurtlePlayer player = brain.m_cachedPlayer; TurtlePlayer player = brain.m_cachedPlayer;
if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() ) if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() )
|| player.getEntityWorld() != access.getWorld() ) || player.getEntityWorld() != access.getWorld() )
{ {
player = brain.m_cachedPlayer = new TurtlePlayer( brain ); player = brain.m_cachedPlayer = create( brain );
} }
else else
{ {