Skip to content

Commit 1cf4fed

Browse files
disguise api
1 parent 63c94c9 commit 1cf4fed

File tree

30 files changed

+4757
-0
lines changed

30 files changed

+4757
-0
lines changed

paper-api/src/main/java/com/destroystokyo/paper/SkinParts.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,15 @@ public interface SkinParts {
1717
boolean hasHatsEnabled();
1818

1919
int getRaw();
20+
21+
interface Builder {
22+
@org.jetbrains.annotations.NotNull Builder withCape(boolean cape);
23+
@org.jetbrains.annotations.NotNull Builder withJacket(boolean jacket);
24+
@org.jetbrains.annotations.NotNull Builder withLeftSleeve(boolean leftSleeve);
25+
@org.jetbrains.annotations.NotNull Builder withRightSleeve(boolean rightSleeve);
26+
@org.jetbrains.annotations.NotNull Builder withLeftPants(boolean leftPants);
27+
@org.jetbrains.annotations.NotNull Builder withRightPants(boolean rightPants);
28+
@org.jetbrains.annotations.NotNull Builder withHat(boolean hat);
29+
@org.jetbrains.annotations.NotNull SkinParts build();
30+
}
2031
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package io.papermc.paper.disguise;
2+
3+
import com.destroystokyo.paper.profile.PlayerProfile;
4+
import org.bukkit.entity.EntityType;
5+
import org.jetbrains.annotations.ApiStatus;
6+
import org.jspecify.annotations.NullMarked;
7+
8+
/**
9+
* Represents the data used to disguise an entity as another.
10+
* Also supports disguising an entity as a player commonly known as `FakePlayer`.
11+
*/
12+
@NullMarked
13+
public sealed interface DisguiseData permits DisguiseData.OriginalDisguise, EntityTypeDisguise, PlayerDisguise {
14+
15+
/**
16+
* Creates an original disguise data that can be used to reset disguising.
17+
* <p>
18+
* The original instance is set by default when a new entity is spawned
19+
* and represents the state of no disguise should be made.
20+
* <p>
21+
* Same as {@link #reset()}
22+
*
23+
* @return an original disguise data
24+
*/
25+
static DisguiseData original() {
26+
return reset();
27+
}
28+
29+
/**
30+
* Creates a {@link PlayerDisguise.Builder} where you can configure certain properties of the fake player appearance.
31+
*
32+
*
33+
* @param playerProfile a already completed player profile that will be the fake players skin
34+
* @return a builder to configure certain attributes
35+
*/
36+
static PlayerDisguise.Builder player(PlayerProfile playerProfile) {
37+
return new PlayerDisguise.Builder(playerProfile);
38+
}
39+
40+
/**
41+
* Creates a {@link EntityTypeDisguise.Builder} to allow disguising your entity as the given {@link EntityType}.
42+
*
43+
*
44+
* @param entityType the entity type as which the entity should appear as.
45+
* @return an entity disguise
46+
*/
47+
static EntityTypeDisguise.Builder entity(EntityType entityType) {
48+
return new EntityTypeDisguise.Builder(entityType);
49+
}
50+
51+
/**
52+
* An alias for {@link #original()} to cover certain views on it.
53+
*
54+
* @see #original()
55+
*
56+
* @return an original disguise data
57+
*/
58+
static OriginalDisguise reset() {
59+
return new OriginalDisguise();
60+
}
61+
62+
record OriginalDisguise() implements DisguiseData{
63+
@ApiStatus.Internal
64+
public OriginalDisguise() {}
65+
}
66+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package io.papermc.paper.disguise;
2+
3+
import java.util.Objects;
4+
import org.bukkit.entity.EntityType;
5+
import org.jetbrains.annotations.ApiStatus;
6+
import org.jspecify.annotations.NullMarked;
7+
8+
@NullMarked
9+
public record EntityTypeDisguise(EntityType entityType) implements DisguiseData {
10+
@ApiStatus.Internal
11+
public EntityTypeDisguise {
12+
Objects.requireNonNull(entityType, "type cannot be null");
13+
}
14+
15+
/**
16+
* Represents the builder to configure certain appearance settings.
17+
*/
18+
public static class Builder {
19+
private final EntityType entityType;
20+
21+
@ApiStatus.Internal
22+
public Builder(EntityType entityType) {
23+
this.entityType = entityType;
24+
}
25+
26+
/**
27+
* Builds the disguise
28+
*
29+
* @return the built disguise
30+
*/
31+
public EntityTypeDisguise build() {
32+
return new EntityTypeDisguise(entityType);
33+
}
34+
}
35+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package io.papermc.paper.disguise;
2+
3+
import com.destroystokyo.paper.SkinParts;
4+
import com.destroystokyo.paper.profile.PlayerProfile;
5+
import java.util.Objects;
6+
import org.bukkit.Server;
7+
import org.jetbrains.annotations.ApiStatus;
8+
import org.jetbrains.annotations.Nullable;
9+
import org.jspecify.annotations.NullMarked;
10+
11+
@NullMarked
12+
public record PlayerDisguise(PlayerProfile playerProfile, boolean listed, boolean showHead,
13+
@Nullable SkinParts skinParts) implements DisguiseData {
14+
15+
@ApiStatus.Internal
16+
public PlayerDisguise {
17+
Objects.requireNonNull(playerProfile, "profile cannot be null");
18+
}
19+
public static Builder builder(PlayerProfile playerProfile) {
20+
return new Builder(playerProfile);
21+
}
22+
23+
/**
24+
* Represents the builder to configure certain appearance settings.
25+
*/
26+
public static class Builder {
27+
private final PlayerProfile playerProfile;
28+
private boolean listed;
29+
private boolean showHead;
30+
@Nullable
31+
private SkinParts skinParts;
32+
33+
@ApiStatus.Internal
34+
public Builder(PlayerProfile playerProfile) {
35+
this.playerProfile = playerProfile;
36+
}
37+
38+
/**
39+
* Defines if the fake player will be shown in player list.
40+
*
41+
* @param listed true, if the player should be listed else false
42+
* @return the builder instance
43+
*/
44+
public Builder listed(boolean listed) {
45+
this.listed = listed;
46+
return this;
47+
}
48+
49+
/**
50+
* Defines which skin parts should be enabled for the fake player.
51+
* <p>
52+
*
53+
* @param showHead defines if the fake players head should be shown in the player list.
54+
* @return the builder instance
55+
*/
56+
public Builder showHead(boolean showHead) {
57+
this.showHead = showHead;
58+
return this;
59+
}
60+
61+
/**
62+
* Defines which skin parts should be enabled for the fake player.
63+
* <p>
64+
* Use {@link Server#newSkinPartsBuilder()} to get a fresh builder instance for configuration.
65+
*
66+
* @param skinParts the skin parts that should be shown.
67+
* @return the builder instance
68+
*/
69+
public Builder skinParts(SkinParts skinParts) {
70+
this.skinParts = skinParts;
71+
return this;
72+
}
73+
74+
/**
75+
* Builds the disguise
76+
*
77+
* @return the built disguise
78+
*/
79+
public PlayerDisguise build() {
80+
return new PlayerDisguise(playerProfile, listed, showHead, skinParts);
81+
}
82+
}
83+
}

paper-api/src/main/java/org/bukkit/Server.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2607,4 +2607,11 @@ default boolean isOwnedByCurrentRegion(@NotNull org.bukkit.block.Block block) {
26072607
*/
26082608
void allowPausing(@NotNull org.bukkit.plugin.Plugin plugin, boolean value);
26092609
// Paper end - API to check if the server is sleeping
2610+
// Paper start - add disguise api
2611+
/**
2612+
* Creates a new skinparts builder used for overriding skin settings
2613+
* @return a new builder for skin parts
2614+
*/
2615+
com.destroystokyo.paper.SkinParts.@NotNull Builder newSkinPartsBuilder();
2616+
// Paper end - add disguise api
26102617
}

paper-api/src/main/java/org/bukkit/entity/Entity.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,4 +1172,34 @@ public default boolean spawnAt(@NotNull Location location) {
11721172
*/
11731173
void broadcastHurtAnimation(@NotNull java.util.Collection<Player> players);
11741174
// Paper end - broadcast hurt animation
1175+
// Paper start - disguise api
1176+
1177+
/**
1178+
* Gets the current {@link io.papermc.paper.disguise.DisguiseData} of the entity.
1179+
*
1180+
* @return {@link io.papermc.paper.disguise.DisguiseData.OriginalDisguise} if entity is not disguised.
1181+
* Otherwise, one of {@link io.papermc.paper.disguise.EntityTypeDisguise} or {@link io.papermc.paper.disguise.PlayerDisguise}
1182+
*/
1183+
@NotNull io.papermc.paper.disguise.DisguiseData getDisguiseData();
1184+
1185+
/**
1186+
* Sets the current {@link io.papermc.paper.disguise.DisguiseData} of the entity.
1187+
* <p>
1188+
* Following {@link io.papermc.paper.disguise.DisguiseData} can be set:
1189+
* <ul>
1190+
* <li>{@link io.papermc.paper.disguise.PlayerDisguise} use {@link io.papermc.paper.disguise.DisguiseData#player(com.destroystokyo.paper.profile.PlayerProfile)}.
1191+
* It returns a builder where you are able to configure additional settings</li>
1192+
* <li>{@link io.papermc.paper.disguise.EntityTypeDisguise} use {@link io.papermc.paper.disguise.DisguiseData#entity(EntityType)}</li>
1193+
* <li>{@link io.papermc.paper.disguise.DisguiseData.OriginalDisguise} use {@link io.papermc.paper.disguise.DisguiseData#original()} or {@link io.papermc.paper.disguise.DisguiseData#reset()} to reset it again to the original state</li>
1194+
* </ul>
1195+
* <p>
1196+
* The following entities are not supported:
1197+
* <ul>
1198+
* <li>{@link ExperienceOrb}</li>
1199+
* </ul>
1200+
*
1201+
* @param disguiseData the {@link io.papermc.paper.disguise.DisguiseData} that will be set.
1202+
*/
1203+
void setDisguiseData(@NotNull io.papermc.paper.disguise.DisguiseData disguiseData);
1204+
// Paper end - disguise api
11751205
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Uncomment to enable the 'paper-server-generator' project
2+
// include(":paper-server-generator")
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import io.papermc.paperweight.util.defaultJavaLauncher
2+
3+
plugins {
4+
java
5+
id("io.papermc.paperweight.source-generator")
6+
}
7+
8+
paperweight {
9+
atFile.set(layout.projectDirectory.file("wideners.at"))
10+
}
11+
12+
dependencies {
13+
minecraftJar(project(":paper-server", "mappedJarOutgoing"))
14+
implementation(project(":paper-server", "macheMinecraftLibraries"))
15+
16+
implementation("com.squareup:javapoet:1.13.0")
17+
implementation(project(":paper-api"))
18+
implementation("io.github.classgraph:classgraph:4.8.47")
19+
implementation("org.jetbrains:annotations:24.1.0")
20+
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
21+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
22+
}
23+
24+
tasks.register<JavaExec>("generate") {
25+
dependsOn(tasks.check)
26+
mainClass.set("io.papermc.generator.Main")
27+
classpath(sourceSets.main.map { it.runtimeClasspath })
28+
args(projectDir.toPath().resolve("generated").toString())
29+
javaLauncher = javaToolchains.defaultJavaLauncher(project)
30+
}
31+
32+
tasks.test {
33+
useJUnitPlatform()
34+
}
35+
36+
group = "io.papermc.paper"
37+
version = "1.0-SNAPSHOT"

0 commit comments

Comments
 (0)