Skip to content

Commit

Permalink
persistence
Browse files Browse the repository at this point in the history
  • Loading branch information
NicholasBatesNZ committed Mar 9, 2020
1 parent 8db212f commit 17eabf0
Show file tree
Hide file tree
Showing 8 changed files with 3,594 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ engine/src/main/resources/settings.ini
engine/src/main/resources/mercenaries.json
engine/src/main/resources/world.ini
engine/src/main/resources/world.json
engine/src/main/resources/entity_store.dat

# Ignore donwloaded JREs
jre/**
1 change: 1 addition & 0 deletions engine/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dependencies {
compile(group: 'org.terasology.gestalt', name: 'gestalt-module', version: '7.0.5')
compile(group: 'org.terasology.gestalt', name: 'gestalt-util', version: '7.0.5')

compile group: 'com.google.protobuf', name: 'protobuf-java', version: '3.4.0'

compile "com.github.everit-org.json-schema:org.everit.json.schema:1.11.1"
compile "com.github.marschall:zipfilesystem-standalone:1.0.1"
Expand Down
16 changes: 14 additions & 2 deletions engine/src/main/java/org/destinationsol/SolApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.destinationsol.common.SolRandom;
import org.destinationsol.entitysystem.ComponentSystemManager;
import org.destinationsol.entitysystem.EntitySystemManager;
import org.destinationsol.entitysystem.SerialisationManager;
import org.destinationsol.game.DebugOptions;
import org.destinationsol.game.FactionInfo;
import org.destinationsol.game.SaveManager;
Expand All @@ -50,6 +51,7 @@
import org.destinationsol.util.FramerateLimiter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.gestalt.entitysystem.component.Component;
import org.terasology.gestalt.entitysystem.component.management.ComponentManager;
import org.terasology.gestalt.module.sandbox.API;

Expand Down Expand Up @@ -125,6 +127,11 @@ public void create() {

context.put(ComponentSystemManager.class, new ComponentSystemManager(moduleManager.getEnvironment(), context));

SerialisationManager serialisationManager = new SerialisationManager(
SaveManager.getResourcePath("entity_store.dat"), entitySystemManager.getEntityManager(),
moduleManager.getEnvironment().getSubtypesOf(Component.class).iterator().next().getClassLoader());
context.put(SerialisationManager.class, serialisationManager);

logger.info("\n\n ------------------------------------------------------------ \n");
moduleManager.printAvailableModules();

Expand Down Expand Up @@ -261,14 +268,13 @@ public void loadGame(boolean tut, String shipName, boolean isNewGame) {
}

public void play(boolean tut, String shipName, boolean isNewGame) {
context.get(ComponentSystemManager.class).preBegin();

if (isNewGame) {
beforeNewGame();
} else {
beforeLoadGame();
}

context.get(ComponentSystemManager.class).preBegin();
FactionInfo factionInfo = new FactionInfo();
solGame = new SolGame(shipName, tut, isNewGame, commonDrawer, context, worldConfig);
factionDisplay = new FactionDisplay(solGame, factionInfo);
Expand Down Expand Up @@ -347,6 +353,12 @@ private void beforeNewGame() {
* This method is called when the "Continue" button gets pressed. It loads the world file to get the seed used for the world generation, and the number of systems
*/
private void beforeLoadGame() {
try {
context.get(SerialisationManager.class).deserialise();
} catch (Exception e) {
e.printStackTrace();
}

WorldConfig config = SaveManager.loadWorld();
if (config != null) {
worldConfig = config;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* Copyright 2020 The Terasology Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.destinationsol.entitysystem;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collection;

import com.google.common.collect.Lists;
import com.google.protobuf.ByteString;

import org.destinationsol.protobuf.EntityData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.gestalt.assets.ResourceUrn;
import org.terasology.gestalt.entitysystem.component.Component;
import org.terasology.gestalt.entitysystem.entity.EntityManager;
import org.terasology.gestalt.entitysystem.entity.EntityRef;

public final class SerialisationManager {

private static final Logger logger = LoggerFactory.getLogger(SerialisationManager.class);
private File file;
private EntityManager entityManager;
private ClassLoader classLoader;

public SerialisationManager(String path, EntityManager entityManager, ClassLoader classLoader) {
file = new File(path);
this.entityManager = entityManager;
this.classLoader = classLoader;
}

public void serialise() throws IllegalArgumentException, IllegalAccessException, IOException {

EntityData.EntityStore.Builder storeBuilder = EntityData.EntityStore.newBuilder();
for (EntityRef entity : entityManager.allEntities()) {
if (entity.getId() == -1) {
break;
}
EntityData.Entity.Builder entityBuilder = EntityData.Entity.newBuilder();
entityBuilder.setId(entity.getId());

for (Component component : entity.getAllComponents().values()) {
EntityData.Component.Builder componentBuilder = EntityData.Component.newBuilder();
componentBuilder.setTypeName(component.getClass().toString().replaceFirst("class ", ""));

for (Field field : component.getClass().getDeclaredFields()) {
EntityData.Field.Builder fieldBuilder = EntityData.Field.newBuilder();
fieldBuilder.setName(field.getName());
fieldBuilder.setType(field.getType().toString());
field.setAccessible(true);

String value = "";
switch (field.getType().toString()) {
case "double":
value = String.valueOf((double) field.get(component));
break;
case "float":
value = String.valueOf((float) field.get(component));
break;
case "int":
value = String.valueOf((int) field.get(component));
break;
case "long":
value = String.valueOf((long) field.get(component));
break;
case "boolean":
value = String.valueOf((boolean) field.get(component));
break;
case "class java.lang.String":
value = (String) field.get(component);
break;
case "class org.terasology.gestalt.assets.ResourceUrn":
value = ((ResourceUrn) field.get(component)).toString();
break;
default:
logger.error("Trying to serialise unknown data-type: '{}'", field);
break;
}
fieldBuilder.setValue(ByteString.copyFrom(value.getBytes()));
componentBuilder.addField(fieldBuilder);
}
entityBuilder.addComponent(componentBuilder);
}
storeBuilder.addEntity(entityBuilder);
}

FileOutputStream output = new FileOutputStream(file);
storeBuilder.build().writeTo(output);
output.close();
}

public void deserialise() throws IOException, ClassNotFoundException, InstantiationException,
IllegalAccessException, NoSuchFieldException {

FileInputStream input = new FileInputStream(file);
EntityData.EntityStore store = EntityData.EntityStore.parseFrom(input);
input.close();

for (EntityData.Entity entity : store.getEntityList()) {
Collection<Component> componentsToAdd = Lists.newArrayList();

for (EntityData.Component component : entity.getComponentList()) {
Class<?> componentClass = Class.forName(component.getTypeName(), true, classLoader);
Component<?> componentObject = (Component<?>) componentClass.newInstance();

for (EntityData.Field field : component.getFieldList()) {
Field componentObjectField = componentClass.getDeclaredField(field.getName());
componentObjectField.setAccessible(true);

String value = new String(field.getValue().toByteArray());
switch (field.getType()) {
case "double":
componentObjectField.set(componentObject, Double.valueOf(value));
break;
case "float":
componentObjectField.set(componentObject, Float.valueOf(value));
break;
case "int":
componentObjectField.set(componentObject, Integer.valueOf(value));
break;
case "long":
componentObjectField.set(componentObject, Long.valueOf(value));
break;
case "boolean":
componentObjectField.set(componentObject, Boolean.valueOf(value));
break;
case "class java.lang.String":
componentObjectField.set(componentObject, value);
break;
case "class org.terasology.gestalt.assets.ResourceUrn":
componentObjectField.set(componentObject, new ResourceUrn(value));
break;
default:
logger.error("Trying to deserialise unknown data-type: '{}'", componentObjectField);
break;
}
}
componentsToAdd.add(componentObject);
}
entityManager.createEntity(componentsToAdd);
}
}
}
12 changes: 12 additions & 0 deletions engine/src/main/java/org/destinationsol/game/SolGame.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.destinationsol.common.SolException;
import org.destinationsol.common.SolMath;
import org.destinationsol.common.SolRandom;
import org.destinationsol.entitysystem.EntitySystemManager;
import org.destinationsol.entitysystem.SerialisationManager;
import org.destinationsol.files.HullConfigManager;
import org.destinationsol.game.asteroid.AsteroidBuilder;
import org.destinationsol.game.attributes.RegisterUpdateSystem;
Expand Down Expand Up @@ -58,6 +60,7 @@
import org.destinationsol.ui.TutorialManager;
import org.destinationsol.ui.UiDrawer;
import org.destinationsol.ui.Waypoint;
import org.terasology.gestalt.entitysystem.entity.EntityRef;

import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -258,6 +261,15 @@ public void onGameEnd(Context context) {
saveShip();
}
SaveManager.saveWorld(getPlanetManager().getSystems().size());

try {
context.get(SerialisationManager.class).serialise();
} catch (Exception e) {
e.printStackTrace();
}

// TODO: Remove this when context is reset after each game
context.get(EntitySystemManager.class).getEntityManager().allEntities().forEach(EntityRef::delete);
} else {
context.remove(TutorialManager.class, tutorialManager);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ public class ModuleManager {
org.terasology.gestalt.entitysystem.entity.EntityIterator.class,
org.terasology.gestalt.entitysystem.entity.EntityManager.class,
org.terasology.gestalt.entitysystem.event.EventResult.class,
org.terasology.gestalt.entitysystem.event.ReceiveEvent.class
org.terasology.gestalt.entitysystem.event.ReceiveEvent.class,
org.terasology.gestalt.entitysystem.prefab.GeneratedFromRecipeComponent.class
};

protected static ModuleEnvironment environment;
Expand Down
Loading

0 comments on commit 17eabf0

Please sign in to comment.