Game Box MMO Game
Updated at 1685687945000- MMOVirtualWorld: Manages all MMO rooms and schedule to update state the rooms and room's players.
- SyncPositionRoomUpdatedHandler: To sync room's players to clients.
1. MMOVirtualWorld
Actually, a MMOVirtualWorld manages a list of MMORoomGroup, every room will be evenly distributed into every MMORoomGroup like this:
public void addRoom(MMORoom room) { int roomGroupIndex = (int) (room.getId() % roomGroupCount); MMORoomGroup roomGroup = roomGroups[roomGroupIndex]; roomGroup.addRoom(room); }
We need add a room like that to be able to use multi-threading but still ensure every room state's update will be run on only one thread to avoid concurrent issues. To create a MMOVirtualWorld you can do like this:
@EzySingleton public MMOVirtualWorld mmoVirtualWorld() { logger.info("Initialize MMO Virtual World"); return MMOVirtualWorld.builder().build(); }
For more details, please take a look: MMOVirtualWorldConfig
2. MMORoomGroup
A MMORoomGroup will do 2 main tasks:
- Manages MMORooms
- Schedule update MMORooms and MMOPlayers state
The scheduler will work like this:
private void loop() { this.active = true; List roomBuffer = new ArrayList<>(); while (active) { try { long start = System.currentTimeMillis(); this.updateRooms(roomBuffer); long end = System.currentTimeMillis(); long timeElapsed = end - start; if (timeElapsed < timeTickMillis) { //noinspection BusyWait Thread.sleep(timeTickMillis - timeElapsed); } } catch (Exception e) { logger.error("Room group loop error: ", e); } } }
You can see, the sleep time will depend on rooms update elapsed time. So, if we have more rooms, the CPU usage will be higher.
3. MMORoom
A MMORoom manages a list of MMOPlayers. When the update method is called, it will calculate the distance between players to update near by players list of every players in the room like this:public void update() { List playerList = playerManager.getPlayerList(); playerList.forEach(player -> { player.clearNearByPlayers(); playerList.forEach(other -> { double distance = player.getPosition().distance(other.getPosition()); if (distance <= this.distanceOfInterest) { player.addNearbyPlayer(other); } else { player.removeNearByPlayer(other); } }); }); notifyUpdatedHandlers(); }
You can see, in the end of the method, the room will notify to it's all listeners, and we can add the SyncPositionRoomUpdatedHandler
to the listener list.
4. SyncPositionRoomUpdatedHandler
After the room update, we will have a list of updated players. In fact, we must sync the position to clients to allow the clients update and display by the state. Because the update schedule is very quick (in millisecond) so is better to use UDP like this:
public void onRoomUpdated(MMORoom room, List players) { players.forEach(player -> { // Check if player's position or rotation is updated if (player.isStateChanged()) { responseFactory.newArrayResponse() .udpTransport() .command(Commands.SYNC_POSITION) .param(player.getName()) .param(player.getPosition().toArray()) .param(player.getRotation().toArray()) .param(player.getClientTimeTick()) .usernames(player.getNearbyPlayerNames()) .execute(); player.setStateChanged(false); } }); }
To create a MMO game, you can take a look EzySmashers. It's using EzyFox, Game Box for server and Unity for client.