Optimization + added stats

This commit is contained in:
Felix Cravic 2020-04-17 15:58:07 +02:00
parent 944ac43b3f
commit d7372ce853
23 changed files with 307 additions and 43 deletions

View File

@ -40,7 +40,7 @@ public class Main {
shapelessRecipe.addIngredient(ingredient);
recipeManager.addRecipe(shapelessRecipe);
MinecraftServer.getBenchmarkManager().enable(new UpdateOption(2500, TimeUnit.MILLISECOND));
MinecraftServer.getBenchmarkManager().enable(new UpdateOption(60 * 1000, TimeUnit.MILLISECOND));
PlayerInit.init();

View File

@ -133,7 +133,7 @@ public class PlayerInit {
});
player.setEventCallback(PlayerSpawnEvent.class, event -> {
player.setGameMode(GameMode.CREATIVE);
player.setGameMode(GameMode.SURVIVAL);
player.teleport(new Position(0, 75, 0));
/*Random random = new Random();

View File

@ -106,6 +106,7 @@ public class MinecraftServer {
RegistryMain.registerEntities();
RegistryMain.registerSounds();
RegistryMain.registerParticles();
RegistryMain.registerStats();
minecraftServer = new MinecraftServer();

View File

@ -22,6 +22,7 @@ import fr.themode.minestom.scoreboard.BelowNameScoreboard;
import fr.themode.minestom.scoreboard.Team;
import fr.themode.minestom.sound.Sound;
import fr.themode.minestom.sound.SoundCategory;
import fr.themode.minestom.stat.PlayerStatistic;
import fr.themode.minestom.utils.ArrayUtils;
import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.ChunkUtils;
@ -29,9 +30,7 @@ import fr.themode.minestom.utils.Position;
import fr.themode.minestom.world.Dimension;
import fr.themode.minestom.world.LevelType;
import java.util.Collections;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
@ -81,6 +80,9 @@ public class Player extends LivingEntity {
private float flyingSpeed = 0.05f;
private float fieldViewModifier = 0.1f;
// Statistics
private Map<PlayerStatistic, Integer> statisticValueMap = new HashMap<>();
// Vehicle
private PlayerVehicleInformation vehicleInformation;
@ -807,6 +809,10 @@ public class Player extends LivingEntity {
refreshAbilities();
}
public Map<PlayerStatistic, Integer> getStatisticValueMap() {
return statisticValueMap;
}
public PlayerVehicleInformation getVehicleInformation() {
return vehicleInformation;
}

View File

@ -86,7 +86,7 @@ public class Chunk implements Viewable {
private void setCustomBlock(int index, CustomBlock customBlock, Data data) {
UpdateConsumer updateConsumer = customBlock.hasUpdate() ? customBlock::update : null;
setBlock(index, customBlock.getType(), customBlock.getId(), data, updateConsumer);
setBlock(index, customBlock.getBlockId(), customBlock.getId(), data, updateConsumer);
}
private void setBlock(int index, short blockId, short customId, Data data, UpdateConsumer updateConsumer) {

View File

@ -88,7 +88,7 @@ public class InstanceContainer extends Instance {
callBlockPlace(chunk, index, x, y, z);
short id = BLOCK_MANAGER.getBlock(blockId).getType();
short id = BLOCK_MANAGER.getBlock(blockId).getBlockId();
sendBlockChange(chunk, x, y, z, id);
}
}

View File

@ -31,6 +31,10 @@ public class BlockManager {
return this.placementRules.get(blockId);
}
public BlockPlacementRule getBlockPlacementRule(Block block) {
return getBlockPlacementRule(block.getBlockId());
}
public CustomBlock getBlock(String identifier) {
return blocksId.get(identifier);
}

View File

@ -16,12 +16,12 @@ public abstract class CustomBlock {
private static final AtomicInteger idCounter = new AtomicInteger();
private short type;
private short blockId;
private String identifier;
private short id;
public CustomBlock(short type, String identifier) {
this.type = type;
public CustomBlock(short blockId, String identifier) {
this.blockId = blockId;
this.identifier = identifier;
this.id = (short) idCounter.incrementAndGet();
}
@ -52,8 +52,8 @@ public abstract class CustomBlock {
return updateOption.getValue() > 0;
}
public short getType() {
return type;
public short getBlockId() {
return blockId;
}
public String getIdentifier() {

View File

@ -16,6 +16,8 @@ public abstract class BlockPlacementRule {
this(block.getBlockId());
}
public abstract boolean canPlace(Instance instance, BlockPosition blockPosition);
public abstract short blockRefresh(Instance instance, BlockPosition blockPosition);
public short getBlockId() {

View File

@ -11,6 +11,12 @@ public class RedstonePlacementRule extends BlockPlacementRule {
super(Block.REDSTONE_WIRE);
}
@Override
public boolean canPlace(Instance instance, BlockPosition blockPosition) {
// TODO check solid block
return true;
}
@Override
public short blockRefresh(Instance instance, BlockPosition blockPosition) {
int x = blockPosition.getX();

View File

@ -128,9 +128,6 @@ public class InventoryClickProcessor {
return clickResult;
}
StackingRule cursorRule = cursor.getStackingRule();
StackingRule clickedRule = clicked.getStackingRule();
ItemStack resultClicked;
ItemStack resultHeld;

View File

@ -1,5 +1,6 @@
package fr.themode.minestom.listener;
import fr.themode.minestom.MinecraftServer;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.entity.GameMode;
import fr.themode.minestom.entity.Player;
@ -7,7 +8,10 @@ import fr.themode.minestom.event.PlayerBlockInteractEvent;
import fr.themode.minestom.event.PlayerBlockPlaceEvent;
import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.instance.Instance;
import fr.themode.minestom.instance.block.Block;
import fr.themode.minestom.instance.block.BlockManager;
import fr.themode.minestom.instance.block.CustomBlock;
import fr.themode.minestom.instance.block.rule.BlockPlacementRule;
import fr.themode.minestom.inventory.PlayerInventory;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.item.Material;
@ -58,8 +62,17 @@ public class BlockPlacementListener {
PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent((short) 10, blockPosition, packet.hand);
playerBlockPlaceEvent.consumeBlock(player.getGameMode() != GameMode.CREATIVE);
// BlockPlacementRule check
Block block = material.getBlock();
BlockManager blockManager = MinecraftServer.getBlockManager();
BlockPlacementRule blockPlacementRule = blockManager.getBlockPlacementRule(block);
boolean canPlace = true;
if (blockPlacementRule != null) {
canPlace = blockPlacementRule.canPlace(instance, blockPosition);
}
player.callEvent(PlayerBlockPlaceEvent.class, playerBlockPlaceEvent);
if (!playerBlockPlaceEvent.isCancelled()) {
if (!playerBlockPlaceEvent.isCancelled() && canPlace) {
instance.setBlock(blockPosition, material.getBlock());
//instance.setCustomBlock(blockPosition, "updatable");
if (playerBlockPlaceEvent.doesConsumeBlock()) {

View File

@ -10,6 +10,7 @@ import fr.themode.minestom.instance.block.CustomBlock;
import fr.themode.minestom.inventory.PlayerInventory;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket;
import fr.themode.minestom.net.packet.server.play.AcknowledgePlayerDiggingPacket;
import fr.themode.minestom.net.packet.server.play.EntityEffectPacket;
import fr.themode.minestom.net.packet.server.play.RemoveEntityEffectPacket;
import fr.themode.minestom.utils.BlockPosition;
@ -36,13 +37,16 @@ public class PlayerDiggingListener {
player.callEvent(PlayerStartDiggingEvent.class, playerStartDiggingEvent);
if (!playerStartDiggingEvent.isCancelled()) {
player.refreshTargetBlock(customBlock, blockPosition);
// TODO ACKNOWLEDGE
sendAcknowledgePacket(player, blockPosition, customBlock.getBlockId(),
ClientPlayerDiggingPacket.Status.STARTED_DIGGING, true);
} else {
sendAcknowledgePacket(player, blockPosition, customBlock.getBlockId(),
ClientPlayerDiggingPacket.Status.STARTED_DIGGING, false);
}
addEffect(player);
} else {
player.resetTargetBlock();
removeEffect(player);
// TODO ACKNOWLEDGE
}
}
}
@ -99,8 +103,8 @@ public class PlayerDiggingListener {
itemEntity.setPickupDelay(500);
itemEntity.refreshPosition(player.getPosition().clone().add(0, 1.5f, 0));
itemEntity.setInstance(player.getInstance());
Vector velocity = player.getPosition().clone().getDirection().multiply(5);
itemEntity.setVelocity(velocity, 350);
Vector velocity = player.getPosition().clone().getDirection().multiply(6);
itemEntity.setVelocity(velocity, 500);
});
}
@ -121,4 +125,15 @@ public class PlayerDiggingListener {
player.getPlayerConnection().sendPacket(removeEntityEffectPacket);
}
private static void sendAcknowledgePacket(Player player, BlockPosition blockPosition, int blockId,
ClientPlayerDiggingPacket.Status status, boolean success) {
AcknowledgePlayerDiggingPacket acknowledgePlayerDiggingPacket = new AcknowledgePlayerDiggingPacket();
acknowledgePlayerDiggingPacket.blockPosition = blockPosition;
acknowledgePlayerDiggingPacket.blockStateId = blockId;
acknowledgePlayerDiggingPacket.status = status;
acknowledgePlayerDiggingPacket.successful = success;
player.getPlayerConnection().sendPacket(acknowledgePlayerDiggingPacket);
}
}

View File

@ -2,6 +2,12 @@ package fr.themode.minestom.listener;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.client.play.ClientStatusPacket;
import fr.themode.minestom.net.packet.server.play.StatisticsPacket;
import fr.themode.minestom.stat.PlayerStatistic;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class StatusListener {
@ -11,7 +17,25 @@ public class StatusListener {
player.respawn();
break;
case REQUEST_STATS:
// TODO stats
List<StatisticsPacket.Statistic> statisticList = new ArrayList<>();
StatisticsPacket statisticsPacket = new StatisticsPacket();
Map<PlayerStatistic, Integer> playerStatisticValueMap = player.getStatisticValueMap();
for (Map.Entry<PlayerStatistic, Integer> entry : playerStatisticValueMap.entrySet()) {
PlayerStatistic playerStatistic = entry.getKey();
int value = entry.getValue();
StatisticsPacket.Statistic statistic = new StatisticsPacket.Statistic();
statistic.category = playerStatistic.getCategory();
statistic.statisticId = playerStatistic.getStatisticId();
statistic.value = value;
statisticList.add(statistic);
}
statisticsPacket.statistics = statisticList.toArray(new StatisticsPacket.Statistic[statisticList.size()]);
player.getPlayerConnection().sendPacket(statisticsPacket);
break;
}
}

View File

@ -36,9 +36,11 @@ public class NettyDecoder extends ByteToMessageDecoder {
} else {
int readable = buffer.readableBytes();
if (readable < packetLength) {
// Wait for bytes to arrive
bytesToRead = packetLength;
return;
} else {
// There are enough bytes, read them
packetHandler.buffer = buffer.readBytes(packetLength);
bytesToRead = 0;
}

View File

@ -3,6 +3,7 @@ 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;
import fr.themode.minestom.stat.StatisticCategory;
public class StatisticsPacket implements ServerPacket {
@ -21,27 +22,15 @@ public class StatisticsPacket implements ServerPacket {
return ServerPacketIdentifier.STATISTICS;
}
public enum StatisticCategory {
MINED,
CRAFTED,
USED,
BROKEN,
PICKED_UP,
DROPPED,
KILLED,
KILLED_BY,
CUSTOM
}
public static class Statistic {
public StatisticCategory category;
public int statisticIdentifier;
public int statisticId;
public int value;
private void write(PacketWriter writer) {
writer.writeVarInt(category.ordinal());
writer.writeVarInt(statisticIdentifier);
writer.writeVarInt(statisticId);
writer.writeVarInt(value);
}
}

View File

@ -21,18 +21,18 @@ public class PlayerConnection {
}
public void sendPacket(ByteBuf buffer) {
channel.writeAndFlush(buffer.copy());
buffer.retain();
channel.writeAndFlush(buffer);
}
public void writePacket(ByteBuf buffer) {
channel.write(buffer.copy());
buffer.retain();
channel.write(buffer);
}
public void sendPacket(ServerPacket serverPacket) {
if (isOnline()) {
ByteBuf buffer = PacketUtils.writePacket(serverPacket);
sendPacket(buffer);
}
ByteBuf buffer = PacketUtils.writePacket(serverPacket);
sendPacket(buffer);
}
public void flush() {

View File

@ -9,6 +9,7 @@ import fr.themode.minestom.instance.block.Block;
import fr.themode.minestom.item.Material;
import fr.themode.minestom.particle.Particle;
import fr.themode.minestom.sound.Sound;
import fr.themode.minestom.stat.StatisticType;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
@ -25,6 +26,7 @@ public class RegistryMain {
public static final String ENTITIES_PATH = "registry/registries.json";
public static final String SOUNDS_PATH = "registry/registries.json";
public static final String PARTICLES_PATH = "registry/registries.json";
public static final String STATS_PATH = "registry/registries.json";
public static void main(String[] args) {
List<RegistryBlock> blocks = parseBlocks(BLOCKS_PATH);
@ -32,11 +34,12 @@ public class RegistryMain {
List<RegistryEntityType> entities = parseEntities(ENTITIES_PATH);
List<RegistrySound> sounds = parseSounds(SOUNDS_PATH);
List<RegistryParticle> particles = parseParticles(PARTICLES_PATH);
List<RegistryStat> stats = parseStats(STATS_PATH);
//writeBlocksClass(blocks);
//writeItemsClass(items);
//writeEntitiesClass(entities);
//writeSoundsClass(sounds);
writeParticlesClass(particles);
writeStatsClass(stats);
}
public static void registerBlocks() {
@ -103,6 +106,15 @@ public class RegistryMain {
}
}
public static void registerStats() {
List<RegistryStat> registryStats = parseStats(STATS_PATH);
for (RegistryStat registryStat : registryStats) {
StatisticType stat = StatisticType.valueOf(registryStat.name);
stat.setIdentifier(registryStat.id);
}
}
private static void writeBlocksClass(List<RegistryBlock> blocks) {
for (RegistryBlock registryBlock : blocks) {
String line = registryBlock.name + ",";
@ -139,6 +151,13 @@ public class RegistryMain {
}
}
private static void writeStatsClass(List<RegistryStat> stats) {
for (RegistryStat registryStat : stats) {
String line = registryStat.name + ",";
System.out.println(line);
}
}
private static List<RegistryBlock> parseBlocks(String path) {
List<RegistryBlock> blocks = new ArrayList<>();
@ -329,4 +348,34 @@ public class RegistryMain {
return registryParticles;
}
private static List<RegistryStat> parseStats(String path) {
List<RegistryStat> registryStats = new ArrayList<>();
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(path));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Gson gson = new Gson();
JsonObject obj = gson.fromJson(bufferedReader, JsonObject.class);
JsonObject itemsObject = obj.getAsJsonObject("minecraft:custom_stat");
JsonObject entriesObject = itemsObject.getAsJsonObject("entries");
Set<Map.Entry<String, JsonElement>> entriesEntries = entriesObject.entrySet();//will return members of your object
for (Map.Entry<String, JsonElement> entryEntry : entriesEntries) {
RegistryStat registryStat = new RegistryStat();
registryStats.add(registryStat);
String item = entryEntry.getKey();
String itemName = item.toUpperCase().replace("MINECRAFT:", "").replace(".", "_");
registryStat.name = itemName;
short id = entryEntry.getValue().getAsJsonObject().get("protocol_id").getAsShort();
registryStat.id = id;
}
return registryStats;
}
}

View File

@ -0,0 +1,8 @@
package fr.themode.minestom.registry;
public class RegistryStat {
protected String name;
protected int id;
}

View File

@ -0,0 +1,24 @@
package fr.themode.minestom.stat;
public class PlayerStatistic {
private StatisticCategory category;
private int statisticId;
public PlayerStatistic(StatisticCategory category, int statisticId) {
this.category = category;
this.statisticId = statisticId;
}
public PlayerStatistic(StatisticType type) {
this(StatisticCategory.CUSTOM, type.getId());
}
public StatisticCategory getCategory() {
return category;
}
public int getStatisticId() {
return statisticId;
}
}

View File

@ -0,0 +1,13 @@
package fr.themode.minestom.stat;
public enum StatisticCategory {
MINED,
CRAFTED,
USED,
BROKEN,
PICKED_UP,
DROPPED,
KILLED,
KILLED_BY,
CUSTOM
}

View File

@ -0,0 +1,96 @@
package fr.themode.minestom.stat;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public enum StatisticType {
LEAVE_GAME,
PLAY_ONE_MINUTE,
TIME_SINCE_DEATH,
TIME_SINCE_REST,
SNEAK_TIME,
WALK_ONE_CM,
CROUCH_ONE_CM,
SPRINT_ONE_CM,
WALK_ON_WATER_ONE_CM,
FALL_ONE_CM,
CLIMB_ONE_CM,
FLY_ONE_CM,
WALK_UNDER_WATER_ONE_CM,
MINECART_ONE_CM,
BOAT_ONE_CM,
PIG_ONE_CM,
HORSE_ONE_CM,
AVIATE_ONE_CM,
SWIM_ONE_CM,
JUMP,
DROP,
DAMAGE_DEALT,
DAMAGE_DEALT_ABSORBED,
DAMAGE_DEALT_RESISTED,
DAMAGE_TAKEN,
DAMAGE_BLOCKED_BY_SHIELD,
DAMAGE_ABSORBED,
DAMAGE_RESISTED,
DEATHS,
MOB_KILLS,
ANIMALS_BRED,
PLAYER_KILLS,
FISH_CAUGHT,
TALKED_TO_VILLAGER,
TRADED_WITH_VILLAGER,
EAT_CAKE_SLICE,
FILL_CAULDRON,
USE_CAULDRON,
CLEAN_ARMOR,
CLEAN_BANNER,
CLEAN_SHULKER_BOX,
INTERACT_WITH_BREWINGSTAND,
INTERACT_WITH_BEACON,
INSPECT_DROPPER,
INSPECT_HOPPER,
INSPECT_DISPENSER,
PLAY_NOTEBLOCK,
TUNE_NOTEBLOCK,
POT_FLOWER,
TRIGGER_TRAPPED_CHEST,
OPEN_ENDERCHEST,
ENCHANT_ITEM,
PLAY_RECORD,
INTERACT_WITH_FURNACE,
INTERACT_WITH_CRAFTING_TABLE,
OPEN_CHEST,
SLEEP_IN_BED,
OPEN_SHULKER_BOX,
OPEN_BARREL,
INTERACT_WITH_BLAST_FURNACE,
INTERACT_WITH_SMOKER,
INTERACT_WITH_LECTERN,
INTERACT_WITH_CAMPFIRE,
INTERACT_WITH_CARTOGRAPHY_TABLE,
INTERACT_WITH_LOOM,
INTERACT_WITH_STONECUTTER,
BELL_RING,
RAID_TRIGGER,
RAID_WIN,
INTERACT_WITH_ANVIL,
INTERACT_WITH_GRINDSTONE;
private static Int2ObjectOpenHashMap<StatisticType> map = new Int2ObjectOpenHashMap();
private int id;
public static StatisticType fromId(int id) {
return map.get(id);
}
public void setIdentifier(int id) {
this.id = id;
map.put(id, this);
}
public int getId() {
return id;
}
}

View File

@ -70,6 +70,21 @@ public class NbtReaderUtils {
String listName = reader.readShortSizedString();
if (listName.equals("StoredEnchantments")) {
boolean end = false;
while (!end) {
reader.readByte(); // Should be a compound (0x0A)
int size = reader.readInteger();
byte test = reader.readByte();
String lvlName = reader.readShortSizedString();
short lvl = reader.readShort();
byte test2 = reader.readByte();
String idName = reader.readShortSizedString();
short id = reader.readShort();
System.out.println("size: " + lvl + " : " + id);
end = true;
}
// TODO
}
@ -112,7 +127,7 @@ public class NbtReaderUtils {
String listName = reader.readShortSizedString();
if (listName.equals("Lore")) {
byte loreType = reader.readByte(); // Should always be 0x08 (TAG_String)
reader.readByte(); // lore type, should always be 0x08 (TAG_String)
int size = reader.readInteger();
ArrayList<String> lore = new ArrayList<>(size);