Skip to content

Progress Report, 2016 Q3 (Summer)

Neal Terrell edited this page Sep 19, 2016 · 17 revisions

Welcome to the Jinteki.net open-source progress report for Q3 2016. In this quarterly report, we will highlight some of the recent changes to the Jinteki.net Android: Netrunner platform.

About Jinteki.net

Jinteki.net is a service for playing Android: Netrunner in a browser. It requires no installation to play, is compatible with most operating systems and modern browsers, and includes an interactive deck-builder, chat room, and automation of most game rules and cards.

New Contributors

Thanks to the new developers who added to the platform this quarter: carlsondc, Devencire, and Hoclor!

Interested in contributing? Check out our new Getting Started With Development guide, pieced together by queueseven, JoelCFC25, and mtgred! nealterrell also recorded some "live coding" streams to introduce our engine while implementing new cards.

More interested in simply learning to use the site? We also have a great Jinteki.net guide put together by darlingsensei. Help keep it current by adding new items or removing outdated information.

Saintis' Code Browser

As a small side project, Saintis wrote a Netrunner Code Viewer for viewing the implementations of all our Netrunner cards. We think it's a great way for Clojure beginners to get a feel for how cards are structured in our project, without having to dive in head first. There are some extensions in progress, so watch that space (and feel free to contribute as well).

Major System Changes

Never Trust the Client

There's a saying in client-server software development: "Never trust the client." When one computer system (the client) sends commands to a central authority computer (the server), a well-designed server will make sure to validate every part of the message received from the client, in recognition of how easy it is for a malicious user to send fake or altered messages from a compromised client. Video games have dealt with this issue for decades; a first-person shooter client will be programmed to not allow a gun to fire if it is out of ammo, but if the server doesn't double-check messages coming from the client, a hacker can send illicit "fire gun" messages to trick the server into letting the player fire even when the client wouldn't allow the action. In Jinteki.net, our clients (your web browser) send commands like "play card X", "select card Y", and "run server Z" to our game logic server.

Until recently, our game logic server assumed that all commands coming from the client were valid, because it's much faster to program a server under this assumption, and there are relatively few incentives for someone to cheat on our service. But the potential was there. A JavaScript hacker could easily change our client-side code to do lots of malicious behavior... for example, sending a command "play-card {:title "Hedge Fund", :cost 0}". A server that trusts the client will take the :cost of the transmitted card, deduct the player's credits by that amount, and then invoke the card's programmed logic... in this case, creating a Hedge Fund that gained 9cr but cost 0cr to play. Card behavior can't be changed this way, only its data, but this allowed easy hacks to change card play costs, trash costs, agenda point values, and more.

Trusting the client also means sending the entire game state to the client and allowing it to decide what to reveal to the player. If a first-person shooter sends all information about the entire game to a client, it has to trust the client to not reveal positions of non-visible enemies... but a client can easily be compromised to read this information and show it, in what is usually called a "wall hack". Likewise, we historically sent the entire game state to each player in a game, and wrote the client to draw unrezzed corp cards, the opponent's deck, and the opponent's hand face-down. Those cards' information was still in the state, though, and a JavaScript hacker could once again violate the rules of the game by inspecting that state to see the contents of cards in servers, in the opponent's hand, on top of R&D... the potential abuses are endless and game-breaking.

So what do we do? We Never Trust the Client. nealterrell rewrote the game logic server to fix two security issues:

  1. Don't trust the card sent by the client as part of a command. Instead load the server-side version of that card and use it. This goes for deckbuilding (don't trust the decklist sent at the start of the game; reload each card in the deck from the database, based on its card number) and for in-game commands, like the Hedge Fund example above, which would load the appropriate data for Hedge Fund straight from the server's copy of the player's hand.
  2. Don't send private information to a player if they don't have a game-rules reason to know it. The runner does not have a right to know any identifiable information about an unrezzed Corp card, so we construct a special state for the Runner that strips out all information about such a "private" card except the card's identifier (a unique integer that is different each game) and its zone (to allow it to be drawn and targeted by the UI). This means constructing three different states for each command handled by the game server (Corp's, Runner's, Spectators'), but fixes any potential abuse from peeking at private information through the game state.

We have no evidence that anyone was cheating prior to these upgrades, but this is the proper way to program a client-server game, so it's about time we got around to it.

Simultaneous Triggers

Last quarter we debuted a system for manually choosing the resolution order for simultaneous triggers, applying it to the agenda-scored and agenda-stolen event triggers. The system was generally a success and fixed a lot of long standing issues with automating cards like Leela Patel and Gang Sign. Not every trigger requires fine-tuned control over resolution order, so we have been slowly deploying the system to specific triggers when we recognize the need. This quarter we implemented simultaneous trigger resolution for:

  1. Runner-install: for all you Spy Camera addicts. You generally want your Replicator to resolve before your Bazaar... but at the same time, you DON'T want to manually order your Technical Writers. For this extension, nealterrell added "silent" and "interactive" ability flags. If a group of cards are all listening for a particular event and at least one is marked "interactive", then the player gets a prompt to order the effects. If none of the handlers are interactive, then the system resolves one at a time automatically. If a prompt is shown (because both Replicator and Bazaar are interactive), then there are some cards that do not need to be in the list, because they have no interactions in that window, like Technical Writer. These cards are "silent" and will be resolved automatically after all the manually-ordered effects.

    Example animation: Don't stare for too long. If Technical Writers were in play, you wouldn't ever be asked to resolve one manually; they would silently gain credits when each install finished. Also, the initial install did not ask whether Bazaar or Replicator should be used first, because Bazaar is silent if there are no other copies of the installed card in your hand. Replicator resolves, adds the new Spy Camera to grip, then Bazaar resolves automatically, seeing that there is now a new Spy Camera to install. Beautiful!

  2. Successful-run: LOTS of handlers here, and we're still dealing with some issues related to this upgrade. Many handlers are silent (Desperado, Temujin Contract), but others require interaction (Silhouette, Laramy Fisk, Equivocation). Temjin Contract in particular exposed a lot of issues with the initial implementation, leading to the legendary bugfix pull request #1953.

Agenda Swapping

Turntable and Exchange of Information, the banes of JoelCFC25's existence. We have an archive of a dozen issue reports involving these two cards, and if you pay close attention, you can see Joel's descent into madness trying to resolve all the problematic interactions with Mandatory Upgrades, Breaking News, and many other agendas.

Our agendas are coded with an :effect behavior that is triggered when the agenda is scored. AstroScript adds an agenda token to itself, Hostile Takeover grants credits and BP, Rebranding Team registers all assets as Advertisements, Superior Cyberwalls registers an increase in barrier strengths, and Mandatory Upgrades registers an increase in available clicks. The first two agendas worked well with Turntable... the others did not. What's the difference?

The first two agendas use their :effect to trigger some immediate behavior when scored. These behaviors should not be triggered when an agenda is swapped back to the Corp. The other agendas use :effect to register some later behavior... that behavior should be turned off when the agenda is swapped to the Runner, but must be turned back on when returned to the Corp's score area. Because we use :effect for both these types of abilities, we can't simply trigger an agenda's :effect when it returns to the Corp, because while that would fix Mandatory Upgrades, it would grant 7 more credits and 1 more BP for Hostile Takeover.

kevkcc solved this problem by giving agendas an explicit :swapped ability to trigger when they get swapped from Runner to Corp's scored area, allowing Mandatory Upgrades to re-register its bonus click when returned to the Corp. Paired with a :leave-play ability that triggers when swapped from Corp to Runner, we can now accurately code all interactions with Exchange of Information and Turntable correctly.

More Prevention Effects

Prevention effects are the only real "interrupt" mechanism in Android: Netrunner. Many Progress Reports have chronicled our implementations of the game's "prevent/avoid" effects, including:

  1. Damage prevention (Plascrete Carapace)
  2. Tag avoidance (New Angeles City Hall)
  3. Trash prevention (Fall Guy)

What's missing? Take a minute...

Perhaps you guessed it:

  1. Jack-out prevention. Normally you can just trust the Runner to not hit Jack Out after running through an Inazuma, but Labyrinthine Servers requires the ability to interrupt an active attempt to jack out. kevkcc implemented jack-out prevention just for this amazing card!
  2. Exposure prevention. mtgred tasked nealterrell with implementing this feature via Zaibatsu Loyalty and Underway Grid. WORLDS DECK ALERT???

Full Immersion RecStudio and Corp Hosting

Full Immersion RecStudio was an interesting challenge. An immediate example of a similar Runner card is Leprechaun. We implement Leprechaun with two abilities: one to install and host a card from hand (costing 1 click), and another to host an already-installed card onto Leprechaun (costing 0 clicks). The second ability is necessary for interactions with Clone Chip, Retrieval Run, or any other "install a card from somewhere other than the Grip" ability. Corps have similar abilities via Interns, License Acquisition, and Team Sponsorship, but it was decided that Full Immersion RecStudio could not rely on the same trick as Leprechaun to allow a card installed by one of these sources to be "moved" onto FIR.

I'll give you thirty seconds to think of an incorrect rules interaction that would occur if FIR behaved the same way that Leprechaun does...

...

...

If you mentioned the words "NEH", "Astrolabe" or "Turtlebacks", then you are correct! If the solution for using Interns to install onto FIR involved using Interns to create a new server and then using FIR to host the already-installed card, then we would have incorrect rules interactions with any card that triggers "whenever the Corp creates a server". NEH and Astrolabe are irreversibly wrong (revealing the next card in the draw pile), so we need a proper solution to allow the Corp to use a card ability to install an Asset or Agenda on Full Immersion RecStudio.

Each time a Corp card is installed without specifying a server (through card effects, not the "Install from hand" action), we show a list of servers where the card can be installed. We now also allow rezzed Corp cards to announce that they can host the card-to-be-installed if it meets certain criteria. This allows FIR to show in the list of target locations when installing an Adonis Campaign via Interns, as such:

Fun fact of the day: Runner cards can host Runner cards (Djinn), Runner cards can be hosted on Runner cards (Personal Touch), Runner cards can host Corp cards (Film Critic), and Runner cards can be hosted on Corp cards (Parasite); Corp cards can host Corp cards (Worlds Plaza), Corp cards can be hosted on Corp cards (Oversight AI), and Corp cards can host Runner cards (Magnet)... but there are no Corp cards that can be hosted on (installed on) Runner cards.

An example card in this unused design space:

Segfault 1cr
Operation
Play only if the runner is tagged. Install Segfault on an icebreaker as a hosted condition counter with the text "Host icebreaker has -3 strength. Trash Segfault if the runner is not tagged."

Report Error Button

The unfortunate reality of our small community is that we don't have enough volunteer hours to thoroughly test the myriad ways that Netrunner cards can interact with each other. We do our best to maintain a large unit-testing library, but there will always be issues that slip through the cracks. That's why the "Report Error on GitHub" button that you occasionally see in a game is so important; with one simple click of the mouse, you can file a report about an in-game crashing error that (usually) contains enough information for our devs to get started on a fix. Please use it!

Other Improvements and Automations

  • FAQ 3.1 changes to searching.
  • Subliminal Messaging now prompts the user to add to hand automatically. (kevkcc)
  • Identity base link is now loaded from card information (straight from Netrunner DB) so newly-spoiled identities will have their correct link strength even before their logic is coded. (Saintis)
  • A Fan Site that has been swapped to the Corp with Exchange of Information will not return to the Runner's score area when another agenda is scored. @artturipi insists there are reasons you would want to do this, but we remain skeptical. (Hoclor)
  • 24/7 News Cycle can be played with only one agenda scored. (Hoclor)

"Reorder" cards rework

Cards that involved a reordering of the top cards of the deck have long been a bit annoying to play since dragging cards from the temporary zone is rather unintuitive and tedious. Nealterrell thus reworked Indexing and Making an Entrance to allow the user to perform this ordering via prompts (with a final prompt at the end asking for confirmation) and kevkcc extended this system to Rolodex, Data Hound, Shiro, Spy Camera, CBI Raid and Invasion of Privacy

Finalizing an Indexing run.

New commands

  • /move-bottom: move targeted card to the bottom of R&D/Stack.
  • /counter: not a new command, but now specifies the type of counter to add. If no type is specified, it is inferred if possible. Types: ad(vancement), ag(enda), c(redit), p(ower), v(irus). Inference rules: match whatever counter is already on the card if any; otherwise advancement on unscored agenda, agenda on scored agendas, virus on Runner cards with virus subtype, otherwise type must be specified.

NRDB API 2.0

Suppose your software relies on the data format of some external resource, like NetrunnerDB's list of cards. Further suppose that resource needs to change the way it represents its data to better meet its own long-term needs. You can adapt to this change in one of two ways:

  1. Change your code to use the new data format, for example, rewrite The Personal Touch to target cards with a :keyword of Icebreaker (NRDB 2.0) instead of a :subtype of Icebreaker (NRDB 1.0).
  2. Write an adapter to transform the new data format to the old data format, leaving the game logic untouched.

JoelCFC25 and nealterrell decided that option 1 would require too much labor to implement, as it would require rewrites of hundreds of card behaviors and would be prone to error. We felt it was better to go with option 2, with a software layer that transforms new NRDB keys to old ones, even though it will require future developers to know both sets of keywords. zaroth and mtgred further iterated on nealterrell's initial "fetch" script, and helped migrate 100% of card and set checking to the new NRDB API format. zaroth himself was a big contributor to NRDB's decisions about the API!

UI improvements

  • Game titles can be up to 100 characters long. Don't go overboard. (carlsondc)
  • Improvements to the chat log when installing Corp cards, distinguishing between "in" vs "protecting" a server. (Devencire)
  • Consistent sorting of Corp server list for installs, sorting remotes by number and not by name ("Server 10" is alphabetically less than "Server 2" but not numerically). (Devencire)
  • Icons on Security Testing, Patron, and Temujin Contract to identify their server targets; also on Femme Fatale. (Saintis)
  • Password-protected games will no longer reveal their players' factions or identities in the game list. (neaterrell)
  • Stop misclicks on ice from rezzing them outside of a run, ruining your surprise! (Saintis)
  • Typing just "Null" into chat was freezing the UI, but rather than track down exactly WHY, server-mangle any message of just "Null" to "Null ". (nealterrell)
  • Identify the cards trashed from damage in the chat log. (Saintis)
  • Pull Adam's directives from the server when starting a game, so they don't have to be in the decklist anymore. Allows Adam decks to correctly contain 4x of his directives. (Saintis)
  • Targeted Marketing and Salem's Hospitality use an autocomplete text box to name a card. (nealterrell)
  • Admins can now broadcast a message to all active games, alerting them when the server is going to be restarted. (nealterrell)
  • Action panel always shows on Agendas so that the click to advance behaviour is the same as for advanceable Assets - useful for those of us who are paranoid and worried that the opponent can tell a Junebug from a Government Takeover based on number of clicks. (Saintis)
  • The creator of a game can choose to expose both players' hands to spectators, useful for streamers and learners. (nealterrell)

Notable new card implementations

We've gotten through most of our backlog of unimplemented cards thanks to the sustained heroic efforts of JoelCFC25. We don't project any problems with spoiled cards and will be implementing new packs as the developers find time. A few recent cards were particularly challenging or interesting to implement, however:

  • The Black File, Enforcing Loyalty, Algo Trading, Financial Collapse, Obelus (JoelCFC25)
  • Rumor Mill, Paperclip, Data Breach (nealterrell)

As of time of this writing, we are at 98.0% card automation card automation through Blood Money!

Contribute

Jinteki.net is an open-source project run and paid for by mtgred and other volunteers. You can contribute by reporting bugs, submitting fixes, and even adding new implementations on our GitHub page.

Clone this wiki locally