-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Formspec Refactor #9358
Comments
I think it might be useful to either start a document somewhere with the high-level goals of formspecs (ie, what is our end-goal for this API?) that people can work on, or have some sort of 'meeting' in the dev IRC. At this rate, I get the impression that this discussion might last months without going anywhere otherwise. Of course, this is really just more talk... I'm going to try drafting a larger proposal sometime this weekend, and I'll post it here for discussion/feedback. |
Alright, so I was busy last weekend and this week but here's a general idea of what I'd like to see happen: Initial ProposalThis is a proposal for refactoring formspecs and nothing else. It's not about adding new features, but instead primarily aimed at housekeeping and making things easier to extend, test, and maintain. With that said, it's worth restating some of our long-term goals and keeping them in mind when designing the new architecture to avoid future roadblocks. Longterm Goals
Current major issues
ProposalManagement
Parsing
Structure
So how do we do this?
Since this proposal was slightly rushed, I'm sure I've missed some things here. Still, I think this offers a much more concrete plan and an actual roadmap for executing it! I welcome feedback, let's try to make this a good refactor. |
Actually, theoretically the irrlicht gui system isn't that bad. It's just not easily extensible enough. Warning, the following section is about the problems of the limitations of the current formspec language and hence a bit offtopic: |
Pulling the irrlicht GUI source code into our own code and refactoring it is likely to be a good bet |
The Irrlicht gui system isn't bad, but it's not meshing well with what we're doing and the engine is more or less on life support, leaning on it as we have is not really a good idea. I'm also a little worried about carrying on Irrlicht... it's pretty old tech at this point, and I get the impression that we might be stuck redesigning it later to get new features/graphics APIs working someday. This is why I support wrapping and abstracting as much of it as possible and building a new system on top, it lets us change tech later without eating a massive cost.
Definitely wouldn't support either of these options, integrating them into another renderer would be a nightmare and they're not designed for games at all. Maybe something light like imGUI or nuklear, but the problem with these is that they're designed more for immediate-mode UIs, not really the kind of big structured over-the-network UIs that formspecs present. I agree with your second point, but it's out of scope for a refactor like this... regardless, you might've noticed that I support using a proper hierarchy in the backend so that we can transition to such a format in the future. |
I guess, honestly, the thing I'm worried about is that it feels like we have already reinvented the wheel, and formspecs have some pretty particular requirements that most conventional UI engines aren't designed for (defining/modifying a UI on one end of a network and presenting it on another, only the web follows this pattern). To me, that implies that as long as we try to rely on conventional solutions, we're going to have to hack them to do what we need. |
This is not appropriate for production games - it says this at the top of the readme |
I don't think ditching Irrlicht is the way to go. Instead, we should keep Irrlicht, but have an abstraction layer. The current way we handle elements is that they have a As for XML, I don't think that's a very good idea. This is used by the web, but the web wasn't designed with interactivity in mind at all. JavaScript came from Netscape Navigator. If you look at most traditional GUI libraries, they use functions to create elements with the resulting variable referencing that element. Very similar in design to Minetest's HUD. I think that this will probably end better than building FormSpecs on XML. But, as said, this is offtopic because we are just working on the internal code for now. |
This comment has been minimized.
This comment has been minimized.
@Unarelith I know you've left, but any thoughts on this? |
Based on the comments above, I've made a design focusing on the parsing side of things. Source UMLet file: formspecrefactor.uxf.txt Some notes:
Remaining questions:
|
Feedback please |
Let me be clear--on my end, my lack of feedback is a lack of objections. I generally agree with your proposal, and have since you made it. Unfortunately I don't have much to add for your questions, since I haven't touched the current field submission/inventory code. |
I'd really love to give good feedback, but I'm no computer science person. I self-taught myself all my programming knowledge, and I really don't know what constitutes a good organization for a large project. That being said, I'll try my best, but take it with a grain of salt.
|
|
I believe I've come up with something essential to refactoring formspecs after some failed work on a PR I was working on. Please read and give commentary; I think I've stumbled upon one of the largest problems with formspec code and why it is so non-extensible. I think giving Specifically, I think this idea of parser vs. layouter is central to this refactor. To emphasize the importance of this, I'll give a word from experience. I have worked on two attempted PRs that touched on this matter, both failed and never posted on GitHub: Resizing the window with formspecs dynamically without reparsing, and CSS-like units, basically The problem with dynamic resizing is that the parsing of the formspec string also lays everything out, like CSS-like units have the same problem because they need access to Perhaps it is better to just limit this refactor to just rearranging code, but this parsing vs. layouting must be addressed at some point, or formspecs really won't be able to grow. |
I generally agree with the above. With that said, I think it's best to continue with the current plan and implement such a parsing/layout split later. While it does mean that some of our new code will go through multiple revisions, I think it's best to start by separating and cleaning things a bit before we change the layout mechanism. Otherwise, we're going to wind up with a very large, messy, and slow to merge PR. We should do this afterwards, though. |
That PR is still in a partial state of progress, the eventual aim is for ParserState to only contain parser-time stuff - as its name says. You can't do everything in one go, you have to do it progressively I do intend to add support for GUI layouting in the future, but that's not the point of this issue. I define formspecs as strictly the domain-specific language, they will need to be deprecated one day. The point is to separate formspec-related stuff from general GUI stuff, so that an alternative format can be introduced. Perhaps this is a lost cause, and the code should just be archived and this issue closed |
Nothing lost about it imo. It's just a big hill to climb. |
Yes; I suppose it would be better as a separate PR. I was a little aggressive in promoting my idea and didn't mean to diminish the importance of or work put into this refactor; sorry. It's not a lost cause though. Coding is a large hurdle, but by no means impossible. Getting a consensus on a new format for formspecs is probably the harder thing since everyone and their brother has their own idea on what it should be. But this isn't something being doing alone. It's already been shown that there are multiple people willing to help and have helped with previous PRs. There are two core devs willing to work on formspecs (yourself included, of course), so PRs can get merged. It will only be impossible if everyone gives up hope. |
Here's my specific roadmap for the first parts of the refactor: https://forum.minetest.net/viewtopic.php?p=379528#p379528 |
About using XML : If moving from formspec strings, using Lua tables would then be a better choice. Tables have hierarchy and could include functions that could be used as event handlers (onClick, onClose, onMouseOver…) like in many other MT definitions. Anyway, changing GUI specification format is kind of risky. But it is obviously a good thing to be prepared to it. It seems to me important to separate parsing from any other stuff (drawing, layout, event). |
Yeah, a Lua DSL would be a good choice - changing the format is covered by #6527 |
Refactor update: Things are going well, although slower than I expected (I wasn't able to work on it for two days). Specifically, the parsing framework is basically in place, and I've gotten buttons to work with the new code. Technical aspects: I'm largely using Rubenwardy's proposed design and earlier PR, but I've added my own changes:
So what does the button parsing and creation code look like? It's actually fairly simple: Code:Parsing: bool parse_button(ParserState *state, FormSpecElement *element, ElementSpec *spec)
{
if (element->checkLength(state->formspec_version, {4}))
return true;
spec->setElementType(ELEMENT_BUTTON);
spec->setVector2df ("pos", element->arg(0).asVector2df());
spec->setVector2df ("size", element->arg(1).asVector2df());
spec->setWideString("label", element->arg(3).asWideString());
const std::string &name = element->arg(2).asString();
spec->setString("name", name);
if (state.focused_element == name)
spec->setBool("focused", true);
if (element->getType() == "button_exit")
spec->setBool("exit", true);
return element->hasInvalidArgument();
} Creation void GUIFormSpecMenu::createButton(ParserState *state, ElementSpec *espec)
{
v2s32 pos, size;
core::recti rect;
if (state->real_coordinates) {
pos = getElementPosition(espec->getVector2df("pos"));
size = getElementGeometry(espec->getVector2df("size"));
rect = core::recti(pos, pos + size);
} else {
pos = getOldElementPosition(espec->getVector2df("pos"));
pos.Y += (size.Y * imgsize.Y) / 2;
size.X = (espec->getVector2df("size").X * spacing.X) - (spacing.X - imgsize.X);
rect = core::recti(pos.X, pos.Y - m_btn_height,
pos.X + size.X, pos.Y + m_btn_height);
}
if (!state->explicit_size) // TODO: Remove
warningstream << "Invalid use of button without a size[] element" << std::endl;
bool is_exit = espec->getBool("exit");
FieldSpec fspec(
espec->getString("name"),
translate_string(espec->getWideString("label")),
L"",
258 + m_fields.size()
);
fspec.ftype = f_Button;
fspec.is_exit = is_exit;
GUIButton *e = GUIButton::addButton(Environment, rect, m_tsrc,
state->current_parent, fspec.fid, fspec.flabel.c_str());
e->setStyles(getStyleForElement(is_exit ? "button_exit" : "button",
fspec.fname, is_exit ? "button" : ""));
if (espec->getBool("focused"))
Environment->setFocus(e);
m_fields.push_back(fspec);
} So, what is left to be done? Mainly, migrating all the elements to the new format. This is fairly simple, as seen with the above code examples, but also necessitates moving lots of stuff into The branch if you want a look at it: https://github.com/v-rob/minetest/tree/refactor-parse |
There seems to be some conflict on how the refactor should be designed and carried out, and I want to resolve these before I do anything else. So here goes: First, to refactor or to not refactor:
Secondly, parsing design:
Third, Irrlicht usage; I think it is almost certain that we will use Irrlicht as the GUI system while we are redesigning it, but there are still choices to be made on how we use it:
I personally would opt for a complete rewrite as opposed to a refactor, but doing this requires formalizing the JSON format, which needs discussion. For parsing, I would choose element definitions with heterogeneous containers, which is what my refactor was currently using. As for Irrlicht usage, I think a wrapper class is the no-brainer, although I think others will likely argue for a different library. I would like feedback on what others think should be done before I move forward. |
A large-scale formspec refactor is no longer relevant. Replacement is the way things are going. |
This thread is for technical discussion about the code behind formspecs. It's not about the formspec language itself, but the implementation of it. Please do not request any user-facing features here
Formspecs and GUIs have been improving significantly lately. Now, all physical formspec elements create IGUIElements.
Discussion: http://irc.minetest.net/minetest-dev/2020-02-02
Aims
The text was updated successfully, but these errors were encountered: