diff --git a/patchwork-fake-players/build.gradle b/patchwork-fake-players/build.gradle new file mode 100644 index 00000000..e18ff318 --- /dev/null +++ b/patchwork-fake-players/build.gradle @@ -0,0 +1,6 @@ +archivesBaseName = "patchwork-fake-players" +version = getSubprojectVersion(project, "0.1.0") + +dependencies { + implementation project(path: ':patchwork-api-base', configuration: 'dev') +} diff --git a/patchwork-fake-players/src/main/java/net/minecraftforge/common/util/FakePlayer.java b/patchwork-fake-players/src/main/java/net/minecraftforge/common/util/FakePlayer.java new file mode 100644 index 00000000..2408f660 --- /dev/null +++ b/patchwork-fake-players/src/main/java/net/minecraftforge/common/util/FakePlayer.java @@ -0,0 +1,81 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.util; + +import com.mojang.authlib.GameProfile; + +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.c2s.play.ClientSettingsC2SPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.network.ServerPlayerInteractionManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.stat.Stat; +import net.minecraft.text.Text; +import net.minecraft.util.math.Vec3d; + +// Preliminary, simple Fake Player class +public class FakePlayer extends ServerPlayerEntity { + public FakePlayer(ServerWorld world, GameProfile profile) { + super(world.getServer(), world, profile, new ServerPlayerInteractionManager(world)); + } + + @Override + public Vec3d getPosVector() { + return new Vec3d(0, 0, 0); + } + + @Override + public void addChatMessage(Text text, boolean actionBar) { + } + + @Override + public void sendMessage(Text component) { + } + + @Override + public void increaseStat(Stat stat, int num) { + } + + @Override + public boolean isInvulnerableTo(DamageSource source) { + return true; + } + + @Override + public boolean shouldDamagePlayer(PlayerEntity player) { + return false; + } + + @Override + public void onDeath(DamageSource source) { + } + + @Override + public void tick() { + } + + @Override + public void setClientSettings(ClientSettingsC2SPacket packet) { + } + + // Forge also has this here: + // @Override @Nullable public MinecraftServer getServer() { return ServerLifecycleHooks.getCurrentServer(); } +} diff --git a/patchwork-fake-players/src/main/java/net/minecraftforge/common/util/FakePlayerFactory.java b/patchwork-fake-players/src/main/java/net/minecraftforge/common/util/FakePlayerFactory.java new file mode 100644 index 00000000..2403c7c2 --- /dev/null +++ b/patchwork-fake-players/src/main/java/net/minecraftforge/common/util/FakePlayerFactory.java @@ -0,0 +1,70 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.util; + +import java.lang.ref.WeakReference; +import java.util.Map; +import java.util.UUID; + +import com.google.common.collect.Maps; +import com.mojang.authlib.GameProfile; + +import net.minecraft.server.world.ServerWorld; + +public class FakePlayerFactory { + private static final GameProfile MINECRAFT = new GameProfile(UUID.fromString("41C82C87-7AfB-4024-BA57-13D2C99CAE77"), "[Minecraft]"); + // Map of all active fake player profiles to their entities + private static final Map fakePlayers = Maps.newHashMap(); + private static WeakReference MINECRAFT_PLAYER = null; + + public static FakePlayer getMinecraft(ServerWorld world) { + FakePlayer ret = MINECRAFT_PLAYER != null ? MINECRAFT_PLAYER.get() : null; + + if (ret == null) { + ret = FakePlayerFactory.get(world, MINECRAFT); + MINECRAFT_PLAYER = new WeakReference<>(ret); + } + + return ret; + } + + /** + * Get a fake player with a given profile. + * Mods should either hold weak references to the return value, or listen for a + * WorldEvent.Unload and kill all references to prevent worlds staying in memory. + */ + public static FakePlayer get(ServerWorld world, GameProfile profile) { + return fakePlayers.computeIfAbsent(profile, it -> new FakePlayer(world, it)); + } + + /** + * Used internally to clean up fake players when worlds are unloaded on server stop. + */ + public static void unloadWorld(ServerWorld world) { + fakePlayers.entrySet().removeIf(entry -> entry.getValue().world == world); + + // This shouldn't be strictly necessary, but let's be aggressive. + FakePlayer mc = MINECRAFT_PLAYER != null ? MINECRAFT_PLAYER.get() : null; + + if (mc != null && mc.world == world) { + MINECRAFT_PLAYER = null; + } + } +} diff --git a/patchwork-fake-players/src/main/java/net/patchworkmc/impl/fakeplayers/PatchworkFakePlayers.java b/patchwork-fake-players/src/main/java/net/patchworkmc/impl/fakeplayers/PatchworkFakePlayers.java new file mode 100644 index 00000000..1e9db443 --- /dev/null +++ b/patchwork-fake-players/src/main/java/net/patchworkmc/impl/fakeplayers/PatchworkFakePlayers.java @@ -0,0 +1,38 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.patchworkmc.impl.fakeplayers; + +import net.minecraftforge.common.util.FakePlayerFactory; + +import net.minecraft.server.world.ServerWorld; + +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.api.ModInitializer; + +public class PatchworkFakePlayers implements ModInitializer { + @Override + public void onInitialize() { + ServerLifecycleEvents.SERVER_STOPPED.register(server -> { + for (ServerWorld world : server.getWorlds()) { + FakePlayerFactory.unloadWorld(world); + } + }); + } +} diff --git a/patchwork-fake-players/src/main/java/net/patchworkmc/mixin/fakeplayers/MixinPlayerAdvancementTracker.java b/patchwork-fake-players/src/main/java/net/patchworkmc/mixin/fakeplayers/MixinPlayerAdvancementTracker.java new file mode 100644 index 00000000..3a101a98 --- /dev/null +++ b/patchwork-fake-players/src/main/java/net/patchworkmc/mixin/fakeplayers/MixinPlayerAdvancementTracker.java @@ -0,0 +1,44 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.patchworkmc.mixin.fakeplayers; + +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.CallbackInfoReturnable; +import net.minecraftforge.common.util.FakePlayer; + +import net.minecraft.advancement.Advancement; +import net.minecraft.advancement.PlayerAdvancementTracker; +import net.minecraft.server.network.ServerPlayerEntity; + +@Mixin(PlayerAdvancementTracker.class) +public class MixinPlayerAdvancementTracker { + @Shadow + private ServerPlayerEntity owner; + + @Inject(method = "grantCriterion", at = @At("HEAD"), cancellable = true) + private void onGrantCriterion(Advancement advancement, String criterion, CallbackInfoReturnable cir) { + if (owner instanceof FakePlayer) { + cir.setReturnValue(false); + } + } +} diff --git a/patchwork-fake-players/src/main/resources/assets/patchwork-extensions/icon.png b/patchwork-fake-players/src/main/resources/assets/patchwork-extensions/icon.png new file mode 100644 index 00000000..de75d2fb Binary files /dev/null and b/patchwork-fake-players/src/main/resources/assets/patchwork-extensions/icon.png differ diff --git a/patchwork-fake-players/src/main/resources/fabric.mod.json b/patchwork-fake-players/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..a544c018 --- /dev/null +++ b/patchwork-fake-players/src/main/resources/fabric.mod.json @@ -0,0 +1,29 @@ +{ + "schemaVersion": 1, + "id": "patchwork-fake-players", + "version": "${version}", + "name": "Patchwork Fake Players", + "description": "Implements the Minecraft Forge fake players API", + "authors": [ + "PatchworkMC" + ], + "license": "LGPL-2.1-only", + "icon": "assets/patchwork-fake-players/icon.png", + "environment": "*", + "depends": { + "patchwork-api-base": "*", + "fabric": "*" + }, + "mixins": [ + "patchwork-fake-players.mixins.json" + ], + "entrypoints": { + "main": [ + "net.patchworkmc.impl.fakeplayers.PatchworkFakePlayers" + ] + }, + "custom": { + "modmenu:api": true, + "modmenu:parent": "patchwork" + } +} diff --git a/patchwork-fake-players/src/main/resources/patchwork-extensions.mixins.json b/patchwork-fake-players/src/main/resources/patchwork-extensions.mixins.json new file mode 100644 index 00000000..27671806 --- /dev/null +++ b/patchwork-fake-players/src/main/resources/patchwork-extensions.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "net.patchworkmc.mixin.fakeplayers", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "MixinPlayerAdvancementTracker", + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/settings.gradle b/settings.gradle index 3da056d2..f6ab08d4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,6 +27,7 @@ include 'patchwork-extensions' include 'patchwork-extensions-block' include 'patchwork-extensions-item' include 'patchwork-extensions-shearing' +include 'patchwork-fake-players' include 'patchwork-fml' include 'patchwork-god-classes' include 'patchwork-gui'