Compare commits

...

8 Commits
4.1.7 ... 4.1.8

Author SHA1 Message Date
Jikoo
64af4dddb0 Bump version to 4.1.8 for release 2021-06-11 18:40:39 -04:00
Jikoo
f613c0a522 Remove redundant load 2021-06-11 18:39:19 -04:00
Jikoo
1cae4c7a8e Correct window id 2021-06-11 18:39:07 -04:00
Jikoo
ff7243db6a Fix script issues
Temporarily explicitly declare Spigot dependencies
I don't have the time to deal with whatever the difference between remote and local bash/maven versions is right now.
2021-06-11 12:05:38 -04:00
Jikoo
07a8e3b973 Add 1.17 support 2021-06-11 10:50:50 -04:00
Jikoo
9fccea60f7 Update copyright 2021-06-11 10:50:36 -04:00
Jikoo
9a2b379a64 Escape changelog for YAML
With 1.17 releasing soon, we'll get to see if this was the issue very shortly.
Worst case scenario the yaml is still messed up, but since the changelog is now the last element, unless it's so badly malformed that the entire action can't run the file should still upload even if the changelog does not.
2021-06-08 11:38:26 -04:00
Jikoo
4d800361d8 Bump version to 4.1.8-SNAPSHOT for development 2021-05-29 09:51:39 -04:00
46 changed files with 1923 additions and 67 deletions

View File

@@ -14,7 +14,7 @@ jobs:
- name: Set Up Java
uses: actions/setup-java@v1
with:
java-version: 1.8
java-version: 16
# Use cache to speed up build
- name: Cache Maven Repo

View File

@@ -13,9 +13,6 @@ jobs:
with:
fetch-depth: 0
- name: Set CurseForge Variables
run: . scripts/set_curseforge_env.sh
- name: Fetch Github Release Asset
uses: dsaltares/fetch-gh-release-asset@0.0.5
with:
@@ -23,6 +20,9 @@ jobs:
version: ${{ github.event.release.id }}
file: OpenInv.jar
- name: Set CurseForge Variables
run: . scripts/set_curseforge_env.sh "${{ github.event.release.body }}"
- name: Create CurseForge Release
uses: itsmeow/curseforge-upload@v3
with:
@@ -30,7 +30,8 @@ jobs:
project_id: 31432
game_endpoint: minecraft
file_path: ./OpenInv.jar
changelog: ${{ github.event.release.body }}
display_name: ${{ github.event.release.name }}
game_versions: ${{ env.CURSEFORGE_MINECRAFT_VERSIONS }}
display_name: "${{ github.event.release.name }}"
game_versions: "${{ env.CURSEFORGE_MINECRAFT_VERSIONS }}"
release_type: release
changelog_type: markdown
changelog: "${{ env.CURSEFORGE_CHANGELOG }}"

View File

@@ -1,5 +1,5 @@
<!--
~ Copyright (C) 2011-2020 lishid. All rights reserved.
~ Copyright (C) 2011-2021 lishid. All rights reserved.
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
<parent>
<artifactId>openinvparent</artifactId>
<groupId>com.lishid</groupId>
<version>4.1.7</version>
<version>4.1.8</version>
</parent>
<artifactId>openinvapi</artifactId>

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
<!--
~ Copyright (C) 2011-2020 lishid. All rights reserved.
~ Copyright (C) 2011-2021 lishid. All rights reserved.
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
<parent>
<groupId>com.lishid</groupId>
<artifactId>openinvparent</artifactId>
<version>4.1.7</version>
<version>4.1.8</version>
</parent>
<artifactId>openinvassembly</artifactId>

View File

@@ -1,5 +1,5 @@
<!--
~ Copyright (C) 2011-2020 lishid. All rights reserved.
~ Copyright (C) 2011-2021 lishid. All rights reserved.
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (C) 2011-2020 lishid. All rights reserved.
~ Copyright (C) 2011-2021 lishid. All rights reserved.
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@@ -23,7 +23,7 @@
<artifactId>openinvparent</artifactId>
<groupId>com.lishid</groupId>
<relativePath>../../pom.xml</relativePath>
<version>4.1.7</version>
<version>4.1.8</version>
</parent>
<artifactId>openinvadapter1_16_R3</artifactId>

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

73
internal/v1_17_R1/pom.xml Normal file
View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (C) 2011-2021 lishid. All rights reserved.
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, version 3.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>openinvparent</artifactId>
<groupId>com.lishid</groupId>
<relativePath>../../pom.xml</relativePath>
<version>4.1.8</version>
</parent>
<artifactId>openinvadapter1_17_R1</artifactId>
<name>OpenInvAdapter1_17_R1</name>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<artifactId>spigot</artifactId>
<groupId>org.spigotmc</groupId>
<scope>provided</scope>
<version>1.17-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>openinvapi</artifactId>
<groupId>com.lishid</groupId>
</dependency>
<dependency>
<artifactId>openinvplugincore</artifactId>
<groupId>com.lishid</groupId>
</dependency>
<dependency>
<artifactId>annotations</artifactId>
<groupId>org.jetbrains</groupId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<!-- Cannot use minimizeJar until maven-shade-plugin 3.3.0 releases; ASM used does not support Java 16. -->
<configuration>
<minimizeJar>false</minimizeJar>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,348 @@
/*
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.v1_17_R1;
import com.lishid.openinv.OpenInv;
import com.lishid.openinv.internal.IAnySilentContainer;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.minecraft.core.BlockPosition;
import net.minecraft.network.chat.ChatMessage;
import net.minecraft.network.chat.IChatBaseComponent;
import net.minecraft.server.level.EntityPlayer;
import net.minecraft.server.level.PlayerInteractManager;
import net.minecraft.world.ITileInventory;
import net.minecraft.world.InventoryLargeChest;
import net.minecraft.world.TileInventory;
import net.minecraft.world.entity.player.EntityHuman;
import net.minecraft.world.entity.player.PlayerInventory;
import net.minecraft.world.inventory.Container;
import net.minecraft.world.inventory.ContainerChest;
import net.minecraft.world.inventory.Containers;
import net.minecraft.world.inventory.InventoryEnderChest;
import net.minecraft.world.level.EnumGamemode;
import net.minecraft.world.level.World;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.BlockBarrel;
import net.minecraft.world.level.block.BlockChest;
import net.minecraft.world.level.block.BlockChestTrapped;
import net.minecraft.world.level.block.BlockShulkerBox;
import net.minecraft.world.level.block.entity.TileEntity;
import net.minecraft.world.level.block.entity.TileEntityChest;
import net.minecraft.world.level.block.entity.TileEntityEnderChest;
import net.minecraft.world.level.block.entity.TileEntityLootable;
import net.minecraft.world.level.block.state.IBlockData;
import net.minecraft.world.level.block.state.properties.BlockPropertyChestType;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.block.Barrel;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.EnderChest;
import org.bukkit.block.ShulkerBox;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.type.Chest;
import org.bukkit.entity.Cat;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryView;
import org.bukkit.util.BoundingBox;
import org.jetbrains.annotations.NotNull;
public class AnySilentContainer implements IAnySilentContainer {
private Field playerInteractManagerGamemode;
public AnySilentContainer() {
try {
this.playerInteractManagerGamemode = PlayerInteractManager.class.getDeclaredField("b");
this.playerInteractManagerGamemode.setAccessible(true);
} catch (NoSuchFieldException | SecurityException e) {
Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger();
logger.warning("Unable to directly write player gamemode! SilentChest will fail.");
logger.log(Level.WARNING, "Error obtaining gamemode field", e);
}
}
@Override
public boolean isAnySilentContainer(@NotNull final org.bukkit.block.Block bukkitBlock) {
if (bukkitBlock.getType() == Material.ENDER_CHEST) {
return true;
}
BlockState state = bukkitBlock.getState();
return state instanceof org.bukkit.block.Chest
|| state instanceof org.bukkit.block.ShulkerBox
|| state instanceof org.bukkit.block.Barrel;
}
@Override
public boolean isAnyContainerNeeded(@NotNull final Player p, @NotNull final org.bukkit.block.Block block) {
BlockState blockState = block.getState();
// Barrels do not require AnyContainer.
if (blockState instanceof Barrel) {
return false;
}
// Enderchests require a non-occluding block on top to open.
if (blockState instanceof EnderChest) {
return block.getRelative(0, 1, 0).getType().isOccluding();
}
// Shulker boxes require 1/2 a block clear in the direction they open.
if (blockState instanceof ShulkerBox) {
BoundingBox boundingBox = block.getBoundingBox();
if (boundingBox.getVolume() > 1) {
// Shulker box is already open.
return false;
}
BlockData blockData = block.getBlockData();
if (!(blockData instanceof Directional directional)) {
// Shouldn't be possible. Just in case, demand AnyChest.
return true;
}
BlockFace face = directional.getFacing();
boundingBox.shift(face.getDirection());
// Return whether or not bounding boxes overlap.
return block.getRelative(face, 1).getBoundingBox().overlaps(boundingBox);
}
if (!(blockState instanceof org.bukkit.block.Chest)) {
return false;
}
if (isBlockedChest(block)) {
return true;
}
BlockData blockData = block.getBlockData();
if (!(blockData instanceof Chest chest) || ((Chest) blockData).getType() == Chest.Type.SINGLE) {
return false;
}
int ordinal = (chest.getFacing().ordinal() + 4 + (chest.getType() == Chest.Type.RIGHT ? -1 : 1)) % 4;
BlockFace relativeFace = BlockFace.values()[ordinal];
org.bukkit.block.Block relative = block.getRelative(relativeFace);
if (relative.getType() != block.getType()) {
return false;
}
BlockData relativeData = relative.getBlockData();
if (!(relativeData instanceof Chest relativeChest)) {
return false;
}
if (relativeChest.getFacing() != chest.getFacing()
|| relativeChest.getType() != (chest.getType() == Chest.Type.RIGHT ? Chest.Type.LEFT : Chest.Type.RIGHT)) {
return false;
}
return isBlockedChest(relative);
}
private boolean isBlockedChest(org.bukkit.block.Block block) {
org.bukkit.block.Block relative = block.getRelative(0, 1, 0);
return relative.getType().isOccluding()
|| block.getWorld().getNearbyEntities(BoundingBox.of(relative), entity -> entity instanceof Cat).size() > 0;
}
@Override
public boolean activateContainer(
@NotNull final Player bukkitPlayer,
final boolean silentchest,
@NotNull final org.bukkit.block.Block bukkitBlock) {
// Silent ender chest is API-only
if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) {
bukkitPlayer.openInventory(bukkitPlayer.getEnderChest());
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
return true;
}
EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer);
final World world = player.getWorld();
final BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ());
final TileEntity tile = world.getTileEntity(blockPosition);
if (tile == null) {
return false;
}
if (tile instanceof TileEntityEnderChest) {
// Anychest ender chest. See net.minecraft.world.level.block.BlockEnderChest
InventoryEnderChest enderChest = player.getEnderChest();
enderChest.a((TileEntityEnderChest) tile);
player.openContainer(new TileInventory((containerCounter, playerInventory, ignored) -> {
Containers<?> containers = PlayerDataManager.getContainers(enderChest.getSize());
int rows = enderChest.getSize() / 9;
return new ContainerChest(containers, containerCounter, playerInventory, enderChest, rows);
}, new ChatMessage("container.enderchest")));
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
return true;
}
if (!(tile instanceof ITileInventory tileInventory)) {
return false;
}
IBlockData blockData = world.getType(blockPosition);
Block block = blockData.getBlock();
if (block instanceof BlockChest) {
BlockPropertyChestType chestType = blockData.get(BlockChest.c);
if (chestType != BlockPropertyChestType.a) {
BlockPosition adjacentBlockPosition = blockPosition.shift(BlockChest.h(blockData));
IBlockData adjacentBlockData = world.getType(adjacentBlockPosition);
if (adjacentBlockData.getBlock() == block) {
BlockPropertyChestType adjacentChestType = adjacentBlockData.get(BlockChest.c);
if (adjacentChestType != BlockPropertyChestType.a && chestType != adjacentChestType
&& adjacentBlockData.get(BlockChest.b) == blockData.get(BlockChest.b)) {
TileEntity adjacentTile = world.getTileEntity(adjacentBlockPosition);
if (adjacentTile instanceof TileEntityChest && tileInventory instanceof TileEntityChest) {
TileEntityChest rightChest = chestType == BlockPropertyChestType.c ? ((TileEntityChest) tileInventory) : (TileEntityChest) adjacentTile;
TileEntityChest leftChest = chestType == BlockPropertyChestType.c ? (TileEntityChest) adjacentTile : ((TileEntityChest) tileInventory);
if (silentchest && (rightChest.g != null || leftChest.g != null)) {
OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
return false;
}
tileInventory = new ITileInventory() {
public Container createMenu(int containerCounter, PlayerInventory playerInventory, EntityHuman entityHuman) {
leftChest.d(playerInventory.l);
rightChest.d(playerInventory.l);
return ContainerChest.b(containerCounter, playerInventory, new InventoryLargeChest(rightChest, leftChest));
}
public IChatBaseComponent getScoreboardDisplayName() {
if (leftChest.hasCustomName()) {
return leftChest.getScoreboardDisplayName();
}
if (rightChest.hasCustomName()) {
return rightChest.getScoreboardDisplayName();
}
return new ChatMessage("container.chestDouble");
}
};
}
}
}
}
if (block instanceof BlockChestTrapped) {
bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED);
} else {
bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED);
}
}
if (block instanceof BlockShulkerBox) {
bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED);
}
if (block instanceof BlockBarrel) {
bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL);
}
// AnyChest only - SilentChest not active, container unsupported, or unnecessary.
if (!silentchest || player.d.getGameMode() == EnumGamemode.d) {
player.openContainer(tileInventory);
return true;
}
// SilentChest requires access to setting players' gamemode directly.
if (this.playerInteractManagerGamemode == null) {
return false;
}
if (tile instanceof TileEntityLootable lootable) {
if (lootable.g != null) {
OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
return false;
}
}
EnumGamemode gamemode = player.d.getGameMode();
this.forceGameMode(player, EnumGamemode.d);
player.openContainer(tileInventory);
this.forceGameMode(player, gamemode);
return true;
}
@Override
public void deactivateContainer(@NotNull final Player bukkitPlayer) {
if (this.playerInteractManagerGamemode == null) {
return;
}
InventoryView view = bukkitPlayer.getOpenInventory();
switch (view.getType()) {
case CHEST:
case ENDER_CHEST:
case SHULKER_BOX:
case BARREL:
break;
default:
return;
}
EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer);
// Force game mode change without informing plugins or players.
EnumGamemode gamemode = player.d.getGameMode();
this.forceGameMode(player, EnumGamemode.d);
// See EntityPlayer#closeInventory - can't call or we'd recursively deactivate.
player.bV.b(player);
player.bU.a(player.bV);
player.bV = player.bU;
// Revert forced game mode.
this.forceGameMode(player, gamemode);
}
private void forceGameMode(final EntityPlayer player, final EnumGamemode gameMode) {
if (this.playerInteractManagerGamemode == null) {
// No need to warn repeatedly, error on startup and lack of function should be enough.
return;
}
try {
this.playerInteractManagerGamemode.setAccessible(true);
this.playerInteractManagerGamemode.set(player.d, gameMode);
// TODO: may need additional calls to update abilities to prevent container sound + animation
// gameMode.a(player.getAbilities());
// player.updateAbilities();
// should be the fix if it doesn't work as-is
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.v1_17_R1;
import java.io.File;
import java.io.FileOutputStream;
import net.minecraft.nbt.NBTCompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.level.EntityPlayer;
import net.minecraft.world.level.storage.WorldNBTStorage;
import org.apache.logging.log4j.LogManager;
import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
public class OpenPlayer extends CraftPlayer {
public OpenPlayer(CraftServer server, EntityPlayer entity) {
super(server, entity);
}
@Override
public void loadData() {
// See CraftPlayer#loadData
NBTTagCompound loaded = this.server.getHandle().r.load(this.getHandle());
if (loaded != null) {
readExtraData(loaded);
}
}
@Override
public void saveData() {
EntityPlayer player = this.getHandle();
// See net.minecraft.world.level.storage.WorldNBTStorage#save(EntityHuman)
try {
WorldNBTStorage worldNBTStorage = player.c.getPlayerList().r;
NBTTagCompound playerData = player.save(new NBTTagCompound());
setExtraData(playerData);
if (!isOnline()) {
// Special case: save old vehicle data
NBTTagCompound oldData = worldNBTStorage.load(player);
if (oldData != null && oldData.hasKeyOfType("RootVehicle", 10)) {
// See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound)
playerData.set("RootVehicle", oldData.getCompound("RootVehicle"));
}
}
File file = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat.tmp");
File file1 = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat");
NBTCompressedStreamTools.a(playerData, new FileOutputStream(file));
if (file1.exists() && !file1.delete() || !file.renameTo(file1)) {
LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString());
}
} catch (Exception e) {
LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString());
}
}
}

View File

@@ -0,0 +1,231 @@
/*
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.v1_17_R1;
import com.lishid.openinv.OpenInv;
import com.lishid.openinv.internal.IPlayerDataManager;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.OpenInventoryView;
import com.mojang.authlib.GameProfile;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.minecraft.network.chat.ChatComponentText;
import net.minecraft.network.protocol.game.PacketPlayOutOpenWindow;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.EntityPlayer;
import net.minecraft.server.level.WorldServer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.inventory.Container;
import net.minecraft.world.inventory.Containers;
import net.minecraft.world.level.World;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_17_R1.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftContainer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PlayerDataManager implements IPlayerDataManager {
private @Nullable Field bukkitEntity;
public PlayerDataManager() {
try {
bukkitEntity = Entity.class.getDeclaredField("bukkitEntity");
} catch (NoSuchFieldException e) {
Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger();
logger.warning("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded.");
logger.log(Level.WARNING, e.getMessage(), e);
bukkitEntity = null;
}
}
public static @NotNull EntityPlayer getHandle(final Player player) {
if (player instanceof CraftPlayer) {
return ((CraftPlayer) player).getHandle();
}
Server server = player.getServer();
EntityPlayer nmsPlayer = null;
if (server instanceof CraftServer) {
nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getName());
}
if (nmsPlayer == null) {
// Could use reflection to examine fields, but it's honestly not worth the bother.
throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation");
}
return nmsPlayer;
}
@Override
public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) {
// Ensure player has data
if (!offline.hasPlayedBefore()) {
return null;
}
// Create a profile and entity to load the player data
// See net.minecraft.server.PlayerList#attemptLogin
GameProfile profile = new GameProfile(offline.getUniqueId(),
offline.getName() != null ? offline.getName() : offline.getUniqueId().toString());
MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
WorldServer worldServer = server.getWorldServer(World.f);
if (worldServer == null) {
return null;
}
EntityPlayer entity = new EntityPlayer(server, worldServer, profile);
try {
injectPlayer(entity);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// Get the bukkit entity
Player target = entity.getBukkitEntity();
if (target != null) {
// Load data
target.loadData();
}
// Return the entity
return target;
}
void injectPlayer(EntityPlayer player) throws IllegalAccessException {
if (bukkitEntity == null) {
return;
}
bukkitEntity.setAccessible(true);
bukkitEntity.set(player, new OpenPlayer(player.c.server, player));
}
@NotNull
@Override
public Player inject(@NotNull Player player) {
try {
EntityPlayer nmsPlayer = getHandle(player);
injectPlayer(nmsPlayer);
return nmsPlayer.getBukkitEntity();
} catch (IllegalAccessException e) {
e.printStackTrace();
return player;
}
}
@Nullable
@Override
public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) {
EntityPlayer nmsPlayer = getHandle(player);
if (nmsPlayer.b == null) {
return null;
}
InventoryView view = getView(player, inventory);
if (view == null) {
return player.openInventory(inventory.getBukkitInventory());
}
Container container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) {
@Override
public Containers<?> getType() {
return getContainers(inventory.getBukkitInventory().getSize());
}
};
container.setTitle(new ChatComponentText(view.getTitle()));
container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container);
if (container == null) {
return null;
}
nmsPlayer.b.sendPacket(new PacketPlayOutOpenWindow(container.j, container.getType(),
new ChatComponentText(container.getBukkitView().getTitle())));
nmsPlayer.bV = container;
nmsPlayer.initMenu(container);
return container.getBukkitView();
}
private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) {
if (inventory instanceof SpecialEnderChest) {
return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest");
} else if (inventory instanceof SpecialPlayerInventory) {
return new OpenInventoryView(player, inventory, "container.player", "'s Inventory");
} else {
return null;
}
}
static @NotNull Containers<?> getContainers(int inventorySize) {
return switch (inventorySize) {
case 9 -> Containers.a;
case 18 -> Containers.b;
case 36 -> Containers.d; // PLAYER
case 41, 45 -> Containers.e;
case 54 -> Containers.f;
default -> Containers.c; // 9x3
};
}
@Override
public int convertToPlayerSlot(InventoryView view, int rawSlot) {
int topSize = view.getTopInventory().getSize();
if (topSize <= rawSlot) {
// Slot is not inside special inventory, use Bukkit logic.
return view.convertSlot(rawSlot);
}
// Main inventory, slots 0-26 -> 9-35
if (rawSlot < 27) {
return rawSlot + 9;
}
// Hotbar, slots 27-35 -> 0-8
if (rawSlot < 36) {
return rawSlot - 27;
}
// Armor, slots 36-39 -> 39-36
if (rawSlot < 40) {
return 36 + (39 - rawSlot);
}
// Off hand
if (rawSlot == 40) {
return 40;
}
// Drop slots, "out of inventory"
return -1;
}
}

View File

@@ -0,0 +1,341 @@
/*
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.v1_17_R1;
import com.lishid.openinv.internal.ISpecialEnderChest;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.server.level.EntityPlayer;
import net.minecraft.world.ContainerUtil;
import net.minecraft.world.IInventoryListener;
import net.minecraft.world.entity.player.AutoRecipeStackManager;
import net.minecraft.world.entity.player.EntityHuman;
import net.minecraft.world.inventory.InventoryEnderChest;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.TileEntityEnderChest;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventory;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEnderChest {
private final CraftInventory inventory;
private EntityPlayer owner;
private NonNullList<ItemStack> c;
private boolean playerOnline;
public SpecialEnderChest(final Player player, final Boolean online) {
super(PlayerDataManager.getHandle(player));
this.inventory = new CraftInventory(this);
this.owner = PlayerDataManager.getHandle(player);
this.playerOnline = online;
this.c = this.owner.getEnderChest().c;
}
@Override
public @NotNull CraftInventory getBukkitInventory() {
return inventory;
}
@Override
public boolean isInUse() {
return !this.getViewers().isEmpty();
}
@Override
public void setPlayerOffline() {
this.playerOnline = false;
}
@Override
public void setPlayerOnline(@NotNull final Player player) {
if (!this.playerOnline) {
try {
this.owner = PlayerDataManager.getHandle(player);
InventoryEnderChest enderChest = owner.getEnderChest();
for (int i = 0; i < enderChest.getSize(); ++i) {
enderChest.setItem(i, this.c.get(i));
}
this.c = enderChest.c;
enderChest.transaction.addAll(this.transaction);
} catch (Exception ignored) {}
this.playerOnline = true;
}
}
@Override
public @NotNull Player getPlayer() {
return owner.getBukkitEntity();
}
@Override
public void update() {
this.owner.getEnderChest().update();
}
@Override
public List<ItemStack> getContents() {
return this.c;
}
@Override
public void onOpen(CraftHumanEntity who) {
super.onOpen(who);
this.owner.getEnderChest().onOpen(who);
}
@Override
public void onClose(CraftHumanEntity who) {
super.onClose(who);
this.owner.getEnderChest().onClose(who);
}
@Override
public List<HumanEntity> getViewers() {
return this.owner.getEnderChest().getViewers();
}
@Override
public boolean a(EntityHuman entityhuman) {
return true;
}
@Override
public void a(TileEntityEnderChest tileentityenderchest) {
this.owner.getEnderChest().a(tileentityenderchest);
}
@Override
public boolean b(TileEntityEnderChest tileentityenderchest) {
return this.owner.getEnderChest().b(tileentityenderchest);
}
@Override
public int getMaxStackSize() {
return this.owner.getEnderChest().getMaxStackSize();
}
@Override
public void setMaxStackSize(int i) {
this.owner.getEnderChest().setMaxStackSize(i);
}
@Override
public InventoryHolder getOwner() {
return this.owner.getEnderChest().getOwner();
}
@Override
public @Nullable Location getLocation() {
return null;
}
@Override
public void a(IInventoryListener iinventorylistener) {
this.owner.getEnderChest().a(iinventorylistener);
}
@Override
public void b(IInventoryListener iinventorylistener) {
this.owner.getEnderChest().b(iinventorylistener);
}
@Override
public ItemStack getItem(int i) {
return i >= 0 && i < this.c.size() ? this.c.get(i) : ItemStack.b;
}
@Override
public ItemStack splitStack(int i, int j) {
ItemStack itemstack = ContainerUtil.a(this.c, i, j);
if (!itemstack.isEmpty()) {
this.update();
}
return itemstack;
}
@Override
public ItemStack a(ItemStack itemstack) {
ItemStack itemstack1 = itemstack.cloneItemStack();
this.d(itemstack1);
if (itemstack1.isEmpty()) {
return ItemStack.b;
} else {
this.c(itemstack1);
return itemstack1.isEmpty() ? ItemStack.b : itemstack1;
}
}
private void c(ItemStack itemstack) {
for(int i = 0; i < this.getSize(); ++i) {
ItemStack itemstack1 = this.getItem(i);
if (itemstack1.isEmpty()) {
this.setItem(i, itemstack.cloneItemStack());
itemstack.setCount(0);
return;
}
}
}
private void d(ItemStack itemstack) {
for(int i = 0; i < this.getSize(); ++i) {
ItemStack itemstack1 = this.getItem(i);
if (ItemStack.e(itemstack1, itemstack)) {
this.a(itemstack, itemstack1);
if (itemstack.isEmpty()) {
return;
}
}
}
}
private void a(ItemStack itemstack, ItemStack itemstack1) {
int i = Math.min(this.getMaxStackSize(), itemstack1.getMaxStackSize());
int j = Math.min(itemstack.getCount(), i - itemstack1.getCount());
if (j > 0) {
itemstack1.add(j);
itemstack.subtract(j);
this.update();
}
}
@Override
public ItemStack splitWithoutUpdate(int i) {
ItemStack itemstack = this.c.get(i);
if (itemstack.isEmpty()) {
return ItemStack.b;
} else {
this.c.set(i, ItemStack.b);
return itemstack;
}
}
@Override
public void setItem(int i, ItemStack itemstack) {
this.c.set(i, itemstack);
if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) {
itemstack.setCount(this.getMaxStackSize());
}
this.update();
}
@Override
public int getSize() {
return this.owner.getEnderChest().getSize();
}
@Override
public boolean isEmpty() {
return this.c.stream().allMatch(ItemStack::isEmpty);
}
@Override
public void startOpen(EntityHuman entityhuman) {
}
@Override
public void closeContainer(EntityHuman entityhuman) {
}
@Override
public boolean b(int i, ItemStack itemstack) {
return true;
}
@Override
public void clear() {
this.c.clear();
this.update();
}
@Override
public void a(AutoRecipeStackManager autorecipestackmanager) {
for (ItemStack itemstack : this.c) {
autorecipestackmanager.b(itemstack);
}
}
@Override
public List<ItemStack> f() {
List<ItemStack> list = this.c.stream().filter(Predicate.not(ItemStack::isEmpty)).collect(Collectors.toList());
this.clear();
return list;
}
@Override
public ItemStack a(Item item, int i) {
ItemStack itemstack = new ItemStack(item, 0);
for(int j = this.getSize() - 1; j >= 0; --j) {
ItemStack itemstack1 = this.getItem(j);
if (itemstack1.getItem().equals(item)) {
int k = i - itemstack.getCount();
ItemStack itemstack2 = itemstack1.cloneAndSubtract(k);
itemstack.add(itemstack2.getCount());
if (itemstack.getCount() == i) {
break;
}
}
}
if (!itemstack.isEmpty()) {
this.update();
}
return itemstack;
}
@Override
public boolean b(ItemStack itemStack) {
for (ItemStack itemStack1 : this.c) {
if (itemStack1.isEmpty() || ItemStack.e(itemStack1, itemStack) && itemStack1.getCount() < itemStack1.getMaxStackSize()) {
return true;
}
}
return false;
}
@Override
public String toString() {
return this.c.stream().filter((itemStack) -> !itemStack.isEmpty()).collect(Collectors.toList()).toString();
}
@Override
public void a(NBTTagList nbttaglist) {
for(int i = 0; i < nbttaglist.size(); ++i) {
ItemStack itemstack = ItemStack.a(nbttaglist.getCompound(i));
if (!itemstack.isEmpty()) {
this.a(itemstack);
}
}
}
}

View File

@@ -0,0 +1,777 @@
/*
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.v1_17_R1;
import com.google.common.collect.ImmutableList;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportSystemDetails;
import net.minecraft.ReportedException;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.chat.ChatMessage;
import net.minecraft.network.chat.IChatBaseComponent;
import net.minecraft.network.protocol.game.PacketPlayOutSetSlot;
import net.minecraft.server.level.EntityPlayer;
import net.minecraft.tags.Tag;
import net.minecraft.world.ContainerUtil;
import net.minecraft.world.IInventory;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EnumItemSlot;
import net.minecraft.world.entity.player.AutoRecipeStackManager;
import net.minecraft.world.entity.player.EntityHuman;
import net.minecraft.world.entity.player.PlayerInventory;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemArmor;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.IBlockData;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventory;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull;
public class SpecialPlayerInventory extends PlayerInventory implements ISpecialPlayerInventory {
private final CraftInventory inventory;
private boolean playerOnline;
private EntityHuman l;
private NonNullList<ItemStack> h;
private NonNullList<ItemStack> i;
private NonNullList<ItemStack> j;
private List<NonNullList<ItemStack>> n;
public SpecialPlayerInventory(final Player bukkitPlayer, final Boolean online) {
super(PlayerDataManager.getHandle(bukkitPlayer));
this.inventory = new CraftInventory(this);
this.playerOnline = online;
this.l = super.l;
this.h = this.l.getInventory().h;
this.i = this.l.getInventory().i;
this.j = this.l.getInventory().j;
this.n = ImmutableList.of(this.h, this.i, this.j);
}
@Override
public void setPlayerOnline(@NotNull final Player player) {
if (!this.playerOnline) {
EntityPlayer entityPlayer = PlayerDataManager.getHandle(player);
entityPlayer.getInventory().transaction.addAll(this.transaction);
this.l = entityPlayer;
for (int i = 0; i < getSize(); ++i) {
this.l.getInventory().setItem(i, getRawItem(i));
}
this.l.getInventory().k = this.k;
this.h = this.l.getInventory().h;
this.i = this.l.getInventory().i;
this.j = this.l.getInventory().j;
this.n = ImmutableList.of(this.h, this.i, this.j);
this.playerOnline = true;
}
}
@Override
public boolean a(final EntityHuman entityhuman) {
return true;
}
@Override
public @NotNull CraftInventory getBukkitInventory() {
return this.inventory;
}
@Override
public ItemStack getItem(int i) {
List<ItemStack> list = this.h;
if (i >= list.size()) {
i -= list.size();
list = this.i;
} else {
i = this.getReversedItemSlotNum(i);
}
if (i >= list.size()) {
i -= list.size();
list = this.j;
} else if (list == this.i) {
i = this.getReversedArmorSlotNum(i);
}
if (i >= list.size()) {
return ItemStack.b;
}
return list.get(i);
}
private ItemStack getRawItem(int i) {
NonNullList<ItemStack> list = null;
for (NonNullList<ItemStack> next : this.n) {
if (i < next.size()) {
list = next;
break;
}
i -= next.size();
}
return list == null ? ItemStack.b : list.get(i);
}
@Override
public IChatBaseComponent getDisplayName() {
return new ChatMessage(this.l.getName());
}
@Override
public boolean hasCustomName() {
return false;
}
private int getReversedArmorSlotNum(final int i) {
if (i == 0) {
return 3;
}
if (i == 1) {
return 2;
}
if (i == 2) {
return 1;
}
if (i == 3) {
return 0;
}
return i;
}
private int getReversedItemSlotNum(final int i) {
if (i >= 27) {
return i - 27;
}
return i + 9;
}
@Override
public int getSize() {
return 45;
}
@Override
public boolean isInUse() {
return !this.getViewers().isEmpty();
}
@Override
public void setItem(int i, final ItemStack itemstack) {
List<ItemStack> list = this.h;
if (i >= list.size()) {
i -= list.size();
list = this.i;
} else {
i = this.getReversedItemSlotNum(i);
}
if (i >= list.size()) {
i -= list.size();
list = this.j;
} else if (list == this.i) {
i = this.getReversedArmorSlotNum(i);
}
if (i >= list.size()) {
this.l.drop(itemstack, true);
return;
}
list.set(i, itemstack);
}
@Override
public void setPlayerOffline() {
this.playerOnline = false;
}
@Override
public @NotNull HumanEntity getPlayer() {
return this.l.getBukkitEntity();
}
@Override
public ItemStack splitStack(int i, final int j) {
List<ItemStack> list = this.h;
if (i >= list.size()) {
i -= list.size();
list = this.i;
} else {
i = this.getReversedItemSlotNum(i);
}
if (i >= list.size()) {
i -= list.size();
list = this.j;
} else if (list == this.i) {
i = this.getReversedArmorSlotNum(i);
}
if (i >= list.size()) {
return ItemStack.b;
}
return list.get(i).isEmpty() ? ItemStack.b : ContainerUtil.a(list, i, j);
}
@Override
public ItemStack splitWithoutUpdate(int i) {
List<ItemStack> list = this.h;
if (i >= list.size()) {
i -= list.size();
list = this.i;
} else {
i = this.getReversedItemSlotNum(i);
}
if (i >= list.size()) {
i -= list.size();
list = this.j;
} else if (list == this.i) {
i = this.getReversedArmorSlotNum(i);
}
if (i >= list.size()) {
return ItemStack.b;
}
if (!list.get(i).isEmpty()) {
ItemStack itemstack = list.get(i);
list.set(i, ItemStack.b);
return itemstack;
}
return ItemStack.b;
}
@Override
public List<ItemStack> getContents() {
return this.n.stream().flatMap(Collection::stream).collect(Collectors.toList());
}
@Override
public boolean isEmpty() {
return this.n.stream().flatMap(Collection::stream).allMatch(ItemStack::isEmpty);
}
@Override
public List<ItemStack> getArmorContents() {
return this.i;
}
@Override
public void onOpen(CraftHumanEntity who) {
this.transaction.add(who);
this.l.getInventory().transaction.add(who);
}
@Override
public void onClose(CraftHumanEntity who) {
this.transaction.remove(who);
this.l.getInventory().transaction.remove(who);
}
@Override
public List<HumanEntity> getViewers() {
return this.transaction;
}
@Override
public InventoryHolder getOwner() {
return this.l.getBukkitEntity();
}
public Location getLocation() {
return this.l.getBukkitEntity().getLocation();
}
/* Below this point largely just copied out of NMS to redirect to our overridden variables. */
@Override
public ItemStack getItemInHand() {
return d(this.k) ? this.h.get(this.k) : ItemStack.b;
}
private boolean isSimilarAndNotFull(ItemStack itemstack, ItemStack itemstack1) {
return !itemstack.isEmpty() && ItemStack.e(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize();
}
@Override
public int canHold(ItemStack itemstack) {
int remains = itemstack.getCount();
for(int i = 0; i < this.h.size(); ++i) {
ItemStack itemstack1 = this.getItem(i);
if (itemstack1.isEmpty()) {
return itemstack.getCount();
}
if (this.isSimilarAndNotFull(itemstack1, itemstack)) {
remains -= (Math.min(itemstack1.getMaxStackSize(), this.getMaxStackSize())) - itemstack1.getCount();
}
if (remains <= 0) {
return itemstack.getCount();
}
}
ItemStack offhandItemStack = this.getItem(this.h.size() + this.i.size());
if (this.isSimilarAndNotFull(offhandItemStack, itemstack)) {
remains -= (Math.min(offhandItemStack.getMaxStackSize(), this.getMaxStackSize())) - offhandItemStack.getCount();
}
return remains <= 0 ? itemstack.getCount() : itemstack.getCount() - remains;
}
@Override
public int getFirstEmptySlotIndex() {
for(int i = 0; i < this.h.size(); ++i) {
if (this.h.get(i).isEmpty()) {
return i;
}
}
return -1;
}
@Override
public void a(ItemStack itemstack) {
int i = this.b(itemstack);
if (d(i)) {
this.k = i;
} else if (i == -1) {
this.k = this.i();
if (!this.h.get(this.k).isEmpty()) {
int j = this.getFirstEmptySlotIndex();
if (j != -1) {
this.h.set(j, this.h.get(this.k));
}
}
this.h.set(this.k, itemstack);
} else {
this.c(i);
}
}
@Override
public void c(int i) {
this.k = this.i();
ItemStack itemstack = this.h.get(this.k);
this.h.set(this.k, this.h.get(i));
this.h.set(i, itemstack);
}
@Override
public int b(ItemStack itemstack) {
for (int i = 0; i < this.h.size(); ++i) {
if (!this.h.get(i).isEmpty() && ItemStack.e(itemstack, this.h.get(i))) {
return i;
}
}
return -1;
}
@Override
public int c(ItemStack itemstack) {
for (int i = 0; i < this.h.size(); ++i) {
ItemStack itemstack1 = this.h.get(i);
if (!this.h.get(i).isEmpty() && ItemStack.e(itemstack, this.h.get(i)) && !this.h.get(i).g() && !itemstack1.hasEnchantments() && !itemstack1.hasName()) {
return i;
}
}
return -1;
}
@Override
public int i() {
int i;
int j;
for (j = 0; j < 9; ++j) {
i = (this.k + j) % 9;
if (this.h.get(i).isEmpty()) {
return i;
}
}
for (j = 0; j < 9; ++j) {
i = (this.k + j) % 9;
if (!this.h.get(i).hasEnchantments()) {
return i;
}
}
return this.k;
}
@Override
public void a(double d0) {
if (d0 > 0.0D) {
d0 = 1.0D;
}
if (d0 < 0.0D) {
d0 = -1.0D;
}
this.k = (int) (this.k - d0);
while (this.k < 0) {
this.k += 9;
}
while (this.k >= 9) {
this.k -= 9;
}
}
@Override
public int a(Predicate<ItemStack> predicate, int i, IInventory iinventory) {
byte b0 = 0;
boolean flag = i == 0;
int j = b0 + ContainerUtil.a(this, predicate, i - b0, flag);
j += ContainerUtil.a(iinventory, predicate, i - j, flag);
ItemStack itemstack = this.l.bV.getCarried();
j += ContainerUtil.a(itemstack, predicate, i - j, flag);
if (itemstack.isEmpty()) {
this.l.bV.setCarried(ItemStack.b);
}
return j;
}
private int i(ItemStack itemstack) {
int i = this.firstPartial(itemstack);
if (i == -1) {
i = this.getFirstEmptySlotIndex();
}
return i == -1 ? itemstack.getCount() : this.d(i, itemstack);
}
private int d(int i, ItemStack itemstack) {
Item item = itemstack.getItem();
int j = itemstack.getCount();
ItemStack itemstack1 = this.getItem(i);
if (itemstack1.isEmpty()) {
itemstack1 = new ItemStack(item, 0);
if (itemstack.hasTag()) {
itemstack1.setTag(Objects.requireNonNull(itemstack.getTag()).clone());
}
this.setItem(i, itemstack1);
}
k = Math.min(j, itemstack1.getMaxStackSize() - itemstack1.getCount());
if (k > this.getMaxStackSize() - itemstack1.getCount()) {
k = this.getMaxStackSize() - itemstack1.getCount();
}
if (k != 0) {
j -= k;
itemstack1.add(k);
itemstack1.d(5);
}
return j;
}
@Override
public int firstPartial(ItemStack itemstack) {
if (this.isSimilarAndNotFull(this.getItem(this.k), itemstack)) {
return this.k;
} else if (this.isSimilarAndNotFull(this.getItem(40), itemstack)) {
return 40;
} else {
for(int i = 0; i < this.h.size(); ++i) {
if (this.isSimilarAndNotFull(this.h.get(i), itemstack)) {
return i;
}
}
return -1;
}
}
@Override
public void j() {
for (NonNullList<ItemStack> nonNullList : this.n) {
for (int i = 0; i < nonNullList.size(); ++i) {
if (!nonNullList.get(i).isEmpty()) {
nonNullList.get(i).a(this.l.t, this.l, i, this.k == i);
}
}
}
}
@Override
public boolean pickup(ItemStack itemStack) {
return this.c(-1, itemStack);
}
@Override
public boolean c(int i, ItemStack itemStack) {
if (itemStack.isEmpty()) {
return false;
} else {
try {
if (itemStack.g()) {
if (i == -1) {
i = this.getFirstEmptySlotIndex();
}
if (i >= 0) {
this.h.set(i, itemStack.cloneItemStack());
this.h.get(i).d(5);
itemStack.setCount(0);
return true;
} else if (this.l.getAbilities().d) {
itemStack.setCount(0);
return true;
} else {
return false;
}
} else {
int j;
do {
j = itemStack.getCount();
if (i == -1) {
itemStack.setCount(this.i(itemStack));
} else {
itemStack.setCount(this.d(i, itemStack));
}
} while(!itemStack.isEmpty() && itemStack.getCount() < j);
if (itemStack.getCount() == j && this.l.getAbilities().d) {
itemStack.setCount(0);
return true;
} else {
return itemStack.getCount() < j;
}
}
} catch (Throwable var6) {
CrashReport crashreport = CrashReport.a(var6, "Adding item to inventory");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Item being added");
crashreportsystemdetails.a("Item ID", Item.getId(itemStack.getItem()));
crashreportsystemdetails.a("Item data", itemStack.getDamage());
crashreportsystemdetails.a("Item name", () -> itemStack.getName().getString());
throw new ReportedException(crashreport);
}
}
}
@Override
public void f(ItemStack itemStack) {
this.a(itemStack, true);
}
@Override
public void a(ItemStack itemStack, boolean flag) {
while(true) {
if (!itemStack.isEmpty()) {
int i = this.firstPartial(itemStack);
if (i == -1) {
i = this.getFirstEmptySlotIndex();
}
if (i != -1) {
int j = itemStack.getMaxStackSize() - this.getItem(i).getCount();
if (this.c(i, itemStack.cloneAndSubtract(j)) && flag && this.l instanceof EntityPlayer) {
((EntityPlayer)this.l).b.sendPacket(new PacketPlayOutSetSlot(-2, i, this.getItem(i)));
}
continue;
}
this.l.drop(itemStack, false);
}
return;
}
}
@Override
public void g(ItemStack itemStack) {
for (NonNullList<ItemStack> nonNullList : this.n) {
for (int i = 0; i < nonNullList.size(); ++i) {
if (nonNullList.get(i) == itemStack) {
nonNullList.set(i, ItemStack.b);
break;
}
}
}
}
@Override
public float a(IBlockData iBlockData) {
return this.h.get(this.k).a(iBlockData);
}
@Override
public NBTTagList a(NBTTagList nbtTagList) {
NBTTagCompound nbttagcompound;
int i;
for(i = 0; i < this.h.size(); ++i) {
if (!this.h.get(i).isEmpty()) {
nbttagcompound = new NBTTagCompound();
nbttagcompound.setByte("Slot", (byte)i);
this.h.get(i).save(nbttagcompound);
nbtTagList.add(nbttagcompound);
}
}
for(i = 0; i < this.i.size(); ++i) {
if (!this.i.get(i).isEmpty()) {
nbttagcompound = new NBTTagCompound();
nbttagcompound.setByte("Slot", (byte)(i + 100));
this.i.get(i).save(nbttagcompound);
nbtTagList.add(nbttagcompound);
}
}
for(i = 0; i < this.j.size(); ++i) {
if (!this.j.get(i).isEmpty()) {
nbttagcompound = new NBTTagCompound();
nbttagcompound.setByte("Slot", (byte)(i + 150));
this.j.get(i).save(nbttagcompound);
nbtTagList.add(nbttagcompound);
}
}
return nbtTagList;
}
@Override
public void b(NBTTagList nbtTagList) {
this.h.clear();
this.i.clear();
this.j.clear();
for(int i = 0; i < nbtTagList.size(); ++i) {
NBTTagCompound nbttagcompound = nbtTagList.getCompound(i);
int j = nbttagcompound.getByte("Slot") & 255;
ItemStack itemstack = ItemStack.a(nbttagcompound);
if (!itemstack.isEmpty()) {
if (j < this.h.size()) {
this.h.set(j, itemstack);
} else if (j >= 100 && j < this.i.size() + 100) {
this.i.set(j - 100, itemstack);
} else if (j >= 150 && j < this.j.size() + 150) {
this.j.set(j - 150, itemstack);
}
}
}
}
@Override
public ItemStack e(int i) {
return this.i.get(i);
}
@Override
public void a(DamageSource damageSource, float f, int[] intArray) {
if (f > 0.0F) {
f /= 4.0F;
if (f < 1.0F) {
f = 1.0F;
}
for (int index : intArray) {
ItemStack itemstack = this.i.get(index);
if ((!damageSource.isFire() || !itemstack.getItem().w()) && itemstack.getItem() instanceof ItemArmor) {
itemstack.damage((int) f, this.l, (entityHuman) -> entityHuman.broadcastItemBreak(EnumItemSlot.a(EnumItemSlot.Function.b, index)));
}
}
}
}
@Override
public void dropContents() {
for (List<ItemStack> list : this.n) {
for (int i = 0; i < list.size(); ++i) {
ItemStack itemstack = list.get(i);
if (!itemstack.isEmpty()) {
list.set(i, ItemStack.b);
this.l.a(itemstack, true, false);
}
}
}
}
@Override
public boolean h(ItemStack itemStack) {
return this.n.stream()
.flatMap(Collection::stream)
.anyMatch(itemStack1 -> !itemStack1.isEmpty() && itemStack1.doMaterialsMatch(itemStack));
}
@Override
public boolean a(Tag<Item> tag) {
return this.n.stream()
.flatMap(Collection::stream)
.anyMatch(itemStack -> !itemStack.isEmpty() && itemStack.a(tag));
}
@Override
public void a(PlayerInventory playerInventory) {
for(int i = 0; i < this.getSize(); ++i) {
this.setItem(i, playerInventory.getItem(i));
}
this.k = playerInventory.k;
}
@Override
public void clear() {
for (List<ItemStack> list : this.n) {
list.clear();
}
}
@Override
public void a(AutoRecipeStackManager autoRecipeStackManager) {
for (ItemStack itemstack : this.h) {
autoRecipeStackManager.a(itemstack);
}
}
}

View File

@@ -1,5 +1,5 @@
<!--
~ Copyright (C) 2011-2020 lishid. All rights reserved.
~ Copyright (C) 2011-2021 lishid. All rights reserved.
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
<parent>
<artifactId>openinvparent</artifactId>
<groupId>com.lishid</groupId>
<version>4.1.7</version>
<version>4.1.8</version>
</parent>
<artifactId>openinvplugincore</artifactId>

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 Jikoo. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
* Copyright (C) 2011-2021 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,5 @@
<!--
~ Copyright (C) 2011-2020 lishid. All rights reserved.
~ Copyright (C) 2011-2021 lishid. All rights reserved.
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
<artifactId>openinvparent</artifactId>
<name>OpenInv</name>
<url>http://dev.bukkit.org/bukkit-plugins/openinv/</url>
<version>4.1.7</version>
<version>4.1.8</version>
<packaging>pom</packaging>
@@ -38,6 +38,7 @@
<module>api</module>
<module>plugin</module>
<module>internal/v1_16_R3</module>
<module>internal/v1_17_R1</module>
<module>assembly</module>
</modules>
</profile>
@@ -80,13 +81,13 @@
<artifactId>openinvapi</artifactId>
<groupId>com.lishid</groupId>
<scope>compile</scope>
<version>4.1.7</version>
<version>4.1.8</version>
</dependency>
<dependency>
<artifactId>openinvplugincore</artifactId>
<groupId>com.lishid</groupId>
<scope>compile</scope>
<version>4.1.7</version>
<version>4.1.8</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -32,7 +32,7 @@ function lookup_email_username() {
# Get a pretty list of supported Minecraft versions
function get_minecraft_versions() {
versions=$(. ./scripts/get_spigot_versions.sh)
readarray -t versions <<< "$(. ./scripts/get_spigot_versions.sh)"
for version in "${versions[@]}"; do
# Append comma if variable is set, then append version

View File

@@ -15,28 +15,21 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# TODO FIGURE OUT AND REMOVE WHEN LESS STRESS
hacky_versions=("1.16.5-R0.1-SNAPSHOT" "1.17-R0.1-SNAPSHOT")
for hacky_version in "${hacky_versions[@]}"; do
echo "$hacky_version"
done
exit 0
# Note that this script is designed for use in GitHub Actions, and is not
# particularly robust nor configurable. Run from project parent directory.
# Use a nameref as a cache - maven evaluation is pretty slow.
# Re-calling the script and relying on it to handle caching is way easier than passing around info.
declare -a spigot_versions
# We don't care about concatenation - either it's not null and we return or it's null and we instantiate.
# shellcheck disable=SC2199
if [[ ${spigot_versions[@]} ]]; then
for spigot_version in "${spigot_versions[@]}"; do
echo "$spigot_version"
done
return
fi
# Pull Spigot dependency information from Maven.
# Since we only care about Spigot versions, only check modules in the folder internal.
readarray -t modules <<< "$(mvn help:evaluate -Dexpression=project.modules -q -DforceStdout -P all | grep -oP '(?<=<string>)(internal/.*)(?=</string>)')"
declare -n versions="spigot_versions"
for module in "${modules[@]}"; do
# Get number of dependencies declared in pom of specified internal module.
max_index=$(mvn help:evaluate -Dexpression=project.dependencies -q -DforceStdout -P all -pl "$module" | grep -c "<dependency>")

View File

@@ -30,8 +30,8 @@ get_buildtools () {
wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O $buildtools
}
versions=$(. ./scripts/get_spigot_versions.sh)
echo Found Spigot dependencies: "$versions"
readarray -t versions <<< "$(. ./scripts/get_spigot_versions.sh)"
echo Found Spigot dependencies: "${versions[@]}"
for version in "${versions[@]}"; do
set -e

View File

@@ -20,7 +20,7 @@
# Parse Spigot dependency information into major Minecraft versions
function get_curseforge_minecraft_versions() {
versions=$(. ./scripts/get_spigot_versions.sh)
readarray -t versions <<< "$(. ./scripts/get_spigot_versions.sh)"
for version in "${versions[@]}"; do
# Parse Minecraft major version
@@ -38,5 +38,18 @@ function get_curseforge_minecraft_versions() {
echo "${minecraft_versions}"
}
# Modify provided changelog to not break when inserted into yaml file.
function get_yaml_safe_changelog() {
changelog=$1
# Since we're using a flow scalar, newlines need to be doubled.
echo "${changelog//
/
}"
}
minecraft_versions=$(get_curseforge_minecraft_versions)
echo "CURSEFORGE_MINECRAFT_VERSIONS=$minecraft_versions" >> "$GITHUB_ENV"
changelog=$(get_yaml_safe_changelog "$1")
printf "CURSEFORGE_CHANGELOG<<EOF\n%s\nEOF\n" "$changelog" >> "$GITHUB_ENV"