0.4.0 SNAPSHOT

This commit is contained in:
LOOHP 2021-02-19 23:33:21 +08:00
parent a0f45a5b17
commit 8d2b7ea0cb
32 changed files with 2345 additions and 140 deletions

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.loohp</groupId>
<artifactId>Limbo</artifactId>
<version>0.3.8-ALPHA</version>
<version>0.4.0-ALPHA-SNAPSHOT</version>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>

View File

@ -152,7 +152,7 @@ public class Console implements CommandSender {
return;
}
while (true) {
String command = tabReader.readLine(PROMPT);
String command = tabReader.readLine(PROMPT).trim();
if (command.length() > 0) {
String[] input = CustomStringUtils.splitStringToArgs(command);
new Thread(() -> Limbo.getInstance().dispatchCommand(this, input)).start();

View File

@ -0,0 +1,135 @@
package com.loohp.limbo.Entity;
import java.util.UUID;
import com.loohp.limbo.Limbo;
import com.loohp.limbo.Entity.DataWatcher.WatchableField;
import com.loohp.limbo.Entity.DataWatcher.WatchableObjectType;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Utils.Rotation3f;
import com.loohp.limbo.World.World;
public class ArmorStand extends LivingEntity {
@WatchableField(MetadataIndex = 14, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x01)
protected boolean small = false;
@WatchableField(MetadataIndex = 14, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x04)
protected boolean arms = false;
@WatchableField(MetadataIndex = 14, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x08)
protected boolean noBasePlate = false;
@WatchableField(MetadataIndex = 14, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x10)
protected boolean marker = false;
@WatchableField(MetadataIndex = 15, WatchableObjectType = WatchableObjectType.ROTATION)
protected Rotation3f headRotation = new Rotation3f(0.0, 0.0, 0.0);
@WatchableField(MetadataIndex = 16, WatchableObjectType = WatchableObjectType.ROTATION)
protected Rotation3f bodyRotation = new Rotation3f(0.0, 0.0, 0.0);
@WatchableField(MetadataIndex = 17, WatchableObjectType = WatchableObjectType.ROTATION)
protected Rotation3f leftArmRotation = new Rotation3f(-10.0, 0.0, -10.0);
@WatchableField(MetadataIndex = 18, WatchableObjectType = WatchableObjectType.ROTATION)
protected Rotation3f rightArmRotation = new Rotation3f(-15.0, 0.0, 10.0);
@WatchableField(MetadataIndex = 19, WatchableObjectType = WatchableObjectType.ROTATION)
protected Rotation3f leftLegRotation = new Rotation3f(-1.0, 0.0, -1.0);
@WatchableField(MetadataIndex = 20, WatchableObjectType = WatchableObjectType.ROTATION)
protected Rotation3f rightLegRotation = new Rotation3f(1.0, 0.0, 1.0);
public ArmorStand(int entityId, UUID uuid, World world, double x, double y, double z, float yaw, float pitch) {
super(EntityType.ARMOR_STAND, entityId, uuid, world, x, y, z, yaw, pitch);
}
public ArmorStand(UUID uuid, World world, double x, double y, double z, float yaw, float pitch) {
this(Limbo.getInstance().getNextEntityId(), uuid, world, x, y, z, yaw, pitch);
}
public ArmorStand(World world, double x, double y, double z, float yaw, float pitch) {
this(Limbo.getInstance().getNextEntityId(), UUID.randomUUID(), world, x, y, z, yaw, pitch);
}
public ArmorStand(UUID uuid, Location location) {
this(Limbo.getInstance().getNextEntityId(), uuid, location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
}
public ArmorStand(Location location) {
this(Limbo.getInstance().getNextEntityId(), UUID.randomUUID(), location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
}
public boolean isSmall() {
return small;
}
public void setSmall(boolean small) {
this.small = small;
}
public boolean showArms() {
return arms;
}
public void setArms(boolean arms) {
this.arms = arms;
}
public boolean hasNoBasePlate() {
return noBasePlate;
}
public void setNoBasePlate(boolean noBasePlate) {
this.noBasePlate = noBasePlate;
}
public boolean isMarker() {
return marker;
}
public void setMarker(boolean marker) {
this.marker = marker;
}
public Rotation3f getHeadRotation() {
return headRotation;
}
public void setHeadRotation(Rotation3f headRotation) {
this.headRotation = headRotation;
}
public Rotation3f getBodyRotation() {
return bodyRotation;
}
public void setBodyRotation(Rotation3f bodyRotation) {
this.bodyRotation = bodyRotation;
}
public Rotation3f getLeftArmRotation() {
return leftArmRotation;
}
public void setLeftArmRotation(Rotation3f leftArmRotation) {
this.leftArmRotation = leftArmRotation;
}
public Rotation3f getRightArmRotation() {
return rightArmRotation;
}
public void setRightArmRotation(Rotation3f rightArmRotation) {
this.rightArmRotation = rightArmRotation;
}
public Rotation3f getLeftLegRotation() {
return leftLegRotation;
}
public void setLeftLegRotation(Rotation3f leftLegRotation) {
this.leftLegRotation = leftLegRotation;
}
public Rotation3f getRightLegRotation() {
return rightLegRotation;
}
public void setRightLegRotation(Rotation3f rightLegRotation) {
this.rightLegRotation = rightLegRotation;
}
}

View File

@ -0,0 +1,178 @@
package com.loohp.limbo.Entity;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class DataWatcher {
private Entity entity;
private Map<Field, WatchableObject> values;
public DataWatcher(Entity entity) {
this.entity = entity;
this.values = new HashMap<>();
Class<?> clazz = entity.getClass();
while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
WatchableField a = field.getAnnotation(WatchableField.class);
if (a != null) {
field.setAccessible(true);
try {
values.put(field, new WatchableObject(field.get(entity), a.MetadataIndex(), a.WatchableObjectType(), a.IsOptional(), a.IsBitmask(), a.Bitmask()));
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
clazz = clazz.getSuperclass();
}
}
public Entity getEntity() {
return entity;
}
public boolean isValid() {
return entity.isValid();
}
public synchronized Map<Field, WatchableObject> update() throws IllegalArgumentException, IllegalAccessException {
if (!isValid()) {
return null;
}
Map<Field, WatchableObject> updated = new HashMap<>();
for (Entry<Field, WatchableObject> entry : values.entrySet()) {
Field field = entry.getKey();
WatchableObject watchableObj = entry.getValue();
field.setAccessible(true);
Object newValue = field.get(entity);
if ((newValue == null && watchableObj.getValue() != null) || (newValue != null && watchableObj.getValue() == null) || (newValue != null && watchableObj.getValue() != null && !newValue.equals(watchableObj.getValue()))) {
watchableObj.setValue(newValue);
updated.put(field, watchableObj);
}
}
return updated;
}
public Map<Field, WatchableObject> getWatchableObjects() {
return Collections.unmodifiableMap(values);
}
public static class WatchableObject {
private int index;
private WatchableObjectType type;
private boolean optional;
private boolean isBitmask;
private int bitmask;
private Object value;
public WatchableObject(Object value, int index, WatchableObjectType type, boolean optional, boolean isBitmask, int bitmask) {
this.index = index;
this.type = type;
this.optional = optional;
this.isBitmask = isBitmask;
this.bitmask = bitmask;
this.value = value;
}
public WatchableObject(Object value, int index, WatchableObjectType type, boolean isBitmask, int bitmask) {
this(value, index, type, false, isBitmask, bitmask);
}
public WatchableObject(Object value, int index, WatchableObjectType type, boolean optional) {
this(value, index, type, optional, false, 0x00);
}
public WatchableObject(Object value, int index, WatchableObjectType type) {
this(value, index, type, false, false, 0x00);
}
public Object getValue() {
return value;
}
public void setValue(Object newValue) {
this.value = newValue;
}
public int getIndex() {
return index;
}
public WatchableObjectType getType() {
return type;
}
public boolean isOptional() {
return optional;
}
public boolean isBitmask() {
return isBitmask;
}
public int getBitmask() {
return bitmask;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public static @interface WatchableField {
int MetadataIndex();
WatchableObjectType WatchableObjectType();
boolean IsOptional() default false;
boolean IsBitmask() default false;
int Bitmask() default 0x00;
}
public static enum WatchableObjectType {
BYTE(0),
VARINT(1, 17),
FLOAT(2),
STRING(3),
CHAT(4, 5),
SLOT(6),
BOOLEAN(7),
ROTATION(8),
POSITION(9, 10),
DIRECTION(11),
UUID(-1, 12),
BLOCKID(-1, 13),
NBT(14),
PARTICLE(15),
VILLAGER_DATA(16),
POSE(18);
int typeId;
int optionalTypeId;
WatchableObjectType(int typeId, int optionalTypeId) {
this.typeId = typeId;
this.optionalTypeId = optionalTypeId;
}
WatchableObjectType(int typeId) {
this(typeId, -1);
}
public int getTypeId() {
return typeId;
}
public int getOptionalTypeId() {
return optionalTypeId;
}
}
}

View File

@ -0,0 +1,283 @@
package com.loohp.limbo.Entity;
import java.util.UUID;
import com.loohp.limbo.Limbo;
import com.loohp.limbo.Entity.DataWatcher.WatchableField;
import com.loohp.limbo.Entity.DataWatcher.WatchableObjectType;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.World.World;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
public abstract class Entity {
@WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x01)
protected boolean onFire = false;
@WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x02)
protected boolean crouching = false;
@WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x04)
protected boolean unused = false;
@WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x08)
protected boolean sprinting = false;
@WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x10)
protected boolean swimming = false;
@WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x20)
protected boolean invisible = false;
@WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x40)
protected boolean glowing = false;
@WatchableField(MetadataIndex = 0, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x80)
protected boolean elytraFlying = false;
@WatchableField(MetadataIndex = 1, WatchableObjectType = WatchableObjectType.VARINT)
protected int air = 300;
@WatchableField(MetadataIndex = 2, WatchableObjectType = WatchableObjectType.CHAT, IsOptional = true)
protected BaseComponent[] customName = null;
@WatchableField(MetadataIndex = 3, WatchableObjectType = WatchableObjectType.BOOLEAN)
protected boolean customNameVisible = false;
@WatchableField(MetadataIndex = 4, WatchableObjectType = WatchableObjectType.BOOLEAN)
protected boolean silent = false;
@WatchableField(MetadataIndex = 5, WatchableObjectType = WatchableObjectType.BOOLEAN)
protected boolean noGravity = false;
@WatchableField(MetadataIndex = 6, WatchableObjectType = WatchableObjectType.POSE)
protected Pose pose = Pose.STANDING;
protected final EntityType type;
protected int entityId;
protected UUID uuid;
protected World world;
protected double x;
protected double y;
protected double z;
protected float yaw;
protected float pitch;
public Entity(EntityType type, int entityId, UUID uuid, World world, double x, double y, double z, float yaw, float pitch) {
this.type = type;
this.entityId = entityId;
this.uuid = uuid;
this.world = world;
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
}
public Entity(EntityType type, UUID uuid, World world, double x, double y, double z, float yaw, float pitch) {
this(type, Limbo.getInstance().getNextEntityId(), uuid, world, x, y, z, yaw, pitch);
}
public Entity(EntityType type, World world, double x, double y, double z, float yaw, float pitch) {
this(type, Limbo.getInstance().getNextEntityId(), UUID.randomUUID(), world, x, y, z, yaw, pitch);
}
public Entity(EntityType type, UUID uuid, Location location) {
this(type, Limbo.getInstance().getNextEntityId(), uuid, location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
}
public Entity(EntityType type, Location location) {
this(type, Limbo.getInstance().getNextEntityId(), UUID.randomUUID(), location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
}
public EntityType getType() {
return type;
}
public Location getLocation() {
return new Location(world, x, y, z, yaw, pitch);
}
public void teleport(Location location) {
this.world = location.getWorld();
this.x = location.getX();
this.y = location.getY();
this.z = location.getZ();
this.yaw = location.getYaw();
this.pitch = location.getPitch();
}
public BaseComponent[] getCustomName() {
return customName;
}
public void setCustomName(String name) {
this.customName = name == null ? null : new BaseComponent[] {new TextComponent(name)};
}
public void setCustomName(BaseComponent component) {
this.customName = component == null ? null : new BaseComponent[] {component};
}
public void setCustomName(BaseComponent[] components) {
this.customName = components;
}
public boolean isOnFire() {
return onFire;
}
public void setOnFire(boolean onFire) {
this.onFire = onFire;
}
public boolean isCrouching() {
return crouching;
}
public void setCrouching(boolean crouching) {
this.crouching = crouching;
}
public boolean isSprinting() {
return sprinting;
}
public void setSprinting(boolean sprinting) {
this.sprinting = sprinting;
}
public boolean isSwimming() {
return swimming;
}
public void setSwimming(boolean swimming) {
this.swimming = swimming;
}
public boolean isInvisible() {
return invisible;
}
public void setInvisible(boolean invisible) {
this.invisible = invisible;
}
public boolean isGlowing() {
return glowing;
}
public void setGlowing(boolean glowing) {
this.glowing = glowing;
}
public boolean isElytraFlying() {
return elytraFlying;
}
public void setElytraFlying(boolean elytraFlying) {
this.elytraFlying = elytraFlying;
}
public int getAir() {
return air;
}
public void setAir(int air) {
this.air = air;
}
public boolean isCustomNameVisible() {
return customNameVisible;
}
public void setCustomNameVisible(boolean customNameVisible) {
this.customNameVisible = customNameVisible;
}
public boolean isSilent() {
return silent;
}
public void setSilent(boolean silent) {
this.silent = silent;
}
public boolean hasGravity() {
return !noGravity;
}
public void setGravity(boolean gravity) {
this.noGravity = !gravity;
}
public Pose getPose() {
return pose;
}
public void setPose(Pose pose) {
this.pose = pose;
}
public World getWorld() {
return world;
}
public void setWorld(World world) {
this.world = world;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public double getZ() {
return z;
}
public void setZ(double z) {
this.z = z;
}
public float getYaw() {
return yaw;
}
public void setYaw(float yaw) {
this.yaw = yaw;
}
public float getPitch() {
return pitch;
}
public void setPitch(float pitch) {
this.pitch = pitch;
}
public int getEntityId() {
return entityId;
}
public UUID getUniqueId() {
return uuid;
}
public boolean isValid() {
return world.getEntities().contains(this);
}
@SuppressWarnings("deprecation")
public void remove() {
Limbo.getInstance().getUnsafe().removeEntity(world, this);
}
@SuppressWarnings("deprecation")
public DataWatcher getDataWatcher() {
return Limbo.getInstance().getUnsafe().getDataWatcher(world, this);
}
}

View File

@ -0,0 +1,395 @@
package com.loohp.limbo.Entity;
import java.util.HashMap;
import java.util.Map;
import com.loohp.limbo.Utils.NamespacedKey;
import com.loohp.limbo.Player.Player;
public enum EntityType {
// These strings MUST match the strings in nms.EntityTypes and are case sensitive.
/**
* An item resting on the ground.
* <p>
* Spawn with {@link World#dropItem(Location, ItemStack)} or {@link
* World#dropItemNaturally(Location, ItemStack)}
*/
//DROPPED_ITEM("item", Item.class, 1, false),
/**
* An experience orb.
*/
//EXPERIENCE_ORB("experience_orb", ExperienceOrb.class, 2),
/**
* @see AreaEffectCloud
*/
//AREA_EFFECT_CLOUD("area_effect_cloud", AreaEffectCloud.class, 3),
/**
* @see ElderGuardian
*/
//ELDER_GUARDIAN("elder_guardian", ElderGuardian.class, 4),
/**
* @see WitherSkeleton
*/
//WITHER_SKELETON("wither_skeleton", WitherSkeleton.class, 5),
/**
* @see Stray
*/
//STRAY("stray", Stray.class, 6),
/**
* A flying chicken egg.
*/
//EGG("egg", Egg.class, 7),
/**
* A leash attached to a fencepost.
*/
//LEASH_HITCH("leash_knot", LeashHitch.class, 8),
/**
* A painting on a wall.
*/
//PAINTING("painting", Painting.class, 9),
/**
* An arrow projectile; may get stuck in the ground.
*/
//ARROW("arrow", Arrow.class, 10),
/**
* A flying snowball.
*/
//SNOWBALL("snowball", Snowball.class, 11),
/**
* A flying large fireball, as thrown by a Ghast for example.
*/
//FIREBALL("fireball", LargeFireball.class, 12),
/**
* A flying small fireball, such as thrown by a Blaze or player.
*/
//SMALL_FIREBALL("small_fireball", SmallFireball.class, 13),
/**
* A flying ender pearl.
*/
//ENDER_PEARL("ender_pearl", EnderPearl.class, 14),
/**
* An ender eye signal.
*/
//ENDER_SIGNAL("eye_of_ender", EnderSignal.class, 15),
/**
* A flying splash potion.
*/
//SPLASH_POTION("potion", ThrownPotion.class, 16, false),
/**
* A flying experience bottle.
*/
//THROWN_EXP_BOTTLE("experience_bottle", ThrownExpBottle.class, 17),
/**
* An item frame on a wall.
*/
//ITEM_FRAME("item_frame", ItemFrame.class, 18),
/**
* A flying wither skull projectile.
*/
//WITHER_SKULL("wither_skull", WitherSkull.class, 19),
/**
* Primed TNT that is about to explode.
*/
//PRIMED_TNT("tnt", TNTPrimed.class, 20),
/**
* A block that is going to or is about to fall.
*/
//FALLING_BLOCK("falling_block", FallingBlock.class, 21, false),
/**
* Internal representation of a Firework once it has been launched.
*/
//FIREWORK("firework_rocket", Firework.class, 22, false),
/**
* @see Husk
*/
//HUSK("husk", Husk.class, 23),
/**
* Like {@link #ARROW} but causes the {@link PotionEffectType#GLOWING} effect on all team members.
*/
//SPECTRAL_ARROW("spectral_arrow", SpectralArrow.class, 24),
/**
* Bullet fired by {@link #SHULKER}.
*/
//SHULKER_BULLET("shulker_bullet", ShulkerBullet.class, 25),
/**
* Like {@link #FIREBALL} but with added effects.
*/
//DRAGON_FIREBALL("dragon_fireball", DragonFireball.class, 26),
/**
* @see ZombieVillager
*/
//ZOMBIE_VILLAGER("zombie_villager", ZombieVillager.class, 27),
/**
* @see SkeletonHorse
*/
//SKELETON_HORSE("skeleton_horse", SkeletonHorse.class, 28),
/**
* @see ZombieHorse
*/
//ZOMBIE_HORSE("zombie_horse", ZombieHorse.class, 29),
/**
* Mechanical entity with an inventory for placing weapons / armor into.
*/
ARMOR_STAND("armor_stand", ArmorStand.class, 1),
/**
* @see Donkey
*/
//DONKEY("donkey", Donkey.class, 31),
/**
* @see Mule
*/
//MULE("mule", Mule.class, 32),
/**
* @see EvokerFangs
*/
//EVOKER_FANGS("evoker_fangs", EvokerFangs.class, 33),
/**
* @see Evoker
*/
//EVOKER("evoker", Evoker.class, 34),
/**
* @see Vex
*/
//VEX("vex", Vex.class, 35),
/**
* @see Vindicator
*/
//VINDICATOR("vindicator", Vindicator.class, 36),
/**
* @see Illusioner
*/
//ILLUSIONER("illusioner", Illusioner.class, 37),
/**
* @see CommandMinecart
*/
//MINECART_COMMAND("command_block_minecart", CommandMinecart.class, 40),
/**
* A placed boat.
*/
//BOAT("boat", Boat.class, 41),
/**
* @see RideableMinecart
*/
//MINECART("minecart", RideableMinecart.class, 42),
/**
* @see StorageMinecart
*/
//MINECART_CHEST("chest_minecart", StorageMinecart.class, 43),
/**
* @see PoweredMinecart
*/
//MINECART_FURNACE("furnace_minecart", PoweredMinecart.class, 44),
/**
* @see ExplosiveMinecart
*/
//MINECART_TNT("tnt_minecart", ExplosiveMinecart.class, 45),
/**
* @see HopperMinecart
*/
//MINECART_HOPPER("hopper_minecart", HopperMinecart.class, 46),
/**
* @see SpawnerMinecart
*/
//MINECART_MOB_SPAWNER("spawner_minecart", SpawnerMinecart.class, 47),
//CREEPER("creeper", Creeper.class, 50),
//SKELETON("skeleton", Skeleton.class, 51),
//SPIDER("spider", Spider.class, 52),
//GIANT("giant", Giant.class, 53),
//ZOMBIE("zombie", Zombie.class, 54),
//SLIME("slime", Slime.class, 55),
//GHAST("ghast", Ghast.class, 56),
//ZOMBIFIED_PIGLIN("zombified_piglin", PigZombie.class, 57),
//ENDERMAN("enderman", Enderman.class, 58),
//CAVE_SPIDER("cave_spider", CaveSpider.class, 59),
//SILVERFISH("silverfish", Silverfish.class, 60),
//BLAZE("blaze", Blaze.class, 61),
//MAGMA_CUBE("magma_cube", MagmaCube.class, 62),
//ENDER_DRAGON("ender_dragon", EnderDragon.class, 63),
//WITHER("wither", Wither.class, 64),
//BAT("bat", Bat.class, 65),
//WITCH("witch", Witch.class, 66),
//ENDERMITE("endermite", Endermite.class, 67),
//GUARDIAN("guardian", Guardian.class, 68),
//SHULKER("shulker", Shulker.class, 69),
//PIG("pig", Pig.class, 90),
//SHEEP("sheep", Sheep.class, 91),
//COW("cow", Cow.class, 92),
//CHICKEN("chicken", Chicken.class, 93),
//SQUID("squid", Squid.class, 94),
//WOLF("wolf", Wolf.class, 95),
//MUSHROOM_COW("mooshroom", MushroomCow.class, 96),
//SNOWMAN("snow_golem", Snowman.class, 97),
//OCELOT("ocelot", Ocelot.class, 98),
//IRON_GOLEM("iron_golem", IronGolem.class, 99),
//HORSE("horse", Horse.class, 100),
//RABBIT("rabbit", Rabbit.class, 101),
//POLAR_BEAR("polar_bear", PolarBear.class, 102),
//LLAMA("llama", Llama.class, 103),
//LLAMA_SPIT("llama_spit", LlamaSpit.class, 104),
//PARROT("parrot", Parrot.class, 105),
//VILLAGER("villager", Villager.class, 120),
//ENDER_CRYSTAL("end_crystal", EnderCrystal.class, 200),
//TURTLE("turtle", Turtle.class, -1),
//PHANTOM("phantom", Phantom.class, -1),
//TRIDENT("trident", Trident.class, -1),
//COD("cod", Cod.class, -1),
//SALMON("salmon", Salmon.class, -1),
//PUFFERFISH("pufferfish", PufferFish.class, -1),
//TROPICAL_FISH("tropical_fish", TropicalFish.class, -1),
//DROWNED("drowned", Drowned.class, -1),
//DOLPHIN("dolphin", Dolphin.class, -1),
//CAT("cat", Cat.class, -1),
//PANDA("panda", Panda.class, -1),
//PILLAGER("pillager", Pillager.class, -1),
//RAVAGER("ravager", Ravager.class, -1),
//TRADER_LLAMA("trader_llama", TraderLlama.class, -1),
//WANDERING_TRADER("wandering_trader", WanderingTrader.class, -1),
//FOX("fox", Fox.class, -1),
//BEE("bee", Bee.class, -1),
//HOGLIN("hoglin", Hoglin.class, -1),
//PIGLIN("piglin", Piglin.class, -1),
//STRIDER("strider", Strider.class, -1),
//ZOGLIN("zoglin", Zoglin.class, -1),
//PIGLIN_BRUTE("piglin_brute", PiglinBrute.class, -1),
/**
* A fishing line and bobber.
*/
//FISHING_HOOK("fishing_bobber", FishHook.class, -1, false),
/**
* A bolt of lightning.
* <p>
* Spawn with {@link World#strikeLightning(Location)}.
*/
//LIGHTNING("lightning_bolt", LightningStrike.class, -1, false),
PLAYER("player", Player.class, 106, false),
/**
* An unknown entity without an Entity Class
*/
UNKNOWN(null, null, -1, false);
private final String name;
private final Class<? extends Entity> clazz;
private final short typeId;
private final boolean independent;
private final boolean living;
private final NamespacedKey key;
private static final Map<String, EntityType> NAME_MAP = new HashMap<>();
private static final Map<Short, EntityType> ID_MAP = new HashMap<>();
static {
for (EntityType type : values()) {
if (type.name != null) {
NAME_MAP.put(type.name.toLowerCase(java.util.Locale.ENGLISH), type);
}
if (type.typeId > 0) {
ID_MAP.put(type.typeId, type);
}
}
// Add legacy names
/*
NAME_MAP.put("xp_orb", EXPERIENCE_ORB);
NAME_MAP.put("eye_of_ender_signal", ENDER_SIGNAL);
NAME_MAP.put("xp_bottle", THROWN_EXP_BOTTLE);
NAME_MAP.put("fireworks_rocket", FIREWORK);
NAME_MAP.put("evocation_fangs", EVOKER_FANGS);
NAME_MAP.put("evocation_illager", EVOKER);
NAME_MAP.put("vindication_illager", VINDICATOR);
NAME_MAP.put("illusion_illager", ILLUSIONER);
NAME_MAP.put("commandblock_minecart", MINECART_COMMAND);
NAME_MAP.put("snowman", SNOWMAN);
NAME_MAP.put("villager_golem", IRON_GOLEM);
NAME_MAP.put("ender_crystal", ENDER_CRYSTAL);
NAME_MAP.put("zombie_pigman", ZOMBIFIED_PIGLIN);
*/
}
private EntityType(String name, Class<? extends Entity> clazz, int typeId) {
this(name, clazz, typeId, true);
}
private EntityType(String name, Class<? extends Entity> clazz, int typeId, boolean independent) {
this.name = name;
this.clazz = clazz;
this.typeId = (short) typeId;
this.independent = independent;
this.living = clazz != null && LivingEntity.class.isAssignableFrom(clazz);
this.key = (name == null) ? null : NamespacedKey.minecraft(name);
}
/**
* Gets the entity type name.
*
* @return the entity type's name
* @deprecated Magic value
*/
@Deprecated
public String getName() {
return name;
}
public NamespacedKey getKey() {
return key;
}
public Class<? extends Entity> getEntityClass() {
return clazz;
}
/**
* Gets the entity network type id.
*
* @return the network type id
*/
public short getTypeId() {
return typeId;
}
/**
* Gets an entity type from its name.
*
* @param name the entity type's name
* @return the matching entity type or null
* @deprecated Magic value
*/
@Deprecated
public static EntityType fromName(String name) {
if (name == null) {
return null;
}
return NAME_MAP.get(name.toLowerCase(java.util.Locale.ENGLISH));
}
/**
* Gets an entity from its id.
*
* @param id the raw type id
* @return the matching entity type or null
* @deprecated Magic value
*/
@Deprecated
public static EntityType fromId(int id) {
if (id > Short.MAX_VALUE) {
return null;
}
return ID_MAP.get((short) id);
}
/**
* Some entities cannot be spawned using {@link
* World#spawnEntity(Location, EntityType)} or {@link
* World#spawn(Location, Class)}, usually because they require additional
* information in order to spawn.
*
* @return False if the entity type cannot be spawned
*/
public boolean isSpawnable() {
return independent;
}
public boolean isAlive() {
return living;
}
}

View File

@ -0,0 +1,132 @@
package com.loohp.limbo.Entity;
import java.util.UUID;
import com.loohp.limbo.Limbo;
import com.loohp.limbo.Entity.DataWatcher.WatchableField;
import com.loohp.limbo.Entity.DataWatcher.WatchableObjectType;
import com.loohp.limbo.Inventory.EquipmentSlot;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.World.BlockPosition;
import com.loohp.limbo.World.World;
public abstract class LivingEntity extends Entity {
@WatchableField(MetadataIndex = 7, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x01)
protected boolean handActive = false;
@WatchableField(MetadataIndex = 7, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x02)
protected boolean activeHand = false; //false = main hand, true = off hand
@WatchableField(MetadataIndex = 7, WatchableObjectType = WatchableObjectType.BYTE, IsBitmask = true, Bitmask = 0x04)
protected boolean inRiptideSpinAttack = false;
@WatchableField(MetadataIndex = 8, WatchableObjectType = WatchableObjectType.FLOAT)
protected float health = 1.0F;
@WatchableField(MetadataIndex = 9, WatchableObjectType = WatchableObjectType.VARINT)
protected int potionEffectColor = 0;
@WatchableField(MetadataIndex = 10, WatchableObjectType = WatchableObjectType.BOOLEAN)
protected boolean potionEffectAmbient = false;
@WatchableField(MetadataIndex = 11, WatchableObjectType = WatchableObjectType.VARINT)
protected int arrowsInEntity = 0;
@WatchableField(MetadataIndex = 12, WatchableObjectType = WatchableObjectType.VARINT)
protected int absorption = 0;
@WatchableField(MetadataIndex = 13, WatchableObjectType = WatchableObjectType.POSITION, IsOptional = true)
protected BlockPosition sleepingLocation = null;
public LivingEntity(EntityType type, int entityId, UUID uuid, World world, double x, double y, double z, float yaw, float pitch) {
super(type, entityId, uuid, world, x, y, z, yaw, pitch);
}
public LivingEntity(EntityType type, UUID uuid, World world, double x, double y, double z, float yaw, float pitch) {
this(type, Limbo.getInstance().getNextEntityId(), uuid, world, x, y, z, yaw, pitch);
}
public LivingEntity(EntityType type, World world, double x, double y, double z, float yaw, float pitch) {
this(type, Limbo.getInstance().getNextEntityId(), UUID.randomUUID(), world, x, y, z, yaw, pitch);
}
public LivingEntity(EntityType type, UUID uuid, Location location) {
this(type, Limbo.getInstance().getNextEntityId(), uuid, location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
}
public LivingEntity(EntityType type, Location location) {
this(type, Limbo.getInstance().getNextEntityId(), UUID.randomUUID(), location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
}
public boolean isHandActive() {
return handActive;
}
public void setHandActive(boolean handActive) {
this.handActive = handActive;
}
public EquipmentSlot getActiveHand() {
return activeHand ? EquipmentSlot.OFFHAND : EquipmentSlot.MAINHAND;
}
public void setActiveHand(EquipmentSlot activeHand) {
if (activeHand.equals(EquipmentSlot.MAINHAND)) {
this.activeHand = false;
} else if (activeHand.equals(EquipmentSlot.OFFHAND)) {
this.activeHand = true;
} else {
throw new IllegalArgumentException("Invalid EquipmentSlot " + activeHand.toString());
}
}
public boolean isInRiptideSpinAttack() {
return inRiptideSpinAttack;
}
public void setInRiptideSpinAttack(boolean inRiptideSpinAttack) {
this.inRiptideSpinAttack = inRiptideSpinAttack;
}
public float getHealth() {
return health;
}
public void setHealth(float health) {
this.health = health;
}
public int getPotionEffectColor() {
return potionEffectColor;
}
public void setPotionEffectColor(int potionEffectColor) {
this.potionEffectColor = potionEffectColor;
}
public boolean isPotionEffectAmbient() {
return potionEffectAmbient;
}
public void setPotionEffectAmbient(boolean potionEffectAmbient) {
this.potionEffectAmbient = potionEffectAmbient;
}
public int getArrowsInEntity() {
return arrowsInEntity;
}
public void setArrowsInEntity(int arrowsInEntity) {
this.arrowsInEntity = arrowsInEntity;
}
public int getAbsorption() {
return absorption;
}
public void setAbsorption(int absorption) {
this.absorption = absorption;
}
public BlockPosition getSleepingLocation() {
return sleepingLocation;
}
public void setSleepingLocation(BlockPosition sleepingLocation) {
this.sleepingLocation = sleepingLocation;
}
}

View File

@ -0,0 +1,34 @@
package com.loohp.limbo.Entity;
public enum Pose {
STANDING(0),
FALL_FLYING(1),
SLEEPING(2),
SWIMMING(3),
SPIN_ATTACK(4),
SNEAKING(5),
DYING(6);
private static final Pose[] VALUES = values();
private int id;
Pose(int id) {
this.id = id;
}
public int getId() {
return id;
}
public static Pose fromId(int id) {
for (Pose pose : VALUES) {
if (id == pose.id) {
return pose;
}
}
return null;
}
}

View File

@ -3,9 +3,12 @@ package com.loohp.limbo.File;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Reader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
@ -18,32 +21,36 @@ import com.loohp.limbo.Utils.YamlOrder;
public class FileConfiguration {
File file;
Map<String, Object> mapping;
String header;
private Map<String, Object> mapping;
private String header;
public FileConfiguration(File file) throws FileNotFoundException {
this.file = file;
if (file.exists()) {
reloadConfig();
reloadConfig(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
} else {
mapping = new LinkedHashMap<>();
}
}
@Deprecated
public FileConfiguration(InputStream input){
reloadConfig(input);
reloadConfig(new InputStreamReader(input, StandardCharsets.UTF_8));
}
public FileConfiguration reloadConfig() throws FileNotFoundException {
return reloadConfig(new FileInputStream(file));
public FileConfiguration(Reader reader){
reloadConfig(reader);
}
private FileConfiguration reloadConfig(InputStream input) {
public FileConfiguration reloadConfig(File file) throws FileNotFoundException {
return reloadConfig(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
}
public FileConfiguration reloadConfig(InputStream input) {
return reloadConfig(new InputStreamReader(input, StandardCharsets.UTF_8));
}
public FileConfiguration reloadConfig(Reader reader) {
Yaml yml = new Yaml();
mapping = yml.load(input);
mapping = yml.load(reader);
return this;
}
@ -87,7 +94,29 @@ public class FileConfiguration {
}
}
public void saveConfig(File file) throws FileNotFoundException, UnsupportedEncodingException {
public String saveToString() throws IOException {
DumperOptions options = new DumperOptions();
options.setIndent(2);
options.setPrettyFlow(true);
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
Representer customRepresenter = new Representer();
YamlOrder customProperty = new YamlOrder();
customRepresenter.setPropertyUtils(customProperty);
Yaml yaml = new Yaml(customRepresenter, options);
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
if (header != null) {
pw.println("#" + header.replace("\n", "\n#"));
}
yaml.dump(mapping, pw);
pw.flush();
pw.close();
return writer.toString();
}
public void saveConfig(File file) throws IOException {
DumperOptions options = new DumperOptions();
options.setIndent(2);
options.setPrettyFlow(true);

View File

@ -4,6 +4,10 @@ import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Properties;
@ -16,29 +20,44 @@ import com.loohp.limbo.Utils.NamespacedKey;
import com.loohp.limbo.World.World;
public class ServerProperties {
public static final String COMMENT = "For explaination of what each of the options does, please visit:\nhttps://github.com/LOOHP/Limbo/blob/master/src/main/resources/server.properties";
File file;
int maxPlayers;
int serverPort;
String serverIp;
NamespacedKey levelName;
String schemFileName;
NamespacedKey levelDimension;
GameMode defaultGamemode;
Location worldSpawn;
boolean reducedDebugInfo;
boolean allowFlight;
String motdJson;
String versionString;
int protocol;
boolean bungeecord;
private File file;
private int maxPlayers;
private int serverPort;
private String serverIp;
private NamespacedKey levelName;
private String schemFileName;
private NamespacedKey levelDimension;
private GameMode defaultGamemode;
private Location worldSpawn;
private boolean reducedDebugInfo;
private boolean allowFlight;
private String motdJson;
private String versionString;
private int protocol;
private boolean bungeecord;
private int viewDistance;
private double ticksPerSecond;
Optional<BufferedImage> favicon;
public ServerProperties(File file) throws IOException {
this.file = file;
Properties def = new Properties();
def.load(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("server.properties"), StandardCharsets.UTF_8));
Properties prop = new Properties();
prop.load(new FileInputStream(file));
prop.load(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
for (Entry<Object, Object> entry : def.entrySet()) {
String key = entry.getKey().toString();
String value = entry.getValue().toString();
prop.putIfAbsent(key, value);
}
prop.store(new PrintWriter(file, StandardCharsets.UTF_8), COMMENT);
protocol = Limbo.getInstance().serverImplmentationProtocol;
@ -63,6 +82,8 @@ public class ServerProperties {
motdJson = prop.getProperty("motd");
versionString = prop.getProperty("version");
bungeecord = Boolean.parseBoolean(prop.getProperty("bungeecord"));
viewDistance = Integer.parseInt(prop.getProperty("view-distance"));
ticksPerSecond = Double.parseDouble(prop.getProperty("ticks-per-second"));
File png = new File("server-icon.png");
if (png.exists()) {
@ -155,5 +176,13 @@ public class ServerProperties {
public int getProtocol() {
return protocol;
}
public int getViewDistance() {
return viewDistance;
}
public double getDefinedTicksPerSecond() {
return ticksPerSecond;
}
}

View File

@ -0,0 +1,12 @@
package com.loohp.limbo.Inventory;
public enum EquipmentSlot {
MAINHAND,
OFFHAND,
HELMENT,
CHESTPLATE,
LEGGINGS,
BOOTS;
}

View File

@ -27,6 +27,7 @@ import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@ -108,6 +109,8 @@ public class Limbo {
public final int serverImplmentationProtocol = 754;
public final String limboImplementationVersion;
private AtomicBoolean isRunning;
private ServerConnection server;
private Console console;
@ -126,6 +129,9 @@ public class Limbo {
private DimensionRegistry dimensionRegistry;
@SuppressWarnings("unused")
private Tick tick;
private Metrics metrics;
public AtomicInteger entityIdCount = new AtomicInteger();
@ -136,6 +142,7 @@ public class Limbo {
@SuppressWarnings("unchecked")
public Limbo() throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
instance = this;
isRunning = new AtomicBoolean(true);
if (!noGui) {
while (!GUI.loadFinish) {
@ -304,6 +311,8 @@ public class Limbo {
server = new ServerConnection(properties.getServerIp(), properties.getServerPort());
tick = new Tick(this);
metrics = new Metrics();
console.run();
@ -357,6 +366,27 @@ public class Limbo {
return world;
}
public void registerWorld(World world) {
if (!worlds.contains(world)) {
worlds.add(world);
} else {
throw new RuntimeException("World already registered");
}
}
public void unregisterWorld(World world) {
if (worlds.indexOf(world) == 0) {
throw new RuntimeException("World already registered");
} else if (!worlds.contains(world)) {
throw new RuntimeException("World not registered");
} else {
for (Player player : world.getPlayers()) {
player.teleport(properties.getWorldSpawn());
}
worlds.remove(world);
}
}
public ServerProperties getServerProperties() {
return properties;
}
@ -387,12 +417,12 @@ public class Limbo {
public void addPlayer(Player player) {
playersByName.put(player.getName(), player);
playersByUUID.put(player.getUUID(), player);
playersByUUID.put(player.getUniqueId(), player);
}
public void removePlayer(Player player) {
playersByName.remove(player.getName());
playersByUUID.remove(player.getUUID());
playersByUUID.remove(player.getUniqueId());
}
public List<World> getWorlds() {
@ -453,6 +483,7 @@ public class Limbo {
}
public void stopServer() {
isRunning.set(false);
console.sendMessage("Stopping Server...");
for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
@ -476,6 +507,10 @@ public class Limbo {
System.exit(0);
}
public boolean isRunning() {
return isRunning.get();
}
public int getNextEntityId() {
if (entityIdCount.get() == Integer.MAX_VALUE) {
return entityIdCount.getAndSet(0);

View File

@ -5,6 +5,11 @@ import java.util.UUID;
import com.loohp.limbo.Limbo;
import com.loohp.limbo.Commands.CommandSender;
import com.loohp.limbo.Entity.DataWatcher;
import com.loohp.limbo.Entity.DataWatcher.WatchableField;
import com.loohp.limbo.Entity.DataWatcher.WatchableObjectType;
import com.loohp.limbo.Entity.EntityType;
import com.loohp.limbo.Entity.LivingEntity;
import com.loohp.limbo.Events.PlayerChatEvent;
import com.loohp.limbo.Events.PlayerTeleportEvent;
import com.loohp.limbo.Location.Location;
@ -14,30 +19,42 @@ import com.loohp.limbo.Server.Packets.PacketPlayOutGameState;
import com.loohp.limbo.Server.Packets.PacketPlayOutPositionAndLook;
import com.loohp.limbo.Server.Packets.PacketPlayOutRespawn;
import com.loohp.limbo.Utils.GameMode;
import com.loohp.limbo.World.World;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.chat.ComponentSerializer;
public class Player implements CommandSender {
public class Player extends LivingEntity implements CommandSender {
public final ClientConnection clientConnection;
public final PlayerInteractManager playerInteractManager;
private final String username;
private final UUID uuid;
protected final String username;
protected GameMode gamemode;
protected DataWatcher watcher;
protected int entityId;
private Location location;
@WatchableField(MetadataIndex = 14, WatchableObjectType = WatchableObjectType.FLOAT)
protected float additionalHearts = 0.0F;
@WatchableField(MetadataIndex = 15, WatchableObjectType = WatchableObjectType.VARINT)
protected int score = 0;
@WatchableField(MetadataIndex = 16, WatchableObjectType = WatchableObjectType.BYTE)
protected byte skinLayers = 0;
@WatchableField(MetadataIndex = 17, WatchableObjectType = WatchableObjectType.BYTE)
protected byte mainHand = 1;
//@WatchableField(MetadataIndex = 18, WatchableObjectType = WatchableObjectType.NBT)
//protected Entity leftShoulder = null;
//@WatchableField(MetadataIndex = 19, WatchableObjectType = WatchableObjectType.NBT)
//protected Entity rightShoulder = null;
public Player(ClientConnection clientConnection, String username, UUID uuid, int entityId, Location location) {
public Player(ClientConnection clientConnection, String username, UUID uuid, int entityId, Location location, PlayerInteractManager playerInteractManager) throws IllegalArgumentException, IllegalAccessException {
super(EntityType.PLAYER, entityId, uuid, location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
this.clientConnection = clientConnection;
this.username = username;
this.uuid = uuid;
this.entityId = entityId;
this.location = location.clone();
this.playerInteractManager = playerInteractManager;
this.playerInteractManager.setPlayer(this);
this.watcher = new DataWatcher(this);
this.watcher.update();
}
public GameMode getGamemode() {
@ -55,41 +72,95 @@ public class Player implements CommandSender {
}
this.gamemode = gamemode;
}
@Deprecated
protected void setEntityId(int entityId) {
this.entityId = entityId;
}
public World getWorld() {
return location.clone().getWorld();
public float getAdditionalHearts() {
return additionalHearts;
}
public void setAdditionalHearts(float additionalHearts) {
this.additionalHearts = additionalHearts;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public byte getSkinLayers() {
return skinLayers;
}
public void setSkinLayers(byte skinLayers) {
this.skinLayers = skinLayers;
}
public byte getMainHand() {
return mainHand;
}
public void setMainHand(byte mainHand) {
this.mainHand = mainHand;
}
public int getEntityId() {
return entityId;
@Override
public DataWatcher getDataWatcher() {
return watcher;
}
@Override
public boolean isValid() {
return Limbo.getInstance().getPlayers().contains(this);
}
@Override
public void remove() {
}
/*
public Entity getLeftShoulder() {
return leftShoulder;
}
public Location getLocation() {
return location.clone();
public void setLeftShoulder(Entity leftShoulder) {
this.leftShoulder = leftShoulder;
}
public void setLocation(Location location) {
this.location = location;
public Entity getRightShoulder() {
return rightShoulder;
}
public void setRightShoulder(Entity rightShoulder) {
this.rightShoulder = rightShoulder;
}
*/
@Override
public String getName() {
return username;
}
public UUID getUUID() {
return uuid;
}
@Override
public boolean hasPermission(String permission) {
return Limbo.getInstance().getPermissionsManager().hasPermission(this, permission);
}
@Override
public void teleport(Location location) {
PlayerTeleportEvent event = Limbo.getInstance().getEventsManager().callEvent(new PlayerTeleportEvent(this, getLocation(), location));
if (!event.isCancelled()) {
location = event.getTo();
super.teleport(location);
try {
if (!this.location.getWorld().equals(location.getWorld())) {
if (!world.equals(location.getWorld())) {
PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(location.getWorld(), Limbo.getInstance().getDimensionRegistry().getCodec(), 0, gamemode, false, false, true);
clientConnection.sendPacket(respawn);
}
@ -101,6 +172,10 @@ public class Player implements CommandSender {
}
}
protected void setLocation(Location location) {
super.teleport(location);
}
public void sendMessage(String message, UUID uuid) {
sendMessage(TextComponent.fromLegacyText(message), uuid);
}

View File

@ -0,0 +1,135 @@
package com.loohp.limbo.Player;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import com.loohp.limbo.Limbo;
import com.loohp.limbo.Entity.Entity;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Server.Packets.PacketPlayOutEntityDestroy;
import com.loohp.limbo.Server.Packets.PacketPlayOutEntityMetadata;
import com.loohp.limbo.Server.Packets.PacketPlayOutLightUpdate;
import com.loohp.limbo.Server.Packets.PacketPlayOutMapChunk;
import com.loohp.limbo.Server.Packets.PacketPlayOutSpawnEntity;
import com.loohp.limbo.Server.Packets.PacketPlayOutSpawnEntityLiving;
import com.loohp.limbo.Server.Packets.PacketPlayOutUnloadChunk;
import com.loohp.limbo.World.World;
import net.querz.mca.Chunk;
public class PlayerInteractManager {
private Player player;
private Set<Entity> entities;
private Map<Chunk, World> chunks;
public PlayerInteractManager() {
this.player = null;
this.entities = new HashSet<>();
this.chunks = new HashMap<>();
}
protected void setPlayer(Player player) {
if (this.player == null) {
this.player = player;
} else {
throw new RuntimeException("Player in PlayerInteractManager cannot be changed once created");
}
}
public Player getPlayer() {
return player;
}
public void update() throws IOException {
int viewDistanceChunks = Limbo.getInstance().getServerProperties().getViewDistance();
int viewDistanceBlocks = viewDistanceChunks << 4;
Location location = player.getLocation();
Set<Entity> entitiesInRange = player.getWorld().getEntities().stream().filter(each -> each.getLocation().distanceSquared(location) < viewDistanceBlocks * viewDistanceBlocks).collect(Collectors.toSet());
for (Entity entity : entitiesInRange) {
if (!entities.contains(entity)) {
if (entity.getType().isAlive()) {
PacketPlayOutSpawnEntityLiving packet = new PacketPlayOutSpawnEntityLiving(entity.getEntityId(), entity.getUniqueId(), entity.getType(), entity.getX(), entity.getY(), entity.getZ(), entity.getYaw(), entity.getPitch(), entity.getPitch(), (short) 0, (short) 0, (short) 0);
player.clientConnection.sendPacket(packet);
PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(entity);
player.clientConnection.sendPacket(meta);
} else {
PacketPlayOutSpawnEntity packet = new PacketPlayOutSpawnEntity(entity.getEntityId(), entity.getUniqueId(), entity.getType(), entity.getX(), entity.getY(), entity.getZ(), entity.getPitch(), entity.getYaw(), (short) 0, (short) 0, (short) 0);
player.clientConnection.sendPacket(packet);
PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(entity);
player.clientConnection.sendPacket(meta);
}
}
}
List<Integer> ids = new ArrayList<>();
for (Entity entity : entities) {
if (!entitiesInRange.contains(entity)) {
ids.add(entity.getEntityId());
}
}
PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(ids.stream().mapToInt(each -> each).toArray());
player.clientConnection.sendPacket(packet);
entities = entitiesInRange;
int playerChunkX = (int) location.getX() >> 4;
int playerChunkZ = (int) location.getZ() >> 4;
World world = location.getWorld();
Set<Chunk> chunksInRange = new HashSet<>();
for (int x = playerChunkX - viewDistanceChunks; x < playerChunkX + viewDistanceChunks; x++) {
for (int z = playerChunkZ - viewDistanceChunks; z < playerChunkZ + viewDistanceChunks; z++) {
Chunk chunk = world.getChunkAt(x, z);
if (chunk != null) {
chunksInRange.add(chunk);
}
}
}
for (Entry<Chunk, World> entry : chunks.entrySet()) {
Chunk chunk = entry.getKey();
if (location.getWorld().getChunkXZ(chunk) == null) {
World world0 = entry.getValue();
int[] chunkPos = world0.getChunkXZ(chunk);
PacketPlayOutUnloadChunk packet0 = new PacketPlayOutUnloadChunk(chunkPos[0], chunkPos[1]);
player.clientConnection.sendPacket(packet0);
}
}
for (Chunk chunk : chunksInRange) {
if (!chunks.containsKey(chunk)) {
int[] chunkPos = world.getChunkXZ(chunk);
PacketPlayOutMapChunk packet0 = new PacketPlayOutMapChunk(chunkPos[0], chunkPos[1], chunk, world.getEnvironment());
player.clientConnection.sendPacket(packet0);
List<Byte[]> blockChunk = world.getLightEngineBlock().getBlockLightBitMask(chunkPos[0], chunkPos[1]);
if (blockChunk == null) {
blockChunk = new ArrayList<>();
}
List<Byte[]> skyChunk = null;
if (world.hasSkyLight()) {
skyChunk = world.getLightEngineSky().getSkyLightBitMask(chunkPos[0], chunkPos[1]);
}
if (skyChunk == null) {
skyChunk = new ArrayList<>();
}
PacketPlayOutLightUpdate chunkdata = new PacketPlayOutLightUpdate(chunkPos[0], chunkPos[1], true, skyChunk, blockChunk);
player.clientConnection.sendPacket(chunkdata);
}
}
chunks = chunksInRange.stream().collect(Collectors.toMap(each -> each, each -> world));
}
}

View File

@ -1,5 +1,6 @@
package com.loohp.limbo.Player;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Utils.GameMode;
@Deprecated
@ -14,7 +15,12 @@ public class Unsafe {
@Deprecated
public void a(Player a, int b) {
a.entityId = b;
a.setEntityId(b);
}
@Deprecated
public void a(Player a, Location b) {
a.setLocation(b);
}
}

View File

@ -44,7 +44,6 @@ public class PluginManager {
if (name.endsWith("plugin.yml") || name.endsWith("limbo.yml")) {
found = true;
@SuppressWarnings("deprecation")
FileConfiguration pluginYaml = new FileConfiguration(zip);
String main = pluginYaml.get("main", String.class);
String pluginName = pluginYaml.get("name", String.class);

View File

@ -26,6 +26,7 @@ import com.loohp.limbo.Events.StatusPingEvent;
import com.loohp.limbo.File.ServerProperties;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Player.Player;
import com.loohp.limbo.Player.PlayerInteractManager;
import com.loohp.limbo.Server.Packets.Packet;
import com.loohp.limbo.Server.Packets.PacketHandshakingIn;
import com.loohp.limbo.Server.Packets.PacketLoginInLoginStart;
@ -40,9 +41,8 @@ import com.loohp.limbo.Server.Packets.PacketPlayInRotation;
import com.loohp.limbo.Server.Packets.PacketPlayInTabComplete;
import com.loohp.limbo.Server.Packets.PacketPlayOutDeclareCommands;
import com.loohp.limbo.Server.Packets.PacketPlayOutDisconnect;
import com.loohp.limbo.Server.Packets.PacketPlayOutLightUpdate;
import com.loohp.limbo.Server.Packets.PacketPlayOutEntityMetadata;
import com.loohp.limbo.Server.Packets.PacketPlayOutLogin;
import com.loohp.limbo.Server.Packets.PacketPlayOutMapChunk;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerAbilities;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerAbilities.PlayerAbilityFlags;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo;
@ -50,7 +50,6 @@ import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoAction;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoData;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoData.PlayerInfoDataAddPlayer.PlayerSkinProperty;
import com.loohp.limbo.Server.Packets.PacketPlayOutPositionAndLook;
import com.loohp.limbo.Server.Packets.PacketPlayOutShowPlayerSkins;
import com.loohp.limbo.Server.Packets.PacketPlayOutSpawnPosition;
import com.loohp.limbo.Server.Packets.PacketPlayOutTabComplete;
import com.loohp.limbo.Server.Packets.PacketPlayOutTabComplete.TabCompleteMatches;
@ -72,11 +71,10 @@ import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.chat.ComponentSerializer;
import net.querz.mca.Chunk;
public class ClientConnection extends Thread {
public enum ClientState {
public static enum ClientState {
LEGACY,
HANDSHAKE,
STATUS,
@ -97,10 +95,14 @@ public class ClientConnection extends Thread {
private InetAddress inetAddress;
private boolean ready;
public ClientConnection(Socket client_socket) {
this.client_socket = client_socket;
this.inetAddress = client_socket.getInetAddress();
this.lastKeepAlivePayLoad = new AtomicLong();
this.running = false;
this.ready = false;
}
public InetAddress getInetAddress() {
@ -131,6 +133,10 @@ public class ClientConnection extends Thread {
return running;
}
public boolean isReady() {
return ready;
}
public synchronized void sendPacket(PacketOut packet) throws IOException {
byte[] packetByte = packet.serializePacket();
DataTypeIO.writeVarInt(output, packetByte.length);
@ -232,11 +238,13 @@ public class ClientConnection extends Thread {
bungeeUUID = UUID.fromString(data[2].replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5"));
inetAddress = InetAddress.getByName(ip);
String skinJson = data[3];
String skin = skinJson.split("\"value\":\"")[1].split("\"")[0];
String signature = skinJson.split("\"signature\":\"")[1].split("\"")[0];
bungeeSkin = new SkinResponse(skin, signature);
if (data.length > 3) {
String skinJson = data[3];
String skin = skinJson.split("\"value\":\"")[1].split("\"")[0];
String signature = skinJson.split("\"signature\":\"")[1].split("\"")[0];
bungeeSkin = new SkinResponse(skin, signature);
}
} catch (Exception e) {
Limbo.getInstance().getConsole().sendMessage("If you wish to use bungeecord's IP forwarding, please enable that in your bungeecord config.yml as well!");
disconnectDuringLogin(new BaseComponent[] {new TextComponent(ChatColor.RED + "Please connect from the proxy!")});
@ -260,7 +268,8 @@ public class ClientConnection extends Thread {
state = ClientState.PLAY;
player = new Player(this, username, uuid, Limbo.getInstance().getNextEntityId(), Limbo.getInstance().getServerProperties().getWorldSpawn());
player = new Player(this, username, uuid, Limbo.getInstance().getNextEntityId(), Limbo.getInstance().getServerProperties().getWorldSpawn(), new PlayerInteractManager());
player.setSkinLayers((byte) (0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40));
Limbo.getInstance().addPlayer(player);
break;
@ -292,37 +301,11 @@ public class ClientConnection extends Thread {
World world = s.getWorld();
for (int x = 0; x < world.getChunks().length; x++) {
for (int z = 0; z < world.getChunks()[x].length; z++) {
Chunk chunk = world.getChunks()[x][z];
if (chunk != null) {
PacketPlayOutMapChunk chunkdata = new PacketPlayOutMapChunk(x, z, chunk, world.getEnvironment());
sendPacket(chunkdata);
}
}
}
for (int x = 0; x < world.getChunks().length; x++) {
for (int z = 0; z < world.getChunks()[x].length; z++) {
List<Byte[]> blockChunk = world.getLightEngineBlock().getBlockLightBitMask(x, z);
if (blockChunk == null) {
blockChunk = new ArrayList<>();
}
List<Byte[]> skyChunk = null;
if (world.hasSkyLight()) {
skyChunk = world.getLightEngineSky().getSkyLightBitMask(x, z);
}
if (skyChunk == null) {
skyChunk = new ArrayList<>();
}
PacketPlayOutLightUpdate chunkdata = new PacketPlayOutLightUpdate(x, z, true, skyChunk, blockChunk);
sendPacket(chunkdata);
}
}
player.playerInteractManager.update();
SkinResponse skinresponce = isBungeecord ? bungeeSkin : MojangAPIUtils.getSkinFromMojangServer(player.getName());
SkinResponse skinresponce = isBungeecord && bungeeSkin != null ? bungeeSkin : MojangAPIUtils.getSkinFromMojangServer(player.getName());
PlayerSkinProperty skin = skinresponce != null ? new PlayerSkinProperty(skinresponce.getSkin(), skinresponce.getSignature()) : null;
PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo(PlayerInfoAction.ADD_PLAYER, player.getUUID(), new PlayerInfoData.PlayerInfoDataAddPlayer(player.getName(), Optional.ofNullable(skin), p.getDefaultGamemode(), 0, false, Optional.empty()));
PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo(PlayerInfoAction.ADD_PLAYER, player.getUniqueId(), new PlayerInfoData.PlayerInfoDataAddPlayer(player.getName(), Optional.ofNullable(skin), p.getDefaultGamemode(), 0, false, Optional.empty()));
sendPacket(info);
/*
for (ClientConnection client : Limbo.getInstance().getServerConnection().getClients()) {
@ -332,9 +315,6 @@ public class ClientConnection extends Thread {
}
*/
PacketPlayOutShowPlayerSkins show = new PacketPlayOutShowPlayerSkins(player.getEntityId());
sendPacket(show);
Set<PlayerAbilityFlags> flags = new HashSet<>();
if (p.isAllowFlight()) {
flags.add(PlayerAbilityFlags.FLY);
@ -359,9 +339,15 @@ public class ClientConnection extends Thread {
sendPacket(spawnPos);
PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch(), 1);
player.setLocation(new Location(world, s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch()));
Limbo.getInstance().getUnsafe().setPlayerLocationSilently(player, new Location(world, s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch()));
sendPacket(positionLook);
player.getDataWatcher().update();
PacketPlayOutEntityMetadata show = new PacketPlayOutEntityMetadata(player, false, Player.class.getDeclaredField("skinLayers"));
sendPacket(show);
ready = true;
while (client_socket.isConnected()) {
try {
int size = DataTypeIO.readVarInt(input);
@ -381,7 +367,7 @@ public class ClientConnection extends Thread {
PacketPlayOutPositionAndLook cancel = new PacketPlayOutPositionAndLook(returnTo.getX(), returnTo.getY(), returnTo.getZ(), returnTo.getYaw(), returnTo.getPitch(), 1);
sendPacket(cancel);
} else {
player.setLocation(event.getTo());
Limbo.getInstance().getUnsafe().setPlayerLocationSilently(player, event.getTo());
PacketPlayOutUpdateViewPosition response = new PacketPlayOutUpdateViewPosition((int) player.getLocation().getX() >> 4, (int) player.getLocation().getZ() >> 4);
sendPacket(response);
}
@ -396,7 +382,7 @@ public class ClientConnection extends Thread {
PacketPlayOutPositionAndLook cancel = new PacketPlayOutPositionAndLook(returnTo.getX(), returnTo.getY(), returnTo.getZ(), returnTo.getYaw(), returnTo.getPitch(), 1);
sendPacket(cancel);
} else {
player.setLocation(event.getTo());
Limbo.getInstance().getUnsafe().setPlayerLocationSilently(player, event.getTo());
PacketPlayOutUpdateViewPosition response = new PacketPlayOutUpdateViewPosition((int) player.getLocation().getX() >> 4, (int) player.getLocation().getZ() >> 4);
sendPacket(response);
}
@ -411,7 +397,7 @@ public class ClientConnection extends Thread {
PacketPlayOutPositionAndLook cancel = new PacketPlayOutPositionAndLook(returnTo.getX(), returnTo.getY(), returnTo.getZ(), returnTo.getYaw(), returnTo.getPitch(), 1);
sendPacket(cancel);
} else {
player.setLocation(event.getTo());
Limbo.getInstance().getUnsafe().setPlayerLocationSilently(player, event.getTo());
PacketPlayOutUpdateViewPosition response = new PacketPlayOutUpdateViewPosition((int) player.getLocation().getX() >> 4, (int) player.getLocation().getZ() >> 4);
sendPacket(response);
}
@ -457,7 +443,7 @@ public class ClientConnection extends Thread {
}
} catch (Exception e) {}
} catch (Exception e) {e.printStackTrace();}
try {
client_socket.close();

View File

@ -6,16 +6,16 @@ import java.io.IOException;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketPlayOutShowPlayerSkins extends PacketOut {
private int entityId;
public PacketPlayOutShowPlayerSkins(int entityId) {
this.entityId = entityId;
}
public class PacketPlayOutEntityDestroy extends PacketOut {
public int getEntityId() {
return entityId;
private int[] entityIds;
public PacketPlayOutEntityDestroy(int... entityIds) {
this.entityIds = entityIds;
}
public int[] getEntityIds() {
return entityIds;
}
@Override
@ -24,13 +24,10 @@ public class PacketPlayOutShowPlayerSkins extends PacketOut {
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
DataTypeIO.writeVarInt(output, entityId);
output.writeByte(16);
DataTypeIO.writeVarInt(output, 0);
int bitmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40;
output.writeByte(bitmask);
output.writeByte(0xff);
DataTypeIO.writeVarInt(output, entityIds.length);
for (int id : entityIds) {
DataTypeIO.writeVarInt(output, id);
}
return buffer.toByteArray();
}

View File

@ -0,0 +1,156 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import com.loohp.limbo.Entity.DataWatcher.WatchableObject;
import com.loohp.limbo.Entity.DataWatcher.WatchableObjectType;
import com.loohp.limbo.Entity.Entity;
import com.loohp.limbo.Entity.Pose;
import com.loohp.limbo.Utils.DataTypeIO;
import com.loohp.limbo.Utils.Rotation3f;
import com.loohp.limbo.World.BlockPosition;
import net.md_5.bungee.chat.ComponentSerializer;
public class PacketPlayOutEntityMetadata extends PacketOut {
public static final int END_OFF_METADATA = 0xff;
private Entity entity;
public boolean allFields;
public Field[] fields;
public PacketPlayOutEntityMetadata(Entity entity, boolean allFields, Field... fields) {
this.entity = entity;
this.allFields = allFields;
this.fields = fields;
}
public PacketPlayOutEntityMetadata(Entity entity) {
this(entity, true);
}
public Entity getEntity() {
return entity;
}
@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
DataTypeIO.writeVarInt(output, entity.getEntityId());
Collection<WatchableObject> watches;
if (allFields) {
watches = new HashSet<>(entity.getDataWatcher().getWatchableObjects().values());
} else {
watches = new HashSet<>();
Map<Field, WatchableObject> entries = entity.getDataWatcher().getWatchableObjects();
for (Field field : fields) {
WatchableObject watch = entries.get(field);
if (watch != null) {
watches.add(watch);
}
}
}
Map<Integer, Integer> bitmasks = new HashMap<>();
Iterator<WatchableObject> itr = watches.iterator();
while (itr.hasNext()) {
WatchableObject watch = itr.next();
if (watch.isBitmask()) {
itr.remove();
Integer bitmask = bitmasks.get(watch.getIndex());
if (bitmask == null) {
bitmask = 0;
}
if ((boolean) watch.getValue()) {
bitmask |= watch.getBitmask();
} else {
bitmask &= ~watch.getBitmask();
}
bitmasks.put(watch.getIndex(), bitmask);
}
}
for (Entry<Integer, Integer> entry : bitmasks.entrySet()) {
watches.add(new WatchableObject(entry.getValue().byteValue(), entry.getKey(), WatchableObjectType.BYTE));
}
for (WatchableObject watch : watches) {
output.writeByte(watch.getIndex());
if (watch.isOptional()) {
DataTypeIO.writeVarInt(output, watch.getType().getOptionalTypeId());
output.writeBoolean(watch.getValue() != null);
} else {
DataTypeIO.writeVarInt(output, watch.getType().getTypeId());
}
if (!watch.isOptional() || watch.getValue() != null) {
switch (watch.getType()) {
//case BLOCKID:
// break;
case POSITION:
DataTypeIO.writeBlockPosition(output, (BlockPosition) watch.getValue());
break;
case BOOLEAN:
output.writeBoolean((boolean) watch.getValue());
break;
case BYTE:
output.writeByte((byte) watch.getValue());
break;
case CHAT:
DataTypeIO.writeString(output, ComponentSerializer.toString(watch.getValue()), StandardCharsets.UTF_8);
break;
//case DIRECTION:
// break;
case FLOAT:
output.writeFloat((float) watch.getValue());
break;
//case NBT:
// break;
//case PARTICLE:
// break;
case POSE:
DataTypeIO.writeVarInt(output, ((Pose) watch.getValue()).getId());
break;
case ROTATION:
Rotation3f rotation = (Rotation3f) watch.getValue();
output.writeFloat((float) rotation.getX());
output.writeFloat((float) rotation.getY());
output.writeFloat((float) rotation.getZ());
break;
//case SLOT:
// break;
case STRING:
DataTypeIO.writeString(output, watch.getValue().toString(), StandardCharsets.UTF_8);
break;
case UUID:
DataTypeIO.writeUUID(output, (UUID) watch.getValue());
break;
case VARINT:
DataTypeIO.writeVarInt(output, (int) watch.getValue());
break;
//case VILLAGER_DATA:
// break;
default:
break;
}
}
}
output.writeByte(END_OFF_METADATA);
return buffer.toByteArray();
}
}

View File

@ -25,8 +25,7 @@ public class PacketPlayOutRespawn extends PacketOut {
private boolean isFlat;
private boolean copyMetaData;
public PacketPlayOutRespawn(World world, CompoundTag dimensionCodec, long hashedSeed, GameMode gamemode, boolean isDebug,
boolean isFlat, boolean copyMetaData) {
public PacketPlayOutRespawn(World world, CompoundTag dimensionCodec, long hashedSeed, GameMode gamemode, boolean isDebug, boolean isFlat, boolean copyMetaData) {
this.dimension = world.getEnvironment();
this.dimensionCodec = dimensionCodec;
this.worldName = new NamespacedKey(world.getName()).toString();

View File

@ -0,0 +1,111 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.UUID;
import com.loohp.limbo.Entity.EntityType;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketPlayOutSpawnEntity extends PacketOut {
private int entityId;
private UUID uuid;
private EntityType type;
private double x;
private double y;
private double z;
private float pitch;
private float yaw;
private int data;
private short velocityX;
private short velocityY;
private short velocityZ;
public PacketPlayOutSpawnEntity(int entityId, UUID uuid, EntityType type, double x, double y, double z, float pitch, float yaw, short velocityX, short velocityY, short velocityZ) {
this.entityId = entityId;
this.uuid = uuid;
this.type = type;
this.x = x;
this.y = y;
this.z = z;
this.pitch = pitch;
this.yaw = yaw;
this.data = 0; //TO-DO
this.velocityX = velocityX;
this.velocityY = velocityY;
this.velocityZ = velocityZ;
}
public int getEntityId() {
return entityId;
}
public UUID getUuid() {
return uuid;
}
public EntityType getType() {
return type;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
public float getPitch() {
return pitch;
}
public float getYaw() {
return yaw;
}
public int getData() {
return data;
}
public short getVelocityX() {
return velocityX;
}
public short getVelocityY() {
return velocityY;
}
public short getVelocityZ() {
return velocityZ;
}
@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
DataTypeIO.writeVarInt(output, entityId);
DataTypeIO.writeUUID(output, uuid);
DataTypeIO.writeVarInt(output, type.getTypeId());
output.writeDouble(x);
output.writeDouble(y);
output.writeDouble(z);
output.writeByte((byte) (int) (pitch * 256.0F / 360.0F));
output.writeByte((byte) (int) (yaw * 256.0F / 360.0F));
output.writeInt(data);
output.writeShort((int) (velocityX * 8000));
output.writeShort((int) (velocityY * 8000));
output.writeShort((int) (velocityZ * 8000));
return buffer.toByteArray();
}
}

View File

@ -0,0 +1,111 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.UUID;
import com.loohp.limbo.Entity.EntityType;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketPlayOutSpawnEntityLiving extends PacketOut {
private int entityId;
private UUID uuid;
private EntityType type;
private double x;
private double y;
private double z;
private float yaw;
private float pitch;
private float headPitch;
private short velocityX;
private short velocityY;
private short velocityZ;
public PacketPlayOutSpawnEntityLiving(int entityId, UUID uuid, EntityType type, double x, double y, double z, float yaw, float pitch, float headPitch, short velocityX, short velocityY, short velocityZ) {
this.entityId = entityId;
this.uuid = uuid;
this.type = type;
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
this.headPitch = headPitch;
this.velocityX = velocityX;
this.velocityY = velocityY;
this.velocityZ = velocityZ;
}
public int getEntityId() {
return entityId;
}
public UUID getUuid() {
return uuid;
}
public EntityType getType() {
return type;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
public float getYaw() {
return yaw;
}
public float getPitch() {
return pitch;
}
public float getHeadPitch() {
return headPitch;
}
public short getVelocityX() {
return velocityX;
}
public short getVelocityY() {
return velocityY;
}
public short getVelocityZ() {
return velocityZ;
}
@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
DataTypeIO.writeVarInt(output, entityId);
DataTypeIO.writeUUID(output, uuid);
DataTypeIO.writeVarInt(output, type.getTypeId());
output.writeDouble(x);
output.writeDouble(y);
output.writeDouble(z);
output.writeByte((byte) (int) (yaw * 256.0F / 360.0F));
output.writeByte((byte) (int) (pitch * 256.0F / 360.0F));
output.writeByte((byte) (int) (headPitch * 256.0F / 360.0F));
output.writeShort((int) (velocityX * 8000));
output.writeShort((int) (velocityY * 8000));
output.writeShort((int) (velocityZ * 8000));
return buffer.toByteArray();
}
}

View File

@ -0,0 +1,37 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class PacketPlayOutUnloadChunk extends PacketOut {
private int chunkX;
private int chunkZ;
public PacketPlayOutUnloadChunk(int chunkX, int chunkZ) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
}
public int getChunkX() {
return chunkX;
}
public int getChunkZ() {
return chunkZ;
}
@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
output.writeInt(chunkX);
output.writeInt(chunkZ);
return buffer.toByteArray();
}
}

View File

@ -0,0 +1,51 @@
package com.loohp.limbo;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
public class Tick {
private TimerTask timerTask;
public Tick(Limbo instance) {
this.timerTask = new TimerTask () {
@Override
public void run () {
if (instance.isRunning()) {
instance.getPlayers().forEach(each -> {
if (each.clientConnection.isReady()) {
try {
each.playerInteractManager.update();
} catch (IOException e) {
e.printStackTrace();
}
/*
try {
each.getDataWatcher().update();
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
*/
}
});
instance.getWorlds().forEach(each -> {
try {
each.update();
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
});
} else {
this.cancel();
}
}
};
new Timer().schedule(timerTask, 0, Math.round(1000 / instance.getServerProperties().getDefinedTicksPerSecond()));
}
public void cancel() {
timerTask.cancel();
}
}

View File

@ -2,13 +2,18 @@ package com.loohp.limbo;
import java.lang.reflect.Constructor;
import com.loohp.limbo.Entity.DataWatcher;
import com.loohp.limbo.Entity.Entity;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Player.Player;
import com.loohp.limbo.Utils.GameMode;
import com.loohp.limbo.World.World;
@Deprecated
public class Unsafe {
private com.loohp.limbo.Player.Unsafe playerUnsafe;
private com.loohp.limbo.World.Unsafe worldUnsafe;
protected Unsafe() {
try {
@ -16,6 +21,11 @@ public class Unsafe {
playerConstructor.setAccessible(true);
playerUnsafe = playerConstructor.newInstance();
playerConstructor.setAccessible(false);
Constructor<com.loohp.limbo.World.Unsafe> worldConstructor = com.loohp.limbo.World.Unsafe.class.getDeclaredConstructor();
worldConstructor.setAccessible(true);
worldUnsafe = worldConstructor.newInstance();
worldConstructor.setAccessible(false);
} catch (Exception e) {e.printStackTrace();}
}
@ -28,5 +38,20 @@ public class Unsafe {
public void setPlayerEntityId(Player player, int entityId) {
playerUnsafe.a(player, entityId);
}
@Deprecated
public void removeEntity(World world, Entity entity) {
worldUnsafe.a(world, entity);
}
@Deprecated
public DataWatcher getDataWatcher(World world, Entity entity) {
return worldUnsafe.b(world, entity);
}
@Deprecated
public void setPlayerLocationSilently(Player player, Location location) {
playerUnsafe.a(player, location);
}
}

View File

@ -1,6 +1,8 @@
package com.loohp.limbo.Utils;
public class NamespacedKey {
public static final String MINECRAFT_KEY = "minecraft";
private String namespace;
private String key;
@ -20,6 +22,10 @@ public class NamespacedKey {
this.namespace = namespace;
this.key = key;
}
public static NamespacedKey minecraft(String key) {
return new NamespacedKey(MINECRAFT_KEY, key);
}
public String getNamespace() {
return namespace;

View File

@ -0,0 +1,77 @@
package com.loohp.limbo.Utils;
public class Rotation3f {
private double x;
private double y;
private double z;
public Rotation3f(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public double getZ() {
return z;
}
public void setZ(double z) {
this.z = z;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(x);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(y);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(z);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Rotation3f other = (Rotation3f) obj;
if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x)) {
return false;
}
if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y)) {
return false;
}
if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z)) {
return false;
}
return true;
}
}

View File

@ -19,7 +19,7 @@ public class Schematic {
//short height = nbt.getShort("Height");
byte[] blockdata = nbt.getByteArray("BlockData");
CompoundTag palette = nbt.getCompoundTag("Palette");
ListTag<CompoundTag> blockEntities = nbt.getListTag("BlockEntities").asTypedList(CompoundTag.class);
ListTag<CompoundTag> blockEntities = nbt.containsKey("BlockEntities") ? nbt.getListTag("BlockEntities").asTypedList(CompoundTag.class) : null;
Map<Integer, String> mapping = new HashMap<>();
for (String key : palette.keySet()) {
mapping.put(palette.getInt(key), key);
@ -54,19 +54,21 @@ public class Schematic {
Chunk chunk = world.getChunkAtWorldPos(x, z);
Iterator<CompoundTag> itr = blockEntities.iterator();
while (itr.hasNext()) {
CompoundTag tag = itr.next();
int[] pos = tag.getIntArray("Pos");
if (pos[0] == x && pos[1] == y && pos[2] == z) {
ListTag<CompoundTag> newTag = chunk.getTileEntities();
newTag.add(SchematicConvertionUtils.toTileEntityTag(tag));
chunk.setTileEntities(newTag);
itr.remove();
break;
if (blockEntities != null) {
Iterator<CompoundTag> itr = blockEntities.iterator();
while (itr.hasNext()) {
CompoundTag tag = itr.next();
int[] pos = tag.getIntArray("Pos");
if (pos[0] == x && pos[1] == y && pos[2] == z) {
ListTag<CompoundTag> newTag = chunk.getTileEntities();
newTag.add(SchematicConvertionUtils.toTileEntityTag(tag));
chunk.setTileEntities(newTag);
itr.remove();
break;
}
}
}
}
index++;
}

View File

@ -0,0 +1,21 @@
package com.loohp.limbo.World;
import com.loohp.limbo.Entity.DataWatcher;
import com.loohp.limbo.Entity.Entity;
@Deprecated
public class Unsafe {
private Unsafe() {}
@Deprecated
public void a(World a, Entity b) {
a.removeEntity(b);
}
@Deprecated
public DataWatcher b(World a, Entity b) {
return a.getDataWatcher(b);
}
}

View File

@ -1,7 +1,25 @@
package com.loohp.limbo.World;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.loohp.limbo.Limbo;
import com.loohp.limbo.Entity.ArmorStand;
import com.loohp.limbo.Entity.DataWatcher;
import com.loohp.limbo.Entity.DataWatcher.WatchableObject;
import com.loohp.limbo.Entity.Entity;
import com.loohp.limbo.Entity.EntityType;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Player.Player;
import com.loohp.limbo.Server.Packets.PacketPlayOutEntityDestroy;
import com.loohp.limbo.Server.Packets.PacketPlayOutEntityMetadata;
import com.loohp.limbo.Utils.SchematicConvertionUtils;
import net.querz.mca.Chunk;
@ -17,6 +35,7 @@ public class World {
private int length;
private LightEngineBlock lightEngineBlock;
private LightEngineSky lightEngineSky;
private Map<Entity, DataWatcher> entities;
public World(String name, int width, int length, Environment environment) {
this.name = name;
@ -52,6 +71,8 @@ public class World {
if (environment.hasSkyLight()) {
this.lightEngineSky = new LightEngineSky(this);
}
this.entities = new LinkedHashMap<>();
}
public LightEngineBlock getLightEngineBlock() {
@ -107,6 +128,49 @@ public class World {
public Chunk getChunkAtWorldPos(int x, int z) {
return this.chunks[(x >> 4)][(z >> 4)];
}
public Chunk getChunkAt(int x, int z) {
if (x < 0 || z < 0 || x >= chunks.length || z >= chunks[x].length) {
return null;
}
return this.chunks[x][z];
}
public int getChunkX(Chunk chunk) {
for (int x = 0; x < chunks.length; x++) {
for (int z = 0; z < chunks[x].length; z++) {
Chunk c = getChunkAt(x, z);
if (c.equals(chunk)) {
return x;
}
}
}
return Integer.MIN_VALUE;
}
public int getChunkZ(Chunk chunk) {
for (int x = 0; x < chunks.length; x++) {
for (int z = 0; z < chunks[x].length; z++) {
Chunk c = getChunkAt(x, z);
if (c.equals(chunk)) {
return z;
}
}
}
return Integer.MIN_VALUE;
}
public int[] getChunkXZ(Chunk chunk) {
for (int x = 0; x < chunks.length; x++) {
for (int z = 0; z < chunks[x].length; z++) {
Chunk c = getChunkAt(x, z);
if (c.equals(chunk)) {
return new int[] {x, z};
}
}
}
return null;
}
public String getName() {
return name;
@ -131,6 +195,81 @@ public class World {
public int getChunkLength() {
return (length >> 4) + 1;
}
public Set<Entity> getEntities() {
return Collections.unmodifiableSet(entities.keySet());
}
public Entity spawnEntity(EntityType type, Location location) {
if (!location.getWorld().equals(this)) {
throw new IllegalArgumentException("Location not in world.");
}
Entity entity;
switch (type) {
case ARMOR_STAND:
entity = new ArmorStand(location);
break;
default:
throw new UnsupportedOperationException("This EntityType cannot be summoned.");
}
entities.put(entity, new DataWatcher(entity));
return entity;
}
public Entity addEntity(Entity entity) {
if (entity.getWorld().equals(this)) {
entities.put(entity, new DataWatcher(entity));
} else {
throw new IllegalArgumentException("Location not in world.");
}
return entity;
}
public List<Player> getPlayers() {
return Limbo.getInstance().getPlayers().stream().filter(each -> each.getWorld().equals(this)).collect(Collectors.toList());
}
protected void removeEntity(Entity entity) {
entities.remove(entity);
PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(entity.getEntityId());
for (Player player : getPlayers()) {
try {
player.clientConnection.sendPacket(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
}
protected DataWatcher getDataWatcher(Entity entity) {
return entities.get(entity);
}
public void update() throws IllegalArgumentException, IllegalAccessException {
for (DataWatcher watcher : entities.values()) {
if (watcher.getEntity().getWorld().equals(this)) {
Map<Field, WatchableObject> updated = watcher.update();
PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata(watcher.getEntity(), false, updated.keySet().toArray(new Field[0]));
for (Player player : getPlayers()) {
try {
player.clientConnection.sendPacket(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(watcher.getEntity().getEntityId());
for (Player player : getPlayers()) {
try {
player.clientConnection.sendPacket(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
entities.remove(watcher.getEntity());
}
}
}
@Override
public int hashCode() {

View File

@ -27,17 +27,21 @@
"PacketPlayOutChat": "0x0E",
"PacketPlayOutPlayerAbilities": "0x30",
"PacketPlayOutMapChunk": "0x20",
"PacketPlayOutUnloadChunk": "0x1C",
"PacketPlayOutLightUpdate": "0x23",
"PacketPlayOutKeepAlive": "0x1F",
"PacketPlayOutPlayerInfo": "0x32",
"PacketPlayOutUpdateViewPosition": "0x40",
"PacketPlayOutShowPlayerSkins": "0x44",
"PacketPlayOutDisconnect": "0x19",
"PacketPlayOutPluginMessaging": "0x17",
"PacketPlayOutTabComplete": "0x0F",
"PacketPlayOutDeclareCommands": "0x10",
"PacketPlayOutRespawn": "0x39",
"PacketPlayOutGameState": "0x1D"
"PacketPlayOutGameState": "0x1D",
"PacketPlayOutEntityDestroy": "0x36",
"PacketPlayOutEntityMetadata": "0x44",
"PacketPlayOutSpawnEntity": "0x00",
"PacketPlayOutSpawnEntityLiving": "0x02"
},
"StatusIn": {
"0x01": "PacketStatusInPing",

View File

@ -28,6 +28,12 @@ world-spawn=world;20.5;17;22.5;-90;0
#Reduce debug info
reduced-debug-info=false
#The view distance of the server
view-distance=6
#Ticks per second of the server
ticks-per-second=5
#Server list message in Json
motd={"text":"","extra":[{"text":"Limbo Server!","color":"yellow"}]}