Kingdom Of Galanor

From our thread on the Unity Forums

As mentioned in an earlier post, we’ve been working on the turn-based combat system. Here’s a video of it in action in its current state.

Currently, only basic melee attacks have been implemented, and the attack priority is only sorted by attacker type (i.e. mob, player, pet). Eventually, the attack order will also be governed by dexterity and spell/skill type.

We had a few headaches synchronising the attack animations between clients; programming multiplayer is such a PITA compared with single player, but it’s a nice feeling when it comes together 🙂

There are still bugs to be ironed out, mainly relating to situations where players unexpectedly disconnect during combat, but they are few and far between now as we’ve dealt with the majority and in general it’s pretty stable.

We’ve also decided on a title for the game, The Kingdom of Galanor.

As always, any comments, suggestions, criticisms are always welcome.

Kingdom Of Galanor

From our thread on the Unity Forums

We’ve been working on a lot of ‘under the hood’ stuff, making sure the core systems are as stable and maintainable as possible. The worst thing is finding out sometime down the line that some bad early design decisions have come back to haunt you.

One of the first obvious hurdles we had to overcome was how to deal with teleports. Initially, we had a simple design, whereby the teleport gameobject contained a component that had a reference to a destination gameobject and when activated it just moved the player to the destination location.

All well and good, except that as we use a different scene for each map we ran into the issue that as cross scene references aren’t allowed we couldn’t store the reference to the destination in the teleport if the destination wasn’t in the same map.

So a slight design change meant we stored the name of the destination gameobject in the teleport along with the scene path as strings and then when activated, the teleport loads the new scene (if necessary) and once the scene is loaded it searches for the destination gameobject by name and then moves the player to its location.

Job done, or was it? With the number of teleports that will eventually be in the game, this would soon become a nightmare to maintain. Anything that relies on manual entry of strings to make references for anything other than a few objects isn’t going to cut it.

In addition to that, we found that although this worked acceptably in a single player environment once we tried it networked we saw ‘warping’ of the player character because it was at its old location from the previous map for a few frames whilst the teleport located the destination and sent the new location over the network. So we fixed this by adding the location and rotation of the destination as properties of the teleport and sending them along with the scene change message, so all clients could update to the new position instantly.

This, however, meant that it was even more difficult to maintain the link between teleports and destinations and was quite frankly turning into a nightmare. So it was pretty obvious that a rethink was required.

After a bit of discussion, it was decided to move all teleport logic and data to a singleton manager which would store the information for all the teleports and destinations. Which just left the issue of how to easily get that information into the manager in the first place.

Custom Editor Window to the rescue!

We designed a custom editor that enables us to create/edit and delete teleports directly in scenes and it automatically saves the info for each teleport/destination into an asset which is loaded into the teleport manager at runtime. This has changed the task of maintenance from a manual task to visual design. We can quickly locate and update teleports and destination maps/positions and the new information is automatically saved. We can also automatically check for orphaned teleport and destination objects.

Now when a teleport gameobject is activated at runtime, it just queries the manager for its destination information and voila!

Quick snap of the editor in action, and that’s it for this update. See you again soon.

Kingdom Of Galanor

From our thread on the Unity Forums

Have been tidying up the network code that handles parties and combat, particularly to make sure that unexpected disconnects are handled gracefully and don’t result in errors and null reference exceptions for the remaining clients.

The party system is substantially complete and is working exactly as planned. The combat system is partially implemented, with passive and aggressive mob behaviour.

When we originally started developing this we had player stats network synchronised, so any time any player had a stat update (HP, MP, DEX etc.) it was broadcast to every connected client, which created unnecessary network traffic. But it became clear that most of the time access to remote client stats wasn’t required, and it would be more efficient to have stats on the local client only and just send the stats to any interested clients on the occasion they are required.

We currently have a placeholder scene in place for combat, and in that we can see that the party leader correctly receives data from all players in the party, which it will use to calculate the result of the combat, and then transmit that to the other party members as and when needed.

Hopefully, the next update should have a working implementation of the turn-based combat system.

Players are currently only sending about 1 update a second to synchronise position and rotation (packed into one vector3), which although doesn’t result in absolutely perfect synchronisation is easily good enough for this type of game.

Also, we have also been experimenting with a shader based random screen transition system.

Kingdom Of Galanor

From our thread on the Unity Forums

Continuing to develop and improve the networking code, we’ve now implemented the basics of a party system, basic network synchronised mob wandering and aggro behaviour, and scene switching for the what will be a turn-based combat system.

One of the early problems faced was with how to approach handling the mobs for each map; we needed them to be network aware because we wanted to use RPCs to control their behaviour and be synchronized between clients, which meant that we couldn’t just place prefabs in the scene. So Initially we put placeholder gameobjects in the map scene which contained a script that used InstantiateSceneObject() to create the actual mob when the map loaded.

This approach presented a number of problems, the following being the most annoying:-

  1. Firstly the mobs were spawned on all clients, irrespective of whether the client was on the map that the mobs belong to; Which meant that we had to add logic to hide the mobs on clients that were on a different map.
  2. It also meant that we were sending unnecessary instantiation messages to some clients, therefore wasting bandwidth.
  3. On top of this because of the way RPCs work as standard, the control RPCs for the mobs were also sent to every client, meaning we were wasting more bandwidth and also had to filter them out for clients on other maps.
  4. Furthermore, when a map was entered for the first time in any session there was a noticeable hitch on all clients as all the mobs were created.
  5. Finally, we had to have some way to remove all the mobs once there were no more players in the map.

After playing around with this for a while it became clear that it was going to be unwieldy and inefficient, so we decided to rethink our approach from the ground up.

After a bit more experimentation, we decided that we wouldn’t instantiate the mobs as scene objects, and we wouldn’t give them a PhotonView component. Then rather than having a mob spawner placeholder in the map, we would just place the actual mob gameobject itself.

This neatly dealt with problems 1,2,3 and 4 from the above list, however, we now need a way for the mobs to synchronize over the network. Which is where PhotonNetwork.RaiseEvent comes into its own. Using RaiseEvent we can specify exactly which clients get sent messages, so we can send messages only to those clients on the same map.

We also added a script to the mobs which listens for RaiseEvent messages and filters the messages by the EventCode, so they can take the appropriate action based on the message received. We also needed a way to give each mob a unique identifier (think PhotonView.viewID) that will always be the same for the corresponding mob on all clients, but this turned out to be quite straightforward, by using the build index of the map they are on (multiplied by 100,000) added to the child index of the mob. This gives us more than enough mob unique IDs for any given map and means that if we send the ID in the network message, the receiving mob can tell if the message is targeted at it or not.

So problem 5 is also now dealt with, as the mobs are created and destroyed along with the map as players leave and enter it, which has no effect on other clients.

We also created a couple of helper classes to give us handy functions to send messages to players (all players, other players, only players in the same map, etc.).

Now there was another part of the puzzle to be solved. We needed a way to decide which client should be responsible for controlling the mobs in the map. It can’t just be the current MasterClient, because the MasterClient won’t have any knowledge of mobs in maps that it isn’t itself on. So we devised a method to have each map maintain its own ‘MapMasterClient’ which is automatically updated as players enter and leave maps, and it is this client that will control the mobs for that map.

With the addition of a couple of network messages to invoke functions to synchronize the state of all the mobs when players first enter a map the puzzle was complete. We now have a system that makes it easy to control different sets of mobs for different clients, depending on which map they are on, and which also minimizes the amount of network traffic required to handle this.

As a direct result of this, we’ve taken the decision to avoid using RPCs for anything in the game, and instead implement all network communication using RaiseEvent. Also the only thing we will use PhotonNetwork.Instantiate for is the player gameobject.

With 20 clients connected, all the players on the same map and moving around constantly along with the mob wandering logic, we are still only at around 250 messages per second per room, which is within our target. In practice, most players aren’t moving constantly and the party system will reduce movement data even further for clients in a party, but we need to allow for worst case scenarios.

We’re still a way off having a playable version, but things are progressing well and as soon as we have something available for testing I’ll post an update here.

Kingdom Of Galanor

From our thread on the Unity Forums

Earlier this year we started work on a multiplayer RPG game, The Kingdom of Galanor and have recently reached the point that we can start doing some testing of network code.

We think we will probably use PUN, partly because of our familiarity with it already and partly because of the automatic host migration, because we are opting for player hosted rooms rather than dedicated servers.

In this test (video below, showing two of the clients) we conduct a 20 player test of our latest player (and pets) transform and animation synchronisation code and interest management; With 20CCU split roughly evenly between 2 maps it resulted in a maximum of only 116 msg/s and about 12mb data per hour. (The data will be optimised further).

The test itself was quite busy in terms of constant player movement, and in practise I think the network traffic would probably be lower than the test indicated. Our aim is to be able to support 32 players per game (room) and at the moment it looks like we are on course to be able to fit that into the room limit of 500 msg/s limit imposed by PUN (Photon Unity Networking).

We are also well into the development of the quests, combat and work skills/production systems and I’ll post updates on those once we’ve got something to show.

The intention is that this will be a PC only game and will be released on Steam.

Early alpha test of networking code