Obtain a head for minecraft-heads - java

i try making a plugin where i need to display heads on a GUI, i found these heads on minecraft-heads in the custom heads section, but those aren't normal player's head , they're stocked in a plugin, head database, so i can't obtain them with a SkullMeta#setOwner("Player"). My question is: how can i obtain those heads ?
To know: In the website i can obtain them without the head database plugin, but the commands are like: /give #p skull 1 3 {display:{Name:"Earth"},SkullOwner:{Id:"e3ae97fb-b688-4dfd-8ee6-247790f22ecd",Properties:{textures:[{Value:"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTI4OWQ1YjE3ODYyNmVhMjNkMGIwYzNkMmRmNWMwODVlODM3NTA1NmJmNjg1YjVlZDViYjQ3N2ZlODQ3MmQ5NCJ9fX0="}]}}} so i have the possibility to place a NPC with the skin, then obtain his head, or /give the item to the player then change it position but that isn't anyway optimized.
Can you help me ?
Edit: i have to access to the head URL
Edit: One of my friends found the solution using the URL, here is it:
public static void setHead(ItemMeta im, String playerSkullUrl) {
GameProfile profile = new GameProfile(UUID.randomUUID(), null);
byte[] encodedData = Base64.getEncoder().encode(String.format("{textures:{SKIN:{url:\"%s\"}}}", playerSkullUrl).getBytes());
profile.getProperties().put("textures", new Property("textures", new String(encodedData)));
Field profileField = null;
try {
profileField = im.getClass().getDeclaredField("profile");
profileField.setAccessible(true);
profileField.set(im, profile);
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e1) {
e1.printStackTrace();
}
}
That's all ^^

First, the HeadDatabase resource contains heads with skins that contain newly registered players, and therefore also created skins. There is no need to have the HeadDatabase API available, as you can easily retrieve heads with skins using the Bukkit API.
To be able to retrieve heads, you need the SkullMeta interface, which provides the necessary properties to call the correct head.
An example code how to retrieve a head using Bukkit API:
ItemMeta itemMeta = new ItemStack(Material.PLAYER_HEAD).getItemMeta();
if (itemMeta instanceof SkullMeta) {
return; // This check is not necessary, but for safe cast usually better
}
SkullMeta meta = (SkullMeta) itemMeta;
OfflinePlayer player = ...; // Get one of offline player using Bukkit#getOfflinePlayer
// Version check above 1.12+
if (Version.isCurrentHigher(Version.v1_12_R1)) {
meta.setOwningPlayer(player); // Player can be online or offline
} else {
meta.setOwner(player.getName()); // SkullMeta#setOwner is deprecated
}
If you use Paper API, you could use Player#setPlayerProfile and set the existing profile to this Player object.
If you already have an existing skin and UUID, like you mentioned the Properties you can use SessionServer from Mojang and retrieving player informations as a Json object. You could use my workaround for this, which is thread safe.

Related

Libgdx json file initial game values

Quick question.
In my code I have the storing of my game values to Json. How would I do something where the first time they enter the game it sets the players values to the default base values. I have a method that has these values set that I can call and then use my save method? But I need a method that checks if its the first time the game has been run.. And if its the first time somehow create the json file to save to later.
Something like this should do it:
public class Game
{
final int COINS_DEFAULT = 0;
final String PLAYER_NAME_DEFAULT = "PlayerName";
...
File userInfoJSON = new File("/filepath");
if (userInfoJSON == null)
{
resetToDefaultsThenSaveToJSON();
}
}
For Libgdx you should use FileHandle:
FileHandle valuesFile = Gdx.files.internal("values.json");
if (!valuesFile.exists()) {
createJsonValuesFile();
}
I would suggest you to check(and create) it prior the actual game starts, for example, during the loading screen setup.

Bukkit - Change player's name above head?

I'm back again.
Today I have a question that many people have asked before. The reason I'm asking again is because in all my ~90 minutes of searching, I couldn't find an updated answer. Many answers tell me to use iTag/TagAPI, but I ran into some problems trying to use that, therefore I would not like to use iTag/TagAPI. I'm trying to use packets, and I found one answer, but it too was outdated.
EntityPlayer entityP = ((CraftPlayer) p).getHandle();
entityP.displayName = args[0];
for (Player a: Bukkit.getOnlinePlayers()) {
if (!p.getUniqueId().equals(a.getUniqueId()))
((CraftPlayer) a).getHandle().playerConnection.sendPacket(new PacketPlayOutNamedEntitySpawn(entityP));
}
Here's that thread I was going off of: https://bukkit.org/threads/change-player-name-above-head.162356/
Any help is appreciated!
It is possible to achieve this in 1.8. For convenience, I used ProtocolLib and PacketWrapper.
Since the 1.8 update, the NamedEntitySpawn packet has been modified and changing player's name by modifying that has been no longer supported.(ref)
But this post gave a reference: we can use packet PlayerInfoData. I did some testing, and here's the result(tested against 1.9.2):
Here's the code:
Player theGuyToChangeNameFor = Bukkit.getPlayer("theguy");
PlayerInfoData pid = new PlayerInfoData(WrappedGameProfile.fromPlayer(theGuyToChangeNameFor), 1,
EnumWrappers.NativeGameMode.SURVIVAL,
WrappedChatComponent.fromText("whatever_string"));
WrapperPlayServerPlayerInfo wpspi = new WrapperPlayServerPlayerInfo();
wpspi.setAction(EnumWrappers.PlayerInfoAction.REMOVE_PLAYER);
wpspi.setData(Collections.singletonList(pid));
for(Player p : Bukkit.getOnlinePlayers())
{
if(p.equals(theGuyToChangeNameFor))
{
continue;
}
p.hidePlayer(theGuyToChangeNameFor);
wpspi.sendPacket(p);
}
ProtocolLibrary.getProtocolManager().addPacketListener(
new PacketAdapter(this, PacketType.Play.Server.PLAYER_INFO)
{
#Override
public void onPacketSending(PacketEvent event)
{
if(event.getPacket().getPlayerInfoAction().read(0) != EnumWrappers.PlayerInfoAction.ADD_PLAYER)
{
return;
}
PlayerInfoData pid = event.getPacket().getPlayerInfoDataLists().read(0).get(0);
if(!pid.getProfile().getName().toLowerCase().equals("theguy")) // Here you can do something to ensure you're changing the name of the correct guy
{
return;
}
PlayerInfoData newPid = new PlayerInfoData(pid.getProfile().withName("HEAD_NAME"), pid.getPing(), pid.getGameMode(),
WrappedChatComponent.fromText("TAB_LIST_NAME"));
event.getPacket().getPlayerInfoDataLists().write(0, Collections.singletonList(newPid));
}
}
);
for(Player p : Bukkit.getOnlinePlayers())
{
if(p.equals(theGuyToChangeNameFor))
{
continue;
}
p.showPlayer(theGuyToChangeNameFor);
}
Explanation:
We use ProtocolLib to modify the PlayerInfoData packets from the server to change the player's display name. (You can see that name tag and tab list name can even be two different values!)
hidePlayer, showPlayer and REMOVE_PLAYER are used to refresh the player's name immediately(otherwise it will require logging out and in again). So far haven't found a better method. If you have one, say it:)

Updating pre-existing documents in mongoDB java driver when you've changed document structure

I've got a database of playerdata that has some pre-existing fields from previous versions of the program. Example out-dated document:
{
"playername": "foo"
}
but a player document generated under the new version would look like this:
{
"playername": "bar",
"playercurrency": 20
}
the issue is that if I try to query playercurrency on foo I get a NullPointerException because playercurrency doesn't exist for foo. I want to add the playercurrency field to foo without disturbing any other data that could be stored in foo. I've tried some code using $exists Example:
players.updateOne(new Document("playername", "foo"), new Document("$exists", new Document("playername", "")));
players.updateOne(new Document("playername", "foo"), new Document("$exists", new Document("playercurrency", 20)));
My thought is that it updates only playercurrency because it doesn't exist and it would leave playername alone becuase it exists. I might be using exists horribly wrong, and if so please do let me know because this is one of my first MongoDB projects and I would like to learn as much as I possibly can.
Do you have to do this with java? Whenever I add a new field that I want to be required I just use the command line to migrate all existing documents. This will loop through all players that don't have a playercurrency and set it to 0 (change to whatever default you want):
db.players.find({playercurrency:null}).forEach(function(player) {
player.playercurrency = 0; // or whatever default value
db.players.save(player);
});
This will result in you having the following documents:
{
"playername" : "foo",
"playercurrency" : 0
}
{
"playername" : "bar",
"playercurrency" : 20
}
So I know that it is normally frowned upon on answering your own question, but nobody really posted what I ended up doing I would like to take this time to thank #Mark Watson for answering and ultimately guiding me to finding my answer.
Since checking if a certain field is null doesn't work in the MongoDB Java Driver I needed to find a different way to know when something is primed for an update. So after a little bit of research I stumbled upon this question which helped me come up with this code:
private static void updateValue(final String name, final Object defaultValue, final UUID key) {
if (!exists(name, key)) {
FindIterable iterable = players.find(new Document("_id", key));
iterable.forEach(new Block<Document>() {
#Override
public void apply(Document document) {
players.updateOne(new Document("_id", key), new Document("$set", new Document(name, defaultValue)));
}
});
}
}
private static boolean exists(String name, UUID key) {
Document query = new Document(name, new Document("$exists", true)).append("_id", key);
return players.count(query) == 1;
}
Obviously this is a little specialized to what I wanted to do, but with little revisions it can be easliy changed to work with anything you might need. Make sure to replace players with your Collection object.

Get IAM users list by java aws sdk

Want to get list of all IAM users using sdk aws java. Class that we are using is AmazonIdentityManagementClient and method used is listuser(). API doc suggest pass parameter MaxItem and Marker. Whereas method do not recognize the parameter. Can anyone suggest how to do pagination here.
AmazonIdentityManagementClient amazonidentitymanagmentclient = new AmazonIdentityManagementClient();
ListUsersResult listuserresult = new ListUsersResult();
try {
listuserresult=amazonidentitymanagmentclient.listUsers();
List<User> listuser = new ArrayList<User>();
listuser = listuserresult.getUsers() //need to pass maxitems,marker here
}
} catch (Exception e) {
return null;
}
You need to use
ListUsersResult listUsers(ListUsersRequest listUsersRequest)
throws AmazonServiceException,
AmazonClientException
to use the marker feature.
You can set the marker in the ListUsersRequest . You need to get the marker from the results ( ListUsersResult ) of previous call of the listusers. The ListUsersResult has a method getMarker which can be used to get the marker to be used for next call. Then use the object ListUsesrsRequest. set the marker with the value got from getMarker and then call this listusers . Do this in a loop till the isTruncated method in the ListUsersResults indicates there are no more elements to return. If you don't set maxitem, by default it will return 100 items as per documentation. You can set that in your ListUsersRequest to a different value based on how much you want to display in a page.

Delete all files in 'folder' or with prefix in Google Cloud Bucket from Java

I know the idea of 'folders' is sort of non existent or different in Google Cloud Storage, but I need a way to delete all objects in a 'folder' or with a given prefix from Java.
The GcsService has a delete function, but as far as I can tell it only takes 1 GscFilename object and does not honor wildcards (i.e., "folderName/**" did not work).
Any tips?
The API only supports deleting a single object at a time. You can only request many deletions using many HTTP requests or by batching many delete requests. There is no API call to delete multiple objects using wildcards or the like. In order to delete all of the objects with a certain prefix, you'd need to list the objects, then make a delete call for each object that matches the pattern.
The command-line utility, gsutil, does exactly that when you ask it to delete the path "gs://bucket/dir/**. It fetches a list of objects matching that pattern, then it makes a delete call for each of them.
If you need a quick solution, you could always have your Java program exec gsutil.
Here is the code that corresponds to the above answer in case anyone else wants to use it:
public void deleteFolder(String bucket, String folderName) throws CoultNotDeleteFile {
try
{
ListResult list = gcsService.list(bucket, new ListOptions.Builder().setPrefix(folderName).setRecursive(true).build());
while(list.hasNext())
{
ListItem item = list.next();
gcsService.delete(new GcsFilename(file.getBucket(), item.getName()));
}
}
catch (IOException e)
{
//Error handling
}
}
Extremely late to the party, but here's for current google searches. We can delete multiple blobs efficiently by leveraging com.google.cloud.storage.StorageBatch.
Like so:
public static void rmdir(Storage storage, String bucket, String dir) {
StorageBatch batch = storage.batch();
Page<Blob> blobs = storage.list(bucket, Storage.BlobListOption.currentDirectory(),
Storage.BlobListOption.prefix(dir));
for(Blob blob : blobs.iterateAll()) {
batch.delete(blob.getBlobId());
}
batch.submit();
}
This should run MUCH faster than deleting one by one when your bucket/folder contains a non trivial amount of items.
Edit since this is getting a little attention, I'll demo error handling:
public static boolean rmdir(Storage storage, String bucket, String dir) {
List<StorageBatchResult<Boolean>> results = new ArrayList<>();
StorageBatch batch = storage.batch();
try {
Page<Blob> blobs = storage.list(bucket, Storage.BlobListOption.currentDirectory(),
Storage.BlobListOption.prefix(dir));
for(Blob blob : blobs.iterateAll()) {
results.add(batch.delete(blob.getBlobId()));
}
} finally {
batch.submit();
return results.stream().allMatch(r -> r != null && r.get());
}
}
This method will:
Delete every blob in the given folder of the given bucket returning true if so. The method will return false otherwise. One can look into the return method of batch.delete() for a better understanding and error proofing.
To ensure ALL items are deleted, you could call this like:
boolean success = false
while(!success)) {
success = rmdir(storage, bucket, dir);
}
I realise this is an old question, but I just stumbled upon the same issue and found a different way to resolve it.
The Storage class in the Google Cloud Java Client for Storage includes a method to list the blobs in a bucket, which can also accept an option to set a prefix to filter results to blobs whose names begin with the prefix.
For example, deleting all the files with a given prefix from a bucket can be achieved like this:
Storage storage = StorageOptions.getDefaultInstance().getService();
Iterable<Blob> blobs = storage.list("bucket_name", Storage.BlobListOption.prefix("prefix")).iterateAll();
for (Blob blob : blobs) {
blob.delete(Blob.BlobSourceOption.generationMatch());
}

Categories

Resources