Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Commit 547331d

Browse files
williamblqouteallTheGlitch76
authored
Add FakePlayer API (#178)
* Add FakePlayer * Add FakePlayerFactory * Invoke FakePlayerFactory#unloadWorld * Fix license * Improve code quality of `FakePlayerFactory`: - Make some private static fields final - Remove an explicit generic type that was inferrable - Simplify logic in `unloadWorld` to mirror the logic in `getMinecraft` - Add javadoc for `unloadWorld` * Fix formatting in a couple of comments * Improve `FakePlayerFactory#get`: - username -> profile (shouldn't break anything) - switch to using computeIfAbsent * Move fake players into a new module * Update fake players unloading to use `fabric-lifecycle-events-v1` * Fix style * Update patchwork-extensions/src/main/resources/fabric.mod.json * Update patchwork-fake-players/build.gradle Co-authored-by: qouteall <qouteall@163.com> Co-authored-by: Glitch <glitchieproductionsofficial@gmail.com>
1 parent 494367d commit 547331d

9 files changed

Lines changed: 280 additions & 0 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
archivesBaseName = "patchwork-fake-players"
2+
version = getSubprojectVersion(project, "0.1.0")
3+
4+
dependencies {
5+
implementation project(path: ':patchwork-api-base', configuration: 'dev')
6+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package net.minecraftforge.common.util;
21+
22+
import com.mojang.authlib.GameProfile;
23+
24+
import net.minecraft.entity.damage.DamageSource;
25+
import net.minecraft.entity.player.PlayerEntity;
26+
import net.minecraft.network.packet.c2s.play.ClientSettingsC2SPacket;
27+
import net.minecraft.server.network.ServerPlayerEntity;
28+
import net.minecraft.server.network.ServerPlayerInteractionManager;
29+
import net.minecraft.server.world.ServerWorld;
30+
import net.minecraft.stat.Stat;
31+
import net.minecraft.text.Text;
32+
import net.minecraft.util.math.Vec3d;
33+
34+
// Preliminary, simple Fake Player class
35+
public class FakePlayer extends ServerPlayerEntity {
36+
public FakePlayer(ServerWorld world, GameProfile profile) {
37+
super(world.getServer(), world, profile, new ServerPlayerInteractionManager(world));
38+
}
39+
40+
@Override
41+
public Vec3d getPosVector() {
42+
return new Vec3d(0, 0, 0);
43+
}
44+
45+
@Override
46+
public void addChatMessage(Text text, boolean actionBar) {
47+
}
48+
49+
@Override
50+
public void sendMessage(Text component) {
51+
}
52+
53+
@Override
54+
public void increaseStat(Stat stat, int num) {
55+
}
56+
57+
@Override
58+
public boolean isInvulnerableTo(DamageSource source) {
59+
return true;
60+
}
61+
62+
@Override
63+
public boolean shouldDamagePlayer(PlayerEntity player) {
64+
return false;
65+
}
66+
67+
@Override
68+
public void onDeath(DamageSource source) {
69+
}
70+
71+
@Override
72+
public void tick() {
73+
}
74+
75+
@Override
76+
public void setClientSettings(ClientSettingsC2SPacket packet) {
77+
}
78+
79+
// Forge also has this here:
80+
// @Override @Nullable public MinecraftServer getServer() { return ServerLifecycleHooks.getCurrentServer(); }
81+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package net.minecraftforge.common.util;
21+
22+
import java.lang.ref.WeakReference;
23+
import java.util.Map;
24+
import java.util.UUID;
25+
26+
import com.google.common.collect.Maps;
27+
import com.mojang.authlib.GameProfile;
28+
29+
import net.minecraft.server.world.ServerWorld;
30+
31+
public class FakePlayerFactory {
32+
private static final GameProfile MINECRAFT = new GameProfile(UUID.fromString("41C82C87-7AfB-4024-BA57-13D2C99CAE77"), "[Minecraft]");
33+
// Map of all active fake player profiles to their entities
34+
private static final Map<GameProfile, FakePlayer> fakePlayers = Maps.newHashMap();
35+
private static WeakReference<FakePlayer> MINECRAFT_PLAYER = null;
36+
37+
public static FakePlayer getMinecraft(ServerWorld world) {
38+
FakePlayer ret = MINECRAFT_PLAYER != null ? MINECRAFT_PLAYER.get() : null;
39+
40+
if (ret == null) {
41+
ret = FakePlayerFactory.get(world, MINECRAFT);
42+
MINECRAFT_PLAYER = new WeakReference<>(ret);
43+
}
44+
45+
return ret;
46+
}
47+
48+
/**
49+
* Get a fake player with a given profile.
50+
* Mods should either hold weak references to the return value, or listen for a
51+
* WorldEvent.Unload and kill all references to prevent worlds staying in memory.
52+
*/
53+
public static FakePlayer get(ServerWorld world, GameProfile profile) {
54+
return fakePlayers.computeIfAbsent(profile, it -> new FakePlayer(world, it));
55+
}
56+
57+
/**
58+
* Used internally to clean up fake players when worlds are unloaded on server stop.
59+
*/
60+
public static void unloadWorld(ServerWorld world) {
61+
fakePlayers.entrySet().removeIf(entry -> entry.getValue().world == world);
62+
63+
// This shouldn't be strictly necessary, but let's be aggressive.
64+
FakePlayer mc = MINECRAFT_PLAYER != null ? MINECRAFT_PLAYER.get() : null;
65+
66+
if (mc != null && mc.world == world) {
67+
MINECRAFT_PLAYER = null;
68+
}
69+
}
70+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package net.patchworkmc.impl.fakeplayers;
21+
22+
import net.minecraftforge.common.util.FakePlayerFactory;
23+
24+
import net.minecraft.server.world.ServerWorld;
25+
26+
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
27+
import net.fabricmc.api.ModInitializer;
28+
29+
public class PatchworkFakePlayers implements ModInitializer {
30+
@Override
31+
public void onInitialize() {
32+
ServerLifecycleEvents.SERVER_STOPPED.register(server -> {
33+
for (ServerWorld world : server.getWorlds()) {
34+
FakePlayerFactory.unloadWorld(world);
35+
}
36+
});
37+
}
38+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package net.patchworkmc.mixin.fakeplayers;
21+
22+
import org.spongepowered.asm.mixin.Mixin;
23+
import org.spongepowered.asm.mixin.Shadow;
24+
import org.spongepowered.asm.mixin.injection.At;
25+
import org.spongepowered.asm.mixin.injection.Inject;
26+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
27+
import net.minecraftforge.common.util.FakePlayer;
28+
29+
import net.minecraft.advancement.Advancement;
30+
import net.minecraft.advancement.PlayerAdvancementTracker;
31+
import net.minecraft.server.network.ServerPlayerEntity;
32+
33+
@Mixin(PlayerAdvancementTracker.class)
34+
public class MixinPlayerAdvancementTracker {
35+
@Shadow
36+
private ServerPlayerEntity owner;
37+
38+
@Inject(method = "grantCriterion", at = @At("HEAD"), cancellable = true)
39+
private void onGrantCriterion(Advancement advancement, String criterion, CallbackInfoReturnable<Boolean> cir) {
40+
if (owner instanceof FakePlayer) {
41+
cir.setReturnValue(false);
42+
}
43+
}
44+
}
22.2 KB
Loading
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"schemaVersion": 1,
3+
"id": "patchwork-fake-players",
4+
"version": "${version}",
5+
"name": "Patchwork Fake Players",
6+
"description": "Implements the Minecraft Forge fake players API",
7+
"authors": [
8+
"PatchworkMC"
9+
],
10+
"license": "LGPL-2.1-only",
11+
"icon": "assets/patchwork-fake-players/icon.png",
12+
"environment": "*",
13+
"depends": {
14+
"patchwork-api-base": "*",
15+
"fabric": "*"
16+
},
17+
"mixins": [
18+
"patchwork-fake-players.mixins.json"
19+
],
20+
"entrypoints": {
21+
"main": [
22+
"net.patchworkmc.impl.fakeplayers.PatchworkFakePlayers"
23+
]
24+
},
25+
"custom": {
26+
"modmenu:api": true,
27+
"modmenu:parent": "patchwork"
28+
}
29+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"required": true,
3+
"package": "net.patchworkmc.mixin.fakeplayers",
4+
"compatibilityLevel": "JAVA_8",
5+
"mixins": [
6+
"MixinPlayerAdvancementTracker",
7+
],
8+
"injectors": {
9+
"defaultRequire": 1
10+
}
11+
}

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ include 'patchwork-extensions-block'
2828
include 'patchwork-extensions-blockentity'
2929
include 'patchwork-extensions-item'
3030
include 'patchwork-extensions-shearing'
31+
include 'patchwork-fake-players'
3132
include 'patchwork-fml'
3233
include 'patchwork-god-classes'
3334
include 'patchwork-gui'

0 commit comments

Comments
 (0)