Publish the source code of all in-game widgets

The worst monsters in the Hearthlands warp the fabric of space and time...

Publish the source code of all in-game widgets

Postby ElSid » Mon Jul 20, 2020 10:21 pm

While working on UI tweaks I encountered the fact that implementation of some widgets is retrieved by a client as compiled Java bytecode. The source code of widgets like FadeIn, ExpWnd, Link is not present in the github repository: https://github.com/dolda2000/hafen-client. This is quite unpleasant. To understand how they are composed I need to look into the object structure via debugger or try to decompile bytecode (haven't tried yet). And even if I will change their behaviour there is no guarantee that the server will not send another version that will break my tweaks and I'd need to investigate this again. It would be nice to have the source code of these and all other widgets implementation stored somewhere with public access. Or just put it inside the hafen-client source code and don't consider Java bytecode as a game resource.
ElSid
 
Posts: 29
Joined: Sun Jul 26, 2015 9:45 am

Re: Publish the source code of all in-game widgets

Postby shubla » Mon Jul 20, 2020 11:10 pm

Many people have complained about this.
Loftar has stated somewhere that the current system gives more flexibility without having to constantly update the client.
Probably not going to change it anytime soon!
Image
I'm not sure that I have a strong argument against sketch colors - Jorb, November 2019
http://i.imgur.com/CRrirds.png?1
Join the moderated unofficial discord for the game! https://discord.gg/2TAbGj2
Purus Pasta, The Best Client
User avatar
shubla
 
Posts: 13043
Joined: Sun Nov 03, 2013 11:26 am
Location: Finland

Re: Publish the source code of all in-game widgets

Postby loftar » Wed Jul 22, 2020 6:25 pm

I've posted about this issue previously, but I guess it bears repeating in one post.

The reason I put code into resources is because it has a number of advantages. Most importantly, it's incredibly convenient for me to be able to push small changes (some minor tooltip, some custom graphics) without having to do a full client update and boot people who haven't updated. In that way, it helps custom clients as well, since the client author doesn't have to merge changes for every other patch just for the client to remain usable.

I do deeply understand why it's a pain for client modders, however. Precisely because the kind of code I tend to put into resources is "on the edge", so to speak (it tends to be the visible part of many mechanics), it's exactly the kind of code that client modders would tend to be the most interested in, and also important to interact with for the kind of client modifications that I can even agree are the most legitimate of modifications. As such, I'd honestly want to provide a better way to interact with it, and I've spent some amount of time trying to think of one (to no success thus far). It is of course true, nonetheless, that it's not a problem that I'm personally afflicted by, so it's not the kind of thing that I spend every day thinking about. As such, if you have any good ideas for how to achieve a better system for handling these things, I'm interested. That being said, it would have to be something that preserves the advantages that I derive from the current system.

For what it's worth, though, the source code of all such code is included in all the resources that contain compiled code. Some resources haven't been recompiled since I added that, but for example, the Link class you mentioned (being in gfx/terobjs/consobj-pv) has been recompiled since and its source code is indeed included in the resource. I don't think this solution is anywhere near optimal, but it does save you having to use a decompiler, at least.
"Object-oriented design is the roman numerals of computing." -- Rob Pike
User avatar
loftar
 
Posts: 8926
Joined: Fri Apr 03, 2009 7:05 am

Re: Publish the source code of all in-game widgets

Postby ElSid » Wed Jul 22, 2020 8:35 pm

I understand the problem in general but some details are not clear for me since I'm not the one who is the game developer. How widgets are classified by those that are deployed with the new client version and fetched as a resource? Is it content, visual structure or logic? Content clearly should be fetched as a resource if it's some text or a specific image. Background texture or a window border might be customized. The visual structure is definitely something to be customized. In general markdown languages solve this but it might be an overkill. Instead a special function can be a customization point that takes a content as an input and should provide some widget in the output according to a contract defined by the logic. Default implementation still can be fetched as a resource. And I don't propose to touch the logic.

If everything above is not possible then there is a question what is an accepted behaviour for a custom client to break the game visually? Is it ok to don't show content, show something that isn't supposed to be shown, show with incorrect layout (overlapping, wrong placement, size) or just crash? The easiest way to tweak and break the game is to find a widget, decompile and add its source code with some changes. Less breaking and less powerful is to change a widget after it's created and composed. If it's acceptable then it would be nice to skip the decompilation step and just have the source code published somewhere automatically after each update. At least if there is breaking change custom clients developers could easily identify what's changed and prepare a fix.
ElSid
 
Posts: 29
Joined: Sun Jul 26, 2015 9:45 am

Re: Publish the source code of all in-game widgets

Postby loftar » Wed Jul 22, 2020 8:59 pm

ElSid wrote:How widgets are classified by those that are deployed with the new client version and fetched as a resource? Is it content, visual structure or logic?

I'm not sure I understand your question, but if what you're asking is how the client knows whether a widget is implemented with code that is included in the client or to load a resource to create the widget, then generally speaking, the message from the server to create a widget just contains a string to identify the widget being created. If that string contains a colon, then that is assumed to encode a resource as name:version. Otherwise, it identifies a widget that is included in the client (by the @Widget.RName annotation on the corresponding widget factory classes). This is in gettype/gettype2 in Widget.java.

ElSid wrote:Content clearly should be fetched as a resource if it's some text or a specific image. Background texture or a window border might be customized. The visual structure is definitely something to be customized. In general markdown languages solve this but it might be an overkill. Instead a special function can be a customization point that takes a content as an input and should provide some widget in the output according to a contract defined by the logic. Default implementation still can be fetched as a resource. And I don't propose to touch the logic.

Sorry, I just don't really understand what you're talking about here. What is even the context? Are you suggesting that code for sprites/tooltips/widgets in resources be replaced with... markdown? Why? And how is that even a programming language?
"Object-oriented design is the roman numerals of computing." -- Rob Pike
User avatar
loftar
 
Posts: 8926
Joined: Fri Apr 03, 2009 7:05 am

Re: Publish the source code of all in-game widgets

Postby ElSid » Wed Jul 22, 2020 10:18 pm

loftar wrote:
ElSid wrote:How widgets are classified by those that are deployed with the new client version and fetched as a resource? Is it content, visual structure or logic?

I'm not sure I understand your question, but if what you're asking is how the client knows whether a widget is implemented with code that is included in the client or to load a resource to create the widget, then generally speaking, the message from the server to create a widget just contains a string to identify the widget being created. If that string contains a colon, then that is assumed to encode a resource as name:version. Otherwise, it identifies a widget that is included in the client (by the @Widget.RName annotation on the corresponding widget factory classes). This is in gettype/gettype2 in Widget.java.


My question is why ExpWnd is end up in the game resources and haven.BuddyWnd with its all tabs and subtabs in the client source? I see two classes (not Java classes) of widgets: the first class contains widgets added into the client source code and the second contains delivered as a resource. Probably something like Button is a too general thing to be placed into resources but there are several windows containing a lot of game specific information that are composed in the client source code. It could be more flexible to keep almost everything as a resource but it's not like that no and I wonder why. If I known why I can try to produce more reasonable ideas.

loftar wrote:
ElSid wrote:Content clearly should be fetched as a resource if it's some text or a specific image. Background texture or a window border might be customized. The visual structure is definitely something to be customized. In general markdown languages solve this but it might be an overkill. Instead a special function can be a customization point that takes a content as an input and should provide some widget in the output according to a contract defined by the logic. Default implementation still can be fetched as a resource. And I don't propose to touch the logic.

Sorry, I just don't really understand what you're talking about here. What is even the context? Are you suggesting that code for sprites/tooltips/widgets in resources be replaced with... markdown? Why? And how is that even a programming language?


I mentioned markdown language as an example. I haven't written "programming language" just "language". A some set of rules that can describe a widget only from a visual point of view (e.g. place a button with text "foo" and width 100 at position 50, 100, a label with text "bar" at 50, 50, and a picture from "gfx/baz" resource at 0, 0). But as I said it might be an overkill.

Instead I want each widget that is stored as a resource to be more customizable on initialization. For example ExpWnd adds child widgets in the method tick:
Code: Select all
public void tick(double dt) {
    if (img == null) {
        Tex pic = exp.get().layer(Resource.imgc).tex();
        String text = exp.get().layer(Resource.pagina).text;
        // ...
        add(new Img(pic));
        add(new Img(fnd.render(text, 300).tex()));
        // ...
    }
}


If I want to change the text width from 300 to a different value there is no simple way to do it. So one idea is to have a method that will initialize it and can be overridden. Also it should not depend on the types, fields and methods that are not know at the compile time for the client code:
Code: Select all
// defined in the resource
class ExpWnd {
    public void tick(double dt) {
        if (img == null) {
            Content content = ExpWndContentBuilder.get().make_content(exp.get().layer(Resource.imgc).tex(), exp.get().layer(Resource.pagina).text);
            add(conent.pic);
            add(conent.text);
        }
    }
}

// defined in the vanilla client source code
interface ExpWndContentBuilder {
    class Content {
        Img pic;
        Img text;
    }

    public Content make_content(Tex pic, String text);

    static public ExpWndContentBuilder get() {
        return Widget.gettype2("ui/expwndcontentbuilder");
        // This line can be changed by a custom client to
        // return new MyExpWndContentBuilder();
    }
}

// defined in the resource
class DefaultExpWndContentBuilder implements ExpWndContentBuilder {
    public Content make_content(Tex pic, String text) {
        // ...
        return content;
    }
}

// defined in the custom client code
class MyExpWndContentBuilder implements ExpWndContentBuilder {
    public Content make_content(Tex pic, String text) {
        // ...
        return content;
    }
}
ElSid
 
Posts: 29
Joined: Sun Jul 26, 2015 9:45 am

Re: Publish the source code of all in-game widgets

Postby loftar » Sat Jul 25, 2020 1:15 am

ElSid wrote:My question is why ExpWnd is end up in the game resources and haven.BuddyWnd with its all tabs and subtabs in the client source?

Ok, sure, that isn't always a fully consistent decision, and there are a couple of aspects I balance when consdering that. Sometimes it's really just for legacy reasons (because something has been part of the client since before I started putting stuff into resources), sometimes it's just because it's something I find particularly reasonable that clients modders should have access to (like CharWnd or GameUI, which I otherwise really would like to put into resources). Sometimes it's because something is expected to have a consistent protocol against the server anyway and I suspect it is more useful to be able to modify it in the client without (on a contrary point to the one I made earlier) having to do a server/resource update. For some things it can be quite a complex decision whether to put it into a resource or not.

ElSid wrote:I mentioned markdown language as an example. I haven't written "programming language" just "language". A some set of rules that can describe a widget only from a visual point of view (e.g. place a button with text "foo" and width 100 at position 50, 100, a label with text "bar" at 50, 50, and a picture from "gfx/baz" resource at 0, 0). But as I said it might be an overkill.

Overkill aside (though I agree it probably would be), the real problem is that a widget is rarely just a graphical layout thing. More often than not, they need behavior as well. To the extent that they only are "layout-related", I tend to use the "relpos" DSL (the one in Widget.java) for layout specifications instead of widget code in resources.

ElSid wrote:Instead I want each widget that is stored as a resource to be more customizable on initialization. For example ExpWnd adds child widgets in the method tick:

Now that I've seen your other thread, I understand better what it is that you're after, but the issue with the solution you're proposing is that it's only really useful for your specific case, and most other systems like it have the same issue. They only solve one particular angle of customization, add a lot of complexity for that singular purpose, and are pretty much useless for everyone else. Also, while I realize that your example wasn't meant to convey a completely thought-through solution or anything, it has the major issue of definitely requiring updates to the main codebase for every "codeful" resource added, which completely defeats the purpose.

I suspect that a seed of an idea for a solution to the problem of resource code would be to able to allow custom clients to create subclasses of classes defined in resources (to be used in place of the original class, but still inheriting it) in order to more selectively override behavior (that would allow non-overridden methods to still be updated with newer versions of the resource while still allowing changes to the behavior to persist over such updates). Even such a solution wouldn't be ideal, though (since it would still depend on the code in the resource to have the appropriate overridable methods for important things, and, as already discussed, it's going to be impossible to completely predict and preempt every desirable angle of customization), but it would probably be better than nothing. Arguably the real problem with that solution is just getting javac in the development environment to be able to get code from resources onto its classpath, and I really don't know how to solve that issue.
"Object-oriented design is the roman numerals of computing." -- Rob Pike
User avatar
loftar
 
Posts: 8926
Joined: Fri Apr 03, 2009 7:05 am

Re: Publish the source code of all in-game widgets

Postby ElSid » Tue Jul 28, 2020 9:10 pm

loftar wrote: I tend to use the "relpos" DSL (the one in Widget.java) for layout specifications instead of widget code in resources.


"relpos" for me looks more like a stack-oriented programming language. And so far the problem is hardcoded constants. For example:
Code: Select all
120!wpyc
120 is a coordicate by x but if I want to scale it I should do it on c operator. And on c type information of 120 is lost. If it would be something like:
Code: Select all
${x}!wpyc

with additional meta information:
Code: Select all
x = 120

I would be much easier to reason about x and scale it. This example seems to be simple but this language allows to do any write arithmetic expression. Something like:
Code: Select all
120!wpy3*10+c

Which means 120 * 3 + 10 will be used as x coordinate if I'm correct. And what is the meaning of 3 here is unclear. Probably it's some kind of counter and to scale this properly I need to convert the expression into scale(120) * 3 + scale(10) that would be possible having a named constant:
Code: Select all
${width}!wpy${n}*${offset}+c

Code: Select all
width = 120
n = 3
offset = 10
ElSid
 
Posts: 29
Joined: Sun Jul 26, 2015 9:45 am

Re: Publish the source code of all in-game widgets

Postby mvgulik » Fri Jul 31, 2020 3:51 pm

mvgulik
 
Posts: 3742
Joined: Fri May 21, 2010 2:29 am

Re: Publish the source code of all in-game widgets

Postby loftar » Fri Jul 31, 2020 10:39 pm

ElSid wrote:with additional meta information:
Code: Select all
x = 120


Perhaps, but the problem seems to be where that meta information comes from.


I don't quite understand what you want to imply by that and what relevance it has to this thread.
"Object-oriented design is the roman numerals of computing." -- Rob Pike
User avatar
loftar
 
Posts: 8926
Joined: Fri Apr 03, 2009 7:05 am

Next

Return to Bugs

Who is online

Users browsing this forum: No registered users and 5 guests