|
| 1 | +--- |
| 2 | +title: Central Monitor & Placeholder System |
| 3 | +--- |
| 4 | + |
| 5 | +### Custom monitor modules |
| 6 | +If you want to add a monitor module, simply attach a component that implements `IMonitorModuleItem` to your `ComponentItem`. |
| 7 | +Modules can have a custom UI, can be ticked (in a placeholder or not) and, most importantly, rendered. |
| 8 | +??? example "Example of a custom module in Java" |
| 9 | + ```java |
| 10 | + public class ExampleModuleBehaviour implements IMonitorModuleItem { |
| 11 | + @Override |
| 12 | + public String getType() { |
| 13 | + // can be any string, this is currently only used for CC: Tweaked compat |
| 14 | + return "example"; |
| 15 | + } |
| 16 | + |
| 17 | + @Override |
| 18 | + public void tick(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group) { |
| 19 | + // this is only called on the logical server |
| 20 | + // put all of your module's logic here instead of in getRenderer(stack) |
| 21 | + // can also be left completely empty (like in the image module) |
| 22 | + } |
| 23 | + |
| 24 | + @Override |
| 25 | + public void tickInPlaceholder(ItemStack stack, PlaceholderContext context) { |
| 26 | + // this is also only called on the logical server, but only when a placeholder accesses this module and wants to render it |
| 27 | + // this *isn't* called on each tick |
| 28 | + // you can even put the same code here as in the tick() method, like the text module does |
| 29 | + } |
| 30 | + |
| 31 | + @Override |
| 32 | + public IMonitorRenderer getRenderer(ItemStack stack) { |
| 33 | + // this is only called on the logical client |
| 34 | + // should return a new instance of the renderer for this module (not null) |
| 35 | + // for examples of renderer code look in the GTCEu Modern github: |
| 36 | + // https://github.com/GregTechCEu/GregTech-Modern/tree/1.20.1/src/main/java/com/gregtechceu/gtceu/client/renderer |
| 37 | + return new MonitorTextRenderer(MultiLineComponent.of("this text is displayed on the monitor"), 1.0); |
| 38 | + } |
| 39 | + |
| 40 | + @Override |
| 41 | + public Widget createUIWidget(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group) { |
| 42 | + // should create the UI for your module and return it |
| 43 | + // if the module doesn't need a UI just return new WidgetGroup() |
| 44 | + return new WidgetGroup(); |
| 45 | + } |
| 46 | + } |
| 47 | + ``` |
| 48 | + |
| 49 | +!!! info "For info on the placeholder system itself, see [the gameplay wiki page](../../Gameplay/Central-Monitor.md)" |
| 50 | + |
| 51 | +### Adding custom placeholders |
| 52 | + |
| 53 | +Placeholders can be added by calling `PlaceholderHandler.addPlaceholder(...)` at any point during runtime (preferably at mod init time). |
| 54 | +They can take any number of arguments in the form of a `List<MultiLineComponent>`. They also take an instance of `PlaceholderContext` and |
| 55 | +must return a `MultiLineComponent`. Placeholders can also render literally anything, not only text, using `MultiLineComponent.addRenderer()`, |
| 56 | +`GraphicsComponent` and an `IPlaceholderRenderer` (that has to be registered separately using `PlaceholderHandler.addRenderer(...)`) |
| 57 | + |
| 58 | +??? example "Example of a `sum` placeholder in Java" |
| 59 | + ```java |
| 60 | + public class Example { |
| 61 | + // you should call this function at mod initialization |
| 62 | + public static void addPlaceholders() { |
| 63 | + int priority = 1; // by default the priority of all placeholders is 0 (you don't have to specify it) |
| 64 | + PlaceholderHandler.addPlaceholder(new Placeholder("sum", priority) { |
| 65 | + @Override |
| 66 | + public MultiLineComponent apply(PlaceholderContext ctx, List<MultiLineComponent> args) throws PlaceholderException { |
| 67 | + PlaceholderUtils.checkArgs(args, 2); // check that there are exactly 2 arguments |
| 68 | + double a = PlaceholderUtils.toDouble(args.get(0)); |
| 69 | + double b = PlaceholderUtils.toDouble(args.get(1)); |
| 70 | + return MultiLineComponent.literal(a + b); |
| 71 | + } |
| 72 | + }); |
| 73 | + // you can call addPlaceholder as many times as you need |
| 74 | + // if you want to override an existing placeholder, simply add a new one with the same name and a higher or equal priority |
| 75 | + } |
| 76 | + } |
| 77 | + ``` |
| 78 | + |
| 79 | +!!! tip "Placeholder exceptions" |
| 80 | + Any runtime exception that occurs while processing a placeholder will be caught and even displayed to the player. |
| 81 | + Instead of relying on runtime exceptions though, you should throw any subclass of `PlaceholderException`, for example |
| 82 | + `InvalidNumberException` or `MissingItemException`. All the `PlaceholderUtils` methods throw these, so you should use them |
| 83 | + instead of calling `parseDouble` yourself, for example. |
| 84 | + |
| 85 | +!!! note "Placeholder data" |
| 86 | + If your placeholder needs to save any data specific to the placeholder caller, you can use `getData(ctx)` at any point in |
| 87 | + a placeholder. It will return a `CompoundTag` that is automatically saved, and you're free to modify it in whatever way you want. |
| 88 | + |
| 89 | +### Placeholder graphics |
| 90 | + |
| 91 | +You may have noticed, that some placeholders output graphics instead of text, for example `rect` or `quad`. |
| 92 | +To achieve that you have to write your own class that implements `IPlaceholderRenderer`, or use an existing one. |
| 93 | +They work similarly to normal renderers, except you can pass a `CompoundTag` into them from your placeholder. |
| 94 | +To register one, call `PlaceholderHandler.addRenderer("put_id_here", new YourRendererClassHere())`. |
| 95 | +After that, you can reference it from any placeholder by calling `output.addGraphics(new GraphicsComponent(x, y, "put_id_here", renderData)` |
| 96 | +on the object that your placeholder will return. `renderData` is the same `CompoundTag` that will be passed into your renderer as an argument. |
| 97 | +This is done to avoid calling rendering code on the server side, as all placeholders are processed server-side only. A neat side effect of that |
| 98 | +is that all players will (almost always) see the same thing on the monitor. |
| 99 | + |
| 100 | +!!! warning "Graphics do not work on the Computer Monitor Cover" |
| 101 | + |
| 102 | +### Placeholder parsing |
| 103 | + |
| 104 | +You may want to add something that needs to parse a string containing placeholders. To achieve that, you can use |
| 105 | +`PlaceholderHandler.processPlaceholders(string, context)`. You can also use `PlaceholderHandler.placeholderExists(name)` |
| 106 | +to check if a placeholder exists, or `PlaceholderHandler.getAllPlaceholderNames()` to get all placeholders. |
| 107 | +To get a `PlaceholderContext`, you just have to call its constructor (it takes in basic parameters like `Level`, `BlockPos`, etc., most of which can be `null`). |
0 commit comments