Skip to content
vini2003 edited this page Jan 16, 2020 · 12 revisions

Contents:

  • BaseRenderer - in-house rendering utilities, exposed publicly.
  • BaseScreen- extension of Vanilla screen, implements methods used by Spinnery, and overrides default behaviour. extend this if you need extra functionality.
  • BaseContainer - extension of Vanilla container, implements methods used by Spinnery, and overrides default behaviour. extend this if you need extra functionality.
  • WWidget - base class that any and all widgets build/should build upon. extend this if you need extra functionality; though Spinnery, by default, provides some extensions:
    • WPanel - all widgets must be linked to a panel, but not necessarily be located on top of it.
    • WButton - implements a simple self-resetting button. Optionally, provides a label.
    • WToggle - implements a simple non-self-resetting toggle. Optionally, provides a label.
    • WDropdown - implements a simple drop-down panel. Optionally, provides a label. Internally, widgets are stored in a two-dimensional array, implemented through a List of Lists.
    • WList - implements a simple list, with smooth scrolling. Optionally, provides a label. Internally, widgets are stored in a two-dimensional array, implemented through a List of Lists.
    • WDynamicText - implements a complete textbox, with support for Ctrl + C, Ctrl + V, Ctrl + A, Ctrl + D, Shift + Left (A), Shift + Right (D), Delete, Left (A), Right (D) and Backspace, alongside text culling allowing for longer-than-textbox texts. Optionally, provides a label/default text.
    • WStaticText - implements a simple static text object, with no default text wrapping by default.
    • WSlot - reimplements Slot class to be decent. Shift + RMB + Drag will place 1 item in slots the cursor is dragged on top of. Shift + LMB + Drag will evenly distribute items through the same slots.
    • WStaticImage - implements a static image object that displays the selected image.
    • WDynamicImage - implements a dynamic image object that displays a sequence of images. Work in progress.
  • Theme - handles theme loading, parsing, building, and management. Themes are JSONs located under ./minecraft/resources/spinnery. A default one is provided. Themes have an ID, which is a String. A Theme can be retrieved from the ResourceRegistry with ResourceRegistry.get(theme). A sub-theme (for a specific widget) can be obtained with .get(theme).getXTheme(). WColor is a class that holds Alpha, Red, Green and Blue members used for drawing. Strings in the JSON are parsed to WColors, which are stored inside the sub-theme. A WColor element can be obtained with .get(theme).getXTheme().getXPart(). Raw RGB integer values can be obtained with .RGB. Any themes located in ./minecraft/resources/spinnery will automatically be loaded on resource load/reload (supporting F3 + T).

Example:

Create a class that extends BaseContainer:

package spinnery.container.common;

import net.minecraft.entity.player.PlayerInventory;

import spinnery.container.common.widget.WPanel;

public class TestContainer extends BaseContainer {
	public TestContainer(int synchronizationID, PlayerInventory newLinkedPlayerInventory) {
		super(synchronizationID, newLinkedPlayerInventory);
	}
}

Then, add a main panel to the container:

setLinkedPanel(new WPanel(x, y, z, sizeX, sizeY, this));

Afterwards, register the container on the server:

ContainerProviderRegistry.INSTANCE.registerFactory(ID, (syncId, id, player, buffer) -> new TestContainer(syncId, player.inventory))

As you may have realized, buffer is a PacketByteBuf which can be used to pass customized data to the container constructor. Once your TestContainer is registered, you can open it with:

ContainerProviderRegistry.INSTANCE.openContainer(ID, player, (buffer) -> {});

You may pass data to buffer with the lambda expression which we left empty in (buffer) -> {}. Before moving on, we must register our TestContainer to a screen so we can actually play with it. That's done in the client, with:

ScreenProviderRegistry.INSTANCE.registerFactory(ID, (syncId, identifier, player, buffer) -> new BaseScreen(ID, new TestContainer(syncId, player.inventory), player));

Given we don't need anything fancier than a BaseScreen, we register one to TestContainer.

Once that's done, congratulations, you have a working container and screen that can be summoned at any time!

Here's some example code so you have something to base yourself on:

public class TestContainer extends BaseContainer {
	public TestContainer(int synchronizationID, BlockPos newLinkedInventoryPosition, PlayerInventory newLinkedPlayerInventory) {
		super(synchronizationID, newLinkedPlayerInventory);

		setLinkedInventory(((TestBlock) newLinkedPlayerInventory.player.world.getBlockState(newLinkedInventoryPosition).getBlock()).getInventory());

		setLinkedPanel(new WPanel(30, 0, - 10, 170, 210, this));

		linkedPanel.center();

		WSlot.addPlayerInventory(0, 18, 18, linkedPlayerInventory, linkedPanel);

		WDropdown dropdownA = new WDropdown(WAnchor.MC_ORIGIN, - 70, 0, 0, 66, 18, 66, 170, linkedPanel);

		WStaticText staticTextA = new WStaticText(WAnchor.MC_ORIGIN, 0, 0, 20, "? ?? ???", linkedPanel);

		dropdownA.add(staticTextA);

		WList listA = new WList(WAnchor.MC_ORIGIN, 174, 0, 0, 66, 170, linkedPanel);

		for (int i = 0; i < 54; ++ i) {
			WSlot slotA = new WSlot(WAnchor.MC_ORIGIN, 0, 0, 3, 18, 18, ++ i, linkedInventory, linkedPanel);
			WSlot slotB = new WSlot(WAnchor.MC_ORIGIN, 0, 0, 3, 18, 18, ++ i, linkedInventory, linkedPanel);
			WSlot slotC = new WSlot(WAnchor.MC_ORIGIN, 0, 0, 3, 18, 18, ++ i, linkedInventory, linkedPanel);

			listA.add(slotA, slotB, slotC);
		}

		WHorizontalSlider sliderA = new WHorizontalSlider(WAnchor.MC_ORIGIN, 30, 25, 0, 18, 9, 9, linkedPanel);

		WToggle toggleA = new WToggle(WAnchor.MC_ORIGIN, 30, 50, 0, 18, 9, linkedPanel);
		WToggle toggleB = new WToggle(WAnchor.MC_ORIGIN, 30, 70, 0, 18, 9, linkedPanel);
		WToggle toggleC = new WToggle(WAnchor.MC_ORIGIN, 30, 90, 0, 18, 9, linkedPanel);

		WButton buttonA = new WButton(WAnchor.MC_ORIGIN, 55, 50, 20, 9, 9, linkedPanel);
		WButton buttonB = new WButton(WAnchor.MC_ORIGIN, 55, 70, 20, 9, 9, linkedPanel);
		WButton buttonC = new WButton(WAnchor.MC_ORIGIN, 55, 90, 20, 9, 9, linkedPanel);

		buttonA.setLabel("Yeet");
		buttonB.setLabel("Yoot");
		buttonC.setLabel("Yuut");

		WDynamicText dynamicTextA = new WDynamicText(WAnchor.MC_ORIGIN, 30, 110, 0, 100, 18, linkedPanel);

		dynamicTextA.setLabel("Type here...");

		listA.setLabel("Slots!");

		linkedPanel.setLabel("Hello, world!");

		dropdownA.setLabel("OwO");

		getLinkedPanel().add(listA, sliderA, dropdownA, toggleA, toggleB, buttonA, buttonB, buttonC, toggleC, dynamicTextA);
	}
}

Notice that the TestContainer constructor was altered to take a BlockPos, meaning the registries were changed, and the call to open the container writes the BlockPos to buffer.

The end result?

Spinnery

Spinnery is licensed under the LGPL-3.0 license.

Clone this wiki locally