Public Repository for the Magicbane Shadowbane Emulator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

276 lines
8.2 KiB

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.net.client.msg;
import engine.Enum;
import engine.gameManager.DbManager;
import engine.net.AbstractConnection;
import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.Network;
import engine.net.client.Protocol;
import engine.objects.AbstractGameObject;
import engine.objects.City;
import engine.objects.Mine;
import engine.objects.Runegate;
import engine.session.Session;
import org.pmw.tinylog.Logger;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
public class CityDataMsg extends ClientNetMsg {
public static final long wdComp = 0xFF00FF0000000003L;
private static final byte ver = 1;
private static ByteBuffer cachedEnterWorld;
private static long cachedExpireTime;
private final boolean forEnterWorld;
private Session s;
private boolean updateCities = false;
private boolean updateRunegates = false;
private boolean updateMines = false;
/**
* This is the general purpose constructor.
*
* @param s Session
* @param forEnterWorld boolean flag
*/
public CityDataMsg(Session s, boolean forEnterWorld) {
super(Protocol.CITYDATA);
this.s = s;
this.forEnterWorld = forEnterWorld;
}
public CityDataMsg(boolean updateCities, boolean updateRunegates, boolean updateMines) {
super(Protocol.CITYDATA);
this.s = null;
this.forEnterWorld = false;
this.updateCities = updateCities;
this.updateRunegates = updateRunegates;
this.updateMines = updateMines;
}
/**
* This constructor is used by NetMsgFactory. It attempts to deserialize the
* ByteBuffer into a message. If a BufferUnderflow occurs (based on reading
* past the limit) then this constructor Throws that Exception to the
* caller.
*/
public CityDataMsg(AbstractConnection origin, ByteBufferReader reader) {
super(Protocol.CITYDATA, origin, reader);
this.forEnterWorld = false;
}
private static void attemptSerializeForEnterWorld(ByteBuffer bb) {
bb.clear();
ByteBufferWriter temp = new ByteBufferWriter(bb);
temp.put((byte) 0); // PAD
ArrayList<City> cityList = new ArrayList<>();
ConcurrentHashMap<Integer, AbstractGameObject> map = DbManager.getMap(Enum.GameObjectType.City);
for (AbstractGameObject ago : map.values())
if (ago.getObjectType().equals(Enum.GameObjectType.City))
cityList.add((City) ago);
temp.putInt(cityList.size());
for (City city : cityList)
City.serializeForClientMsg(city, temp);
temp.put((byte) 0); // PAD
// Serialize runegates
temp.putInt(Runegate._runegates.values().size());
for (Runegate runegate : Runegate._runegates.values()) {
runegate._serializeForEnterWorld(temp);
}
ArrayList<Mine> mineList = new ArrayList<>();
for (Mine toAdd : Mine.mineMap.keySet()) {
mineList.add(toAdd);
}
temp.putInt(mineList.size());
for (Mine mine : mineList) {
if(mine.getParentZone() != null && !mine.getParentZone().isContinent())
Mine.serializeForClientMsg(mine, temp);
}
temp.put((byte) 0); // PAD
}
@Override
protected int getPowerOfTwoBufferSize() {
return (18); // 2^14 == 16384
}
/**
* Serializes the subclass specific items to the supplied NetMsgWriter.
*/
@Override
protected void _serialize(ByteBufferWriter writer) {
if (this.forEnterWorld)
serializeForEnterWorld(writer);
else
serializeForMapUpdate(writer);
}
/**
* Specific use serializer
*
* @param writer
*/
private void serializeForMapUpdate(ByteBufferWriter writer) {
//Handle City updates
if (this.updateCities) {
writer.put((byte) 0);
ArrayList<City> cityList = new ArrayList<>();
ConcurrentHashMap<Integer, AbstractGameObject> map = DbManager.getMap(Enum.GameObjectType.City);
if (map != null) {
for (AbstractGameObject ago : map.values())
if (ago.getObjectType().equals(Enum.GameObjectType.City))
cityList.add((City) ago);
writer.putInt(cityList.size());
for (City city : cityList) {
City.serializeForClientMsg(city, writer);
}
} else {
Logger.error("missing city map");
writer.putInt(0);
}
} else
writer.put((byte) 1);
//Handle Runegate updates
if (this.updateRunegates) {
writer.put((byte) 0);
writer.putInt(Runegate._runegates.values().size());
for (Runegate runegate : Runegate._runegates.values()) {
runegate._serializeForEnterWorld(writer);
}
} else
writer.put((byte) 1);
//Handle Mine updates
try {
if (this.updateMines) {
ArrayList<Mine> mineList = new ArrayList<>();
for (Mine toAdd : Mine.mineMap.keySet()) {
mineList.add(toAdd);
}
writer.putInt(mineList.size());
for (Mine mine : mineList) {
if(mine.getParentZone() != null && !mine.getParentZone().isContinent())
Mine.serializeForClientMsg(mine, writer);
}
} else
writer.putInt(0);
} catch (Exception e) {
Logger.error(e);
}
writer.put((byte) 0); // PAD
}
/**
* Specific use serializer
*
* @param writer
*/
private void serializeForEnterWorld(ByteBufferWriter writer) {
if (s == null || s.getPlayerCharacter() == null)
return;
long startT = System.currentTimeMillis();
if (cachedEnterWorld == null) {
// Never before been cached, so init stuff
cachedEnterWorld = Network.byteBufferPool.getBuffer(19);
cachedExpireTime = 0L;
}
//Check to see if its time to renew cache.
if (cachedExpireTime < System.currentTimeMillis()) {
synchronized (cachedEnterWorld) {
CityDataMsg.attemptSerializeForEnterWorld(cachedEnterWorld);
}
cachedExpireTime = startT + 60000;
}
writer.putBB(cachedEnterWorld);
}
/**
* Deserializes the subclass specific items from the supplied NetMsgReader.
*/
@Override
protected void _deserialize(ByteBufferReader reader) {
// Client only sends 11 bytes.
byte type = reader.get();
if (type == 1) {
reader.get();
reader.get();
reader.getInt();
} else {
reader.get();
reader.getInt();
reader.get();
reader.getInt();
}
}
/**
* @return the s
*/
public Session getS() {
return s;
}
/**
* @return the forEnterWorld
*/
public boolean isForEnterWorld() {
return forEnterWorld;
}
public void updateCities(boolean value) {
this.updateCities = value;
}
public void updateRunegates(boolean value) {
this.updateRunegates = value;
}
public void updateMines(boolean value) {
this.updateMines = value;
}
}