Added array-style lookup with numbered columns in SDBs

This commit is contained in:
Obique
2019-01-26 15:00:05 -06:00
parent c0f42dfead
commit 4ae382a8aa
9 changed files with 981 additions and 630 deletions

View File

@@ -6,7 +6,7 @@ plugins {
id 'idea'
id "com.github.johnrengelman.shadow" version "4.0.4"
id "org.javamodularity.moduleplugin" version "1.4.0"
id "org.beryx.jlink" version "2.4.0"
id "org.beryx.jlink" version "2.4.3"
}
mainClassName = 'com.projectswg.holocore.ProjectSWG'

File diff suppressed because one or more lines are too long

View File

@@ -86,6 +86,10 @@ public class ProjectSWG {
Log.i("Holocore version: %s", VERSION);
if (ProjectSWG.class.getResourceAsStream("/marker.txt") == null) {
Log.a("Failed to read Holocore resources - aborting");
return -1;
}
DataManager.initialize();
Thread.currentThread().setPriority(10);
initializeServerFactory();

View File

@@ -0,0 +1,239 @@
/***********************************************************************************
* Copyright (c) 2019 /// 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 <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.resources.support.data.server_info;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class SdbColumnArraySet {
private final Pattern pattern;
private final Map<Integer, Integer> mappedColumns;
private final AtomicReference<SdbResultSet> set;
private final AtomicInteger arraySize;
private SdbColumnArraySet(@Nullable SdbResultSet set, @Language("RegExp") String regex) {
this.pattern = Pattern.compile(regex);
this.mappedColumns = new HashMap<>();
this.set = new AtomicReference<>(set);
this.arraySize = new AtomicInteger(0);
loadColumnInfo(set);
}
public int size() {
return arraySize.get();
}
protected SdbResultSet getResultSet() {
return set.get();
}
protected Collection<Entry<Integer, Integer>> getMappedEntries() {
return mappedColumns.entrySet();
}
void loadColumnInfo(@Nullable SdbResultSet set) {
mappedColumns.clear();
arraySize.set(0);
this.set.getAndSet(set);
if (set == null)
return;
int columnIndex = 0;
for (String column : set.getColumns()) {
Matcher matcher = pattern.matcher(column);
boolean match = matcher.matches();
if (match && matcher.groupCount() == 1) {
String arrayIndexStr = matcher.group(1);
try {
int arrayIndex = Integer.parseUnsignedInt(arrayIndexStr);
arraySize.updateAndGet(prevIndex -> arrayIndex >= prevIndex ? arrayIndex + 1 : prevIndex);
mappedColumns.put(arrayIndex, columnIndex);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("invalid pattern. The first capturing group must be only digits");
}
} else if (match) {
throw new IllegalArgumentException("invalid pattern. Regex must have capturing group for array index");
}
columnIndex++;
}
}
public static class SdbTextColumnArraySet extends SdbColumnArraySet {
private String [] cachedArray;
SdbTextColumnArraySet(@Nullable SdbResultSet set, @Language("RegExp") String regex) {
super(set, regex);
this.cachedArray = null;
}
public String [] getArray() {
SdbResultSet set = getResultSet();
String [] cachedArray = this.cachedArray;
if (cachedArray == null || cachedArray.length != size()) {
cachedArray = new String[size()];
this.cachedArray = cachedArray;
}
Arrays.fill(cachedArray, null);
if (set != null) {
for (Entry<Integer, Integer> e : getMappedEntries()) {
cachedArray[e.getKey()] = set.getText(e.getValue());
}
}
return cachedArray;
}
}
public static class SdbIntegerColumnArraySet extends SdbColumnArraySet {
private int [] cachedArray;
SdbIntegerColumnArraySet(@Nullable SdbResultSet set, @Language("RegExp") String regex) {
super(set, regex);
this.cachedArray = null;
}
public int [] getArray() {
SdbResultSet set = getResultSet();
int [] cachedArray = this.cachedArray;
if (cachedArray == null || cachedArray.length != size()) {
cachedArray = new int[size()];
this.cachedArray = cachedArray;
}
Arrays.fill(cachedArray, Integer.MAX_VALUE);
if (set != null) {
for (Entry<Integer, Integer> e : getMappedEntries()) {
cachedArray[e.getKey()] = (int) set.getInt(e.getValue());
}
}
return cachedArray;
}
}
public static class SdbLongColumnArraySet extends SdbColumnArraySet {
private long [] cachedArray;
SdbLongColumnArraySet(@Nullable SdbResultSet set, @Language("RegExp") String regex) {
super(set, regex);
this.cachedArray = null;
}
public long [] getArray() {
SdbResultSet set = getResultSet();
long [] cachedArray = this.cachedArray;
if (cachedArray == null || cachedArray.length != size()) {
cachedArray = new long[size()];
this.cachedArray = cachedArray;
}
Arrays.fill(cachedArray, Long.MAX_VALUE);
if (set != null) {
for (Entry<Integer, Integer> e : getMappedEntries()) {
cachedArray[e.getKey()] = set.getInt(e.getValue());
}
}
return cachedArray;
}
}
public static class SdbRealColumnArraySet extends SdbColumnArraySet {
private double [] cachedArray;
SdbRealColumnArraySet(@Nullable SdbResultSet set, @Language("RegExp") String regex) {
super(set, regex);
this.cachedArray = null;
}
public double [] getArray() {
SdbResultSet set = getResultSet();
double [] cachedArray = this.cachedArray;
if (cachedArray == null || cachedArray.length != size()) {
cachedArray = new double[size()];
this.cachedArray = cachedArray;
}
Arrays.fill(cachedArray, Double.NaN);
if (set != null) {
for (Entry<Integer, Integer> e : getMappedEntries()) {
cachedArray[e.getKey()] = set.getReal(e.getValue());
}
}
return cachedArray;
}
}
public static class SdbBooleanColumnArraySet extends SdbColumnArraySet {
private boolean [] cachedArray;
SdbBooleanColumnArraySet(@Nullable SdbResultSet set, @Language("RegExp") String regex) {
super(set, regex);
this.cachedArray = null;
}
public boolean [] getArray() {
SdbResultSet set = getResultSet();
boolean [] cachedArray = this.cachedArray;
if (cachedArray == null || cachedArray.length != size()) {
cachedArray = new boolean[size()];
this.cachedArray = cachedArray;
}
Arrays.fill(cachedArray, false);
if (set != null) {
for (Entry<Integer, Integer> e : getMappedEntries()) {
cachedArray[e.getKey()] = set.getBoolean(e.getValue());
}
}
return cachedArray;
}
}
}

View File

@@ -26,7 +26,9 @@
***********************************************************************************/
package com.projectswg.holocore.resources.support.data.server_info;
import com.projectswg.holocore.resources.support.data.server_info.SdbColumnArraySet.*;
import me.joshlarson.jlcommon.log.Log;
import org.intellij.lang.annotations.Language;
import java.io.*;
import java.util.*;
@@ -65,6 +67,11 @@ public class SdbLoader {
void close() throws IOException;
boolean next() throws IOException;
List<String> getColumns();
SdbTextColumnArraySet getTextArrayParser(@Language("RegExp") String regex);
SdbIntegerColumnArraySet getIntegerArrayParser(@Language("RegExp") String regex);
SdbLongColumnArraySet getLongArrayParser(@Language("RegExp") String regex);
SdbRealColumnArraySet getRealArrayParser(@Language("RegExp") String regex);
SdbBooleanColumnArraySet getBooleanArrayParser(@Language("RegExp") String regex);
String getText(int index);
String getText(String columnName);
@@ -83,10 +90,12 @@ public class SdbLoader {
private final Iterator<SdbResultSet> sdbs;
private final AtomicReference<SdbResultSet> sdb;
private final Set<SdbColumnArraySet> arraySets;
private MasterSdbResultSet(Iterator<SdbResultSet> sdbs) {
this.sdbs = sdbs;
this.sdb = new AtomicReference<>(sdbs.hasNext() ? sdbs.next() : null);
this.arraySets = new HashSet<>();
}
@Override
@@ -109,6 +118,8 @@ public class SdbLoader {
}
set = sdbs.next();
sdb.set(set);
for (SdbColumnArraySet arraySet : arraySets)
arraySet.loadColumnInfo(set);
if (set == null)
return false; // shouldn't be possible anyways
}
@@ -120,6 +131,36 @@ public class SdbLoader {
return getResultSet().getColumns();
}
private <T extends SdbColumnArraySet> T registerArrayParser(T instance) {
arraySets.add(instance);
return instance;
}
@Override
public SdbTextColumnArraySet getTextArrayParser(@Language("RegExp") String regex) {
return registerArrayParser(new SdbTextColumnArraySet(this, regex));
}
@Override
public SdbIntegerColumnArraySet getIntegerArrayParser(String regex) {
return registerArrayParser(new SdbIntegerColumnArraySet(this, regex));
}
@Override
public SdbLongColumnArraySet getLongArrayParser(String regex) {
return registerArrayParser(new SdbLongColumnArraySet(this, regex));
}
@Override
public SdbRealColumnArraySet getRealArrayParser(String regex) {
return registerArrayParser(new SdbRealColumnArraySet(this, regex));
}
@Override
public SdbBooleanColumnArraySet getBooleanArrayParser(String regex) {
return registerArrayParser(new SdbBooleanColumnArraySet(this, regex));
}
@Override
public String getText(int index) {
return getResultSet().getText(index);
@@ -227,6 +268,31 @@ public class SdbLoader {
return Arrays.asList(columnNames);
}
@Override
public SdbTextColumnArraySet getTextArrayParser(@Language("RegExp") String regex) {
return new SdbTextColumnArraySet(this, regex);
}
@Override
public SdbIntegerColumnArraySet getIntegerArrayParser(String regex) {
return new SdbIntegerColumnArraySet(this, regex);
}
@Override
public SdbLongColumnArraySet getLongArrayParser(String regex) {
return new SdbLongColumnArraySet(this, regex);
}
@Override
public SdbRealColumnArraySet getRealArrayParser(String regex) {
return new SdbRealColumnArraySet(this, regex);
}
@Override
public SdbBooleanColumnArraySet getBooleanArrayParser(String regex) {
return new SdbBooleanColumnArraySet(this, regex);
}
@Override
public String getText(int index) {
return columnValues[index];
@@ -279,33 +345,44 @@ public class SdbLoader {
lineBuffer.clear();
try {
int b;
readLoop:
while (true) {
b = input.read();
switch (b) {
case -1:
throw new EOFException();
case '\n':
if (!endsNewline)
throw new EOFException();
case '\t':
break readLoop;
case '\r':
continue;
default:
lineBuffer.pushBack((char) b);
break;
}
}
fillLineBuffer(endsNewline);
} catch (EOFException e) {
if (lineBuffer.isEmpty())
throw e;
} catch (IOException e) {
if (lineBuffer.isEmpty())
throw new EOFException();
throw new EOFException("Expected data, got " + e.getClass().getName() + ": " + e.getMessage());
}
return lineBuffer.toString();
}
@SuppressWarnings("HardcodedLineSeparator") // ignores \r
private void fillLineBuffer(boolean endsNewline) throws IOException {
BasicStringBuilder lineBuffer = this.lineBuffer;
int b;
readLoop:
while (true) {
b = input.read();
switch (b) {
case -1:
throw new EOFException("Expected data, got EOF");
case '\n':
if (!endsNewline)
throw new EOFException("Expected data, got newline");
case '\t':
break readLoop;
case '\r':
continue;
default:
lineBuffer.pushBack((char) b);
break;
}
}
}
@SuppressWarnings("HardcodedLineSeparator") // ignores \r
private String fetchLine() {
lineBuffer.clear();
try {

View File

@@ -27,6 +27,7 @@
package com.projectswg.holocore.resources.support.global.zone.name_filter;
import me.joshlarson.jlcommon.log.Log;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
@@ -36,7 +37,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
public class NameFilter {
@@ -49,10 +50,10 @@ public class NameFilter {
private final InputStream reservedStream;
private final InputStream fictionStream;
public NameFilter(InputStream profaneStream, InputStream reservedStream, InputStream fictionStream) {
this.profaneStream = profaneStream;
this.reservedStream = reservedStream;
this.fictionStream = fictionStream;
public NameFilter(@NotNull InputStream profaneStream, @NotNull InputStream reservedStream, @NotNull InputStream fictionStream) {
this.profaneStream = Objects.requireNonNull(profaneStream, "profaneStream");
this.reservedStream = Objects.requireNonNull(reservedStream, "reservedStream");
this.fictionStream = Objects.requireNonNull(fictionStream, "fictionStream");
this.profaneWords = new ArrayList<>();
this.reservedWords = new ArrayList<>();
this.fictionNames = new ArrayList<>();

View File

@@ -11,16 +11,15 @@ import com.projectswg.holocore.intents.support.objects.items.CreateStaticItemInt
import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent;
import com.projectswg.holocore.resources.support.data.config.ConfigFile;
import com.projectswg.holocore.resources.support.data.server_info.DataManager;
import com.projectswg.holocore.resources.support.data.server_info.SdbColumnArraySet.SdbIntegerColumnArraySet;
import com.projectswg.holocore.resources.support.data.server_info.SdbColumnArraySet.SdbTextColumnArraySet;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import com.projectswg.holocore.resources.support.data.server_info.StandardLog;
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
import com.projectswg.holocore.resources.support.data.server_info.loader.NpcLoader;
import com.projectswg.holocore.resources.support.data.server_info.loader.NpcLoader.NpcInfo;
import com.projectswg.holocore.resources.support.global.player.Player;
import com.projectswg.holocore.resources.support.objects.ObjectCreator;
import com.projectswg.holocore.resources.support.objects.permissions.ContainerPermissions;
import com.projectswg.holocore.resources.support.objects.permissions.ReadWritePermissions;
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureDifficulty;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
@@ -110,6 +109,8 @@ public final class LootGenerationService extends Service {
long startTime = StandardLog.onStartLoad("loot tables");
try (SdbResultSet set = SdbLoader.load(new File("serverdata/loot/loot_table.sdb"))) {
SdbTextColumnArraySet itemGroups = set.getTextArrayParser("items_group_([0-9]+)");
SdbIntegerColumnArraySet chanceGroups = set.getIntegerArrayParser("chance_group_([0-9]+)");
while (set.next()) {
String tableName = set.getText("loot_id");
if (tableName.equals("-"))
@@ -118,13 +119,16 @@ public final class LootGenerationService extends Service {
LootTable table = new LootTable();
int totalChance = 0; // Must not be above 100. Also used to convert chances in the form of "33, 33, 34" to "33, 66, 100"
for (int groupNum = 1; groupNum <= 16 && totalChance < 100; groupNum++) {
int groupChance = (int) set.getInt("chance_group_" + groupNum);
if (groupChance == 0)
String [] itemGroupsArray = itemGroups.getArray();
int [] chanceGroupsArray = chanceGroups.getArray();
assert itemGroupsArray.length == chanceGroupsArray.length;
for (int groupNum = 0; groupNum < chanceGroupsArray.length && totalChance < 100; groupNum++) {
int groupChance = chanceGroupsArray[groupNum];
if (groupChance == 0 || groupChance == Integer.MAX_VALUE)
continue;
groupChance += totalChance;
table.addLootGroup(new LootGroup(groupChance, set.getText("items_group_" + groupNum).split(";")));
table.addLootGroup(new LootGroup(groupChance, itemGroupsArray[groupNum].split(";")));
totalChance = groupChance;
}

View File

@@ -31,10 +31,7 @@ import com.projectswg.common.data.encodables.tangible.Race;
import com.projectswg.holocore.resources.support.global.zone.name_filter.NameFilter;
import me.joshlarson.jlcommon.log.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
@@ -219,6 +216,8 @@ public class SWGNameGenerator {
RaceNameRule rule = null;
try(InputStream stream = getClass().getResourceAsStream("/namegen/" + species + ".txt")) {
if (stream == null)
throw new FileNotFoundException("/namegen/"+species+".txt");
rule = createRaceRule(stream);
if (rule != null)

View File