mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-13 19:51:27 +01:00
Update
This commit is contained in:
parent
212fceb142
commit
994494c5de
@ -24,7 +24,7 @@ dependencies {
|
||||
apt lombokDependency
|
||||
|
||||
// https://mvnrepository.com/artifact/com.github.jhg023/SimpleNet
|
||||
implementation group: 'com.github.jhg023', name: 'SimpleNet', version: '1.6.2'
|
||||
implementation group: 'com.github.jhg023', name: 'SimpleNet', version: '1.6.5'
|
||||
// https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
|
||||
implementation group: 'it.unimi.dsi', name: 'fastutil', version: '8.3.0'
|
||||
|
||||
|
@ -11,7 +11,6 @@ import fr.themode.minestom.event.*;
|
||||
import fr.themode.minestom.instance.InstanceContainer;
|
||||
import fr.themode.minestom.inventory.Inventory;
|
||||
import fr.themode.minestom.inventory.InventoryType;
|
||||
import fr.themode.minestom.inventory.rule.InventoryConditionResult;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.utils.Position;
|
||||
import fr.themode.minestom.utils.Vector;
|
||||
@ -22,7 +21,7 @@ public class PlayerInit {
|
||||
|
||||
static {
|
||||
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
|
||||
//instanceContainer = Main.getInstanceManager().createInstanceContainer(new File("C:\\Users\\themo\\OneDrive\\Bureau\\Minestom data"));
|
||||
//instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(new File("chunk_data"));
|
||||
instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer();
|
||||
instanceContainer.enableAutoChunkLoad(true);
|
||||
instanceContainer.setChunkGenerator(chunkGeneratorDemo);
|
||||
@ -65,8 +64,7 @@ public class PlayerInit {
|
||||
p.teleport(player.getPosition());
|
||||
}
|
||||
|
||||
ChickenCreature chickenCreature = new ChickenCreature();
|
||||
chickenCreature.refreshPosition(player.getPosition());
|
||||
ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
|
||||
chickenCreature.setInstance(player.getInstance());
|
||||
|
||||
});
|
||||
@ -101,21 +99,19 @@ public class PlayerInit {
|
||||
}*/
|
||||
|
||||
ItemStack item = new ItemStack(1, (byte) 43);
|
||||
item.setDisplayName("LE NOM PUTAIN");
|
||||
item.setDisplayName("LE NOM DE L'ITEM");
|
||||
//item.getLore().add("lol le lore");
|
||||
player.getInventory().addItemStack(item);
|
||||
|
||||
Inventory inventory = new Inventory(InventoryType.CHEST_1_ROW, "Test inventory");
|
||||
inventory.setInventoryCondition((slot, inventory1, clickedItem, cursorItem) -> {
|
||||
InventoryConditionResult result = new InventoryConditionResult(clickedItem, cursorItem);
|
||||
result.setCancel(false);
|
||||
return result;
|
||||
inventory.setInventoryCondition((slot, inventory1, inventoryConditionResult) -> {
|
||||
inventoryConditionResult.setCancel(false);
|
||||
});
|
||||
inventory.setItemStack(0, item.clone());
|
||||
|
||||
player.openInventory(inventory);
|
||||
|
||||
//getInventory().addItemStack(new ItemStack(1, (byte) 100));
|
||||
player.getInventory().addItemStack(new ItemStack(1, (byte) 100));
|
||||
|
||||
/*TeamManager teamManager = Main.getTeamManager();
|
||||
Team team = teamManager.createTeam(getUsername());
|
||||
|
@ -4,45 +4,50 @@ import fr.themode.minestom.entity.Entity;
|
||||
import fr.themode.minestom.entity.EntityCreature;
|
||||
import fr.themode.minestom.entity.EntityType;
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.entity.pathfinding.EntityPathFinder;
|
||||
import fr.themode.minestom.entity.vehicle.PlayerVehicleInformation;
|
||||
import fr.themode.minestom.utils.BlockPosition;
|
||||
import fr.themode.minestom.utils.Position;
|
||||
import fr.themode.minestom.utils.Vector;
|
||||
import net.tofweb.starlite.CellSpace;
|
||||
import net.tofweb.starlite.CostBlockManager;
|
||||
import net.tofweb.starlite.Path;
|
||||
import net.tofweb.starlite.Pathfinder;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class ChickenCreature extends EntityCreature {
|
||||
|
||||
private Path path;
|
||||
private int counter;
|
||||
private Position target;
|
||||
private long lastTeleport;
|
||||
private long wait = 500;
|
||||
private EntityPathFinder pathFinder = new EntityPathFinder(this);
|
||||
private LinkedList<BlockPosition> blockPositions;
|
||||
private Position targetPosition;
|
||||
|
||||
private float randomX = new Random().nextFloat();
|
||||
private float randomZ = new Random().nextFloat();
|
||||
public ChickenCreature(Position defaultPosition) {
|
||||
super(EntityType.CHICKEN, defaultPosition);
|
||||
setBoundingBox(0.4f, 0.7f, 0.4f);
|
||||
}
|
||||
|
||||
public ChickenCreature() {
|
||||
super(EntityType.CHICKEN);
|
||||
setBoundingBox(0.4f, 0.7f, 0.4f);
|
||||
this(new Position());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawn() {
|
||||
//Player player = MinecraftServer.getConnectionManager().getPlayer("TheMode911");
|
||||
//moveTo(player.getPosition().add(2, 0, 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
super.update();
|
||||
float speed = 0.025f;
|
||||
float speed = 0.075f;
|
||||
|
||||
if (hasPassenger()) {
|
||||
Entity passenger = getPassengers().iterator().next();
|
||||
if (passenger instanceof Player) {
|
||||
Player player = (Player) passenger;
|
||||
float sideways = player.getVehicleSideways();
|
||||
float forward = player.getVehicleForward();
|
||||
PlayerVehicleInformation vehicleInformation = player.getVehicleInformation();
|
||||
float sideways = vehicleInformation.getSideways();
|
||||
float forward = vehicleInformation.getForward();
|
||||
|
||||
boolean jump = player.isVehicleJump();
|
||||
boolean unmount = player.isVehicleUnmount();
|
||||
boolean jump = vehicleInformation.shouldJump();
|
||||
boolean unmount = vehicleInformation.shouldUnmount();
|
||||
|
||||
if (jump && isOnGround()) {
|
||||
setVelocity(new Vector(0, 6, 0), 500);
|
||||
@ -87,67 +92,37 @@ public class ChickenCreature extends EntityCreature {
|
||||
move(x, 0, z, updateView);
|
||||
}
|
||||
} else {
|
||||
move(randomX * speed, 0, randomZ * speed, true);
|
||||
//move(randomX * speed, 0, randomZ * speed, true);
|
||||
}
|
||||
|
||||
/*if (path == null) {
|
||||
System.out.println("FIND PATH");
|
||||
Player player = Main.getConnectionManager().getPlayer("Raulnil");
|
||||
if (player != null) {
|
||||
refreshPath(player);
|
||||
this.target = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == null) {
|
||||
Cell cell = path.pollFirst();
|
||||
if (cell != null) {
|
||||
this.target = new Position(cell.getX(), cell.getY(), cell.getZ());
|
||||
System.out.println("NEW TARGET");
|
||||
} else {
|
||||
path = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (path != null && target != null) {
|
||||
if (path.isEmpty()) {
|
||||
System.out.println("FINISHED PATH");
|
||||
path = null;
|
||||
} else {
|
||||
float distance = getPosition().getDistance(target);
|
||||
//System.out.println("DISTANCE: "+distance);
|
||||
if (distance <= 1) {
|
||||
System.out.println("RESET TARGET");
|
||||
target = null;
|
||||
if (blockPositions != null) {
|
||||
if (targetPosition != null) {
|
||||
float distance = getPosition().getDistance(targetPosition);
|
||||
if (distance < 0.2f) {
|
||||
setNextPathPosition();
|
||||
System.out.println("END TARGET");
|
||||
} else {
|
||||
//System.out.println("WALK");
|
||||
moveTowards(target, speed);
|
||||
moveTowards(targetPosition, speed);
|
||||
System.out.println("MOVE TOWARD " + targetPosition);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawn() {
|
||||
// setVelocity(new Vector(0, 1, 0), 3000);
|
||||
private void setNextPathPosition() {
|
||||
BlockPosition blockPosition = blockPositions.pollFirst();
|
||||
|
||||
if (blockPosition == null) {
|
||||
this.blockPositions = null;
|
||||
this.targetPosition = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.targetPosition = blockPosition.toPosition();
|
||||
}
|
||||
|
||||
private void refreshPath(Player target) {
|
||||
long time = System.currentTimeMillis();
|
||||
Position position = getPosition();
|
||||
Position targetPosition = target.getPosition();
|
||||
CellSpace space = new CellSpace();
|
||||
space.setGoalCell((int) targetPosition.getX(), (int) targetPosition.getY(), (int) targetPosition.getZ());
|
||||
space.setStartCell((int) position.getX(), (int) position.getY(), (int) position.getZ());
|
||||
|
||||
CostBlockManager blockManager = new CostBlockManager(space);
|
||||
blockManager.blockCell(space.makeNewCell(6, 6, 3));
|
||||
blockManager.blockCell(space.makeNewCell(6, 5, 4));
|
||||
|
||||
Pathfinder pathfinder = new Pathfinder(blockManager);
|
||||
|
||||
this.path = pathfinder.findPath();
|
||||
|
||||
System.out.println("PATH FINDING: " + (System.currentTimeMillis() - time) + " ms");
|
||||
private void moveTo(Position position) {
|
||||
this.blockPositions = pathFinder.getPath(position);
|
||||
setNextPathPosition();
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import fr.themode.minestom.entity.EntityManager;
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.instance.InstanceManager;
|
||||
import fr.themode.minestom.instance.block.BlockManager;
|
||||
import fr.themode.minestom.listener.PacketListenerManager;
|
||||
import fr.themode.minestom.listener.manager.PacketListenerManager;
|
||||
import fr.themode.minestom.net.ConnectionManager;
|
||||
import fr.themode.minestom.net.ConnectionUtils;
|
||||
import fr.themode.minestom.net.PacketProcessor;
|
||||
@ -35,6 +35,7 @@ public class MinecraftServer {
|
||||
private static final int MS_TO_SEC = 1000;
|
||||
public static final int TICK_MS = MS_TO_SEC / 20;
|
||||
public static final int TICK_PER_SECOND = MS_TO_SEC / TICK_MS;
|
||||
|
||||
// Networking
|
||||
private static ConnectionManager connectionManager;
|
||||
private static PacketProcessor packetProcessor;
|
||||
|
@ -87,17 +87,22 @@ public abstract class Entity implements Viewable, DataContainer {
|
||||
protected boolean noGravity;
|
||||
protected Pose pose = Pose.STANDING;
|
||||
|
||||
public Entity(int entityType) {
|
||||
public Entity(int entityType, Position defaultPosition) {
|
||||
this.id = generateId();
|
||||
this.entityType = entityType;
|
||||
this.uuid = UUID.randomUUID();
|
||||
this.position = new Position();
|
||||
this.position = defaultPosition.clone();
|
||||
|
||||
setBoundingBox(0, 0, 0);
|
||||
|
||||
entityById.put(id, this);
|
||||
}
|
||||
|
||||
public Entity(int entityType) {
|
||||
this(entityType, new Position());
|
||||
}
|
||||
|
||||
|
||||
public static Entity getEntity(int id) {
|
||||
return entityById.get(id);
|
||||
}
|
||||
@ -111,7 +116,9 @@ public abstract class Entity implements Viewable, DataContainer {
|
||||
// Called when a new instance is set
|
||||
public abstract void spawn();
|
||||
|
||||
public abstract boolean isOnGround();
|
||||
public boolean isOnGround() {
|
||||
return EntityUtils.isOnGround(this);
|
||||
}
|
||||
|
||||
public void teleport(Position position, Runnable callback) {
|
||||
if (instance == null)
|
||||
@ -250,7 +257,7 @@ public abstract class Entity implements Viewable, DataContainer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Call the abstract update method
|
||||
update();
|
||||
|
||||
// Scheduled synchronization
|
||||
@ -537,11 +544,11 @@ public abstract class Entity implements Viewable, DataContainer {
|
||||
|
||||
public boolean sameChunk(Position position) {
|
||||
Position pos = getPosition();
|
||||
int chunkX1 = ChunkUtils.getChunkX((int) pos.getX());
|
||||
int chunkZ1 = ChunkUtils.getChunkX((int) pos.getZ());
|
||||
int chunkX1 = ChunkUtils.getChunkCoordinate((int) pos.getX());
|
||||
int chunkZ1 = ChunkUtils.getChunkCoordinate((int) pos.getZ());
|
||||
|
||||
int chunkX2 = ChunkUtils.getChunkX((int) position.getX());
|
||||
int chunkZ2 = ChunkUtils.getChunkX((int) position.getZ());
|
||||
int chunkX2 = ChunkUtils.getChunkCoordinate((int) position.getX());
|
||||
int chunkZ2 = ChunkUtils.getChunkCoordinate((int) position.getZ());
|
||||
|
||||
return chunkX1 == chunkX2 && chunkZ1 == chunkZ2;
|
||||
}
|
||||
|
@ -4,14 +4,18 @@ import fr.themode.minestom.event.DeathEvent;
|
||||
import fr.themode.minestom.net.packet.server.play.*;
|
||||
import fr.themode.minestom.net.player.PlayerConnection;
|
||||
import fr.themode.minestom.utils.ChunkUtils;
|
||||
import fr.themode.minestom.utils.EntityUtils;
|
||||
import fr.themode.minestom.utils.Position;
|
||||
|
||||
// TODO pathfinding
|
||||
public abstract class EntityCreature extends LivingEntity {
|
||||
|
||||
|
||||
public EntityCreature(EntityType entityType, Position defaultPosition) {
|
||||
super(entityType.getId(), defaultPosition);
|
||||
}
|
||||
|
||||
public EntityCreature(EntityType entityType) {
|
||||
super(entityType.getId());
|
||||
this(entityType, new Position());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -79,9 +83,9 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
|
||||
@Override
|
||||
public void kill() {
|
||||
this.isDead = true;
|
||||
triggerStatus((byte) 3);
|
||||
scheduleRemove(1000); // Needed for proper death animation
|
||||
this.isDead = true; // So the entity isn't killed over and over again
|
||||
triggerStatus((byte) 3); // Start death animation status
|
||||
scheduleRemove(1000); // Needed for proper death animation (wait for it to finish before destroying the entity)
|
||||
DeathEvent deathEvent = new DeathEvent();
|
||||
callEvent(DeathEvent.class, deathEvent);
|
||||
}
|
||||
@ -94,20 +98,15 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
EntityPacket entityPacket = new EntityPacket();
|
||||
entityPacket.entityId = getEntityId();
|
||||
|
||||
SpawnMobPacket spawnMobPacket = new SpawnMobPacket();
|
||||
spawnMobPacket.entityId = getEntityId();
|
||||
spawnMobPacket.entityUuid = getUuid();
|
||||
spawnMobPacket.entityType = getEntityType();
|
||||
spawnMobPacket.position = getPosition();
|
||||
spawnMobPacket.headPitch = 0;
|
||||
SpawnLivingEntityPacket spawnLivingEntityPacket = new SpawnLivingEntityPacket();
|
||||
spawnLivingEntityPacket.entityId = getEntityId();
|
||||
spawnLivingEntityPacket.entityUuid = getUuid();
|
||||
spawnLivingEntityPacket.entityType = getEntityType();
|
||||
spawnLivingEntityPacket.position = getPosition();
|
||||
spawnLivingEntityPacket.headPitch = 0;
|
||||
|
||||
playerConnection.sendPacket(entityPacket);
|
||||
playerConnection.sendPacket(spawnMobPacket);
|
||||
playerConnection.sendPacket(spawnLivingEntityPacket);
|
||||
playerConnection.sendPacket(getMetadataPacket());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnGround() {
|
||||
return EntityUtils.isOnGround(this);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public class EntityManager {
|
||||
|
||||
private static InstanceManager instanceManager = MinecraftServer.getInstanceManager();
|
||||
|
||||
private UpdateType updateType = UpdateType.PER_CHUNK;
|
||||
private UpdateType updateType = UpdateType.PER_INSTANCE;
|
||||
private Set<Instance> instances = instanceManager.getInstances();
|
||||
|
||||
private ExecutorService entitiesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_ENTITIES, "Ms-EntitiesPool");
|
||||
@ -40,6 +40,9 @@ public class EntityManager {
|
||||
case PER_INSTANCE:
|
||||
instanceUpdate(instances, time);
|
||||
break;
|
||||
case SINGLE_THREADED:
|
||||
singleThreaded(instances, time);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
@ -141,6 +144,33 @@ public class EntityManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Single threaded update (like the notchian server)
|
||||
*
|
||||
* @param instances
|
||||
* @param time
|
||||
*/
|
||||
private void singleThreaded(Set<Instance> instances, long time) {
|
||||
for (Instance instance : instances) {
|
||||
Set<Player> players = instance.getPlayers();
|
||||
Set<EntityCreature> creatures = instance.getCreatures();
|
||||
Set<ObjectEntity> objects = instance.getObjectEntities();
|
||||
|
||||
if (!players.isEmpty() || !creatures.isEmpty() || !objects.isEmpty()) {
|
||||
for (Player player : players) {
|
||||
player.tick(time);
|
||||
}
|
||||
for (EntityCreature creature : creatures) {
|
||||
creature.tick(time);
|
||||
}
|
||||
for (ObjectEntity objectEntity : objects) {
|
||||
objectEntity.tick(time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public UpdateType getUpdateType() {
|
||||
return updateType;
|
||||
}
|
||||
@ -156,6 +186,7 @@ public class EntityManager {
|
||||
public enum UpdateType {
|
||||
PER_CHUNK,
|
||||
PER_ENTITY_TYPE,
|
||||
PER_INSTANCE;
|
||||
PER_INSTANCE,
|
||||
SINGLE_THREADED;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package fr.themode.minestom.entity;
|
||||
|
||||
import fr.themode.minestom.net.packet.server.play.SpawnExperienceOrbPacket;
|
||||
import fr.themode.minestom.net.player.PlayerConnection;
|
||||
import fr.themode.minestom.utils.EntityUtils;
|
||||
|
||||
public class ExperienceOrb extends Entity {
|
||||
|
||||
@ -25,11 +24,6 @@ public class ExperienceOrb extends Entity {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnGround() {
|
||||
return EntityUtils.isOnGround(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewer(Player player) {
|
||||
PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
|
@ -9,6 +9,7 @@ import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.net.packet.server.play.CollectItemPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityAnimationPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityPropertiesPacket;
|
||||
import fr.themode.minestom.utils.Position;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
@ -29,12 +30,16 @@ public abstract class LivingEntity extends Entity {
|
||||
private boolean activeHand;
|
||||
private boolean riptideSpinAttack;
|
||||
|
||||
public LivingEntity(int entityType) {
|
||||
super(entityType);
|
||||
public LivingEntity(int entityType, Position defaultPosition) {
|
||||
super(entityType, defaultPosition);
|
||||
setupAttributes();
|
||||
setGravity(0.02f);
|
||||
}
|
||||
|
||||
public LivingEntity(int entityType) {
|
||||
this(entityType, new Position());
|
||||
}
|
||||
|
||||
public abstract void kill();
|
||||
|
||||
@Override
|
||||
|
@ -1,8 +1,7 @@
|
||||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.themode.minestom.net.packet.server.play.SpawnObjectPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.SpawnEntityPacket;
|
||||
import fr.themode.minestom.net.player.PlayerConnection;
|
||||
import fr.themode.minestom.utils.EntityUtils;
|
||||
|
||||
public abstract class ObjectEntity extends Entity {
|
||||
|
||||
@ -16,13 +15,13 @@ public abstract class ObjectEntity extends Entity {
|
||||
public void addViewer(Player player) {
|
||||
PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
|
||||
SpawnObjectPacket spawnObjectPacket = new SpawnObjectPacket();
|
||||
spawnObjectPacket.entityId = getEntityId();
|
||||
spawnObjectPacket.uuid = getUuid();
|
||||
spawnObjectPacket.type = getEntityType();
|
||||
spawnObjectPacket.position = getPosition();
|
||||
spawnObjectPacket.data = getObjectData();
|
||||
playerConnection.sendPacket(spawnObjectPacket);
|
||||
SpawnEntityPacket spawnEntityPacket = new SpawnEntityPacket();
|
||||
spawnEntityPacket.entityId = getEntityId();
|
||||
spawnEntityPacket.uuid = getUuid();
|
||||
spawnEntityPacket.type = getEntityType();
|
||||
spawnEntityPacket.position = getPosition();
|
||||
spawnEntityPacket.data = getObjectData();
|
||||
playerConnection.sendPacket(spawnEntityPacket);
|
||||
playerConnection.sendPacket(getMetadataPacket());
|
||||
super.addViewer(player); // Add player to viewers list and send velocity packet
|
||||
}
|
||||
@ -32,9 +31,4 @@ public abstract class ObjectEntity extends Entity {
|
||||
super.removeViewer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnGround() {
|
||||
return EntityUtils.isOnGround(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import fr.themode.minestom.bossbar.BossBar;
|
||||
import fr.themode.minestom.chat.Chat;
|
||||
import fr.themode.minestom.collision.BoundingBox;
|
||||
import fr.themode.minestom.entity.property.Attribute;
|
||||
import fr.themode.minestom.entity.vehicle.PlayerVehicleInformation;
|
||||
import fr.themode.minestom.event.*;
|
||||
import fr.themode.minestom.instance.Chunk;
|
||||
import fr.themode.minestom.instance.Instance;
|
||||
@ -79,10 +80,7 @@ public class Player extends LivingEntity {
|
||||
private float fieldViewModifier = 0.1f;
|
||||
|
||||
// Vehicle
|
||||
private float sideways;
|
||||
private float forward;
|
||||
private boolean jump;
|
||||
private boolean unmount;
|
||||
private PlayerVehicleInformation vehicleInformation;
|
||||
|
||||
public Player(UUID uuid, String username, PlayerConnection playerConnection) {
|
||||
super(100);
|
||||
@ -658,22 +656,6 @@ public class Player extends LivingEntity {
|
||||
return Collections.unmodifiableSet(bossBars);
|
||||
}
|
||||
|
||||
public float getVehicleSideways() {
|
||||
return sideways;
|
||||
}
|
||||
|
||||
public float getVehicleForward() {
|
||||
return forward;
|
||||
}
|
||||
|
||||
public boolean isVehicleJump() {
|
||||
return jump;
|
||||
}
|
||||
|
||||
public boolean isVehicleUnmount() {
|
||||
return unmount;
|
||||
}
|
||||
|
||||
public void openInventory(Inventory inventory) {
|
||||
if (inventory == null)
|
||||
throw new IllegalArgumentException("Inventory cannot be null, use Player#closeInventory() to close current");
|
||||
@ -798,6 +780,10 @@ public class Player extends LivingEntity {
|
||||
refreshAbilities();
|
||||
}
|
||||
|
||||
public PlayerVehicleInformation getVehicleInformation() {
|
||||
return vehicleInformation;
|
||||
}
|
||||
|
||||
private void refreshAbilities() {
|
||||
PlayerAbilitiesPacket playerAbilitiesPacket = new PlayerAbilitiesPacket();
|
||||
playerAbilitiesPacket.invulnerable = invulnerable;
|
||||
@ -866,10 +852,7 @@ public class Player extends LivingEntity {
|
||||
}
|
||||
|
||||
public void refreshVehicleSteer(float sideways, float forward, boolean jump, boolean unmount) {
|
||||
this.sideways = sideways;
|
||||
this.forward = forward;
|
||||
this.jump = jump;
|
||||
this.unmount = unmount;
|
||||
this.vehicleInformation.refresh(sideways, forward, jump, unmount);
|
||||
}
|
||||
|
||||
public int getChunkRange() {
|
||||
|
@ -0,0 +1,57 @@
|
||||
package fr.themode.minestom.entity.pathfinding;
|
||||
|
||||
import fr.themode.minestom.entity.Entity;
|
||||
import fr.themode.minestom.utils.BlockPosition;
|
||||
import fr.themode.minestom.utils.Position;
|
||||
import net.tofweb.starlite.*;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class EntityPathFinder {
|
||||
|
||||
private Entity entity;
|
||||
|
||||
public EntityPathFinder(Entity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public LinkedList<BlockPosition> getPath2(Position target) {
|
||||
BlockPosition entityPosition = entity.getPosition().toBlockPosition();
|
||||
BlockPosition targetPosition = target.toBlockPosition();
|
||||
|
||||
LinkedList<BlockPosition> blockPositions = new LinkedList<>();
|
||||
|
||||
CellSpace cellSpace = new CellSpace();
|
||||
cellSpace.setGoalCell(targetPosition.getX(), targetPosition.getY(), targetPosition.getZ());
|
||||
cellSpace.setStartCell(entityPosition.getX(), entityPosition.getY(), entityPosition.getZ());
|
||||
|
||||
|
||||
CostBlockManager costBlockManager = new CostBlockManager(cellSpace);
|
||||
// TODO add blocked cells
|
||||
|
||||
|
||||
Pathfinder pathfinder = new Pathfinder(costBlockManager);
|
||||
|
||||
Path path = pathfinder.findPath();
|
||||
|
||||
for (Cell cell : path) {
|
||||
blockPositions.add(new BlockPosition(cell.getX(), cell.getY(), cell.getZ()));
|
||||
}
|
||||
|
||||
return blockPositions;
|
||||
}
|
||||
|
||||
public LinkedList<BlockPosition> getPath(Position target) {
|
||||
LinkedList<BlockPosition> blockPositions = new LinkedList<>();
|
||||
|
||||
JPS jps = new JPS(entity.getInstance(), entity.getPosition(), target);
|
||||
|
||||
for (Position position : jps.getPath()) {
|
||||
blockPositions.add(position.toBlockPosition());
|
||||
}
|
||||
|
||||
System.out.println("test: " + blockPositions.size());
|
||||
return blockPositions;
|
||||
}
|
||||
|
||||
}
|
297
src/main/java/fr/themode/minestom/entity/pathfinding/JPS.java
Normal file
297
src/main/java/fr/themode/minestom/entity/pathfinding/JPS.java
Normal file
@ -0,0 +1,297 @@
|
||||
package fr.themode.minestom.entity.pathfinding;
|
||||
|
||||
import fr.themode.minestom.instance.Instance;
|
||||
import fr.themode.minestom.utils.BlockPosition;
|
||||
import fr.themode.minestom.utils.Position;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class JPS {
|
||||
|
||||
private Instance instance;
|
||||
private Position startPosition;
|
||||
private Position endPosition;
|
||||
|
||||
private Node startNode;
|
||||
private Node endNode;
|
||||
|
||||
private boolean pathFound = false;
|
||||
private ArrayList<Node> checkedNodes = new ArrayList<>();
|
||||
private ArrayList<Node> uncheckedNodes = new ArrayList<>();
|
||||
|
||||
private int maxNodeTests;
|
||||
private boolean canClimbLadders;
|
||||
private double maxFallDistance;
|
||||
|
||||
// ---
|
||||
// CONSTRUCTORS
|
||||
// ---
|
||||
|
||||
public JPS(Instance instance, Position start, Position end, int maxNodeTests, boolean canClimbLadders, double maxFallDistance) {
|
||||
this.instance = instance;
|
||||
this.startPosition = start;
|
||||
this.endPosition = end;
|
||||
|
||||
startNode = new Node(startPosition, 0, null);
|
||||
endNode = new Node(endPosition, 0, null);
|
||||
|
||||
this.maxNodeTests = maxNodeTests;
|
||||
this.canClimbLadders = canClimbLadders;
|
||||
this.maxFallDistance = maxFallDistance;
|
||||
}
|
||||
|
||||
public JPS(Instance instance, Position start, Position end) {
|
||||
this(instance, start, end, 1000, false, 1);
|
||||
}
|
||||
|
||||
// ---
|
||||
// PATHFINDING
|
||||
// ---
|
||||
|
||||
public Position[] getPath() {
|
||||
// check if player could stand at start and endpoint, if not return empty path
|
||||
if (!(canStandAt(startPosition) && canStandAt(endPosition)))
|
||||
return new Position[0];
|
||||
|
||||
// time for benchmark
|
||||
long nsStart = System.nanoTime();
|
||||
|
||||
uncheckedNodes.add(startNode);
|
||||
|
||||
// cycle through untested nodes until a exit condition is fulfilled
|
||||
while (checkedNodes.size() < maxNodeTests && pathFound == false && uncheckedNodes.size() > 0) {
|
||||
Node n = uncheckedNodes.get(0);
|
||||
for (Node nt : uncheckedNodes)
|
||||
if (nt.getEstimatedFinalExpense() < n.getEstimatedFinalExpense())
|
||||
n = nt;
|
||||
|
||||
if (n.estimatedExpenseLeft < 1) {
|
||||
pathFound = true;
|
||||
endNode = n;
|
||||
|
||||
// print information about last node
|
||||
//Bukkit.broadcastMessage(uncheckedNodes.size() + "uc " + checkedNodes.size() + "c " + round(n.expense) + "cne " + round(n.getEstimatedFinalExpense()) + "cnee ");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
n.getReachablePositions();
|
||||
uncheckedNodes.remove(n);
|
||||
checkedNodes.add(n);
|
||||
}
|
||||
|
||||
// returning if no path has been found
|
||||
if (!pathFound) {
|
||||
float duration = (System.nanoTime() - nsStart) / 1000000f;
|
||||
System.out.println("TOOK " + duration + " ms not found!");
|
||||
|
||||
return new Position[0];
|
||||
}
|
||||
|
||||
// get length of path to create array, 1 because of start
|
||||
int length = 1;
|
||||
Node n = endNode;
|
||||
while (n.origin != null) {
|
||||
n = n.origin;
|
||||
length++;
|
||||
}
|
||||
|
||||
Position[] Positions = new Position[length];
|
||||
|
||||
//fill Array
|
||||
n = endNode;
|
||||
for (int i = length - 1; i > 0; i--) {
|
||||
Positions[i] = n.getPosition();
|
||||
n = n.origin;
|
||||
}
|
||||
|
||||
Positions[0] = startNode.getPosition();
|
||||
|
||||
// outputting benchmark result
|
||||
float duration = (System.nanoTime() - nsStart) / 1000000f;
|
||||
System.out.println("TOOK " + duration + " ms!");
|
||||
|
||||
return Positions;
|
||||
}
|
||||
|
||||
private Node getNode(Position loc) {
|
||||
Node test = new Node(loc, 0, null);
|
||||
|
||||
for (Node n : checkedNodes)
|
||||
if (n.x == test.x && n.y == test.y && n.z == test.z)
|
||||
return n;
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
// ---
|
||||
// NODE
|
||||
// ---
|
||||
|
||||
public boolean isObstructed(Position loc) {
|
||||
//if(loc.getBlock().getType().isSolid())
|
||||
//return true;
|
||||
short blockId = instance.getBlockId(loc.toBlockPosition());
|
||||
return blockId != 0;
|
||||
}
|
||||
|
||||
// ---
|
||||
// CHECKS
|
||||
// ---
|
||||
|
||||
public boolean canStandAt(Position loc) {
|
||||
return !(isObstructed(loc) || isObstructed(loc.clone().add(0, 1, 0)) || !isObstructed(loc.clone().add(0, -1, 0)));
|
||||
}
|
||||
|
||||
public double distanceTo(Position loc1, Position loc2) {
|
||||
double deltaX = Math.abs(loc1.getX() - loc2.getX());
|
||||
double deltaY = Math.abs(loc1.getY() - loc2.getY());
|
||||
double deltaZ = Math.abs(loc1.getZ() - loc2.getZ());
|
||||
|
||||
// euclidean distance
|
||||
double distance2d = Math.sqrt(deltaX * deltaX + deltaZ * deltaZ);
|
||||
double distance3d = Math.sqrt(distance2d * distance2d + deltaY * deltaY);
|
||||
|
||||
return distance3d;
|
||||
|
||||
// manhattan distance
|
||||
//return deltaX + deltaY + deltaZ;
|
||||
}
|
||||
|
||||
// ---
|
||||
// UTIL
|
||||
// ---
|
||||
|
||||
public double round(double d) {
|
||||
return ((int) (d * 100)) / 100d;
|
||||
}
|
||||
|
||||
public class Node {
|
||||
public int x;
|
||||
public int y;
|
||||
public int z;
|
||||
public Node origin;
|
||||
public double expense;
|
||||
private Position position;
|
||||
private BlockPosition blockPosition;
|
||||
private double estimatedExpenseLeft = -1;
|
||||
|
||||
// ---
|
||||
// CONSTRUCTORS
|
||||
// ---
|
||||
|
||||
public Node(Position loc, double expense, Node origin) {
|
||||
position = loc;
|
||||
blockPosition = loc.toBlockPosition();
|
||||
x = blockPosition.getX();
|
||||
y = blockPosition.getY();
|
||||
z = blockPosition.getZ();
|
||||
|
||||
this.origin = origin;
|
||||
|
||||
this.expense = expense;
|
||||
}
|
||||
|
||||
// ---
|
||||
// GETTERS
|
||||
// ---
|
||||
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public double getEstimatedFinalExpense() {
|
||||
if (estimatedExpenseLeft == -1)
|
||||
estimatedExpenseLeft = distanceTo(position, endPosition);
|
||||
|
||||
return expense + 1.1 * estimatedExpenseLeft;
|
||||
}
|
||||
|
||||
// ---
|
||||
// PATHFINDING
|
||||
// ---
|
||||
|
||||
public void getReachablePositions() {
|
||||
//trying to get all possibly walkable blocks
|
||||
for (int x = -1; x <= 1; x++)
|
||||
for (int z = -1; z <= 1; z++)
|
||||
if (!(x == 0 && z == 0) && x * z == 0) {
|
||||
Position loc = new Position(blockPosition.getX() + x, blockPosition.getY(), blockPosition.getZ() + z);
|
||||
|
||||
// usual unchanged y
|
||||
if (canStandAt(loc))
|
||||
reachNode(loc, expense + 1);
|
||||
|
||||
// one block up
|
||||
if (!isObstructed(loc.clone().add(-x, 2, -z))) // block above current tile, thats why subtracting x and z
|
||||
{
|
||||
Position nLoc = loc.clone().add(0, 1, 0);
|
||||
if (canStandAt(nLoc))
|
||||
reachNode(nLoc, expense + 1.4142);
|
||||
}
|
||||
|
||||
// one block down or falling multiple blocks down
|
||||
if (!isObstructed(loc.clone().add(0, 1, 0))) // block above possible new tile
|
||||
{
|
||||
Position nLoc = loc.clone().add(0, -1, 0);
|
||||
if (canStandAt(nLoc)) // one block down
|
||||
reachNode(nLoc, expense + 1.4142);
|
||||
else if (!isObstructed(nLoc) && !isObstructed(nLoc.clone().add(0, 1, 0))) // fall
|
||||
{
|
||||
int drop = 1;
|
||||
while (drop <= maxFallDistance && !isObstructed(loc.clone().add(0, -drop, 0))) {
|
||||
Position locF = loc.clone().add(0, -drop, 0);
|
||||
if (canStandAt(locF)) {
|
||||
Node fallNode = addFallNode(loc, expense + 1);
|
||||
fallNode.reachNode(locF, expense + drop * 2);
|
||||
}
|
||||
|
||||
drop++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ladder
|
||||
/*if(canClimbLadders)
|
||||
if(loc.clone().add(-x, 0, -z).getBlock().getType() == Material.LADDER)
|
||||
{
|
||||
Position nLoc = loc.clone().add(-x, 0, -z);
|
||||
int up = 1;
|
||||
while(nLoc.clone().add(0, up, 0).getBlock().getType() == Material.LADDER)
|
||||
up++;
|
||||
|
||||
reachNode(nLoc.clone().add(0, up, 0), expense + up * 2);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
public void reachNode(Position locThere, double expenseThere) {
|
||||
Node nt = getNode(locThere);
|
||||
|
||||
if (nt.origin == null && nt != startNode) // new node
|
||||
{
|
||||
nt.expense = expenseThere;
|
||||
nt.origin = this;
|
||||
|
||||
uncheckedNodes.add(nt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// no new node
|
||||
if (nt.expense > expenseThere) // this way is faster to go there
|
||||
{
|
||||
nt.expense = expenseThere;
|
||||
nt.origin = this;
|
||||
}
|
||||
}
|
||||
|
||||
public Node addFallNode(Position loc, double expense) {
|
||||
Node n = new Node(loc, expense, this);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package fr.themode.minestom.entity.vehicle;
|
||||
|
||||
public class PlayerVehicleInformation {
|
||||
|
||||
private float sideways;
|
||||
private float forward;
|
||||
private boolean jump;
|
||||
private boolean unmount;
|
||||
|
||||
public float getSideways() {
|
||||
return sideways;
|
||||
}
|
||||
|
||||
public float getForward() {
|
||||
return forward;
|
||||
}
|
||||
|
||||
public boolean shouldJump() {
|
||||
return jump;
|
||||
}
|
||||
|
||||
public boolean shouldUnmount() {
|
||||
return unmount;
|
||||
}
|
||||
|
||||
public void refresh(float sideways, float forward, boolean jump, boolean unmount) {
|
||||
this.sideways = sideways;
|
||||
this.forward = forward;
|
||||
this.jump = jump;
|
||||
this.unmount = unmount;
|
||||
}
|
||||
}
|
@ -18,12 +18,20 @@ public class ChunkLoaderIO {
|
||||
}
|
||||
|
||||
private static String getChunkFileName(int chunkX, int chunkZ) {
|
||||
return "chunk." + chunkX + "." + chunkZ + ".data";
|
||||
return "chunk_" + chunkX + "." + chunkZ + ".data";
|
||||
}
|
||||
|
||||
protected void saveChunk(Chunk chunk, File folder, Runnable callback) {
|
||||
IOManager.submit(() -> {
|
||||
File chunkFile = getChunkFile(chunk.getChunkX(), chunk.getChunkZ(), folder);
|
||||
if (!chunkFile.exists()) {
|
||||
try {
|
||||
chunkFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(chunkFile)) {
|
||||
byte[] data = chunk.getSerializedData();
|
||||
fos.write(CompressionUtils.getCompressedData(data));
|
||||
|
@ -159,8 +159,8 @@ public abstract class Instance implements BlockModifier, DataContainer {
|
||||
}
|
||||
|
||||
public Chunk getChunkAt(double x, double z) {
|
||||
int chunkX = ChunkUtils.getChunkX((int) x);
|
||||
int chunkZ = ChunkUtils.getChunkX((int) z);
|
||||
int chunkX = ChunkUtils.getChunkCoordinate((int) x);
|
||||
int chunkZ = ChunkUtils.getChunkCoordinate((int) z);
|
||||
return getChunk(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,9 @@ public class InstanceManager {
|
||||
private Set<Instance> instances = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
public InstanceContainer createInstanceContainer(File folder) {
|
||||
if (folder != null && !folder.exists())
|
||||
folder.mkdir();
|
||||
|
||||
InstanceContainer instance = new InstanceContainer(UUID.randomUUID(), folder);
|
||||
this.instances.add(instance);
|
||||
return instance;
|
||||
|
@ -9,7 +9,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BlockBatch implements IBatch {
|
||||
public class BlockBatch implements InstanceBatch {
|
||||
|
||||
private InstanceContainer instance;
|
||||
|
||||
|
@ -13,7 +13,7 @@ import java.util.function.Consumer;
|
||||
/**
|
||||
* Use chunk coordinate (0-16) instead of world's
|
||||
*/
|
||||
public class ChunkBatch implements IBatch {
|
||||
public class ChunkBatch implements InstanceBatch {
|
||||
|
||||
private InstanceContainer instance;
|
||||
private Chunk chunk;
|
||||
|
@ -6,7 +6,7 @@ import fr.themode.minestom.utils.thread.MinestomThread;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public interface IBatch extends BlockModifier {
|
||||
public interface InstanceBatch extends BlockModifier {
|
||||
|
||||
ExecutorService batchesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_BLOCK_BATCH, "Ms-BlockBatchPool");
|
||||
|
@ -2,6 +2,8 @@ package fr.themode.minestom.inventory;
|
||||
|
||||
import fr.themode.minestom.Viewable;
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.inventory.click.InventoryClickProcessor;
|
||||
import fr.themode.minestom.inventory.click.InventoryClickResult;
|
||||
import fr.themode.minestom.inventory.rule.InventoryCondition;
|
||||
import fr.themode.minestom.inventory.rule.InventoryConditionResult;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
@ -31,6 +33,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
|
||||
private ConcurrentHashMap<Player, ItemStack> cursorPlayersItem = new ConcurrentHashMap<>();
|
||||
|
||||
private InventoryCondition inventoryCondition;
|
||||
private InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
|
||||
|
||||
public Inventory(InventoryType inventoryType, String title) {
|
||||
this.id = generateId();
|
||||
@ -154,150 +157,43 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
|
||||
@Override
|
||||
public void leftClick(Player player, int slot) {
|
||||
PlayerInventory playerInventory = player.getInventory();
|
||||
ItemStack cursorItem = getCursorItem(player);
|
||||
ItemStack cursor = getCursorItem(player);
|
||||
boolean isInWindow = isClickInWindow(slot);
|
||||
ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(slot, offset);
|
||||
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, this, clicked, cursorItem);
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
|
||||
if (result.isCancel()) {
|
||||
System.out.println(clicked.getMaterial() + " + " + cursorItem.getMaterial());
|
||||
if (isInWindow) {
|
||||
setItemStack(slot, clicked);
|
||||
setCursorPlayerItem(player, cursorItem);
|
||||
} else {
|
||||
playerInventory.setItemStack(slot, offset, clicked);
|
||||
setCursorPlayerItem(player, cursorItem);
|
||||
}
|
||||
// Refresh client window
|
||||
player.getPlayerConnection().sendPacket(getWindowItemsPacket());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// End condition
|
||||
InventoryClickResult clickResult = clickProcessor.leftClick(getInventoryCondition(), slot, clicked, cursor);
|
||||
|
||||
if (cursorItem.isAir() && clicked.isAir())
|
||||
return;
|
||||
|
||||
ItemStack resultCursor;
|
||||
ItemStack resultClicked;
|
||||
StackingRule cursorRule = cursorItem.getStackingRule();
|
||||
StackingRule clickedRule = clicked.getStackingRule();
|
||||
|
||||
if (cursorRule.canBeStacked(cursorItem, clicked)) {
|
||||
|
||||
resultCursor = cursorItem.clone();
|
||||
resultClicked = clicked.clone();
|
||||
|
||||
int totalAmount = cursorRule.getAmount(cursorItem) + clickedRule.getAmount(clicked);
|
||||
|
||||
if (!clickedRule.canApply(resultClicked, totalAmount)) {
|
||||
resultCursor = cursorRule.apply(resultCursor, totalAmount - cursorRule.getMaxSize());
|
||||
resultClicked = clickedRule.apply(resultClicked, clickedRule.getMaxSize());
|
||||
} else {
|
||||
resultCursor = cursorRule.apply(resultCursor, 0);
|
||||
resultClicked = clickedRule.apply(resultClicked, totalAmount);
|
||||
}
|
||||
} else {
|
||||
resultCursor = clicked.clone();
|
||||
resultClicked = cursorItem.clone();
|
||||
}
|
||||
if (clickResult.doRefresh())
|
||||
player.getPlayerConnection().sendPacket(getWindowItemsPacket());
|
||||
|
||||
if (isInWindow) {
|
||||
setItemStack(slot, resultClicked);
|
||||
setCursorPlayerItem(player, resultCursor);
|
||||
setItemStack(slot, clickResult.getClicked());
|
||||
setCursorPlayerItem(player, clickResult.getCursor());
|
||||
} else {
|
||||
playerInventory.setItemStack(slot, offset, resultClicked);
|
||||
setCursorPlayerItem(player, resultCursor);
|
||||
playerInventory.setItemStack(slot, offset, clickResult.getClicked());
|
||||
setCursorPlayerItem(player, clickResult.getCursor());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rightClick(Player player, int slot) {
|
||||
PlayerInventory playerInventory = player.getInventory();
|
||||
ItemStack cursorItem = getCursorItem(player);
|
||||
ItemStack cursor = getCursorItem(player);
|
||||
boolean isInWindow = isClickInWindow(slot);
|
||||
ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(slot, offset);
|
||||
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, this, clicked, cursorItem);
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
InventoryClickResult clickResult = clickProcessor.rightClick(getInventoryCondition(), slot, clicked, cursor);
|
||||
|
||||
if (result.isCancel()) {
|
||||
System.out.println(clicked.getMaterial() + " + " + cursorItem.getMaterial());
|
||||
if (isInWindow) {
|
||||
setItemStack(slot, clicked);
|
||||
setCursorPlayerItem(player, cursorItem);
|
||||
} else {
|
||||
playerInventory.setItemStack(slot, offset, clicked);
|
||||
setCursorPlayerItem(player, cursorItem);
|
||||
}
|
||||
// Refresh client window
|
||||
player.getPlayerConnection().sendPacket(getWindowItemsPacket());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// End condition
|
||||
|
||||
if (cursorItem.isAir() && clicked.isAir())
|
||||
return;
|
||||
|
||||
StackingRule cursorRule = cursorItem.getStackingRule();
|
||||
StackingRule clickedRule = clicked.getStackingRule();
|
||||
|
||||
ItemStack resultCursor;
|
||||
ItemStack resultClicked;
|
||||
|
||||
if (cursorRule.canBeStacked(cursorItem, clicked)) {
|
||||
resultClicked = clicked.clone();
|
||||
int amount = clickedRule.getAmount(clicked) + 1;
|
||||
|
||||
if (!cursorRule.canApply(cursorItem, amount)) {
|
||||
return;
|
||||
} else {
|
||||
resultCursor = cursorItem.clone();
|
||||
resultCursor = cursorRule.apply(resultCursor, cursorRule.getAmount(resultCursor) - 1);
|
||||
resultClicked = clickedRule.apply(resultClicked, amount);
|
||||
}
|
||||
} else {
|
||||
if (cursorItem.isAir()) {
|
||||
int amount = (int) Math.ceil((double) clicked.getAmount() / 2d);
|
||||
|
||||
resultCursor = clicked.clone();
|
||||
resultCursor = cursorRule.apply(resultCursor, amount);
|
||||
|
||||
resultClicked = clicked.clone();
|
||||
resultClicked = clickedRule.apply(resultClicked, clicked.getAmount() / 2);
|
||||
} else {
|
||||
if (clicked.isAir()) {
|
||||
int amount = cursorItem.getAmount();
|
||||
|
||||
resultCursor = cursorItem.clone();
|
||||
resultCursor = cursorRule.apply(resultCursor, amount - 1);
|
||||
|
||||
resultClicked = cursorItem.clone();
|
||||
resultClicked = clickedRule.apply(resultClicked, 1);
|
||||
} else {
|
||||
resultCursor = clicked.clone();
|
||||
resultClicked = cursorItem.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clickResult.doRefresh())
|
||||
player.getPlayerConnection().sendPacket(getWindowItemsPacket());
|
||||
|
||||
if (isInWindow) {
|
||||
setItemStack(slot, resultClicked);
|
||||
setCursorPlayerItem(player, resultCursor);
|
||||
setItemStack(slot, clickResult.getClicked());
|
||||
setCursorPlayerItem(player, clickResult.getCursor());
|
||||
} else {
|
||||
playerInventory.setItemStack(slot, offset, resultClicked);
|
||||
setCursorPlayerItem(player, resultCursor);
|
||||
playerInventory.setItemStack(slot, offset, clickResult.getClicked());
|
||||
setCursorPlayerItem(player, clickResult.getCursor());
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,12 +207,14 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, this, clicked, cursorItem);
|
||||
InventoryConditionResult result = new InventoryConditionResult(clicked, cursorItem);
|
||||
inventoryCondition.accept(slot, null, result);
|
||||
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
|
||||
if (result.isCancel()) {
|
||||
System.out.println(clicked.getMaterial() + " + " + cursorItem.getMaterial());
|
||||
//System.out.println(clicked.getMaterial() + " + " + cursorItem.getMaterial());
|
||||
if (isInWindow) {
|
||||
setItemStack(slot, clicked);
|
||||
setCursorPlayerItem(player, cursorItem);
|
||||
@ -412,61 +310,19 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
|
||||
PlayerInventory playerInventory = player.getInventory();
|
||||
boolean isInWindow = isClickInWindow(slot);
|
||||
ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(slot, offset);
|
||||
ItemStack cursorItem = getCursorItem(player);
|
||||
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, this, clicked, cursorItem);
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
|
||||
if (result.isCancel()) {
|
||||
System.out.println(clicked.getMaterial() + " + " + cursorItem.getMaterial());
|
||||
if (isInWindow) {
|
||||
setItemStack(slot, clicked);
|
||||
setCursorPlayerItem(player, cursorItem);
|
||||
} else {
|
||||
playerInventory.setItemStack(slot, offset, clicked);
|
||||
setCursorPlayerItem(player, cursorItem);
|
||||
}
|
||||
// Refresh client window
|
||||
player.getPlayerConnection().sendPacket(getWindowItemsPacket());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// End condition
|
||||
|
||||
if (!cursorItem.isAir())
|
||||
return;
|
||||
|
||||
ItemStack heldItem = playerInventory.getItemStack(key);
|
||||
|
||||
ItemStack resultClicked;
|
||||
ItemStack resultHeld;
|
||||
InventoryClickResult clickResult = clickProcessor.changeHeld(getInventoryCondition(), slot, clicked, heldItem);
|
||||
|
||||
if (clicked.isAir()) {
|
||||
// Set held item [key] to slot
|
||||
resultClicked = ItemStack.AIR_ITEM;
|
||||
resultHeld = clicked.clone();
|
||||
} else {
|
||||
if (heldItem.isAir()) {
|
||||
// if held item [key] is air then set clicked to held
|
||||
resultClicked = ItemStack.AIR_ITEM;
|
||||
resultHeld = clicked.clone();
|
||||
} else {
|
||||
// Otherwise replace held item and held
|
||||
resultClicked = heldItem.clone();
|
||||
resultHeld = clicked.clone();
|
||||
}
|
||||
}
|
||||
if (clickResult.doRefresh())
|
||||
player.getPlayerConnection().sendPacket(getWindowItemsPacket());
|
||||
|
||||
if (isInWindow) {
|
||||
setItemStack(slot, resultClicked);
|
||||
setItemStack(slot, clickResult.getClicked());
|
||||
} else {
|
||||
playerInventory.setItemStack(slot, offset, resultClicked);
|
||||
playerInventory.setItemStack(slot, offset, clickResult.getClicked());
|
||||
}
|
||||
playerInventory.setItemStack(key, resultHeld);
|
||||
playerInventory.setItemStack(key, clickResult.getCursor());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -499,12 +355,14 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, this, clicked, cursorItem);
|
||||
InventoryConditionResult result = new InventoryConditionResult(clicked, cursorItem);
|
||||
inventoryCondition.accept(slot, null, result);
|
||||
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
|
||||
if (result.isCancel()) {
|
||||
System.out.println(clicked.getMaterial() + " + " + cursorItem.getMaterial());
|
||||
//System.out.println(clicked.getMaterial() + " + " + cursorItem.getMaterial());
|
||||
if (isInWindow) {
|
||||
setItemStack(slot, clicked);
|
||||
setCursorPlayerItem(player, cursorItem);
|
||||
|
@ -1,6 +1,8 @@
|
||||
package fr.themode.minestom.inventory;
|
||||
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.inventory.click.InventoryClickProcessor;
|
||||
import fr.themode.minestom.inventory.click.InventoryClickResult;
|
||||
import fr.themode.minestom.inventory.rule.InventoryCondition;
|
||||
import fr.themode.minestom.inventory.rule.InventoryConditionResult;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
@ -12,28 +14,18 @@ import fr.themode.minestom.net.player.PlayerConnection;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static fr.themode.minestom.utils.inventory.PlayerInventoryUtils.*;
|
||||
|
||||
public class PlayerInventory implements InventoryModifier, InventoryClickHandler {
|
||||
|
||||
public static final int INVENTORY_SIZE = 46;
|
||||
|
||||
private static final int OFFSET = 9;
|
||||
|
||||
private static final int CRAFT_SLOT_1 = 36;
|
||||
private static final int CRAFT_SLOT_2 = 37;
|
||||
private static final int CRAFT_SLOT_3 = 38;
|
||||
private static final int CRAFT_SLOT_4 = 39;
|
||||
private static final int CRAFT_RESULT = 40;
|
||||
private static final int HELMET_SLOT = 41;
|
||||
private static final int CHESTPLATE_SLOT = 42;
|
||||
private static final int LEGGINGS_SLOT = 43;
|
||||
private static final int BOOTS_SLOT = 44;
|
||||
private static final int OFFHAND_SLOT = 45;
|
||||
|
||||
private Player player;
|
||||
private ItemStack[] items = new ItemStack[INVENTORY_SIZE];
|
||||
private ItemStack cursorItem = ItemStack.AIR_ITEM;
|
||||
|
||||
private InventoryCondition inventoryCondition;
|
||||
private InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
|
||||
|
||||
public PlayerInventory(Player player) {
|
||||
this.player = player;
|
||||
@ -224,30 +216,6 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
|
||||
return this.items[slot];
|
||||
}
|
||||
|
||||
|
||||
protected int convertSlot(int slot, int offset) {
|
||||
switch (slot) {
|
||||
case 1:
|
||||
return CRAFT_SLOT_1 + 1;
|
||||
case 2:
|
||||
return CRAFT_SLOT_2 + 1;
|
||||
case 3:
|
||||
return CRAFT_SLOT_3 + 1;
|
||||
case 4:
|
||||
return CRAFT_SLOT_4 + 1;
|
||||
}
|
||||
//System.out.println("ENTRY: " + slot + " | " + offset);
|
||||
final int rowSize = 9;
|
||||
slot -= offset;
|
||||
if (slot >= rowSize * 3 && slot < rowSize * 4) {
|
||||
slot = slot % 9;
|
||||
} else {
|
||||
slot = slot + rowSize;
|
||||
}
|
||||
//System.out.println("CONVERT: " + slot);
|
||||
return slot;
|
||||
}
|
||||
|
||||
protected int convertToPacketSlot(int slot) {
|
||||
if (slot > -1 && slot < 9) { // Held bar 0-9
|
||||
slot = slot + 36;
|
||||
@ -291,127 +259,30 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
|
||||
|
||||
@Override
|
||||
public void leftClick(Player player, int slot) {
|
||||
ItemStack cursorItem = getCursorItem();
|
||||
ItemStack cursor = getCursorItem();
|
||||
ItemStack clicked = getItemStack(convertSlot(slot, OFFSET));
|
||||
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, null, clicked, cursorItem);
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
InventoryClickResult clickResult = clickProcessor.leftClick(getInventoryCondition(), slot, clicked, cursor);
|
||||
|
||||
if (result.isCancel()) {
|
||||
setItemStack(slot, OFFSET, clicked);
|
||||
setCursorItem(cursorItem);
|
||||
// Refresh client slot
|
||||
sendSlotRefresh((short) slot, clicked);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// End condition
|
||||
if (clickResult.doRefresh())
|
||||
sendSlotRefresh((short) slot, clicked);
|
||||
|
||||
/*if (!cursorItem.isAir()) {
|
||||
if (slot == 0 || slot == 6 || slot == 7 || slot == 8) {
|
||||
return; // Disable putting item on CRAFTING_RESULT and chestplate/leggings/boots slots
|
||||
}
|
||||
}*/
|
||||
|
||||
if (cursorItem.isAir() && clicked.isAir())
|
||||
return;
|
||||
|
||||
ItemStack resultCursor;
|
||||
ItemStack resultClicked;
|
||||
|
||||
StackingRule cursorRule = cursorItem.getStackingRule();
|
||||
StackingRule clickedRule = clicked.getStackingRule();
|
||||
|
||||
if (clickedRule.canBeStacked(clicked, cursorItem)) {
|
||||
resultCursor = cursorItem.clone();
|
||||
resultClicked = clicked.clone();
|
||||
int totalAmount = cursorItem.getAmount() + clicked.getAmount();
|
||||
if (!clickedRule.canApply(resultClicked, totalAmount)) {
|
||||
resultCursor = cursorRule.apply(resultCursor, totalAmount - cursorRule.getMaxSize());
|
||||
resultClicked = clickedRule.apply(resultClicked, clickedRule.getMaxSize());
|
||||
} else {
|
||||
resultCursor = cursorRule.apply(resultCursor, 0);
|
||||
resultClicked = clickedRule.apply(resultClicked, totalAmount);
|
||||
}
|
||||
} else {
|
||||
resultCursor = clicked.clone();
|
||||
resultClicked = cursorItem.clone();
|
||||
}
|
||||
|
||||
setItemStack(slot, OFFSET, resultClicked);
|
||||
setCursorItem(resultCursor);
|
||||
setItemStack(slot, OFFSET, clickResult.getClicked());
|
||||
setCursorItem(clickResult.getCursor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rightClick(Player player, int slot) {
|
||||
ItemStack cursorItem = getCursorItem();
|
||||
ItemStack cursor = getCursorItem();
|
||||
ItemStack clicked = getItemStack(slot, OFFSET);
|
||||
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, null, clicked, cursorItem);
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
InventoryClickResult clickResult = clickProcessor.rightClick(getInventoryCondition(), slot, clicked, cursor);
|
||||
|
||||
if (result.isCancel()) {
|
||||
setItemStack(slot, OFFSET, clicked);
|
||||
setCursorItem(cursorItem);
|
||||
// Refresh client slot
|
||||
sendSlotRefresh((short) slot, clicked);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// End condition
|
||||
if (clickResult.doRefresh())
|
||||
sendSlotRefresh((short) slot, clicked);
|
||||
|
||||
if (cursorItem.isAir() && clicked.isAir())
|
||||
return;
|
||||
|
||||
ItemStack resultCursor;
|
||||
ItemStack resultClicked;
|
||||
|
||||
StackingRule cursorRule = cursorItem.getStackingRule();
|
||||
StackingRule clickedRule = clicked.getStackingRule();
|
||||
|
||||
if (clickedRule.canBeStacked(clicked, cursorItem)) {
|
||||
resultClicked = clicked.clone();
|
||||
int amount = clicked.getAmount() + 1;
|
||||
if (!clickedRule.canApply(resultClicked, amount)) {
|
||||
return;
|
||||
} else {
|
||||
resultCursor = cursorItem.clone();
|
||||
resultCursor = cursorRule.apply(resultCursor, cursorRule.getAmount(resultCursor) - 1);
|
||||
resultClicked = clickedRule.apply(resultClicked, amount);
|
||||
}
|
||||
} else {
|
||||
if (cursorItem.isAir()) {
|
||||
int amount = (int) Math.ceil((double) clicked.getAmount() / 2d);
|
||||
resultCursor = clicked.clone();
|
||||
resultCursor = cursorRule.apply(resultCursor, amount);
|
||||
|
||||
resultClicked = clicked.clone();
|
||||
resultClicked = clickedRule.apply(resultClicked, clicked.getAmount() / 2);
|
||||
} else {
|
||||
if (clicked.isAir()) {
|
||||
int amount = cursorItem.getAmount();
|
||||
resultCursor = cursorItem.clone();
|
||||
resultCursor = cursorRule.apply(resultCursor, amount - 1);
|
||||
|
||||
resultClicked = cursorItem.clone();
|
||||
resultClicked = clickedRule.apply(resultClicked, 1);
|
||||
} else {
|
||||
resultCursor = clicked.clone();
|
||||
resultClicked = cursorItem.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setItemStack(slot, OFFSET, resultClicked);
|
||||
setCursorItem(resultCursor);
|
||||
setItemStack(slot, OFFSET, clickResult.getClicked());
|
||||
setCursorItem(clickResult.getCursor());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -437,7 +308,9 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, null, clicked, cursorItem);
|
||||
InventoryConditionResult result = new InventoryConditionResult(clicked, cursorItem);
|
||||
inventoryCondition.accept(slot, null, result);
|
||||
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
|
||||
@ -501,48 +374,16 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
|
||||
if (!getCursorItem().isAir())
|
||||
return;
|
||||
|
||||
ItemStack cursorItem = getCursorItem();
|
||||
ItemStack heldItem = getItemStack(key);
|
||||
ItemStack clicked = getItemStack(slot, OFFSET);
|
||||
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, null, clicked, cursorItem);
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
InventoryClickResult clickResult = clickProcessor.changeHeld(getInventoryCondition(), slot, clicked, heldItem);
|
||||
|
||||
if (result.isCancel()) {
|
||||
setItemStack(slot, OFFSET, clicked);
|
||||
setCursorItem(cursorItem);
|
||||
// Refresh client slot
|
||||
sendSlotRefresh((short) slot, clicked);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// End condition
|
||||
if (clickResult.doRefresh())
|
||||
sendSlotRefresh((short) slot, clicked);
|
||||
|
||||
ItemStack resultClicked;
|
||||
ItemStack resultHeld;
|
||||
|
||||
if (clicked.isAir()) {
|
||||
// Set held item [key] to slot
|
||||
resultClicked = ItemStack.AIR_ITEM;
|
||||
resultHeld = clicked.clone();
|
||||
} else {
|
||||
if (heldItem.isAir()) {
|
||||
// if held item [key] is air then set clicked to held
|
||||
resultClicked = ItemStack.AIR_ITEM;
|
||||
resultHeld = clicked.clone();
|
||||
} else {
|
||||
// Otherwise replace held item and held
|
||||
resultClicked = heldItem.clone();
|
||||
resultHeld = clicked.clone();
|
||||
}
|
||||
}
|
||||
|
||||
setItemStack(slot, OFFSET, resultClicked);
|
||||
setItemStack(key, resultHeld);
|
||||
setItemStack(slot, OFFSET, clickResult.getClicked());
|
||||
setItemStack(key, clickResult.getCursor());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -555,7 +396,9 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, null, clicked, cursorItem);
|
||||
InventoryConditionResult result = new InventoryConditionResult(clicked, cursorItem);
|
||||
inventoryCondition.accept(slot, null, result);
|
||||
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
|
||||
@ -610,8 +453,18 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
|
||||
return;
|
||||
for (Integer s : slots) {
|
||||
ItemStack draggedItem = cursorItem.clone();
|
||||
draggedItem = stackingRule.apply(draggedItem, 1);
|
||||
setItemStack(s, OFFSET, draggedItem);
|
||||
ItemStack slotItem = getItemStack(s);
|
||||
if (draggedItem.isSimilar(slotItem)) {
|
||||
int amount = slotItem.getAmount() + 1;
|
||||
if (stackingRule.canApply(slotItem, amount)) {
|
||||
slotItem = stackingRule.apply(slotItem, amount);
|
||||
setItemStack(s, OFFSET, slotItem);
|
||||
}
|
||||
System.out.println("TEST: " + s + ":" + OFFSET);
|
||||
} else if (slotItem.isAir()) {
|
||||
draggedItem = stackingRule.apply(draggedItem, 1);
|
||||
setItemStack(s, OFFSET, draggedItem);
|
||||
}
|
||||
}
|
||||
cursorItem = stackingRule.apply(cursorItem, cursorAmount - size);
|
||||
setCursorItem(cursorItem);
|
||||
@ -645,7 +498,9 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
|
||||
// Start condition
|
||||
InventoryCondition inventoryCondition = getInventoryCondition();
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = inventoryCondition.accept(slot, null, clicked, cursorItem);
|
||||
InventoryConditionResult result = new InventoryConditionResult(clicked, cursorItem);
|
||||
inventoryCondition.accept(slot, null, result);
|
||||
|
||||
cursorItem = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
|
||||
|
@ -0,0 +1,168 @@
|
||||
package fr.themode.minestom.inventory.click;
|
||||
|
||||
import fr.themode.minestom.inventory.rule.InventoryCondition;
|
||||
import fr.themode.minestom.inventory.rule.InventoryConditionResult;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.item.StackingRule;
|
||||
|
||||
public class InventoryClickProcessor {
|
||||
|
||||
public InventoryClickResult leftClick(InventoryCondition inventoryCondition, int slot, ItemStack clicked, ItemStack cursor) {
|
||||
InventoryClickResult clickResult = startCondition(inventoryCondition, slot, clicked, cursor);
|
||||
|
||||
if (clickResult.isCancel()) {
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
if (cursor.isAir() && clicked.isAir()) {
|
||||
clickResult.setCancel(true);
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
StackingRule cursorRule = cursor.getStackingRule();
|
||||
StackingRule clickedRule = clicked.getStackingRule();
|
||||
|
||||
ItemStack resultCursor;
|
||||
ItemStack resultClicked;
|
||||
|
||||
if (cursorRule.canBeStacked(cursor, clicked)) {
|
||||
|
||||
resultCursor = cursor.clone();
|
||||
resultClicked = clicked.clone();
|
||||
|
||||
int totalAmount = cursorRule.getAmount(cursor) + clickedRule.getAmount(clicked);
|
||||
|
||||
if (!clickedRule.canApply(resultClicked, totalAmount)) {
|
||||
resultCursor = cursorRule.apply(resultCursor, totalAmount - cursorRule.getMaxSize());
|
||||
resultClicked = clickedRule.apply(resultClicked, clickedRule.getMaxSize());
|
||||
} else {
|
||||
resultCursor = cursorRule.apply(resultCursor, 0);
|
||||
resultClicked = clickedRule.apply(resultClicked, totalAmount);
|
||||
}
|
||||
} else {
|
||||
resultCursor = clicked.clone();
|
||||
resultClicked = cursor.clone();
|
||||
}
|
||||
|
||||
clickResult.setClicked(resultClicked);
|
||||
clickResult.setCursor(resultCursor);
|
||||
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
public InventoryClickResult rightClick(InventoryCondition inventoryCondition, int slot, ItemStack clicked, ItemStack cursor) {
|
||||
InventoryClickResult clickResult = startCondition(inventoryCondition, slot, clicked, cursor);
|
||||
|
||||
if (clickResult.isCancel()) {
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
if (cursor.isAir() && clicked.isAir()) {
|
||||
clickResult.setCancel(true);
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
StackingRule cursorRule = cursor.getStackingRule();
|
||||
StackingRule clickedRule = clicked.getStackingRule();
|
||||
|
||||
ItemStack resultCursor;
|
||||
ItemStack resultClicked;
|
||||
|
||||
if (clickedRule.canBeStacked(clicked, cursor)) {
|
||||
resultClicked = clicked.clone();
|
||||
int amount = clicked.getAmount() + 1;
|
||||
if (!clickedRule.canApply(resultClicked, amount)) {
|
||||
return clickResult;
|
||||
} else {
|
||||
resultCursor = cursor.clone();
|
||||
resultCursor = cursorRule.apply(resultCursor, cursorRule.getAmount(resultCursor) - 1);
|
||||
resultClicked = clickedRule.apply(resultClicked, amount);
|
||||
}
|
||||
} else {
|
||||
if (cursor.isAir()) {
|
||||
int amount = (int) Math.ceil((double) clicked.getAmount() / 2d);
|
||||
resultCursor = clicked.clone();
|
||||
resultCursor = cursorRule.apply(resultCursor, amount);
|
||||
|
||||
resultClicked = clicked.clone();
|
||||
resultClicked = clickedRule.apply(resultClicked, clicked.getAmount() / 2);
|
||||
} else {
|
||||
if (clicked.isAir()) {
|
||||
int amount = cursor.getAmount();
|
||||
resultCursor = cursor.clone();
|
||||
resultCursor = cursorRule.apply(resultCursor, amount - 1);
|
||||
|
||||
resultClicked = cursor.clone();
|
||||
resultClicked = clickedRule.apply(resultClicked, 1);
|
||||
} else {
|
||||
resultCursor = clicked.clone();
|
||||
resultClicked = cursor.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clickResult.setClicked(resultClicked);
|
||||
clickResult.setCursor(resultCursor);
|
||||
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
public InventoryClickResult changeHeld(InventoryCondition inventoryCondition, int slot, ItemStack clicked, ItemStack cursor) {
|
||||
InventoryClickResult clickResult = startCondition(inventoryCondition, slot, clicked, cursor);
|
||||
|
||||
if (clickResult.isCancel()) {
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
if (cursor.isAir() && clicked.isAir()) {
|
||||
clickResult.setCancel(true);
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
StackingRule cursorRule = cursor.getStackingRule();
|
||||
StackingRule clickedRule = clicked.getStackingRule();
|
||||
|
||||
ItemStack resultClicked;
|
||||
ItemStack resultHeld;
|
||||
|
||||
if (clicked.isAir()) {
|
||||
// Set held item [key] to slot
|
||||
resultClicked = ItemStack.AIR_ITEM;
|
||||
resultHeld = clicked.clone();
|
||||
} else {
|
||||
if (cursor.isAir()) {
|
||||
// if held item [key] is air then set clicked to held
|
||||
resultClicked = ItemStack.AIR_ITEM;
|
||||
resultHeld = clicked.clone();
|
||||
} else {
|
||||
// Otherwise replace held item and held
|
||||
resultClicked = cursor.clone();
|
||||
resultHeld = clicked.clone();
|
||||
}
|
||||
}
|
||||
|
||||
clickResult.setClicked(resultClicked);
|
||||
clickResult.setCursor(resultHeld);
|
||||
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
private InventoryClickResult startCondition(InventoryCondition inventoryCondition, int slot, ItemStack clicked, ItemStack cursor) {
|
||||
InventoryClickResult clickResult = new InventoryClickResult(clicked, cursor);
|
||||
if (inventoryCondition != null) {
|
||||
InventoryConditionResult result = new InventoryConditionResult(clicked, cursor);
|
||||
inventoryCondition.accept(slot, null, result);
|
||||
|
||||
cursor = result.getCursorItem();
|
||||
clicked = result.getClickedItem();
|
||||
|
||||
if (result.isCancel()) {
|
||||
clickResult.setClicked(clicked);
|
||||
clickResult.setCursor(cursor);
|
||||
clickResult.setRefresh(true);
|
||||
}
|
||||
}
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package fr.themode.minestom.inventory.click;
|
||||
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
|
||||
public class InventoryClickResult {
|
||||
|
||||
private ItemStack clicked;
|
||||
private ItemStack cursor;
|
||||
|
||||
private boolean cancel;
|
||||
private boolean refresh;
|
||||
|
||||
public InventoryClickResult(ItemStack clicked, ItemStack cursor) {
|
||||
this.clicked = clicked;
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
public ItemStack getClicked() {
|
||||
return clicked;
|
||||
}
|
||||
|
||||
protected void setClicked(ItemStack clicked) {
|
||||
this.clicked = clicked;
|
||||
}
|
||||
|
||||
public ItemStack getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
protected void setCursor(ItemStack cursor) {
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
public boolean isCancel() {
|
||||
return cancel;
|
||||
}
|
||||
|
||||
protected void setCancel(boolean cancel) {
|
||||
this.cancel = cancel;
|
||||
}
|
||||
|
||||
public boolean doRefresh() {
|
||||
return refresh;
|
||||
}
|
||||
|
||||
protected void setRefresh(boolean refresh) {
|
||||
this.refresh = refresh;
|
||||
}
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
package fr.themode.minestom.inventory.rule;
|
||||
|
||||
import fr.themode.minestom.inventory.Inventory;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
|
||||
public interface InventoryCondition {
|
||||
|
||||
InventoryConditionResult accept(int slot, Inventory inventory, ItemStack clickedItem, ItemStack cursorItem);
|
||||
void accept(int slot, Inventory inventory, InventoryConditionResult inventoryConditionResult);
|
||||
|
||||
}
|
||||
|
@ -11,12 +11,13 @@ public class ItemStack implements DataContainer {
|
||||
public static final ItemStack AIR_ITEM = new ItemStack(0, (byte) 1);
|
||||
private static StackingRule defaultStackingRule;
|
||||
|
||||
private int materialId;
|
||||
|
||||
{
|
||||
if (defaultStackingRule == null)
|
||||
defaultStackingRule = new VanillaStackingRule(64);
|
||||
defaultStackingRule = new VanillaStackingRule(127);
|
||||
}
|
||||
|
||||
private Material material;
|
||||
private byte amount;
|
||||
private short damage;
|
||||
|
||||
@ -27,8 +28,8 @@ public class ItemStack implements DataContainer {
|
||||
private StackingRule stackingRule;
|
||||
private Data data;
|
||||
|
||||
public ItemStack(Material material, byte amount, short damage) {
|
||||
this.material = material;
|
||||
public ItemStack(int materialId, byte amount, short damage) {
|
||||
this.materialId = materialId;
|
||||
this.amount = amount;
|
||||
this.damage = damage;
|
||||
this.lore = new ArrayList<>();
|
||||
@ -37,21 +38,25 @@ public class ItemStack implements DataContainer {
|
||||
}
|
||||
|
||||
public ItemStack(int id, byte amount) {
|
||||
this(Material.fromId(id), amount, (short) 0);
|
||||
this(id, amount, (short) 0);
|
||||
}
|
||||
|
||||
public ItemStack(Material material, byte amount) {
|
||||
this(material.getId(), amount);
|
||||
}
|
||||
|
||||
public boolean isAir() {
|
||||
return material == Material.AIR;
|
||||
return materialId == Material.AIR.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not take amount in consideration
|
||||
*
|
||||
* @param itemStack
|
||||
* @return
|
||||
* @param itemStack The ItemStack to compare to
|
||||
* @return true if both items are similar (without comparing amount)
|
||||
*/
|
||||
public boolean isSimilar(ItemStack itemStack) {
|
||||
return itemStack.getMaterial() == material &&
|
||||
return itemStack.getMaterialId() == materialId &&
|
||||
itemStack.getDisplayName() == displayName &&
|
||||
itemStack.isUnbreakable() == unbreakable &&
|
||||
itemStack.getDamage() == damage &&
|
||||
@ -67,8 +72,8 @@ public class ItemStack implements DataContainer {
|
||||
return damage;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
public int getMaterialId() {
|
||||
return materialId;
|
||||
}
|
||||
|
||||
public void setAmount(byte amount) {
|
||||
@ -116,7 +121,7 @@ public class ItemStack implements DataContainer {
|
||||
}
|
||||
|
||||
public ItemStack clone() {
|
||||
ItemStack itemStack = new ItemStack(material, amount, damage);
|
||||
ItemStack itemStack = new ItemStack(materialId, amount, damage);
|
||||
itemStack.setDisplayName(displayName);
|
||||
itemStack.setUnbreakable(unbreakable);
|
||||
itemStack.setLore(getLore());
|
||||
|
@ -7,6 +7,7 @@ import fr.themode.minestom.instance.Chunk;
|
||||
import fr.themode.minestom.instance.Instance;
|
||||
import fr.themode.minestom.inventory.PlayerInventory;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.item.Material;
|
||||
import fr.themode.minestom.item.StackingRule;
|
||||
import fr.themode.minestom.net.packet.client.play.ClientPlayerBlockPlacementPacket;
|
||||
import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket;
|
||||
@ -26,7 +27,8 @@ public class BlockPlacementListener {
|
||||
return;
|
||||
|
||||
ItemStack usedItem = hand == Player.Hand.MAIN ? playerInventory.getItemInMainHand() : playerInventory.getItemInOffHand();
|
||||
if (!usedItem.getMaterial().isBlock()) {
|
||||
Material material = Material.fromId(usedItem.getMaterialId());
|
||||
if (material != null && !material.isBlock()) {
|
||||
//instance.setBlock(blockPosition.clone().add(0, 1, 0), (short) 10);
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
package fr.themode.minestom.listener;
|
||||
|
||||
import fr.themode.minestom.entity.GameMode;
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.inventory.PlayerInventory;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.net.packet.client.play.ClientCreativeInventoryActionPacket;
|
||||
|
||||
import static fr.themode.minestom.utils.inventory.PlayerInventoryUtils.OFFSET;
|
||||
import static fr.themode.minestom.utils.inventory.PlayerInventoryUtils.convertSlot;
|
||||
|
||||
public class CreativeInventoryActionListener {
|
||||
|
||||
public static void listener(ClientCreativeInventoryActionPacket packet, Player player) {
|
||||
if (player.getGameMode() != GameMode.CREATIVE)
|
||||
return;
|
||||
ItemStack item = packet.item;
|
||||
short slot = packet.slot;
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
inventory.setItemStack(convertSlot(slot, OFFSET), item);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package fr.themode.minestom.listener;
|
||||
package fr.themode.minestom.listener.manager;
|
||||
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.listener.*;
|
||||
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
|
||||
import fr.themode.minestom.net.packet.client.play.*;
|
||||
|
||||
@ -31,12 +32,13 @@ public class PacketListenerManager {
|
||||
addListener(ClientUseItemPacket.class, UseItemListener::useItemListener);
|
||||
addListener(ClientStatusPacket.class, StatusListener::listener);
|
||||
addListener(ClientSettingsPacket.class, SettingsListener::listener);
|
||||
addListener(ClientCreativeInventoryActionPacket.class, CreativeInventoryActionListener::listener);
|
||||
}
|
||||
|
||||
public <T extends ClientPlayPacket> void process(T packet, Player player) {
|
||||
BiConsumer<T, Player> biConsumer = (BiConsumer<T, Player>) listeners.get(packet.getClass());
|
||||
if (biConsumer == null) {
|
||||
// System.err.println("Packet " + packet.getClass() + " does not have any listener!");
|
||||
System.err.println("Packet " + packet.getClass() + " does not have any listener!");
|
||||
return;
|
||||
}
|
||||
biConsumer.accept(packet, player);
|
@ -41,9 +41,9 @@ public class PacketProcessor {
|
||||
public void process(Client client, int id, int length, int offset) {
|
||||
PlayerConnection playerConnection = connectionPlayerConnectionMap.computeIfAbsent(client, c -> new PlayerConnection(client));
|
||||
ConnectionState connectionState = playerConnection.getConnectionState();
|
||||
/*if (!printBlackList.contains(id)) {
|
||||
System.out.println("RECEIVED ID: 0x" + Integer.toHexString(id) + " State: " + connectionState);
|
||||
}*/
|
||||
//if (!printBlackList.contains(id)) {
|
||||
//System.out.println("RECEIVED ID: 0x" + Integer.toHexString(id) + " State: " + connectionState);
|
||||
//}
|
||||
|
||||
PacketReader packetReader = new PacketReader(client, length, offset);
|
||||
|
||||
|
@ -14,7 +14,7 @@ public class ClientPacketsHandler {
|
||||
}
|
||||
|
||||
public ClientPacket getPacketInstance(int id) {
|
||||
//System.out.println("RECEIVED PACKET 0x" + Integer.toHexString(id));
|
||||
System.out.println("RECEIVED PACKET 0x" + Integer.toHexString(id));
|
||||
if (id > SIZE)
|
||||
throw new IllegalStateException("Packet ID 0x" + Integer.toHexString(id) + " has been tried to be parsed, debug needed");
|
||||
|
||||
|
@ -14,7 +14,6 @@ public class ClientPlayPacketsHandler extends ClientPacketsHandler {
|
||||
register(0x09, ClientClickWindowPacket.class);
|
||||
register(0x0A, ClientCloseWindow.class);
|
||||
register(0x0B, ClientPluginMessagePacket.class);
|
||||
register(0x1C, ClientSteerVehiclePacket.class);
|
||||
register(0x0E, ClientUseEntityPacket.class);
|
||||
register(0x0F, ClientKeepAlivePacket.class);
|
||||
|
||||
@ -25,6 +24,8 @@ public class ClientPlayPacketsHandler extends ClientPacketsHandler {
|
||||
register(0x19, ClientPlayerAbilitiesPacket.class);
|
||||
register(0x1A, ClientPlayerDiggingPacket.class);
|
||||
register(0x1B, ClientEntityActionPacket.class);
|
||||
register(0x1C, ClientSteerVehiclePacket.class);
|
||||
register(0x1D, ClientRecipeBookData.class);
|
||||
|
||||
register(0x23, ClientHeldItemChangePacket.class);
|
||||
register(0x26, ClientCreativeInventoryActionPacket.class);
|
||||
|
@ -3,6 +3,8 @@ package fr.themode.minestom.net.packet.client.login;
|
||||
import fr.themode.minestom.MinecraftServer;
|
||||
import fr.themode.minestom.entity.GameMode;
|
||||
import fr.themode.minestom.entity.Player;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.item.Material;
|
||||
import fr.themode.minestom.net.ConnectionManager;
|
||||
import fr.themode.minestom.net.ConnectionState;
|
||||
import fr.themode.minestom.net.packet.PacketReader;
|
||||
@ -10,6 +12,7 @@ import fr.themode.minestom.net.packet.client.ClientPreplayPacket;
|
||||
import fr.themode.minestom.net.packet.server.login.JoinGamePacket;
|
||||
import fr.themode.minestom.net.packet.server.login.LoginSuccessPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.DeclareCommandsPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.DeclareRecipesPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.PlayerInfoPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.SpawnPositionPacket;
|
||||
import fr.themode.minestom.net.player.PlayerConnection;
|
||||
@ -111,6 +114,21 @@ public class LoginStartPacket implements ClientPreplayPacket {
|
||||
|
||||
|
||||
connection.sendPacket(declareCommandsPacket);
|
||||
|
||||
|
||||
{
|
||||
DeclareRecipesPacket recipesPacket = new DeclareRecipesPacket();
|
||||
DeclareRecipesPacket.Recipe recipe = new DeclareRecipesPacket.Recipe();
|
||||
recipe.recipeId = "crafting_shapeless";
|
||||
recipe.type = "crafting_shapeless";
|
||||
recipe.group = "test group";
|
||||
DeclareRecipesPacket.Ingredient ingredient = new DeclareRecipesPacket.Ingredient();
|
||||
ingredient.items = new ItemStack[]{new ItemStack(Material.STONE, (byte) 1)};
|
||||
recipe.ingredients = new DeclareRecipesPacket.Ingredient[]{ingredient};
|
||||
recipe.result = new ItemStack(Material.STONE, (byte) 50);
|
||||
recipesPacket.recipes = new DeclareRecipesPacket.Recipe[]{recipe};
|
||||
connection.sendPacket(recipesPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,50 @@
|
||||
package fr.themode.minestom.net.packet.client.play;
|
||||
|
||||
import fr.themode.minestom.net.packet.PacketReader;
|
||||
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
|
||||
|
||||
public class ClientRecipeBookData extends ClientPlayPacket {
|
||||
|
||||
public int type;
|
||||
|
||||
public String recipeId;
|
||||
|
||||
public boolean craftingRecipeBookOpen;
|
||||
public boolean craftingRecipeFilterActive;
|
||||
public boolean smeltingRecipeBookOpen;
|
||||
public boolean smeltingRecipeFilterActive;
|
||||
public boolean blastingRecipeBookOpen;
|
||||
public boolean blastingRecipeFilterActive;
|
||||
public boolean smokingRecipeBookOpen;
|
||||
public boolean smokingRecipeFilterActive;
|
||||
|
||||
@Override
|
||||
public void read(PacketReader reader, Runnable callback) {
|
||||
reader.readVarInt(id -> {
|
||||
this.type = id;
|
||||
|
||||
switch (id) {
|
||||
case 0:
|
||||
reader.readSizedString((string, length) -> {
|
||||
System.out.println("test: " + string);
|
||||
callback.run();
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
reader.readBoolean(value -> craftingRecipeBookOpen = value);
|
||||
reader.readBoolean(value -> craftingRecipeFilterActive = value);
|
||||
reader.readBoolean(value -> smeltingRecipeBookOpen = value);
|
||||
reader.readBoolean(value -> smeltingRecipeFilterActive = value);
|
||||
reader.readBoolean(value -> blastingRecipeBookOpen = value);
|
||||
reader.readBoolean(value -> blastingRecipeFilterActive = value);
|
||||
reader.readBoolean(value -> smokingRecipeBookOpen = value);
|
||||
reader.readBoolean(value -> {
|
||||
smokingRecipeFilterActive = value;
|
||||
callback.run();
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ public class StatusRequestPacket implements ClientPreplayPacket {
|
||||
|
||||
@Override
|
||||
public void read(PacketReader reader, Runnable callback) {
|
||||
callback.run();
|
||||
// Empty
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,10 @@ package fr.themode.minestom.net.packet.server;
|
||||
|
||||
public class ServerPacketIdentifier {
|
||||
|
||||
public static final int SPAWN_OBJECT = 0x00;
|
||||
public static final int SPAWN_ENTITY = 0x00;
|
||||
public static final int SPAWN_EXPERIENCE_ORB = 0x01;
|
||||
public static final int SPAWN_GLOBAL_ENTITY = 0x02;
|
||||
public static final int SPAWN_MOB = 0x03;
|
||||
public static final int SPAWN_WEATHER_ENTITY = 0x02;
|
||||
public static final int SPAWN_LIVING_ENTITY = 0x03;
|
||||
public static final int SPAWN_PAINTING = 0x04;
|
||||
public static final int SPAWN_PLAYER = 0x05;
|
||||
public static final int ENTITY_ANIMATION = 0x06;
|
||||
|
@ -0,0 +1,103 @@
|
||||
package fr.themode.minestom.net.packet.server.play;
|
||||
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.net.packet.PacketWriter;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacketIdentifier;
|
||||
|
||||
public class DeclareRecipesPacket implements ServerPacket {
|
||||
|
||||
public Recipe[] recipes;
|
||||
|
||||
@Override
|
||||
public void write(PacketWriter writer) {
|
||||
writer.writeVarInt(recipes.length);
|
||||
for (Recipe recipe : recipes) {
|
||||
recipe.write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.DECLARE_RECIPES;
|
||||
}
|
||||
|
||||
public static class Recipe {
|
||||
|
||||
public String recipeId;
|
||||
public String type;
|
||||
|
||||
public String group;
|
||||
|
||||
// crafting_shapeless
|
||||
// ++ group
|
||||
// ++ ingredients
|
||||
// ++ result
|
||||
|
||||
// crafting_shaped
|
||||
public int width;
|
||||
public int height;
|
||||
// ++ group
|
||||
// ++ ingredients
|
||||
// ++ result
|
||||
|
||||
// smelting
|
||||
// ++ group
|
||||
public Ingredient ingredient;
|
||||
// ++ result
|
||||
public float experience;
|
||||
public int cookingTime;
|
||||
|
||||
|
||||
public Ingredient[] ingredients;
|
||||
public ItemStack result;
|
||||
|
||||
|
||||
private void write(PacketWriter writer) {
|
||||
writer.writeSizedString(recipeId);
|
||||
writer.writeSizedString(type);
|
||||
|
||||
switch (type) {
|
||||
case "crafting_shapeless":
|
||||
writer.writeSizedString(group);
|
||||
writer.writeVarInt(ingredients.length);
|
||||
for (Ingredient ingredient : ingredients) {
|
||||
ingredient.write(writer);
|
||||
}
|
||||
writer.writeItemStack(result);
|
||||
break;
|
||||
case "crafting_shaped":
|
||||
writer.writeVarInt(width);
|
||||
writer.writeVarInt(height);
|
||||
writer.writeSizedString(group);
|
||||
for (Ingredient ingredient : ingredients) {
|
||||
ingredient.write(writer);
|
||||
}
|
||||
writer.writeItemStack(result);
|
||||
break;
|
||||
case "smelting":
|
||||
writer.writeSizedString(group);
|
||||
ingredient.write(writer);
|
||||
writer.writeItemStack(result);
|
||||
writer.writeFloat(experience);
|
||||
writer.writeVarInt(cookingTime);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Ingredient {
|
||||
|
||||
// The count of each item should be 1
|
||||
public ItemStack[] items;
|
||||
|
||||
private void write(PacketWriter writer) {
|
||||
writer.writeVarInt(items.length);
|
||||
for (ItemStack itemStack : items) {
|
||||
writer.writeItemStack(itemStack);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -7,29 +7,37 @@ import fr.themode.minestom.utils.Position;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SpawnObjectPacket implements ServerPacket {
|
||||
public class SpawnEntityPacket implements ServerPacket {
|
||||
|
||||
public int entityId;
|
||||
public UUID uuid;
|
||||
public int type;
|
||||
public Position position;
|
||||
public int data;
|
||||
public short velocityX, velocityY, velocityZ;
|
||||
|
||||
@Override
|
||||
public void write(PacketWriter writer) {
|
||||
writer.writeVarInt(entityId);
|
||||
writer.writeUuid(uuid);
|
||||
writer.writeVarInt(type);
|
||||
|
||||
writer.writeDouble(position.getX());
|
||||
writer.writeDouble(position.getY());
|
||||
writer.writeDouble(position.getZ());
|
||||
writer.writeFloat(position.getYaw());
|
||||
writer.writeFloat(position.getPitch());
|
||||
|
||||
writer.writeByte((byte) (position.getYaw() * 256 / 360));
|
||||
writer.writeByte((byte) (position.getPitch() * 256 / 360));
|
||||
|
||||
writer.writeInt(data);
|
||||
|
||||
writer.writeShort(velocityX);
|
||||
writer.writeShort(velocityY);
|
||||
writer.writeShort(velocityZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.SPAWN_OBJECT;
|
||||
return ServerPacketIdentifier.SPAWN_ENTITY;
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ import fr.themode.minestom.utils.Position;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SpawnMobPacket implements ServerPacket {
|
||||
public class SpawnLivingEntityPacket implements ServerPacket {
|
||||
|
||||
public int entityId;
|
||||
public UUID entityUuid;
|
||||
@ -38,6 +38,6 @@ public class SpawnMobPacket implements ServerPacket {
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.SPAWN_MOB;
|
||||
return ServerPacketIdentifier.SPAWN_LIVING_ENTITY;
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ import fr.themode.minestom.net.packet.PacketWriter;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacketIdentifier;
|
||||
|
||||
public class SpawnGlobalEntityPacket implements ServerPacket {
|
||||
public class SpawnWeatherEntityPacket implements ServerPacket {
|
||||
|
||||
public int entityId;
|
||||
public byte type;
|
||||
@ -21,6 +21,6 @@ public class SpawnGlobalEntityPacket implements ServerPacket {
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.SPAWN_GLOBAL_ENTITY;
|
||||
return ServerPacketIdentifier.SPAWN_WEATHER_ENTITY;
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package fr.themode.minestom.net.packet.server.play;
|
||||
|
||||
import fr.themode.minestom.net.packet.PacketWriter;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacketIdentifier;
|
||||
|
||||
public class UnlockRecipesPacket implements ServerPacket {
|
||||
|
||||
public int mode;
|
||||
|
||||
public boolean craftingRecipeBookOpen;
|
||||
public boolean craftingRecipeBookFilterActive;
|
||||
public boolean smeltingRecipeBookOpen;
|
||||
public boolean smeltingRecipeBookFilterActive;
|
||||
|
||||
public String[] recipesId;
|
||||
|
||||
// Only if mode = 0
|
||||
public String[] initRecipesId;
|
||||
|
||||
@Override
|
||||
public void write(PacketWriter writer) {
|
||||
writer.writeVarInt(mode);
|
||||
|
||||
writer.writeBoolean(craftingRecipeBookOpen);
|
||||
writer.writeBoolean(craftingRecipeBookFilterActive);
|
||||
writer.writeBoolean(smeltingRecipeBookOpen);
|
||||
writer.writeBoolean(smeltingRecipeBookFilterActive);
|
||||
|
||||
writer.writeVarInt(recipesId.length);
|
||||
for (String string : recipesId) {
|
||||
writer.writeSizedString(string);
|
||||
}
|
||||
|
||||
if (mode == 0) {
|
||||
writer.writeVarInt(initRecipesId.length);
|
||||
for (String string : initRecipesId) {
|
||||
writer.writeSizedString(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.UNLOCK_RECIPES;
|
||||
}
|
||||
}
|
@ -52,6 +52,10 @@ public class BlockPosition {
|
||||
return new BlockPosition(x, y, z);
|
||||
}
|
||||
|
||||
public Position toPosition() {
|
||||
return new Position(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BlockPosition[" + x + ":" + y + ":" + z + "]";
|
||||
|
@ -8,12 +8,8 @@ public class ChunkUtils {
|
||||
return instance.getChunk((int) Math.floor(x / 16), (int) Math.floor(z / 16)) == null;
|
||||
}
|
||||
|
||||
public static int getChunkX(int x) {
|
||||
return Math.floorDiv(x, 16);
|
||||
}
|
||||
|
||||
public static int getChunkZ(int z) {
|
||||
return Math.floorDiv(z, 16);
|
||||
public static int getChunkCoordinate(int xz) {
|
||||
return Math.floorDiv(xz, 16);
|
||||
}
|
||||
|
||||
public static long getChunkIndex(int chunkX, int chunkZ) {
|
||||
@ -37,8 +33,8 @@ public class ChunkUtils {
|
||||
int counter = 0;
|
||||
for (int x = startLoop; x < endLoop; x++) {
|
||||
for (int z = startLoop; z < endLoop; z++) {
|
||||
int chunkX = Math.floorDiv((int) (position.getX() + 16 * x), 16);
|
||||
int chunkZ = Math.floorDiv((int) (position.getZ() + 16 * z), 16);
|
||||
int chunkX = getChunkCoordinate((int) (position.getX() + 16 * x));
|
||||
int chunkZ = getChunkCoordinate((int) (position.getZ() + 16 * z));
|
||||
visibleChunks[counter] = getChunkIndex(chunkX, chunkZ);
|
||||
counter++;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ public class PacketUtils {
|
||||
int size = packet.getSize();
|
||||
Utils.writeVarInt(packet, size);
|
||||
|
||||
System.out.println("WRITE PACKET: " + id + " " + serverPacket.getClass().getSimpleName() + " size: " + size);
|
||||
//System.out.println("WRITE PACKET: " + id + " " + serverPacket.getClass().getSimpleName() + " size: " + size);
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ public class Utils {
|
||||
packet.putBoolean(false);
|
||||
} else {
|
||||
packet.putBoolean(true);
|
||||
Utils.writeVarInt(packet, itemStack.getMaterial().getId());
|
||||
Utils.writeVarInt(packet, itemStack.getMaterialId());
|
||||
packet.putByte(itemStack.getAmount());
|
||||
|
||||
if (!itemStack.hasNbtTag()) {
|
||||
|
@ -0,0 +1,40 @@
|
||||
package fr.themode.minestom.utils.inventory;
|
||||
|
||||
public class PlayerInventoryUtils {
|
||||
|
||||
public static final int OFFSET = 9;
|
||||
|
||||
public static final int CRAFT_SLOT_1 = 36;
|
||||
public static final int CRAFT_SLOT_2 = 37;
|
||||
public static final int CRAFT_SLOT_3 = 38;
|
||||
public static final int CRAFT_SLOT_4 = 39;
|
||||
public static final int CRAFT_RESULT = 40;
|
||||
public static final int HELMET_SLOT = 41;
|
||||
public static final int CHESTPLATE_SLOT = 42;
|
||||
public static final int LEGGINGS_SLOT = 43;
|
||||
public static final int BOOTS_SLOT = 44;
|
||||
public static final int OFFHAND_SLOT = 45;
|
||||
|
||||
public static int convertSlot(int slot, int offset) {
|
||||
switch (slot) {
|
||||
case 1:
|
||||
return CRAFT_SLOT_1 + 1;
|
||||
case 2:
|
||||
return CRAFT_SLOT_2 + 1;
|
||||
case 3:
|
||||
return CRAFT_SLOT_3 + 1;
|
||||
case 4:
|
||||
return CRAFT_SLOT_4 + 1;
|
||||
}
|
||||
//System.out.println("ENTRY: " + slot + " | " + offset);
|
||||
final int rowSize = 9;
|
||||
slot -= offset;
|
||||
if (slot >= rowSize * 3 && slot < rowSize * 4) {
|
||||
slot = slot % 9;
|
||||
} else {
|
||||
slot = slot + rowSize;
|
||||
}
|
||||
//System.out.println("CONVERT: " + slot);
|
||||
return slot;
|
||||
}
|
||||
}
|
@ -4,14 +4,12 @@ import fr.themode.minestom.MinecraftServer;
|
||||
|
||||
public enum TimeUnit {
|
||||
|
||||
TICK, MILLISECOND, SECOND;
|
||||
TICK, MILLISECOND;
|
||||
|
||||
public long toMilliseconds(int value) {
|
||||
switch (this) {
|
||||
case TICK:
|
||||
return MinecraftServer.TICK_MS * value;
|
||||
case SECOND:
|
||||
return value * 1000;
|
||||
case MILLISECOND:
|
||||
return value;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user