Planetarium Engineering Snack

Libplanet 0.2 Released

(English한국어)

Hello, last week our team released the second minor version1 of Libplanet, Version 0.2. Although there have been several changes, this article will cover some key feature additions and API changes.

Introduction to Libplanet

Before getting into our updates, I haven’t introduced Libplanet on this blog, so let me briefly explain it to you.

Libplanet is a common library that solves game implementation problems such as P2P communication and data synchronization when creating online multiplay games that run on distributed P2P.

Libplanet is now being developed in C# language, with the aim of being used in conjunction with the popular Unity engine. Of course, even if you don’t use Unity, Libplanet targets .NET Standard 2.0 so that it’s easy to use for games that are implemented on .NET or Mono.

Another feature of Libplanet is that it is a library, not an engine or a framework. Since engines and frameworks control the entry point (Main() method) of a process and dictate its execution flow, game programmers have limited control and can only program essentially through scripts within sections explictly allowed. Libplanet does not preempt the game process and operates only when it is explicitly invoked by the game programmer. This allows Libplanet to function with game engines like Unity without imposing additional limitations on the developer.

Libplanet is listed on NuGet along with API docs.

NAT Traversal

Although P2P communication was possible from Libplanet 0.1, all peers had to have a public IP. In other words, because we couldn’t reach peers behind routers, network communication was actually limited in reality. Solving this issue was a top priority for us and so traversing NAT was a major goal in the 0.2 roadmap. To cover most cases, we implemented RFC 5766 and RFC 5389, called TURN and STUN. Also, there weren’t any open source C# implementation to ease the process, so our team’s Swen Mun implemented the necessary parts of the specification from scratch. If you’re interested in Swen’s journey, please also read the article, Moving Beyond NAT, in which he explains how he solved this problem.

More Game-fitting Transaction

Transaction<T> is a unit that synchronizes data between network members. Up to the previous version of Libplanet, we referred to existing technologies such as Bitcoin that solve similar problems and took on the concept that all transactions had a sender and a recipient. In the case of Bitcoin, it deals with monetary transactions so the notion that there are senders and recipients in every transaction comes naturally. In games, however, there are often actions that do not carry a recipient concept, such as the movement of a character, or actions that may have more than one recipient, such as wide range skills.

So to make this transaction more game-fitting, Libplanet from this version on will dismiss the SenderRecipient concept of Transaction<T> and instead, replace it with the SignerUpdatedAddress concept.

New Status Access API

Previously, all IAction implementations had to request a set of account addresses to be accessed within the Execute() method through the RequestStates() method. Ones that attempted to read or write status of addresses that weren’t requested in advance were treated as invalid.

However, we came to the conclusion that, since the status shared in the public network through blockchain could be read anyway, the limitation on reading didn’t mean much, only the limit on updating.

Additionally, the duplicated information on the accounts to be accessed in both the RequestStates() method and the Execute() method was bug-prone. And even if you were careful, fixing the both methods together was a big hassle.

To solve these problems, the IAction interface’s status access API has been greatly improved on this version of Libplanet. The RequestStates() method has disappeared altogether, and the PreviousStates property of the IActionContext object, which entered the factor in IAction.Execute() method, now provides a kind of “record of changes” API. This “record of changes” is stacked inside the Execute() method and when it finally returns the change history, the status is then updated.

Also, when a transaction is created, the action is executed in “rehearsal mode,” which obtains a set of addresses that the Execute() method is trying to update. The address set is then included in the transaction with a signature. This prevents a recipient node from changing the account status of addresses not included in the address set of the signed transaction.

Optional Subtype Polymorphism

Up to the previous version, the only usage of Libplanet actions was that each game defines an abstract classs which implements IAction and has multiple concrete classes inheriting it. But depending on the game, there are cases where it might be better to implement IAction as an only class and select a behavior based on data that goes into the action than to define multiple types of action at the IAction level. Moreover, some projects might face difficulties because the dynamic dispatcher for IAction types is internally implemented using .NET reflection.

Hence, from this version of Libplanet, T in Transaction<T> needs not only to implement IAction but also to concrete classes. Abstraction classes or interfaces aren’t acceptable even if they implement IAction, and the presence of subtypes is completely ignored.

Instead, if you want to select the behavior of an action through subtype polymorphism, you can use PolymorphicAction<T>, a new action class to decorate another action. For example, changing Transaction<AbstractAction> to Transaction<PolymorphicAction<AbstractionAction>> will work as it has been in most cases. Of course, the PolymorphicAction<T> class uses .NET reflection under the hood.

Furthermore,

There have been lots of other changes on Libplanet 0.2.0, so check them out in our release notes.

FYI, two days after the release of 0.2.0, a new version with some troubleshooting issues is now released, with the latest version being 0.2.1 (as of April 9, 2019).

If you’re curious, install and have a look around. And If you have any questions, please join our Discord chatroom!


  1. We have not yet released a major version. ↩︎