Giter Club home page Giter Club logo

Comments (8)

timderspieler avatar timderspieler commented on June 2, 2024 1

@CryptoMorin sorry for the late reply but I really appreciate your help. Yes I completely changed the library calls to primarly use UUIDs wherever I can.

Thank you very much. I will close this issue for now.

Have a great weekend!

from xseries.

CryptoMorin avatar CryptoMorin commented on June 2, 2024

Can you point out the exact NMS/CraftBukkit class and method name in which you think this type of caching doesn't occur?
getOfflinePlayer(UUID) returns the online player object if they're, well, online.

Also there is no applySkinValue() method in SkullUtils anymore, can you point out the new method name?

from xseries.

timderspieler avatar timderspieler commented on June 2, 2024

"Can you point out the exact NMS/CraftBukkit class and method name in which you think this type of caching doesn't occur?
getOfflinePlayer(UUID) returns the online player object if they're, well, online."
If thats the case, my point is no longer valid and I am fine with that. The issue is, that I still have some slight performance issues using the SkullUtils. It's making HttpRequests where it (normally) shouldn't for my understanding. I thought that if a player is already online, the skin value of the player can be fetched using its GameProfile... or is that the case?

grafik

(Spark Report a user gave me: https://spark.lucko.me/7iMSIN2ZrX )

from xseries.

CryptoMorin avatar CryptoMorin commented on June 2, 2024

This is certainly a problem when the string name is used, but it's cached, so I'm not sure why this is happening. The only thing I can think of is the explanation I marked with "@@@" in the second method.

If that is the case, I guess I can detect it by comparing the UUID to the one I marked with "***" in the first method in my own custom cache?

public OfflinePlayer getOfflinePlayer(String name) {
  Preconditions.checkArgument(name != null, "name cannot be null");
  Preconditions.checkArgument(!name.isBlank(), "name cannot be empty");

  // Checks if the player is online to get the online instance
  OfflinePlayer result = this.getPlayerExact(name);
  if (result == null) {
      GameProfile profile = null;
      if (this.getOnlineMode() || SpigotConfig.bungee) {
          // Profile lookup is performed here, obfuscated version of get() method below
          profile = (GameProfile)this.console.ap().a(name).orElse((Object)null);
      }

      if (profile == null) {
          result = this.getOfflinePlayer(new GameProfile(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)), name));
          // *** Profiles that are not found are returned with a special UUID, I can check the returned offlineplayer's UUID and if its the same as the one encoded here, i can blacklist it.
         // For reference the this.getOfflinePlayer above makes a new offlineplayer with the same UUID as its profile, but it never actually uses it back later for some reasons...
      } else {
          result = this.getOfflinePlayer(profile);
      }
  } else {
      this.offlinePlayers.remove(((OfflinePlayer)result).getUniqueId());
  }

  return (OfflinePlayer)result;
}
public Optional<GameProfile> get(String s) {
    String s1 = s.toLowerCase(Locale.ROOT);
    UserCache.UserCacheEntry usercache_usercacheentry = (UserCache.UserCacheEntry) this.profilesByName.get(s1);
    boolean flag = false;

    if (usercache_usercacheentry != null && (new Date()).getTime() >= usercache_usercacheentry.expirationDate.getTime()) {
        this.profilesByUUID.remove(usercache_usercacheentry.getProfile().getId());
        this.profilesByName.remove(usercache_usercacheentry.getProfile().getName().toLowerCase(Locale.ROOT));
        flag = true;
        usercache_usercacheentry = null;
    }

    Optional optional;

    if (usercache_usercacheentry != null) {
        usercache_usercacheentry.setLastAccess(this.getNextOperation());
        optional = Optional.of(usercache_usercacheentry.getProfile());
    } else {
        optional = lookupGameProfile(this.profileRepository, s); // Spigot - use correct case for offline players
        // Lookup ^^^^^^^^^^^^^^^^^^^^^^^^^
        if (optional.isPresent()) {
            // @@@ So if for some reasons this player's profile doesn't exist on the server,
            // there is no cache to prevent it from looking it up again?
            this.add((GameProfile) optional.get());
            // Cache ^^^^^^^^^^^^^^^
            flag = false;
        }
    }

    if (flag && !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { // Spigot - skip saving if disabled
        this.save();
    }

    return optional;
}
public void add(GameProfile gameprofile) {
    Calendar calendar = Calendar.getInstance();

    calendar.setTime(new Date());
    calendar.add(2, 1);
    // Cached for a month ^
    Date date = calendar.getTime();
    UserCache.UserCacheEntry usercache_usercacheentry = new UserCache.UserCacheEntry(gameprofile, date);

    this.safeAdd(usercache_usercacheentry);
    if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(); // Spigot - skip saving if disabled
}




After looking a bit more it appears that what I described can only happen to online mode servers (probably):

private static Optional<GameProfile> lookupGameProfile(GameProfileRepository gameprofilerepository, String s) {
    final AtomicReference<GameProfile> atomicreference = new AtomicReference();
    ProfileLookupCallback profilelookupcallback = new ProfileLookupCallback() {
        public void onProfileLookupSucceeded(GameProfile gameprofile) {
            atomicreference.set(gameprofile);
        }

        public void onProfileLookupFailed(String s1, Exception exception) {
            atomicreference.set(null); // CraftBukkit - decompile error
        }
    };

    gameprofilerepository.findProfilesByNames(new String[]{s}, profilelookupcallback);
    GameProfile gameprofile = (GameProfile) atomicreference.get();

    if (!usesAuthentication() && gameprofile == null) {
        // I'm not sure what usesAuthentication() exactly means but
        // I guess it has something to do with online mode?
        // If that's the case, the report you sent shows it's in online mode 
        // so this block is never getting called anyways.
        UUID uuid = UUIDUtil.createOfflinePlayerUUID(s);

        return Optional.of(new GameProfile(uuid, s));
    } else {
        return Optional.ofNullable(gameprofile);
    }
}

from xseries.

timderspieler avatar timderspieler commented on June 2, 2024

This is actually interesting. So I should check if it makes a difference using the UUID of a player instead of the playername?

from xseries.

CryptoMorin avatar CryptoMorin commented on June 2, 2024

If you can use the player's UUID and you have access to that, that's definitely better, you should use the UUID whenever you can instead of the name.

But if your only option to get the skull that you want is the player name (or if it's a configuration option which allows both), I can push a commit to test if my solution would work but I noticed something else. What does DeathLogic.requestHeadDrop() actually do? Is it possible to see the line that uses SkullUtils? What type of argument is passed (I'm assuming it's the player name) and where does it come from?
Because from the looks of it, whatever skull it's requesting should exist and be cached normally.

from xseries.

timderspieler avatar timderspieler commented on June 2, 2024

Of course!

requestHeadDrop is a simple method that calculates the chance of a player head being dropped after the player has been killed.
I won't go into too much detail here because despite generating the player head using the SkullUtils, it does some economy related stuff that has nothing to do with XSeries.

But this is the way the SkullUtils are called:

drop_head = getPlugin().getItemUtils().buildSkull(displayname, pp.getName());

and this is the buildSkull method inside the ItemUtils class:

public ItemStack buildSkull(String name, String owner) {

	// Replace special characters in
	owner = owner.replaceAll("[^a-zA-Z0-9]", "");

	ItemStack result = XMaterial.PLAYER_HEAD.parseItem();
	applyShort(result, (short) 3);
	SkullMeta result_meta = SkullUtils.applySkin(result.getItemMeta(), owner);
	result_meta.setDisplayName(MessageManager.colorize(name));
	result.setItemMeta(result_meta);
	
	return result;
	
}

from xseries.

CryptoMorin avatar CryptoMorin commented on June 2, 2024

So it gets the skull of a player after they died. That means the player is online and the server should cache it properly. Can't you just directly use their UUID instead?
This question is kind of unrelated to the main issue, but I'm not sure what's the difference between name and owner don't they both originate from Player#getName()? Why is the replaceAll() line necessary?

Anyways, I pushed some changes: d98b12c so for now copy paste this as a standalone class in your plugin until we can decide if this is a viable fix.

from xseries.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.