UI API

ironchefpython

Member
Contributor
Architecture
So I'm reading through the code, I noticed there is a completely new UI framework in there. I can't help but wonder why, given that there are dozens of freely available UI toolkits.

At any rate, being able to create new user interface layouts is a crucial part of modding. So let's see what it would take to replicate the classic (and by classic I mean many months old) inventory/crafting layout from Minecraft. (note that I'm not advocating this layout, it's just for demonstration purposes)



I'm working on the Javascript code that would drive this screen. Here's an excerpt, I'm still working on a full example.

== EDIT ==
code deleted, comprehensive example in a subsequent post

The idea is that within a mod, developers will be able to create CubbyHoles and assign them to players and NPCs and objects like chests or machines, and create new user interfaces to interact with these Cubbyholes
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Very nice :)

With the example posted the UI mock-up already has a headslot (well, in theory, since we know it is the MC example). I see how the code would handle a mod allowing a head slot item to be interacted with, but wouldn't there be a UI-side bit of logic on where a head slot (or any other new slot) would go in the first place? How would you connect the UI slot and the cubbyhole? Need some sort of name to map the two, I figure.

As for why there's a homebrewed UI framework (and there's more, a whole branch of pending UI changes over at https://github.com/small-jeeper/Terasol ... MenuAndGUI) - well. We looked at Nifty, but something about it was meh. Other options I can't remember much about, but we had some internal stuff working already, so just enhanced that. If you know of any good options feel free to mention :)
 

ironchefpython

Member
Contributor
Architecture
I probably should have waited until my sample code was completed until posting this thread. I think the code below makes it more clear what I was trying to communicate.

The "mod" below creates both the player inventory, and the mechanism to display this inventory. It clearly duplicated functionality that is "hard-coded" into the engine, but I think there are significant advantages to moving this basic functionality into a mod that can be easily edited.

I encourage you to look at what I'm doing not in terms of the keywords or function names I'm using, but as more of a philosophy, that even the most basic game functions should be implemented with the mod API, and should be visible to edit and learn from. Reading the code below, most users would have no difficulty adding new inventory slots, or making the player crafting area 2 x 1, or 3 x 4, or whatever, they could easily add a ring slot, limit the types of items that could go into quick slots, etc.

Code:
// Add a cubbyhole to represent the head equipment slot associated with the
// player
var headCub = game.createCubbyhole();

// adding the new cubbyhole to the player assigns the contents of the cubbyhole
// to the player for ownership purposes
player.addCubbyhole(headCub);

// Add an event handler that fires when an item is dropped into this cubbyhole
headCub.addEvent("drop", function(item) {

   // We test to make sure that any item dropped here must have a head slot
   // property
   if (item.slot != "head") {
      
      // returning false disallows the drop event.
      return false;
   }
   
   // if the item fits in this slot, have the player equip the item.  Note that
   // we are returning the value from the equip event, so if the equip event
   // handler prevents the equip action, we also prevent the item from being
   // dropped in this cubbyhole
   return player.equip(this);
});

// Similarly, add a cubbyhole for the chest
var chestCub = game.createCubbyhole();
player.addCubbyhole(chestCub);
headCub.addEvent("drop", function(item) {
   if (item.slot != "chest") {
      return false;
   }
   return player.equip(this);
});

// and legs
var legCub = game.createCubbyhole();
player.addCubbyhole(legCub);
headCub.addEvent("drop", function(item) {
   if (item.slot != "leg") {
      return false;
   }
   return player.equip(this);
});

// and feet
var feetCub = game.createCubbyhole();
player.addCubbyhole(feetCub);
headCub.addEvent("drop", function(item) {
   if (item.slot != "feet") {
      return false;
   }
   return player.equip(this);
});

// We need a global variable to store the currently equipped item
var equipped = 1;

// Now we create cubbyholes for the quickslots 1 through 0
var equipCubs = [];
for (var int i = 0; i <= 9; i++) {
   
   // execute the following in a closure to caputre the value of i
   function(i) {
      // create a new cubbyhole, and associate it with the player
      var cub = game.createCubbyhole();
      player.addCubbyhole(cub);
      
      // Add a new keybinding to the game engine.  When this keybinding is
      // invoked the item in the associated cubbyhole will be equipped.  The
      // default keys to bind to this actions are the number keys  through 0
      var bind = game.createBinding("Equip Item " + i, i);
      bind.addEvent("invoke", function() {
         player.equip(cub);
         equipped = i;
      });
      
      equipCubs[i] = cub;
   }(i);   
}

// when the mousewheel is scrolled up, switch to the previous item
game.addEvent("mousescrollup", function() {
   eqippped = --equipped % 10;
   player.equip(equipCubs[equipped])
});

// when the mousewheel is scrolled down, switch to the next item
game.addEvent("mousescrolldown", function() {
   eqippped = ++equipped % 10;
   player.equip(equipCubs[equipped])
});


// Let's add the 4 craft cubbyholes
var craftCubs = [];
for (var int i = 0; i < 4; i++) {
   var cub = game.createCubbyhole();
   player.addCubbyhole(cub);
   craftCubs[i] = cub;
}


// And finally we make the inventory cubbyholes
var invCubs = [];
for (var int i = 0; i < 40; i++) {
   var cub = game.createCubbyhole();
   player.addCubbyhole(cub);
   invCubs[i] = cub;
}


// Now we need to build the UI.  We start by creating all of the individual
// panels, that will be assembled into the full interface

// create a UI panel to hold the 4 armor cubbyholes
var armorPanel = new LayoutGrid(4, 1);
armorPanel.append(headCub);
armorPanel.append(chestCub);
armorPanel.append(legCub);
armorPanel.append(feetCub);

// create a UI panel to hold the 4 crafting input cubbyholes
var craftInputPanel = new LayoutGrid(2, 2);
for (var int i = 0; i < 4; i++) {
   craftInputPanel.append(craftCubs[i]);
}

// create a UI panel to hold the crafting output cubbyhole
var craftOutputPanel = new LayoutGrid(1, 1);
craftOutputPanel.append(Crafting.createOutputCubby(craftCubs, 2));

// create a UI panel to hold the player inventory
var invPanel = new LayoutGrid(4, 10);
for (var int i = 0; i < 40; i++) {
   invPanel.append(invCubs[i]);
}

// create a UI panel to hold the player equipment quick slots
var equipPanel = new LayoutGrid(1, 10);
for (var int i = 0; i < 10; i++) {
   equipPanel.append(equipCubs[i]);
}

// arrange the invididual items at the top of the UI into a single panel
var topPanel = new LayoutGrid(1,5);
topPanel.append(armorPanel);
topPanel.append(player.getModelPanel());
topPanel.append(craftInputPanel);
topPanel.append("arrow.png");
topPanel.append(craftOutputPanel);

// and finally arrange everything into the final layout
var charPanel = new LayoutGrid(3,1);
charPanel.append(topPanel);
charPanel.append(invPanel);
charPanel.append(equipPanel);

// create a key binding for the inventory screen, and we're done!
var bind = game.createBinding("Show character", "e");
bind.addEvent("invoke", function() {
   charPanel.show();
});
With the example posted the UI mock-up already has a headslot (well, in theory, since we know it is the MC example). I see how the code would handle a mod allowing a head slot item to be interacted with, but wouldn't there be a UI-side bit of logic on where a head slot (or any other new slot) would go in the first place? How would you connect the UI slot and the cubbyhole? Need some sort of name to map the two, I figure.
This is why I feel foolish for posting the code example too early. In the full version, the code both creates the "slot" for the head item to go in, and also creates the UI for the user to interact with it. All the connection is done in the mod API.

If you know of any good options feel free to mention
Swing, SWT, Qt Jambi, Apache Pivot, JavaFX. (There are many more, these are only the ones I've personally evaluated)

If you want to be really kind to modders, you can allow custom UIs to be built using HTML, and then use an embedded HTML layout engine for display, such as CSSBox, Cobra, WebView, or even the ancient HTMLEditorKit.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Good stuff! Thanks a bunch. Sorry if the quirky questions get in the way, I'm still trying to learn myself and would rather ask at a potentially bad point rather than not ask at all. I like the model you're putting together and agree that modding potential should start as "deep" in the code as we can realistically add it :)

I'll leave others to comment more on the UI bit - I haven't been much involved there.
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
ironchefpython said:
Swing, SWT, Qt Jambi, Apache Pivot, JavaFX. (There are many more, these are only the ones I've personally evaluated)
The vast majority of which aren't compatible with LWJGL. Maybe Qt Jambi, although it is hard to tell with the lack of documentation on the site.
 
Top