Skip to content

Commit

Permalink
Add texture support to get|set_skull_owner()
Browse files Browse the repository at this point in the history
  • Loading branch information
PseudoKnight committed Jul 18, 2024
1 parent f4cc0e3 commit 17906e0
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ public interface MCPlayerProfile extends AbstractionObject {

void setProperty(MCProfileProperty property);

boolean removeProperty(String key);

}
5 changes: 5 additions & 0 deletions src/main/java/com/laytonsmith/abstraction/blocks/MCSkull.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.laytonsmith.abstraction.blocks;

import com.laytonsmith.abstraction.MCOfflinePlayer;
import com.laytonsmith.abstraction.MCPlayerProfile;

public interface MCSkull extends MCBlockState {

Expand All @@ -21,4 +22,8 @@ public interface MCSkull extends MCBlockState {
* @param player - The new skull owner or {@code null} to clear the current owner.
*/
void setOwningPlayer(MCOfflinePlayer player);

MCPlayerProfile getPlayerProfile();

void setPlayerProfile(MCPlayerProfile profile);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.laytonsmith.abstraction.bukkit;

import com.laytonsmith.PureUtilities.Common.ReflectionUtils;
import com.destroystokyo.paper.profile.PlayerProfile;
import com.destroystokyo.paper.profile.ProfileProperty;
import com.laytonsmith.abstraction.MCPlayerProfile;
import com.laytonsmith.abstraction.MCProfileProperty;

Expand All @@ -9,47 +10,41 @@

public class BukkitMCPlayerProfile implements MCPlayerProfile {

Object pp;
PlayerProfile pp;

public BukkitMCPlayerProfile(Object pp) {
this.pp = pp;
this.pp = (PlayerProfile) pp;
}

@Override
public String getName() {
return (String) ReflectionUtils.invokeMethod(this.pp, "getName");
return this.pp.getName();
}

@Override
public UUID getId() {
return (UUID) ReflectionUtils.invokeMethod(this.pp, "getId");
return this.pp.getId();
}

@Override
public MCProfileProperty getProperty(String key) {
Set<?> properties = (Set<?>) ReflectionUtils.invokeMethod(this.pp, "getProperties");
for(Object property : properties) {
if(ReflectionUtils.invokeMethod(property, "getName").equals(key)) {
String name = (String) ReflectionUtils.invokeMethod(property, "getName");
String value = (String) ReflectionUtils.invokeMethod(property, "getValue");
String signature = (String) ReflectionUtils.invokeMethod(property, "getSignature");
return new MCProfileProperty(name, value, signature);
Set<ProfileProperty> properties = this.pp.getProperties();
for(ProfileProperty p : properties) {
if(p.getName().equals(key)) {
return new MCProfileProperty(p.getName(), p.getValue(), p.getSignature());
}
}
return null;
}

@Override
public void setProperty(MCProfileProperty property) {
Class clz;
try {
clz = Class.forName("com.destroystokyo.paper.profile.ProfileProperty");
} catch (ClassNotFoundException e) {
return;
}
Object profileProperty = ReflectionUtils.newInstance(clz, new Class[]{String.class, String.class, String.class},
new Object[]{property.getName(), property.getValue(), property.getSignature()});
ReflectionUtils.invokeMethod(this.pp, "setProperty", profileProperty);
this.pp.setProperty(new ProfileProperty(property.getName(), property.getValue(), property.getValue()));
}

@Override
public boolean removeProperty(String key) {
return this.pp.removeProperty(key);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

import com.laytonsmith.PureUtilities.Common.ReflectionUtils;
import com.laytonsmith.abstraction.MCOfflinePlayer;
import com.laytonsmith.abstraction.MCPlayerProfile;
import com.laytonsmith.abstraction.blocks.MCSkull;
import com.laytonsmith.abstraction.bukkit.BukkitMCOfflinePlayer;

import com.laytonsmith.abstraction.bukkit.BukkitMCPlayerProfile;
import com.laytonsmith.abstraction.bukkit.BukkitMCServer;
import com.laytonsmith.core.Static;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Skull;

Expand Down Expand Up @@ -46,4 +50,20 @@ public void setOwningPlayer(MCOfflinePlayer player) {
// Set the skull owner.
this.skull.setOwningPlayer((OfflinePlayer) player.getHandle());
}

@Override
public MCPlayerProfile getPlayerProfile() {
if(((BukkitMCServer) Static.getServer()).isPaper()) {
Object profile = ReflectionUtils.invokeMethod(Skull.class, this.skull, "getPlayerProfile");
if(profile != null) {
return new BukkitMCPlayerProfile(profile);
}
}
return null;
}

@Override
public void setPlayerProfile(MCPlayerProfile profile) {
ReflectionUtils.invokeMethod(this.skull, "setPlayerProfile", profile.getHandle());
}
}
81 changes: 47 additions & 34 deletions src/main/java/com/laytonsmith/core/functions/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import com.laytonsmith.abstraction.MCOfflinePlayer;
import com.laytonsmith.abstraction.MCPattern;
import com.laytonsmith.abstraction.MCPlayer;
import com.laytonsmith.abstraction.MCPlayerProfile;
import com.laytonsmith.abstraction.MCProfileProperty;
import com.laytonsmith.abstraction.MCWorld;
import com.laytonsmith.abstraction.StaticLayer;
import com.laytonsmith.abstraction.blocks.MCBanner;
Expand Down Expand Up @@ -940,15 +942,16 @@ public String getName() {

@Override
public Integer[] numArgs() {
return new Integer[]{2};
return new Integer[]{2, 3};
}

@Override
public String docs() {
return "void {locationArray, owner}"
return "void {locationArray, owner, [texture]}"
+ " Sets the owner of the skull at the given location by name or uuid."
+ " Supplying null will clear the skull owner, but due to limitations in Bukkit, clients will only"
+ " see this change after reloading the block."
+ " If owner is not null, the texture value as a Base64 encoded string may be provided. (Paper only)"
+ " If no world is provided and the function is executed by a player, the player's world is used."
+ " If the block at the given location isn't a skull, a RangeException is thrown.";
}
Expand Down Expand Up @@ -976,23 +979,30 @@ public Boolean runAsync() {
@Override
public Mixed exec(Target t, com.laytonsmith.core.environments.Environment environment, Mixed... args)
throws ConfigRuntimeException {
MCWorld defaultWorld = null;
MCCommandSender sender = environment.getEnv(CommandHelperEnvironment.class).GetCommandSender();
if(sender instanceof MCPlayer) {
defaultWorld = ((MCPlayer) sender).getWorld();
}
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], defaultWorld, t);
MCPlayer p = environment.getEnv(CommandHelperEnvironment.class).GetPlayer();
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], p != null ? p.getWorld() : null, t);
MCBlock block = loc.getBlock();
MCBlockState blockState = block.getState();
if(blockState instanceof MCSkull) {
MCSkull skull = (MCSkull) blockState;
MCOfflinePlayer owner = (args[1] instanceof CNull ? null : Static.GetUser(args[1], t));
skull.setOwningPlayer(owner);
skull.update();
return CVoid.VOID;
} else {
if(!(blockState instanceof MCSkull skull)) {
throw new CRERangeException("The block at the specified location is not a skull", t);
}
MCOfflinePlayer owner = (args[1] instanceof CNull ? null : Static.GetUser(args[1], t));
if(owner != null && args.length == 3) {
MCPlayerProfile profile = Static.getServer().getPlayerProfile(owner.getUniqueID(), owner.getName());
if(profile != null) {
if(args[2] instanceof CNull) {
profile.removeProperty("textures");
} else {
profile.setProperty(new MCProfileProperty("textures", args[2].val(), null));
}
skull.setPlayerProfile(profile);
skull.update();
return CVoid.VOID;
}
}
skull.setOwningPlayer(owner);
skull.update();
return CVoid.VOID;
}
}

Expand All @@ -1013,8 +1023,9 @@ public Integer[] numArgs() {
public String docs() {
return "array {locationArray}"
+ " Returns the owner name and uuid of the skull at the given location as an array in format:"
+ " {name: NAME, uuid: UUID}, or null if the skull does not have an owner. The value at the 'name'"
+ " key will be an empty string if the server does not know the player's name."
+ " {name: string, uuid: string, texture: string}, or null if the skull does not have an owner."
+ " The value at the 'name' key will be an empty string if the server does not know the player's name."
+ " The 'texture' value is the Base64 encoded string of the textures property, or null. (Paper only)"
+ " If no world is provided and the function is executed by a player, the player's world is used."
+ " If the block at the given location isn't a skull, a RangeException is thrown.";
}
Expand Down Expand Up @@ -1042,27 +1053,29 @@ public Boolean runAsync() {
@Override
public Mixed exec(Target t, com.laytonsmith.core.environments.Environment environment, Mixed... args)
throws ConfigRuntimeException {
MCWorld defaultWorld = null;
MCCommandSender sender = environment.getEnv(CommandHelperEnvironment.class).GetCommandSender();
if(sender instanceof MCPlayer) {
defaultWorld = ((MCPlayer) sender).getWorld();
}
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], defaultWorld, t);
MCPlayer p = environment.getEnv(CommandHelperEnvironment.class).GetPlayer();
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], p != null ? p.getWorld() : null, t);
MCBlockState blockState = loc.getBlock().getState();
if(blockState instanceof MCSkull) {
MCSkull skull = (MCSkull) blockState;
MCOfflinePlayer owner = skull.getOwningPlayer();
if(owner == null) {
return CNull.NULL;
if(!(blockState instanceof MCSkull skull)) {
throw new CRERangeException("The block at the specified location is not a skull", t);
}
MCOfflinePlayer owner = skull.getOwningPlayer();
if(owner == null) {
return CNull.NULL;
}
CArray ret = new CArray(t);
ret.set("name", owner.getName());
ret.set("uuid", owner.getUniqueID().toString());
MCPlayerProfile playerProfile = skull.getPlayerProfile();
if(playerProfile != null) {
MCProfileProperty textureProperty = playerProfile.getProperty("textures");
if(textureProperty != null) {
ret.set("texture", skull.getPlayerProfile().getProperty("textures").getValue());
} else {
CArray ret = new CArray(t);
ret.set("name", owner.getName());
ret.set("uuid", owner.getUniqueID().toString());
return ret;
ret.set("texture", CNull.NULL, t);
}
} else {
throw new CRERangeException("The block at the specified location is not a skull", t);
}
return ret;
}
}

Expand Down

0 comments on commit 17906e0

Please sign in to comment.