mirror of
https://github.com/ProjectSWGCore/Holocore.git
synced 2026-09-11 21:45:26 -04:00
Removed automatic delta sending for SWGMap and added some new SDB loaders
This commit is contained in:
+1
-1
Submodule pswgcommon updated: d08a091fd4...9f0e9fd4fa
@@ -1,159 +0,0 @@
|
||||
/***********************************************************************************
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.holocore.display;
|
||||
|
||||
import com.projectswg.common.data.location.Terrain;
|
||||
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.GalacticResourceLoader;
|
||||
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.GalacticResourceSpawn;
|
||||
import javafx.application.Application;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class ResourceSpawnViewer extends Application {
|
||||
|
||||
private static final int MAP_SIZE = 16384;
|
||||
private static final double POSITION_GAUSSIAN_FACTOR = MAP_SIZE / 2 * Math.sqrt(2);
|
||||
private static final int STAGE_SIZE = 800;
|
||||
|
||||
private static final Terrain [] ALL_PLANETS = new Terrain[] {
|
||||
Terrain.CORELLIA, Terrain.DANTOOINE, Terrain.DATHOMIR,
|
||||
Terrain.ENDOR, Terrain.KASHYYYK_MAIN, Terrain.LOK,
|
||||
Terrain.MUSTAFAR, Terrain.NABOO, Terrain.RORI,
|
||||
Terrain.TALUS, Terrain.TATOOINE, Terrain.YAVIN4
|
||||
};
|
||||
private static final Color [] COLORS = new Color[] {
|
||||
Color.BLACK, Color.LIGHTGRAY, Color.BLUE, Color.MAGENTA,
|
||||
Color.CYAN, Color.ORANGE, Color.DARKGRAY, Color.PINK, Color.GRAY,
|
||||
Color.RED, Color.GREEN, Color.YELLOW
|
||||
};
|
||||
|
||||
private ComboBox<Terrain> terrainCombo;
|
||||
private Button saveButton;
|
||||
private Canvas resourceCanvas;
|
||||
|
||||
public static void main(String [] args) {
|
||||
Application.launch(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
VBox root = new VBox();
|
||||
HBox topPanel = new HBox();
|
||||
root.getChildren().add(topPanel);
|
||||
root.getChildren().add(resourceCanvas = new Canvas(800, 800));
|
||||
topPanel.getChildren().add(terrainCombo = new ComboBox<>());
|
||||
topPanel.getChildren().add(saveButton = new Button("Save"));
|
||||
setupTopPanel();
|
||||
primaryStage.setScene(new Scene(root, STAGE_SIZE, STAGE_SIZE + 20));
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
private void setupTopPanel() {
|
||||
terrainCombo.setItems(FXCollections.observableArrayList(ALL_PLANETS));
|
||||
terrainCombo.valueProperty().addListener((val, o, n) -> onTerrainChanged(n));
|
||||
terrainCombo.setValue(Terrain.TATOOINE);
|
||||
saveButton.setOnAction(e -> save());
|
||||
}
|
||||
|
||||
private void save() {
|
||||
WritableImage writableImage = new WritableImage(STAGE_SIZE, STAGE_SIZE);
|
||||
resourceCanvas.snapshot(null, writableImage);
|
||||
try {
|
||||
ImageIO.write(SwingFXUtils.fromFXImage(writableImage, null), "png", new File("resource_spawns.png"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void onTerrainChanged(Terrain terrain) {
|
||||
GraphicsContext gc = resourceCanvas.getGraphicsContext2D();
|
||||
gc.clearRect(0, 0, STAGE_SIZE, STAGE_SIZE);
|
||||
for (int x = 0; x < STAGE_SIZE/2; x++) {
|
||||
for (int y = 0; y < STAGE_SIZE/2; y++) {
|
||||
double dist = Math.sqrt(Math.pow(STAGE_SIZE/2-x, 2)+Math.pow(STAGE_SIZE/2-y, 2));
|
||||
double opacity = getProbabilityOpacity(dist/STAGE_SIZE*MAP_SIZE);
|
||||
gc.setStroke(new Color(0, 0, 0, opacity * 0.75));
|
||||
gc.strokeLine(x, y, x, y);
|
||||
gc.strokeLine(STAGE_SIZE-x, STAGE_SIZE-y, STAGE_SIZE-x, STAGE_SIZE-y);
|
||||
gc.strokeLine(STAGE_SIZE-x, y, STAGE_SIZE-x, y);
|
||||
gc.strokeLine(x, STAGE_SIZE-y, x, STAGE_SIZE-y);
|
||||
}
|
||||
}
|
||||
GalacticResourceLoader loader = new GalacticResourceLoader();
|
||||
List<GalacticResourceSpawn> spawns = loader.loadSpawns();
|
||||
int index = 0;
|
||||
for (GalacticResourceSpawn spawn : spawns) {
|
||||
if (spawn.getTerrain() != terrain)
|
||||
continue;
|
||||
Color c = COLORS[(index++) % COLORS.length];
|
||||
gc.setFill(c.deriveColor(0, 1, 1, 0.7));
|
||||
double x = convertToStage(spawn.getX());
|
||||
double z = convertToStage(spawn.getZ());
|
||||
double width = (double) spawn.getRadius() / (MAP_SIZE/2) * STAGE_SIZE;
|
||||
gc.fillOval(x-width/2, STAGE_SIZE-z-width/2, width, width);
|
||||
gc.setFill(Color.BLACK);
|
||||
gc.fillText(Long.toString(spawn.getResourceId()), convertToStage(spawn.getX()) - getHorizontalShift(spawn.getResourceId()), STAGE_SIZE-convertToStage(spawn.getZ())+5);
|
||||
}
|
||||
}
|
||||
|
||||
private int convertToStage(double x) {
|
||||
return (int) (x / (MAP_SIZE/2) * STAGE_SIZE/2) + STAGE_SIZE/2;
|
||||
}
|
||||
|
||||
|
||||
private int getHorizontalShift(long resourceId) {
|
||||
if (resourceId < 10)
|
||||
return 4;
|
||||
if (resourceId < 100)
|
||||
return 8;
|
||||
return 12;
|
||||
}
|
||||
|
||||
private double getProbabilityOpacity(double dist) {
|
||||
return getGaussianY(((dist / POSITION_GAUSSIAN_FACTOR) - 0.5) * 6);
|
||||
}
|
||||
|
||||
private double getGaussianY(double x) {
|
||||
return Math.pow(Math.exp(-((x * x) / 2)), 1 / (Math.sqrt(2 * Math.PI)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.projectswg.holocore;
|
||||
|
||||
import com.projectswg.connection.HolocoreSocket;
|
||||
import com.projectswg.connection.ServerConnectionChangedReason;
|
||||
import com.projectswg.common.network.packets.swg.holo.HoloConnectionStopped.ConnectionStoppedReason;
|
||||
import com.projectswg.holocore.client.HolocoreSocket;
|
||||
import me.joshlarson.jlcommon.concurrency.BasicThread;
|
||||
import me.joshlarson.jlcommon.concurrency.Delay;
|
||||
|
||||
@@ -18,25 +18,25 @@ public class ProjectSWGRunner {
|
||||
public void start() {
|
||||
runner.start();
|
||||
{
|
||||
HolocoreSocket socket = new HolocoreSocket(InetAddress.getLoopbackAddress(), 44463);
|
||||
long start = System.nanoTime();
|
||||
boolean connected = false;
|
||||
while (System.nanoTime() - start <= 60E9) { // 60s max wait
|
||||
connected = socket.getServerStatus().equals("UP");
|
||||
if (connected)
|
||||
break;
|
||||
Delay.sleepSeconds(1);
|
||||
}
|
||||
if (connected) {
|
||||
start = System.nanoTime();
|
||||
try (HolocoreSocket socket = new HolocoreSocket(InetAddress.getLoopbackAddress(), 44463)) {
|
||||
long start = System.nanoTime();
|
||||
boolean connected = false;
|
||||
while (System.nanoTime() - start <= 60E9) { // 60s max wait
|
||||
if (socket.connect(1000)) {
|
||||
socket.disconnect(ServerConnectionChangedReason.CLIENT_DISCONNECT);
|
||||
connected = socket.getServerStatus().equals("UP");
|
||||
if (connected)
|
||||
break;
|
||||
Delay.sleepSeconds(1);
|
||||
}
|
||||
if (connected) {
|
||||
start = System.nanoTime();
|
||||
while (System.nanoTime() - start <= 60E9) { // 60s max wait
|
||||
if (socket.connect(1000)) {
|
||||
socket.disconnect(ConnectionStoppedReason.NETWORK);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
socket.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-7
@@ -6,6 +6,7 @@ import com.projectswg.common.data.location.Terrain;
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.common.network.packets.PacketType;
|
||||
import com.projectswg.common.network.packets.SWGPacket;
|
||||
import com.projectswg.common.network.packets.swg.holo.HoloConnectionStopped.ConnectionStoppedReason;
|
||||
import com.projectswg.common.network.packets.swg.holo.login.HoloLoginRequestPacket;
|
||||
import com.projectswg.common.network.packets.swg.holo.login.HoloLoginResponsePacket;
|
||||
import com.projectswg.common.network.packets.swg.login.EnumerateCharacterId.SWGCharacter;
|
||||
@@ -15,9 +16,8 @@ import com.projectswg.common.network.packets.swg.zone.SceneEndBaselines;
|
||||
import com.projectswg.common.network.packets.swg.zone.baselines.Baseline;
|
||||
import com.projectswg.common.network.packets.swg.zone.insertion.CmdStartScene;
|
||||
import com.projectswg.common.network.packets.swg.zone.insertion.SelectCharacter;
|
||||
import com.projectswg.connection.HolocoreSocket;
|
||||
import com.projectswg.connection.RawPacket;
|
||||
import com.projectswg.connection.ServerConnectionChangedReason;
|
||||
import com.projectswg.holocore.client.HolocoreSocket;
|
||||
import com.projectswg.holocore.client.RawPacket;
|
||||
import com.projectswg.holocore.resources.support.objects.ObjectCreator;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
|
||||
import me.joshlarson.jlcommon.concurrency.BasicThread;
|
||||
@@ -26,9 +26,7 @@ import org.junit.Assert;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
@@ -107,8 +105,8 @@ public class HolocoreClient {
|
||||
|
||||
public void disconnect() {
|
||||
listenThread.stop(false);
|
||||
socket.disconnect(ServerConnectionChangedReason.CLIENT_DISCONNECT);
|
||||
socket.terminate();
|
||||
socket.disconnect(ConnectionStoppedReason.APPLICATION);
|
||||
socket.close();
|
||||
listenThread.awaitTermination(1000);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ import java.util.*;
|
||||
|
||||
public class ProjectSWG {
|
||||
|
||||
public static final String VERSION = "DEC18";
|
||||
public static final String VERSION = "FEB19";
|
||||
|
||||
private static final Galaxy GALAXY = new Galaxy();
|
||||
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
/***********************************************************************************
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.holocore.resources.gameplay.combat.buff;
|
||||
|
||||
import com.projectswg.common.data.CRC;
|
||||
import me.joshlarson.jlcommon.utilities.Arguments;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class BuffData {
|
||||
|
||||
private final int crc;
|
||||
private final String name;
|
||||
private final String groupName;
|
||||
private final int groupPriority;
|
||||
private final String [] effectNames;
|
||||
private final float [] effectValues;
|
||||
|
||||
private int maxStackCount;
|
||||
private float defaultDuration;
|
||||
private String effectFileName;
|
||||
private String particleHardPoint;
|
||||
private String stanceParticle;
|
||||
private String callback;
|
||||
private boolean persistent;
|
||||
private boolean removedOnDeath;
|
||||
private boolean decayOnPvpDeath;
|
||||
|
||||
public BuffData(String name, String groupName, int groupPriority) {
|
||||
this.crc = CRC.getCrc(name.toLowerCase(Locale.ENGLISH));
|
||||
this.name = name;
|
||||
this.groupName = groupName;
|
||||
this.groupPriority = groupPriority;
|
||||
this.effectNames = new String[5];
|
||||
this.effectValues = new float[5];
|
||||
}
|
||||
|
||||
public int getCrc() {
|
||||
return crc;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
public int getGroupPriority() {
|
||||
return groupPriority;
|
||||
}
|
||||
|
||||
public int getMaxStackCount() {
|
||||
return maxStackCount;
|
||||
}
|
||||
|
||||
public String getEffectName(int effect) {
|
||||
Arguments.validate(effect >= 0 && effect < 5, "Effect # must be in range: [0, 5)");
|
||||
return effectNames[effect];
|
||||
}
|
||||
|
||||
public float getEffectValue(int effect) {
|
||||
Arguments.validate(effect >= 0 && effect < 5, "Effect # must be in range: [0, 5)");
|
||||
return effectValues[effect];
|
||||
}
|
||||
|
||||
public float getDefaultDuration() {
|
||||
return defaultDuration;
|
||||
}
|
||||
|
||||
public String getEffectFileName() {
|
||||
return effectFileName;
|
||||
}
|
||||
|
||||
public String getParticleHardPoint() {
|
||||
return particleHardPoint;
|
||||
}
|
||||
|
||||
public String getStanceParticle() {
|
||||
return stanceParticle;
|
||||
}
|
||||
|
||||
public String getCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public boolean isPersistent() {
|
||||
return persistent;
|
||||
}
|
||||
|
||||
public boolean isRemovedOnDeath() {
|
||||
return removedOnDeath;
|
||||
}
|
||||
|
||||
public boolean isDecayOnPvpDeath() {
|
||||
return decayOnPvpDeath;
|
||||
}
|
||||
|
||||
public void setMaxStackCount(int maxStackCount) {
|
||||
this.maxStackCount = maxStackCount;
|
||||
}
|
||||
|
||||
public void setEffectName(int effect, String name) {
|
||||
Arguments.validate(effect >= 0 && effect < 5, "Effect # must be in range: [0, 5)");
|
||||
effectNames[effect] = name;
|
||||
}
|
||||
|
||||
public void setEffectValue(int effect, float value) {
|
||||
Arguments.validate(effect >= 0 && effect < 5, "Effect # must be in range: [0, 5)");
|
||||
effectValues[effect] = value;
|
||||
}
|
||||
|
||||
public void setDefaultDuration(float defaultDuration) {
|
||||
this.defaultDuration = defaultDuration;
|
||||
}
|
||||
|
||||
public void setEffectFileName(String effectFileName) {
|
||||
this.effectFileName = effectFileName;
|
||||
}
|
||||
|
||||
public void setParticleHardPoint(String particleHardPoint) {
|
||||
this.particleHardPoint = particleHardPoint;
|
||||
}
|
||||
|
||||
public void setStanceParticle(String stanceParticle) {
|
||||
this.stanceParticle = stanceParticle;
|
||||
}
|
||||
|
||||
public void setCallback(String callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void setPersistent(boolean persistent) {
|
||||
this.persistent = persistent;
|
||||
}
|
||||
|
||||
public void setRemovedOnDeath(boolean removedOnDeath) {
|
||||
this.removedOnDeath = removedOnDeath;
|
||||
}
|
||||
|
||||
public void setDecayOnPvpDeath(boolean decayOnPvpDeath) {
|
||||
this.decayOnPvpDeath = decayOnPvpDeath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/***********************************************************************************
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.holocore.resources.gameplay.combat.buff;
|
||||
|
||||
import com.projectswg.common.data.CRC;
|
||||
import com.projectswg.common.data.swgfile.ClientFactory;
|
||||
import com.projectswg.common.data.swgfile.visitors.DatatableData;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class BuffMap {
|
||||
|
||||
private final Map<Integer, BuffData> buffMap;
|
||||
|
||||
public BuffMap() {
|
||||
this.buffMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
DatatableData buffTable = (DatatableData) ClientFactory.getInfoFromFile("datatables/buff/buff.iff");
|
||||
int rows = buffTable.getRowCount();
|
||||
|
||||
buffMap.clear();
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
BuffData buff = new BuffData(buffTable.getString(row, "NAME"), buffTable.getString(row, "GROUP1"), buffTable.getInt(row, "PRIORITY"));
|
||||
buff.setMaxStackCount(buffTable.getInt(row, "MAX_STACKS"));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
buff.setEffectName(i, buffTable.getString(row, "EFFECT"+(i+1)+"_PARAM"));
|
||||
buff.setEffectValue(i, buffTable.getFloat(row, "EFFECT"+(i+1)+"_VALUE"));
|
||||
}
|
||||
buff.setDefaultDuration(buffTable.getFloat(row, "DURATION"));
|
||||
buff.setEffectFileName(buffTable.getString(row, "PARTICLE"));
|
||||
buff.setParticleHardPoint(buffTable.getString(row, "PARTICLE_HARDPOINT"));
|
||||
buff.setStanceParticle(buffTable.getString(row, "STANCE_PARTICLE"));
|
||||
buff.setCallback(buffTable.getString(row, "CALLBACK"));
|
||||
buff.setPersistent(buffTable.getInt(row, "IS_PERSISTENT") == 1);
|
||||
buff.setRemovedOnDeath(buffTable.getInt(row, "REMOVE_ON_DEATH") == 1);
|
||||
buff.setDecayOnPvpDeath(buffTable.getInt(row, "DECAY_ON_PVP_DEATH") == 1);
|
||||
buffMap.put(buff.getCrc(), buff);
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return buffMap.size();
|
||||
}
|
||||
|
||||
public BuffData getBuff(int crc) {
|
||||
return buffMap.get(crc);
|
||||
}
|
||||
|
||||
public BuffData getBuff(CRC crc) {
|
||||
return getBuff(crc.getCrc());
|
||||
}
|
||||
|
||||
public BuffData getBuff(String name) {
|
||||
return getBuff(getCrc(name));
|
||||
}
|
||||
|
||||
public boolean containsBuff(int crc) {
|
||||
return buffMap.containsKey(crc);
|
||||
}
|
||||
|
||||
public boolean containsBuff(String name) {
|
||||
return containsBuff(getCrc(name));
|
||||
}
|
||||
|
||||
private int getCrc(String name) {
|
||||
return CRC.getCrc(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
}
|
||||
+3
-51
@@ -31,8 +31,6 @@ import com.projectswg.common.data.encodables.oob.StringId;
|
||||
import com.projectswg.common.data.info.Config;
|
||||
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.DatatableData;
|
||||
import com.projectswg.holocore.intents.support.global.chat.SystemMessageIntent;
|
||||
import com.projectswg.holocore.intents.support.objects.swg.DestroyObjectIntent;
|
||||
import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent;
|
||||
@@ -41,6 +39,7 @@ 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.SdbLoader;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
|
||||
import com.projectswg.holocore.resources.support.global.player.Player;
|
||||
import com.projectswg.holocore.resources.support.objects.SpecificObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
|
||||
@@ -60,16 +59,13 @@ public class TravelHelper {
|
||||
|
||||
private final Map<String, TravelGroup> travel;
|
||||
private final ThreadPool travelExecutor;
|
||||
private final AllowedRouteManager routeManager;
|
||||
private final TravelPointManager pointManager;
|
||||
|
||||
public TravelHelper() {
|
||||
this.travel = new ConcurrentHashMap<>();
|
||||
this.travelExecutor = new ThreadPool(3, "travel-shuttles-%d");
|
||||
this.routeManager = new AllowedRouteManager();
|
||||
this.pointManager = new TravelPointManager();
|
||||
|
||||
loadAllowedRoutesAndPrices();
|
||||
createGalaxyTravels();
|
||||
loadTravelPoints();
|
||||
}
|
||||
@@ -89,11 +85,11 @@ public class TravelHelper {
|
||||
}
|
||||
|
||||
public boolean isValidRoute(Terrain departure, Terrain destination) {
|
||||
return routeManager.isRouteAvailable(departure, destination);
|
||||
return getTravelFee(departure, destination) != 0;
|
||||
}
|
||||
|
||||
public int getTravelFee(Terrain departure, Terrain destination) {
|
||||
return routeManager.getRouteFee(departure, destination);
|
||||
return DataLoader.travelCosts().getCost(departure, destination);
|
||||
}
|
||||
|
||||
public TravelGroup getTravelGroup(String template) {
|
||||
@@ -191,25 +187,6 @@ public class TravelHelper {
|
||||
traveler.moveToContainer(destination.getCollector().getParent(), destination.getLocation());
|
||||
}
|
||||
|
||||
private void loadAllowedRoutesAndPrices() {
|
||||
DatatableData travelFeeTable = (DatatableData) ClientFactory.getInfoFromFile("datatables/travel/travel.iff");
|
||||
// Sets up the travelPlanets array to be in the order of the datatable
|
||||
Terrain [] travelPlanets = new Terrain[travelFeeTable.getRowCount()];
|
||||
travelFeeTable.handleRows(currentRow -> travelPlanets[currentRow] = Terrain.getTerrainFromName((String) travelFeeTable.getCell(currentRow, "Planet")));
|
||||
|
||||
for (int rowIndex = 0; rowIndex < travelPlanets.length; rowIndex++) {
|
||||
for (int columnIndex = rowIndex; columnIndex < travelPlanets.length; columnIndex++) {
|
||||
int price = (int) travelFeeTable.getCell(rowIndex, columnIndex+1);
|
||||
|
||||
if (price <= 0) // If price is below or equal to 0 then this is an invalid route and isn't an option.
|
||||
continue;
|
||||
|
||||
routeManager.addRoute(travelPlanets[rowIndex], travelPlanets[columnIndex], price);
|
||||
routeManager.addRoute(travelPlanets[columnIndex], travelPlanets[rowIndex], price);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createGalaxyTravels() {
|
||||
Config config = DataManager.getConfig(ConfigFile.FEATURES);
|
||||
long groundTime = config.getInt("SHUTTLE-GROUND-TIME", 120);
|
||||
@@ -266,29 +243,4 @@ public class TravelHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private static class AllowedRouteManager {
|
||||
|
||||
private final Map<Terrain, Map<Terrain, Integer>> routeCosts;
|
||||
|
||||
public AllowedRouteManager() {
|
||||
this.routeCosts = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public void addRoute(Terrain departure, Terrain destination, int fee) {
|
||||
Map<Terrain, Integer> departureCosts = routeCosts.computeIfAbsent(departure, k -> new ConcurrentHashMap<>());
|
||||
departureCosts.put(destination, fee);
|
||||
}
|
||||
|
||||
public boolean isRouteAvailable(Terrain departure, Terrain destination) {
|
||||
return routeCosts.get(departure) != null && routeCosts.get(departure).get(destination) != null;
|
||||
}
|
||||
|
||||
public int getRouteFee(Terrain departure, Terrain destination) {
|
||||
Integer fee = routeCosts.get(departure).get(destination);
|
||||
if (fee == null)
|
||||
return 0;
|
||||
return fee;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -62,14 +62,14 @@ public class InstanceLocation implements Persistable, MongoPersistable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(MongoData data) {
|
||||
public void readMongo(MongoData data) {
|
||||
instanceNumber = data.getInteger("number", 0);
|
||||
instanceType = InstanceType.valueOf(data.getString("type", "NONE"));
|
||||
location = data.getDocument("location", new Location());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(MongoData data) {
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putInteger("number", instanceNumber);
|
||||
data.putString("type", instanceType.name());
|
||||
data.putDocument("location", location);
|
||||
|
||||
+6
-2
@@ -39,8 +39,12 @@ public class SWGObjectFactory {
|
||||
obj.save(stream);
|
||||
}
|
||||
|
||||
public static MongoData save(SWGObject obj) {
|
||||
return save(obj, new MongoData());
|
||||
}
|
||||
|
||||
public static MongoData save(SWGObject obj, MongoData data) {
|
||||
obj.save(data);
|
||||
obj.saveMongo(data);
|
||||
assert data.containsKey("id") : "serialized MongoData does not contain the objectId";
|
||||
assert data.containsKey("template") : "serialized MongoData does not contain the template";
|
||||
return data;
|
||||
@@ -60,7 +64,7 @@ public class SWGObjectFactory {
|
||||
assert objectId != 0 : "objectId is not defined in MongoData";
|
||||
assert template != null : "template is not defined in MongoData";
|
||||
SWGObject obj = ObjectCreator.createObjectFromTemplate(objectId, template);
|
||||
obj.read(data);
|
||||
obj.readMongo(data);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
/***********************************************************************************
|
||||
* 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.loader;
|
||||
|
||||
import com.projectswg.common.data.CRC;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.SdbColumnArraySet.SdbRealColumnArraySet;
|
||||
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 org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public final class BuffLoader extends DataLoader {
|
||||
|
||||
private final Map<Integer, BuffInfo> buffsByCrc;
|
||||
private final Map<String, BuffInfo> buffsByName;
|
||||
|
||||
BuffLoader() {
|
||||
this.buffsByCrc = new HashMap<>();
|
||||
this.buffsByName = new HashMap<>();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BuffInfo getBuff(int crc) {
|
||||
return buffsByCrc.get(crc);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BuffInfo getBuff(CRC crc) {
|
||||
return getBuff(crc.getCrc());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BuffInfo getBuff(String name) {
|
||||
return buffsByName.get(name.toLowerCase(Locale.US));
|
||||
}
|
||||
|
||||
public boolean containsBuff(int crc) {
|
||||
return buffsByCrc.containsKey(crc);
|
||||
}
|
||||
|
||||
public boolean containsBuff(String name) {
|
||||
return buffsByName.containsKey(name.toLowerCase(Locale.US));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void load() throws IOException {
|
||||
try (SdbResultSet set = SdbLoader.load(new File("serverdata/buff/buff.sdb"))) {
|
||||
SdbTextColumnArraySet effectParams = set.getTextArrayParser("effect([0-9]+)_param");
|
||||
SdbRealColumnArraySet effectValues = set.getRealArrayParser("effect([0-9]+)_value");
|
||||
while (set.next()) {
|
||||
BuffInfo buff = new BuffInfo(set, effectParams, effectValues);
|
||||
buffsByCrc.put(buff.getCrc(), buff);
|
||||
buffsByName.put(buff.getName(), buff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class BuffInfo {
|
||||
|
||||
private final String name;
|
||||
private final int crc;
|
||||
private final String group1;
|
||||
private final String group2;
|
||||
private final String block;
|
||||
private final int priority;
|
||||
private final String icon;
|
||||
private final double duration;
|
||||
private final String [] effectNames;
|
||||
private final double [] effectValues;
|
||||
private final String state;
|
||||
private final String callback;
|
||||
private final String particle;
|
||||
private final String particleHardpoint;
|
||||
private final int visible;
|
||||
private final boolean debuff;
|
||||
private final String stanceParticle;
|
||||
private final boolean dispellPlayer;
|
||||
private final boolean removeOnDeath;
|
||||
private final boolean playerRemovable;
|
||||
private final boolean celestial;
|
||||
private final int maxStackCount;
|
||||
private final boolean persistent;
|
||||
private final boolean displayOrder;
|
||||
private final boolean removeOnRespec;
|
||||
private final boolean aiRemoveOnCombatEnd;
|
||||
private final boolean decayOnPvpDeath;
|
||||
|
||||
public BuffInfo(SdbResultSet set, SdbTextColumnArraySet effectNames, SdbRealColumnArraySet effectValues) {
|
||||
this.name = set.getText("name").toLowerCase(Locale.US);
|
||||
this.crc = CRC.getCrc(this.name);
|
||||
this.group1 = set.getText("group1");
|
||||
this.group2 = set.getText("group2");
|
||||
this.block = set.getText("block");
|
||||
this.priority = (int) set.getInt("priority");
|
||||
this.icon = set.getText("icon");
|
||||
this.duration = set.getReal("duration");
|
||||
this.effectNames = effectNames.getArray().clone();
|
||||
this.effectValues = effectValues.getArray().clone();
|
||||
this.state = set.getText("state");
|
||||
this.callback = set.getText("callback");
|
||||
this.particle = set.getText("particle");
|
||||
this.particleHardpoint = set.getText("particle_hardpoint");
|
||||
this.visible = (int) set.getInt("visible");
|
||||
this.debuff = set.getBoolean("debuff");
|
||||
this.stanceParticle = set.getText("stance_particle");
|
||||
this.dispellPlayer = set.getInt("dispell_player") != 0;
|
||||
this.removeOnDeath = set.getInt("remove_on_death") != 0;
|
||||
this.playerRemovable = set.getInt("player_removable") != 0;
|
||||
this.celestial = set.getInt("is_celestial") != 0;
|
||||
this.maxStackCount = (int) set.getInt("max_stacks");
|
||||
this.persistent = set.getInt("is_persistent") != 0;
|
||||
this.displayOrder = set.getInt("display_order") != 0;
|
||||
this.removeOnRespec = set.getInt("remove_on_respec") != 0;
|
||||
this.aiRemoveOnCombatEnd = set.getInt("ai_remove_on_combat_end") != 0;
|
||||
this.decayOnPvpDeath = set.getInt("decay_on_pvp_death") != 0;
|
||||
|
||||
assert this.effectNames.length == this.effectValues.length : "effect params and effect values differ in size";
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getCrc() {
|
||||
return crc;
|
||||
}
|
||||
|
||||
public String getGroup1() {
|
||||
return group1;
|
||||
}
|
||||
|
||||
public String getGroup2() {
|
||||
return group2;
|
||||
}
|
||||
|
||||
public String getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public double getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public String[] getEffectNames() {
|
||||
return effectNames.clone();
|
||||
}
|
||||
|
||||
public String getEffectName(int index) {
|
||||
return effectNames[index];
|
||||
}
|
||||
|
||||
public double[] getEffectValues() {
|
||||
return effectValues.clone();
|
||||
}
|
||||
|
||||
public double getEffectValue(int index) {
|
||||
return effectValues[index];
|
||||
}
|
||||
|
||||
public int getEffects() {
|
||||
return effectNames.length;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public String getCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public String getParticle() {
|
||||
return particle;
|
||||
}
|
||||
|
||||
public String getParticleHardpoint() {
|
||||
return particleHardpoint;
|
||||
}
|
||||
|
||||
public int getVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public boolean isDebuff() {
|
||||
return debuff;
|
||||
}
|
||||
|
||||
public String getStanceParticle() {
|
||||
return stanceParticle;
|
||||
}
|
||||
|
||||
public boolean isDispellPlayer() {
|
||||
return dispellPlayer;
|
||||
}
|
||||
|
||||
public boolean isRemoveOnDeath() {
|
||||
return removeOnDeath;
|
||||
}
|
||||
|
||||
public boolean isPlayerRemovable() {
|
||||
return playerRemovable;
|
||||
}
|
||||
|
||||
public boolean isCelestial() {
|
||||
return celestial;
|
||||
}
|
||||
|
||||
public int getMaxStackCount() {
|
||||
return maxStackCount;
|
||||
}
|
||||
|
||||
public boolean isPersistent() {
|
||||
return persistent;
|
||||
}
|
||||
|
||||
public boolean isDisplayOrder() {
|
||||
return displayOrder;
|
||||
}
|
||||
|
||||
public boolean isRemoveOnRespec() {
|
||||
return removeOnRespec;
|
||||
}
|
||||
|
||||
public boolean isAiRemoveOnCombatEnd() {
|
||||
return aiRemoveOnCombatEnd;
|
||||
}
|
||||
|
||||
public boolean isDecayOnPvpDeath() {
|
||||
return decayOnPvpDeath;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -8,6 +8,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
enum CachedLoader {
|
||||
BUFFS (BuffLoader::new),
|
||||
BUILDING_CELLS (BuildingCellLoader::new),
|
||||
NPC_LOADER (NpcLoader::new),
|
||||
NPC_COMBAT_PROFILES (NpcCombatProfileLoader::new),
|
||||
@@ -17,10 +18,12 @@ enum CachedLoader {
|
||||
NPC_WEAPON_RANGES (NpcWeaponRangeLoader::new),
|
||||
STATIC_SPAWNS (NpcStaticSpawnLoader::new),
|
||||
OBJECT_DATA (ObjectDataLoader::new),
|
||||
PERFORMANCES (PerformanceLoader::new),
|
||||
COMMANDS (CommandLoader::new),
|
||||
SLOT_DEFINITIONS (SlotDefinitionLoader::new),
|
||||
ZONE_INSERTIONS (TerrainZoneInsertionLoader::new),
|
||||
VEHICLES (VehicleLoader::new);
|
||||
VEHICLES (VehicleLoader::new),
|
||||
TRAVEL_COSTS (TravelCostLoader::new);
|
||||
|
||||
private final AtomicReference<SoftReference<DataLoader>> cachedLoader;
|
||||
private final Supplier<DataLoader> supplier;
|
||||
|
||||
+12
@@ -18,6 +18,10 @@ public abstract class DataLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public static BuffLoader buffs() {
|
||||
return (BuffLoader) CachedLoader.BUFFS.load();
|
||||
}
|
||||
|
||||
public static BuildoutLoader buildouts() {
|
||||
return BuildoutLoader.load(List.of());
|
||||
}
|
||||
@@ -66,6 +70,10 @@ public abstract class DataLoader {
|
||||
return (ObjectDataLoader) CachedLoader.OBJECT_DATA.load();
|
||||
}
|
||||
|
||||
public static PerformanceLoader performances() {
|
||||
return (PerformanceLoader) CachedLoader.PERFORMANCES.load();
|
||||
}
|
||||
|
||||
public static CommandLoader commands() {
|
||||
return (CommandLoader) CachedLoader.COMMANDS.load();
|
||||
}
|
||||
@@ -78,6 +86,10 @@ public abstract class DataLoader {
|
||||
return (TerrainZoneInsertionLoader) CachedLoader.ZONE_INSERTIONS.load();
|
||||
}
|
||||
|
||||
public static TravelCostLoader travelCosts() {
|
||||
return (TravelCostLoader) CachedLoader.TRAVEL_COSTS.load();
|
||||
}
|
||||
|
||||
public static VehicleLoader vehicles() {
|
||||
return (VehicleLoader) CachedLoader.VEHICLES.load();
|
||||
}
|
||||
|
||||
+5
-4
@@ -35,10 +35,7 @@ import me.joshlarson.jlcommon.log.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
public final class ObjectDataLoader extends DataLoader {
|
||||
|
||||
@@ -52,6 +49,10 @@ public final class ObjectDataLoader extends DataLoader {
|
||||
return attributes.get(iff);
|
||||
}
|
||||
|
||||
public Collection<String> getObjects() {
|
||||
return Collections.unmodifiableCollection(attributes.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() throws IOException {
|
||||
try (SdbResultSet set = SdbLoader.load(new File("serverdata/objects/object_data.sdb"))) {
|
||||
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
/***********************************************************************************
|
||||
* 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.loader;
|
||||
|
||||
import com.projectswg.common.data.CRC;
|
||||
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 org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class PerformanceLoader extends DataLoader {
|
||||
|
||||
private final Map<String, PerformanceInfo> nameMap;
|
||||
private final Map<Integer, PerformanceInfo> danceMap;
|
||||
|
||||
PerformanceLoader() {
|
||||
this.nameMap = new HashMap<>();
|
||||
this.danceMap = new HashMap<>();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PerformanceInfo getPerformanceByName(String performanceName) {
|
||||
return nameMap.get(performanceName);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PerformanceInfo getPerformanceByDanceId(int danceVisualId) {
|
||||
return danceMap.get(danceVisualId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void load() throws IOException {
|
||||
try (SdbResultSet set = SdbLoader.load(new File("serverdata/performance/performance.sdb"))) {
|
||||
SdbTextColumnArraySet flourishes = set.getTextArrayParser("flourish(%d+)");
|
||||
while (set.next()) {
|
||||
PerformanceInfo performance = new PerformanceInfo(set, flourishes);
|
||||
nameMap.put(performance.getPerformanceName(), performance);
|
||||
danceMap.put(performance.getDanceVisualId(), performance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class PerformanceInfo {
|
||||
|
||||
private final String performanceName;
|
||||
private final int instrumentAudioId;
|
||||
private final String requiredSong;
|
||||
private final String requiredInstrument;
|
||||
private final String requiredDance;
|
||||
private final int danceVisualId;
|
||||
private final int actionPointsPerLoop;
|
||||
private final double loopDuration;
|
||||
private final CRC type;
|
||||
private final int baseXp;
|
||||
private final int flourishXpMod;
|
||||
private final int healMindWound;
|
||||
private final int healShockWound;
|
||||
private final String requiredSkillMod;
|
||||
private final int requiredSkillModValue;
|
||||
private final String mainloop;
|
||||
private final String [] flourishes;
|
||||
private final String intro;
|
||||
private final String outro;
|
||||
|
||||
public PerformanceInfo(SdbResultSet set, SdbTextColumnArraySet flourishes) {
|
||||
this.performanceName = set.getText("performance_name");
|
||||
this.instrumentAudioId = (int) set.getInt("instrument_audio_id");
|
||||
this.requiredSong = set.getText("required_song");
|
||||
this.requiredInstrument = set.getText("required_instrument");
|
||||
this.requiredDance = set.getText("required_dance");
|
||||
this.danceVisualId = (int) set.getInt("dance_visual_id");
|
||||
this.actionPointsPerLoop = (int) set.getInt("action_points_per_loop");
|
||||
this.loopDuration = set.getReal("loop_duration");
|
||||
this.type = new CRC((int) set.getInt("type"));
|
||||
this.baseXp = (int) set.getInt("base_xp");
|
||||
this.flourishXpMod = (int) set.getInt("flourish_xp_mod");
|
||||
this.healMindWound = (int) set.getInt("heal_mind_wound");
|
||||
this.healShockWound = (int) set.getInt("heal_shock_wound");
|
||||
this.requiredSkillMod = set.getText("required_skill_mod");
|
||||
this.requiredSkillModValue = (int) set.getInt("required_skill_mod_value");
|
||||
this.mainloop = set.getText("mainloop");
|
||||
this.flourishes = flourishes.getArray().clone();
|
||||
this.intro = set.getText("intro");
|
||||
this.outro = set.getText("outro");
|
||||
}
|
||||
|
||||
public String getPerformanceName() {
|
||||
return performanceName;
|
||||
}
|
||||
|
||||
public int getInstrumentAudioId() {
|
||||
return instrumentAudioId;
|
||||
}
|
||||
|
||||
public String getRequiredSong() {
|
||||
return requiredSong;
|
||||
}
|
||||
|
||||
public String getRequiredInstrument() {
|
||||
return requiredInstrument;
|
||||
}
|
||||
|
||||
public String getRequiredDance() {
|
||||
return requiredDance;
|
||||
}
|
||||
|
||||
public int getDanceVisualId() {
|
||||
return danceVisualId;
|
||||
}
|
||||
|
||||
public int getActionPointsPerLoop() {
|
||||
return actionPointsPerLoop;
|
||||
}
|
||||
|
||||
public double getLoopDuration() {
|
||||
return loopDuration;
|
||||
}
|
||||
|
||||
public CRC getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getBaseXp() {
|
||||
return baseXp;
|
||||
}
|
||||
|
||||
public int getFlourishXpMod() {
|
||||
return flourishXpMod;
|
||||
}
|
||||
|
||||
public int getHealMindWound() {
|
||||
return healMindWound;
|
||||
}
|
||||
|
||||
public int getHealShockWound() {
|
||||
return healShockWound;
|
||||
}
|
||||
|
||||
public String getRequiredSkillMod() {
|
||||
return requiredSkillMod;
|
||||
}
|
||||
|
||||
public int getRequiredSkillModValue() {
|
||||
return requiredSkillModValue;
|
||||
}
|
||||
|
||||
public String getMainloop() {
|
||||
return mainloop;
|
||||
}
|
||||
|
||||
public String[] getFlourishes() {
|
||||
return flourishes.clone();
|
||||
}
|
||||
|
||||
public String getIntro() {
|
||||
return intro;
|
||||
}
|
||||
|
||||
public String getOutro() {
|
||||
return outro;
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
-42
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
|
||||
* 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. *
|
||||
@@ -25,59 +25,74 @@
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
|
||||
package com.projectswg.utility.packets;
|
||||
package com.projectswg.holocore.resources.support.data.server_info.loader;
|
||||
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.common.network.packets.PacketType;
|
||||
import com.projectswg.common.network.packets.SWGPacket;
|
||||
import com.projectswg.common.network.packets.swg.zone.object_controller.ObjectController;
|
||||
import com.projectswg.common.data.location.Terrain;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PacketRecord {
|
||||
public final class TravelCostLoader extends DataLoader {
|
||||
|
||||
private final boolean server;
|
||||
private final Instant time;
|
||||
private final byte[] data;
|
||||
private final Map<Terrain, Map<Terrain, Integer>> costs;
|
||||
|
||||
public PacketRecord(boolean server, Instant time, byte[] data) {
|
||||
this.server = server;
|
||||
this.time = time;
|
||||
this.data = data;
|
||||
TravelCostLoader() {
|
||||
this.costs = new EnumMap<>(Terrain.class);
|
||||
}
|
||||
|
||||
public boolean isServer() {
|
||||
return server;
|
||||
public boolean isCostDefined(Terrain source) {
|
||||
return costs.containsKey(source);
|
||||
}
|
||||
|
||||
public Instant getTime() {
|
||||
return time;
|
||||
public int getCost(Terrain source, Terrain destination) {
|
||||
Map<Terrain, Integer> costMap = costs.get(source);
|
||||
if (costMap == null)
|
||||
return 0;
|
||||
return costMap.getOrDefault(destination, 0);
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public PacketType parseType() {
|
||||
NetBuffer data = NetBuffer.wrap(this.data);
|
||||
data.position(2);
|
||||
return PacketType.fromCrc(data.getInt());
|
||||
}
|
||||
|
||||
public SWGPacket parse() {
|
||||
NetBuffer data = NetBuffer.wrap(this.data);
|
||||
data.position(2);
|
||||
PacketType type = PacketType.fromCrc(data.getInt());
|
||||
data.position(0);
|
||||
SWGPacket packet;
|
||||
if (type == PacketType.OBJECT_CONTROLLER) {
|
||||
return ObjectController.decodeController(data);
|
||||
} else {
|
||||
packet = PacketType.getForCrc(type.getCrc());
|
||||
if (packet != null)
|
||||
packet.decode(data);
|
||||
return packet;
|
||||
@Override
|
||||
public final void load() throws IOException {
|
||||
try (SdbResultSet set = SdbLoader.load(new File("serverdata/travel/travel_costs.sdb"))) {
|
||||
while (set.next()) {
|
||||
TravelCostInfo travel = new TravelCostInfo(set);
|
||||
costs.put(travel.getPlanet(), travel.getCosts());
|
||||
}
|
||||
}
|
||||
for (Terrain key : costs.keySet()) {
|
||||
for (Map<Terrain, Integer> costMap : costs.values()) {
|
||||
assert costMap.keySet().equals(costs.keySet()) : "planet "+key+" is improperly defined in travel_costs.sdb";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class TravelCostInfo {
|
||||
|
||||
private final Terrain planet;
|
||||
private final EnumMap<Terrain, Integer> costs;
|
||||
|
||||
public TravelCostInfo(SdbResultSet set) {
|
||||
this.planet = Terrain.getTerrainFromName(set.getText("planet"));
|
||||
this.costs = new EnumMap<>(Terrain.class);
|
||||
for (String col : set.getColumns()) {
|
||||
if (col.equalsIgnoreCase("planet"))
|
||||
continue;
|
||||
costs.put(Terrain.getTerrainFromName(col), (int) set.getInt(col));
|
||||
}
|
||||
}
|
||||
|
||||
public Terrain getPlanet() {
|
||||
return planet;
|
||||
}
|
||||
|
||||
public Map<Terrain, Integer> getCosts() {
|
||||
return Collections.unmodifiableMap(costs);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -93,7 +93,8 @@ public class FindFriendCallback implements ICmdCallback {
|
||||
waypoint.setPosition(location.getTerrain(), location.getX(), location.getY(), location.getZ());
|
||||
waypoint.setColor(WaypointColor.PURPLE);
|
||||
waypoint.setName(friendName);
|
||||
ghost.addWaypoint(waypoint);
|
||||
if (!ghost.addWaypoint(waypoint))
|
||||
SystemMessageIntent.broadcastPersonal(player, "@base_player:too_many_waypoints");
|
||||
new ObjectCreatedIntent(waypoint).broadcast();
|
||||
new SystemMessageIntent(player, new ProsePackage(new StringId("ui_cmnty", "friend_location_create_new_wp"), "TU", friendName)).broadcast();
|
||||
} else {
|
||||
|
||||
+2
-1
@@ -65,7 +65,8 @@ public class RequestWaypointCmdCallback implements ICmdCallback {
|
||||
waypoint.setPosition(terrain, position.getX(), position.getY(), position.getZ());
|
||||
waypoint.setName(name);
|
||||
waypoint.setColor(color);
|
||||
player.getPlayerObject().addWaypoint(waypoint);
|
||||
if (!player.getPlayerObject().addWaypoint(waypoint))
|
||||
SystemMessageIntent.broadcastPersonal(player, "@base_player:too_many_waypoints");
|
||||
ObjectCreatedIntent.broadcast(waypoint);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -166,7 +166,8 @@ public class WaypointCmdCallback implements ICmdCallback {
|
||||
if (name == null || name.isEmpty())
|
||||
name = "Waypoint";
|
||||
|
||||
ghost.addWaypoint(createWaypoint(color, name, location.build()));
|
||||
if (!ghost.addWaypoint(createWaypoint(color, name, location.build())))
|
||||
SystemMessageIntent.broadcastPersonal(player, "@base_player:too_many_waypoints");
|
||||
|
||||
if (differentPlanetMessage) {
|
||||
new SystemMessageIntent(player, "Waypoint: New waypoint \""+ name + "\" created for location "
|
||||
|
||||
-20
@@ -75,9 +75,6 @@ public class BaselineObject {
|
||||
case 6:
|
||||
parseBaseline6(buffer);
|
||||
break;
|
||||
case 7:
|
||||
parseBaseline7(buffer);
|
||||
break;
|
||||
case 8:
|
||||
parseBaseline8(buffer);
|
||||
break;
|
||||
@@ -107,10 +104,6 @@ public class BaselineObject {
|
||||
return createBaseline(target, 6, this::createBaseline6);
|
||||
}
|
||||
|
||||
public Baseline createBaseline7(Player target) {
|
||||
return createBaseline(target, 7, this::createBaseline7);
|
||||
}
|
||||
|
||||
public Baseline createBaseline8(Player target) {
|
||||
return createBaseline(target, 8, this::createBaseline8);
|
||||
}
|
||||
@@ -155,15 +148,6 @@ public class BaselineObject {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the seventh baseline for the specified target. This baseline is sent when the object is used.
|
||||
* @param target the target to prepare the baseline for
|
||||
* @param data the baseline to build
|
||||
*/
|
||||
protected void createBaseline7(Player target, BaselineBuilder data) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the eighth baseline for the specified target. Only sent if the target has some permissions.
|
||||
* @param target the target to prepare the baseline for
|
||||
@@ -198,10 +182,6 @@ public class BaselineObject {
|
||||
|
||||
}
|
||||
|
||||
protected void parseBaseline7(NetBuffer buffer) {
|
||||
|
||||
}
|
||||
|
||||
protected void parseBaseline8(NetBuffer buffer) {
|
||||
|
||||
}
|
||||
|
||||
+47
-9
@@ -26,23 +26,43 @@
|
||||
***********************************************************************************/
|
||||
package com.projectswg.holocore.resources.support.global.player;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
public enum PlayerFlags {
|
||||
/** Marks as Looking for a Group */
|
||||
LFG (0),
|
||||
LFG (0),
|
||||
/** Marks as Helper */
|
||||
HELPER (1),
|
||||
HELPER (1),
|
||||
/** Marks as Roleplayer */
|
||||
ROLEPLAYER (2),
|
||||
ROLEPLAYER (2),
|
||||
/** - */
|
||||
FACTION (3),
|
||||
/** - */
|
||||
SPECIES (4),
|
||||
/** - */
|
||||
TITLE (5),
|
||||
/** - */
|
||||
FRIEND (6),
|
||||
/** Away from Keyboard */
|
||||
AFK (7),
|
||||
/** Logged Out */
|
||||
LD (8),
|
||||
AFK (7),
|
||||
/** Logged Out / Link Dead */
|
||||
LD (8),
|
||||
/** Display the Faction Rank */
|
||||
FACTIONRANK (9),
|
||||
FACTIONRANK (9),
|
||||
/** Display the player's location in the matchmaking search */
|
||||
DISPLAY_LOCATION_IN_SEARCH (10),
|
||||
/** Marks as Out of Character */
|
||||
OOC (11),
|
||||
OOC (11),
|
||||
/** - */
|
||||
SEARCH_BY_SOURCE_GALAXY (12),
|
||||
/** Marks as Looking for Work */
|
||||
LFW (13);
|
||||
LFW (13),
|
||||
/** - */
|
||||
ANONYMOUS (127);
|
||||
|
||||
private static final PlayerFlags [] FLAGS = values();
|
||||
|
||||
private int flag;
|
||||
|
||||
@@ -53,4 +73,22 @@ public enum PlayerFlags {
|
||||
public int getFlag() {
|
||||
return flag;
|
||||
}
|
||||
|
||||
public static BitSet bitsetFromFlags(Set<PlayerFlags> flags) {
|
||||
BitSet ret = new BitSet(128);
|
||||
for (PlayerFlags flag : flags) {
|
||||
ret.set(flag.flag);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Set<PlayerFlags> flagsFromBitset(BitSet bitset) {
|
||||
Set<PlayerFlags> ret = EnumSet.noneOf(PlayerFlags.class);
|
||||
for (PlayerFlags flag : FLAGS) {
|
||||
if (bitset.get(flag.flag))
|
||||
ret.add(flag);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -50,7 +50,7 @@ import com.projectswg.holocore.services.support.objects.ObjectStorageService.Bui
|
||||
import me.joshlarson.jlcommon.utilities.Arguments;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.time.Instant;
|
||||
|
||||
public class CharacterCreation {
|
||||
|
||||
@@ -165,8 +165,7 @@ public class CharacterCreation {
|
||||
|
||||
private void setPlayerObjectValues(PlayerObject playerObj) {
|
||||
playerObj.setProfession(create.getProfession());
|
||||
Calendar date = Calendar.getInstance();
|
||||
playerObj.setBornDate(date.get(Calendar.YEAR), date.get(Calendar.MONTH) + 1, date.get(Calendar.DAY_OF_MONTH));
|
||||
playerObj.setBornDate(Instant.now());
|
||||
}
|
||||
|
||||
private void createStarterClothing(CreatureObject creature, String race) {
|
||||
|
||||
+2
-2
@@ -74,12 +74,12 @@ public final class AdminPermissions implements ContainerPermissions {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(MongoData data) {
|
||||
public void readMongo(MongoData data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(MongoData data) {
|
||||
public void saveMongo(MongoData data) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ public interface ContainerPermissions extends Persistable, MongoPersistable {
|
||||
|
||||
static MongoData save(MongoData data, ContainerPermissions permissions) {
|
||||
data.putString("type", permissions.getType().name());
|
||||
permissions.save(data);
|
||||
permissions.saveMongo(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -86,12 +86,12 @@ public final class DefaultPermissions implements ContainerPermissions {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(MongoData data) {
|
||||
public void readMongo(MongoData data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(MongoData data) {
|
||||
public void saveMongo(MongoData data) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -64,7 +64,7 @@ public final class ReadOnlyPermissions implements ContainerPermissions {
|
||||
private ReadOnlyPermissions(MongoData data) {
|
||||
this.exempt = new HashSet<>();
|
||||
this.locked = false;
|
||||
read(data);
|
||||
readMongo(data);
|
||||
this.locked = true;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ public final class ReadOnlyPermissions implements ContainerPermissions {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(MongoData data) {
|
||||
public void readMongo(MongoData data) {
|
||||
if (locked)
|
||||
throw new IllegalStateException("Permissions is already locked");
|
||||
for (long id : data.getArray("exempt", Long.class))
|
||||
@@ -116,7 +116,7 @@ public final class ReadOnlyPermissions implements ContainerPermissions {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(MongoData data) {
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putArray("exempt", exempt.stream().map(SWGObject::getObjectId).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -68,7 +68,7 @@ public final class ReadWritePermissions implements ContainerPermissions {
|
||||
private ReadWritePermissions(MongoData data) {
|
||||
this.allowed = new HashSet<>();
|
||||
this.locked = false;
|
||||
read(data);
|
||||
readMongo(data);
|
||||
this.locked = true;
|
||||
}
|
||||
|
||||
@@ -112,14 +112,14 @@ public final class ReadWritePermissions implements ContainerPermissions {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(MongoData data) {
|
||||
public void readMongo(MongoData data) {
|
||||
if (locked)
|
||||
throw new IllegalStateException("Permissions is already locked");
|
||||
allowed.addAll(data.getArray("allowed", Long.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(MongoData data) {
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putArray("allowed", new ArrayList<>(allowed));
|
||||
}
|
||||
|
||||
|
||||
+24
-14
@@ -11,6 +11,7 @@ import com.projectswg.holocore.resources.support.global.zone.sui.SuiWindow;
|
||||
import com.projectswg.holocore.resources.support.objects.radial.RadialHandlerInterface;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.player.PlayerObject;
|
||||
import com.projectswg.holocore.utilities.IntentFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -27,6 +28,7 @@ public class TerminalBankRadial implements RadialHandlerInterface {
|
||||
@Override
|
||||
public void getOptions(Collection<RadialOption> options, Player player, SWGObject target) {
|
||||
CreatureObject creature = player.getCreatureObject();
|
||||
PlayerObject playerObject = player.getPlayerObject();
|
||||
|
||||
{
|
||||
List<RadialOption> useOptions = new ArrayList<>();
|
||||
@@ -47,7 +49,7 @@ public class TerminalBankRadial implements RadialHandlerInterface {
|
||||
List<RadialOption> reserveOptions = new ArrayList<>();
|
||||
if (creature.getBankBalance() >= 1E9 || creature.getCashBalance() >= 1E9)
|
||||
reserveOptions.add(RadialOption.create(RadialItem.SERVER_MENU49, "@sui:bank_galactic_reserve_deposit"));
|
||||
if (creature.getReserveBalance() > 0)
|
||||
if (playerObject != null && playerObject.getGalacticReserveDeposit() > 0)
|
||||
reserveOptions.add(RadialOption.create(RadialItem.SERVER_MENU48, "@sui:bank_galactic_reserve_withdraw"));
|
||||
|
||||
options.add(RadialOption.createSilent(RadialItem.SERVER_MENU50, "@sui:bank_galactic_reserve", reserveOptions));
|
||||
@@ -133,15 +135,19 @@ public class TerminalBankRadial implements RadialHandlerInterface {
|
||||
SystemMessageIntent.broadcastPersonal(player, "You have to wait to perform another Galactic Reserve transaction");
|
||||
return;
|
||||
}
|
||||
long amount = creature.getBankBalance();
|
||||
if (amount > 1E9)
|
||||
amount = (long) 1E9;
|
||||
if (creature.getReserveBalance() + amount > 3E9 || amount == 0) {
|
||||
PlayerObject playerObject = player.getPlayerObject();
|
||||
if (playerObject == null) {
|
||||
SystemMessageIntent.broadcastPersonal(player, "Internal server error with loading your player");
|
||||
return;
|
||||
}
|
||||
long updatedBank = creature.getBankBalance() - 1_000_000_000L;
|
||||
byte reserveBalance = playerObject.getGalacticReserveDeposit();
|
||||
if (reserveBalance >= 3 || updatedBank < 0) {
|
||||
SystemMessageIntent.broadcastPersonal(player, "@error_message:bank_deposit");
|
||||
return;
|
||||
}
|
||||
creature.setBankBalance((creature.getBankBalance() - amount));
|
||||
creature.setReserveBalance((creature.getReserveBalance() + amount));
|
||||
creature.setBankBalance(updatedBank);
|
||||
playerObject.setGalacticReserveDeposit((byte) (reserveBalance + 1));
|
||||
creature.updateLastGalacticReserveTime();
|
||||
}
|
||||
|
||||
@@ -150,15 +156,19 @@ public class TerminalBankRadial implements RadialHandlerInterface {
|
||||
SystemMessageIntent.broadcastPersonal(player, "You have to wait to perform another Galactic Reserve transaction");
|
||||
return;
|
||||
}
|
||||
long amount = creature.getReserveBalance();
|
||||
if (amount > 1E9)
|
||||
amount = (long) 1E9;
|
||||
if (creature.getBankBalance() + amount > 2E9 || amount == 0) {
|
||||
SystemMessageIntent.broadcastPersonal(player, "@error_message:bank_withdraw");
|
||||
PlayerObject playerObject = player.getPlayerObject();
|
||||
if (playerObject == null) {
|
||||
SystemMessageIntent.broadcastPersonal(player, "Internal server error with loading your player");
|
||||
return;
|
||||
}
|
||||
creature.setBankBalance(creature.getBankBalance() + amount);
|
||||
creature.setReserveBalance(creature.getReserveBalance() - amount);
|
||||
long updatedBank = creature.getBankBalance() + 1_000_000_000L;
|
||||
byte reserveBalance = playerObject.getGalacticReserveDeposit();
|
||||
if (reserveBalance <= 0 || updatedBank >= 2_000_000_000L) {
|
||||
SystemMessageIntent.broadcastPersonal(player, "@error_message:bank_deposit");
|
||||
return;
|
||||
}
|
||||
creature.setBankBalance(updatedBank);
|
||||
playerObject.setGalacticReserveDeposit((byte) (reserveBalance - 1));
|
||||
creature.updateLastGalacticReserveTime();
|
||||
}
|
||||
|
||||
|
||||
+30
-41
@@ -33,16 +33,15 @@ import com.projectswg.holocore.intents.gameplay.combat.CreatureKilledIntent;
|
||||
import com.projectswg.holocore.intents.gameplay.combat.buffs.BuffIntent;
|
||||
import com.projectswg.holocore.intents.gameplay.player.experience.skills.SkillModIntent;
|
||||
import com.projectswg.holocore.intents.support.global.zone.PlayerEventIntent;
|
||||
import com.projectswg.holocore.resources.gameplay.combat.buff.BuffData;
|
||||
import com.projectswg.holocore.resources.gameplay.combat.buff.BuffMap;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.StandardLog;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.BuffLoader.BuffInfo;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
|
||||
import com.projectswg.holocore.resources.support.global.player.Player;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.creature.Buff;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
|
||||
import me.joshlarson.jlcommon.concurrency.BasicScheduledThread;
|
||||
import me.joshlarson.jlcommon.control.IntentHandler;
|
||||
import me.joshlarson.jlcommon.control.Service;
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -52,8 +51,8 @@ import java.util.stream.Stream;
|
||||
public class BuffService extends Service {
|
||||
|
||||
/*
|
||||
* TODO allow removal of buffs with BuffData where PLAYER_REMOVABLE == 1
|
||||
* TODO remove buffs on respec. Listen for respec event and remove buffs with BuffData where
|
||||
* TODO allow removal of buffs with BuffInfo where PLAYER_REMOVABLE == 1
|
||||
* TODO remove buffs on respec. Listen for respec event and remove buffs with BuffInfo where
|
||||
* REMOVE_ON_RESPEC == 1
|
||||
* TODO remove group buff(s) from receiver when distance between caster and receiver is 100m.
|
||||
* Perform same check upon zoning in. Skillmod1 effect name is "group"
|
||||
@@ -61,20 +60,10 @@ public class BuffService extends Service {
|
||||
|
||||
private final BasicScheduledThread timerCheckThread;
|
||||
private final Set<CreatureObject> monitored;
|
||||
private final BuffMap dataMap; // All CRCs are lower-cased buff names!
|
||||
|
||||
public BuffService() {
|
||||
timerCheckThread = new BasicScheduledThread("buff-timer-check", this::checkBuffTimers);
|
||||
monitored = new HashSet<>();
|
||||
dataMap = new BuffMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean initialize() {
|
||||
long startTime = StandardLog.onStartLoad("buffs");
|
||||
dataMap.load();
|
||||
StandardLog.onEndLoad(dataMap.size(), "buffs", startTime);
|
||||
return super.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,9 +90,9 @@ public class BuffService extends Service {
|
||||
|
||||
@IntentHandler
|
||||
private void handleBuffIntent(BuffIntent bi) {
|
||||
BuffData buffData = getBuff(bi.getBuffName());
|
||||
BuffInfo buffData = getBuff(bi.getBuffName());
|
||||
Objects.requireNonNull(buffData, "No known buff: " + bi.getBuffName());
|
||||
assert buffData.getName().equals(bi.getBuffName()) : "BuffIntent name ["+bi.getBuffName()+"] does not match BuffData name ["+buffData.getName()+ ']';
|
||||
assert buffData.getName().equals(bi.getBuffName()) : "BuffIntent name ["+bi.getBuffName()+"] does not match BuffInfo name ["+buffData.getName()+ ']';
|
||||
if (bi.isRemove()) {
|
||||
removeBuff(bi.getReceiver(), buffData, false);
|
||||
} else {
|
||||
@@ -186,11 +175,11 @@ public class BuffService extends Service {
|
||||
}
|
||||
|
||||
private boolean isBuffRemovedOnDeath(Buff buff) {
|
||||
return getBuff(buff).isRemovedOnDeath();
|
||||
return getBuff(buff).isRemoveOnDeath();
|
||||
}
|
||||
|
||||
private boolean isBuffInfinite(BuffData buffData) {
|
||||
return buffData.getDefaultDuration() < 0;
|
||||
private boolean isBuffInfinite(BuffInfo buffData) {
|
||||
return buffData.getDuration() < 0;
|
||||
}
|
||||
|
||||
private boolean isCreatureBuffed(CreatureObject creature) {
|
||||
@@ -207,9 +196,9 @@ public class BuffService extends Service {
|
||||
buffStream.forEach(buff -> removeBuff(creature, getBuff(buff), true));
|
||||
}
|
||||
|
||||
private void addBuff(CreatureObject receiver, @NotNull BuffData buffData, CreatureObject buffer) {
|
||||
String groupName = buffData.getGroupName();
|
||||
Optional<Buff> groupBuff = receiver.getBuffEntries(buff -> groupName.equals(getBuff(buff).getGroupName())).findAny();
|
||||
private void addBuff(CreatureObject receiver, @NotNull BuffInfo buffData, CreatureObject buffer) {
|
||||
String groupName = buffData.getGroup1();
|
||||
Optional<Buff> groupBuff = receiver.getBuffEntries(buff -> groupName.equals(getBuff(buff).getGroup1())).findAny();
|
||||
|
||||
int applyTime = calculatePlayTime(receiver);
|
||||
|
||||
@@ -224,8 +213,8 @@ public class BuffService extends Service {
|
||||
checkStackCount(receiver, buff, applyTime, 1);
|
||||
}
|
||||
} else {
|
||||
BuffData oldBuff = getBuff(buff);
|
||||
if (buffData.getGroupPriority() >= oldBuff.getGroupPriority()) {
|
||||
BuffInfo oldBuff = getBuff(buff);
|
||||
if (buffData.getPriority() >= oldBuff.getPriority()) {
|
||||
removeBuff(receiver, oldBuff, true);
|
||||
applyBuff(receiver, buffer, buffData, applyTime);
|
||||
}
|
||||
@@ -235,7 +224,7 @@ public class BuffService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private void removeBuff(CreatureObject creature, @NotNull BuffData buffData, boolean expired) {
|
||||
private void removeBuff(CreatureObject creature, @NotNull BuffInfo buffData, boolean expired) {
|
||||
Optional<Buff> optionalEntry = creature.getBuffEntries(buff -> buff.getCrc() == buffData.getCrc()).findAny();
|
||||
if (!optionalEntry.isPresent())
|
||||
return; // Obique: Used to be an assertion, however if a service sends the removal after it expires it would assert - so I just removed it.
|
||||
@@ -257,7 +246,7 @@ public class BuffService extends Service {
|
||||
}
|
||||
|
||||
private void checkStackCount(CreatureObject receiver, Buff buff, int applyTime, int stackMod) {
|
||||
BuffData buffData = getBuff(buff);
|
||||
BuffInfo buffData = getBuff(buff);
|
||||
|
||||
Objects.requireNonNull(buffData, "No known buff: " + buff.getCrc());
|
||||
// If it's the same buff, we need to check for stacks
|
||||
@@ -279,26 +268,26 @@ public class BuffService extends Service {
|
||||
|
||||
// If the stack count was incremented, also renew the duration
|
||||
if (stackMod > 0) {
|
||||
receiver.setBuffDuration(crc, applyTime, (int) buffData.getDefaultDuration());
|
||||
receiver.setBuffDuration(crc, applyTime, (int) buffData.getDuration());
|
||||
}
|
||||
}
|
||||
|
||||
private void applyBuff(CreatureObject receiver, CreatureObject buffer, BuffData buffData, int applyTime) {
|
||||
private void applyBuff(CreatureObject receiver, CreatureObject buffer, BuffInfo buffData, int applyTime) {
|
||||
// TODO stack counts upon add/remove need to be defined on a per-buff basis due to skillmod influence. Scripts might not be a bad idea.
|
||||
int stackCount = 1;
|
||||
int buffDuration = (int) buffData.getDefaultDuration();
|
||||
int buffDuration = (int) buffData.getDuration();
|
||||
{
|
||||
Player bufferPlayer = buffer.getOwner();
|
||||
String bufferUsername = bufferPlayer == null ? "NULL" : bufferPlayer.getUsername();
|
||||
StandardLog.onPlayerTrace(this, receiver, "received buff '%s' from %s/%s; applyTime: %d, buffDuration: %d", buffData.getName(), bufferUsername, buffer.getObjectName(), applyTime, buffDuration);
|
||||
}
|
||||
Buff buff = new Buff(buffData.getCrc(), applyTime + buffDuration, buffData.getEffectValue(0), buffDuration, buffer.getObjectId(), stackCount);
|
||||
Buff buff = new Buff(buffData.getCrc(), applyTime + buffDuration, (float) buffData.getEffectValue(0), buffDuration, buffer.getObjectId(), stackCount);
|
||||
|
||||
checkSkillMods(buffData, receiver, 1);
|
||||
receiver.addBuff(buff);
|
||||
|
||||
sendParticleEffect(buffData.getEffectFileName(), receiver, buffData.getParticleHardPoint());
|
||||
sendParticleEffect(buffData.getStanceParticle(), receiver, buffData.getParticleHardPoint());
|
||||
sendParticleEffect(buffData.getParticle(), receiver, buffData.getParticleHardpoint());
|
||||
sendParticleEffect(buffData.getStanceParticle(), receiver, buffData.getParticleHardpoint());
|
||||
|
||||
addToMonitored(receiver);
|
||||
}
|
||||
@@ -309,19 +298,19 @@ public class BuffService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCallback(BuffData buffData, CreatureObject creature) {
|
||||
private void checkCallback(BuffInfo buffData, CreatureObject creature) {
|
||||
String callback = buffData.getCallback();
|
||||
|
||||
if (callback.equals("none")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dataMap.containsBuff(callback)) {
|
||||
if (DataLoader.buffs().containsBuff(callback)) {
|
||||
addBuff(creature, getBuff(callback), creature);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSkillMods(BuffData buffData, CreatureObject creature, int valueFactor) {
|
||||
private void checkSkillMods(BuffInfo buffData, CreatureObject creature, int valueFactor) {
|
||||
/*
|
||||
* TODO Check effectName == "group". If yes, every group member within 100m range (maybe
|
||||
* just the ones aware of the buffer) receive the buff. Once outside range, buff needs
|
||||
@@ -331,19 +320,19 @@ public class BuffService extends Service {
|
||||
sendSkillModIntent(creature, buffData.getEffectName(i), buffData.getEffectValue(i), valueFactor);
|
||||
}
|
||||
|
||||
private void sendSkillModIntent(CreatureObject creature, String effectName, float effectValue, int valueFactor) {
|
||||
private void sendSkillModIntent(CreatureObject creature, String effectName, double effectValue, int valueFactor) {
|
||||
if (!effectName.isEmpty())
|
||||
new SkillModIntent(effectName, 0, (int) effectValue * valueFactor, creature).broadcast();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BuffData getBuff(String name) {
|
||||
return dataMap.getBuff(name);
|
||||
private BuffInfo getBuff(String name) {
|
||||
return DataLoader.buffs().getBuff(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BuffData getBuff(@NotNull Buff buff) {
|
||||
return dataMap.getBuff(buff.getCrc());
|
||||
private BuffInfo getBuff(@NotNull Buff buff) {
|
||||
return DataLoader.buffs().getBuff(buff.getCrc());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-32
@@ -30,8 +30,6 @@ import com.projectswg.common.data.encodables.oob.ProsePackage;
|
||||
import com.projectswg.common.data.encodables.oob.StringId;
|
||||
import com.projectswg.common.data.encodables.tangible.Posture;
|
||||
import com.projectswg.common.data.location.Location;
|
||||
import com.projectswg.common.data.swgfile.ClientFactory;
|
||||
import com.projectswg.common.data.swgfile.visitors.DatatableData;
|
||||
import com.projectswg.common.network.packets.swg.zone.object_controller.Animation;
|
||||
import com.projectswg.holocore.intents.gameplay.entertainment.dance.DanceIntent;
|
||||
import com.projectswg.holocore.intents.gameplay.entertainment.dance.FlourishIntent;
|
||||
@@ -40,6 +38,8 @@ import com.projectswg.holocore.intents.gameplay.player.experience.ExperienceInte
|
||||
import com.projectswg.holocore.intents.support.global.chat.SystemMessageIntent;
|
||||
import com.projectswg.holocore.intents.support.global.zone.PlayerEventIntent;
|
||||
import com.projectswg.holocore.intents.support.global.zone.PlayerTransformedIntent;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.PerformanceLoader.PerformanceInfo;
|
||||
import com.projectswg.holocore.resources.support.global.player.Player;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
|
||||
@@ -65,39 +65,14 @@ public class EntertainmentService extends Service {
|
||||
private static final byte XP_CYCLE_RATE = 10;
|
||||
private static final byte WATCH_RADIUS = 20;
|
||||
|
||||
private final Map<String, PerformanceData> performanceMap; // performance names mapped to performance data
|
||||
private final Map<Long, Performance> performerMap;
|
||||
private final Map<String, String> danceMap; // Maps performance ID to performance name
|
||||
private final ScheduledExecutorService executorService;
|
||||
|
||||
public EntertainmentService() {
|
||||
performanceMap = new HashMap<>();
|
||||
performerMap = new HashMap<>(); // TODO synchronize access?
|
||||
danceMap = new HashMap<>();
|
||||
executorService = Executors.newSingleThreadScheduledExecutor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean initialize() {
|
||||
DatatableData performanceTable = (DatatableData) ClientFactory.getInfoFromFile("datatables/performance/performance.iff");
|
||||
|
||||
for (int i = 0; i < performanceTable.getRowCount(); i++) {
|
||||
String requiredDance = (String) performanceTable.getCell(i, 4);
|
||||
|
||||
// Load the dances only. Music is currently unsupported.
|
||||
if (!requiredDance.isEmpty()) {
|
||||
String performanceName = (String) performanceTable.getCell(i, 0);
|
||||
String performanceNumber = String.valueOf(performanceTable.getCell(i, 5)); // danceVisualId
|
||||
PerformanceData performanceData = new PerformanceData(performanceNumber, (int) performanceTable.getCell(i, 10)); // flourishXpMod
|
||||
|
||||
performanceMap.put(performanceName, performanceData); // Map the name to the performance data
|
||||
danceMap.put(performanceNumber, performanceName); // Map the dance ID to a performance name!
|
||||
}
|
||||
}
|
||||
|
||||
return super.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean terminate() {
|
||||
executorService.shutdownNow();
|
||||
@@ -116,7 +91,7 @@ public class EntertainmentService extends Service {
|
||||
|
||||
if (!changeDance && dancer.isPerforming()) {
|
||||
new SystemMessageIntent(dancer.getOwner(), "@performance:already_performing_self").broadcast();
|
||||
} else if (performanceMap.containsKey(danceName)) {
|
||||
} else if (DataLoader.performances().getPerformanceByName(danceName) != null) {
|
||||
// The dance name is valid.
|
||||
if (dancer.hasAbility("startDance+" + danceName)) {
|
||||
|
||||
@@ -157,7 +132,7 @@ public class EntertainmentService extends Service {
|
||||
case PE_ZONE_IN_SERVER:
|
||||
// We need to check if they're dancing in order to start giving them XP
|
||||
if (isEntertainer(creature) && creature.getPosture().equals(Posture.SKILL_ANIMATING)) {
|
||||
scheduleExperienceTask(creature, danceMap.get(creature.getAnimation().replace("dance_", "")));
|
||||
scheduleExperienceTask(creature, DataLoader.performances().getPerformanceByDanceId(Integer.parseInt(creature.getAnimation().replace("dance_", ""))).getPerformanceName());
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -311,7 +286,7 @@ public class EntertainmentService extends Service {
|
||||
}
|
||||
|
||||
private void startDancing(CreatureObject dancer, String danceName) {
|
||||
dancer.setAnimation("dance_" + performanceMap.get(danceName).getPerformanceId());
|
||||
dancer.setAnimation("dance_" + DataLoader.performances().getPerformanceByName(danceName).getPerformanceName());
|
||||
dancer.setPerformanceId(0); // 0 - anything else will make it look like we're playing music
|
||||
dancer.setPerformanceCounter(0);
|
||||
dancer.setPerforming(true);
|
||||
@@ -342,7 +317,7 @@ public class EntertainmentService extends Service {
|
||||
|
||||
private void changeDance(CreatureObject dancer, String newPerformanceName) {
|
||||
performerMap.get(dancer.getObjectId()).setPerformanceName(newPerformanceName);
|
||||
dancer.setAnimation("dance_" + performanceMap.get(newPerformanceName).getPerformanceId());
|
||||
dancer.setAnimation("dance_" + DataLoader.performances().getPerformanceByName(newPerformanceName).getPerformanceName());
|
||||
}
|
||||
|
||||
private void startWatching(CreatureObject actor, CreatureObject creature) {
|
||||
@@ -448,7 +423,7 @@ public class EntertainmentService extends Service {
|
||||
}
|
||||
|
||||
String performanceName = performance.getPerformanceName();
|
||||
PerformanceData performanceData = performanceMap.get(performanceName);
|
||||
PerformanceInfo performanceData = DataLoader.performances().getPerformanceByName(performanceName);
|
||||
int flourishXpMod = performanceData.getFlourishXpMod();
|
||||
int performanceCounter = performer.getPerformanceCounter();
|
||||
int xpGained = performanceCounter * flourishXpMod;
|
||||
|
||||
+14
-14
@@ -208,7 +208,7 @@ public class CivilWarService extends Service {
|
||||
private void changeRank(PlayerObject playerObject, int newRank) {
|
||||
assert (newRank < 1 || newRank > 12);
|
||||
|
||||
int oldRank = playerObject.getCurrentRank();
|
||||
int oldRank = playerObject.getCurrentGcwRank();
|
||||
|
||||
assert (oldRank > 1);
|
||||
|
||||
@@ -218,7 +218,7 @@ public class CivilWarService extends Service {
|
||||
PvpFaction faction = creature.getPvpFaction();
|
||||
int abilityIndex = faction == PvpFaction.IMPERIAL ? IMPERIAL_INDEX : REBEL_INDEX;
|
||||
|
||||
playerObject.setCurrentRank(newRank);
|
||||
playerObject.setCurrentGcwRank(newRank);
|
||||
|
||||
if (oldRank > newRank) {
|
||||
// They've been demoted
|
||||
@@ -258,8 +258,8 @@ public class CivilWarService extends Service {
|
||||
}
|
||||
|
||||
private void updateRank(PlayerObject playerObject) {
|
||||
int currentRank = playerObject.getCurrentRank();
|
||||
float oldProgress = playerObject.getRankProgress();
|
||||
int currentRank = playerObject.getCurrentGcwRank();
|
||||
float oldProgress = playerObject.getCurrentGcwRankProgress();
|
||||
int points = playerObject.getGcwPoints();
|
||||
float decay = 0;
|
||||
|
||||
@@ -270,10 +270,10 @@ public class CivilWarService extends Service {
|
||||
float newProgress = rankProgress(oldProgress, decay, currentRank, points);
|
||||
|
||||
if (newProgress >= 100) {
|
||||
int promotion = playerObject.getCurrentRank() + 1;
|
||||
int promotion = playerObject.getCurrentGcwRank() + 1;
|
||||
|
||||
if (promotion > 12) { // 12 is the max rank
|
||||
playerObject.setRankProgress(99.99F);
|
||||
playerObject.setCurrentGcwRankProgress(99.99F);
|
||||
moveToLifetime(playerObject, points);
|
||||
return;
|
||||
}
|
||||
@@ -292,17 +292,17 @@ public class CivilWarService extends Service {
|
||||
return;
|
||||
} else {
|
||||
// They've ranked up, but cannot rank up again
|
||||
playerObject.setRankProgress(nextRankProgress);
|
||||
playerObject.setCurrentGcwRankProgress(nextRankProgress);
|
||||
}
|
||||
|
||||
} else if (newProgress > 0) {
|
||||
// Set their new progress
|
||||
playerObject.setRankProgress(newProgress);
|
||||
playerObject.setCurrentGcwRankProgress(newProgress);
|
||||
} else if (newProgress < 0 && isRankDown(oldProgress, newProgress)) {
|
||||
int demotion = playerObject.getCurrentRank() - 1;
|
||||
int demotion = playerObject.getCurrentGcwRank() - 1;
|
||||
|
||||
if (demotion < 1) { // 1 is the minimum rank
|
||||
playerObject.setRankProgress(0);
|
||||
playerObject.setCurrentGcwRankProgress(0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ public class CivilWarService extends Service {
|
||||
return;
|
||||
} else {
|
||||
// They've ranked down, but cannot rank down again
|
||||
playerObject.setRankProgress(nextRankProgress);
|
||||
playerObject.setCurrentGcwRankProgress(nextRankProgress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ public class CivilWarService extends Service {
|
||||
|
||||
private void updateRanks() {
|
||||
playerObjects.forEach(playerObject -> {
|
||||
if (playerObject.getCurrentRank() > 0)
|
||||
if (playerObject.getCurrentGcwRank() > 0)
|
||||
updateRank(playerObject);
|
||||
});
|
||||
|
||||
@@ -431,14 +431,14 @@ public class CivilWarService extends Service {
|
||||
|
||||
if (fi.getNewFaction() == PvpFaction.NEUTRAL) {
|
||||
// They've left the imperials or rebels and must have rank removed
|
||||
playerObject.setCurrentRank(0);
|
||||
playerObject.setCurrentGcwRank(0);
|
||||
|
||||
int points = playerObject.getGcwPoints();
|
||||
|
||||
moveToLifetime(playerObject, points);
|
||||
} else {
|
||||
// They've joined the imperials or rebels and become Privates
|
||||
playerObject.setCurrentRank(1);
|
||||
playerObject.setCurrentGcwRank(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-11
@@ -63,15 +63,12 @@ public class BadgeService extends Service {
|
||||
}
|
||||
|
||||
private void grantBadge(PlayerObject player, int beginSlotId, String collectionName, boolean isHidden, String slotName) {
|
||||
BitSet collections = BitSet.valueOf(player.getCollectionBadges());
|
||||
|
||||
collections.set(beginSlotId);
|
||||
player.setCollectionBadges(collections.toByteArray());
|
||||
player.setCollectionFlag(beginSlotId);
|
||||
handleMessage(player, hasCompletedCollection(player, collectionName), collectionName, isHidden, slotName);
|
||||
}
|
||||
|
||||
private void grantBadgeIncrement(PlayerObject player, int beginSlotId, int endSlotId, int maxSlotValue) {
|
||||
BitSet collections = BitSet.valueOf(player.getCollectionBadges());
|
||||
BitSet collections = player.getCollectionBadges();
|
||||
|
||||
int binaryValue = 1;
|
||||
int curValue = 0;
|
||||
@@ -94,7 +91,7 @@ public class BadgeService extends Service {
|
||||
collections.clear(beginSlotId + i);
|
||||
}
|
||||
}
|
||||
player.setCollectionBadges(collections.toByteArray());
|
||||
player.setCollectionFlags(collections);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,15 +261,12 @@ public class BadgeService extends Service {
|
||||
}
|
||||
|
||||
private boolean hasBadge(PlayerObject player, int badgeBeginSlotId) {
|
||||
BitSet collections = BitSet.valueOf(player.getCollectionBadges());
|
||||
|
||||
return collections.get(badgeBeginSlotId);
|
||||
return player.getCollectionFlag(badgeBeginSlotId);
|
||||
}
|
||||
|
||||
private boolean hasCompletedCollection(PlayerObject player, String collectionTitle) {
|
||||
|
||||
String collectionName = "";
|
||||
BitSet collections = BitSet.valueOf(player.getCollectionBadges());
|
||||
BitSet collections = player.getCollectionBadges();
|
||||
|
||||
for (int row = 0; row < collectionTable.getRowCount(); row++) {
|
||||
int beginSlotId = (int) collectionTable.getCell(row, 4);
|
||||
|
||||
+15
-11
@@ -6,6 +6,7 @@ import com.projectswg.holocore.intents.support.global.chat.SystemMessageIntent;
|
||||
import com.projectswg.holocore.intents.support.global.command.ExecuteCommandIntent;
|
||||
import com.projectswg.holocore.intents.support.objects.swg.DestroyObjectIntent;
|
||||
import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
|
||||
import com.projectswg.holocore.resources.support.global.commands.Command;
|
||||
import com.projectswg.holocore.resources.support.global.player.AccessLevel;
|
||||
import com.projectswg.holocore.resources.support.global.zone.sui.SuiButtons;
|
||||
@@ -92,21 +93,24 @@ public class CustomObjectService extends Service {
|
||||
}
|
||||
|
||||
private ListBoxRecursive createListBoxRecursive() {
|
||||
return createListBoxRecursive(new File("clientdata/object"));
|
||||
return createListBoxRecursive(DataLoader.objectData().getObjects());
|
||||
}
|
||||
|
||||
private ListBoxRecursive createListBoxRecursive(File start) {
|
||||
private ListBoxRecursive createListBoxRecursive(Collection<String> objects) {
|
||||
Map<String, Object> mapping = new TreeMap<>();
|
||||
File [] children = start.listFiles();
|
||||
assert children != null;
|
||||
for (File file : children) {
|
||||
if (file.isDirectory()) {
|
||||
mapping.put(file.getName(), createListBoxRecursive(file));
|
||||
} else if (file.isFile() && file.getName().startsWith("shared_") && file.getName().endsWith(".iff")) {
|
||||
String iff = file.getAbsolutePath().replace(new File("clientdata").getAbsolutePath()+File.separator, "");
|
||||
mapping.put(prettyIff(iff), iff.replace(File.separatorChar, '/'));
|
||||
}
|
||||
for (String iff : objects) {
|
||||
mapping.put(prettyIff(iff), iff.replace(File.separatorChar, '/'));
|
||||
}
|
||||
// File [] children = start.listFiles();
|
||||
// assert children != null;
|
||||
// for (File file : children) {
|
||||
// if (file.isDirectory()) {
|
||||
// mapping.put(file.getName(), createListBoxRecursive(file));
|
||||
// } else if (file.isFile() && file.getName().startsWith("shared_") && file.getName().endsWith(".iff")) {
|
||||
// String iff = file.getAbsolutePath().replace(new File("clientdata").getAbsolutePath()+File.separator, "");
|
||||
// mapping.put(prettyIff(iff), iff.replace(File.separatorChar, '/'));
|
||||
// }
|
||||
// }
|
||||
return new ListBoxRecursive(mapping);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -117,7 +117,7 @@ public class ChatFriendService extends Service {
|
||||
}
|
||||
|
||||
private void handleRequestFriendList(Player player) {
|
||||
player.getPlayerObject().sendFriendsList();
|
||||
player.getPlayerObject().sendFriendList();
|
||||
}
|
||||
|
||||
/* Ignore List */
|
||||
|
||||
+2
-2
@@ -127,14 +127,14 @@ public class ConnectionService extends Service {
|
||||
PlayerObject player = p.getPlayerObject();
|
||||
if (player == null)
|
||||
return;
|
||||
player.setFlagBitmask(PlayerFlags.LD);
|
||||
player.setFlag(PlayerFlags.LD);
|
||||
}
|
||||
|
||||
private void clearPlayerFlag(Player p) {
|
||||
PlayerObject player = p.getPlayerObject();
|
||||
if (player == null)
|
||||
return;
|
||||
player.clearFlagBitmask(PlayerFlags.LD);
|
||||
player.clearFlag(PlayerFlags.LD);
|
||||
}
|
||||
|
||||
private void zoneIn(Player p) {
|
||||
|
||||
+26
-1
@@ -13,10 +13,12 @@ import com.projectswg.holocore.resources.support.data.server_info.ObjectDatabase
|
||||
import com.projectswg.holocore.resources.support.data.server_info.StandardLog;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.BuildoutLoader;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.mongodb.users.PswgUserDatabase;
|
||||
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 com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
|
||||
import me.joshlarson.jlcommon.concurrency.ScheduledThreadPool;
|
||||
import me.joshlarson.jlcommon.control.IntentHandler;
|
||||
import me.joshlarson.jlcommon.control.Service;
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
@@ -24,6 +26,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
@@ -31,6 +35,9 @@ import java.util.function.Function;
|
||||
public class ObjectStorageService extends Service {
|
||||
|
||||
private final ObjectDatabase<SWGObject> database;
|
||||
private final PswgUserDatabase userDatabase;
|
||||
private final ScheduledThreadPool persistenceThread;
|
||||
private final Set<SWGObject> persistedObjects;
|
||||
private final Map<Long, SWGObject> objectMap;
|
||||
private final Map<Long, SWGObject> buildouts;
|
||||
private final Map<String, BuildingObject> buildingLookup;
|
||||
@@ -38,6 +45,9 @@ public class ObjectStorageService extends Service {
|
||||
|
||||
public ObjectStorageService() {
|
||||
this.database = new CachedObjectDatabase<>("odb/objects.db", SWGObjectFactory::create, SWGObjectFactory::save);
|
||||
this.userDatabase = new PswgUserDatabase();
|
||||
this.persistenceThread = new ScheduledThreadPool(1, 3, "object-storage-service");
|
||||
this.persistedObjects = new CopyOnWriteArraySet<>();
|
||||
this.objectMap = new ConcurrentHashMap<>(256*1024, 0.8f, Runtime.getRuntime().availableProcessors());
|
||||
this.buildouts = new HashMap<>(128*1024, 1f);
|
||||
this.buildingLookup = new HashMap<>();
|
||||
@@ -59,14 +69,17 @@ public class ObjectStorageService extends Service {
|
||||
database.traverse(this::loadObject);
|
||||
}
|
||||
|
||||
persistenceThread.start();
|
||||
persistenceThread.executeWithFixedDelay(TimeUnit.MINUTES.toMillis(5), TimeUnit.MINUTES.toMillis(5), this::saveObjects);
|
||||
started.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stop() {
|
||||
persistenceThread.stop();
|
||||
started.set(false);
|
||||
return true;
|
||||
return persistenceThread.awaitTermination(1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,6 +88,7 @@ public class ObjectStorageService extends Service {
|
||||
database.close();
|
||||
}
|
||||
ObjectLookup.setObjectAuthority(null);
|
||||
saveObjects();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -84,6 +98,7 @@ public class ObjectStorageService extends Service {
|
||||
if (!database.load() && database.fileExists())
|
||||
return false;
|
||||
}
|
||||
database.traverse(persistedObjects::add);
|
||||
StandardLog.onEndLoad(database.size(), "players", startTime);
|
||||
return true;
|
||||
}
|
||||
@@ -129,6 +144,12 @@ public class ObjectStorageService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private void saveObjects() {
|
||||
for (SWGObject obj : persistedObjects) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@IntentHandler
|
||||
private void processObjectCreatedIntent(ObjectCreatedIntent intent) {
|
||||
SWGObject obj = intent.getObject();
|
||||
@@ -205,6 +226,10 @@ public class ObjectStorageService extends Service {
|
||||
AUTHORITY.set(authority);
|
||||
}
|
||||
|
||||
public static boolean isDefined() {
|
||||
return AUTHORITY.get() != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SWGObject getObjectById(long id) {
|
||||
return AUTHORITY.get().apply(id);
|
||||
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
/***********************************************************************************
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.holocore.utilities.clientdata_printer;
|
||||
|
||||
import com.projectswg.common.data.swgfile.ClientFactory;
|
||||
import com.projectswg.common.data.swgfile.visitors.DatatableData;
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
import me.joshlarson.jlcommon.log.log_wrapper.ConsoleLogWrapper;
|
||||
|
||||
public class ClientdataPrinterDatatable {
|
||||
|
||||
public static void main(String [] args) {
|
||||
Log.addWrapper(new ConsoleLogWrapper());
|
||||
printTable("datatables/buildout/areas_tatooine.iff");
|
||||
}
|
||||
|
||||
private static void printTable(String table) {
|
||||
DatatableData data = (DatatableData) ClientFactory.getInfoFromFile(table);
|
||||
for (int col = 0; col < data.getColumnCount(); col++) {
|
||||
System.out.print(data.getColumnName(col) + ',');
|
||||
}
|
||||
System.out.println();
|
||||
for (int row = 0; row < data.getRowCount(); row++) {
|
||||
for (int col = 0; col < data.getColumnCount(); col++) {
|
||||
System.out.print(data.getCell(row, col) + ",");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -59,9 +59,9 @@ public class TestTravelHelper extends TestRunnerNoIntents {
|
||||
for (Terrain terrain : terrains) {
|
||||
Assert.assertEquals(100, helper.getTravelFee(terrain, terrain));
|
||||
}
|
||||
Assert.assertEquals(2000, helper.getTravelFee(Terrain.DATHOMIR, Terrain.CORELLIA));
|
||||
Assert.assertEquals(1250, helper.getTravelFee(Terrain.DATHOMIR, Terrain.CORELLIA));
|
||||
Assert.assertEquals(2000, helper.getTravelFee(Terrain.CORELLIA, Terrain.DATHOMIR));
|
||||
Assert.assertEquals(1750, helper.getTravelFee(Terrain.NABOO, Terrain.ENDOR));
|
||||
Assert.assertEquals(4000, helper.getTravelFee(Terrain.NABOO, Terrain.ENDOR));
|
||||
Assert.assertEquals(500, helper.getTravelFee(Terrain.TATOOINE, Terrain.NABOO));
|
||||
Assert.assertFalse(helper.isValidRoute(Terrain.TATOOINE, Terrain.YAVIN4));
|
||||
Assert.assertTrue(helper.isValidRoute(Terrain.TATOOINE, Terrain.LOK));
|
||||
|
||||
+23
-1
@@ -27,14 +27,18 @@
|
||||
|
||||
package com.projectswg.holocore.resources.support.data.collections;
|
||||
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.holocore.test.runners.TestRunnerNoIntents;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.BitSet;
|
||||
|
||||
public class TestSWGFlag extends TestRunnerNoIntents {
|
||||
|
||||
@Test
|
||||
public void testFlag() {
|
||||
public void testFlagAccuracy() {
|
||||
SWGFlag flag = new SWGFlag(3, 16);
|
||||
flag.set(1);
|
||||
flag.set(4);
|
||||
@@ -47,6 +51,24 @@ public class TestSWGFlag extends TestRunnerNoIntents {
|
||||
Assert.assertEquals(1, ints[1]);
|
||||
Assert.assertEquals(1, ints[2]);
|
||||
Assert.assertEquals(1, ints[3]);
|
||||
SWGFlag decoded = new SWGFlag(3, 16);
|
||||
decoded.decode(NetBuffer.wrap(flag.encode()));
|
||||
Assert.assertArrayEquals(flag.encode(), decoded.encode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlagSize() {
|
||||
byte [] encoded;
|
||||
SWGFlag flag = new SWGFlag(3, 16);
|
||||
|
||||
encoded = flag.encode();
|
||||
Assert.assertEquals(4, encoded.length);
|
||||
|
||||
flag.set(1);
|
||||
encoded = flag.encode();
|
||||
Assert.assertEquals(8, encoded.length);
|
||||
Assert.assertEquals(1, encoded[0]);
|
||||
Assert.assertEquals(2, encoded[4]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
/***********************************************************************************
|
||||
* 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.objects.swg;
|
||||
|
||||
import com.projectswg.common.data.CRC;
|
||||
import com.projectswg.common.data.encodables.mongo.MongoData;
|
||||
import com.projectswg.common.data.encodables.mongo.MongoPersistable;
|
||||
import com.projectswg.common.data.encodables.oob.StringId;
|
||||
import com.projectswg.common.data.encodables.tangible.PvpFlag;
|
||||
import com.projectswg.holocore.resources.support.data.persistable.SWGObjectFactory;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.intangible.IntangibleObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.player.PlayerObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.tangible.OptionFlag;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.tangible.TangibleObject;
|
||||
import com.projectswg.holocore.test.resources.GenericCreatureObject;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.Binary;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TestSWGPersistence {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void assertContains(Map<String, Object> expected, Map<String, Object> actual) {
|
||||
for (Entry<String, Object> e : expected.entrySet()) {
|
||||
if (actual.get(e.getKey()) instanceof Map) {
|
||||
assertContains((Map<String, Object>) e.getValue(), (Map<String, Object>) actual.get(e.getKey()));
|
||||
} else if (actual.get(e.getKey()) instanceof Collection) {
|
||||
Collection<Object> expectedCollection = (Collection<Object>) e.getValue();
|
||||
Collection<Object> actualCollection = (Collection<Object>) actual.get(e.getKey());
|
||||
Assert.assertEquals("Key: '"+e.getKey()+"' Size mismatch.", expectedCollection.size(), actualCollection.size());
|
||||
Assert.assertTrue("Key: '"+e.getKey()+"' Expected <"+expectedCollection+"> but was <"+actualCollection+">", actualCollection.containsAll(expectedCollection));
|
||||
} else {
|
||||
Assert.assertEquals("Key: '" + e.getKey() + "'", e.getValue(), actual.get(e.getKey()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Document encode(MongoData data) {
|
||||
Document ret = new Document();
|
||||
for (Entry<String, Object> e : data.entrySet()) {
|
||||
if (e.getValue() instanceof MongoData)
|
||||
ret.put(e.getKey(), encode(((MongoData) e.getValue())));
|
||||
else
|
||||
ret.put(e.getKey(), e.getValue());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void test(SWGObject obj, Document expected) {
|
||||
Document saved = encode(SWGObjectFactory.save(obj, new MongoData()));
|
||||
assertContains(expected, saved);
|
||||
SWGObject gen = SWGObjectFactory.create(new MongoData(saved));
|
||||
Document saved2 = SWGObjectFactory.save(gen, new MongoData()).toDocument();
|
||||
assertContains(expected, saved2);
|
||||
Assert.assertEquals(saved, saved2);
|
||||
}
|
||||
|
||||
private void testSWGObject(SWGObject obj) {
|
||||
System.out.println(obj);
|
||||
obj.getChildObjects().stream()
|
||||
.map(SWGObjectFactory::save)
|
||||
.map(MongoData::toDocument)
|
||||
.forEach(System.out::println);
|
||||
Document expected = map(
|
||||
"id", obj.getObjectId(),
|
||||
"template", obj.getTemplate(),
|
||||
"base1", map(
|
||||
"cashBalance", obj.getCashBalance(),
|
||||
"bankBalance", obj.getBankBalance()
|
||||
),
|
||||
"base3", map(
|
||||
"complexity", obj.getComplexity(),
|
||||
"stringId", map("file", obj.getStringId().getFile(), "key", obj.getStringId().getKey()),
|
||||
"objectName", obj.getObjectName(),
|
||||
"volume", obj.getVolume()
|
||||
),
|
||||
"base6", map(
|
||||
"detailStringId", map("file", obj.getDetailStringId().getFile(), "key", obj.getDetailStringId().getKey())
|
||||
),
|
||||
"location", map(
|
||||
"type", obj.getInstanceLocation().getInstanceType().name(),
|
||||
"number", obj.getInstanceLocation().getInstanceNumber(),
|
||||
"location", map(
|
||||
"terrain", obj.getTerrain().name(),
|
||||
"point", map(
|
||||
"x", obj.getX(),
|
||||
"y", obj.getY(),
|
||||
"z", obj.getZ()
|
||||
),
|
||||
"orientation", map(
|
||||
"x", obj.getLocation().getOrientationX(),
|
||||
"y", obj.getLocation().getOrientationY(),
|
||||
"z", obj.getLocation().getOrientationZ(),
|
||||
"w", obj.getLocation().getOrientationW()
|
||||
)
|
||||
)
|
||||
),
|
||||
"permissions", map("type", obj.getContainerPermissions().getType().name()),
|
||||
"attributes", map(),
|
||||
"serverAttributes", map(),
|
||||
"children", obj.getChildObjects().stream()
|
||||
.map(SWGObjectFactory::save)
|
||||
.map(MongoData::toDocument)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
test(obj, expected);
|
||||
}
|
||||
|
||||
private void testTangibleObject(TangibleObject obj) {
|
||||
testSWGObject(obj);
|
||||
|
||||
Document expected = map(
|
||||
"appearance", Map.ofEntries(obj.getCustomization().entrySet().stream().map(e -> Map.entry(e.getKey(), e.getValue().getValue())).toArray(Entry[]::new)),
|
||||
"maxHitPoints", obj.getMaxHitPoints(),
|
||||
"components", obj.getComponents(),
|
||||
"condition", obj.getCondition(),
|
||||
"pvpFlags", obj.getPvpFlags().stream().mapToInt(PvpFlag::getBitmask).reduce(0, (a, b) -> a | b),
|
||||
"pvpStatus", obj.getPvpStatus().name(),
|
||||
"pvpFaction", obj.getPvpFaction().name(),
|
||||
"visibleGmOnly", obj.isVisibleGmOnly(),
|
||||
"objectEffects", new Binary(obj.getObjectEffects()),
|
||||
"optionFlags", obj.getOptionFlags().stream().map(OptionFlag::getFlag).reduce(0, (a, b) -> a | b)
|
||||
);
|
||||
test(obj, expected);
|
||||
}
|
||||
|
||||
private void testCreatureObject(CreatureObject obj) {
|
||||
testTangibleObject(obj);
|
||||
|
||||
Document expected = map(
|
||||
"base4", map(
|
||||
"accelPercent", obj.getAccelPercent(),
|
||||
"accelScale", obj.getAccelScale(),
|
||||
"movementPercent", obj.getMovementPercent(),
|
||||
"movementScale", obj.getMovementScale(),
|
||||
"slopeModPercent", obj.getSlopeModPercent(),
|
||||
"slopeModAngle", obj.getSlopeModPercent(),
|
||||
"waterModPercent", obj.getWaterModPercent(),
|
||||
"runSpeed", obj.getRunSpeed(),
|
||||
"walkSpeed", obj.getWalkSpeed(),
|
||||
"turnScale", obj.getTurnScale(),
|
||||
"totalLevelXp", obj.getTotalLevelXp()
|
||||
),
|
||||
"base6", map(
|
||||
"level", (int) obj.getLevel(),
|
||||
"levelHealthGranted", obj.getLevelHealthGranted(),
|
||||
"animation", obj.getAnimation(),
|
||||
"moodAnimation", obj.getMoodAnimation(),
|
||||
"guildId", obj.getGuildId(),
|
||||
"lookAtTargetId", obj.getLookAtTargetId(),
|
||||
"intendedTargetId", obj.getIntendedTargetId(),
|
||||
"moodId", (int) obj.getMoodId(),
|
||||
"costume", obj.getCostume(),
|
||||
"visible", obj.isVisible(),
|
||||
"shownOnRadar", obj.isShownOnRadar(),
|
||||
"beast", obj.isBeast(),
|
||||
"difficulty", obj.getDifficulty().name(),
|
||||
"hologramColor", obj.getHologramColor().name(),
|
||||
"equippedWeapon", obj.getEquippedWeapon() == null ? null : obj.getEquippedWeapon().getObjectId(),
|
||||
"maxAttributes", List.of(obj.getMaxHealth(), 0, obj.getMaxAction(), 0, obj.getMaxMind(), 0),
|
||||
"buffs", Map.ofEntries(obj.getBuffEntries(b -> true).map(b -> Map.entry(CRC.getString(b.getCrc()), MongoData.store(b).toDocument())).toArray(Entry[]::new))
|
||||
),
|
||||
"posture", obj.getPosture().name(),
|
||||
"race", obj.getRace().name(),
|
||||
"height", obj.getHeight(),
|
||||
"battleFatigue", obj.getBattleFatigue(),
|
||||
"ownerId", obj.getOwnerId(),
|
||||
"statesBitmask", obj.getStatesBitmask(),
|
||||
"factionRank", (int) obj.getFactionRank(),
|
||||
"skills", obj.getSkills(),
|
||||
"baseAttributes", List.of(obj.getBaseHealth(), 0, obj.getBaseAction(), 0, obj.getBaseMind(), 0)
|
||||
);
|
||||
test(obj, expected);
|
||||
}
|
||||
|
||||
private void testIntangibleObject(IntangibleObject obj) {
|
||||
testSWGObject(obj);
|
||||
|
||||
Document expected = map(
|
||||
"count", obj.getCount()
|
||||
);
|
||||
test(obj, expected);
|
||||
}
|
||||
|
||||
private void testPlayerObject(PlayerObject obj) {
|
||||
testIntangibleObject(obj);
|
||||
|
||||
Document expected = map(
|
||||
"base3", map(
|
||||
|
||||
),
|
||||
"base6", map(
|
||||
|
||||
),
|
||||
"base8", map(
|
||||
|
||||
),
|
||||
"base9", map(
|
||||
"languageId", obj.getLanguageId(),
|
||||
"killMeter", obj,
|
||||
"petId", obj,
|
||||
"friendsList", obj,
|
||||
"ignoreList", obj,
|
||||
"petAbilities", obj,
|
||||
"activePetAbilities", obj
|
||||
),
|
||||
"biography", obj.getBiography()
|
||||
);
|
||||
test(obj, expected);
|
||||
}
|
||||
|
||||
private void test(SWGObject obj) {
|
||||
switch (obj.getBaselineType()) {
|
||||
case PLAY:
|
||||
testPlayerObject((PlayerObject) obj);
|
||||
break;
|
||||
case ITNO:
|
||||
testIntangibleObject((IntangibleObject) obj);
|
||||
break;
|
||||
case CREO:
|
||||
testCreatureObject((CreatureObject) obj);
|
||||
break;
|
||||
case TANO:
|
||||
testTangibleObject((TangibleObject) obj);
|
||||
break;
|
||||
default:
|
||||
testSWGObject(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatureObject() {
|
||||
GenericCreatureObject creature = new GenericCreatureObject(1);
|
||||
creature.setObjectName("TEST");
|
||||
creature.setStringId(new StringId("file", "key"));
|
||||
creature.setDetailStf(new StringId("file-d", "key-d"));
|
||||
creature.setComplexity(2);
|
||||
creature.setVolume(3);
|
||||
|
||||
test(creature);
|
||||
}
|
||||
|
||||
private static Document map(Object ... values) {
|
||||
assert values.length % 2 == 0;
|
||||
Document map = new Document();
|
||||
for (int i = 0; i < values.length-1; i+=2) {
|
||||
assert values[i] instanceof String;
|
||||
if (values[i+1] instanceof Float)
|
||||
map.put((String) values[i], ((Float) values[i+1]).doubleValue());
|
||||
else
|
||||
map.put((String) values[i], values[i+1]);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,10 +28,10 @@ package com.projectswg.holocore.test.resources;
|
||||
|
||||
import com.projectswg.common.data.objects.GameObjectType;
|
||||
import com.projectswg.holocore.resources.support.global.player.PlayerState;
|
||||
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.creature.CreatureObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.player.PlayerObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.tangible.TangibleObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@@ -71,14 +71,15 @@ public class GenericCreatureObject extends CreatureObject {
|
||||
setGameObjectType(GameObjectType.GOT_CREATURE_CHARACTER);
|
||||
|
||||
PlayerObject playerObject = new PlayerObject(-getObjectId());
|
||||
playerObject.setTemplate("object/player/shared_player.iff");
|
||||
playerObject.setArrangement(List.of(List.of("ghost")));
|
||||
playerObject.systemMove(this);
|
||||
playerObject.setObjectName(name);
|
||||
createInventoryObject("inventory");
|
||||
createInventoryObject("datapad");
|
||||
createInventoryObject("appearance_inventory");
|
||||
createInventoryObject("bank");
|
||||
createInventoryObject("mission_bag");
|
||||
createInventoryObject("object/tangible/inventory/shared_character_inventory.iff");
|
||||
createInventoryObject("object/tangible/datapad/shared_character_datapad.iff");
|
||||
createInventoryObject("object/tangible/inventory/shared_appearance_inventory.iff");
|
||||
createInventoryObject("object/tangible/bank/shared_character_bank.iff");
|
||||
createInventoryObject("object/tangible/mission_bag/shared_mission_bag.iff");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,10 +87,10 @@ public class GenericCreatureObject extends CreatureObject {
|
||||
return (GenericPlayer) super.getOwner();
|
||||
}
|
||||
|
||||
private void createInventoryObject(String slot) {
|
||||
SWGObject obj = new TangibleObject(GENERATED_IDS.incrementAndGet());
|
||||
obj.setArrangement(List.of(List.of(slot)));
|
||||
private void createInventoryObject(String template) {
|
||||
SWGObject obj = ObjectCreator.createObjectFromTemplate(GENERATED_IDS.incrementAndGet(), template);
|
||||
obj.systemMove(this);
|
||||
assert obj.getSlotArrangement() != -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
* 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.utilities.clientdata_printer;
|
||||
package com.projectswg.utility.clientdata_printer;
|
||||
|
||||
import com.projectswg.common.data.swgfile.ClientFactory;
|
||||
import com.projectswg.common.data.swgfile.visitors.DatatableData;
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
/***********************************************************************************
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.utility.clientdata_printer;
|
||||
|
||||
import com.projectswg.common.data.swgfile.ClientFactory;
|
||||
import com.projectswg.common.data.swgfile.visitors.DatatableData;
|
||||
import com.projectswg.common.data.swgfile.visitors.DatatableData.ColumnType;
|
||||
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.loader.VehicleLoader.VehicleInfo;
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
import me.joshlarson.jlcommon.log.log_wrapper.ConsoleLogWrapper;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ClientdataPrinterDatatable {
|
||||
|
||||
private static final Pattern COLUMN_SPLITTER = Pattern.compile("_|(?<=[a-z])(?=[A-Z])");
|
||||
|
||||
public static void main(String [] args) throws IOException {
|
||||
Log.addWrapper(new ConsoleLogWrapper());
|
||||
printTable("datatables/travel/travel.iff");
|
||||
}
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
private static void printTable(String table) throws IOException {
|
||||
DatatableData data = (DatatableData) ClientFactory.getInfoFromFile(table);
|
||||
File outputFile = new File("serverdata/", table.replace("datatables/", "").replace(".iff", ".sdb"));
|
||||
try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), StandardCharsets.UTF_8))) {
|
||||
for (int col = 0; col < data.getColumnCount(); col++) {
|
||||
if (col > 0)
|
||||
out.write('\t');
|
||||
out.write(toSdbColumn(data.getColumnName(col)));
|
||||
}
|
||||
out.newLine();
|
||||
for (int col = 0; col < data.getColumnCount(); col++) {
|
||||
if (col > 0)
|
||||
out.write('\t');
|
||||
out.write(data.getColumnType(col).toString());
|
||||
}
|
||||
out.newLine();
|
||||
for (int row = 0; row < data.getRowCount(); row++) {
|
||||
for (int col = 0; col < data.getColumnCount(); col++) {
|
||||
if (col > 0)
|
||||
out.write('\t');
|
||||
out.write(String.valueOf(data.getCell(row, col)));
|
||||
}
|
||||
out.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
String type = toJavaClass(table.substring(table.lastIndexOf('/')+1).replace(".iff", ""));
|
||||
|
||||
System.out.printf("public final class %sLoader extends DataLoader {%n\t%n"+
|
||||
"\t%sLoader() {%n"+
|
||||
"\t\t%n"+
|
||||
"\t}%n", type, type);
|
||||
System.out.println("\t");
|
||||
|
||||
// load() method
|
||||
System.out.printf("\t@Override%n"+
|
||||
"\tpublic final void load() throws IOException {%n"+
|
||||
"\t\ttry (SdbResultSet set = SdbLoader.load(new File(\"%s\"))) {%n"+
|
||||
"\t\t\twhile (set.next()) {%n"+
|
||||
"\t\t\t\t%sInfo %s = new %sInfo(set);%n"+
|
||||
"\t\t\t\t// TODO: Store information%n"+
|
||||
"\t\t\t}%n"+
|
||||
"\t\t}%n"+
|
||||
"\t}%n", outputFile, type, Character.toLowerCase(type.charAt(0))+type.substring(1), type);
|
||||
System.out.println("\t");
|
||||
|
||||
System.out.printf("\tpublic static class %sInfo {%n", type);
|
||||
System.out.println("\t\t");
|
||||
for (int i = 0; i < data.getColumnCount(); i++) {
|
||||
System.out.printf("\t\tprivate final %s %s;%n", toJavaType(data.getColumnType(i)), toJavaVariable(data.getColumnName(i)));
|
||||
}
|
||||
System.out.println("\t\t");
|
||||
System.out.printf("\t\tpublic %sInfo(SdbResultSet set) {%n", type);
|
||||
for (int i = 0; i < data.getColumnCount(); i++) {
|
||||
String sdbCol = toSdbColumn(data.getColumnName(i));
|
||||
String rhs;
|
||||
switch (data.getColumnType(i)) {
|
||||
case BOOLEAN:
|
||||
rhs = "set.getBoolean(\""+sdbCol+"\")";
|
||||
break;
|
||||
case FLOAT:
|
||||
rhs = "set.getReal(\""+sdbCol+"\")";
|
||||
break;
|
||||
case CRC:
|
||||
rhs = "new CRC((int) set.getInt(\""+sdbCol+"\"))";
|
||||
break;
|
||||
case INTEGER:
|
||||
rhs = "(int) set.getInt(\""+sdbCol+"\")";
|
||||
break;
|
||||
case STRING:
|
||||
case ENUM:
|
||||
case DATATABLE_ENUM:
|
||||
case NONE:
|
||||
default:
|
||||
rhs ="set.getText(\""+sdbCol+"\")";
|
||||
break;
|
||||
}
|
||||
System.out.printf("\t\t\tthis.%s = %s;%n", toJavaVariable(data.getColumnName(i)), rhs);
|
||||
}
|
||||
System.out.println("\t\t}");
|
||||
System.out.println("\t}");
|
||||
System.out.println("}");
|
||||
}
|
||||
|
||||
private static String toJavaType(ColumnType type) {
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
return "boolean";
|
||||
case FLOAT:
|
||||
return "double";
|
||||
case CRC:
|
||||
return "CRC";
|
||||
case INTEGER:
|
||||
return "int";
|
||||
case STRING:
|
||||
case ENUM:
|
||||
case DATATABLE_ENUM:
|
||||
case NONE:
|
||||
default:
|
||||
return "String";
|
||||
}
|
||||
}
|
||||
|
||||
private static String toJavaVariable(String col) {
|
||||
String [] parts = COLUMN_SPLITTER.split(col);
|
||||
StringBuilder str = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (String part : parts) {
|
||||
if (first)
|
||||
str.append(part.toLowerCase(Locale.US));
|
||||
else if (str.length() > 0)
|
||||
str.append(Character.toUpperCase(part.charAt(0))).append(part.substring(1).toLowerCase(Locale.US));
|
||||
first = false;
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
private static String toJavaClass(String col) {
|
||||
String [] parts = COLUMN_SPLITTER.split(col);
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (String part : parts) {
|
||||
str.append(Character.toUpperCase(part.charAt(0))).append(part.substring(1).toLowerCase(Locale.US));
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
private static String toSdbColumn(String col) {
|
||||
String [] parts = COLUMN_SPLITTER.split(col);
|
||||
return String.join("_", parts).toLowerCase(Locale.US);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import com.projectswg.common.data.CRC;
|
||||
import com.projectswg.common.data.encodables.tangible.Posture;
|
||||
import com.projectswg.common.data.location.Location;
|
||||
import com.projectswg.common.data.location.Terrain;
|
||||
import com.projectswg.common.network.hcap.PacketRecord;
|
||||
import com.projectswg.common.network.packets.PacketType;
|
||||
import com.projectswg.common.network.packets.SWGPacket;
|
||||
import com.projectswg.common.network.packets.swg.zone.*;
|
||||
@@ -182,9 +183,12 @@ public class PacketCaptureAnalysis {
|
||||
|
||||
private void handleSceneCreateObjectByCrc(SceneCreateObjectByCrc p) {
|
||||
objectCreations.incrementAndGet();
|
||||
assertNotNull(p, currentTerrain.get(), "unknown terrain");
|
||||
SWGObject obj = ObjectCreator.createObjectFromTemplate(p.getObjectId(), CRC.getString(p.getObjectCrc()));
|
||||
p.setLocation(Location.builder(p.getLocation()).setTerrain(currentTerrain.get()).build());
|
||||
|
||||
if (currentTerrain.get() == null)
|
||||
p.setLocation(Location.builder(p.getLocation()).setTerrain(Terrain.GONE).build());
|
||||
else
|
||||
p.setLocation(Location.builder(p.getLocation()).setTerrain(currentTerrain.get()).build());
|
||||
obj.setLocation(p.getLocation());
|
||||
loadingObjects.add(obj);
|
||||
assertFalse(p, objects.containsKey(p.getObjectId()), "object already exists [initialized]");
|
||||
@@ -201,8 +205,10 @@ public class PacketCaptureAnalysis {
|
||||
}
|
||||
|
||||
private void handleBaseline(Baseline p) {
|
||||
assertTrue(p, !loadingObjects.isEmpty(), "no loading objects defined");
|
||||
assertEquals(p, loadingObjects.getLast().getObjectId(), p.getObjectId(), "baseline sent for non-loading object");
|
||||
assertFalse(p, objects.containsKey(p.getObjectId()), "already-initialized object");
|
||||
loadingObjects.getLast().parseBaseline(p);
|
||||
}
|
||||
|
||||
private void handleDeltasMessage(DeltasMessage p) {
|
||||
|
||||
@@ -27,111 +27,82 @@
|
||||
|
||||
package com.projectswg.utility.packets;
|
||||
|
||||
import com.projectswg.common.network.hcap.HcapInputStream;
|
||||
import com.projectswg.common.network.hcap.PacketRecord;
|
||||
import com.projectswg.common.network.packets.SWGPacket;
|
||||
import com.projectswg.utility.packets.PacketCaptureAnalysis.PacketCaptureAssertion;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.io.*;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
@SuppressWarnings({ "UseOfSystemOutOrSystemErr", "CallToPrintStackTrace" })
|
||||
public class ProcessPacketCapture {
|
||||
|
||||
public static void main(String [] args) throws IOException {
|
||||
try (DataInputStream packetCapture = new DataInputStream(new FileInputStream(new File(args[0])))) {
|
||||
byte version = packetCapture.readByte();
|
||||
assert version == 2;
|
||||
Map<String, Object> information = readSystemInformation(version, packetCapture);
|
||||
List<PacketRecord> packets = readPackets(packetCapture);
|
||||
System.out.println("Read " + packets.size() + " packets");
|
||||
public static void main(String [] args) {
|
||||
for (String arg : args) {
|
||||
if (!arg.endsWith(".hcap")) {
|
||||
System.out.println("Skipping " + arg + " - does not have .hcap extension");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args.length > 1 && args[1].equalsIgnoreCase("--printPackets")) {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yy HH:mm:ss.SSS").withZone((ZoneId) information.get("time.time_zone"));
|
||||
int packetNumber = 0;
|
||||
int packetPadding = (int) Math.floor(Math.log10(packets.size())) + 1;
|
||||
for (PacketRecord packet : packets) {
|
||||
System.out.printf("%s [%0"+packetPadding+"d] %s %s%n", formatter.format(packet.getTime()), packetNumber, (packet.isServer() ? "OUT: " : "IN: "), packet.parse());
|
||||
packetNumber++;
|
||||
}
|
||||
} else {
|
||||
PacketCaptureAnalysis analysis = PacketCaptureAnalysis.from(packets);
|
||||
System.out.println("Analysis:");
|
||||
System.out.println(" Objects Created: " + analysis.getObjectCreations());
|
||||
System.out.println(" Objects Deleted: " + analysis.getObjectDeletions() + " [Implicit: " + analysis.getObjectDeletionsImplicit() + "]");
|
||||
System.out.println(" Zone-ins: " + analysis.getCharacterZoneIns() + " " + analysis.getPlayers());
|
||||
System.out.println(" Errors: " + analysis.getErrors().size());
|
||||
for (PacketCaptureAssertion e : analysis.getErrors()) {
|
||||
System.err.println(" " + e.getMessage());
|
||||
System.err.println(" " + e.getPacket());
|
||||
try (HcapInputStream packetCapture = new HcapInputStream(new FileInputStream(new File(arg)))) {
|
||||
try (BufferedWriter output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(arg.replace(".hcap", ".txt"))), StandardCharsets.UTF_8))) {
|
||||
Map<String, Object> information = packetCapture.getSystemInformation();
|
||||
List<PacketRecord> packets = readPackets(packetCapture);
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yy HH:mm:ss.SSS").withZone((ZoneId) information.get("time.time_zone"));
|
||||
int packetNumber = 0;
|
||||
int packetPadding = (int) Math.floor(Math.log10(packets.size())) + 1;
|
||||
for (PacketRecord packet : packets) {
|
||||
SWGPacket parsed = packet.parse();
|
||||
String parsedInfo = (parsed == null) ? String.format("%08X", ByteBuffer.wrap(packet.getData()).order(ByteOrder.LITTLE_ENDIAN).getInt(2)) : parsed.toString();
|
||||
output.write(String.format("%s [%0"+packetPadding+"d] %s %s%n", formatter.format(packet.getTime()), packetNumber, (packet.isServer() ? "OUT: " : "IN: "), parsedInfo));
|
||||
packetNumber++;
|
||||
}
|
||||
|
||||
PacketCaptureAnalysis analysis = PacketCaptureAnalysis.from(packets);
|
||||
output.write(String.format("Read %d packets%n", packets.size()));
|
||||
output.write(String.format("Analysis:%n"));
|
||||
output.write(String.format(" Objects Created: %d%n", analysis.getObjectCreations()));
|
||||
output.write(String.format(" Objects Deleted: %d [Implicit: %d]%n", analysis.getObjectDeletions(), analysis.getObjectDeletionsImplicit()));
|
||||
output.write(String.format(" Zone-ins: %d %s%n", analysis.getCharacterZoneIns(), analysis.getPlayers()));
|
||||
output.write(String.format(" Errors: %d%n", analysis.getErrors().size()));
|
||||
for (PacketCaptureAssertion e : analysis.getErrors()) {
|
||||
output.write(" " + e.getMessage() + System.lineSeparator());
|
||||
output.write(" " + e.getPacket() + System.lineSeparator());
|
||||
}
|
||||
System.out.println("Wrote " + packets.size() + " packets with analysis to " + arg.replace(".hcap", ".txt"));
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, Object> readSystemInformation(byte version, DataInputStream packetCapture) throws IOException {
|
||||
int count = packetCapture.readByte();
|
||||
System.out.println("System Information:");
|
||||
Map<String, Object> information = new LinkedHashMap<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Map.Entry<String, Object> entry = parseEntry(version, packetCapture.readUTF());
|
||||
information.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
int maxLength = information.keySet().stream().mapToInt(String::length).max().orElse(10);
|
||||
for (Entry<String, Object> e : information.entrySet()) {
|
||||
System.out.printf(" %-"+maxLength+"s = %s%n", e.getKey(), e.getValue().toString());
|
||||
}
|
||||
return information;
|
||||
}
|
||||
|
||||
private static List<PacketRecord> readPackets(DataInputStream packetCapture) throws IOException {
|
||||
private static List<PacketRecord> readPackets(HcapInputStream packetCapture) throws IOException {
|
||||
List<PacketRecord> packets = new ArrayList<>(1024);
|
||||
while (packetCapture.available() >= 11) {
|
||||
boolean server = packetCapture.readBoolean();
|
||||
Instant time = Instant.ofEpochMilli(packetCapture.readLong());
|
||||
int dataLength = packetCapture.readUnsignedShort();
|
||||
byte [] data = new byte[dataLength];
|
||||
int n = packetCapture.read(data);
|
||||
while (n < dataLength)
|
||||
n += packetCapture.read(data, n, dataLength - n);
|
||||
assert n == dataLength;
|
||||
packets.add(new PacketRecord(server, time, data));
|
||||
PacketRecord record;
|
||||
while ((record = packetCapture.readPacket()) != null) {
|
||||
try {
|
||||
if (record.getData().length < 6)
|
||||
continue;
|
||||
record.parse();
|
||||
packets.add(record);
|
||||
} catch (BufferUnderflowException e) {
|
||||
System.err.printf("Packet parser failed for packet of length %d at %s%n", record.getData().length, record.getTime());
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
return packets;
|
||||
}
|
||||
|
||||
private static Map.Entry<String, Object> parseEntry(byte version, String str) {
|
||||
String [] keyValue = str.split("=", 2);
|
||||
assert keyValue.length == 2;
|
||||
String key = keyValue[0].toLowerCase(Locale.US);
|
||||
String value = keyValue[1];
|
||||
|
||||
if (version == 2) {
|
||||
switch (key) {
|
||||
case "time.current_time":
|
||||
return Map.entry(key, Instant.ofEpochMilli(Long.parseLong(value)));
|
||||
case "time.time_zone":
|
||||
return Map.entry(key, ZoneId.of(value.split(":")[0]));
|
||||
default:
|
||||
return Map.entry(key, value);
|
||||
}
|
||||
} else if (version == 3) {
|
||||
switch (key) {
|
||||
case "time.current_time":
|
||||
return Map.entry(key, Instant.parse(value));
|
||||
case "time.time_zone":
|
||||
return Map.entry(key, ZoneId.of(value));
|
||||
default:
|
||||
return Map.entry(key, value);
|
||||
}
|
||||
} else {
|
||||
return Map.entry(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user