Most visitors online was 12720 , on 2 May 2024
Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature currently requires accessing the site using the built-in Safari browser.
I have no idea. I never knew why they did that, it's so much slower than the strategy pattern.Why people are using switch statements in sources v140+ and not using array(strategy pattern like), with handlers behind a interface like OdinMS does in v62?
You must be registered to see links...
That's true.There's a lot of questionable code written in public Java Emulators, you need to keep in mind there are no qualifications required for developing and releasing a 'repack'/source, which is why you'll find a lot of non-Odin code doesn't keep up to coding conventions.
It's because Celino did it in v82 for MSEA and everyone thought it was good because Celino had it. There's a very hivemind thinking process here.
Also doesn't help that decompiled nexon binaries does this.
It's because Celino did it in v82 for MSEA and everyone thought it was good because Celino had it. There's a very hivemind thinking process here.
Also doesn't help that decompiled nexon binaries does this.
That is not true. It's because RMZero used Celino as base. And there's lots v83+ (excluding v83, more likely v111+) source/repack used RMZero's source as base.
It term of performance, you won't find much differences.
There's also lots bad practices in RMZero's source. I'm not saying he's not a good coder, but lot of his codes are really ugly.
It's because Celino did it in v82 for MSEA and everyone thought it was good because Celino had it. There's a very hivemind thinking process here.
Also doesn't help that decompiled nexon binaries does this.
@Override
public void messageReceived(final IoSession session, final Object message) throws Exception {
final SeekableLittleEndianAccessor slea = new GenericSeekableLittleEndianAccessor(new ByteArrayByteStream((byte[]) message));
final RecvPacketOpcode code = Header.get(slea.readShort());
if (code != null) {
final Client c = (Client) session.getAttribute(StringPool.CLIENT_KEY);
if (ServerConstants.enableHandledPacketLogging) {// Debugging
if (!code.isIgnorePacketSpamOrLog()) {
System.out.println(String.format("[%s] %s\nString : %s", code.name(), HexTool.toString((byte[]) message), HexTool.toStringFromAscii((byte[]) message)));
}
}
if (code.NeedsChecking()) {
if (!c.isLoggedIn()) {
session.close(true);
return;
}
/*
* if ((code.isCSOperation() && type == ServerType.CHANNEL) ||
* (!code.isCSOperation() && type != ServerType.CHANNEL)) {
* return; }
*/
}
final long cTime = System.currentTimeMillis();
final long Differences = cTime - c.LastCapturedTimeMillis_500MSThreshold;
if (Differences < 500) { // within 500ms
if (!code.isIgnorePacketSpamOrLog() && !c.FlagPendingDisconnection) { // Not move life, mob, summon, dragon
c.PacketSpamCountWithinHalfSecond++;
// 70 should be the acceptable level, but we will test with 200 first to make sure it doesn't affect laggers.
if (c.PacketSpamCountWithinHalfSecond > 200) { // Spam > 70 packet within 500ms = dc.
c.FlagPendingDisconnection();
ServerLog.RegisterForLogging(ServerLogType.PacketSpam,
String.format("[%s 0x%s] CharOrAccId : %s, Field : %s, Count : %d\nData : %s\nString : %s",
code.name(),
Integer.toHexString(code.getValue()),
c.getPlayer() != null ? c.getPlayer().getName() : "Accid=" + String.valueOf(c.getAccID()),
c.getPlayer() != null ? MapleMapFactory.getFullMapName(c.getPlayer().getMapId()) : "-1",
c.PacketSpamCountWithinHalfSecond,
HexTool.toString((byte[]) message),
HexTool.toStringFromAscii((byte[]) message)));
}
}
} else {
c.LastCapturedTimeMillis_500MSThreshold = cTime;
c.PacketSpamCountWithinHalfSecond = 0;
}
// This is also used throughout the packet handler to determine the current time instead of calling System.currentTimeMillis() again
c.LastCapturedTimeMillis = cTime;
// System.out.println("Differences : "+(Differences)+", count : "+c.PacketSpamCountWithinHalfSecond+", cTime : " + cTime);
handlePacket(code, slea, c, type);
} else if (ServerConstants.enableUnhandledPacketLogging) { // Console output part for debugging
System.out.println(String.format("[Unhandled Packet] %s\nString : %s", HexTool.toString((byte[]) message), HexTool.toStringFromAscii((byte[]) message)));
}
}
public static final void handlePacket(final RecvPacketOpcode header, final SeekableLittleEndianAccessor slea, final Client c, final ServerType type) {
switch (header) {
...
}
I think that it's important to notice that actually the way most handlers are implemented also violates SRP. This is because most handlers actually have two responsibilities:
- Extract/Parse data from the message
- Decide how to change the world state with that data
The problem with this is that the former has more to do with the app-layer protocol, whereas the latter has something to do with game logic. This is especially true for some of the more complicated handlers, such as the attack handlers. Now of course this still works out alright in practice but if you want to get things 100% right, these two things should be seperated. I'm currently working on this in my own code and I can already see how much cleaner the code becomes after this separation.