From e225aa8727b727361b3d464ff0d08e44ab3ebf4c Mon Sep 17 00:00:00 2001 From: Waverunner Date: Mon, 20 Jul 2015 12:42:41 -0400 Subject: [PATCH] Updated ServerFactory to allow parsing of tab-deliminated Server Datatable Files (.sdf txt files) to Interchangeable File Format for source control diff viewing instead of using binary files An IFF is created for the corresponding SDF if: one does not exist or the SDF's modify date is > than the IFF's modify date --- .gitignore | 1 + serverdata/map/map_locations.iff | Bin 7940 -> 0 bytes serverdata/map/map_locations.sdf | 107 +++++++++++++ serverdata/map/static_city_points.iff | Bin 994 -> 0 bytes serverdata/map/static_city_points.sdf | 37 +++++ src/resources/client_info/DataFactory.java | 28 +++- src/resources/client_info/IffNode.java | 33 ++++ src/resources/client_info/SWGFile.java | 5 + src/resources/client_info/ServerFactory.java | 145 +++++++++++++++++- .../client_info/visitors/DatatableData.java | 92 +++++++++++ src/services/EngineManager.java | 16 +- 11 files changed, 454 insertions(+), 10 deletions(-) delete mode 100644 serverdata/map/map_locations.iff create mode 100644 serverdata/map/map_locations.sdf delete mode 100644 serverdata/map/static_city_points.iff create mode 100644 serverdata/map/static_city_points.sdf diff --git a/.gitignore b/.gitignore index f897d83d..16fd367a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ /clientdata /.settings /odb +/serverdata/**/*.iff packets.txt log.txt diff --git a/serverdata/map/map_locations.iff b/serverdata/map/map_locations.iff deleted file mode 100644 index 092392e9386f3a1f57cbd22fe2e88c0a45650f5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7940 zcmcJU|BjqC5Xb31eThnWgmS;~Pyecv_M}K{uS!m;swlF&tasrSFlU>bwolN``4GnC^v!X1_k5 zCL+nUZ!Fv70;ai&LA$P&d@-7+x~+>ZLTP_?Ux>)iJFGmH8U}_B!-ZT5bS1V$#>-69 z;26>_%ALdA;J7Wv88MaCPl8;+!`{RB32FNcgR&R3P~4?)EaM64lg?$sUbr#RI`d=2 z8&=AU)jy1%CUhI2t!%Tyk!^);q?uCvXGwhi>AW?j6pd6v`e5|EClS)L;p!a3HO~{M z>hzU_8c;>h6YAbqc4~0;SntCHoy^ic^Sg>dtrzkKYftasw4xAU;9^Cg_RHkU6@?g% zO%;WjnWn_FKDi1QDkfy@phJ0x3C7Sn9FRWy>5VvIky%eh=?MnhURFRnR98Ug7UcwT zo;s&qx=aY(lRhXX^=IHvB2f#*kXJo!QA+&+;LCdn0KwYXL#d9c-t!UfulEa>EYV0l1mdLOlET)0YC{n#N zN3=`aVS()j=_LCdfl}Yz#^!z1onyELw$`tEyXZzU#pWQ z^WwnSgBmNUMyLYzwqGlL0qlw}(vkpsC9Kud;6fLgsEsUAoxwa|8Lt|q@6gVjreUI2 zjh&Db7tJ-OaiK)enF85G zd0MG`MLlNh-D^l==T?xq(aYhBMt?SPVS?uQ!sa{G1N@<1Zaof32aS6@Ez{#bxYlI| z&w*9;V;2@7{8eV`iT5PV8_!_zg5{5^&l!8>J&BWKKVOX*m%m{7I;`O=$*~0+=f};8O&hKb-SCIQlt;iRYZ{qBvca&Zdp7S7k%CLe+um z{CGSb(yFc5foFN4atY-eKVTz}?(9UfKc<1ITIjRmD%D1{nQ4{K0EFXrEnXO8tN)*j z$PBK>vq*=dZ9)ZWu28QQN>o@z1oN5E=P_IplvD*|gEpL6gSENWHl%4v655DMUN0}XXD|1{dlzY(ZgA+} z+Ny(K#UD_Y=;&gwxvHR|&_U|b(XoGm-)qv|A#!jWpI_ha``nu;mI}bwzFo=XW`^J2 zGnvelY;nE};M^&CwLR{O0FDg0Si^l(ZZ9%|#|;b`^puLrq#fJ5OkltRrKB%VP{v}? zc%lnTRY|`Qop95_1hEEFj|T`F32|gHZ4UIWM>rT~Czd0|4_u<~-bR>DsAb-5a1Hdf zBJ{o`VYht8RoWH2PM)vR2wx{$99Q9Tm39afLwJ@sN(;}E99gARd|cq_4*CzH6Qa`9 z!l(IXUeaop5`0>C+**<*;2vP@G4y%~nOE9cqG0lccOqam8DuNI!mZhk&<#P(aGv(q zPUt0?Cas*I^5X-%A@d;e`HE7gxIz#X5_Yi8hFD&Zo^*3N2!Go{te_|&ZfujHH%4Y# zh{?O$S`>VhYJSRq4}(zzuh+SbH{BxrPo|ZYSm3(l#Wg*r1x`mtSc(2$#~2{lAwZDpvvAA(`+OCp8&^!J^bW5UKcG8@*4dgj}mFwB)HC@PK-|K$5^!EvZq_yq-$vpSN*% ylSYi_vLl7>qy*Uh2z(xRY84CJ)}*n@0o~80tGxJD>}P>zEGGXm`EY>#RP-0gu2?Am diff --git a/serverdata/map/static_city_points.sdf b/serverdata/map/static_city_points.sdf new file mode 100644 index 00000000..8b293e0a --- /dev/null +++ b/serverdata/map/static_city_points.sdf @@ -0,0 +1,37 @@ +planet city x z +s s f f +tatooine Mos Eisley 3528 -4804 +tatooine Bestine -1290 -3590 +tatooine Mos Espa -2902 2130 +tatooine Mos Entha 1291 3138 +tatooine Wayfar -5124 -6530 +tatooine Anchorhead 40 -5348 +tatooine Mos Taike 3813 2354 +corellia Coronet -178 -4504 +corellia Tyrena -5140 -2450 +corellia Bela Vistal 6766 -5692 +corellia Kor Vella -3420 3146 +corellia Doaba Guerfel 3274 5582 +corellia Vreni Island -5538 -6176 +naboo Theed -5488 4380 +naboo Keren 1888 2700 +naboo Moenia 4836 -4830.5 +naboo Dee'ja Peak 4686 -1375 +naboo Kaddara 5288 6687 +rori Narmle -5140 -2368 +rori Restuss 5318 5680 +rori Rebel Outpost 3677 -6447 +endor Research Outpost 3222 -3467 +endor Smuggler Outpost -898 1587 +talus Dearic 422 -3004 +talus Nashal 4163 5220 +yavin4 Mining Outpost -312 4865 +yavin4 Labor Outpost -6925 -5707 +dantooine Mining Outpost -640 2486 +dantooine Pirate Outpost 1588 -6399 +dantooine Imperial Outpost -4224 -2400 +dathomir Trade Outpost 599 3071 +dathomir Quarentine Zone -6358 930 +dathomir Science Outpost -85 -1600 +lok Nym's Stronghold 440 5029 +lok Imperial Outpost -1920 -3084 diff --git a/src/resources/client_info/DataFactory.java b/src/resources/client_info/DataFactory.java index 464bf83c..37ed07eb 100644 --- a/src/resources/client_info/DataFactory.java +++ b/src/resources/client_info/DataFactory.java @@ -27,21 +27,14 @@ package resources.client_info; -import utilities.ByteUtilities; - import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; /** * Created by Waverunner on 6/9/2015 */ public abstract class DataFactory { - // readFile only called if dataMap doesn't contain the file as a key or it's value is null protected ClientData readFile(String file) { if (file == null || file.isEmpty()) { System.err.println("File cannot be null or empty!"); @@ -64,6 +57,27 @@ public abstract class DataFactory { return clientData; } + protected File writeFile(SWGFile swgFile, ClientData data) { + if (swgFile == null || data == null) { + System.err.println("File or data objects cannot be null or empty!"); + return null; + } + + File save = new File(swgFile.getFileName()); + data.writeIff(swgFile); + try { + swgFile.save(save); + } catch (IOException e) { + e.printStackTrace(); + } + + return save; + } + protected abstract ClientData createDataObject(String type); + protected ClientData createDataObject(SWGFile swgFile) { + return createDataObject(swgFile.getType()); + } + protected abstract String getFolder(); } diff --git a/src/resources/client_info/IffNode.java b/src/resources/client_info/IffNode.java index d859b8fe..f8afaf13 100644 --- a/src/resources/client_info/IffNode.java +++ b/src/resources/client_info/IffNode.java @@ -67,26 +67,46 @@ public class IffNode { return bb.get(); } + public void writeByte(byte val) { + bb.order(ByteOrder.LITTLE_ENDIAN).put(val); + } + public short readShort() { initBuffer(); return bb.order(ByteOrder.LITTLE_ENDIAN).getShort(); } + public void writeShort(short val) { + bb.order(ByteOrder.LITTLE_ENDIAN).putShort(val); + } + public int readInt() { initBuffer(); return bb.order(ByteOrder.LITTLE_ENDIAN).getInt(); } + public void writeInt(int val) { + bb.order(ByteOrder.LITTLE_ENDIAN).putInt(val); + } + public float readFloat() { initBuffer(); return bb.getFloat(); } + public void writeFloat(float val) { + bb.putFloat(val); + } + public long readLong() { initBuffer(); return bb.order(ByteOrder.LITTLE_ENDIAN).getLong(); } + public void writeLong(long val) { + bb.order(ByteOrder.LITTLE_ENDIAN).putLong(val); + } + public int readUInt() { initBuffer(); return bb.order(ByteOrder.BIG_ENDIAN).getInt(); @@ -119,6 +139,11 @@ public class IffNode { return string; } + public void writeString(String s) { + bb.put(s.getBytes(Charset.forName("US-ASCII"))); + writeByte((byte) 0); + } + public void readChunk(ChunkReader reader) { initBuffer(); while(bb.hasRemaining()) { @@ -198,6 +223,14 @@ public class IffNode { if (bb == null) bb = ByteBuffer.wrap(getChunkData()); } + public void initWriteBuffer(int size) { + bb = ByteBuffer.allocate(size); + } + + public void updateChunk() { + chunkData = bb.array(); + } + private byte[] createForm() { List childrenData = new ArrayList<>(); int size = 0; diff --git a/src/resources/client_info/SWGFile.java b/src/resources/client_info/SWGFile.java index 3e4e6db3..de3c5068 100644 --- a/src/resources/client_info/SWGFile.java +++ b/src/resources/client_info/SWGFile.java @@ -45,6 +45,11 @@ public class SWGFile { public SWGFile() {} + public SWGFile(String fileName, String type) { + this(type); + this.fileName = fileName; + } + public SWGFile(String type) { this.type = type; this.master = new IffNode(type, true); diff --git a/src/resources/client_info/ServerFactory.java b/src/resources/client_info/ServerFactory.java index a829705a..097e0e30 100644 --- a/src/resources/client_info/ServerFactory.java +++ b/src/resources/client_info/ServerFactory.java @@ -29,6 +29,17 @@ package resources.client_info; import resources.client_info.visitors.DatatableData; +import java.io.File; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + /** * Created by Waverunner on 6/9/2015 @@ -42,6 +53,138 @@ public final class ServerFactory extends DataFactory { return (data != null ? (DatatableData) data : null); } + public void updateServerIffs() throws IOException { + File root = new File(getFolder()); + + Files.walkFileTree(root.toPath(), new FileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes basicFileAttributes) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) throws IOException { + if (path.toString().endsWith("sdf")) { + String name = path.toString(); + name = name.substring(0, name.length() - 4) + ".iff"; + + File iff = new File(name); + + if (!iff.exists()) { + convertSif(path, name); + System.out.println("Created Server Datatable: " + name); + } else { + File sif = path.toFile(); + if (sif.lastModified() > iff.lastModified()) { + convertSif(path, name); + System.out.println("Updated Server Datatable: " + name); + } + } + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path path, IOException e) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path path, IOException e) throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } + + private void convertSif(Path sif, String newPath) { + SWGFile swgFile = new SWGFile(newPath, "DTII"); + + DatatableData data = (DatatableData) createDataObject(swgFile); + + String[] columnTypes = null; + String[] columnNames = null; + Object[][] table = null; + + List defaultValues = new ArrayList<>(); + try { + int lineNum = -1; + + List rows = Files.readAllLines(sif); + Iterator itr = rows.iterator(); + while (itr.hasNext()) { + String row = itr.next(); + if (row == null || row.isEmpty() || row.startsWith("#") || row.startsWith("//")) { + itr.remove(); + continue; + } + + // Don't break out of the loop, make sure we remove all the commented/null/empty rows + if (!(lineNum <= 1)) + continue; + + lineNum++; + if (lineNum == 0) { + columnNames = row.split("\t"); + } else if (lineNum == 1) { + columnTypes = row.split("\t"); + for (int i = 0; i < columnTypes.length; i++) { + String columnType = columnTypes[i]; + if (columnType.contains("[")) { + String[] split = columnType.split("\\["); + columnTypes[i] = split[0].toLowerCase(); + defaultValues.add(split[1].replace("]", "")); + } else { + columnTypes[i] = columnType.toLowerCase(); + defaultValues.add(""); + } + } + } + itr.remove(); + } + + if (columnNames == null || columnTypes == null) { + System.err.println("Failed to convert sif " + sif.getFileName()); + return; + } + + table = new Object[rows.size()][columnTypes.length]; + + for (int i = 0; i < rows.size(); i++) { + createDatatableRow(i, rows.get(i), columnTypes, table, defaultValues); + } + + } catch (IOException e) { + e.printStackTrace(); + } + + data.setColumnNames(columnNames); + data.setColumnTypes(columnTypes); + data.setTable(table); + + writeFile(swgFile, data); + } + + private void createDatatableRow(int rowNum, String line, String[] columnTypes, Object[][] table, List defValues) { + String[] values = line.split("\t", -1); + + for (int t = 0; t < columnTypes.length; t++) { + String type = columnTypes[t]; + String val = values[t]; + + if (val.isEmpty() && !defValues.get(t).isEmpty()) + val = defValues.get(t); + + switch(type) { + case "b": table[rowNum][t] = Boolean.valueOf(val); break; + case "h": + case "i": table[rowNum][t] = Integer.valueOf(val); break; + case "f": table[rowNum][t] = Float.valueOf(val); break; + case "s": table[rowNum][t] = val; break; + default: System.err.println("Don't know how to parse type " + type); break; + } + } + } + @Override protected ClientData createDataObject(String type) { switch(type) { @@ -55,7 +198,7 @@ public final class ServerFactory extends DataFactory { return "./serverdata/"; } - private static ServerFactory getInstance() { + public static ServerFactory getInstance() { if (instance == null) instance = new ServerFactory(); return instance; diff --git a/src/resources/client_info/visitors/DatatableData.java b/src/resources/client_info/visitors/DatatableData.java index 500e3f5a..c856a3b3 100644 --- a/src/resources/client_info/visitors/DatatableData.java +++ b/src/resources/client_info/visitors/DatatableData.java @@ -62,6 +62,79 @@ public class DatatableData extends ClientData { } } + @Override + public void writeIff(SWGFile iff) { + iff.addForm("0001"); + writeColumns(iff.addChunk("COLS")); + writeTypes(iff.addChunk("TYPE")); + writeRows(iff.addChunk("ROWS")); + } + + private void writeColumns(IffNode chunk) { + int size = getTableStringSize(columnNames); + + chunk.initWriteBuffer(size + 4); + + chunk.writeInt(columnNames.length); + for (String columnName : columnNames) { + chunk.writeString(columnName); + } + + chunk.updateChunk(); + } + + private void writeTypes(IffNode chunk) { + int size = getTableStringSize(columnTypes); + + chunk.initWriteBuffer(size); + + for (String columnType : columnTypes) { + chunk.writeString(columnType); + } + + chunk.updateChunk(); + } + + private void writeRows(IffNode chunk) { + int size = 0; + int rows = table.length; + + for (int i = 0; i < columnTypes.length; i++) { + String type = columnTypes[i]; + switch(type) { + case "b": + case "f": + case "h": + case "i": size += 4 * rows; break; + case "s": { + for (int r = 0; r < rows; r++) { + size += ((String) table[r][i]).length() + 1; + } + break; + } + default: System.err.println("Cannot write row type " + type); + } + } + chunk.initWriteBuffer(size + 4); + + chunk.writeInt(rows); + + for (int r = 0; r < rows; r++) { + for (int t = 0; t < columnTypes.length; t++) { + String type = columnTypes[t]; + switch(type) { + case "b": + case "h": + case "i": chunk.writeInt((Integer) table[r][t]); break; + case "f": chunk.writeFloat((Float) table[r][t]); break; + case "s": chunk.writeString((String) table[r][t]); break; + default: System.err.println("Cannot write datatable to type " + type); + } + } + } + chunk.updateChunk(); + } + private void parseTypes(IffNode chunk) { columnTypes = new String[columnNames.length]; @@ -190,4 +263,23 @@ public class DatatableData extends ClientData { return columnTypes[column]; } + public void setColumnNames(String[] columnNames) { + this.columnNames = columnNames; + } + + public void setColumnTypes(String[] columnTypes) { + this.columnTypes = columnTypes; + } + + public void setTable(Object[][] table) { + this.table = table; + } + + private int getTableStringSize(String[] table) { + int size = 0; + for (String s : table) { + size += s.length() + 1; + } + return size; + } } diff --git a/src/services/EngineManager.java b/src/services/EngineManager.java index d3968baa..08961089 100644 --- a/src/services/EngineManager.java +++ b/src/services/EngineManager.java @@ -28,8 +28,10 @@ package services; import java.io.File; +import java.io.IOException; import resources.Galaxy; +import resources.client_info.ServerFactory; import resources.config.ConfigFile; import resources.control.Manager; import resources.server_info.Config; @@ -46,6 +48,8 @@ public class EngineManager extends Manager { addChildService(networkManager); addChildService(shutdownService); + + initializeServerFactory(); } @Override @@ -56,7 +60,7 @@ public class EngineManager extends Manager { wipeCharacterDatabase(); if (config.getInt("WIPE-ODB-FILES", 0) == 1) wipeOdbFiles(); - + return super.initialize(); } @@ -73,5 +77,13 @@ public class EngineManager extends Manager { } } } - + + + private void initializeServerFactory() { + try { + ServerFactory.getInstance().updateServerIffs(); + } catch (IOException e) { + e.printStackTrace(); + } + } }