This commit is contained in:
Felix Cravic 2020-03-29 20:58:30 +02:00
parent 212fceb142
commit 994494c5de
47 changed files with 1182 additions and 573 deletions

View File

@ -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'

View File

@ -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());

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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

View File

@ -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);
}
}

View File

@ -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() {

View File

@ -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;
}
}

View 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;
}
}
}

View File

@ -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;
}
}

View File

@ -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));

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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);

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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());

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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);

View File

@ -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

View File

@ -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;
}
});
}
}

View File

@ -16,7 +16,7 @@ public class StatusRequestPacket implements ClientPreplayPacket {
@Override
public void read(PacketReader reader, Runnable callback) {
callback.run();
// Empty
callback.run();
}
}

View File

@ -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;

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 + "]";

View File

@ -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++;
}

View File

@ -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);
}));
}

View File

@ -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()) {

View File

@ -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;
}
}

View File

@ -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;
}