Skip to content
Vinyarion edited this page Dec 10, 2020 · 6 revisions

Custom guis

This feature allows you to make dynamic interactive guis to display information to players. They are written in JS and are actually executed on the client. Don't worry, though, they are sandboxed and don't have access to anything except rendering code. They can't be used to cheat, as there is also no access to the game state.

Files

The guis are in the assets/[your pack namespace]/anduril/guis folder and its subfolders. To create a gui, create a new file with only lowercase Latin letters, the digits 0-9, and the . or _ characters in the name and with a .js file extension.

Displaying a gui

The guis can only be displayed by using the command /anduril_gui <players> <loc> [<redisplay>] [<data>].

  • <players> The players to whom the gui will be displayed.
  • <loc> The location in the resourcepack of the gui. For example, to display a gui named assets/sybyline/guis/testgui.js, you would need to pass sybyline:testgui as the argument.
  • [<redisplay>] Whether this gui should replace any custom guis the player might have open. If false, it can be used to update the client with data.
  • [<data>] A compound NBT tag representing the data the client should use.

Writing a gui

There are six functions that you can define to draw gui elements and update them:

  • tick This function is called every Minecraft client tick and can be used to update some things in your gui.
  • init This is where you set up your screen and add basic elements to it.
  • update_data This is called when the server sends custom data to the client. The custom data is placed in the global variable data.
  • render_pre Render function that gets called before the widgets (buttons etc.) you added are rendered. Render backgrounds here.
  • render Render function that gets called after the widgets, but before subscreens are rendered.
  • render_post Render function that gets called after everything. Render text and tooltips here.

There are three numerical variables bound on the render calls:

  • mouseX and mouseY The position of the cursor on the screen.
  • partialTicks The time of the current frame in-between ticks, e.g., 0.5 means halfway between frames.

There is one global variable bound on the tick call:

  • ticks The number of ticks the player has existed.

There are several special global variables:

  • util The utility object. (see IScriptUtil)
  • screen The window context object. (see IScriptWindow)
  • gui The renderer context object. (see IScriptUtil)
  • data The data object that the gui was initialized with or updated with.

Here's an example script that shows how things should look. There are allusions to some upcoming features, as the developer was too lazy to remove them.

// Test script
// gui, screen, data, util always exist
//use("org.lwjgl.opengl.GL11", "gl");
number = 0;
iinc = 1;
texture = util.new_resource("lotr:textures/entity/player/cloak/test.png");
item = util.new_item("minecraft:stick", 1);
name = "Vinyarion";
head = util.new_item("minecraft:player_head{SkullOwner:Vinyarion}");
tick = function() {
  head = util.new_item(util.format("minecraft:player_head{SkullOwner:%s}", name));
};
init = function() {
  var ww = 200;
  var hh = 160;
  screen.pos(screen.ww_h() - ww / 2, screen.wh_h() - hh / 2);
  screen.size(ww, hh);
  gui.screen_add(gui.new_button(screen.ww_h() + 15, screen.y() + 30, 80, 20, "Update head", function() {
    name = name_field.value();
    util.debug({"i":3,d:3.14,"l":[{v:[3,7,1],b:""}],o:{s:"t\"h''''ing"}});
  }));
  button_inc = gui.new_button(screen.ww_h() + 15, screen.y() + 60, 50, 20, "Add 1", function() {
    number += iinc;
    gui.message_send("Chat " + number);
  });
  gui.screen_add(button_inc);
  gui.screen_add(gui.new_button(screen.ww_h() + 15, screen.y() + 90, 80, 40, "Send data", function() {
    gui.message_send(util.format("/anduril_gui @s sybyline:testgui false {test:%s,playernames:[%s]}", number, name_field.value()));
    item = util.new_item("minecraft:stick", number);
  }));
  gui.screen_add(gui.new_button(screen.x() + screen.w() - 10, screen.y(), 10, 10, "x", function() {
    gui.gui_close();
  }, function() {
    gui.draw_tooltip("Close", mouseX, mouseY);
  }));
  name_field = gui.new_textfield(5, 5, 200, 20, "Vinyarion");
  gui.screen_add(name_field);
  slider_object = gui.new_slider(screen.ww() - 205, 5, 200, 20, "Slide - 0", 0.0, function(slider) {
    slider.text("Slide - " + slider.value());
  });
  gui.screen_add(slider_object);
  check_object = gui.new_checkbox(screen.ww_h() + 75, screen.y() + 60, 20, 20, "", true, function(box) {
    if (box.value()) {
      iinc = 1;
      button_inc.text("Add 1");
    } else {
      iinc = -1;
      button_inc.text("Sub 1");
    }
  });
  gui.screen_add(check_object);
  list = gui.new_list(screen.x() + 10, screen.y() + 30, 100, 100, 0, 0, 90, 45);
  var dra = function(entry) {
    gui.bind_resource(texture);
    if (entry.contains(mouseX, mouseY)) {
//      GL11.glColor4d(1.0, 1.0, 1.0, 1.0);
    } else {
//      GL11.glColor4d(0.7, 0.7, 0.7, 1.0);
    }
    var ii = entry.index() % 2;
    if (ii == 0) {
      gui.draw_blitStretch(entry.x(), entry.y(), entry.w(), entry.h(), 0, 0, 128, 256);
    } else {
      gui.draw_blitStretch(entry.x(), entry.y(), entry.w(), entry.h(), 128, 0, 128, 256);
    }
  };
  var hovr = function(entry) {
    gui.draw_tooltip("Index: " + entry.index(), mouseX, mouseY);
  };
  var clik = function(entry) {
    var thingy = "n/a";
    if (exists(data.test)) {
      thingy = data.test;
    }
    gui.message_print("Click i:" + entry.index() + " d:" + thingy);
    gui.gui_clickSound();
    return true;
  };
  list.new_entry(dra, hovr, clik);
  gui.screen_add(list);
};
update_data = function() {
  util.log("Data: " + data);
  if (exists(data.playernames)) {
    util.debug_info(data.playernames);
    data.playernames.forEach(function(playername) {
      list.new_entry(function(entry) {
        //draw
        gui.draw_item(util.new_item(util.format("minecraft:player_head{SkullOwner:%s}", playername), number), entry.x(), entry.y(), true);
        gui.draw_tooltip("Name: " + playername, mouseX, mouseY);
      }, function(entry) {
        //hover
      }, function(entry) {
        //click
        name = playername;
        return true;
      });
    });
  }
};
render_pre = function() {
  gui.draw_gradientBackground();
  gui.draw_blankBackground();
};
render = function() {
};
render_post = function() {
  gui.draw_textCenter("Menu thing", screen.ww_h(), screen.y() + 5, -1);
  gui.depth_push(1);
  gui.depth_pushGL();
  gui.draw_pointSmall(mouseX, mouseY, -1);
  gui.depth_popGL();
  gui.depth_pop();
//  gui.bind_resource(texture);
//  gui.draw_blitStretch(screen.x() - 100, screen.y(), 100, 100, 0, 0, 256, 256);
//  gui.draw_item(head, mouseX - 32, mouseY - 32, true);
};
util.log("Gui is opened");
Clone this wiki locally