Çözüldü Java - Low-level Paket (ProtocolLib)

  • Konuyu Başlatan Konuyu Başlatan Senpai
  • Başlangıç tarihi Başlangıç tarihi
  • Görüntüleme 141
Durum
Üzgünüz bu konu cevaplar için kapatılmıştır...

Senpai

Züm... Zümrü... Zümrüt...
Yasaklandı
Katılım
24 Kasım 2014
Mesajlar
816
Elmaslar
341
Puan
14.845
Yaş
27
Konum
Istanbul
Minecraft
NaN2
Sorunu çözmek için araştırma yaptım ancak pek bir kaynak bulamadım. Eğer daha önce low-level paketler ile uğraşmış birisi varsa yardım edebilir mi?

Yapmaya çalıştığım şey: Farklı lokasyonlarda skull spawnlıyoruz. Bu skullar hediye oluyor. Tıklandığında ise oyuncu hediyesini alabiliyor. Ancak, hediyeler client-side spawnlanmak zorunda çünkü oyuncular zaten aldıkları hediyeleri bir daha görememeleri lazım.

Sorun: Şuan debug olarak kendi elim ile spawnladığım zaman olması gerektiği gibi despawn oluyor aynı zamanda girdiğim zaman bir daha hediyeyi göremiyorum. Ancak oyuncu sunucuya girdiği zaman ne yazık ki blockları setuplayamıyorum.

İlk çözüm olarak chunk paketlerini dinledim ancak çalışmadı. Şuan kodun son hali böyle:

Kod:
package com.etu.lobby.packets;

import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.BlockPosition;
import com.comphenix.protocol.wrappers.WrappedBlockData;
import com.etu.lobby.BaseClass;
import com.etu.lobby.models.Present;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;

import java.util.Set;

public class PresentPacketHandler {
    private final BaseClass plugin;
    private boolean protocolLibInitialized = false;

    public PresentPacketHandler(BaseClass plugin) {
        this.plugin = plugin;
        plugin.getServer().getScheduler().runTask(plugin, () -> {
            if (ProtocolLibrary.getProtocolManager() != null) {
                protocolLibInitialized = true;
                registerPacketListeners();
            } else {
                plugin.getLogger().severe("err: protocol lib cant be initialized");
            }
        });
    }

    private void registerPacketListeners() {
        if (ProtocolLibrary.getProtocolManager() == null) return;

        ProtocolLibrary.getProtocolManager().addPacketListener( // eğer tekse
            new PacketAdapter(plugin, PacketType.Play.Server.BLOCK_CHANGE) {
                @Override
                public void onPacketSending(PacketEvent event) {
                    try {
                        if (event.getPacket().getMeta("present_handler") != null) {
                            return;
                        }

                        BlockPosition pos = event.getPacket().getBlockPositionModifier().read(0);
                        Location loc = pos.toLocation(event.getPlayer().getWorld());
                        if (((BaseClass)this.plugin).getPresentService().isPresent(loc)) {
                            event.setCancelled(true);
                            event.getPlayer().sendBlockChange(loc, Material.PLAYER_HEAD.createBlockData());
                        }
                    } catch (Exception ignored) {}
                }
            }
        );

        ProtocolLibrary.getProtocolManager().addPacketListener( // çoklu
            new PacketAdapter(plugin, PacketType.Play.Server.MULTI_BLOCK_CHANGE) {
                @Override
                public void onPacketSending(PacketEvent event) {
                    try {
                        PacketContainer packet = event.getPacket();
                        Object sectionPosition = packet.getModifier().read(0);
                        short[] positions = (short[]) packet.getModifier().read(1);
                        Object[] data = (Object[]) packet.getModifier().read(2);

                        if (positions == null || data == null) return;

                        int baseX = (int) sectionPosition.getClass().getMethod("getX").invoke(sectionPosition) << 4;
                        int baseY = (int) sectionPosition.getClass().getMethod("getY").invoke(sectionPosition) << 4;
                        int baseZ = (int) sectionPosition.getClass().getMethod("getZ").invoke(sectionPosition) << 4;

                        for (int i = 0; i < positions.length; i++) {
                            short pos = positions[i];
                            int x = baseX + (pos & 15);
                            int y = baseY + (pos >> 8 & 15);
                            int z = baseZ + (pos >> 4 & 15);
                            
                            Location loc = new Location(event.getPlayer().getWorld(), x, y, z);
                            if (((BaseClass)this.plugin).getPresentService().isPresent(loc)) {
                                sendBlockChange(event.getPlayer(), loc, Material.PLAYER_HEAD);
                            }
                        }
                    } catch (Exception ignored) {}
                }
            }
        );
    }

    public void syncPresentsForPlayer(Player player) {
        if (!protocolLibInitialized) {
            plugin.getLogger().warning("err: fallback to bukkit");
            syncPresentsWithBukkit(player);
            return;
        }

        Set<String> claimed = plugin.getPresentService().getClaimedPresents(player.getUniqueId());
        
        for (Present present : plugin.getPresentService().getAllPresents()) {
            Location loc = present.getLocation();
            if (claimed.contains(present.getId())) {
                sendBlockChange(player, loc, Material.AIR);
            } else {
                sendBlockChange(player, loc, Material.PLAYER_HEAD);
            }
        }
    }

    private void syncPresentsWithBukkit(Player player) {
        Set<String> claimed = plugin.getPresentService().getClaimedPresents(player.getUniqueId());
        
        for (Present present : plugin.getPresentService().getAllPresents()) {
            Location loc = present.getLocation();
            if (claimed.contains(present.getId())) {
                player.sendBlockChange(loc, Material.AIR.createBlockData());
            } else {
                player.sendBlockChange(loc, Material.PLAYER_HEAD.createBlockData());
            }
        }
    }

    public void hidePresent(Player player, Location location) {
        sendBlockChange(player, location, Material.AIR);
    }

    public void showPresent(Player player, Location location) {
        sendBlockChange(player, location, Material.PLAYER_HEAD);
    }

    private void sendBlockChange(Player player, Location loc, Material material) {
        if (!protocolLibInitialized) {
            player.sendBlockChange(loc, material.createBlockData());
            return;
        }

        try {
            PacketContainer packet = ProtocolLibrary.getProtocolManager()
                .createPacket(PacketType.Play.Server.BLOCK_CHANGE);

            packet.getBlockPositionModifier()
                .write(0, new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
            
            packet.getBlockData().write(0, WrappedBlockData.createData(material));
            
            packet.setMeta("present_handler", true); // meta
            
            ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet);
        } catch (Exception e) {
            player.sendBlockChange(loc, material.createBlockData());
        }
    }
}

Java:
package com.etu.lobby.services;

import com.etu.lobby.BaseClass;
import com.etu.lobby.models.Present;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Skull;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import org.bukkit.ChatColor;
import org.bukkit.Sound;
import org.bukkit.Particle;
import org.bukkit.Color;

import java.io.File;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

public class PresentService {
    private final BaseClass plugin;
    private final Map<String, Present> presents;
    private final String headTexture;
    private final int rewardHype;
    private final Set<UUID> processingPlayers;

    private static final String SQL_GET_CLAIMED_PRESENTS =
        "SELECT present_id FROM claimed_presents WHERE uuid = ?";
    private static final String SQL_INSERT_CLAIMED_PRESENT =
        "INSERT INTO claimed_presents (uuid, present_id) VALUES (?, ?)";
    private static final String SQL_CHECK_CLAIMED_PRESENT =
        "SELECT 1 FROM claimed_presents WHERE uuid = ? AND present_id = ?";
    private static final String SQL_COUNT_CLAIMED_PRESENTS =
        "SELECT COUNT(*) FROM claimed_presents WHERE uuid = ?";

    public PresentService(BaseClass plugin) {
        this.plugin = plugin;
        this.presents = new HashMap<>();
        this.processingPlayers = new HashSet<>();

        initializeConfig();
        YamlConfiguration config = loadConfig();
        
        this.headTexture = config.getString("settings.headTexture");
        this.rewardHype = config.getInt("settings.rewardHype", 25);
        
        loadPresents(config);
    }

    private void initializeConfig() {
        plugin.saveResource("presents.yml", false);
    }

    private YamlConfiguration loadConfig() {
        return YamlConfiguration.loadConfiguration(
            new File(plugin.getDataFolder(), "presents.yml")
        );
    }

    private void loadPresents(YamlConfiguration config) {
        List<Map<?, ?>> presentsList = config.getMapList("presents");
        for (Map<?, ?> presentMap : presentsList) {
            String id = (String) presentMap.get("id");
            Map<?, ?> locationMap = (Map<?, ?>) presentMap.get("location");
            
            if (id != null && locationMap != null) {
                Location location = parseLocation(locationMap);
                if (location != null) {
                    presents.put(id, new Present(id, location));
                }
            }
        }
        plugin.getLogger().info("Loaded " + presents.size() + " presents");
    }

    public void setupInitialBlocks(Player player) {
        // bug: yüklenmiyor
        plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
            for (Present present : presents.values()) {
                Location loc = present.getLocation();
                if (!loc.getChunk().isLoaded()) {
                    loc.getChunk().load();
                }
            }

            for (Present present : presents.values()) {
                Location loc = present.getLocation();
                Block block = loc.getBlock();
                block.setType(Material.PLAYER_HEAD);
                Skull skull = (Skull) block.getState();
                setSkullTexture(skull);
            }

            if (plugin.getPresentPacketHandler() != null) {
                plugin.getPresentPacketHandler().syncPresentsForPlayer(player);
            } else {
                Set<String> claimed = getClaimedPresents(player.getUniqueId());
                for (Present present : presents.values()) {
                    if (claimed.contains(present.getId())) {
                        player.sendBlockChange(present.getLocation(), Material.AIR.createBlockData());
                    }
                }
            }
        }, 20L);
    }

    private void setSkullTexture(Skull skull) {
        try {
            GameProfile profile = new GameProfile(UUID.randomUUID(), null);
            profile.getProperties().put("textures", new Property("textures", headTexture));
            
            Field profileField = skull.getClass().getDeclaredField("profile");
            profileField.setAccessible(true);
            profileField.set(skull, profile);
            skull.update();
        } catch (Exception e) {
            plugin.getLogger().severe("err: skull texture " + e.getMessage());
        }
    }

    private Location parseLocation(Map<?, ?> locationMap) {
        try {
            String world = (String) locationMap.get("world");
            double x = ((Number) locationMap.get("x")).doubleValue();
            double y = ((Number) locationMap.get("y")).doubleValue();
            double z = ((Number) locationMap.get("z")).doubleValue();
            
            return new Location(plugin.getServer().getWorld(world), x, y, z);
        } catch (Exception e) {
            plugin.getLogger().warning("err: parse location " + e.getMessage());
            return null;
        }
    }

    public void initializePlayerPresents(Player player) {
        UUID playerUuid = player.getUniqueId();
        if (processingPlayers.contains(playerUuid)) {
            return;
        }

        processingPlayers.add(playerUuid);
        try {
            plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
                setupInitialBlocks(player);
            }, 2L);
        } finally {
            processingPlayers.remove(playerUuid);
        }
    }

    public Set<String> getClaimedPresents(UUID playerUuid) {
        Set<String> claimedPresentIds = new HashSet<>();
        try (Connection conn = plugin.getDatabaseManager().getConnection();
             PreparedStatement ps = conn.prepareStatement(SQL_GET_CLAIMED_PRESENTS)) {
            
            ps.setString(1, playerUuid.toString());
            ResultSet rs = ps.executeQuery();
            
            while (rs.next()) {
                claimedPresentIds.add(rs.getString("present_id"));
            }
        } catch (SQLException e) {
            plugin.getLogger().severe("err: sql (get_claimed_presents) " + e.getMessage());
        }
        return claimedPresentIds;
    }

    public void claimPresent(Player player, String presentId) {
        UUID playerUuid = player.getUniqueId();
        if (hasPlayerClaimed(playerUuid, presentId)) {
            return;
        }

        try (Connection conn = plugin.getDatabaseManager().getConnection();
             PreparedStatement ps = conn.prepareStatement(SQL_INSERT_CLAIMED_PRESENT)) {
            
            ps.setString(1, playerUuid.toString());
            ps.setString(2, presentId);
            ps.executeUpdate();

            Present present = presents.get(presentId);
            if (present != null) {
                handlePresentClaim(player, present);
            }
        } catch (SQLException e) {
            plugin.getLogger().severe("err: sql (insert_claimed_present) " + e.getMessage());
        }
    }

    private void handlePresentClaim(Player player, Present present) {
        Location loc = present.getLocation();
        
        Block block = loc.getBlock();
        if (block.getType() == Material.PLAYER_HEAD) {
            block.setType(Material.AIR);
        }
        
        plugin.getPresentPacketHandler().hidePresent(player, loc);
        
        playClaimEffects(player, present.getLocation());
        giveClaimRewards(player);
        sendClaimMessage(player);
    }

    private void playClaimEffects(Player player, Location location) {
        Location particleLoc = location.clone().add(0.5, 0.5, 0.5);
        
        player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 1.0f);
        
        Particle.DustOptions dustOptions = new Particle.DustOptions(Color.RED, 1.0f);
        particleLoc.getWorld().spawnParticle(
            Particle.REDSTONE,
            particleLoc,
            20, 0.3, 0.3, 0.3,
            0,
            dustOptions
        );
    }

    private void giveClaimRewards(Player player) {
        plugin.getHypeService().addPlayerHype(player.getUniqueId(), rewardHype);
        plugin.getScoreboardService().updateScoreboard(player);
    }

    private void sendClaimMessage(Player player) {
        int claimed = getPlayerClaimedCount(player.getUniqueId());
        int total = presents.size();
        
        player.sendMessage(ChatColor.translateAlternateColorCodes('&',
            String.format("&aYou found a present! &e(&b%d&e/&b%d&e)", claimed, total))
        );
    }

    public boolean isPresent(Location location) {
        return presents.values().stream()
                .anyMatch(present -> present.isAt(location));
    }

    public String getPresentIdAtLocation(Location location) {
        return presents.entrySet().stream()
                .filter(entry -> entry.getValue().isAt(location))
                .map(Map.Entry::getKey)
                .findFirst()
                .orElse(null);
    }

    private boolean hasPlayerClaimed(UUID playerUuid, String presentId) {
        try (Connection conn = plugin.getDatabaseManager().getConnection();
             PreparedStatement ps = conn.prepareStatement(SQL_CHECK_CLAIMED_PRESENT)) {
            
            ps.setString(1, playerUuid.toString());
            ps.setString(2, presentId);
            return ps.executeQuery().next();
        } catch (SQLException e) {
            plugin.getLogger().severe("err: sql (check_claimed_present) " + e.getMessage());
            return false;
        }
    }

    private int getPlayerClaimedCount(UUID playerUuid) {
        try (Connection conn = plugin.getDatabaseManager().getConnection();
             PreparedStatement ps = conn.prepareStatement(SQL_COUNT_CLAIMED_PRESENTS)) {
            
            ps.setString(1, playerUuid.toString());
            ResultSet rs = ps.executeQuery();
            
            if (rs.next()) {
                return rs.getInt(1);
            }
        } catch (SQLException e) {
            plugin.getLogger().severe("err: sql (count_claimed_presents) " + e.getMessage());
        }
        return 0;
    }

    public Collection<Present> getAllPresents() {
        return presents.values();
    }

    public Present getPresentById(String id) {
        return presents.get(id);
    }
}

Kod:
package com.etu.lobby.listeners;

import com.etu.lobby.BaseClass;

import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class PresentListener implements Listener {
    private final BaseClass plugin;
    private final Map<UUID, Long> clickCooldowns = new HashMap<>();
    private static final long CLICK_COOLDOWN = 5000;

    public PresentListener(BaseClass plugin) {
        this.plugin = plugin;
    }

    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event) {
        plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
            Player player = event.getPlayer();
            plugin.getPresentPacketHandler().syncPresentsForPlayer(player);
        }, 10L);
    }

    @EventHandler
    public void onPlayerInteract(PlayerInteractEvent event) {
        if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
        if (event.getClickedBlock() == null) return;
        if (event.getClickedBlock().getType() != Material.PLAYER_HEAD) return;

        Player player = event.getPlayer();
        Location loc = event.getClickedBlock().getLocation();
        
        if (!plugin.getPresentService().isPresent(loc)) return;
        
        long currentTime = System.currentTimeMillis();
        if (clickCooldowns.containsKey(player.getUniqueId())) {
            long lastClick = clickCooldowns.get(player.getUniqueId());
            if (currentTime - lastClick < CLICK_COOLDOWN) {
                return;
            }
        }
        
        clickCooldowns.put(player.getUniqueId(), currentTime);
        
        event.setCancelled(true);
        String presentId = plugin.getPresentService().getPresentIdAtLocation(loc);
        
        plugin.getPresentPacketHandler().hidePresent(player, loc);
        plugin.getPresentService().claimPresent(player, presentId);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onBlockBreak(BlockBreakEvent event) {
        if (event.getBlock().getType() == Material.PLAYER_HEAD) {
            if (plugin.getPresentService().isPresent(event.getBlock().getLocation())) {
                event.setCancelled(true);
            }
        }
    }
}

Yardımcı olabilecek varsa mesajlarınızı bekliyorum, teşekkürler <3
 
Konu kilit, çözüldü. Chunk yüklenmeden blokları manipüle etmeye çalıştığım için çalışmıyormuş.

Kod:
public void setupInitialBlocks(Player player) {
        for (Present present : presents.values()) {
            Location loc = present.getLocation();
            if (!loc.getChunk().isLoaded()) {
                loc.getChunk().load(true); // force
            }
        }

        for (Present present : presents.values()) {
            Location loc = present.getLocation();
            Block block = loc.getBlock();
            if (block.getType() != Material.PLAYER_HEAD) {
                block.setType(Material.PLAYER_HEAD);
                Skull skull = (Skull) block.getState();
                setSkullTexture(skull);
            }
        }
    }

 
Durum
Üzgünüz bu konu cevaplar için kapatılmıştır...

Hala Discord sunucumuza katılmadın mı?

Büyük bir topluluğun parçası ol, etkinliklere katıl ve özel hediyeler kazanma şansı yakala!

Şimdi Katıl
Üst