and that's QMAW

This commit is contained in:
Bob 2025-08-07 17:45:16 +02:00
parent d70464b3d1
commit e8b7504fff
7 changed files with 264 additions and 26 deletions

View File

@ -3,12 +3,20 @@ package com.hbm.qmaw;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import com.hbm.lib.RefStrings;
import com.hbm.qmaw.components.*;
import cpw.mods.fml.common.FMLCommonHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.resources.LanguageManager;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
public class GuiQMAW extends GuiScreen {
@ -16,19 +24,128 @@ public class GuiQMAW extends GuiScreen {
protected static final ResourceLocation texture = new ResourceLocation(RefStrings.MODID + ":textures/gui/gui_wiki.png");
public String title;
public List<ManualElement[]> lines = new ArrayList();
public ItemStack icon;
public List<List<ManualElement>> lines = new ArrayList();
protected int xSize = 192;
protected int ySize = 256;
protected int xSize = 340;
protected int ySize = 224;
protected int guiLeft;
protected int guiTop;
protected boolean isDragging = false;
protected int scrollProgress = 0;
protected int lastClickX = 0;
protected int lastClickY = 0;
public static final String EN_US = "en_US";
public GuiQMAW(QuickManualAndWiki qmaw) {
parseQMAW(qmaw);
}
protected void parseQMAW(QuickManualAndWiki qmaw) {
LanguageManager lang = Minecraft.getMinecraft().getLanguageManager();
this.title = qmaw.title.get(lang.getCurrentLanguage());
if(title == null) this.title = qmaw.title.get(EN_US);
if(title == null) this.title = "Missing Localization!";
this.icon = qmaw.icon;
String toParse = qmaw.contents.get(lang.getCurrentLanguage());
if(toParse == null) toParse = qmaw.contents.get(EN_US);
if(toParse == null) toParse = "Missing Localization!";
toParse = "" + toParse; // strings are reference types, no?
int maxLineLength = xSize - 29;
String prevToParse = "" + toParse;
int maxIterations = 1000;
int currentLineWidth = 0;
while(!toParse.isEmpty() && maxIterations > 0) {
if(this.lines.isEmpty()) this.lines.add(new ArrayList());
List<ManualElement> currentLine = this.lines.get(this.lines.size() - 1);
toParse = toParse.trim();
maxIterations--;
if(toParse.startsWith("<br>")) {
toParse = toParse.substring(4);
currentLine = new ArrayList();
this.lines.add(currentLine);
currentLineWidth = 0;
continue;
}
// handle links
if(toParse.startsWith("[[")) {
int end = toParse.indexOf("]]");
if(end != -1) {
String link = toParse.substring(2, end);
toParse = toParse.substring(end + 2);
int pipe = link.indexOf("|");
QComponentLink linkComponent;
if(pipe == -1) {
linkComponent = new QComponentLink(link, link);
} else {
linkComponent = new QComponentLink(link.substring(pipe + 1, link.length()), link.substring(0, pipe));
}
// append to current line
int width = linkComponent.getWidth();
if(width + currentLineWidth <= maxLineLength) {
currentLine.add(linkComponent);
currentLineWidth += width;
// new line
} else {
currentLine = new ArrayList();
this.lines.add(currentLine);
currentLine.add(linkComponent);
currentLineWidth = width;
}
prevToParse = "" + toParse;
continue;
}
}
// handle standard text
int delimit = toParse.length();
int spaceIndex = toParse.indexOf(" ");
if(spaceIndex != -1) delimit = Math.min(delimit, spaceIndex);
int linkIndex = toParse.indexOf("[[");
if(linkIndex != -1) delimit = Math.min(delimit, linkIndex);
int brIndex = toParse.indexOf("<br>");
if(brIndex != -1) delimit = Math.min(delimit, brIndex);
if(delimit > 0) {
QComponentText textComponent = new QComponentText(toParse.substring(0, delimit) + (spaceIndex == delimit ? " " : ""));
toParse = toParse.substring(delimit);
// append to current line
int width = textComponent.getWidth();
if(width + currentLineWidth <= maxLineLength) {
currentLine.add(textComponent);
currentLineWidth += width;
// new line
} else {
currentLine = new ArrayList();
this.lines.add(currentLine);
currentLine.add(textComponent);
currentLineWidth = width;
}
prevToParse = "" + toParse;
continue;
}
if(toParse.equals(prevToParse)) break;
prevToParse = "" + toParse;
}
}
@Override
@ -38,19 +155,85 @@ public class GuiQMAW extends GuiScreen {
this.guiTop = (this.height - this.ySize) / 2;
}
@Override
protected void mouseClicked(int x, int y, int key) {
super.mouseClicked(x, y, key);
if(key == 0) {
this.lastClickX = x;
this.lastClickY = y;
}
}
public int getSliderPosition() {
double progress = (double) scrollProgress / (double) (lines.size() - 1);
return 25 + (int) (progress * 180);
}
@Override
public void drawScreen(int mouseX, int mouseY, float f) {
this.drawDefaultBackground();
if(Mouse.isButtonDown(0) && guiLeft + xSize - 15 <= mouseX && guiLeft + xSize - 15 + 12 > mouseX && guiTop + 25 < mouseY && guiTop + 25 + 191 >= mouseY) {
isDragging = true;
}
if(!Mouse.isButtonDown(0)) isDragging = false;
if(isDragging) {
int min = guiTop + 25 + 8;
int max = guiTop + 25 + 191 - 8;
int span = max - min;
double progress = MathHelper.clamp_double((double) (mouseY - min) / span, 0D, 1D);
this.scrollProgress = MathHelper.clamp_int((int) Math.round((lines.size() - 1) * progress), 0, lines.size() - 1);
}
handleScroll();
//this.drawRect(0, 0, this.width, this.height, 0x80919191);
this.drawRect(0, 0, this.width, this.height, 0xe0000000);
this.drawGuiContainerBackgroundLayer(f, mouseX, mouseY);
GL11.glDisable(GL11.GL_LIGHTING);
this.drawGuiContainerForegroundLayer(mouseX, mouseY);
GL11.glEnable(GL11.GL_LIGHTING);
this.lastClickX = 0;
this.lastClickY = 0;
}
protected void handleScroll() {
if(!Mouse.isButtonDown(0) && !Mouse.isButtonDown(1) && Mouse.next()) {
int scroll = Mouse.getEventDWheel();
if(scroll > 0 && this.scrollProgress > 0) this.scrollProgress--;
if(scroll < 0 && this.scrollProgress < this.lines.size() - 1) this.scrollProgress++;
}
}
private void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
int x = 0;
int y = 0;
int x = 4;
int y = 4;
if(this.icon != null) {
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_DEPTH_TEST);
Minecraft mc = Minecraft.getMinecraft();
GL11.glRotated(180, 1, 0, 0);
RenderHelper.enableStandardItemLighting();
GL11.glRotated(-180, 1, 0, 0);
itemRender.renderItemAndEffectIntoGUI(this.fontRendererObj, mc.renderEngine, this.icon, guiLeft + x, guiTop + y);
itemRender.renderItemOverlayIntoGUI(this.fontRendererObj, mc.renderEngine, this.icon, guiLeft + x, guiTop + y, null);
RenderHelper.disableStandardItemLighting();
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glPopMatrix();
x += 20;
y += (16 - this.fontRendererObj.FONT_HEIGHT) / 2;
}
y += 1;
this.fontRendererObj.drawString(title, guiLeft + x, guiTop + y, 0xFFFFFF);
}
@ -58,6 +241,52 @@ public class GuiQMAW extends GuiScreen {
private void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) {
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
Minecraft.getMinecraft().getTextureManager().bindTexture(texture);
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize);
drawTexturedModalRect(guiLeft, guiTop, 0, 0, 170, ySize);
drawTexturedModalRect(guiLeft + 170, guiTop, 22, 0, 170, ySize);
// scroll bar
drawTexturedModalRect(guiLeft + xSize - 15, guiTop + getSliderPosition(), 192, 0, 12, 16);
int x = guiLeft + 7;
int y = guiTop + 30;
int lineNum = 0;
for(List<ManualElement> line : lines) {
lineNum++;
if(lineNum <= this.scrollProgress) continue;
int maxHeight = 0;
int inset = 0;
for(ManualElement element : line) {
maxHeight = Math.max(maxHeight, element.getHeight());
}
if(y + maxHeight > guiTop + 219) break;
if(line.isEmpty()) y += this.fontRendererObj.FONT_HEIGHT;
for(ManualElement element : line) {
int elementX = x + inset;
int elementY = y + (maxHeight - element.getHeight()) / 2;
boolean mouseOver = (elementX <= mouseX && elementX + element.getWidth() > mouseX && elementY < mouseY && elementY + element.getHeight() >= mouseY);
element.render(mouseOver, elementX, elementY, mouseX, mouseY);
if(elementX <= lastClickX && elementX + element.getWidth() > lastClickX && elementY < lastClickY && elementY + element.getHeight() >= lastClickY)
element.onClick();
inset += element.getWidth();
}
y += maxHeight + 2;
}
}
@Override
protected void keyTyped(char typedChar, int keyCode) {
if(keyCode == 1 || keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode()) {
this.mc.displayGuiScreen((GuiScreen) null);
this.mc.setIngameFocus();
}
}
}

View File

@ -1,12 +1,9 @@
package com.hbm.qmaw;
public abstract class ManualElement {
public int x;
public int y;
public abstract int getWidth();
public abstract int getHeight();
public abstract void render(boolean isMouseOver, int mouseX, int mouseY);
public abstract void render(boolean isMouseOver, int x, int y, int mouseX, int mouseY);
public abstract void onClick();
}

View File

@ -172,7 +172,9 @@ public class QMAWLoader implements IResourceManagerReloadListener {
}
/** Extracts all the info from a json file's main object to add a QMAW to the system. Very barebones, only handles name, icon and the localized text. */
public static void registerJson(String name, JsonObject json) {
public static void registerJson(String file, JsonObject json) {
String name = json.get("name").getAsString();
QuickManualAndWiki qmaw = new QuickManualAndWiki(name);
if(json.has("icon")) {
@ -195,7 +197,7 @@ public class QMAWLoader implements IResourceManagerReloadListener {
ItemStack trigger = SerializableRecipe.readItemStack(element.getAsJsonArray());
// items get renamed and removed all the time, so we add some more debug goodness for those cases
if(trigger == null || trigger.getItem() == ModItems.nothing) {
MainRegistry.logger.info("[QMAW] Manual " + name + " references nonexistant trigger " + element.toString());
MainRegistry.logger.info("[QMAW] Manual " + file + " references nonexistant trigger " + element.toString());
} else {
QMAWLoader.triggers.put(new ComparableStack(trigger).makeSingular(), qmaw);
}

View File

@ -9,10 +9,12 @@ import com.hbm.qmaw.QuickManualAndWiki;
import cpw.mods.fml.common.FMLCommonHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
public class QComponentLink extends ManualElement {
@ -35,6 +37,8 @@ public class QComponentLink extends ManualElement {
} else {
this.icon = qmaw.icon;
}
this.font = Minecraft.getMinecraft().fontRenderer;
}
public QComponentLink setColor(int color, int hoverColor) {
@ -45,30 +49,33 @@ public class QComponentLink extends ManualElement {
@Override
public int getWidth() {
return font.getStringWidth(text) + (icon != null ? 20 : 0);
return font.getStringWidth(text) + (icon != null ? 18 : 0);
}
@Override
public int getHeight() {
return Math.max(font.FONT_HEIGHT, icon != null ? 18 : 0);
return Math.max(font.FONT_HEIGHT, icon != null ? 16 : 0);
}
@Override
public void render(boolean isMouseOver, int mouseX, int mouseY) {
int x = this.x;
int y = this.y;
public void render(boolean isMouseOver, int x, int y, int mouseX, int mouseY) {
if(this.icon != null) {
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_DEPTH_TEST);
Minecraft mc = Minecraft.getMinecraft();
GL11.glRotated(180, 1, 0, 0);
RenderHelper.enableStandardItemLighting();
GL11.glRotated(-180, 1, 0, 0);
itemRender.renderItemAndEffectIntoGUI(this.font, mc.renderEngine, this.icon, x, y);
itemRender.renderItemOverlayIntoGUI(this.font, mc.renderEngine, this.icon, x, y, null);
RenderHelper.disableStandardItemLighting();
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glPopMatrix();
x += 20;
y += (18 - font.FONT_HEIGHT) / 2;
x += 18;
y += (16 - font.FONT_HEIGHT) / 2;
}
font.drawString(text, x, y, isMouseOver ? hoverColor : color);
@ -76,6 +83,9 @@ public class QComponentLink extends ManualElement {
@Override public void onClick() {
QuickManualAndWiki qmaw = QMAWLoader.qmaw.get(link);
if(qmaw != null) FMLCommonHandler.instance().showGuiScreen(new GuiQMAW(qmaw));
if(qmaw != null) {
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
FMLCommonHandler.instance().showGuiScreen(new GuiQMAW(qmaw));
}
}
}

View File

@ -36,7 +36,7 @@ public class QComponentText extends ManualElement {
}
@Override
public void render(boolean isMouseOver, int mouseX, int mouseY) {
public void render(boolean isMouseOver, int x, int y, int mouseX, int mouseY) {
font.drawString(text, x, y, color);
}

View File

@ -3,9 +3,9 @@
"icon": ["hbm:item.gun_light_revolver", 1, 0],
"trigger": [["hbm:item.plate_iron"], ["hbm:item.plate_gold"], ["hbm:item.plate_sludge"]],
"title": {
"en_US": "TEST PAGE"
}
"en_US": "Demo"
},
"content": {
"en_US": "This is a test page that links to [[Demo|DEMO]].\n\nFormat line break"
"en_US": "Referred to as a collective as \"flux\" in NTM, neutrons are the sole driver of fission and therefore the driver of heat production in an RBMK. Fuel assemblies in fuel rod columns will create neutrons according to a mathematically defined flux function which is described in more detail in Category:RBMK Fuel. Some will spontaneously output neutrons whereas others will only emit them when they receive input neutrons with most fuels requiring some form of input to get started. Neutrons are emitted in every horizontal direction away from the fuel rod and will interact with various types of columns during their travel before eventually being absorbed by something. Neutrons are either emitted as fast moving or slow moving and react best with fuels in either state depending on the properties of the fuel. To convert fast neutrons to slow neutrons, they must pass through a moderator such as graphite which can come in the form of moderated rods or moderator columns. There is no way to make slow neutrons become fast after being moderated. If not properly sealed, neutrons can leak out of the RBMK and cause immense environmental radiation. To prevent this, cover every column in the RBMK that neutrons pass through with an RBMK cover panel and seal off all paths that neutrons take with either solid blocks or a column that absorbs the neutrons fully."
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1017 B