Added player saving and loading from disk

This commit is contained in:
Sergey Karmanov 2021-08-30 18:23:42 +03:00
parent e967a64401
commit 0100c8791d
Signed by: serega404
GPG Key ID: 97CADD982D88DF68
10 changed files with 141 additions and 70 deletions

View File

@ -39,10 +39,6 @@ public class ProgressiaLauncher {
GUI.addTopLayer(new LayerTitle("Title")); GUI.addTopLayer(new LayerTitle("Title"));
} }
public static void play() {
proxy.setupServer();
}
private static void setupCrashReports() { private static void setupCrashReports() {
// Context providers // Context providers
CrashReports.registerProvider(new OSContextProvider()); CrashReports.registerProvider(new OSContextProvider());

View File

@ -30,7 +30,6 @@ import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.localization.Localizer; import ru.windcorp.progressia.client.localization.Localizer;
import ru.windcorp.progressia.common.resource.ResourceManager; import ru.windcorp.progressia.common.resource.ResourceManager;
import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.TestContent; import ru.windcorp.progressia.test.TestContent;
import ru.windcorp.progressia.test.TestMusicPlayer; import ru.windcorp.progressia.test.TestMusicPlayer;
@ -62,10 +61,4 @@ public class ClientProxy implements Proxy {
TestMusicPlayer.start(); TestMusicPlayer.start();
} }
public void setupServer() {
ServerState.startServer();
ClientState.connectToLocalServer();
}
} }

View File

@ -18,18 +18,18 @@
package ru.windcorp.progressia.server; package ru.windcorp.progressia.server;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import glm.vec._3.Vec3; import glm.vec._3.Vec3;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.entity.EntityDataRegistry; import ru.windcorp.progressia.common.world.entity.EntityDataRegistry;
import ru.windcorp.progressia.server.comms.ClientPlayer;
import ru.windcorp.progressia.server.events.PlayerJoinedEvent; import ru.windcorp.progressia.server.events.PlayerJoinedEvent;
import ru.windcorp.progressia.server.events.PlayerLeftEvent; import ru.windcorp.progressia.server.events.PlayerLeftEvent;
import ru.windcorp.progressia.test.TestContent; import ru.windcorp.progressia.test.TestContent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
public class PlayerManager { public class PlayerManager {
private final Server server; private final Server server;
@ -50,21 +50,25 @@ public class PlayerManager {
} }
public void removePlayer(Player player) { public void removePlayer(Player player) {
server.getWorld().getContainer().savePlayer(player, server);
this.players.remove(player); this.players.remove(player);
getServer().postEvent(new PlayerLeftEvent.Immutable(getServer(), player)); getServer().postEvent(new PlayerLeftEvent.Immutable(getServer(), player));
} }
public EntityData conjurePlayerEntity(String login) { public Player conjurePlayer(ClientPlayer clientPlayer, String login) {
// TODO Live up to the name
if (TestContent.PLAYER_LOGIN.equals(login)) { Player player = getServer().getWorld().getContainer().loadPlayer(login, clientPlayer, getServer());
EntityData entity = spawnPlayerEntity(login); if (player == null) { // create new player
return entity; EntityData entity = spawnPlayerEntity(clientPlayer, login);
} else { player = new Player(entity, getServer(), clientPlayer);
throw CrashReports.report(null, "Unknown login %s, javahorse stupid", login);
} }
getServer().getWorld().getData().addEntity(player.getEntity());
return player;
} }
private EntityData spawnPlayerEntity(String login) { private EntityData spawnPlayerEntity(ClientPlayer clientPlayer, String login) {
EntityData player = EntityDataRegistry.getInstance().create("Test:Player"); EntityData player = EntityDataRegistry.getInstance().create("Test:Player");
player.setEntityId(TestContent.PLAYER_ENTITY_ID); player.setEntityId(TestContent.PLAYER_ENTITY_ID);
@ -73,8 +77,6 @@ public class PlayerManager {
player.setUpVector(new Vec3(0, 0, 1)); player.setUpVector(new Vec3(0, 0, 1));
player.setLookingAt(new Vec3(2, 1, 0)); player.setLookingAt(new Vec3(2, 1, 0));
getServer().getWorld().getData().addEntity(player);
return player; return player;
} }

View File

@ -18,6 +18,7 @@
package ru.windcorp.progressia.server; package ru.windcorp.progressia.server;
import java.io.IOException;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.function.Function; import java.util.function.Function;
@ -39,7 +40,7 @@ public class ServerState {
ServerState.instance = instance; ServerState.instance = instance;
} }
public static void startServer() { public static void startServer() throws IOException {
Function<Server, WorldGenerator> generator = new TestGenerationConfig().getGenerator(); Function<Server, WorldGenerator> generator = new TestGenerationConfig().getGenerator();
WorldContainer container = new RegionFormat("Test:Region").create(Paths.get("tmp_world")); WorldContainer container = new RegionFormat("Test:Region").create(Paths.get("tmp_world"));

View File

@ -80,12 +80,11 @@ public class ClientManager {
setGravityModelPacket.set(getServer().getWorld().getData().getGravityModel()); setGravityModelPacket.set(getServer().getWorld().getData().getGravityModel());
client.sendPacket(setGravityModelPacket); client.sendPacket(setGravityModelPacket);
EntityData entity = getServer().getPlayerManager().conjurePlayerEntity(login); Player player = getServer().getPlayerManager().conjurePlayer(client, login);
Player player = new Player(entity, getServer(), client);
getServer().getPlayerManager().addPlayer(player); getServer().getPlayerManager().addPlayer(player);
PacketSetLocalPlayer packet = new PacketSetLocalPlayer(); PacketSetLocalPlayer packet = new PacketSetLocalPlayer();
packet.set(entity.getEntityId()); packet.set(player.getEntity().getEntityId());
client.sendPacket(packet); client.sendPacket(packet);
} }

View File

@ -17,12 +17,14 @@
*/ */
package ru.windcorp.progressia.server.world.io; package ru.windcorp.progressia.server.world.io;
import java.nio.file.Path;
import glm.vec._3.i.Vec3i; import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.DefaultWorldData;
import ru.windcorp.progressia.server.Player;
import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.comms.ClientPlayer;
import java.nio.file.Path;
public interface WorldContainer { public interface WorldContainer {
@ -32,6 +34,10 @@ public interface WorldContainer {
void save(DefaultChunkData chunk, DefaultWorldData world, Server server); void save(DefaultChunkData chunk, DefaultWorldData world, Server server);
Player loadPlayer(String login, ClientPlayer clientPlayer, Server server);
void savePlayer(Player player, Server server);
void close(); void close();
} }

View File

@ -17,6 +17,7 @@
*/ */
package ru.windcorp.progressia.server.world.io; package ru.windcorp.progressia.server.world.io;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.util.namespaces.Namespaced;
@ -27,6 +28,6 @@ public abstract class WorldContainerFormat extends Namespaced {
super(id); super(id);
} }
public abstract WorldContainer create(Path directory); public abstract WorldContainer create(Path directory) throws IOException;
} }

View File

@ -1,15 +1,20 @@
package ru.windcorp.progressia.test; package ru.windcorp.progressia.test;
import ru.windcorp.progressia.ProgressiaLauncher; import ru.windcorp.progressia.client.ClientState;
import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.GUI; import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.gui.BasicButton;
import ru.windcorp.progressia.client.graphics.gui.Button; import ru.windcorp.progressia.client.graphics.gui.Button;
import ru.windcorp.progressia.client.graphics.gui.GUILayer; import ru.windcorp.progressia.client.graphics.gui.GUILayer;
import ru.windcorp.progressia.client.graphics.gui.Label; import ru.windcorp.progressia.client.graphics.gui.Label;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
import ru.windcorp.progressia.client.localization.MutableString; import ru.windcorp.progressia.client.localization.MutableString;
import ru.windcorp.progressia.client.localization.MutableStringLocalized; import ru.windcorp.progressia.client.localization.MutableStringLocalized;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.server.ServerState;
import java.io.IOException;
public class LayerTitle extends GUILayer { public class LayerTitle extends GUILayer {
@ -22,11 +27,7 @@ public class LayerTitle extends GUILayer {
Font buttonFont = titleFont; Font buttonFont = titleFont;
MutableString playText = new MutableStringLocalized("Layer" + name + ".Play"); MutableString playText = new MutableStringLocalized("Layer" + name + ".Play");
getRoot().addChild(new Button(name + ".Play", new Label(name + ".Play", buttonFont, playText)).addAction(b -> { getRoot().addChild(new Button(name + ".Play", new Label(name + ".Play", buttonFont, playText)).addAction(this::startGame));
GUI.removeLayer(this);
ProgressiaLauncher.play();
}));
MutableString quitText = new MutableStringLocalized("Layer" + name + ".Quit"); MutableString quitText = new MutableStringLocalized("Layer" + name + ".Quit");
getRoot().addChild(new Button(name + "Quit", new Label(name + ".Quit", buttonFont, quitText)).addAction(b -> { getRoot().addChild(new Button(name + "Quit", new Label(name + ".Quit", buttonFont, quitText)).addAction(b -> {
@ -34,4 +35,14 @@ public class LayerTitle extends GUILayer {
})); }));
} }
private void startGame(BasicButton basicButton) {
GUI.removeLayer(this);
try {
ServerState.startServer();
ClientState.connectToLocalServer();
} catch (IOException e) {
throw CrashReports.report(e, "Problem with loading server");
}
}
} }

View File

@ -17,6 +17,7 @@
*/ */
package ru.windcorp.progressia.test.region; package ru.windcorp.progressia.test.region;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import ru.windcorp.progressia.server.world.io.WorldContainer; import ru.windcorp.progressia.server.world.io.WorldContainer;
@ -29,7 +30,7 @@ public class RegionFormat extends WorldContainerFormat {
} }
@Override @Override
public WorldContainer create(Path directory) { public WorldContainer create(Path directory) throws IOException {
return new TestWorldDiskIO(directory); return new TestWorldDiskIO(directory);
} }

View File

@ -18,31 +18,37 @@
package ru.windcorp.progressia.test.region; package ru.windcorp.progressia.test.region;
import java.io.DataInputStream; import glm.vec._3.i.Vec3i;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import ru.windcorp.progressia.common.state.IOContext;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.DecodingException;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.DefaultWorldData;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.entity.EntityDataRegistry;
import ru.windcorp.progressia.common.world.generic.ChunkMap; import ru.windcorp.progressia.common.world.generic.ChunkMap;
import ru.windcorp.progressia.common.world.generic.ChunkMaps; import ru.windcorp.progressia.common.world.generic.ChunkMaps;
import ru.windcorp.progressia.server.Player;
import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.comms.ClientPlayer;
import ru.windcorp.progressia.server.world.io.WorldContainer; import ru.windcorp.progressia.server.world.io.WorldContainer;
import ru.windcorp.progressia.test.TestContent;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
public class TestWorldDiskIO implements WorldContainer { public class TestWorldDiskIO implements WorldContainer {
private static final boolean ENABLE = true; private static final boolean ENABLE = true;
private static final String FILE_NAME_FORMAT = "region_%d_%d_%d.progressia_region"; private static final String REGION_FOLDER_NAME = "regions";
private static final String PLAYERS_FOLDER_NAME = "players";
private static final String REGION_NAME_FORMAT = REGION_FOLDER_NAME + "/" + "region_%d_%d_%d.progressia_region";
private static final String PLAYER_NAME_FORMAT = PLAYERS_FOLDER_NAME + "/" + "%s.progressia_player";
private static final int BITS_IN_CHUNK_COORDS = 4; private static final int BITS_IN_CHUNK_COORDS = 4;
public static final int REGION_DIAMETER = 1 << BITS_IN_CHUNK_COORDS; public static final int REGION_DIAMETER = 1 << BITS_IN_CHUNK_COORDS;
@ -60,8 +66,12 @@ public class TestWorldDiskIO implements WorldContainer {
private final Path path; private final Path path;
private final ChunkMap<Region> regions = ChunkMaps.newHashMap(); private final ChunkMap<Region> regions = ChunkMaps.newHashMap();
public TestWorldDiskIO(Path path) { public TestWorldDiskIO(Path path) throws IOException {
this.path = path; this.path = path;
Files.createDirectories(getPath());
Files.createDirectories(getPath().resolve(REGION_FOLDER_NAME));
Files.createDirectories(getPath().resolve(PLAYERS_FOLDER_NAME));
} }
@Override @Override
@ -104,11 +114,53 @@ public class TestWorldDiskIO implements WorldContainer {
} }
} }
private Region getRegion(Vec3i position, boolean createIfMissing) throws IOException { @Override
if (regions.isEmpty()) { public Player loadPlayer(String login, ClientPlayer clientPlayer, Server server) {
Files.createDirectories(getPath());
Path path = getPlayerPath(login);
if (!Files.exists(path)) {
LOG.debug("Could not load player {} because file {} does not exist", login, path);
return null;
} }
EntityData player = EntityDataRegistry.getInstance().create("Test:Player");
try (
DataInputStream dataInputStream = new DataInputStream(
new BufferedInputStream(
Files.newInputStream(
getPlayerPath(login)
)
)
)
) {
player.read(dataInputStream, IOContext.SAVE);
player.setEntityId(TestContent.PLAYER_ENTITY_ID);
return new Player(player, server, clientPlayer);
} catch (IOException ioException) {
throw CrashReports.report(ioException, "Could not load player data: " + login);
}
}
@Override
public void savePlayer(Player player, Server server) {
Path path = getPlayerPath(player.getLogin());
try (
DataOutputStream dataOutputStream = new DataOutputStream(
new BufferedOutputStream(
Files.newOutputStream(path)
)
)
) {
player.getEntity().
write(dataOutputStream, IOContext.SAVE);
} catch (IOException ioException) {
throw CrashReports.report(ioException, "Could not save player %s data in file ", player.getLogin(), path);
}
}
private Region getRegion(Vec3i position, boolean createIfMissing) throws IOException {
Vec3i regionCoords = getRegionCoords(position); Vec3i regionCoords = getRegionCoords(position);
Region region = regions.get(regionCoords); Region region = regions.get(regionCoords);
@ -155,7 +207,7 @@ public class TestWorldDiskIO implements WorldContainer {
private Path getRegionPath(Vec3i regionPos) { private Path getRegionPath(Vec3i regionPos) {
return getPath().resolve( return getPath().resolve(
String.format( String.format(
FILE_NAME_FORMAT, REGION_NAME_FORMAT,
regionPos.x, regionPos.x,
regionPos.y, regionPos.y,
regionPos.z regionPos.z
@ -163,6 +215,15 @@ public class TestWorldDiskIO implements WorldContainer {
); );
} }
private Path getPlayerPath(String login) {
return getPath().resolve(
String.format(
PLAYER_NAME_FORMAT,
login
)
);
}
@Override @Override
public void close() { public void close() {
try { try {
@ -170,7 +231,7 @@ public class TestWorldDiskIO implements WorldContainer {
region.close(); region.close();
} }
} catch (IOException e) { } catch (IOException e) {
CrashReports.report(e, "Could not close region files"); throw CrashReports.report(e, "Could not close region files");
} }
} }