Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.eternalcode.core;

import com.eternalcode.core.feature.afk.AfkService;
import com.eternalcode.core.feature.enderchest.EnderchestService;
import com.eternalcode.core.feature.catboy.CatboyService;
import com.eternalcode.core.feature.home.HomeService;
import com.eternalcode.core.feature.jail.JailService;
Expand All @@ -17,6 +18,8 @@ public interface EternalCoreApi {

CatboyService getCatboyService();

EnderchestService getEnderchestService();

IgnoreService getIgnoreService();

HomeService getHomeService();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.eternalcode.core.feature.enderchest;

import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;

/**
* Paginated ender chests. When the feature is disabled the vanilla ender chest is used and only
* {@link #openEnderchest(Player)} does anything; when ender chests are blocked nothing opens at all.
*/
public interface EnderchestService {

/**
* @return whether ender chests are blocked entirely, which overrides {@link #isVanillaEnderchestReplaced()}
*/
boolean areEnderchestsBlocked();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Co to oznacza? dajmy tutaj szczegółowsze javadocs'y lub lepszą nazwę tej metody


/**
* @return whether paginated ender chests are enabled in the configuration
*/
boolean isVanillaEnderchestReplaced();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Co to oznacza? Jeśli to dotyczy konfiguracji i tego, czy enderchesty mają być paginated - to nazwa metody do zmiany


/**
* Opens the player's own ender chest: the first page when the feature is enabled, the vanilla
* ender chest otherwise. Does nothing while ender chests are blocked.
*
* @param player the player to open the chest for
*/
void openEnderchest(Player player);

/**
* Opens a page of the owner's ender chest to the viewer. The owner may be offline. The viewer is
* notified when the page is beyond the owner's reach. Does nothing when the feature is disabled or
* ender chests are blocked.
*
* @param viewer the player who sees and edits the page
* @param owner the player whose chest is opened, online or not
* @param page 1-based page number
*/
void openEnderchest(Player viewer, OfflinePlayer owner, int page);

/**
* @param player the player to evaluate
* @return number of pages the player's permissions grant, at least 1; pages that already hold items
* stay reachable beyond this limit
*/
int getPageLimit(Player player);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.eternalcode.core.feature.enderchest.event;

import java.util.UUID;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;

/**
* Called right before a page of a paginated ender chest is shown to a viewer.
*/
public class EnderchestOpenEvent extends Event implements Cancellable {

private static final HandlerList HANDLER_LIST = new HandlerList();

private final UUID viewerUniqueId;
private final UUID ownerUniqueId;
private final int page;
private boolean cancelled;

public EnderchestOpenEvent(UUID viewerUniqueId, UUID ownerUniqueId, int page) {
super(false);
this.viewerUniqueId = viewerUniqueId;
this.ownerUniqueId = ownerUniqueId;
this.page = page;
}

public UUID getViewerUniqueId() {
return this.viewerUniqueId;
}

public UUID getOwnerUniqueId() {
return this.ownerUniqueId;
}

public int getPage() {
return this.page;
}

@Override
public boolean isCancelled() {
return this.cancelled;
}

@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}

@Override
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}

public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.eternalcode.core;

import com.eternalcode.core.feature.afk.AfkService;
import com.eternalcode.core.feature.enderchest.EnderchestService;
import com.eternalcode.core.feature.catboy.CatboyService;
import com.eternalcode.core.feature.home.HomeService;
import com.eternalcode.core.feature.ignore.IgnoreService;
Expand Down Expand Up @@ -30,6 +31,11 @@ public CatboyService getCatboyService() {
return this.dependencyProvider.getDependency(CatboyService.class);
}

@Override
public EnderchestService getEnderchestService() {
return this.dependencyProvider.getDependency(EnderchestService.class);
}

@Override
public IgnoreService getIgnoreService() {
return this.dependencyProvider.getDependency(IgnoreService.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import com.eternalcode.core.feature.deathteleport.DeathTeleportSettings;
import com.eternalcode.core.feature.enchant.EnchantConfig;
import com.eternalcode.core.feature.enchant.EnchantSettings;
import com.eternalcode.core.feature.enderchest.EnderchestConfig;
import com.eternalcode.core.feature.enderchest.EnderchestSettings;
import com.eternalcode.core.feature.give.GiveConfig;
import com.eternalcode.core.feature.give.GiveSettings;
import com.eternalcode.core.feature.helpop.HelpOpConfig;
Expand Down Expand Up @@ -252,6 +254,12 @@ public static class Format extends OkaeriConfig {
@Comment("# Automatically teleports players back to their death location after respawning")
DeathTeleportConfig deathTeleport = new DeathTeleportConfig();

@Bean(proxied = EnderchestSettings.class)
@Comment("")
@Comment("# Ender Chest Configuration")
@Comment("# Replaces the vanilla ender chest with a paginated one kept in the database")
EnderchestConfig enderchest = new EnderchestConfig();

@Override
public File getConfigFile(File dataFolder) {
return new File(dataFolder, "config.yml");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package com.eternalcode.core.database.persister;

import com.j256.ormlite.field.FieldType;
import com.j256.ormlite.field.SqlType;
import com.j256.ormlite.field.types.BaseDataType;
import com.j256.ormlite.support.DatabaseResults;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import org.bukkit.inventory.ItemStack;

// Paper only added serializeItemsAsBytes in 1.21.1, so we encode item by item to stay usable on 1.19.3.
// The per item serializeAsBytes we call here differs by one word, easy to mix the two up.
public class ItemStackArrayPersister extends BaseDataType {

private static final ItemStackArrayPersister INSTANCE = new ItemStackArrayPersister();

private static final byte FORMAT_VERSION = 3;
private static final int MAX_SLOTS = 1024;

private ItemStackArrayPersister() {
super(SqlType.BYTE_ARRAY, new Class<?>[] { ItemStack[].class });
}

@Override
public Object javaToSqlArg(FieldType fieldType, Object javaObject) {
return encode((ItemStack[]) javaObject);
}

@Override
public Object resultToSqlArg(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException {
return results.getBytes(columnPos);
}

@Override
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) {
return decode((byte[]) sqlArg);
}

@Override
public Object parseDefaultString(FieldType fieldType, String defaultStr) throws SQLException {
throw new SQLException("Items cannot be given a default value");
}

@Override
public boolean isArgumentHolderRequired() {
return true;
}

@Override
public Class<?> getPrimaryClass() {
return ItemStack[].class;
}

public static ItemStackArrayPersister getSingleton() {
return INSTANCE;
}

private static byte[] encode(ItemStack[] items) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();

try (DataOutputStream output = new DataOutputStream(buffer)) {
output.writeByte(FORMAT_VERSION);
output.writeInt(items.length);
output.writeInt(countStored(items));

for (int slot = 0; slot < items.length; slot++) {
ItemStack item = items[slot];
if (item == null) {
continue;
}

byte[] serialized = item.serializeAsBytes();
output.writeInt(slot);
output.writeInt(serialized.length);
output.write(serialized);
}
}
catch (IOException exception) {
throw new IllegalStateException("Failed to encode items", exception);
}

return buffer.toByteArray();
}

private static int countStored(ItemStack[] items) {
int stored = 0;

for (ItemStack item : items) {
if (item != null) {
stored++;
}
}

return stored;
}

private static ItemStack[] decode(byte[] bytes) {
if (bytes == null) {
return new ItemStack[0];
}

if (bytes.length == 0) {
throw new IllegalStateException("Stored items are empty, the row is corrupted");
}

try (DataInputStream input = new DataInputStream(new ByteArrayInputStream(bytes))) {
byte version = input.readByte();
if (version != FORMAT_VERSION) {
throw new IllegalStateException("Unknown item format: " + version);
}

int slots = input.readInt();
if (slots < 0 || slots > MAX_SLOTS) {
throw new IllegalStateException("Item array declares " + slots + " slots");
}

int stored = input.readInt();
if (stored < 0 || stored > slots) {
throw new IllegalStateException("Item array declares " + stored + " items in " + slots + " slots");
}

ItemStack[] items = new ItemStack[slots];
for (int index = 0; index < stored; index++) {
int slot = input.readInt();
if (slot < 0 || slot >= slots) {
throw new IllegalStateException("Item points at slot " + slot + " outside of " + slots);
}

int length = input.readInt();
if (length <= 0 || length > bytes.length) {
throw new IllegalStateException("Slot " + slot + " declares " + length + " bytes");
}

byte[] serialized = new byte[length];
input.readFully(serialized);
items[slot] = ItemStack.deserializeBytes(serialized);
}

return items;
}
catch (IOException exception) {
throw new IllegalStateException("Failed to decode items", exception);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ public interface ContainerMessages {
Notice cartographyOpened();
Notice targetCartographyOpened();

Notice enderchestOpened();
Notice targetEnderchestOpened();

Notice grindstoneOpened();
Notice targetGrindstoneOpened();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ public class ENContainerMessages extends OkaeriConfig implements ContainerMessag
Notice cartographyOpened = Notice.chat("<color:#9d6eef>► <white>Cartography table opened!");
Notice targetCartographyOpened = Notice.chat("<color:#9d6eef>► <white>Opened a cartography table for {PLAYER}!");

Notice enderchestOpened = Notice.chat("<color:#9d6eef>► <white>Ender chest opened!");
Notice targetEnderchestOpened = Notice.chat("<color:#9d6eef>► <white>Opened an ender chest for {PLAYER}!");

Notice grindstoneOpened = Notice.chat("<color:#9d6eef>► <white>Grindstone opened!");
Notice targetGrindstoneOpened = Notice.chat("<color:#9d6eef>► <white>Opened a grindstone for {PLAYER}!");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ public class PLContainerMessages extends OkaeriConfig implements ContainerMessag
Notice cartographyOpened = Notice.chat("<color:#9d6eef>► <white>Otworzono stół kartograficzny!");
Notice targetCartographyOpened = Notice.chat("<color:#9d6eef>► <white>Otworzono stół kartograficzny dla {PLAYER}!");

Notice enderchestOpened = Notice.chat("<color:#9d6eef>► <white>Otworzono skrzynię kresu!");
Notice targetEnderchestOpened = Notice.chat("<color:#9d6eef>► <white>Otworzono skrzynię kresu dla {PLAYER}!");

Notice grindstoneOpened = Notice.chat("<color:#9d6eef>► <white>Otworzono szlifierkę!");
Notice targetGrindstoneOpened = Notice.chat("<color:#9d6eef>► <white>Otworzono szlifierkę dla {PLAYER}!");

Expand Down
Loading
Loading