diff --git a/.gitignore b/.gitignore
index 5388c84ce..2ff1580a4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,9 +10,9 @@ build
.gradle
# Holocore
-clientdata/
-log/
-cfg/
-odb/
+/clientdata/
+/log/
+/cfg/
+/odb/
*.db
*.iff
diff --git a/src/utility/java/com/projectswg/utility/clientdata/ConvertBuildingList.java b/src/utility/java/com/projectswg/utility/clientdata/ConvertBuildingList.java
new file mode 100644
index 000000000..a86c76d22
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/ConvertBuildingList.java
@@ -0,0 +1,69 @@
+/***********************************************************************************
+ * Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
+ * *
+ * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+ * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+ * Our goal is to create an emulator which will provide a server for players to *
+ * continue playing a game similar to the one they used to play. We are basing *
+ * it on the final publish of the game prior to end-game events. *
+ * *
+ * This file is part of Holocore. *
+ * *
+ * --------------------------------------------------------------------------------*
+ * *
+ * Holocore is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Affero General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * Holocore is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Affero General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Affero General Public License *
+ * along with Holocore. If not, see . *
+ ***********************************************************************************/
+package com.projectswg.utility.clientdata;
+
+import com.projectswg.common.data.location.Terrain;
+import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
+import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
+import com.projectswg.holocore.resources.support.objects.swg.building.BuildingObject;
+import com.projectswg.utility.SdbGenerator;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Locale;
+
+public class ConvertBuildingList implements Converter {
+
+ @Override
+ public void convert() {
+ System.out.println("Converting building list...");
+ Collection objects = DataLoader.buildouts().getObjects().values();
+ try (SdbGenerator gen = new SdbGenerator(new File("serverdata/building/buildings.sdb"))) {
+ gen.writeColumnNames("building_id", "terrain_name", "object_id", "iff", "building_name", "total_cells", "x", "y", "z");
+ for (SWGObject obj : objects) {
+ if (obj instanceof BuildingObject) {
+ String template = obj.getTemplate().substring(obj.getTemplate().lastIndexOf('/') + 1);
+ Terrain terrain = obj.getTerrain();
+ String name = terrain.name().charAt(0) + terrain.name().toLowerCase(Locale.US).substring(1);
+ int cells = ((BuildingObject) obj).getCells().size();
+ if (cells <= 0)
+ continue;
+ gen.writeLine("", terrain, obj.getObjectId(), template, name, cells, obj.getX(), obj.getY(), obj.getZ());
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void convertFile(SdbGenerator sdb, File file) {
+
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/ConvertBuildouts.java b/src/utility/java/com/projectswg/utility/clientdata/ConvertBuildouts.java
new file mode 100644
index 000000000..8d1d2b208
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/ConvertBuildouts.java
@@ -0,0 +1,382 @@
+/***********************************************************************************
+ * Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
+ * *
+ * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+ * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+ * Our goal is to create an emulator which will provide a server for players to *
+ * continue playing a game similar to the one they used to play. We are basing *
+ * it on the final publish of the game prior to end-game events. *
+ * *
+ * This file is part of Holocore. *
+ * *
+ * --------------------------------------------------------------------------------*
+ * *
+ * Holocore is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Affero General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * Holocore is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Affero General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Affero General Public License *
+ * along with Holocore. If not, see . *
+ ***********************************************************************************/
+package com.projectswg.utility.clientdata;
+
+import com.projectswg.common.data.CRC;
+import com.projectswg.common.data.location.Location;
+import com.projectswg.common.data.location.Quaternion;
+import com.projectswg.common.data.location.Terrain;
+import com.projectswg.common.data.swgfile.ClientFactory;
+import com.projectswg.common.data.swgfile.visitors.DatatableData;
+import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
+import com.projectswg.holocore.resources.support.objects.swg.cell.CellObject;
+import com.projectswg.utility.SdbGenerator;
+import com.projectswg.utility.clientdata.buildouts.BuildoutLoader;
+import com.projectswg.utility.clientdata.buildouts.SnapshotLoader;
+import com.projectswg.utility.clientdata.buildouts.SwgBuildoutArea;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.Map.Entry;
+
+public class ConvertBuildouts implements Converter{
+
+ private static final String [][] AREA_COLUMNS = {
+ {"id", "terrain", "area_name", "event", "min_x", "min_z", "max_x", "max_z", "adjust_coordinates", "translate_x", "translate_z"}
+ };
+ private static final String [][] OBJECT_COLUMNS = {
+ {"id", "area_id", "template_crc", "container_id", "x", "y", "z", "orientation_x", "orientation_y", "orientation_z", "orientation_w", "radius", "cell_index"}
+ };
+
+ private final List areas;
+ private final List fallbackAreas;
+
+ public ConvertBuildouts() {
+ this.areas = new ArrayList<>();
+ this.fallbackAreas = new ArrayList<>(Terrain.values().length);
+ int areaId = -1;
+ for (Terrain t : Terrain.values()) {
+ fallbackAreas.add(new GenBuildoutArea(null, t, -8196, -8196, 8196, 8196, areaId, false));
+ areaId--;
+ }
+ }
+
+ @Override
+ public void convert() {
+ try {
+ createAreas();
+ createObjects();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void createAreas() throws IOException {
+ System.out.println("Generating areas...");
+ try (SdbGenerator gen = new SdbGenerator(new File("serverdata/buildout/areas.sdb"))) {
+ gen.writeColumnNames(AREA_COLUMNS[0]);
+ writeAreas(gen);
+ }
+ }
+
+ private void createObjects() throws IOException {
+ System.out.println("Generating objects...");
+ List objects = new LinkedList<>();
+ System.out.println(" Creating buildouts...");
+ createBuildouts(objects);
+ System.out.println(" Creating snapshots...");
+ createSnapshots(objects);
+ System.out.println(" Generating file...");
+ generateObjectFile(objects);
+ }
+
+ private void createBuildouts(List objects) {
+ BuildoutLoader loader = new BuildoutLoader();
+ loader.loadAllBuildouts();
+ for (Entry> areaObjects : loader.getObjects().entrySet()) {
+ GenBuildoutArea area = null;
+ for (GenBuildoutArea a : areas) {
+ if (a.area.getName().equals(areaObjects.getKey())) {
+ area = a;
+ break;
+ }
+ }
+ if (area == null) {
+ System.err.println("Unknown area! Name: " + areaObjects.getKey());
+ continue;
+ }
+ for (SWGObject obj : areaObjects.getValue()) {
+ obj.setBuildoutAreaId(area.id);
+ addClientObject(objects, obj);
+ }
+ }
+ }
+
+ private void createSnapshots(List objects) {
+ SnapshotLoader snapLoader = new SnapshotLoader();
+ snapLoader.loadAllSnapshots();
+ List snapshots = new LinkedList<>();
+ for (SWGObject obj : snapLoader.getObjects()) {
+ addClientObject(snapshots, obj);
+ }
+ setSnapshotData(snapshots, objects);
+ }
+
+ private void setSnapshotData(List snapshots, List objects) {
+ for (SWGObject snap : snapshots) {
+ GenBuildoutArea area = getAreaForObject(snap);
+ if (area != null)
+ snap.setBuildoutAreaId(area.id);
+ else
+ System.err.println("No area for: " + snap.getObjectId() + " / " + snap.getTerrain());
+ }
+ objects.addAll(snapshots);
+ }
+
+ private void generateObjectFile(List objects) throws IOException {
+ try (SdbGenerator gen = new SdbGenerator(new File("serverdata/buildout/objects.sdb"))) {
+ gen.writeColumnNames(OBJECT_COLUMNS[0]);
+ int objNum = 0;
+ int percent = 0;
+ objects.sort((o1, o2) -> {
+ int comp;
+ comp = Integer.compare(o1.getBuildoutAreaId(), o2.getBuildoutAreaId());
+ if (comp != 0)
+ return comp;
+ comp = Long.compare(o1.getSuperParent() != null ? o1.getSuperParent().getObjectId() : o1.getObjectId(), o2.getSuperParent() != null ? o2.getSuperParent().getObjectId() : o2.getObjectId());
+ if (comp != 0)
+ return comp;
+ comp = Integer.compare(getBuildoutDepth(o1), getBuildoutDepth(o2));
+ if (comp != 0)
+ return comp;
+ return 0;
+ });
+ isValidBuildoutAreas(objects);
+ for (SWGObject obj : objects) {
+ if (obj instanceof CellObject)
+ continue;
+ writeObject(gen, obj);
+ while (percent / 100.0 * objects.size() <= objNum) {
+ System.out.print(".");
+ percent++;
+ }
+ objNum++;
+ }
+ System.out.println();
+ }
+ }
+
+ private int getBuildoutDepth(SWGObject object) {
+ if (object.getParent() == null)
+ return 0;
+ return getBuildoutDepth(object.getParent()) + 1;
+ }
+
+ private void addClientObject(List objects, SWGObject obj) {
+ objects.add(obj);
+ for (SWGObject child : obj.getContainedObjects()) {
+ addClientObject(objects, child);
+ }
+ for (SWGObject child : obj.getSlots().values()) {
+ if (child != null)
+ addClientObject(objects, child);
+ }
+ }
+
+ private void writeAreas(SdbGenerator gen) throws IOException {
+ DatatableData table = (DatatableData) ClientFactory.getInfoFromFile("datatables/buildout/buildout_scenes.iff");
+ areas.clear();
+ for (int sceneRow = 0; sceneRow < table.getRowCount(); sceneRow++) {
+ Terrain t = Terrain.getTerrainFromName((String) table.getCell(sceneRow, 0));
+ getArea(t, sceneRow, (Boolean) table.getCell(sceneRow, 1));
+ }
+ Collections.sort(areas);
+ for (int i = fallbackAreas.size()-1; i >= 0; i--) {
+ GenBuildoutArea fallback = fallbackAreas.get(i);
+ String name = fallback.terrain.name().toLowerCase(Locale.US);
+ gen.writeLine(fallback.id, name, name + "_global", "", -8196, -8196, 8196, 8196, "0", 0, 0);
+ }
+ int percent = 0;
+ for (int i = 0; i < areas.size(); i++) {
+ GenBuildoutArea area = areas.get(i);
+ writeArea(gen, area, null);
+ for (int j = i+1; j < areas.size() && area.equals(areas.get(j)); j++) {
+ writeArea(gen, areas.get(j), area.area.getName());
+ i++;
+ }
+ while (percent / 100.0 * areas.size() <= i) {
+ System.out.print(".");
+ percent++;
+ }
+ }
+ System.out.println();
+ }
+
+ private void getArea(Terrain t, int sceneRow, boolean adjust) {
+ String file = "datatables/buildout/areas_"+t.getName()+".iff";
+ DatatableData areaTable = (DatatableData) ClientFactory.getInfoFromFile(file);
+ for (int row = 0; row < areaTable.getRowCount(); row++) {
+ SwgBuildoutArea area = new SwgBuildoutArea();
+ area.load(areaTable.getRow(row), sceneRow, row);
+ areas.add(new GenBuildoutArea(area, t, area.getX1(), area.getZ1(), area.getX2(), area.getZ2(), sceneRow*100+row, adjust));
+ }
+ }
+
+ private void writeArea(SdbGenerator gen, GenBuildoutArea area, String substituteName) throws IOException {
+ if (substituteName == null)
+ substituteName = area.area.getName();
+ String terrain = area.terrain.getName();
+ double x1 = area.area.getX1();
+ double z1 = area.area.getZ1();
+ double x2 = area.area.getX2();
+ double z2 = area.area.getZ2();
+ double transX = 0;
+ double transZ = 0;
+ boolean adjust = area.adjust || !area.area.getCompositeName().isEmpty();
+ if (!area.area.getCompositeName().isEmpty()) {
+ transX = area.area.getCompositeX1() + (area.area.getCompositeX2() - area.area.getCompositeX1()) / 2;
+ transZ = area.area.getCompositeZ1() + (area.area.getCompositeZ2() - area.area.getCompositeZ1()) / 2;
+ }
+ transX -= area.area.getX1() + (area.area.getX2() - area.area.getX1()) / 2;
+ transZ -= area.area.getZ1() + (area.area.getZ2() - area.area.getZ1()) / 2;
+ gen.writeLine(area.id, terrain, substituteName, area.area.getEventRequired(), x1, z1, x2, z2, adjust?"1":"0", transX, transZ);
+ }
+
+ private void writeObject(SdbGenerator gen, SWGObject object) throws IOException {
+ long id = object.getObjectId();
+ int crc = CRC.getCrc(object.getTemplate());
+ long container = (object.getParent() != null) ? object.getParent().getObjectId() : 0;
+ if (object.getParent() instanceof CellObject)
+ container = object.getParent().getParent().getObjectId();
+ Location l = object.getLocation();
+ Quaternion q = l.getOrientation();
+ double radius = object.getLoadRange();
+ int cellIndex = (object.getParent() instanceof CellObject) ? ((CellObject) object.getParent()).getNumber() : 0;
+ float x = (float) l.getX(), y = (float) l.getY(), z = (float) l.getZ();
+ float oX = (float) q.getX(), oY = (float) q.getY(), oZ = (float) q.getZ(), oW = (float) q.getW();
+ gen.writeLine(id, object.getBuildoutAreaId(), crc, container, x, y, z, oX, oY, oZ, oW, radius, cellIndex);
+ }
+
+ private GenBuildoutArea getAreaForObject(SWGObject obj) {
+ SWGObject superParent = obj.getSuperParent();
+ Location l = superParent == null ? obj.getLocation() : superParent.getLocation();
+ double x = l.getX();
+ double z = l.getZ();
+ int ind = Collections.binarySearch(areas, new GenBuildoutArea(null, obj.getTerrain(), x, z, x, z, 0, false), (area1, area2) -> {
+ int comp = area1.terrain.getName().compareTo(area2.terrain.getName());
+ if (comp != 0)
+ return comp;
+ if (area2.x1 < area1.x1)
+ return 1;
+ if (area2.x2 > area1.x2)
+ return -1;
+ if (area2.z1 < area1.z1)
+ return 1;
+ if (area2.z2 > area1.z2)
+ return -1;
+ return Integer.compare(area1.getSorting(), area2.getSorting());
+ });
+ if (ind < 0) {
+ for (GenBuildoutArea fallback : fallbackAreas) {
+ if (fallback.terrain == obj.getTerrain())
+ return fallback;
+ }
+ return null;
+ }
+ return areas.get(ind);
+ }
+
+ private void isValidBuildoutAreas(List objects) {
+ for (SWGObject obj : objects) {
+ GenBuildoutArea area = getAreaForObject(obj);
+ assert area != null : "no buildout area found for object: " + obj;
+ assert obj.getBuildoutAreaId() == area.id : "invalid buildout area for object " + obj;
+ }
+ }
+
+ private static class GenBuildoutArea implements Comparable {
+ public final SwgBuildoutArea area;
+ public final Terrain terrain;
+ public final int index;
+ public final int x1;
+ public final int z1;
+ public final int x2;
+ public final int z2;
+ public final int id;
+ public final boolean adjust;
+
+ public GenBuildoutArea(SwgBuildoutArea area, Terrain terrain, double x1, double z1, double x2, double z2, int id, boolean adjust) {
+ this.area = area;
+ this.terrain = terrain;
+ if (area != null)
+ this.index = area.getIndex();
+ else
+ this.index = -1;
+ this.x1 = (int) x1;
+ this.z1 = (int) z1;
+ this.x2 = (int) x2;
+ this.z2 = (int) z2;
+ this.id = id;
+ this.adjust = adjust;
+ }
+
+ @Override
+ public int compareTo(GenBuildoutArea area) {
+ int comp = Integer.compare(index, area.index);
+ if (comp != 0)
+ return comp;
+ comp = Integer.compare(x1, area.x1);
+ if (comp != 0)
+ return comp;
+ comp = Integer.compare(z1, area.z1);
+ if (comp != 0)
+ return comp;
+ comp = Integer.compare(x2, area.x2);
+ if (comp != 0)
+ return comp;
+ comp = Integer.compare(z2, area.z2);
+ if (comp != 0)
+ return comp;
+ return Integer.compare(getSorting(), area.getSorting());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof GenBuildoutArea))
+ return false;
+ GenBuildoutArea area = (GenBuildoutArea) o;
+ return terrain.equals(area.terrain) && x1 == area.x1 && z1 == area.z1;
+ }
+
+ @Override
+ public int hashCode() {
+ return terrain.hashCode() ^ Integer.hashCode(x1) ^ Integer.hashCode(z1);
+ }
+
+ private int getSorting() {
+ if (area == null)
+ return 1;
+ String [] parts = area.getName().split("_");
+ if (parts.length != 3)
+ return 2;
+ if (isNumber(parts[1]) && isNumber(parts[2]))
+ return 1;
+ return 2;
+ }
+
+ private boolean isNumber(String str) {
+ try {
+ Integer.parseInt(str);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/ConvertObjectData.java b/src/utility/java/com/projectswg/utility/clientdata/ConvertObjectData.java
new file mode 100644
index 000000000..e888cc2d2
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/ConvertObjectData.java
@@ -0,0 +1,116 @@
+package com.projectswg.utility.clientdata;
+
+import com.projectswg.common.data.swgfile.ClientFactory;
+import com.projectswg.common.data.swgfile.visitors.ObjectData;
+import com.projectswg.common.data.swgfile.visitors.ObjectData.ObjectDataAttribute;
+import com.projectswg.utility.SdbGenerator;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+class ConvertObjectData implements Converter {
+
+ private static final ObjectDataAttribute[] ATTRIBUTES = Arrays.stream(ObjectDataAttribute.values()).filter(a -> a != ObjectDataAttribute.UNKNOWN).collect(Collectors.toList()).toArray(new ObjectDataAttribute[0]);
+ private static final File CLIENTDATA = new File("clientdata");
+
+ private final Object [] line;
+
+ public ConvertObjectData() {
+ this.line = new Object[ATTRIBUTES.length+1];
+ }
+
+ @Override
+ public void convert() {
+ System.out.println("Converting object data...");
+ try (SdbGenerator sdb = new SdbGenerator(new File("serverdata/objects/object_data.sdb"))) {
+ {
+ List columns = new ArrayList<>();
+ columns.add("iff");
+ columns.addAll(Arrays.stream(ATTRIBUTES).map(ObjectDataAttribute::getName).collect(Collectors.toList()));
+ sdb.writeColumnNames(columns);
+ }
+ Converter.traverseFiles(this, new File(CLIENTDATA, "object"), sdb, file -> file.getName().endsWith(".iff"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void convertFile(SdbGenerator sdb, File file) throws IOException {
+ ObjectData objectData = (ObjectData) ClientFactory.getInfoFromFile(file);
+ if (objectData == null) {
+ System.err.println("Failed to load object: " + file);
+ return;
+ }
+ if (file.getName().equals(""))
+ System.out.println(objectData.getAttribute(ObjectDataAttribute.OBJECT_NAME));
+ line[0] = file.getAbsolutePath().replace(CLIENTDATA.getAbsolutePath()+'/', "");
+ for (int i = 0; i < ATTRIBUTES.length; i++) {
+ ObjectDataAttribute attr = ATTRIBUTES[i];
+ line[i+1] = initializeDataType(attr, objectData.getAttribute(attr));
+ }
+ sdb.writeLine(line);
+ }
+
+ private static Object initializeDataType(ObjectDataAttribute attribute, Object o) {
+ switch (attribute) {
+ case ATTACK_TYPE:
+ case COLLISION_MATERIAL_BLOCK_FLAGS:
+ case COLLISION_MATERIAL_FLAGS:
+ case COLLISION_MATERIAL_PASS_FLAGS:
+ case COLLISION_ACTION_BLOCK_FLAGS:
+ case COLLISION_ACTION_FLAGS:
+ case COLLISION_ACTION_PASS_FLAGS:
+ case CONTAINER_TYPE:
+ case CONTAINER_VOLUME_LIMIT:
+ case GAME_OBJECT_TYPE:
+ case GENDER:
+ case NICHE:
+ case RACE:
+ case SPECIES:
+ case SURFACE_TYPE:
+ case WEAPON_EFFECT_INDEX:
+ case ACCELERATION:
+ case CAMERA_HEIGHT:
+ case CLEAR_FLORA_RADIUS:
+ case COLLISION_HEIGHT:
+ case COLLISION_LENGTH:
+ case COLLISION_OFFSET_X:
+ case COLLISION_OFFSET_Z:
+ case COLLISION_RADIUS:
+ case LOCATION_RESERVATION_RADIUS:
+ case NO_BUILD_RADIUS:
+ case SCALE:
+ case SCALE_THRESHOLD_BEFORE_EXTENT_TEST:
+ case SLOPE_MOD_ANGLE:
+ case SLOPE_MOD_PERCENT:
+ case SPEED:
+ case STEP_HEIGHT:
+ case SWIM_HEIGHT:
+ case TURN_RADIUS:
+ case WARP_TOLERANCE:
+ case WATER_MOD_PERCENT:
+ if (o == null)
+ return "0";
+ return o;
+ case CLIENT_VISIBILITY_FLAG:
+ case FORCE_NO_COLLISION:
+ case HAS_WINGS:
+ case ONLY_VISIBLE_IN_TOOLS:
+ case PLAYER_CONTROLLED:
+ case POSTURE_ALIGN_TO_TERRAIN:
+ case SEND_TO_CLIENT:
+ case SNAP_TO_TERRAIN:
+ case TARGETABLE:
+ case USE_STRUCTURE_FOOTPRINT_OUTLINE:
+ if (o == null)
+ return "false";
+ return o;
+ default:
+ return o;
+ }
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/ConvertRawDatatable.java b/src/utility/java/com/projectswg/utility/clientdata/ConvertRawDatatable.java
new file mode 100644
index 000000000..776f0fb32
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/ConvertRawDatatable.java
@@ -0,0 +1,31 @@
+package com.projectswg.utility.clientdata;
+
+import com.projectswg.utility.SdbGenerator;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+
+public abstract class ConvertRawDatatable implements Converter {
+
+ public ConvertRawDatatable() {
+
+ }
+
+ protected void convert(File input, File output) {
+ try (BufferedReader in = new BufferedReader(new FileReader(input))) {
+ String [] columnNames = in.readLine().split("\t");
+ String [] columnTypes = in.readLine().split("\t");
+ System.out.println(List.of(columnNames));
+ System.out.println(List.of(columnTypes));
+ try (SdbGenerator gen = new SdbGenerator(output)) {
+
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/ConvertSlotDefinition.java b/src/utility/java/com/projectswg/utility/clientdata/ConvertSlotDefinition.java
new file mode 100644
index 000000000..04bfb06af
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/ConvertSlotDefinition.java
@@ -0,0 +1,34 @@
+package com.projectswg.utility.clientdata;
+
+import com.projectswg.common.data.swgfile.ClientFactory;
+import com.projectswg.common.data.swgfile.visitors.SlotDefinitionData;
+import com.projectswg.common.data.swgfile.visitors.SlotDefinitionData.SlotDefinition;
+import com.projectswg.utility.SdbGenerator;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Objects;
+
+class ConvertSlotDefinition implements Converter {
+
+ @Override
+ public void convert() {
+ System.out.println("Converting slot definitions...");
+ try (SdbGenerator sdb = new SdbGenerator(new File("serverdata/abstract/slot_definitions.sdb"))) {
+ sdb.writeColumnNames("slotName", "global", "modifiable", "observeWithParent", "exposeToWorld");
+ convertFile(sdb, new File("clientdata/abstract/slot/slot_definition/slot_definitions.iff"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void convertFile(SdbGenerator sdb, File file) throws IOException {
+ SlotDefinitionData clientdata = (SlotDefinitionData) ClientFactory.getInfoFromFile(file);
+ Objects.requireNonNull(clientdata, "Failed to load clientdata");
+
+ for (SlotDefinition sd : clientdata.getDefinitions().values()) {
+ sdb.writeLine(sd.getName(), sd.isGlobal(), sd.isModifiable(), sd.isObserveWithParent(), sd.isExposeToWorld());
+ }
+ }
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/Converter.java b/src/utility/java/com/projectswg/utility/clientdata/Converter.java
new file mode 100644
index 000000000..b9d2f5560
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/Converter.java
@@ -0,0 +1,36 @@
+package com.projectswg.utility.clientdata;
+
+import com.projectswg.utility.SdbGenerator;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.function.Predicate;
+
+interface Converter {
+
+ File HOLOCORE = new File("serverdata");
+ File RAW = new File("/home/josh/devel/ProjectSWG/sauce/whitengold/dsrc/sku.0/sys.shared/compiled/game/");
+
+ void convert();
+ default void convertFile(SdbGenerator sdb, File file) throws IOException {}
+
+ static void traverseFiles(Converter converter, File directory, SdbGenerator sdb, Predicate filter) {
+ System.out.println(directory);
+ File [] children = directory.listFiles();
+ assert children != null;
+ for (File child : children) {
+ if (child.isDirectory()) {
+ traverseFiles(converter, child, sdb, filter);
+ } else if (filter.test(child)) {
+ try {
+ converter.convertFile(sdb, child);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ System.out.println("Ignoring " + child);
+ }
+ }
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/Converters.java b/src/utility/java/com/projectswg/utility/clientdata/Converters.java
new file mode 100644
index 000000000..baa882bd7
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/Converters.java
@@ -0,0 +1,21 @@
+package com.projectswg.utility.clientdata;
+
+import java.util.function.Supplier;
+
+public enum Converters {
+ BUILDOUT_BUILDING_LIST (ConvertBuildingList::new),
+ BUILDOUT_OBJECTS (ConvertBuildouts::new),
+ OBJECTS_OBJECT_DATA (ConvertObjectData::new),
+ ABSTRACT_SLOT_DEFINITION(ConvertSlotDefinition::new);
+
+ private final Supplier converter;
+
+ Converters(Supplier converter) {
+ this.converter = converter;
+ }
+
+ public void load() {
+ converter.get().convert();
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/buildouts/BuildoutLoader.java b/src/utility/java/com/projectswg/utility/clientdata/buildouts/BuildoutLoader.java
new file mode 100644
index 000000000..3cf9cb0f4
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/buildouts/BuildoutLoader.java
@@ -0,0 +1,91 @@
+/***********************************************************************************
+ * Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
+ * *
+ * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+ * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+ * Our goal is to create an emulator which will provide a server for players to *
+ * continue playing a game similar to the one they used to play. We are basing *
+ * it on the final publish of the game prior to end-game events. *
+ * *
+ * This file is part of Holocore. *
+ * *
+ * --------------------------------------------------------------------------------*
+ * *
+ * Holocore is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Affero General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * Holocore is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Affero General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Affero General Public License *
+ * along with Holocore. If not, see . *
+ ***********************************************************************************/
+package com.projectswg.utility.clientdata.buildouts;
+
+import com.projectswg.common.data.location.Terrain;
+import com.projectswg.common.data.swgfile.ClientFactory;
+import com.projectswg.common.data.swgfile.visitors.CrcStringTableData;
+import com.projectswg.common.data.swgfile.visitors.DatatableData;
+import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
+import me.joshlarson.jlcommon.log.Log;
+
+import java.util.*;
+
+public class BuildoutLoader {
+
+ private static final CrcStringTableData crcTable = (CrcStringTableData) ClientFactory.getInfoFromFile("misc/object_template_crc_string_table.iff");
+
+ private final Map objectTable;
+ private final Map> objects;
+
+ public BuildoutLoader() {
+ objectTable = new HashMap<>();
+ objects = new Hashtable<>();
+ }
+
+ public void loadAllBuildouts() {
+ for (Terrain t : getTerrainsToLoad())
+ loadBuildoutsForTerrain(t);
+ }
+
+ public void loadBuildoutsForTerrain(Terrain terrain) {
+ DatatableData table = (DatatableData) ClientFactory.getInfoFromFile("datatables/buildout/buildout_scenes.iff");
+ for (int row = 0; row < table.getRowCount(); row++) {
+ if (table.getCell(row, 0).equals(terrain.name().toLowerCase(Locale.ENGLISH))) {
+ TerrainBuildoutLoader loader = new TerrainBuildoutLoader(crcTable, terrain);
+ loader.load(row);
+ objects.putAll(loader.getObjects());
+ objectTable.putAll(loader.getObjectTable());
+ return;
+ }
+ }
+ System.err.println("Could not find buildouts for terrain: " + terrain);
+ Log.e("Could not find buildouts for terrain: %s", terrain);
+ }
+
+ public Map getObjectTable() {
+ return objectTable;
+ }
+
+ public Map> getObjects() {
+ return objects;
+ }
+
+ private static List getTerrainsToLoad() {
+ DatatableData table = (DatatableData) ClientFactory.getInfoFromFile("datatables/buildout/buildout_scenes.iff");
+ List terrains = new LinkedList<>();
+ for (int row = 0; row < table.getRowCount(); row++) {
+ Terrain t = Terrain.getTerrainFromName((String) table.getCell(row, 0));
+ if (t != null)
+ terrains.add(t);
+ else
+ System.err.println("Couldn't find terrain: " + table.getCell(row, 0));
+ }
+ return terrains;
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/buildouts/SnapshotLoader.java b/src/utility/java/com/projectswg/utility/clientdata/buildouts/SnapshotLoader.java
new file mode 100644
index 000000000..d2d64df35
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/buildouts/SnapshotLoader.java
@@ -0,0 +1,72 @@
+/***********************************************************************************
+ * Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
+ * *
+ * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+ * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+ * Our goal is to create an emulator which will provide a server for players to *
+ * continue playing a game similar to the one they used to play. We are basing *
+ * it on the final publish of the game prior to end-game events. *
+ * *
+ * This file is part of Holocore. *
+ * *
+ * --------------------------------------------------------------------------------*
+ * *
+ * Holocore is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Affero General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * Holocore is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Affero General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Affero General Public License *
+ * along with Holocore. If not, see . *
+ ***********************************************************************************/
+package com.projectswg.utility.clientdata.buildouts;
+
+import com.projectswg.common.data.location.Terrain;
+import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
+
+import java.util.*;
+
+public class SnapshotLoader {
+
+ private static final Set TERRAINS = EnumSet.of(
+ Terrain.CORELLIA, Terrain.DANTOOINE, Terrain.DATHOMIR,
+ Terrain.DUNGEON1, Terrain.ENDOR, Terrain.LOK,
+ Terrain.NABOO, Terrain.RORI, Terrain.TALUS,
+ Terrain.TATOOINE, Terrain.YAVIN4
+ );
+
+ private final Map objectTable;
+ private final List objects;
+
+ public SnapshotLoader() {
+ objectTable = new HashMap<>();
+ objects = new LinkedList<>();
+ }
+
+ public void loadAllSnapshots() {
+ for (Terrain t : TERRAINS) {
+ loadSnapshotsForTerrain(t);
+ }
+ }
+
+ public void loadSnapshotsForTerrain(Terrain t) {
+ TerrainSnapshotLoader loader = new TerrainSnapshotLoader(t);
+ loader.load();
+ objects.addAll(loader.getObjects());
+ objectTable.putAll(loader.getObjectTable());
+ }
+
+ public Map getObjectTable() {
+ return objectTable;
+ }
+
+ public List getObjects() {
+ return objects;
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/buildouts/SwgBuildoutArea.java b/src/utility/java/com/projectswg/utility/clientdata/buildouts/SwgBuildoutArea.java
new file mode 100644
index 000000000..aac399bf1
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/buildouts/SwgBuildoutArea.java
@@ -0,0 +1,252 @@
+/***********************************************************************************
+ * Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
+ * *
+ * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+ * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+ * Our goal is to create an emulator which will provide a server for players to *
+ * continue playing a game similar to the one they used to play. We are basing *
+ * it on the final publish of the game prior to end-game events. *
+ * *
+ * This file is part of Holocore. *
+ * *
+ * --------------------------------------------------------------------------------*
+ * *
+ * Holocore is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Affero General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * Holocore is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Affero General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Affero General Public License *
+ * along with Holocore. If not, see . *
+ ***********************************************************************************/
+package com.projectswg.utility.clientdata.buildouts;
+
+public class SwgBuildoutArea {
+
+ // Datatable Information
+ private String name;
+ private float x1;
+ private float z1;
+ private float x2;
+ private float z2;
+ private boolean useClipRect;
+ private float clipRectX1;
+ private float clipRectZ1;
+ private float clipRectX2;
+ private float clipRectZ2;
+ private int envFlags;
+ private int envFlagsExclude;
+ private boolean useOrigin;
+ private float originX;
+ private float originZ;
+ private float compositeX1;
+ private float compositeZ1;
+ private float compositeX2;
+ private float compositeZ2;
+ private String compositeName;
+ private boolean isolated;
+ private boolean allowMap;
+ private boolean internal;
+ private boolean allowRadarTerrain;
+ private String eventRequired;
+ // Calculated
+ private int index;
+ // Used to calculate rows
+ private long currentBuilding;
+ private long currentCell;
+ private long buildingObjectId;
+ private long objectIdBase;
+
+ public void load(Object [] datatableRow, int sceneNumber, int areaNumber) {
+ name = (String) datatableRow[0];
+ x1 = (Float) datatableRow[1];
+ z1 = (Float) datatableRow[2];
+ x2 = (Float) datatableRow[3];
+ z2 = (Float) datatableRow[4];
+ useClipRect = (Boolean) datatableRow[5];
+ clipRectX1 = (Float) datatableRow[6];
+ clipRectZ1 = (Float) datatableRow[7];
+ clipRectX2 = (Float) datatableRow[8];
+ clipRectZ2 = (Float) datatableRow[9];
+ envFlags = (Integer) datatableRow[10];
+ envFlagsExclude = (Integer) datatableRow[11];
+ useOrigin = (Boolean) datatableRow[12];
+ originX = (Float) datatableRow[13];
+ originZ = (Float) datatableRow[14];
+ compositeX1 = (Float) datatableRow[15];
+ compositeZ1 = (Float) datatableRow[16];
+ compositeX2 = (Float) datatableRow[17];
+ compositeZ2 = (Float) datatableRow[18];
+ compositeName = (String) datatableRow[19];
+ isolated = (Boolean) datatableRow[20];
+ allowMap = (Boolean) datatableRow[21];
+ internal = (Boolean) datatableRow[22];
+ allowRadarTerrain = (Boolean) datatableRow[23];
+ eventRequired = (String) datatableRow[24];
+ reset();
+ calculate(sceneNumber, areaNumber);
+ }
+
+ private void reset() {
+ currentBuilding = 0;
+ currentCell = 0;
+ buildingObjectId = 0;
+ objectIdBase = 0;
+ }
+
+ private void calculate(int sceneNumber, int areaNumber) {
+ index = sceneNumber * 100 + areaNumber;
+ buildingObjectId = -(index + 1) * 30000L;
+ objectIdBase = buildingObjectId + 2000;
+ }
+
+ public void setCurrentBuilding(long currentBuilding) {
+ this.currentBuilding = currentBuilding;
+ }
+
+ public void setCurrentCell(long currentCell) {
+ this.currentCell = currentCell;
+ }
+
+ public void setBuildingObjectId(long buildingObjectId) {
+ this.buildingObjectId = buildingObjectId;
+ }
+
+ public void setObjectIdBase(long objectIdBase) {
+ this.objectIdBase = objectIdBase;
+ }
+
+ public void incrementBuildingObjectId() {
+ buildingObjectId++;
+ }
+
+ public void incrementObjectIdBase() {
+ objectIdBase++;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public float getX1() {
+ return x1;
+ }
+
+ public float getZ1() {
+ return z1;
+ }
+
+ public float getX2() {
+ return x2;
+ }
+
+ public float getZ2() {
+ return z2;
+ }
+
+ public boolean isUseClipRect() {
+ return useClipRect;
+ }
+
+ public float getClipRectX1() {
+ return clipRectX1;
+ }
+
+ public float getClipRectZ1() {
+ return clipRectZ1;
+ }
+
+ public float getClipRectX2() {
+ return clipRectX2;
+ }
+
+ public float getClipRectZ2() {
+ return clipRectZ2;
+ }
+
+ public int getEnvFlags() {
+ return envFlags;
+ }
+
+ public int getEnvFlagsExclude() {
+ return envFlagsExclude;
+ }
+
+ public boolean isUseOrigin() {
+ return useOrigin;
+ }
+
+ public float getOriginX() {
+ return originX;
+ }
+
+ public float getOriginZ() {
+ return originZ;
+ }
+
+ public float getCompositeX1() {
+ return compositeX1;
+ }
+
+ public float getCompositeZ1() {
+ return compositeZ1;
+ }
+
+ public float getCompositeX2() {
+ return compositeX2;
+ }
+
+ public float getCompositeZ2() {
+ return compositeZ2;
+ }
+
+ public String getCompositeName() {
+ return compositeName;
+ }
+
+ public boolean isIsolated() {
+ return isolated;
+ }
+
+ public boolean isAllowMap() {
+ return allowMap;
+ }
+
+ public boolean isInternal() {
+ return internal;
+ }
+
+ public boolean isAllowRadarTerrain() {
+ return allowRadarTerrain;
+ }
+
+ public String getEventRequired() {
+ return eventRequired;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public long getCurrentBuilding() {
+ return currentBuilding;
+ }
+
+ public long getCurrentCell() {
+ return currentCell;
+ }
+
+ public long getBuildingObjectId() {
+ return buildingObjectId;
+ }
+
+ public long getObjectIdBase() {
+ return objectIdBase;
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/buildouts/SwgBuildoutRow.java b/src/utility/java/com/projectswg/utility/clientdata/buildouts/SwgBuildoutRow.java
new file mode 100644
index 000000000..8dc190726
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/buildouts/SwgBuildoutRow.java
@@ -0,0 +1,164 @@
+/***********************************************************************************
+ * Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
+ * *
+ * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+ * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+ * Our goal is to create an emulator which will provide a server for players to *
+ * continue playing a game similar to the one they used to play. We are basing *
+ * it on the final publish of the game prior to end-game events. *
+ * *
+ * This file is part of Holocore. *
+ * *
+ * --------------------------------------------------------------------------------*
+ * *
+ * Holocore is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Affero General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * Holocore is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Affero General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Affero General Public License *
+ * along with Holocore. If not, see . *
+ ***********************************************************************************/
+package com.projectswg.utility.clientdata.buildouts;
+
+import com.projectswg.common.data.CRC;
+import com.projectswg.common.data.location.Location;
+import com.projectswg.common.data.swgfile.visitors.CrcStringTableData;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+public class SwgBuildoutRow {
+
+ private static final int cellCrc = CRC.getCrc("object/cell/shared_cell.iff");
+
+ private final SwgBuildoutArea buildoutArea;
+ private final AtomicReference location;
+ private long objectId;
+ private long containerId;
+ private int type;
+ private int sharedTemplateCrc;
+ private int cellIndex;
+ private float radius;
+ private int portalLayoutCrc;
+ private String template;
+
+ public SwgBuildoutRow(SwgBuildoutArea buildoutArea) {
+ this.buildoutArea = buildoutArea;
+ this.location = new AtomicReference<>(null);
+ }
+
+ public void load(Object [] datatableRow, CrcStringTableData crcString) {
+ switch (datatableRow.length) {
+ case 11:
+ loadSmall(datatableRow, crcString);
+ break;
+ case 14:
+ loadLarge(datatableRow, crcString);
+ break;
+ default:
+ throw new IllegalArgumentException("Datatable row must be either 11 or 14 columns!");
+ }
+ translateLocation();
+ }
+
+ private void loadSmall(Object [] datatableRow, CrcStringTableData crcString) {
+ loadEndColumns(datatableRow, crcString, 0);
+ if (portalLayoutCrc != 0) { // is building
+ objectId = buildoutArea.getBuildingObjectId();
+ buildoutArea.incrementBuildingObjectId();
+ buildoutArea.setCurrentBuilding(objectId);
+ containerId = 0;
+ } else if (sharedTemplateCrc == cellCrc) {
+ objectId = buildoutArea.getBuildingObjectId();
+ buildoutArea.incrementBuildingObjectId();
+ buildoutArea.setCurrentCell(objectId);
+ containerId = buildoutArea.getCurrentBuilding();
+ } else if (cellIndex > 0) { // is in cell
+ objectId = buildoutArea.getObjectIdBase();
+ buildoutArea.incrementObjectIdBase();
+ containerId = buildoutArea.getCurrentCell();
+ } else { // is somewhere else
+ objectId = buildoutArea.getObjectIdBase();
+ buildoutArea.incrementObjectIdBase();
+ containerId = 0;
+ }
+ }
+
+ private void loadLarge(Object [] datatableRow, CrcStringTableData crcString) {
+ objectId = (Integer) datatableRow[0];
+ containerId = (Integer) datatableRow[1];
+ type = (Integer) datatableRow[2];
+ loadEndColumns(datatableRow, crcString, 3);
+ final long indexShifted = (buildoutArea.getIndex() + 1L) << 48;
+ if (objectId < 0)
+ objectId ^= indexShifted;
+ if (containerId < 0)
+ containerId ^= indexShifted;
+ }
+
+ private void loadEndColumns(Object [] datatableRow, CrcStringTableData crcString, int offset) {
+ sharedTemplateCrc = (Integer) datatableRow[offset];
+ cellIndex = (Integer) datatableRow[offset + 1];
+ Location loc = Location.builder()
+ .setX((Float) datatableRow[offset + 2])
+ .setY((Float) datatableRow[offset + 3])
+ .setZ((Float) datatableRow[offset + 4])
+ .setOrientationW((Float) datatableRow[offset + 5])
+ .setOrientationX((Float) datatableRow[offset + 6])
+ .setOrientationY((Float) datatableRow[offset + 7])
+ .setOrientationZ((Float) datatableRow[offset + 8])
+ .build();
+ location.set(loc);
+ radius = (Float) datatableRow[offset + 9];
+ portalLayoutCrc = (Integer) datatableRow[offset + 10];
+ template = crcString.getTemplateString(sharedTemplateCrc);
+ }
+
+ private void translateLocation() {
+ if (cellIndex != 0)
+ return;
+ location.set(Location.builder(location.get()).translatePosition(buildoutArea.getX1(), 0, buildoutArea.getZ1()).build());
+ }
+
+ public Location getLocation() {
+ return location.get();
+ }
+
+ public long getObjectId() {
+ return objectId;
+ }
+
+ public long getContainerId() {
+ return containerId;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public int getSharedTemplateCrc() {
+ return sharedTemplateCrc;
+ }
+
+ public int getCellIndex() {
+ return cellIndex;
+ }
+
+ public float getRadius() {
+ return radius;
+ }
+
+ public int getPortalLayoutCrc() {
+ return portalLayoutCrc;
+ }
+
+ public String getTemplate() {
+ return template;
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/buildouts/TerrainBuildoutLoader.java b/src/utility/java/com/projectswg/utility/clientdata/buildouts/TerrainBuildoutLoader.java
new file mode 100644
index 000000000..171b8bd5f
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/buildouts/TerrainBuildoutLoader.java
@@ -0,0 +1,125 @@
+/***********************************************************************************
+ * Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
+ * *
+ * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+ * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+ * Our goal is to create an emulator which will provide a server for players to *
+ * continue playing a game similar to the one they used to play. We are basing *
+ * it on the final publish of the game prior to end-game events. *
+ * *
+ * This file is part of Holocore. *
+ * *
+ * --------------------------------------------------------------------------------*
+ * *
+ * Holocore is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Affero General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * Holocore is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Affero General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Affero General Public License *
+ * along with Holocore. If not, see . *
+ ***********************************************************************************/
+package com.projectswg.utility.clientdata.buildouts;
+
+import com.projectswg.common.data.location.Location;
+import com.projectswg.common.data.location.Terrain;
+import com.projectswg.common.data.swgfile.ClientFactory;
+import com.projectswg.common.data.swgfile.visitors.CrcStringTableData;
+import com.projectswg.common.data.swgfile.visitors.DatatableData;
+import com.projectswg.holocore.resources.support.objects.ObjectCreator;
+import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
+import com.projectswg.holocore.resources.support.objects.swg.cell.CellObject;
+import me.joshlarson.jlcommon.log.Log;
+
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+class TerrainBuildoutLoader {
+
+ private static final String BASE_PATH = "datatables/buildout/";
+
+ private final CrcStringTableData crcTable;
+ private final Terrain terrain;
+ private final Map objectTable;
+ private final Map> objects;
+
+ public TerrainBuildoutLoader(CrcStringTableData crcTable, Terrain terrain) {
+ this.crcTable = crcTable;
+ this.terrain = terrain;
+ this.objectTable = new Hashtable<>(512);
+ this.objects = new Hashtable<>();
+ }
+
+ public void load(int sceneNumber) {
+ objects.clear();
+ loadAreas(sceneNumber);
+ }
+
+ public Map getObjectTable() {
+ return objectTable;
+ }
+
+ public Map> getObjects() {
+ return objects;
+ }
+
+ private void loadAreas(int sceneNumber) {
+ String file = BASE_PATH+"areas_"+terrain.getName()+".iff";
+ DatatableData areaTable = (DatatableData) ClientFactory.getInfoFromFile(file);
+ for (int row = 0; row < areaTable.getRowCount(); row++) {
+ SwgBuildoutArea area = new SwgBuildoutArea();
+ area.load(areaTable.getRow(row), sceneNumber, row);
+ loadArea(area);
+ }
+ }
+
+ private void loadArea(SwgBuildoutArea area) {
+ String file = BASE_PATH+terrain.getName()+"/"+area.getName().replace("server", "client")+".iff";
+ DatatableData areaTable = (DatatableData) ClientFactory.getInfoFromFile(file);
+ SwgBuildoutRow buildoutRow = new SwgBuildoutRow(area);
+ objectTable.clear();
+ for (int row = 0; row < areaTable.getRowCount(); row++) {
+ buildoutRow.load(areaTable.getRow(row), crcTable);
+ SWGObject object = createObject(buildoutRow);
+ object.setBuildoutAreaId(area.getIndex());
+ setCellInformation(object, buildoutRow.getCellIndex());
+ addObject(area.getName(), object, buildoutRow.getContainerId());
+ }
+ }
+
+ private SWGObject createObject(SwgBuildoutRow row) {
+ SWGObject object = ObjectCreator.createObjectFromTemplate(row.getObjectId(), row.getTemplate());
+ Location l = row.getLocation();
+ object.setPosition(terrain, l.getX(), l.getY(), l.getZ());
+ object.setOrientation(l.getOrientationX(), l.getOrientationY(), l.getOrientationZ(), l.getOrientationW());
+ return object;
+ }
+
+ private void addObject(String areaName, SWGObject object, long containerId) {
+ objectTable.put(object.getObjectId(), object);
+ if (containerId != 0) {
+ SWGObject container = objectTable.get(containerId);
+ object.systemMove(container);
+ if (container == null)
+ Log.e("Failed to load object: " + object.getTemplate());
+ } else {
+ List list = objects.computeIfAbsent(areaName, k -> new LinkedList<>());
+ list.add(object);
+ }
+ }
+
+ private void setCellInformation(SWGObject object, int cellIndex) {
+ if (!(object instanceof CellObject))
+ return;
+ CellObject cell = (CellObject) object;
+ cell.setNumber(cellIndex);
+ }
+
+}
diff --git a/src/utility/java/com/projectswg/utility/clientdata/buildouts/TerrainSnapshotLoader.java b/src/utility/java/com/projectswg/utility/clientdata/buildouts/TerrainSnapshotLoader.java
new file mode 100644
index 000000000..bd0ac7130
--- /dev/null
+++ b/src/utility/java/com/projectswg/utility/clientdata/buildouts/TerrainSnapshotLoader.java
@@ -0,0 +1,119 @@
+/***********************************************************************************
+ * Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
+ * *
+ * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
+ * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
+ * Our goal is to create an emulator which will provide a server for players to *
+ * continue playing a game similar to the one they used to play. We are basing *
+ * it on the final publish of the game prior to end-game events. *
+ * *
+ * This file is part of Holocore. *
+ * *
+ * --------------------------------------------------------------------------------*
+ * *
+ * Holocore is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Affero General Public License as *
+ * published by the Free Software Foundation, either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * Holocore is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Affero General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Affero General Public License *
+ * along with Holocore. If not, see . *
+ ***********************************************************************************/
+package com.projectswg.utility.clientdata.buildouts;
+
+import com.projectswg.common.data.location.Location;
+import com.projectswg.common.data.location.Terrain;
+import com.projectswg.common.data.swgfile.ClientFactory;
+import com.projectswg.common.data.swgfile.visitors.WorldSnapshotData;
+import com.projectswg.common.data.swgfile.visitors.WorldSnapshotData.Node;
+import com.projectswg.holocore.resources.support.objects.ObjectCreator;
+import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
+import com.projectswg.holocore.resources.support.objects.swg.building.BuildingObject;
+import com.projectswg.holocore.resources.support.objects.swg.cell.CellObject;
+import me.joshlarson.jlcommon.log.Log;
+
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class TerrainSnapshotLoader {
+
+ private static final String BASE_PATH = "snapshot/";
+
+ private final Terrain terrain;
+ private final Map objectTable;
+ private final List objects;
+
+ public TerrainSnapshotLoader(Terrain terrain) {
+ this.terrain = terrain;
+ this.objectTable = new Hashtable<>(12 * 1024);
+ this.objects = new LinkedList<>();
+ }
+
+ public Map getObjectTable() {
+ return objectTable;
+ }
+
+ public List getObjects() {
+ return objects;
+ }
+
+ public void load() {
+ objects.clear();
+ String path = BASE_PATH + terrain.getName() + ".ws";
+ WorldSnapshotData data = (WorldSnapshotData) ClientFactory.getInfoFromFile(path);
+ Map templates = data.getObjectTemplateNames();
+ for (Node node : data.getNodes()) {
+ createFromNode(templates, node);
+ }
+ }
+
+ private void createFromNode(Map templates, Node node) {
+ SWGObject object = createObject(templates, node);
+ object.setBuildoutAreaId(-1);
+ setCellInformation(object, node.getCellIndex());
+ addObject(object, node.getContainerId());
+
+ for (Node child : node.getChildren()) {
+ createFromNode(templates, child);
+ }
+ }
+
+ private SWGObject createObject(Map templateMap, Node row) {
+ SWGObject object = ObjectCreator.createObjectFromTemplate(row.getId(), templateMap.get(row.getObjectTemplateNameIndex()));
+ Location l = row.getLocation();
+ object.setPosition(terrain, l.getX(), l.getY(), l.getZ());
+ object.setOrientation(l.getOrientationX(), l.getOrientationY(), l.getOrientationZ(), l.getOrientationW());
+ return object;
+ }
+
+ private void addObject(SWGObject object, long containerId) {
+ objectTable.put(object.getObjectId(), object);
+ if (containerId != 0) {
+ SWGObject container = objectTable.get(containerId);
+ if (!(object instanceof CellObject) && container instanceof BuildingObject) {
+ Log.w("Not adding: %s to %s - invalid type for BuildingObject", object, container);
+ return;
+ }
+ object.systemMove(container);
+ if (container == null)
+ Log.e("Failed to load object: " + object.getTemplate());
+ } else {
+ objects.add(object);
+ }
+ }
+
+ private void setCellInformation(SWGObject object, int cellIndex) {
+ if (!(object instanceof CellObject))
+ return;
+ CellObject cell = (CellObject) object;
+ cell.setNumber(cellIndex);
+ }
+
+}