Merge branch 'h2-playermanager' into proto_1.12.2
This commit is contained in:
@@ -1,7 +1,3 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2018-06-29
|
|
||||||
*/
|
|
||||||
package mc.core.embedded;
|
package mc.core.embedded;
|
||||||
|
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
@@ -65,13 +61,8 @@ public class FakePlayerManager implements PlayerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Player> getPlayer(String name) {
|
public Player getPlayer(String name) {
|
||||||
return Optional.empty();
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Player> getPlayerById(int id) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -80,7 +71,7 @@ public class FakePlayerManager implements PlayerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCountOnlinePlayers() {
|
public int getCountPlayers() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,4 +79,9 @@ public class FakePlayerManager implements PlayerManager {
|
|||||||
public NetChannel getBroadcastChannel() {
|
public NetChannel getBroadcastChannel() {
|
||||||
return FAKE_NET_CHANNEL;
|
return FAKE_NET_CHANNEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player getOfflinePlayer(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2018-04-15
|
|
||||||
*/
|
|
||||||
package mc.core.player;
|
|
||||||
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import mc.core.Config;
|
|
||||||
import mc.core.EntityLocation;
|
|
||||||
import mc.core.network.BroadcastNetChannel;
|
|
||||||
import mc.core.network.NetChannel;
|
|
||||||
import mc.core.world.World;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class InMemoryPlayerManager implements PlayerManager, Runnable {
|
|
||||||
private static final Random rand = new Random();
|
|
||||||
private List<Player> players;
|
|
||||||
private final Object lock = new Object();
|
|
||||||
@Setter
|
|
||||||
private int keepAliveInterval = 1;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public InMemoryPlayerManager(Config config) {
|
|
||||||
final int c = config.getMaxPlayers() > 50 ? 50 : config.getMaxPlayers();
|
|
||||||
players = Collections.synchronizedList(new ArrayList<>(c));
|
|
||||||
(new Thread(this, "KeepAlive")).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Player createPlayer(String name, EntityLocation location, World world) {
|
|
||||||
SimplePlayer player = new SimplePlayer();
|
|
||||||
player.setId(rand.nextInt(10000));
|
|
||||||
player.setUUID(UUID.nameUUIDFromBytes(name.getBytes()));
|
|
||||||
player.setName(name);
|
|
||||||
player.getLocation().set(location);
|
|
||||||
player.setWorld(world);
|
|
||||||
player.setSettings(new PlayerSettings());
|
|
||||||
|
|
||||||
synchronized (lock) {
|
|
||||||
players.add(player);
|
|
||||||
lock.notify();
|
|
||||||
}
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void joinServer(Player player) {
|
|
||||||
((SimplePlayer) player).setOnline(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leftServer(Player player) {
|
|
||||||
((SimplePlayer) player).setOnline(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Player> getPlayer(final String name) {
|
|
||||||
return players.stream()
|
|
||||||
.filter(player -> player.getName().equalsIgnoreCase(name))
|
|
||||||
.findFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Player> getPlayerById(final int id) {
|
|
||||||
return players.stream()
|
|
||||||
.filter(player -> player.getId() == id)
|
|
||||||
.findFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Player> getPlayers() {
|
|
||||||
return players.stream().filter(Player::isOnline).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCountOnlinePlayers() {
|
|
||||||
return (int) players.stream().filter(Player::isOnline).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public NetChannel getBroadcastChannel() {
|
|
||||||
return new BroadcastNetChannel(players.stream().filter(Player::isOnline));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
|
||||||
synchronized (lock) {
|
|
||||||
while (players.size() == 0) {
|
|
||||||
try {
|
|
||||||
lock.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getBroadcastChannel().sendKeepAlive();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(keepAliveInterval);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
public interface Player {
|
public interface Player {
|
||||||
int getId();
|
int getId();
|
||||||
UUID getUUID();
|
UUID getUuid();
|
||||||
String getName();
|
String getName();
|
||||||
boolean isOnline();
|
boolean isOnline();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2018-04-15
|
|
||||||
*/
|
|
||||||
package mc.core.player;
|
package mc.core.player;
|
||||||
|
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
@@ -9,15 +5,16 @@ import mc.core.network.NetChannel;
|
|||||||
import mc.core.world.World;
|
import mc.core.world.World;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public interface PlayerManager {
|
public interface PlayerManager {
|
||||||
Player createPlayer(String name, EntityLocation location, World world);
|
Player createPlayer(String name, EntityLocation location, World world);
|
||||||
void joinServer(Player player);
|
void joinServer(Player player);
|
||||||
void leftServer(Player player);
|
void leftServer(Player player);
|
||||||
Optional<Player> getPlayer(String name);
|
|
||||||
Optional<Player> getPlayerById(int id);
|
Player getPlayer(String name);
|
||||||
List<Player> getPlayers();
|
List<Player> getPlayers();
|
||||||
int getCountOnlinePlayers();
|
int getCountPlayers();
|
||||||
NetChannel getBroadcastChannel();
|
NetChannel getBroadcastChannel();
|
||||||
|
|
||||||
|
Player getOfflinePlayer(String name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import mc.core.world.block.BlockLocation;
|
|||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.chunk.Chunk;
|
||||||
|
|
||||||
public interface World {
|
public interface World {
|
||||||
|
String getName();
|
||||||
WorldType getWorldType();
|
WorldType getWorldType();
|
||||||
|
|
||||||
EntityLocation getSpawn();
|
EntityLocation getSpawn();
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import mc.core.world.chunk.ChunkSection;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class FlatWorld implements World {
|
public class FlatWorld implements World {
|
||||||
|
@Getter
|
||||||
|
private final String name = "flat";
|
||||||
@Getter
|
@Getter
|
||||||
private final WorldType worldType = WorldType.FLAT;
|
private final WorldType worldType = WorldType.FLAT;
|
||||||
@Setter
|
@Setter
|
||||||
|
|||||||
16
h2_playermanager/build.gradle
Normal file
16
h2_playermanager/build.gradle
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
version '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
/* Core */
|
||||||
|
compile_excludeCopy project(':core')
|
||||||
|
|
||||||
|
/* Spring */
|
||||||
|
compile (group: 'org.springframework', name: 'spring-jdbc', version: spring_version) {
|
||||||
|
exclude group: 'commons-logging'
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Database */
|
||||||
|
compile (group: 'com.h2database', name: 'h2', version: '1.4.196')
|
||||||
|
|
||||||
|
testCompile (group: 'org.springframework', name: 'spring-test', version: spring_version)
|
||||||
|
}
|
||||||
@@ -1,38 +1,31 @@
|
|||||||
/*
|
package mc.core.h2db;
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2018-04-23
|
|
||||||
*/
|
|
||||||
package mc.core.player;
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
import mc.core.exception.ResourceUnloadedException;
|
import mc.core.exception.ResourceUnloadedException;
|
||||||
import mc.core.network.NetChannel;
|
import mc.core.network.NetChannel;
|
||||||
|
import mc.core.player.Player;
|
||||||
|
import mc.core.player.PlayerSettings;
|
||||||
import mc.core.world.World;
|
import mc.core.world.World;
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
import java.lang.ref.Reference;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class SimplePlayer implements Player {
|
public class H2Player implements Player {
|
||||||
private int id;
|
private int id;
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
private String name;
|
private String name;
|
||||||
private boolean online = false;
|
private boolean online = false;
|
||||||
|
private List<Integer> loadedChunks;
|
||||||
private NetChannel channel;
|
private NetChannel channel;
|
||||||
private EntityLocation location = EntityLocation.ZERO();
|
private EntityLocation location;
|
||||||
private Reference<World> $refWorld;
|
private Reference<World> $refWorld;
|
||||||
private boolean flying = false;
|
private boolean flying = false;
|
||||||
private PlayerSettings settings;
|
private PlayerSettings settings;
|
||||||
private List<Integer> loadedChunks = new ArrayList<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UUID getUUID() {
|
|
||||||
return uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public World getWorld() {
|
public World getWorld() {
|
||||||
@@ -47,10 +40,24 @@ public class SimplePlayer implements Player {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setWorld(World world) {
|
public void setWorld(World world) {
|
||||||
|
if (world == null) {
|
||||||
|
this.$refWorld = null;
|
||||||
|
} else {
|
||||||
this.$refWorld = new WeakReference<>(world);
|
this.$refWorld = new WeakReference<>(world);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setUUID(UUID uuid) {
|
@Override
|
||||||
this.uuid = uuid;
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (obj == null || getClass() != obj.getClass()) return false;
|
||||||
|
H2Player player = (H2Player) obj;
|
||||||
|
return id == player.id &&
|
||||||
|
Objects.equals(uuid, player.uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id, uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
259
h2_playermanager/src/main/java/mc/core/h2db/H2PlayerDAO.java
Normal file
259
h2_playermanager/src/main/java/mc/core/h2db/H2PlayerDAO.java
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
package mc.core.h2db;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import mc.core.EntityLocation;
|
||||||
|
import mc.core.world.World;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||||
|
import org.springframework.jdbc.support.KeyHolder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class H2PlayerDAO {
|
||||||
|
private static String INSERT_SQL, INSERT2_SQL,
|
||||||
|
SELECT_BYNAME_SQL, SELECT_BYID_SQL,
|
||||||
|
UPDATE_SQL, UPDATE_LOCATION_SQL,
|
||||||
|
DELETE_SQL;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
@Autowired
|
||||||
|
private World world;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() throws IOException {
|
||||||
|
jdbcTemplate.execute(IOUtils.resourceToString("/sqls/create_tables.sql", StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPlayer(H2Player player) throws SQLException {
|
||||||
|
if (player.getName() == null || player.getName().isEmpty()) {
|
||||||
|
throw new SQLException("Field 'name' is " + (player.getName() == null ? "null" : "empty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getUuid() == null) {
|
||||||
|
throw new SQLException("Field 'uuid' is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getLocation() == null) {
|
||||||
|
throw new SQLException("Fields 'location_*' is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getWorld() == null) {
|
||||||
|
throw new SQLException("Field 'location_world' is null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertWithoutId(H2Player player) throws SQLException {
|
||||||
|
KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||||
|
|
||||||
|
int affectedRows = jdbcTemplate.update(psc -> {
|
||||||
|
PreparedStatement stmt = psc.prepareStatement(INSERT_SQL, Statement.RETURN_GENERATED_KEYS);
|
||||||
|
|
||||||
|
stmt.setString(1, player.getUuid().toString());
|
||||||
|
stmt.setString(2, player.getName());
|
||||||
|
stmt.setDouble(3, player.getLocation().getX());
|
||||||
|
stmt.setDouble(4, player.getLocation().getY());
|
||||||
|
stmt.setDouble(5, player.getLocation().getZ());
|
||||||
|
stmt.setFloat(6, player.getLocation().getYaw());
|
||||||
|
stmt.setFloat(7, player.getLocation().getPitch());
|
||||||
|
stmt.setString(8, player.getWorld().getName());
|
||||||
|
|
||||||
|
return stmt;
|
||||||
|
}, keyHolder);
|
||||||
|
|
||||||
|
if (affectedRows == 0) {
|
||||||
|
throw new SQLException("Serialize player failed: no rows affected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
player.setId(keyHolder.getKey().intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertWithId(H2Player player) throws SQLException {
|
||||||
|
int affectedRows = jdbcTemplate.update(psc -> {
|
||||||
|
PreparedStatement stmt = psc.prepareStatement(INSERT2_SQL);
|
||||||
|
|
||||||
|
stmt.setString(1, player.getUuid().toString());
|
||||||
|
stmt.setString(2, player.getName());
|
||||||
|
stmt.setDouble(3, player.getLocation().getX());
|
||||||
|
stmt.setDouble(4, player.getLocation().getY());
|
||||||
|
stmt.setDouble(5, player.getLocation().getZ());
|
||||||
|
stmt.setFloat(6, player.getLocation().getYaw());
|
||||||
|
stmt.setFloat(7, player.getLocation().getPitch());
|
||||||
|
stmt.setString(8, player.getWorld().getName());
|
||||||
|
stmt.setInt(9, player.getId());
|
||||||
|
|
||||||
|
return stmt;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (affectedRows == 0) {
|
||||||
|
throw new SQLException("Serialize player failed: no rows affected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insert(H2Player player) throws SQLException {
|
||||||
|
checkPlayer(player);
|
||||||
|
|
||||||
|
if (player.getId() > 0) {
|
||||||
|
insertWithId(player);
|
||||||
|
} else {
|
||||||
|
insertWithoutId(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void locationDeserialize(H2Player playerBuffer, ResultSet resultSet) throws SQLException {
|
||||||
|
if (!world.getName().equals(resultSet.getString("location_world"))) {
|
||||||
|
log.warn("Unknown world \"{}\"", resultSet.getString("location_world"));
|
||||||
|
log.warn("Using default (spawn) location for user \"{}\"", playerBuffer.getName());
|
||||||
|
playerBuffer.setLocation(world.getSpawn().clone());
|
||||||
|
} else {
|
||||||
|
playerBuffer.setLocation(new EntityLocation(
|
||||||
|
resultSet.getDouble("location_x"),
|
||||||
|
resultSet.getDouble("location_y"),
|
||||||
|
resultSet.getDouble("location_z"),
|
||||||
|
resultSet.getFloat("location_yaw"),
|
||||||
|
resultSet.getFloat("location_pitch")
|
||||||
|
));
|
||||||
|
playerBuffer.setWorld(world);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getByName(H2Player playerBuffer) throws SQLException {
|
||||||
|
if (playerBuffer.getName() == null || playerBuffer.getName().isEmpty()) {
|
||||||
|
throw new SQLException("Field 'name' is " + (playerBuffer.getName() == null ? "null" : "empty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean[] result = new boolean[]{false};
|
||||||
|
jdbcTemplate.query(SELECT_BYNAME_SQL,
|
||||||
|
ps -> ps.setString(1, playerBuffer.getName()),
|
||||||
|
rs -> {
|
||||||
|
playerBuffer.setId(rs.getInt("id"));
|
||||||
|
playerBuffer.setUuid(UUID.fromString(rs.getString("uuid")));
|
||||||
|
locationDeserialize(playerBuffer, rs);
|
||||||
|
result[0] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getById(H2Player playerBuffer) throws SQLException {
|
||||||
|
if (playerBuffer.getId() == 0) {
|
||||||
|
throw new SQLException("Field 'id' is zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean[] result = new boolean[]{false};
|
||||||
|
jdbcTemplate.query(SELECT_BYID_SQL,
|
||||||
|
ps -> ps.setInt(1, playerBuffer.getId()),
|
||||||
|
rs -> {
|
||||||
|
playerBuffer.setUuid(UUID.fromString(rs.getString("uuid")));
|
||||||
|
playerBuffer.setName(rs.getString("name"));
|
||||||
|
locationDeserialize(playerBuffer, rs);
|
||||||
|
result[0] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(H2Player player) throws SQLException {
|
||||||
|
if (player.getId() == 0) {
|
||||||
|
throw new SQLException("Field 'id' is zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPlayer(player);
|
||||||
|
|
||||||
|
int affectedRows = jdbcTemplate.update(UPDATE_SQL, pss -> {
|
||||||
|
pss.setInt(9, player.getId());
|
||||||
|
pss.setString(1, player.getUuid().toString());
|
||||||
|
pss.setString(2, player.getName());
|
||||||
|
pss.setDouble(3, player.getLocation().getX());
|
||||||
|
pss.setDouble(4, player.getLocation().getY());
|
||||||
|
pss.setDouble(5, player.getLocation().getZ());
|
||||||
|
pss.setFloat(6, player.getLocation().getYaw());
|
||||||
|
pss.setFloat(7, player.getLocation().getPitch());
|
||||||
|
pss.setString(8, player.getWorld().getName());
|
||||||
|
});
|
||||||
|
|
||||||
|
if (affectedRows == 0) {
|
||||||
|
throw new SQLException("Update player failed, no rows affected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateLocation(H2Player player) throws SQLException {
|
||||||
|
if (player.getId() == 0) {
|
||||||
|
throw new SQLException("Field 'id' is zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getLocation() == null) {
|
||||||
|
throw new SQLException("Fields 'location_*' is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getWorld() == null) {
|
||||||
|
throw new SQLException("Field 'location_world' is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getLocation() == null) {
|
||||||
|
throw new SQLException("Fields 'location_*' is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getWorld() == null) {
|
||||||
|
throw new SQLException("Field 'location_world' is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
int affectedRows = jdbcTemplate.update(connection -> {
|
||||||
|
PreparedStatement stmt = connection.prepareStatement(UPDATE_LOCATION_SQL);
|
||||||
|
|
||||||
|
stmt.setInt(7, player.getId());
|
||||||
|
stmt.setDouble(1, player.getLocation().getX());
|
||||||
|
stmt.setDouble(2, player.getLocation().getY());
|
||||||
|
stmt.setDouble(3, player.getLocation().getZ());
|
||||||
|
stmt.setFloat(4, player.getLocation().getYaw());
|
||||||
|
stmt.setFloat(5, player.getLocation().getPitch());
|
||||||
|
stmt.setString(6, player.getWorld().getName());
|
||||||
|
|
||||||
|
return stmt;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (affectedRows == 0) {
|
||||||
|
throw new SQLException("Update player failed, no rows affected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(H2Player player) throws SQLException {
|
||||||
|
if (player.getId() == 0) {
|
||||||
|
throw new SQLException("Field 'id' is zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
int affectedRows = jdbcTemplate.update(DELETE_SQL, pss -> pss.setInt(1, player.getId()));
|
||||||
|
|
||||||
|
if (affectedRows == 0) {
|
||||||
|
throw new SQLException("Remove player failed, no rows affected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
player.setId(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
INSERT_SQL = IOUtils.resourceToString("/sqls/insert_player.sql", StandardCharsets.UTF_8);
|
||||||
|
INSERT2_SQL = IOUtils.resourceToString("/sqls/insert_player_withId.sql", StandardCharsets.UTF_8);
|
||||||
|
SELECT_BYNAME_SQL = IOUtils.resourceToString("/sqls/select_player_byName.sql", StandardCharsets.UTF_8);
|
||||||
|
SELECT_BYID_SQL = IOUtils.resourceToString("/sqls/select_player_byId.sql", StandardCharsets.UTF_8);
|
||||||
|
UPDATE_SQL = IOUtils.resourceToString("/sqls/update_player.sql", StandardCharsets.UTF_8);
|
||||||
|
UPDATE_LOCATION_SQL = IOUtils.resourceToString("/sqls/update_player_location.sql", StandardCharsets.UTF_8);
|
||||||
|
DELETE_SQL = IOUtils.resourceToString("/sqls/delete_player.sql", StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Load sql templates", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
179
h2_playermanager/src/main/java/mc/core/h2db/H2PlayerManager.java
Normal file
179
h2_playermanager/src/main/java/mc/core/h2db/H2PlayerManager.java
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package mc.core.h2db;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import mc.core.EntityLocation;
|
||||||
|
import mc.core.network.BroadcastNetChannel;
|
||||||
|
import mc.core.network.NetChannel;
|
||||||
|
import mc.core.player.Player;
|
||||||
|
import mc.core.player.PlayerManager;
|
||||||
|
import mc.core.player.PlayerSettings;
|
||||||
|
import mc.core.world.World;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.slf4j.helpers.MessageFormatter.format;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class H2PlayerManager implements PlayerManager, Runnable {
|
||||||
|
@Setter
|
||||||
|
@Autowired
|
||||||
|
private H2PlayerDAO h2playerDao;
|
||||||
|
private List<H2Player> playerList = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
private final Object lock = new Object();
|
||||||
|
@Setter
|
||||||
|
private int keepAliveInterval = 1;
|
||||||
|
@Autowired
|
||||||
|
private World world;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
(new Thread(this, "KeepAlive")).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player createPlayer(String name, EntityLocation location, World world) {
|
||||||
|
//TODO в дальнейшем следует в этом методе только имплементацию Player
|
||||||
|
H2Player h2Player = new H2Player();
|
||||||
|
h2Player.setName(name);
|
||||||
|
h2Player.setUuid(UUID.randomUUID());
|
||||||
|
h2Player.setLocation(location.clone());
|
||||||
|
h2Player.setLoadedChunks(new ArrayList<>());
|
||||||
|
h2Player.setWorld(world);
|
||||||
|
h2Player.setSettings(new PlayerSettings());
|
||||||
|
|
||||||
|
try {
|
||||||
|
h2playerDao.insert(h2Player);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error(format("Insert player '{}'", h2Player.getName()).getMessage(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h2Player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void joinServer(Player player) {
|
||||||
|
//TODO в дальнейшем следует именно этому методу передать функции инсерта в БД
|
||||||
|
H2Player h2Player = (H2Player) player;
|
||||||
|
synchronized (lock) {
|
||||||
|
playerList.add(h2Player);
|
||||||
|
h2Player.setOnline(true);
|
||||||
|
lock.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void leftServer(Player player) {
|
||||||
|
H2Player h2Player = (H2Player) player;
|
||||||
|
try {
|
||||||
|
h2playerDao.update(h2Player);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error(format("Update player '{}'", h2Player.getName()).getMessage(), e);
|
||||||
|
synchronized (lock) {
|
||||||
|
playerList.remove(h2Player);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
h2Player.setId(0);
|
||||||
|
h2Player.setOnline(false);
|
||||||
|
h2Player.setWorld(null);
|
||||||
|
h2Player.getLoadedChunks().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player getPlayer(String name) {
|
||||||
|
return playerList.stream()
|
||||||
|
.filter(player -> player.getName().equals(name))
|
||||||
|
.filter(H2Player::isOnline)
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Player> getPlayers() {
|
||||||
|
return playerList.stream()
|
||||||
|
.filter(H2Player::isOnline)
|
||||||
|
.collect(ImmutableList.toImmutableList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCountPlayers() {
|
||||||
|
return (int) playerList.stream()
|
||||||
|
.filter(H2Player::isOnline)
|
||||||
|
.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetChannel getBroadcastChannel() {
|
||||||
|
return new BroadcastNetChannel(
|
||||||
|
playerList.stream()
|
||||||
|
.filter(H2Player::isOnline)
|
||||||
|
.map(player -> (Player)player)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player getOfflinePlayer(String name) {
|
||||||
|
H2Player h2Player = playerList.stream()
|
||||||
|
.filter(player -> player.getName().equals(name))
|
||||||
|
.filter(player -> !player.isOnline())
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
|
||||||
|
if (h2Player == null) {
|
||||||
|
h2Player = playerList.stream()
|
||||||
|
.filter(player -> !player.isOnline())
|
||||||
|
.findAny().orElse(new H2Player());
|
||||||
|
h2Player.setName(name);
|
||||||
|
|
||||||
|
boolean result;
|
||||||
|
try {
|
||||||
|
result = h2playerDao.getByName(h2Player);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error(format("getByName player '{}'", h2Player.getName()).getMessage(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
h2Player.setWorld(world);
|
||||||
|
return h2Player;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h2Player.setWorld(world);
|
||||||
|
return h2Player;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
|
while(getCountPlayers() == 0) {
|
||||||
|
synchronized (lock) {
|
||||||
|
try {
|
||||||
|
lock.wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getBroadcastChannel().sendKeepAlive();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(keepAliveInterval);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
h2_playermanager/src/main/resources/sqls/create_tables.sql
Normal file
14
h2_playermanager/src/main/resources/sqls/create_tables.sql
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS players (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
|
||||||
|
uuid VARCHAR(36) NOT NULL UNIQUE,
|
||||||
|
name VARCHAR(16) NOT NULL,
|
||||||
|
location_x DOUBLE NOT NULL,
|
||||||
|
location_y DOUBLE NOT NULL,
|
||||||
|
location_z DOUBLE NOT NULL,
|
||||||
|
location_yaw FLOAT NOT NULL,
|
||||||
|
location_pitch FLOAT NOT NULL,
|
||||||
|
location_world VARCHAR(64) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_players_uuid ON players(uuid);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_players_name ON players(name);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DELETE FROM players WHERE id = ?;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
INSERT INTO players (uuid, name, location_x, location_y, location_z, location_yaw, location_pitch, location_world)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
INSERT INTO players (uuid, name, location_x, location_y, location_z, location_yaw, location_pitch, location_world, id)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
SELECT uuid, name, location_x, location_y, location_z, location_yaw, location_pitch, location_world
|
||||||
|
FROM players WHERE id = ?
|
||||||
|
LIMIT 1;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
SELECT id, uuid, location_x, location_y, location_z, location_yaw, location_pitch, location_world
|
||||||
|
FROM players WHERE name LIKE ?
|
||||||
|
LIMIT 1;
|
||||||
10
h2_playermanager/src/main/resources/sqls/update_player.sql
Normal file
10
h2_playermanager/src/main/resources/sqls/update_player.sql
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
UPDATE players
|
||||||
|
SET uuid = ?,
|
||||||
|
name = ?,
|
||||||
|
location_x = ?,
|
||||||
|
location_y = ?,
|
||||||
|
location_z = ?,
|
||||||
|
location_yaw = ?,
|
||||||
|
location_pitch = ?,
|
||||||
|
location_world = ?
|
||||||
|
WHERE id = ?;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
UPDATE players
|
||||||
|
SET location_x = ?,
|
||||||
|
location_y = ?,
|
||||||
|
location_z = ?,
|
||||||
|
location_yaw = ?,
|
||||||
|
location_pitch = ?,
|
||||||
|
location_world = ?
|
||||||
|
WHERE id = ?;
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package mc.core.h2db;
|
||||||
|
|
||||||
|
import mc.core.world.World;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan("mc.core.h2db")
|
||||||
|
public class SpringConfig {
|
||||||
|
@Bean
|
||||||
|
public World mockWorld() {
|
||||||
|
World mockWorld = mock(World.class);
|
||||||
|
when(mockWorld.getName()).thenReturn("mock_world");
|
||||||
|
return mockWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSource dataSource() {
|
||||||
|
DriverManagerDataSource dmds = new DriverManagerDataSource();
|
||||||
|
dmds.setDriverClassName("org.h2.Driver");
|
||||||
|
dmds.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
|
||||||
|
dmds.setUsername("sa");
|
||||||
|
return dmds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
|
||||||
|
JdbcTemplate jdbcTemplate = new JdbcTemplate();
|
||||||
|
jdbcTemplate.setDataSource(dataSource);
|
||||||
|
return jdbcTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Scope(value = "prototype")
|
||||||
|
public H2PlayerManager h2PlayerManager(H2PlayerDAO h2PlayerDAO) {
|
||||||
|
H2PlayerManager playerManager = new H2PlayerManager();
|
||||||
|
playerManager.setH2playerDao(h2PlayerDAO);
|
||||||
|
return playerManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
286
h2_playermanager/src/test/java/mc/core/h2db/TestDAO.java
Normal file
286
h2_playermanager/src/test/java/mc/core/h2db/TestDAO.java
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
package mc.core.h2db;
|
||||||
|
|
||||||
|
import mc.core.EntityLocation;
|
||||||
|
import mc.core.world.World;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ContextConfiguration(classes = {SpringConfig.class})
|
||||||
|
public class TestDAO {
|
||||||
|
@Autowired
|
||||||
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
@Autowired
|
||||||
|
private World mockWorld;
|
||||||
|
@Autowired
|
||||||
|
private H2PlayerDAO playerDAO;
|
||||||
|
private H2Player player;
|
||||||
|
|
||||||
|
private void createPlayer() {
|
||||||
|
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||||
|
final double minD = 0.0d, maxD = 10.0d;
|
||||||
|
final float minF = 0.0f, maxF = 359.9f;
|
||||||
|
final int minI = 1000, maxI = 9999;
|
||||||
|
|
||||||
|
player = new H2Player();
|
||||||
|
player.setUuid(UUID.randomUUID());
|
||||||
|
player.setName("player" + rnd.nextInt(minI, maxI));
|
||||||
|
player.setLocation(new EntityLocation(
|
||||||
|
rnd.nextDouble(minD, maxD),
|
||||||
|
rnd.nextDouble(minD, maxD),
|
||||||
|
rnd.nextDouble(minD, maxD),
|
||||||
|
rnd.nextFloat() * (maxF - minF) + minF,
|
||||||
|
rnd.nextFloat() * (maxF - minF) + minF
|
||||||
|
));
|
||||||
|
player.setWorld(mockWorld);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertPlayer(H2Player actualPlayer) {
|
||||||
|
final String sql = "SELECT * FROM players WHERE id = ?";
|
||||||
|
jdbcTemplate.query(sql,
|
||||||
|
ps -> ps.setInt(1, player.getId()),
|
||||||
|
rs -> {
|
||||||
|
assertEquals(actualPlayer.getId(), rs.getInt("id"));
|
||||||
|
assertEquals(actualPlayer.getName(), rs.getString("name"));
|
||||||
|
assertEquals(actualPlayer.getLocation().getX(), rs.getDouble("location_x"), 0.01d);
|
||||||
|
assertEquals(actualPlayer.getLocation().getY(), rs.getDouble("location_y"), 0.01d);
|
||||||
|
assertEquals(actualPlayer.getLocation().getZ(), rs.getDouble("location_z"), 0.01d);
|
||||||
|
assertEquals(actualPlayer.getLocation().getYaw(), rs.getFloat("location_yaw"), 0.01f);
|
||||||
|
assertEquals(actualPlayer.getLocation().getPitch(), rs.getFloat("location_pitch"), 0.01f);
|
||||||
|
assertEquals(actualPlayer.getWorld().getName(), rs.getString("location_world"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() throws IOException {
|
||||||
|
jdbcTemplate.execute(IOUtils.resourceToString("/sqls/drop_table_players.sql", StandardCharsets.UTF_8));
|
||||||
|
jdbcTemplate.execute(IOUtils.resourceToString("/sqls/create_tables.sql", StandardCharsets.UTF_8));
|
||||||
|
createPlayer();
|
||||||
|
assertEquals(0, player.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsert() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
assertPlayer(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = DuplicateKeyException.class)
|
||||||
|
public void testInsertDuplicateKey() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
playerDAO.insert(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testInsertEmptyName() throws SQLException {
|
||||||
|
player.setName("");
|
||||||
|
playerDAO.insert(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testInsertNullName() throws SQLException {
|
||||||
|
player.setName(null);
|
||||||
|
playerDAO.insert(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testInsertNullUuid() throws SQLException {
|
||||||
|
player.setUuid(null);
|
||||||
|
playerDAO.insert(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testInsertNullLocation() throws SQLException {
|
||||||
|
player.setLocation(null);
|
||||||
|
playerDAO.insert(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testInsertNullWorld() throws SQLException {
|
||||||
|
player.setWorld(null);
|
||||||
|
playerDAO.insert(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetByName() throws SQLException {
|
||||||
|
playerDAO.insert(this.player);
|
||||||
|
|
||||||
|
H2Player queryPlayer = new H2Player();
|
||||||
|
queryPlayer.setName(player.getName());
|
||||||
|
|
||||||
|
boolean result = playerDAO.getByName(queryPlayer);
|
||||||
|
|
||||||
|
assertTrue(result);
|
||||||
|
assertEquals(player, queryPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetById() throws SQLException {
|
||||||
|
playerDAO.insert(this.player);
|
||||||
|
|
||||||
|
H2Player queryPlayer = new H2Player();
|
||||||
|
queryPlayer.setId(player.getId());
|
||||||
|
|
||||||
|
boolean result = playerDAO.getById(queryPlayer);
|
||||||
|
|
||||||
|
assertTrue(result);
|
||||||
|
assertEquals(player, queryPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetByNonExistsName() throws SQLException {
|
||||||
|
playerDAO.insert(this.player);
|
||||||
|
|
||||||
|
H2Player player = new H2Player();
|
||||||
|
player.setName("NON_EXISTS_NAME");
|
||||||
|
|
||||||
|
boolean result = playerDAO.getByName(player);
|
||||||
|
assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetByNonExistsId() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertEquals(1, player.getId());
|
||||||
|
|
||||||
|
H2Player queryPlayer = new H2Player();
|
||||||
|
queryPlayer.setId(999);
|
||||||
|
|
||||||
|
boolean result = playerDAO.getById(queryPlayer);
|
||||||
|
assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdate() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
player.setName("UNKNOWN_PLAYER");
|
||||||
|
playerDAO.update(player);
|
||||||
|
|
||||||
|
assertPlayer(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testUpdateEmptyName() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
player.setName("");
|
||||||
|
playerDAO.update(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testUpdateNullName() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
player.setName(null);
|
||||||
|
playerDAO.update(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testUpdateNullUuid() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
player.setUuid(null);
|
||||||
|
playerDAO.update(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testUpdateNullLocation() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
player.setLocation(null);
|
||||||
|
playerDAO.update(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testUpdateNullWorld() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
player.setWorld(null);
|
||||||
|
playerDAO.update(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateLocation() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
final String origName = player.getName();
|
||||||
|
player.setName("UNKNOWN_PLAYER");
|
||||||
|
player.getLocation().setX(33.1d);
|
||||||
|
player.getLocation().setZ(28.99d);
|
||||||
|
playerDAO.updateLocation(player);
|
||||||
|
|
||||||
|
final String sql = "SELECT * FROM players WHERE id = ?";
|
||||||
|
jdbcTemplate.query(sql,
|
||||||
|
ps -> ps.setInt(1, player.getId()),
|
||||||
|
rs -> {
|
||||||
|
assertEquals(player.getId(), rs.getInt("id"));
|
||||||
|
assertEquals(origName, rs.getString("name"));
|
||||||
|
assertEquals(player.getLocation().getX(), rs.getDouble("location_x"), 0.01d);
|
||||||
|
assertEquals(player.getLocation().getY(), rs.getDouble("location_y"), 0.01d);
|
||||||
|
assertEquals(player.getLocation().getZ(), rs.getDouble("location_z"), 0.01d);
|
||||||
|
assertEquals(player.getLocation().getYaw(), rs.getFloat("location_yaw"), 0.01f);
|
||||||
|
assertEquals(player.getLocation().getPitch(), rs.getFloat("location_pitch"), 0.01f);
|
||||||
|
assertEquals(player.getWorld().getName(), rs.getString("location_world"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testUpdateLocationNull() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
player.setLocation(null);
|
||||||
|
playerDAO.updateLocation(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemove() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
final int origId = player.getId();
|
||||||
|
playerDAO.remove(player);
|
||||||
|
assertEquals(0, player.getId());
|
||||||
|
|
||||||
|
final String sql = "SELECT COUNT(*) FROM players WHERE id = ?";
|
||||||
|
jdbcTemplate.query(sql,
|
||||||
|
ps -> ps.setInt(1, origId),
|
||||||
|
rs -> {assertEquals(0, rs.getInt(1));});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testRemoveNonExistsId() throws SQLException {
|
||||||
|
playerDAO.insert(player);
|
||||||
|
assertNotEquals(0, player.getId());
|
||||||
|
|
||||||
|
player.setId(999);
|
||||||
|
playerDAO.remove(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package mc.core.h2db;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
|
||||||
|
public class TestH2Player {
|
||||||
|
@Test
|
||||||
|
public void testEquals() {
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
|
||||||
|
H2Player player1 = new H2Player();
|
||||||
|
player1.setId(1);
|
||||||
|
player1.setUuid(uuid);
|
||||||
|
player1.setName("Player1");
|
||||||
|
|
||||||
|
H2Player player2 = new H2Player();
|
||||||
|
player2.setId(1);
|
||||||
|
player2.setUuid(uuid);
|
||||||
|
player2.setName("Player2");
|
||||||
|
|
||||||
|
assertEquals(player1, player2);
|
||||||
|
|
||||||
|
player2.setId(2);
|
||||||
|
|
||||||
|
assertNotEquals(player1, player2);
|
||||||
|
|
||||||
|
player2.setId(1);
|
||||||
|
player2.setUuid(UUID.randomUUID());
|
||||||
|
|
||||||
|
assertNotEquals(player1, player2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
package mc.core.h2db;
|
||||||
|
|
||||||
|
import mc.core.EntityLocation;
|
||||||
|
import mc.core.player.Player;
|
||||||
|
import mc.core.world.World;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ContextConfiguration(classes = {SpringConfig.class})
|
||||||
|
public class TestH2PlayerManager {
|
||||||
|
@Autowired
|
||||||
|
private ApplicationContext context;
|
||||||
|
@Autowired
|
||||||
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
@Autowired
|
||||||
|
private H2PlayerDAO h2PlayerDAO;
|
||||||
|
@Autowired
|
||||||
|
private World mockWorld;
|
||||||
|
private H2PlayerManager playerManager;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() throws IOException {
|
||||||
|
playerManager = context.getBean(H2PlayerManager.class);
|
||||||
|
|
||||||
|
jdbcTemplate.execute(IOUtils.resourceToString("/sqls/drop_table_players.sql", StandardCharsets.UTF_8));
|
||||||
|
jdbcTemplate.execute(IOUtils.resourceToString("/sqls/create_tables.sql", StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreatePlayer() throws SQLException {
|
||||||
|
final String playerName = "NEW_PLAYER";
|
||||||
|
final Player newPlayer = playerManager.createPlayer(playerName, EntityLocation.ZERO(), mockWorld);
|
||||||
|
|
||||||
|
assertNotNull(newPlayer);
|
||||||
|
assertEquals(H2Player.class, newPlayer.getClass());
|
||||||
|
assertTrue(newPlayer.getId() > 0);
|
||||||
|
|
||||||
|
final H2Player queryPlayer = new H2Player();
|
||||||
|
queryPlayer.setName(playerName);
|
||||||
|
h2PlayerDAO.getByName(queryPlayer);
|
||||||
|
assertTrue(queryPlayer.getId() > 0);
|
||||||
|
|
||||||
|
assertEquals(newPlayer, queryPlayer);
|
||||||
|
assertEquals(newPlayer.getName(), queryPlayer.getName());
|
||||||
|
assertEquals(newPlayer.getLocation(), queryPlayer.getLocation());
|
||||||
|
assertEquals(newPlayer.getWorld(), queryPlayer.getWorld());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoinServer() {
|
||||||
|
assertEquals(0, playerManager.getCountPlayers());
|
||||||
|
|
||||||
|
final String playerName = "NEW_PLAYER";
|
||||||
|
final Player player = playerManager.createPlayer(playerName, EntityLocation.ZERO(), mockWorld);
|
||||||
|
playerManager.joinServer(player);
|
||||||
|
|
||||||
|
assertEquals(1, playerManager.getCountPlayers());
|
||||||
|
assertTrue(player.isOnline());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLeftServer() throws SQLException {
|
||||||
|
assertEquals(0, playerManager.getCountPlayers());
|
||||||
|
|
||||||
|
final String playerName = "NEW_PLAYER";
|
||||||
|
final Player player = playerManager.createPlayer(playerName, EntityLocation.ZERO(), mockWorld);
|
||||||
|
playerManager.joinServer(player);
|
||||||
|
|
||||||
|
assertEquals(1, playerManager.getCountPlayers());
|
||||||
|
assertTrue(player.isOnline());
|
||||||
|
|
||||||
|
final int playerId = player.getId();
|
||||||
|
|
||||||
|
final String anotherName = "ANOTHER_NAME";
|
||||||
|
((H2Player)player).setName(anotherName);
|
||||||
|
|
||||||
|
playerManager.leftServer(player);
|
||||||
|
|
||||||
|
assertEquals(0, playerManager.getCountPlayers());
|
||||||
|
|
||||||
|
assertFalse(player.isOnline());
|
||||||
|
assertEquals(0, player.getId());
|
||||||
|
assertNull(player.getWorld());
|
||||||
|
assertTrue(player.getLoadedChunks().isEmpty());
|
||||||
|
assertNull(player.getSettings());
|
||||||
|
|
||||||
|
H2Player queryPlayer = new H2Player();
|
||||||
|
queryPlayer.setId(playerId);
|
||||||
|
boolean result = h2PlayerDAO.getById(queryPlayer);
|
||||||
|
|
||||||
|
assertTrue(result);
|
||||||
|
((H2Player)player).setId(playerId);
|
||||||
|
assertEquals(player, queryPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPlayer() {
|
||||||
|
assertEquals(0, playerManager.getCountPlayers());
|
||||||
|
|
||||||
|
final String playerName = "NEW_PLAYER";
|
||||||
|
final Player player = playerManager.createPlayer(playerName, EntityLocation.ZERO(), mockWorld);
|
||||||
|
assertNotNull(player);
|
||||||
|
|
||||||
|
playerManager.joinServer(player);
|
||||||
|
|
||||||
|
assertEquals(1, playerManager.getCountPlayers());
|
||||||
|
|
||||||
|
Player queryPlayer = playerManager.getPlayer(playerName);
|
||||||
|
|
||||||
|
assertEquals(player, queryPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPlayers() {
|
||||||
|
assertEquals(0, playerManager.getCountPlayers());
|
||||||
|
|
||||||
|
final String playerName = "NEW_PLAYER";
|
||||||
|
final Player player = playerManager.createPlayer(playerName, EntityLocation.ZERO(), mockWorld);
|
||||||
|
assertNotNull(player);
|
||||||
|
|
||||||
|
playerManager.joinServer(player);
|
||||||
|
|
||||||
|
assertEquals(1, playerManager.getCountPlayers());
|
||||||
|
|
||||||
|
List<Player> players = playerManager.getPlayers();
|
||||||
|
assertEquals(1, players.size());
|
||||||
|
try {
|
||||||
|
players.add(new H2Player());
|
||||||
|
fail();
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(player, players.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCountPlayers() {
|
||||||
|
assertEquals(0, playerManager.getCountPlayers());
|
||||||
|
|
||||||
|
final String playerName = "NEW_PLAYER";
|
||||||
|
final Player player = playerManager.createPlayer(playerName, EntityLocation.ZERO(), mockWorld);
|
||||||
|
assertNotNull(player);
|
||||||
|
|
||||||
|
playerManager.joinServer(player);
|
||||||
|
|
||||||
|
assertEquals(1, playerManager.getCountPlayers());
|
||||||
|
|
||||||
|
playerManager.leftServer(player);
|
||||||
|
|
||||||
|
assertEquals(0, playerManager.getCountPlayers());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOfflinePlayer() {
|
||||||
|
final String playerName = "NEW_PLAYER";
|
||||||
|
final Player player = playerManager.createPlayer(playerName, EntityLocation.ZERO(), mockWorld);
|
||||||
|
playerManager.joinServer(player);
|
||||||
|
playerManager.leftServer(player);
|
||||||
|
|
||||||
|
assertEquals(0, playerManager.getCountPlayers());
|
||||||
|
|
||||||
|
Player offlinePlayer = playerManager.getOfflinePlayer(playerName);
|
||||||
|
assertEquals(player, offlinePlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
DROP INDEX IF EXISTS idx_players_uuid;
|
||||||
|
DROP INDEX IF EXISTS idx_players_name;
|
||||||
|
DROP TABLE IF EXISTS players;
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
package mc.core.network.proto_1_12_2.packets;
|
package mc.core.network.proto_1_12_2.packets;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -17,7 +16,6 @@ import mc.core.world.chunk.Chunk;
|
|||||||
import mc.core.world.chunk.ChunkSection;
|
import mc.core.world.chunk.ChunkSection;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import mc.core.world.block.BlockLocation;
|
|||||||
import mc.core.network.CSPacket;
|
import mc.core.network.CSPacket;
|
||||||
import mc.core.network.NetInputStream;
|
import mc.core.network.NetInputStream;
|
||||||
import mc.core.network.proto_1_12_2.Direction;
|
import mc.core.network.proto_1_12_2.Direction;
|
||||||
import mc.core.utils.CompactedCoords;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import mc.core.world.block.BlockLocation;
|
|||||||
import mc.core.network.CSPacket;
|
import mc.core.network.CSPacket;
|
||||||
import mc.core.network.NetInputStream;
|
import mc.core.network.NetInputStream;
|
||||||
import mc.core.network.proto_1_12_2.Direction;
|
import mc.core.network.proto_1_12_2.Direction;
|
||||||
import mc.core.utils.CompactedCoords;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package mc.core.network.proto_1_12_2.packets;
|
|||||||
import mc.core.network.proto_1_12_2.NetInputStream_p340;
|
import mc.core.network.proto_1_12_2.NetInputStream_p340;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.EOFException;
|
|
||||||
|
|
||||||
public class ByteArrayInputNetStream extends NetInputStream_p340 {
|
public class ByteArrayInputNetStream extends NetInputStream_p340 {
|
||||||
private ByteArrayInputStream bais;
|
private ByteArrayInputStream bais;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package mc.core.network.proto_1_12_2.packets;
|
|||||||
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ import mc.core.world.chunk.Chunk;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_PLAYER;
|
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_PLAYER;
|
||||||
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE;
|
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE;
|
||||||
|
|
||||||
@@ -39,8 +36,8 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand
|
|||||||
|
|
||||||
@Handler
|
@Handler
|
||||||
public void onLoginStart(Channel channel, LoginStartPacket packet) {
|
public void onLoginStart(Channel channel, LoginStartPacket packet) {
|
||||||
Optional<Player> optPlayer = playerManager.getPlayer(packet.getPlayerName());
|
Player player = playerManager.getPlayer(packet.getPlayerName());
|
||||||
if (optPlayer.isPresent() && optPlayer.get().isOnline()) {
|
if (player != null) {
|
||||||
channel.writeAndFlush(new DisconnectPacket(
|
channel.writeAndFlush(new DisconnectPacket(
|
||||||
Text.builder("Player \"")
|
Text.builder("Player \"")
|
||||||
.append(Text.of(packet.getPlayerName(), TextColor.YELLOW))
|
.append(Text.of(packet.getPlayerName(), TextColor.YELLOW))
|
||||||
@@ -48,24 +45,35 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand
|
|||||||
.build()))
|
.build()))
|
||||||
.addListener(ChannelFutureListener.CLOSE);
|
.addListener(ChannelFutureListener.CLOSE);
|
||||||
} else {
|
} else {
|
||||||
Player player = playerManager.getPlayer(packet.getPlayerName())
|
player = playerManager.getOfflinePlayer(packet.getPlayerName());
|
||||||
.orElseGet(() -> playerManager.createPlayer(
|
|
||||||
|
if (player == null) {
|
||||||
|
player = playerManager.createPlayer(
|
||||||
packet.getPlayerName(),
|
packet.getPlayerName(),
|
||||||
world.getSpawn(),
|
world.getSpawn(),
|
||||||
world));
|
world
|
||||||
|
);
|
||||||
|
|
||||||
|
if (player == null) {
|
||||||
|
channel.writeAndFlush(new DisconnectPacket(
|
||||||
|
Text.of("Internal server error: can't create new player"))
|
||||||
|
).addListener(ChannelFutureListener.CLOSE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
channel.writeAndFlush(new LoginSuccessPacket(
|
channel.writeAndFlush(new LoginSuccessPacket(
|
||||||
player.getUUID(),
|
player.getUuid(),
|
||||||
packet.getPlayerName()));
|
packet.getPlayerName()));
|
||||||
channel.attr(ATTR_PLAYER).set(player);
|
channel.attr(ATTR_PLAYER).set(player);
|
||||||
channel.attr(ATTR_STATE).set(State.PLAY);
|
channel.attr(ATTR_STATE).set(State.PLAY);
|
||||||
|
|
||||||
// Join Game
|
// Join Game
|
||||||
JoinGamePacket pkt1 = new JoinGamePacket();
|
JoinGamePacket pkt1 = new JoinGamePacket();
|
||||||
pkt1.setEntityId(player.getId());
|
pkt1.setEntityId(player.getId()); //TODO отделить системный ID от EntityID
|
||||||
pkt1.setMode(PlayerMode.CREATIVE);
|
pkt1.setMode(PlayerMode.CREATIVE); //TODO перенести в Config
|
||||||
pkt1.setDimension(0/*Overworld*/);
|
pkt1.setDimension(0/*Overworld*/); //TODO перенести в World
|
||||||
pkt1.setDifficulty(0/*Peaceful*/);
|
pkt1.setDifficulty(0/*Peaceful*/); //TODO перенести в Config
|
||||||
pkt1.setLevelType(world.getWorldType().getName());
|
pkt1.setLevelType(world.getWorldType().getName());
|
||||||
channel.write(pkt1);
|
channel.write(pkt1);
|
||||||
|
|
||||||
@@ -75,15 +83,17 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand
|
|||||||
channel.write(pkt2);
|
channel.write(pkt2);
|
||||||
|
|
||||||
// Player Abilities
|
// Player Abilities
|
||||||
PlayerAbilitiesPacket pkt3 = new PlayerAbilitiesPacket();
|
PlayerAbilitiesPacket pkt3 = new PlayerAbilitiesPacket(); //TODO перенести в Player
|
||||||
pkt3.setCanFly(true);
|
pkt3.setCanFly(true);
|
||||||
pkt3.setFlying(true);
|
pkt3.setFlying(true);
|
||||||
pkt3.setGodMode(true);
|
pkt3.setGodMode(true);
|
||||||
pkt3.setInstantDestroyBlocks(true);
|
pkt3.setInstantDestroyBlocks(true);
|
||||||
channel.write(pkt3);
|
channel.write(pkt3);
|
||||||
|
|
||||||
channel.flush();
|
channel.flush();
|
||||||
|
|
||||||
// First Chunk
|
// First Chunk
|
||||||
|
//TODO необходимо отправлять больше начальных чанков
|
||||||
ChunkDataPacket pkt8 = new ChunkDataPacket();
|
ChunkDataPacket pkt8 = new ChunkDataPacket();
|
||||||
Chunk chunk = player.getWorld().getChunk(player.getLocation());
|
Chunk chunk = player.getWorld().getChunk(player.getLocation());
|
||||||
pkt8.setX(chunk.getX());
|
pkt8.setX(chunk.getX());
|
||||||
@@ -91,6 +101,7 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand
|
|||||||
pkt8.setChunk(chunk);
|
pkt8.setChunk(chunk);
|
||||||
pkt8.setInitChunk(true);
|
pkt8.setInitChunk(true);
|
||||||
channel.writeAndFlush(pkt8);
|
channel.writeAndFlush(pkt8);
|
||||||
|
|
||||||
player.getLoadedChunks().add(CompactedCoords.compressXZ(0, 0));
|
player.getLoadedChunks().add(CompactedCoords.compressXZ(0, 0));
|
||||||
|
|
||||||
// Player Position And Look
|
// Player Position And Look
|
||||||
@@ -102,10 +113,11 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand
|
|||||||
player.setChannel(new WrapperNetChannel(channel));
|
player.setChannel(new WrapperNetChannel(channel));
|
||||||
|
|
||||||
// Send <Tab> items
|
// Send <Tab> items
|
||||||
|
//TODO обновление должно приходить всем игрокам на сервере
|
||||||
PlayerListItemPacket pkt5 = new PlayerListItemPacket();
|
PlayerListItemPacket pkt5 = new PlayerListItemPacket();
|
||||||
pkt5.setAction(PlayerListItemPacket.Action.ADD_PLAYER);
|
pkt5.setAction(PlayerListItemPacket.Action.ADD_PLAYER);
|
||||||
PlayerListItemPacket.PlayerData playerData = new PlayerListItemPacket.PlayerData();
|
PlayerListItemPacket.PlayerData playerData = new PlayerListItemPacket.PlayerData();
|
||||||
playerData.setUuid(player.getUUID());
|
playerData.setUuid(player.getUuid());
|
||||||
playerData.setName(player.getName());
|
playerData.setName(player.getName());
|
||||||
playerData.setGameMode(PlayerMode.CREATIVE);
|
playerData.setGameMode(PlayerMode.CREATIVE);
|
||||||
playerData.setPing(0);
|
playerData.setPing(0);
|
||||||
@@ -118,26 +130,6 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand
|
|||||||
pkt5.getListPlayers().add(playerData);
|
pkt5.getListPlayers().add(playerData);
|
||||||
channel.writeAndFlush(pkt5);
|
channel.writeAndFlush(pkt5);
|
||||||
|
|
||||||
// Send header/footer <Tab> list
|
|
||||||
PlayerListHeaderAndFooterPacket pkt6 = new PlayerListHeaderAndFooterPacket();
|
|
||||||
Text text = Text.of(TextColor.GOLD, "=============================");
|
|
||||||
pkt6.setHeader(text);
|
|
||||||
pkt6.setFooter(text);
|
|
||||||
channel.writeAndFlush(pkt6);
|
|
||||||
|
|
||||||
// Send Boss bar
|
|
||||||
BossBarPacket pkt7 = new BossBarPacket();
|
|
||||||
BossBarPacket.BarData barData = new BossBarPacket.BarData();
|
|
||||||
barData.setTitle(Text.of(TextColor.GREEN, TextStyle.BOLD, "FORWOLK"));
|
|
||||||
barData.setColor(BossBarPacket.Color.WHITE);
|
|
||||||
barData.setDivision(BossBarPacket.Division._12);
|
|
||||||
barData.setHealth(1.0f);
|
|
||||||
barData.setFlags(BossBarPacket.Flag.NO);
|
|
||||||
pkt7.setUuid(UUID.randomUUID());
|
|
||||||
pkt7.setAction(BossBarPacket.Action.ADD);
|
|
||||||
pkt7.setBarData(barData);
|
|
||||||
channel.writeAndFlush(pkt7);
|
|
||||||
|
|
||||||
playerManager.joinServer(player);
|
playerManager.joinServer(player);
|
||||||
|
|
||||||
CS_PlayerMoveEvent event = new CS_PlayerMoveEvent(player, player.getLocation());
|
CS_PlayerMoveEvent event = new CS_PlayerMoveEvent(player, player.getLocation());
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class StatusHandler extends AbstractStateHandler implements StatusStateHa
|
|||||||
responsePacket.setMaxOnline(config.getMaxPlayers());
|
responsePacket.setMaxOnline(config.getMaxPlayers());
|
||||||
responsePacket.setDescription(config.getDescriptionServer());
|
responsePacket.setDescription(config.getDescriptionServer());
|
||||||
responsePacket.setFaviconBase64(config.getFaviconBase64());
|
responsePacket.setFaviconBase64(config.getFaviconBase64());
|
||||||
responsePacket.setOnline(playerManager.getCountOnlinePlayers());
|
responsePacket.setOnline(playerManager.getCountPlayers());
|
||||||
|
|
||||||
channel.writeAndFlush(responsePacket);
|
channel.writeAndFlush(responsePacket);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ rootProject.name = 'mc-server'
|
|||||||
|
|
||||||
include('core') // Core
|
include('core') // Core
|
||||||
include('flat_world')
|
include('flat_world')
|
||||||
|
include('h2_playermanager')
|
||||||
include('vanilla_commands')
|
include('vanilla_commands')
|
||||||
include('proto_1.12.2') // Protocol 1.12.2
|
include('proto_1.12.2') // Protocol 1.12.2
|
||||||
include('proto_1.12.2_netty') // Protocol 1.12.2 (Netty impl.)
|
include('proto_1.12.2_netty') // Protocol 1.12.2 (Netty impl.)
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public class ListCommand implements CommandExecutor {
|
|||||||
playerManager.getPlayers().forEach(pl -> sj.add(pl.getName()));
|
playerManager.getPlayers().forEach(pl -> sj.add(pl.getName()));
|
||||||
|
|
||||||
Text message = messageFormat.apply(
|
Text message = messageFormat.apply(
|
||||||
"count", playerManager.getCountOnlinePlayers(),
|
"count", playerManager.getCountPlayers(),
|
||||||
"players", sj.toString());
|
"players", sj.toString());
|
||||||
sender.getChannel().sendChatMessage(message, MessageType.SYSTEM_MESSAGE);
|
sender.getChannel().sendChatMessage(message, MessageType.SYSTEM_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user