Merge pull request #73 from P0nk/view-all-char-fix
Fix 'View all characters' transition
This commit is contained in:
52
config.yaml
52
config.yaml
@@ -86,18 +86,18 @@ worlds:
|
|||||||
why_am_i_recommended: Welcome to Galicia!
|
why_am_i_recommended: Welcome to Galicia!
|
||||||
channels: 3
|
channels: 3
|
||||||
|
|
||||||
#Properties for El Nido 11
|
#Properties for Kastia 11
|
||||||
- flag: 0
|
- flag: 0
|
||||||
server_message: Welcome to El Nido!
|
server_message: Welcome to Kastia!
|
||||||
event_message: El Nido!
|
event_message: Kastia!
|
||||||
why_am_i_recommended: Welcome to El Nido!
|
why_am_i_recommended: Welcome to Kastia!
|
||||||
channels: 3
|
channels: 3
|
||||||
|
|
||||||
#Properties for Zenith 12
|
#Properties for Judis 12
|
||||||
- flag: 0
|
- flag: 0
|
||||||
server_message: Welcome to Zenith!
|
server_message: Welcome to Judis!
|
||||||
event_message: Zenith!
|
event_message: Judis!
|
||||||
why_am_i_recommended: Welcome to Zenith!
|
why_am_i_recommended: Welcome to Judis!
|
||||||
channels: 3
|
channels: 3
|
||||||
|
|
||||||
#Properties for Arcenia 13
|
#Properties for Arcenia 13
|
||||||
@@ -107,48 +107,48 @@ worlds:
|
|||||||
why_am_i_recommended: Welcome to Arcenia!
|
why_am_i_recommended: Welcome to Arcenia!
|
||||||
channels: 3
|
channels: 3
|
||||||
|
|
||||||
#Properties for Kastia 14
|
#Properties for Plana 14
|
||||||
- flag: 0
|
|
||||||
server_message: Welcome to Kastia!
|
|
||||||
event_message: Kastia!
|
|
||||||
why_am_i_recommended: Welcome to Kastia!
|
|
||||||
channels: 3
|
|
||||||
|
|
||||||
#Properties for Judis 15
|
|
||||||
- flag: 0
|
|
||||||
server_message: Welcome to Judis!
|
|
||||||
event_message: Judis!
|
|
||||||
why_am_i_recommended: Welcome to Judis!
|
|
||||||
channels: 3
|
|
||||||
|
|
||||||
#Properties for Plana 16
|
|
||||||
- flag: 0
|
- flag: 0
|
||||||
server_message: Welcome to Plana!
|
server_message: Welcome to Plana!
|
||||||
event_message: Plana!
|
event_message: Plana!
|
||||||
why_am_i_recommended: Welcome to Plana!
|
why_am_i_recommended: Welcome to Plana!
|
||||||
channels: 3
|
channels: 3
|
||||||
|
|
||||||
#Properties for Kalluna 17
|
#Properties for El Nido 15
|
||||||
|
- flag: 0
|
||||||
|
server_message: Welcome to El Nido!
|
||||||
|
event_message: El Nido!
|
||||||
|
why_am_i_recommended: Welcome to El Nido!
|
||||||
|
channels: 3
|
||||||
|
|
||||||
|
#Properties for Kalluna 16
|
||||||
- flag: 0
|
- flag: 0
|
||||||
server_message: Welcome to Kalluna!
|
server_message: Welcome to Kalluna!
|
||||||
event_message: Kalluna!
|
event_message: Kalluna!
|
||||||
why_am_i_recommended: Welcome to Kalluna!
|
why_am_i_recommended: Welcome to Kalluna!
|
||||||
channels: 3
|
channels: 3
|
||||||
|
|
||||||
#Properties for Stius 18
|
#Properties for Stius 17
|
||||||
- flag: 0
|
- flag: 0
|
||||||
server_message: Welcome to Stius!
|
server_message: Welcome to Stius!
|
||||||
event_message: Stius!
|
event_message: Stius!
|
||||||
why_am_i_recommended: Welcome to Stius!
|
why_am_i_recommended: Welcome to Stius!
|
||||||
channels: 3
|
channels: 3
|
||||||
|
|
||||||
#Properties for Croa 19
|
#Properties for Croa 18
|
||||||
- flag: 0
|
- flag: 0
|
||||||
server_message: Welcome to Croa!
|
server_message: Welcome to Croa!
|
||||||
event_message: Croa!
|
event_message: Croa!
|
||||||
why_am_i_recommended: Welcome to Croa!
|
why_am_i_recommended: Welcome to Croa!
|
||||||
channels: 3
|
channels: 3
|
||||||
|
|
||||||
|
#Properties for Zenith 19
|
||||||
|
- flag: 0
|
||||||
|
server_message: Welcome to Zenith!
|
||||||
|
event_message: Zenith!
|
||||||
|
why_am_i_recommended: Welcome to Zenith!
|
||||||
|
channels: 3
|
||||||
|
|
||||||
#Properties for Medere 20
|
#Properties for Medere 20
|
||||||
- flag: 0
|
- flag: 0
|
||||||
server_message: Welcome to Medere!
|
server_message: Welcome to Medere!
|
||||||
|
|||||||
@@ -1453,37 +1453,33 @@ public class Server {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public Pair<Pair<Integer, List<Character>>, List<Pair<Integer, List<Character>>>> loadAccountCharlist(Integer accountId, int visibleWorlds) {
|
public SortedMap<Integer, List<Character>> loadAccountCharlist(int accountId, int visibleWorlds) {
|
||||||
List<World> wlist = this.getWorlds();
|
List<World> worlds = this.getWorlds();
|
||||||
if (wlist.size() > visibleWorlds) {
|
if (worlds.size() > visibleWorlds) {
|
||||||
wlist = wlist.subList(0, visibleWorlds);
|
worlds = worlds.subList(0, visibleWorlds);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Pair<Integer, List<Character>>> accChars = new ArrayList<>(wlist.size() + 1);
|
SortedMap<Integer, List<Character>> worldChrs = new TreeMap<>();
|
||||||
int chrTotal = 0;
|
int chrTotal = 0;
|
||||||
List<Character> lastwchars = null;
|
|
||||||
|
|
||||||
lgnRLock.lock();
|
lgnRLock.lock();
|
||||||
try {
|
try {
|
||||||
for (World w : wlist) {
|
for (World world : worlds) {
|
||||||
List<Character> wchars = w.getAccountCharactersView(accountId);
|
List<Character> chrs = world.getAccountCharactersView(accountId);
|
||||||
if (wchars == null) {
|
if (chrs == null) {
|
||||||
if (!accountChars.containsKey(accountId)) {
|
if (!accountChars.containsKey(accountId)) {
|
||||||
accountCharacterCount.put(accountId, (short) 0);
|
accountCharacterCount.put(accountId, (short) 0);
|
||||||
accountChars.put(accountId, new HashSet<>()); // not advisable at all to write on the map on a read-protected environment
|
accountChars.put(accountId, new HashSet<>()); // not advisable at all to write on the map on a read-protected environment
|
||||||
} // yet it's known there's no problem since no other point in the source does
|
} // yet it's known there's no problem since no other point in the source does
|
||||||
} else if (!wchars.isEmpty()) { // this action.
|
} else if (!chrs.isEmpty()) { // this action.
|
||||||
lastwchars = wchars;
|
worldChrs.put(world.getId(), chrs);
|
||||||
|
|
||||||
accChars.add(new Pair<>(w.getId(), wchars));
|
|
||||||
chrTotal += wchars.size();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
lgnRLock.unlock();
|
lgnRLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Pair<>(new Pair<>(chrTotal, lastwchars), accChars);
|
return worldChrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Pair<Short, List<List<Character>>> loadAccountCharactersViewFromDb(int accId, int wlen) {
|
private static Pair<Short, List<List<Character>>> loadAccountCharactersViewFromDb(int accId, int wlen) {
|
||||||
|
|||||||
@@ -28,11 +28,12 @@ import net.AbstractPacketHandler;
|
|||||||
import net.packet.InPacket;
|
import net.packet.InPacket;
|
||||||
import net.server.Server;
|
import net.server.Server;
|
||||||
import tools.PacketCreator;
|
import tools.PacketCreator;
|
||||||
import tools.Pair;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
|
|
||||||
public final class ViewAllCharHandler extends AbstractPacketHandler {
|
public final class ViewAllCharHandler extends AbstractPacketHandler {
|
||||||
|
private static final int CHARACTER_LIMIT = 60; // Client will crash if sending 61 or more characters
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void handlePacket(InPacket p, Client c) {
|
public final void handlePacket(InPacket p, Client c) {
|
||||||
try {
|
try {
|
||||||
@@ -41,34 +42,88 @@ public final class ViewAllCharHandler extends AbstractPacketHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int accountId = c.getAccID();
|
SortedMap<Integer, List<Character>> worldChrs = Server.getInstance().loadAccountCharlist(c.getAccID(), c.getVisibleWorlds());
|
||||||
Pair<Pair<Integer, List<Character>>, List<Pair<Integer, List<Character>>>> loginBlob = Server.getInstance().loadAccountCharlist(accountId, c.getVisibleWorlds());
|
worldChrs = limitTotalChrs(worldChrs, CHARACTER_LIMIT);
|
||||||
|
|
||||||
List<Pair<Integer, List<Character>>> worldChars = loginBlob.getRight();
|
padChrsIfNeeded(worldChrs);
|
||||||
int chrTotal = loginBlob.getLeft().getLeft();
|
|
||||||
List<Character> lastwchars = loginBlob.getLeft().getRight();
|
|
||||||
|
|
||||||
if (chrTotal > 9) {
|
int totalWorlds = worldChrs.size();
|
||||||
int padRight = chrTotal % 3;
|
int totalChrs = countTotalChrs(worldChrs);
|
||||||
if (padRight > 0 && lastwchars != null) {
|
c.sendPacket(PacketCreator.showAllCharacter(totalWorlds, totalChrs));
|
||||||
Character chr = lastwchars.get(lastwchars.size() - 1);
|
|
||||||
|
|
||||||
for (int i = padRight; i < 3; i++) { // filling the remaining slots with the last character loaded
|
final boolean usePic = YamlConfig.config.server.ENABLE_PIC && !c.canBypassPic();
|
||||||
chrTotal++;
|
worldChrs.forEach((worldId, chrs) ->
|
||||||
lastwchars.add(chr);
|
c.sendPacket(PacketCreator.showAllCharacterInfo(worldId, chrs, usePic))
|
||||||
}
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int charsSize = chrTotal;
|
|
||||||
int unk = charsSize + (3 - charsSize % 3); //rowSize?
|
|
||||||
c.sendPacket(PacketCreator.showAllCharacter(charsSize, unk));
|
|
||||||
|
|
||||||
for (Pair<Integer, List<Character>> wchars : worldChars) {
|
|
||||||
c.sendPacket(PacketCreator.showAllCharacterInfo(wchars.getLeft(), wchars.getRight(), YamlConfig.config.server.ENABLE_PIC && !c.canBypassPic()));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static SortedMap<Integer, List<Character>> limitTotalChrs(SortedMap<Integer, List<Character>> worldChrs,
|
||||||
|
int limit) {
|
||||||
|
if (countTotalChrs(worldChrs) <= limit) {
|
||||||
|
return worldChrs;
|
||||||
|
} else {;
|
||||||
|
return cutAfterChrLimit(worldChrs, limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int countTotalChrs(Map<Integer, List<Character>> worldChrs) {
|
||||||
|
return worldChrs.values().stream()
|
||||||
|
.mapToInt(List::size)
|
||||||
|
.sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SortedMap<Integer, List<Character>> cutAfterChrLimit(SortedMap<Integer, List<Character>> worldChrs,
|
||||||
|
int limit) {
|
||||||
|
SortedMap<Integer, List<Character>> cappedCopy = new TreeMap<>();
|
||||||
|
int runningChrTotal = 0;
|
||||||
|
for (Map.Entry<Integer, List<Character>> entry : worldChrs.entrySet()) {
|
||||||
|
int worldId = entry.getKey();
|
||||||
|
List<Character> chrs = entry.getValue();
|
||||||
|
if (runningChrTotal + chrs.size() <= limit) { // Limit not reached, move them all
|
||||||
|
runningChrTotal += chrs.size();
|
||||||
|
cappedCopy.put(worldId, chrs);
|
||||||
|
} else { // Limit would be reached if all chrs were moved. Move just enough to fit within limit.
|
||||||
|
int remainingSlots = limit - runningChrTotal;
|
||||||
|
List<Character> lastChrs = chrs.subList(0, remainingSlots);
|
||||||
|
cappedCopy.put(worldId, lastChrs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cappedCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there are more characters than fits the screen (9), and you start scrolling down,
|
||||||
|
* the characters on the last row will not appear unless the row is completely filled.
|
||||||
|
* Meaning, if there are 1 or 2 characters remaining on the last row, they will not appear.
|
||||||
|
*
|
||||||
|
* @param totalChrs total amount of characters to display on 'View all characters' screen
|
||||||
|
* @return if we need to pad the last row to include the characters that would otherwise not appear
|
||||||
|
*/
|
||||||
|
private static void padChrsIfNeeded(SortedMap<Integer, List<Character>> worldChrs) {
|
||||||
|
while (shouldPadLastRow(countTotalChrs(worldChrs))) {
|
||||||
|
final List<Character> lastWorldChrs = getLastWorldChrs(worldChrs);
|
||||||
|
final Character lastChrForPadding = getLastItem(lastWorldChrs);
|
||||||
|
lastWorldChrs.add(lastChrForPadding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean shouldPadLastRow(int totalChrs) {
|
||||||
|
boolean shouldScroll = totalChrs > 9;
|
||||||
|
boolean isLastRowFilled = totalChrs % 3 == 0;
|
||||||
|
return shouldScroll && !isLastRowFilled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Character> getLastWorldChrs(SortedMap<Integer, List<Character>> worldChrs) {
|
||||||
|
return worldChrs.get(worldChrs.lastKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T getLastItem(List<T> list) {
|
||||||
|
Objects.requireNonNull(list);
|
||||||
|
return list.get(list.size() - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -515,8 +515,8 @@ public class World {
|
|||||||
return chrList;
|
return chrList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Character> getAccountCharactersView(Integer accountId) {
|
public List<Character> getAccountCharactersView(int accountId) {
|
||||||
List<Character> chrList;
|
final List<Character> chrList;
|
||||||
|
|
||||||
accountCharsLock.lock();
|
accountCharsLock.lock();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -2473,11 +2473,11 @@ public class PacketCreator {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Packet showAllCharacter(int chars, int unk) {
|
public static Packet showAllCharacter(int totalWorlds, int totalChrs) {
|
||||||
OutPacket p = OutPacket.create(SendOpcode.VIEW_ALL_CHAR);
|
OutPacket p = OutPacket.create(SendOpcode.VIEW_ALL_CHAR);
|
||||||
p.writeByte(chars > 0 ? 1 : 5); // 2: already connected to server, 3 : unk error (view-all-characters), 5 : cannot find any
|
p.writeByte(totalChrs > 0 ? 1 : 5); // 2: already connected to server, 3 : unk error (view-all-characters), 5 : cannot find any
|
||||||
p.writeInt(chars);
|
p.writeInt(totalWorlds);
|
||||||
p.writeInt(unk);
|
p.writeInt(totalChrs);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user