mirror of
https://github.com/ProjectSWGCore/Holocore.git
synced 2026-01-17 00:06:00 -05:00
Changed Attributes(Im/Mutable) from Java to Kotlin
This commit is contained in:
@@ -6,8 +6,8 @@ plugins {
|
||||
id 'idea'
|
||||
id "com.github.johnrengelman.shadow" version "5.0.0"
|
||||
id "org.javamodularity.moduleplugin" version "1.5.0"
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.3.30'
|
||||
id "org.beryx.jlink" version "2.10.1"
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.3.31'
|
||||
id "org.beryx.jlink" version "2.10.2"
|
||||
}
|
||||
|
||||
mainClassName = 'holocore/com.projectswg.holocore.ProjectSWG'
|
||||
@@ -58,7 +58,7 @@ repositories {
|
||||
dependencies {
|
||||
compile project(':pswgcommon')
|
||||
|
||||
compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: '1.3.30'
|
||||
compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: '1.3.31'
|
||||
compile group: 'org.xerial', name: 'sqlite-jdbc', version: '3.23.1'
|
||||
compile group: 'org.mongodb', name: 'mongodb-driver-sync', version: '3.9.1'
|
||||
compile group: 'me.joshlarson', name: "fast-json", version: '3.0.0'
|
||||
|
||||
@@ -1,340 +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.support.data.collections;
|
||||
|
||||
import com.projectswg.common.encoding.Encodable;
|
||||
import com.projectswg.common.encoding.Encoder;
|
||||
import com.projectswg.common.encoding.StringType;
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Supports a list of elements which automatically sends data as a delta when changed for baselines.
|
||||
*
|
||||
* @param <E> Element that implements {@link Encodable} in order for data to be sent, or a basic
|
||||
* type.
|
||||
*/
|
||||
public class SWGList<E> extends CopyOnWriteArrayList<E> implements Encodable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final StringType strType;
|
||||
private final int view;
|
||||
private final int updateType;
|
||||
private final AtomicInteger updateCount;
|
||||
private final List<byte[]> deltas;
|
||||
private final List<byte[]> data;
|
||||
|
||||
private int deltaSize;
|
||||
private int dataSize;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SWGList} for the defined baseline with the given view and update. Note
|
||||
* that this is an extension of {@link AbstractList} and makes use of
|
||||
* {@link java.util.ArrayList}
|
||||
*
|
||||
* @param view The baseline number this list resides in
|
||||
* @param updateType The update variable used for sending a delta, it's the operand count that
|
||||
* this list resides at within the baseline
|
||||
*/
|
||||
public SWGList(int view, int updateType) {
|
||||
this(view, updateType, StringType.UNSPECIFIED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SWGList} with the given StringType to encode in. Note that this
|
||||
* constructor must be used if the elements within the list is a String.
|
||||
*
|
||||
* @param view The baseline number this list resides in
|
||||
* @param updateType The update number for this variable
|
||||
* @param strType The {@link StringType} of the string, required only if the element in the list
|
||||
* is a String as it's used for encoding either Unicode or ASCII characters
|
||||
*/
|
||||
public SWGList(int view, int updateType, StringType strType) {
|
||||
this.view = view;
|
||||
this.updateType = updateType;
|
||||
this.strType = strType;
|
||||
this.dataSize = 0;
|
||||
this.updateCount = new AtomicInteger(0);
|
||||
this.deltas = Collections.synchronizedList(new LinkedList<>());
|
||||
this.data = new ArrayList<>();
|
||||
this.deltaSize = 0;
|
||||
}
|
||||
|
||||
public void resetUpdateCount() {
|
||||
updateCount.set(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
add(size(), e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, E e) {
|
||||
super.add(index, e);
|
||||
updateCount.incrementAndGet();
|
||||
addObjectData(index, e, (byte) 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
// Sends a "change" delta
|
||||
E previous = super.set(index, element);
|
||||
if (previous != null) {
|
||||
removeData(index);
|
||||
}
|
||||
updateCount.incrementAndGet();
|
||||
addObjectData(index, element, (byte) 2);
|
||||
return previous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
int index = indexOf(o);
|
||||
if (index != -1) {
|
||||
remove(index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(int index) {
|
||||
E element = super.remove(index);
|
||||
if (element != null) {
|
||||
updateCount.incrementAndGet();
|
||||
removeObjectData(index);
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
return super.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of bytes based off of the elements within this Elements that are not of a
|
||||
* standard type handled by {@link Encoder} should implement the {@link Encodable} interface.
|
||||
*
|
||||
* @return Array of bytes with the size, update count, and encoded elements
|
||||
*/
|
||||
@Override
|
||||
public byte[] encode() {
|
||||
ByteBuffer buffer;
|
||||
synchronized (data) {
|
||||
if (dataSize == 0)
|
||||
return new byte[8];
|
||||
buffer = ByteBuffer.allocate(getLength()).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
buffer.putInt(data.size());
|
||||
buffer.putInt(updateCount.get());
|
||||
data.forEach(buffer::put);
|
||||
}
|
||||
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(NetBuffer data) {
|
||||
// We need specific type information
|
||||
throw new UnsupportedOperationException("Use decode(ByteBuffer data, Class<E> elementType) instead");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 8 + dataSize;
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data, StringType type) {
|
||||
int size = data.getInt();
|
||||
updateCount.set(data.getInt());
|
||||
NetBuffer buffer = NetBuffer.wrap(data);
|
||||
for (int i = 0; i < size; i++) {
|
||||
@SuppressWarnings("unchecked")
|
||||
E obj = (E) buffer.getString(type);
|
||||
add(obj);
|
||||
}
|
||||
clearDeltaQueue();
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data, Class<E> elementType) {
|
||||
int size = data.getInt();
|
||||
updateCount.set(data.getInt());
|
||||
|
||||
boolean encodable = Encodable.class.isAssignableFrom(elementType);
|
||||
NetBuffer wrap = NetBuffer.wrap(data);
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (!decodeElement(wrap, elementType, encodable))
|
||||
break;
|
||||
}
|
||||
clearDeltaQueue();
|
||||
}
|
||||
|
||||
private boolean decodeElement(NetBuffer wrap, Class<E> elementType, boolean encodable) {
|
||||
if (encodable) {
|
||||
try {
|
||||
E instance = elementType.getConstructor().newInstance();
|
||||
if (instance instanceof Encodable) {
|
||||
((Encodable) instance).decode(wrap);
|
||||
add(instance);
|
||||
}
|
||||
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
|
||||
Log.e(e);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Object o = wrap.getGeneric(elementType);
|
||||
if (o != null && elementType.isAssignableFrom(o.getClass())) {
|
||||
// Shouldn't be possible to get an exception with the isAssignableFrom check
|
||||
@SuppressWarnings("unchecked")
|
||||
E obj = (E) o;
|
||||
add(obj);
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void sendRefreshedListData(SWGObject target) {
|
||||
clearDeltaQueue();
|
||||
ByteBuffer buffer;
|
||||
synchronized (data) {
|
||||
updateCount.addAndGet(data.size());
|
||||
|
||||
buffer = ByteBuffer.allocate(11 + dataSize).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putInt(data.size() + 1);
|
||||
buffer.putInt(updateCount.get());
|
||||
buffer.put((byte) 3);
|
||||
buffer.putShort((short) data.size());
|
||||
for (byte[] bytes : data) {
|
||||
buffer.put(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
target.sendDelta(view, updateType, buffer.array());
|
||||
}
|
||||
|
||||
public void sendDeltaMessage(SWGObject target) {
|
||||
if (deltas.isEmpty())
|
||||
return;
|
||||
|
||||
target.sendDelta(view, updateType, getDeltaData());
|
||||
// Clear the queue since the delta has been sent to observers through the builder
|
||||
clearDeltaQueue();
|
||||
}
|
||||
|
||||
public void clearDeltaQueue() {
|
||||
synchronized (deltas) {
|
||||
deltas.clear();
|
||||
deltaSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getDeltaData() {
|
||||
ByteBuffer buffer;
|
||||
|
||||
synchronized (deltas) {
|
||||
buffer = ByteBuffer.allocate(8 + deltaSize).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
buffer.putInt(deltas.size());
|
||||
buffer.putInt(updateCount.get());
|
||||
for (byte[] data : deltas) {
|
||||
buffer.put(data);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
private void createDeltaData(byte[] delta) {
|
||||
synchronized (deltas) {
|
||||
deltaSize += delta.length;
|
||||
deltas.add(delta);
|
||||
}
|
||||
}
|
||||
|
||||
private void addObjectData(int index, E obj, byte update) {
|
||||
byte[] encodedData = Encoder.encode(obj, strType);
|
||||
Objects.requireNonNull(encodedData, "Unable to encode obj");
|
||||
|
||||
synchronized (data) {
|
||||
dataSize += encodedData.length;
|
||||
data.add(index, encodedData);
|
||||
}
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(encodedData.length + 3).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.put(update);
|
||||
buffer.putShort((short) index);
|
||||
buffer.put(encodedData);
|
||||
createDeltaData(buffer.array());
|
||||
}
|
||||
|
||||
private void removeObjectData(int index) {
|
||||
removeData(index);
|
||||
|
||||
// Only the index is sent for removing data
|
||||
ByteBuffer buffer = ByteBuffer.allocate(3).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.put((byte) 0);
|
||||
buffer.putShort((short) index);
|
||||
createDeltaData(buffer.array());
|
||||
}
|
||||
|
||||
private void removeData(int index) {
|
||||
synchronized (data) {
|
||||
dataSize -= data.remove(index).length;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SWGList[0" + view + ':' + updateType + ']';
|
||||
}
|
||||
|
||||
public static SWGList<String> getSwgList(NetBuffer buffer, int num, int var, StringType type) {
|
||||
SWGList<String> list = new SWGList<>(num, var, type);
|
||||
list.decode(buffer.getBuffer(), type);
|
||||
return list;
|
||||
}
|
||||
|
||||
public static <T> SWGList<T> getSwgList(NetBuffer buffer, int num, int var, Class<T> c) {
|
||||
SWGList<T> list = new SWGList<>(num, var);
|
||||
list.decode(buffer.getBuffer(), c);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/***********************************************************************************
|
||||
* 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.collections
|
||||
|
||||
import com.projectswg.common.encoding.Encodable
|
||||
import com.projectswg.common.encoding.StringType
|
||||
import com.projectswg.common.network.NetBuffer
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
class SWGList<T: Any>: AbstractMutableList<T>, Encodable {
|
||||
|
||||
val page: Int
|
||||
val update: Int
|
||||
var updateCount: Int = 0
|
||||
private set
|
||||
|
||||
private val list: MutableList<T> = ArrayList()
|
||||
private val deltaQueue: MutableList<Byte> = ArrayList()
|
||||
private var deltaQueueCount: Int = 0
|
||||
private val lock = ReentrantLock()
|
||||
private val encoder: (NetBuffer, T) -> Unit
|
||||
private val decoder: (NetBuffer) -> T
|
||||
private val encodedLength: (T) -> Int
|
||||
|
||||
constructor(page: Int, update: Int, decoder: (NetBuffer) -> T, encoder: (NetBuffer, T) -> Unit, encodedLength: (T) -> Int = ::getMaxEncodedSize) {
|
||||
this.page = page
|
||||
this.update = update
|
||||
this.encoder = encoder
|
||||
this.decoder = decoder
|
||||
this.encodedLength = encodedLength
|
||||
}
|
||||
constructor(page: Int, update: Int, supplier: () -> T, encoder: (NetBuffer, T) -> Unit, encodedLength: (T) -> Int = ::getMaxEncodedSize) {
|
||||
this.page = page
|
||||
this.update = update
|
||||
this.encoder = encoder
|
||||
this.decoder = createDecoder(supplier)
|
||||
this.encodedLength = encodedLength
|
||||
}
|
||||
@JvmOverloads
|
||||
@Deprecated(message="use a lambda-based constructor")
|
||||
constructor(page: Int, update: Int, stringType: StringType = StringType.UNSPECIFIED):
|
||||
this(page, update, decoder={throw UnsupportedOperationException("don't know how to decode object")}, encoder=createDefaultEncoder<T>(stringType), encodedLength=createDefaultEncodedLength(stringType))
|
||||
|
||||
override val size: Int = list.size
|
||||
override fun isEmpty(): Boolean = list.isEmpty()
|
||||
override fun contains(element: T): Boolean = list.contains(element)
|
||||
override fun containsAll(elements: Collection<T>): Boolean = list.containsAll(elements)
|
||||
override fun get(index: Int): T = list[index]
|
||||
override fun indexOf(element: T): Int = list.indexOf(element)
|
||||
override fun lastIndexOf(element: T): Int = list.lastIndexOf(element)
|
||||
override fun iterator(): MutableIterator<T> = SWGListIterator(this, list)
|
||||
override fun listIterator(): MutableListIterator<T> = SWGListIterator(this, list)
|
||||
override fun listIterator(index: Int): MutableListIterator<T> = SWGListIterator(this, list)
|
||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> = throw UnsupportedOperationException("can't return mutable sublist")
|
||||
|
||||
// Add
|
||||
override fun addAll(index: Int, elements: Collection<T>): Boolean {
|
||||
lock.withLock {
|
||||
var indexMut = index
|
||||
for (e in elements) {
|
||||
addInsertDelta(indexMut++, e)
|
||||
}
|
||||
return list.addAll(index, elements)
|
||||
}
|
||||
}
|
||||
override fun addAll(elements: Collection<T>): Boolean {
|
||||
lock.withLock {
|
||||
var index = list.size
|
||||
for (e in elements) {
|
||||
addInsertDelta(index++, e)
|
||||
}
|
||||
return list.addAll(elements)
|
||||
}
|
||||
}
|
||||
override fun add(index: Int, element: T) {
|
||||
lock.withLock {
|
||||
addInsertDelta(index, element)
|
||||
list.add(index, element)
|
||||
}
|
||||
}
|
||||
override fun add(element: T): Boolean {
|
||||
lock.withLock {
|
||||
addInsertDelta(list.size, element)
|
||||
return list.add(element)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove
|
||||
override fun clear() {
|
||||
lock.withLock {
|
||||
for (index in (list.size-1)..0)
|
||||
addRemoveDelta(index)
|
||||
list.clear()
|
||||
}
|
||||
}
|
||||
override fun retainAll(elements: Collection<T>): Boolean {
|
||||
lock.withLock {
|
||||
var changed = false
|
||||
for (index in (list.size-1)..0) {
|
||||
if (list[index] in elements) {
|
||||
addRemoveDelta(index)
|
||||
list.removeAt(index)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
}
|
||||
override fun remove(element: T): Boolean {
|
||||
lock.withLock {
|
||||
val index = list.indexOf(element)
|
||||
if (index != -1) {
|
||||
addRemoveDelta(index)
|
||||
list.removeAt(index)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
override fun removeAll(elements: Collection<T>): Boolean {
|
||||
lock.withLock {
|
||||
var changed = false
|
||||
for (e in elements) {
|
||||
if (remove(e))
|
||||
changed = true
|
||||
}
|
||||
return changed
|
||||
}
|
||||
}
|
||||
override fun removeAt(index: Int): T {
|
||||
lock.withLock {
|
||||
addRemoveDelta(index)
|
||||
return list.removeAt(index)
|
||||
}
|
||||
}
|
||||
|
||||
// Set
|
||||
override fun set(index: Int, element: T): T {
|
||||
lock.withLock {
|
||||
addSetDelta(index, element)
|
||||
return list.set(index, element)
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(): ByteArray {
|
||||
lock.withLock {
|
||||
with(NetBuffer.allocate(8 + list.sumBy(encodedLength))) {
|
||||
addInt(list.size)
|
||||
addInt(updateCount)
|
||||
list.forEach { encoder(this, it) }
|
||||
return array()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun decode(buffer: NetBuffer) {
|
||||
lock.withLock {
|
||||
val size = buffer.int
|
||||
updateCount = buffer.int
|
||||
for (index in 0 until size) {
|
||||
list.add(decoder(buffer))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLength(): Int {
|
||||
lock.withLock {
|
||||
return 8 + list.sumBy(encodedLength)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addRemoveDelta(index: Int) {
|
||||
deltaQueue.add(0)
|
||||
deltaQueue.add(index.toByte())
|
||||
deltaQueue.add(index.ushr(8).toByte())
|
||||
deltaQueueCount++
|
||||
updateCount++
|
||||
}
|
||||
|
||||
private fun addInsertDelta(index: Int, value: T) {
|
||||
val encoded = NetBuffer.allocate(encodedLength(value))
|
||||
encoder(encoded, value)
|
||||
|
||||
deltaQueue.add(1)
|
||||
deltaQueue.add(index.toByte())
|
||||
deltaQueue.add(index.ushr(8).toByte())
|
||||
deltaQueue.addAll(encoded.array().asList())
|
||||
deltaQueueCount++
|
||||
updateCount++
|
||||
}
|
||||
|
||||
private fun addSetDelta(index: Int, value: T) {
|
||||
val encoded = NetBuffer.allocate(encodedLength(value))
|
||||
encoder(encoded, value)
|
||||
|
||||
deltaQueue.add(2)
|
||||
deltaQueue.add(index.toByte())
|
||||
deltaQueue.add(index.ushr(8).toByte())
|
||||
deltaQueue.addAll(encoded.array().asList())
|
||||
deltaQueueCount++
|
||||
updateCount++
|
||||
}
|
||||
|
||||
fun clearDeltaQueue() {
|
||||
lock.withLock {
|
||||
deltaQueue.clear()
|
||||
deltaQueueCount = 0
|
||||
}
|
||||
}
|
||||
|
||||
fun sendRefreshedListData(obj: SWGObject) {
|
||||
lock.withLock {
|
||||
deltaQueue.clear()
|
||||
deltaQueueCount = 0
|
||||
|
||||
updateCount += list.size
|
||||
with(NetBuffer.allocate(11 + list.sumBy(encodedLength))) {
|
||||
addInt(list.size+1)
|
||||
addInt(updateCount)
|
||||
addByte(3)
|
||||
addShort(list.size)
|
||||
list.forEach { encoder(this, it) }
|
||||
obj.sendDelta(page, update, array())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun sendDeltaMessage(obj: SWGObject) {
|
||||
lock.withLock {
|
||||
with(NetBuffer.allocate(8 + deltaQueue.size)) {
|
||||
addInt(deltaQueueCount)
|
||||
addInt(updateCount)
|
||||
addRawArray(deltaQueue.toByteArray())
|
||||
obj.sendDelta(page, update, array())
|
||||
}
|
||||
|
||||
deltaQueue.clear()
|
||||
deltaQueueCount = 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean = other is SWGList<*> && page == other.page && update == other.update && list == other.list
|
||||
override fun hashCode(): Int = page * 10 + update
|
||||
override fun toString(): String = list.toString()
|
||||
|
||||
class SWGListIterator<T: Any>(private val swgList: SWGList<T>, private val list: List<T>) : AbstractIterator<T>(), MutableIterator<T>, MutableListIterator<T> {
|
||||
|
||||
override fun hasPrevious(): Boolean {
|
||||
return position > 0 && list.isNotEmpty()
|
||||
}
|
||||
|
||||
override fun nextIndex(): Int {
|
||||
return position
|
||||
}
|
||||
|
||||
override fun previous(): T {
|
||||
position--
|
||||
return list[--position]
|
||||
}
|
||||
|
||||
override fun previousIndex(): Int {
|
||||
return position-1
|
||||
}
|
||||
|
||||
override fun add(element: T) {
|
||||
swgList.add(position, element)
|
||||
}
|
||||
|
||||
override fun set(element: T) {
|
||||
assert(position > 0)
|
||||
swgList[position-1] = element
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
assert(position > 0)
|
||||
swgList.removeAt(--position)
|
||||
}
|
||||
|
||||
private var position = 0
|
||||
|
||||
override fun computeNext() {
|
||||
val value = list.getOrNull(position++) ?: return done()
|
||||
setNext(value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun getSwgList(buffer: NetBuffer, num: Int, `var`: Int, type: StringType): SWGList<String> {
|
||||
val list = SWGList<String>(num, `var`, type)
|
||||
// list.decode(buffer.buffer, type)
|
||||
return list
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun <T: Any> getSwgList(buffer: NetBuffer, num: Int, `var`: Int, c: Class<T>): SWGList<T> {
|
||||
val list = SWGList<T>(num, `var`)
|
||||
// list.decode(buffer.buffer, c)
|
||||
return list
|
||||
}
|
||||
|
||||
fun createByteList(page: Int, update: Int): SWGList<Byte> = SWGList(page, update, NetBuffer::getByte, { buf, b -> buf.addByte(b.toInt())}, {1})
|
||||
fun createShortList(page: Int, update: Int): SWGList<Short> = SWGList(page, update, NetBuffer::getShort, { buf, s -> buf.addShort(s.toInt())}, {2})
|
||||
fun createIntList(page: Int, update: Int): SWGList<Int> = SWGList(page, update, NetBuffer::getInt, NetBuffer::addInt) {4}
|
||||
fun createLongList(page: Int, update: Int): SWGList<Long> = SWGList(page, update, NetBuffer::getLong, NetBuffer::addLong) {8}
|
||||
fun createFloatList(page: Int, update: Int): SWGList<Float> = SWGList(page, update, NetBuffer::getFloat, NetBuffer::addFloat) {4}
|
||||
fun createDoubleList(page: Int, update: Int): SWGList<Double> = SWGList(page, update, {buf -> buf.float.toDouble()}, {buf, d -> buf.addFloat(d.toFloat())}, {8})
|
||||
fun <T: Encodable> createEncodableList(page: Int, update: Int, supplier: () -> T): SWGList<T> = SWGList(page, update, supplier, NetBuffer::addEncodable, Encodable::getLength)
|
||||
fun createAsciiList(page: Int, update: Int): SWGList<String> = SWGList(page, update, NetBuffer::getAscii, NetBuffer::addAscii) {2+it.length}
|
||||
fun createUnicodeList(page: Int, update: Int): SWGList<String> = SWGList(page, update, NetBuffer::getUnicode, NetBuffer::addUnicode) {4+it.length*2}
|
||||
|
||||
private fun <T: Any> createDefaultEncoder(stringType: StringType): (NetBuffer, T) -> Unit =
|
||||
{ buffer: NetBuffer, obj: T ->
|
||||
when (obj) {
|
||||
is Boolean -> buffer.addBoolean(obj)
|
||||
is Byte -> buffer.addByte(obj.toInt())
|
||||
is Short -> buffer.addShort(obj.toInt())
|
||||
is Int -> buffer.addInt(obj)
|
||||
is Long -> buffer.addLong(obj)
|
||||
is Float -> buffer.addFloat(obj)
|
||||
is Double -> buffer.addFloat(obj.toFloat())
|
||||
is Encodable -> buffer.addEncodable(obj)
|
||||
is String -> {
|
||||
when (stringType) {
|
||||
StringType.ASCII -> buffer.addAscii(obj)
|
||||
StringType.UNICODE -> buffer.addUnicode(obj)
|
||||
else -> throw UnsupportedOperationException("must specify string type to encode a string")
|
||||
}
|
||||
}
|
||||
else -> throw UnsupportedOperationException("don't know how to encode $obj")
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T: Any> createDecoder(supplier: () -> T): (NetBuffer) -> T = { buffer: NetBuffer ->
|
||||
val ret = supplier()
|
||||
if (ret is Encodable)
|
||||
ret.decode(buffer)
|
||||
else
|
||||
throw IllegalArgumentException("invalid type - not encodable: $ret")
|
||||
ret
|
||||
}
|
||||
|
||||
private fun <T: Any> createDefaultEncodedLength(stringType: StringType): (T) -> Int =
|
||||
{ obj: T ->
|
||||
when (obj) {
|
||||
is Boolean -> 1
|
||||
is Byte -> 1
|
||||
is Short -> 2
|
||||
is Int -> 4
|
||||
is Long -> 8
|
||||
is Float -> 4
|
||||
is Double -> 8
|
||||
is Encodable -> obj.length
|
||||
is String -> {
|
||||
when (stringType) {
|
||||
StringType.ASCII -> 2 + obj.length
|
||||
StringType.UNICODE -> 4 + obj.length * 2
|
||||
else -> throw UnsupportedOperationException("must specify string type to encode a string")
|
||||
}
|
||||
}
|
||||
else -> throw UnsupportedOperationException("don't know how to encode $obj")
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> getMaxEncodedSize(item: T): Int {
|
||||
return when (item) {
|
||||
is Boolean -> 1
|
||||
is Byte -> 1
|
||||
is Short -> 2
|
||||
is Int -> 4
|
||||
is Long -> 8
|
||||
is Float -> 4
|
||||
is Double -> 8
|
||||
is Encodable -> item.length
|
||||
is String -> 4 + item.length*2
|
||||
else -> throw UnsupportedOperationException("don't know how to encode $item")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -34,13 +34,17 @@ import com.mongodb.client.model.Indexes
|
||||
import org.bson.Document
|
||||
import java.util.*
|
||||
|
||||
class PswgConfigDatabase(private val collection: MongoCollection<Document>){
|
||||
/**
|
||||
* Empty config database that only returns the defaults
|
||||
*/
|
||||
class PswgConfigDatabase(private val collection: MongoCollection<Document>?) {
|
||||
|
||||
init {
|
||||
collection.createIndex(Indexes.ascending("package"), IndexOptions().unique(true))
|
||||
collection?.createIndex(Indexes.ascending("package"), IndexOptions().unique(true))
|
||||
}
|
||||
|
||||
fun getString(o: Any, key: String, def: String): String {
|
||||
collection ?: return def
|
||||
for (config in getConfigurations(o)) {
|
||||
if (config.containsKey(key))
|
||||
return config.getString(key)
|
||||
@@ -49,6 +53,7 @@ class PswgConfigDatabase(private val collection: MongoCollection<Document>){
|
||||
}
|
||||
|
||||
fun getBoolean(o: Any, key: String, def: Boolean): Boolean {
|
||||
collection ?: return def
|
||||
for (config in getConfigurations(o)) {
|
||||
if (config.containsKey(key))
|
||||
return config.getBoolean(key)!!
|
||||
@@ -57,6 +62,7 @@ class PswgConfigDatabase(private val collection: MongoCollection<Document>){
|
||||
}
|
||||
|
||||
fun getInt(o: Any, key: String, def: Int): Int {
|
||||
collection ?: return def
|
||||
for (config in getConfigurations(o)) {
|
||||
if (config.containsKey(key))
|
||||
return config.getInteger(key)!!
|
||||
@@ -65,6 +71,7 @@ class PswgConfigDatabase(private val collection: MongoCollection<Document>){
|
||||
}
|
||||
|
||||
fun getDouble(o: Any, key: String, def: Double): Double {
|
||||
collection ?: return def
|
||||
for (config in getConfigurations(o)) {
|
||||
if (config.containsKey(key))
|
||||
return config.getDouble(key)!!
|
||||
@@ -72,15 +79,17 @@ class PswgConfigDatabase(private val collection: MongoCollection<Document>){
|
||||
return def
|
||||
}
|
||||
|
||||
fun getLong(o: Any, key: String, def: Long): Double {
|
||||
fun getLong(o: Any, key: String, def: Long): Long {
|
||||
collection ?: return def
|
||||
for (config in getConfigurations(o)) {
|
||||
if (config.containsKey(key))
|
||||
return config.getLong(key)!!.toDouble()
|
||||
return config.getLong(key)!!
|
||||
}
|
||||
return def.toDouble()
|
||||
return def
|
||||
}
|
||||
|
||||
private fun getConfigurations(o: Any): List<Document> {
|
||||
collection!! // Should be verified in calling functions
|
||||
var packageKey = if (o is Class<*>) o.packageName else o.javaClass.packageName
|
||||
require(packageKey.startsWith("com.projectswg.holocore")) { "packageKey must be a part of holocore, was: $packageKey" }
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.logging.Logger
|
||||
object PswgDatabase {
|
||||
|
||||
var config: PswgConfigDatabase? = null
|
||||
@NotNull get() = field!!
|
||||
@NotNull get() = field ?: PswgConfigDatabase(null)
|
||||
private set
|
||||
var users: PswgUserDatabase? = null
|
||||
@NotNull get() = field!!
|
||||
|
||||
@@ -25,59 +25,19 @@
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
|
||||
package com.projectswg.holocore.resources.support.objects.swg.creature.attributes;
|
||||
package com.projectswg.holocore.resources.support.objects.swg
|
||||
|
||||
public class AttributesImmutable implements Attributes {
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class BaselineDelegate<T>(private var value: T, private val page: Int, private val update: Int) {
|
||||
|
||||
private final int health;
|
||||
private final int healthRegen;
|
||||
private final int action;
|
||||
private final int actionRegen;
|
||||
private final int mind;
|
||||
private final int mindRegen;
|
||||
|
||||
AttributesImmutable(Attributes a) {
|
||||
this.health = a.getHealth();
|
||||
this.healthRegen = a.getHealthRegen();
|
||||
this.action = a.getAction();
|
||||
this.actionRegen = a.getActionRegen();
|
||||
this.mind = a.getMind();
|
||||
this.mindRegen = a.getMindRegen();
|
||||
operator fun getValue(thisRef: SWGObject, property: KProperty<*>): T {
|
||||
return value
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHealth() {
|
||||
return health;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHealthRegen() {
|
||||
return healthRegen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActionRegen() {
|
||||
return actionRegen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMind() {
|
||||
return mind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMindRegen() {
|
||||
return mindRegen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attributes getImmutable() {
|
||||
return this;
|
||||
operator fun setValue(thisRef: SWGObject, property: KProperty<*>, value: T) {
|
||||
this.value = value
|
||||
thisRef.sendDelta(page, update, value)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -79,8 +79,8 @@ class CreatureObjectSharedNP implements Persistable, MongoPersistable {
|
||||
|
||||
private AttributesMutable attributes;
|
||||
private AttributesMutable maxAttributes;
|
||||
private SWGList<Equipment> equipmentList = new SWGList<>(6, 23);
|
||||
private SWGList<Equipment> appearanceList = new SWGList<>(6, 33);
|
||||
private SWGList<Equipment> equipmentList = SWGList.Companion.createEncodableList(6, 23, Equipment::new);
|
||||
private SWGList<Equipment> appearanceList = SWGList.Companion.createEncodableList(6, 33, Equipment::new);
|
||||
|
||||
private SWGMap<CRC, Buff> buffs = new SWGMap<>(6, 26);
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/***********************************************************************************
|
||||
* 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:></http:>//www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
package com.projectswg.holocore.resources.support.objects.swg.creature.attributes
|
||||
|
||||
interface Attributes {
|
||||
|
||||
val health: Int
|
||||
val healthRegen: Int
|
||||
val action: Int
|
||||
val actionRegen: Int
|
||||
val mind: Int
|
||||
val mindRegen: Int
|
||||
val immutable: Attributes
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/***********************************************************************************
|
||||
* 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:></http:>//www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
package com.projectswg.holocore.resources.support.objects.swg.creature.attributes
|
||||
|
||||
class AttributesImmutable internal constructor(a: Attributes) : Attributes {
|
||||
|
||||
override val health: Int = a.health
|
||||
override val healthRegen: Int = a.healthRegen
|
||||
override val action: Int = a.action
|
||||
override val actionRegen: Int = a.actionRegen
|
||||
override val mind: Int = a.mind
|
||||
override val mindRegen: Int = a.mindRegen
|
||||
override val immutable = this
|
||||
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
/***********************************************************************************
|
||||
* 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.creature.attributes;
|
||||
|
||||
import com.projectswg.common.data.encodables.mongo.MongoData;
|
||||
import com.projectswg.common.data.encodables.mongo.MongoPersistable;
|
||||
import com.projectswg.common.encoding.Encodable;
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.common.network.NetBufferStream;
|
||||
import com.projectswg.common.persistable.Persistable;
|
||||
import com.projectswg.holocore.resources.support.data.collections.SWGList;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
|
||||
|
||||
public class AttributesMutable implements Attributes, Encodable, Persistable, MongoPersistable {
|
||||
|
||||
/*
|
||||
0 - health
|
||||
1 - health regen
|
||||
2 - action
|
||||
3 - action regen
|
||||
4 - mind
|
||||
5 - mind regen
|
||||
*/
|
||||
|
||||
private final SWGObject obj;
|
||||
private SWGList<Integer> ham;
|
||||
|
||||
public AttributesMutable(SWGObject obj, int type, int update) {
|
||||
this.obj = obj;
|
||||
this.ham = new SWGList<>(type, update);
|
||||
for (int i = 0; i < 6; i++)
|
||||
ham.add(0);
|
||||
ham.clearDeltaQueue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized int getHealth() {
|
||||
return ham.get(0);
|
||||
}
|
||||
|
||||
public final synchronized void setHealth(int health) {
|
||||
if (getHealth() == health)
|
||||
return;
|
||||
ham.set(0, health);
|
||||
ham.sendDeltaMessage(obj);
|
||||
}
|
||||
|
||||
public final synchronized void modifyHealth(int health, int max) {
|
||||
setHealth(Math.max(0, Math.min(max, getHealth()+health)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized int getHealthRegen() {
|
||||
return ham.get(1);
|
||||
}
|
||||
|
||||
public final synchronized void setHealthRegen(int healthRegen) {
|
||||
if (getHealthRegen() == healthRegen)
|
||||
return;
|
||||
ham.set(1, healthRegen);
|
||||
ham.sendDeltaMessage(obj);
|
||||
}
|
||||
|
||||
public final synchronized void modifyHealthRegen(int healthRegen, int max) {
|
||||
setHealthRegen(Math.max(0, Math.min(max, getHealthRegen()+healthRegen)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized int getAction() {
|
||||
return ham.get(2);
|
||||
}
|
||||
|
||||
public final synchronized void setAction(int action) {
|
||||
if (getAction() == action)
|
||||
return;
|
||||
ham.set(2, action);
|
||||
ham.sendDeltaMessage(obj);
|
||||
}
|
||||
|
||||
public final synchronized void modifyAction(int action, int max) {
|
||||
setAction(Math.max(0, Math.min(max, getAction()+action)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized int getActionRegen() {
|
||||
return ham.get(3);
|
||||
}
|
||||
|
||||
public final synchronized void setActionRegen(int actionRegen) {
|
||||
if (getActionRegen() == actionRegen)
|
||||
return;
|
||||
ham.set(3, actionRegen);
|
||||
ham.sendDeltaMessage(obj);
|
||||
}
|
||||
|
||||
public final synchronized void modifyActionRegen(int actionRegen, int max) {
|
||||
setActionRegen(Math.max(0, Math.min(max, getActionRegen()+actionRegen)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized int getMind() {
|
||||
return ham.get(4);
|
||||
}
|
||||
|
||||
public final synchronized void setMind(int mind) {
|
||||
if (getMind() == mind)
|
||||
return;
|
||||
ham.set(4, mind);
|
||||
ham.sendDeltaMessage(obj);
|
||||
}
|
||||
|
||||
public final synchronized void modifyMind(int mind, int max) {
|
||||
setMind(Math.max(0, Math.min(max, getMind()+mind)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized int getMindRegen() {
|
||||
return ham.get(5);
|
||||
}
|
||||
|
||||
public final synchronized void setMindRegen(int mindRegen) {
|
||||
if (getMindRegen() == mindRegen)
|
||||
return;
|
||||
ham.set(5, mindRegen);
|
||||
ham.sendDeltaMessage(obj);
|
||||
}
|
||||
|
||||
public final synchronized void modifyMindRegen(int mindRegen, int max) {
|
||||
setMindRegen(Math.max(0, Math.min(max, getMindRegen()+mindRegen)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attributes getImmutable() {
|
||||
return new AttributesImmutable(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMongo(MongoData data) {
|
||||
setHealth(data.getInteger("health", 0));
|
||||
setHealthRegen(data.getInteger("healthRegen", 0));
|
||||
setAction(data.getInteger("action", 0));
|
||||
setActionRegen(data.getInteger("actionRegen", 0));
|
||||
setMind(data.getInteger("mind", 0));
|
||||
setMindRegen(data.getInteger("mindRegen", 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putInteger("health", getHealth());
|
||||
data.putInteger("healthRegen", getHealthRegen());
|
||||
data.putInteger("action", getAction());
|
||||
data.putInteger("actionRegen", getActionRegen());
|
||||
data.putInteger("mind", getMind());
|
||||
data.putInteger("mindRegen", getMindRegen());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(NetBufferStream stream) {
|
||||
stream.getByte();
|
||||
setHealth(stream.getInt());
|
||||
setHealthRegen(stream.getInt());
|
||||
setAction(stream.getInt());
|
||||
setActionRegen(stream.getInt());
|
||||
setMind(stream.getInt());
|
||||
setMindRegen(stream.getInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(NetBufferStream stream) {
|
||||
stream.addByte(0);
|
||||
stream.addInt(getHealth());
|
||||
stream.addInt(getHealthRegen());
|
||||
stream.addInt(getAction());
|
||||
stream.addInt(getActionRegen());
|
||||
stream.addInt(getMind());
|
||||
stream.addInt(getMindRegen());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(NetBuffer data) {
|
||||
SWGList<Integer> hamDecoded = SWGList.getSwgList(data, 0, 0, Integer.class);
|
||||
setHealth(hamDecoded.get(0));
|
||||
setHealthRegen(hamDecoded.get(1));
|
||||
setAction(hamDecoded.get(2));
|
||||
setActionRegen(hamDecoded.get(3));
|
||||
setMind(hamDecoded.get(4));
|
||||
setMindRegen(hamDecoded.get(5));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encode() {
|
||||
return ham.encode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return ham.getLength();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/***********************************************************************************
|
||||
* 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:></http:>//www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
package com.projectswg.holocore.resources.support.objects.swg.creature.attributes
|
||||
|
||||
import com.projectswg.common.data.encodables.mongo.MongoData
|
||||
import com.projectswg.common.data.encodables.mongo.MongoPersistable
|
||||
import com.projectswg.common.encoding.Encodable
|
||||
import com.projectswg.common.network.NetBuffer
|
||||
import com.projectswg.common.network.NetBufferStream
|
||||
import com.projectswg.common.persistable.Persistable
|
||||
import com.projectswg.holocore.resources.support.data.collections.SWGList
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject
|
||||
import java.util.concurrent.locks.Lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class AttributesMutable(obj: SWGObject, type: Int, update: Int) : Attributes, Encodable, Persistable, MongoPersistable {
|
||||
|
||||
private val ham: SWGList<Int> = SWGList.createIntList(type, update)
|
||||
private val lock = ReentrantLock()
|
||||
|
||||
override var health by SWGListDelegate(obj, lock, ham, 0)
|
||||
override var healthRegen by SWGListDelegate(obj, lock, ham, 1)
|
||||
override var action by SWGListDelegate(obj, lock, ham, 2)
|
||||
override var actionRegen by SWGListDelegate(obj, lock, ham, 3)
|
||||
override var mind by SWGListDelegate(obj, lock, ham, 4)
|
||||
override var mindRegen by SWGListDelegate(obj, lock, ham, 5)
|
||||
override val immutable
|
||||
get() = AttributesImmutable(this)
|
||||
|
||||
init {
|
||||
for (i in 0..5)
|
||||
ham.add(0)
|
||||
ham.clearDeltaQueue()
|
||||
}
|
||||
|
||||
operator fun component1(): Int {
|
||||
return ham[0]
|
||||
}
|
||||
|
||||
operator fun component2(): Int {
|
||||
return ham[2]
|
||||
}
|
||||
|
||||
operator fun component3(): Int {
|
||||
return ham[4]
|
||||
}
|
||||
|
||||
fun modifyHealth(health: Int, max: Int) {
|
||||
lock.withLock { this.health = this.health.addUntilMax(health, max) }
|
||||
}
|
||||
|
||||
fun modifyHealthRegen(healthRegen: Int, max: Int) {
|
||||
lock.withLock { this.healthRegen = this.healthRegen.addUntilMax(healthRegen, max) }
|
||||
}
|
||||
|
||||
fun modifyAction(action: Int, max: Int) {
|
||||
lock.withLock { this.action = this.action.addUntilMax(action, max) }
|
||||
}
|
||||
|
||||
fun modifyActionRegen(actionRegen: Int, max: Int) {
|
||||
lock.withLock { this.actionRegen = this.actionRegen.addUntilMax(actionRegen, max) }
|
||||
}
|
||||
|
||||
fun modifyMind(mind: Int, max: Int) {
|
||||
lock.withLock { this.mind = this.mind.addUntilMax(mind, max) }
|
||||
}
|
||||
|
||||
fun modifyMindRegen(mindRegen: Int, max: Int) {
|
||||
lock.withLock { this.mindRegen = this.mindRegen.addUntilMax(mindRegen, max) }
|
||||
}
|
||||
|
||||
override fun readMongo(data: MongoData) {
|
||||
health = data.getInteger("health", 0)
|
||||
healthRegen = data.getInteger("healthRegen", 0)
|
||||
action = data.getInteger("action", 0)
|
||||
actionRegen = data.getInteger("actionRegen", 0)
|
||||
mind = data.getInteger("mind", 0)
|
||||
mindRegen = data.getInteger("mindRegen", 0)
|
||||
}
|
||||
|
||||
override fun saveMongo(data: MongoData) {
|
||||
data.putInteger("health", health)
|
||||
data.putInteger("healthRegen", healthRegen)
|
||||
data.putInteger("action", action)
|
||||
data.putInteger("actionRegen", actionRegen)
|
||||
data.putInteger("mind", mind)
|
||||
data.putInteger("mindRegen", mindRegen)
|
||||
}
|
||||
|
||||
override fun read(stream: NetBufferStream) {
|
||||
stream.byte
|
||||
health = stream.int
|
||||
healthRegen = stream.int
|
||||
action = stream.int
|
||||
actionRegen = stream.int
|
||||
mind = stream.int
|
||||
mindRegen = stream.int
|
||||
}
|
||||
|
||||
override fun save(stream: NetBufferStream) {
|
||||
stream.addByte(0)
|
||||
stream.addInt(health)
|
||||
stream.addInt(healthRegen)
|
||||
stream.addInt(action)
|
||||
stream.addInt(actionRegen)
|
||||
stream.addInt(mind)
|
||||
stream.addInt(mindRegen)
|
||||
}
|
||||
|
||||
override fun encode(): ByteArray {
|
||||
return ham.encode()
|
||||
}
|
||||
|
||||
override fun decode(data: NetBuffer) {
|
||||
ham.decode(data)
|
||||
}
|
||||
|
||||
override fun getLength(): Int {
|
||||
return ham.length
|
||||
}
|
||||
|
||||
private fun Int.addUntilMax(num: Int, max: Int): Int = Math.max(0, Math.min(max, this + num))
|
||||
|
||||
private class SWGListDelegate(private val obj: SWGObject,
|
||||
private val lock: Lock,
|
||||
private val list: SWGList<Int>,
|
||||
private val index: Int) {
|
||||
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
|
||||
return list[index]
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
|
||||
if (list[index] != value) {
|
||||
lock.withLock {
|
||||
list[index] = value
|
||||
list.sendDeltaMessage(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,106 +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.support.objects.swg.intangible;
|
||||
|
||||
import com.projectswg.common.data.encodables.mongo.MongoData;
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.common.network.NetBufferStream;
|
||||
import com.projectswg.common.network.packets.swg.zone.baselines.Baseline.BaselineType;
|
||||
import com.projectswg.holocore.resources.support.global.network.BaselineBuilder;
|
||||
import com.projectswg.holocore.resources.support.global.player.Player;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
|
||||
|
||||
public class IntangibleObject extends SWGObject {
|
||||
|
||||
public static final int COUNT_PCD_STORED = 0;
|
||||
public static final int COUNT_PCD_CALLED = 1;
|
||||
|
||||
private int count = 0;
|
||||
|
||||
public IntangibleObject(long objectId) {
|
||||
super(objectId, BaselineType.ITNO);
|
||||
}
|
||||
|
||||
public IntangibleObject(long objectId, BaselineType objectType) {
|
||||
super(objectId, objectType);
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
sendDelta(3, 4, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBaseline3(Player target, BaselineBuilder bb) {
|
||||
super.createBaseline3(target, bb); // 4 variables
|
||||
bb.addInt(count); // 4
|
||||
|
||||
bb.incrementOperandCount(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseBaseline3(NetBuffer buffer) {
|
||||
super.parseBaseline3(buffer);
|
||||
count = buffer.getInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveMongo(MongoData data) {
|
||||
super.saveMongo(data);
|
||||
{
|
||||
MongoData base3 = data.getDocument("base3");
|
||||
base3.putInteger("count", count);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMongo(MongoData data) {
|
||||
super.readMongo(data);
|
||||
{
|
||||
MongoData base3 = data.getDocument("base3");
|
||||
count = base3.getInteger("count", 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(NetBufferStream stream) {
|
||||
super.save(stream);
|
||||
stream.addByte(0);
|
||||
stream.addInt(count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(NetBufferStream stream) {
|
||||
super.read(stream);
|
||||
stream.getByte();
|
||||
count = stream.getInt();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/***********************************************************************************
|
||||
* 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:></http:>//www.gnu.org/licenses/>. *
|
||||
*/
|
||||
package com.projectswg.holocore.resources.support.objects.swg.intangible
|
||||
|
||||
import com.projectswg.common.data.encodables.mongo.MongoData
|
||||
import com.projectswg.common.network.NetBuffer
|
||||
import com.projectswg.common.network.NetBufferStream
|
||||
import com.projectswg.common.network.packets.swg.zone.baselines.Baseline.BaselineType
|
||||
import com.projectswg.holocore.resources.support.global.network.BaselineBuilder
|
||||
import com.projectswg.holocore.resources.support.global.player.Player
|
||||
import com.projectswg.holocore.resources.support.objects.swg.BaselineDelegate
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject
|
||||
|
||||
open class IntangibleObject : SWGObject {
|
||||
|
||||
var count: Int by BaselineDelegate(value = 0, page = 3, update = 4)
|
||||
|
||||
constructor(objectId: Long) : super(objectId, BaselineType.ITNO)
|
||||
constructor(objectId: Long, objectType: BaselineType) : super(objectId, objectType)
|
||||
|
||||
override fun createBaseline3(target: Player, bb: BaselineBuilder) {
|
||||
super.createBaseline3(target, bb) // 4 variables
|
||||
bb.addInt(count) // 4
|
||||
|
||||
bb.incrementOperandCount(1)
|
||||
}
|
||||
|
||||
override fun parseBaseline3(buffer: NetBuffer) {
|
||||
super.parseBaseline3(buffer)
|
||||
count = buffer.int
|
||||
}
|
||||
|
||||
override fun saveMongo(data: MongoData) {
|
||||
super.saveMongo(data)
|
||||
run {
|
||||
val base3 = data.getDocument("base3")
|
||||
base3.putInteger("count", count)
|
||||
}
|
||||
}
|
||||
|
||||
override fun readMongo(data: MongoData) {
|
||||
super.readMongo(data)
|
||||
run {
|
||||
val base3 = data.getDocument("base3")
|
||||
count = base3.getInteger("count", 0)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val COUNT_PCD_STORED = 0
|
||||
const val COUNT_PCD_CALLED = 1
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,27 +27,26 @@
|
||||
|
||||
package com.projectswg.holocore.resources.support.data.collections;
|
||||
|
||||
import com.projectswg.common.encoding.StringType;
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.holocore.test.runners.TestRunnerNoIntents;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TestSWGList extends TestRunnerNoIntents {
|
||||
|
||||
@Test
|
||||
public void testAdd() {
|
||||
int size = 24;
|
||||
String[] strings = new String[24];
|
||||
String[] strings = new String[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
strings[i] = "test" + String.valueOf(i);
|
||||
strings[i] = "test" + i;
|
||||
}
|
||||
|
||||
SWGList<String> swgList = new SWGList<>(3, 6, StringType.ASCII);
|
||||
Collections.addAll(swgList, strings);
|
||||
SWGList<String> swgList = SWGList.Companion.createAsciiList(3, 6);
|
||||
swgList.addAll(List.of(strings));
|
||||
|
||||
Assert.assertArrayEquals(strings, swgList.toArray());
|
||||
|
||||
@@ -58,16 +57,46 @@ public class TestSWGList extends TestRunnerNoIntents {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncode() {
|
||||
public void testIteratorUpdate() {
|
||||
int size = 24;
|
||||
String[] strings = new String[24];
|
||||
List<String> strings = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
strings[i] = "test" + String.valueOf(i);
|
||||
strings.add("test" + i);
|
||||
}
|
||||
|
||||
SWGList<String> swgList = new SWGList<>(3, 6, StringType.ASCII);
|
||||
Collections.addAll(swgList, strings);
|
||||
swgList.encode();
|
||||
SWGList<String> swgList = SWGList.Companion.createAsciiList(3, 6);
|
||||
swgList.addAll(strings);
|
||||
|
||||
Assert.assertEquals(size, swgList.getUpdateCount());
|
||||
Assert.assertEquals(strings, swgList);
|
||||
for (ListIterator<String> it = swgList.listIterator(); it.hasNext(); ) {
|
||||
String str = it.next();
|
||||
it.set(str.replace('t', 'j'));
|
||||
}
|
||||
Assert.assertEquals(strings.stream().map(str -> str.replace('t', 'j')).collect(Collectors.toList()), swgList);
|
||||
Assert.assertEquals(size*2, swgList.getUpdateCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncode() {
|
||||
int size = 24;
|
||||
NetBuffer expected = NetBuffer.allocate(8 + 2*size + 5*10 + 6*(size-10));
|
||||
expected.addInt(size);
|
||||
expected.addInt(size);
|
||||
String[] strings = new String[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
strings[i] = "test" + i;
|
||||
expected.addAscii(strings[i]);
|
||||
}
|
||||
|
||||
SWGList<String> swgList = SWGList.Companion.createAsciiList(3, 6);
|
||||
Collections.addAll(swgList, strings);
|
||||
byte [] encoded = swgList.encode();
|
||||
Assert.assertArrayEquals(expected.array(), encoded);
|
||||
Assert.assertEquals(encoded.length, swgList.getLength());
|
||||
|
||||
SWGList<String> decodedList = SWGList.Companion.createAsciiList(3, 6);
|
||||
decodedList.decode(NetBuffer.wrap(encoded));
|
||||
Assert.assertEquals(swgList, decodedList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
package com.projectswg.holocore.test.runners;
|
||||
|
||||
import com.projectswg.holocore.resources.support.data.server_info.DataManager;
|
||||
import com.projectswg.holocore.resources.support.objects.ObjectCreator;
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
import me.joshlarson.jlcommon.log.log_wrapper.ConsoleLogWrapper;
|
||||
@@ -39,7 +38,6 @@ public abstract class TestRunner {
|
||||
public static void initializeStatic() {
|
||||
Log.clearWrappers();
|
||||
Log.addWrapper(new ConsoleLogWrapper());
|
||||
DataManager.initialize();
|
||||
}
|
||||
|
||||
protected static long getUniqueId() {
|
||||
|
||||
Reference in New Issue
Block a user