#Leaf (forked from FabricMC/fabric)
1 messages ยท Page 3 of 1
class name cant be the same as the other mixins btw, have to be unique
and it needs to also be added to the mixins json file
I think you need to take the cir variable
And if it's cancelable, you need to either call cir.cancel() or set the return value.
But it's a void function.
So probably don't need to set cancelable
Yeah its a void function. No return no argument
CallbackInfoReturnable<String> cir ??
having CallbackInfoReturnable is only useful if the original function returns something and you want to capture or manipulate it
Okay the game starts let's see if it print hello world when a game start
Yess
LOG : Mod f:0, t:1755352169599> The game starts!
Let's pop a new NewWindow in this context
No window poped
How can I run my own thread loop function?
Or redirect the OnRender/OnTick function to call mine?
when in doubt, do it how the game does it
search for familiar strings/classes/functions in the decompile and see where it takes you
UIManager uiManager = new UIManager();
uiManager.addUi(viewport);
?
no
I'm grepping that
the UIManager is a static class
you need to write another mixin
where you define an invoker
then from your other mixin you use that invoker
Another Mixin class or method ?
@Mixin(UIManager.class)
public interface UIManagerInvoker {
@Invoker("AddUI")
public static void invokeAddUI(UIElementInterface uiElementInterface) {
throw new AssertionError();
}
}
Whole new mixin
make sure to register it in the mod config
Then from your original mixin, do
UIManagerInvoker.invokeAddUI(theNewWindowInstance);
Might work, might not. You might need to create an invoker on the constructor of NewWindow and use that to construct it, not sure.
And how I use it in ExampleMixin.java ?
.
UIManagerInvoker.invokeAddUI(uiElement);
Lets retry
@Mixin(UIManager.class)
public interface UIManagerInvoker {
@Invoker("AddUI")
public static void invokeAddUI(UIElementInterface uiElementInterface) {
//throw new AssertionError();
UIManager.AddUI(uiElementInterface);
}
}```
Black screen after loading the game. Inputs generates exceptions
STACK TRACE
-----------------------------------------
Callframe at: isClimbingRope
function: ChangeClimbDirection -- file: CFarming_Interact.lua line # 384 | Vanilla
Wtf
LOG : Mod f:0, t:1755353686193> The game starts!
DEBUG: Leaf f:0, t:1755353686202> NativeMethodAccessorImpl.invoke0 (Native Method)> Generating mapped inner class zombie/gameStates/IngameState$Anonymous$57f40be3686240ed8a4b46a9bbc89f53 (originally com/example/mixin/ExampleMixin$1)
ERROR: General f:0, t:1755353686247> ExceptionLogger.logException> Exception thrown
java.lang.RuntimeException: Mixin transformation of com.example.mixin.UIManagerInvoker failed at KnotClassDelegate.getPostMixinClassByteArray(KnotClassDelegate.java:579).
Stack trace:
dev.aoqia.leaf.loader.impl.launch.knot.KnotClassDelegate.getPostMixinClassByteArray(KnotClassDelegate.java:579)
dev.aoqia.leaf.loader.impl.launch.knot.KnotClassDelegate.tryLoadClass(KnotClassDelegate.java:460)
dev.aoqia.leaf.loader.impl.launch.knot.KnotClassDelegate.loadClass(KnotClassDelegate.java:322)
dev.aoqia.leaf.loader.impl.launch.knot.KnotClassLoader.loadClass(KnotClassLoader.java:118)
java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
knot//zombie.gameStates.IngameState.handler$zza000$modid$enter(IngameState.java:2104)
knot//zombie.gameStates.IngameState.enter(IngameState.java:846)
knot//zombie.gameStates.GameStateMachine.update(GameStateMachine.java:133)
knot//zombie.GameWindow.logic(GameWindow.java:382)
knot//zombie.GameWindow.frameStep(GameWindow.java:916)
knot//zombie.GameWindow.mainThreadStep(GameWindow.java:642)
knot//zombie.MainThread.mainLoop(MainThread.java:76)
java.base/java.lang.Thread.run(Thread.java:840)
Caused by: org.spongepowered.asm.mixin.transformer.throwables.IllegalClassLoadError: Illegal classload request for accessor mixin com.example.mixin.UIManagerInvoker. The mixin is missing from modid.mixins.json which owns package com.example.mixin.* and the mixin has not been applied.
org.spongepowered.asm.mixin.transformer.MixinProcessor.applyMixins(MixinProcessor.java:323)
org.spongepowered.asm.mixin.transformer.MixinTransformer.transformClass(MixinTransformer.java:237)
org.spongepowered.asm.mixin.transformer.MixinTransformer.transformClassBytes(MixinTransformer.java:202)
dev.aoqia.leaf.loader.impl.launch.knot.KnotClassDelegate.getPostMixinClassByteArray(KnotClassDelegate.java:572)
... 12 more
is this ytour mixin?
package com.example.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
import zombie.ui.UIElementInterface;
import zombie.ui.UIManager;
@Mixin(UIManager.class)
public interface UIManagerInvoker {
@Invoker("AddUI")
public static void invokeAddUI(UIElementInterface uiElementInterface) {
//throw new AssertionError();
UIManager.AddUI(uiElementInterface);
}
}```
Yes
ERROR: General f:0, t:1755353686247> ExceptionLogger.logException> Exception thrown
java.lang.RuntimeException: Mixin transformation of com.example.mixin.UIManagerInvoker failed at KnotClassDelegate.getPostMixinClassByteArray(KnotClassDelegate.java:579).
Stack trace:```
modid.mixins.json
Where is this damn file
/leaf-example-mod/build/resources/main/modid.mixins.json
/leaf-example-mod/src/main/resources/modid.mixins.json
{
"required": true,
"package": "com.example.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
"ExampleMixin",
"UIManagerInvoker" ///// <<<< THIS
],
"injectors": {
"defaultRequire": 1
},
"overwrites": {
"requireAnnotations": true
}
}```
Same boring black screen
The game +intellij just crash while I was trying to minimize the game....
in IDEA you can CTRL+N and search for a file
Okay now
java.lang.NullPointerException: Cannot invoke "java.lang.Boolean.booleanValue()" because the return value of "zombie.ui.UIElementInterface.isFollowGameWorld()" is null at UIManager.update(UIManager.java:673).
I messed with the UIManager now everything breaks
also this isnt correct
the throw new AssertionError() is there to make sure the invokeAddUI is there for a reason, im pretty sure it's to make sure that you dont call the wrong thing on accident
you dont do any code in there, you want to use the invoker like a proxy method
Yes but the proxy must call the right method like so?
//throw new AssertionError();
UIManager.AddUI(uiElementInterface);
So you would use your invoker like UIManagerInvoker.AddUI(iface) not do UIManager.AddUI in the invoker method
Aaaah
simply like that ?
@Mixin(UIManager.class)
public interface UIManagerInvoker {
@Invoker("AddUI")
public static void invokeAddUI(UIElementInterface uiElementInterface) {
throw new AssertionError();
}
}```
yes keep it that
then you call your invokeAddUI from another mixin or entrypoint or wherever you want
All the invoker does is let you call UIManager.AddUI since you can't call it directly.
I must repeat the Mixin process for every call I make ?
To game code? Yes.
You only have to write the invoker once, but then you can now call that method as much as you want.
You have to "expose" game things in order for your code to interact with it.
Nice
Okkkk it makes sense
Same errors, game crashe
The logs are polluted with the same Exception
which is what
Which is
LOG : Mod f:0, t:1755355205701> The game starts!
DEBUG: Leaf f:0, t:1755355205706> NativeMethodAccessorImpl.invoke0 (Native Method)> Generating mapped inner class zombie/gameStates/IngameState$Anonymous$135f0306fc854a75a7897f96ee601c84 (originally com/example/mixin/ExampleMixin$1)
ERROR: General f:0, t:1755355206849> ExceptionLogger.logException> Exception thrown
java.lang.NullPointerException: Cannot invoke "java.lang.Boolean.booleanValue()" because the return value of "zombie.ui.UIElementInterface.isFollowGameWorld()" is null at UIManager.update(UIManager.java:673).
Stack trace:
knot//zombie.ui.UIManager.update(UIManager.java:673)
knot//zombie.GameWindow.logic(GameWindow.java:326)
knot//zombie.GameWindow.frameStep(GameWindow.java:916)
knot//zombie.GameWindow.mainThreadStep(GameWindow.java:642)
knot//zombie.MainThread.mainLoop(MainThread.java:76)
java.base/java.lang.Thread.run(Thread.java:840)
an error that don't seems to be corelated to the code I'm editing which turn the developement very hard
It seems related
What it's saying is, that when UIManager.update was called by the main loop
Maybe related but there is not very much informations
It ried to call .isFollowGameWorld() on something and that returned null, when it should be a boolean
it's perfectly enough information..
you just have to read...
and give yourself a chance to understand
again
when UIManager.update is called
it's doing some work on its children
it goes to called isFollowGameWorld on that object, and it reutrns null instead of boolean
This is probably your NewWindow instance, which is probably broken
I understand the error message but the question is what I did wrong in MY code not .isFollowGameWorld() ?
read what i said three or four more times
Keep in mind that you only need 1 mixin class file per class you are mixin. So one for UIManager, one for say IsoPlayer, etc
its not 1 class per method thankfully
hehe
There is no NewWindow instance
the short of it seems to be that you are successfully adding something to UIManager but it doesn't like it
what?
then what are you adding to the UIManager?
I'm calling AddUI which takes a UIElementInterface
yes.. the window instance
yes, but I changed the original
window = new NewWindow(...)
ExampleMod.java
package com.example;
import dev.aoqia.leaf.api.ModInitializer;
import zombie.debug.DebugLog;
import zombie.debug.DebugLogStream;
//import zombie.ui.NewWindow;
public class ExampleMod implements ModInitializer {
public static final String MOD_ID = "modid";
public static final DebugLogStream LOGGER = DebugLog.Mod;
public static final String GAME_VERSION_CHANGED_EVENT = "GameVersionChanged";
@Override
public void onInitialize() {
System.out.println("Hello Leaf World!!! >w<");
//NewWindow window;
//window = new NewWindow(0, 0, 500, 500, true);
//window.render();
}
}
Coming in late, but is there a benefit to using Java for UI? I thought the Lua exposure for UI is one of the few near 100% cases.
It's probably due to UIElementInterface.isFollowGameWorld() probably returns a field.booleanValue() or something and field is null because you instantiated the class wrong OR the field not set for some other reason or something
he's doing the whole project zomboid in first person 3d thing
I remember, but UI?
this is what i'm saying too
just the window to draw the first person view into..
Ooh
UIManagerInvoker.java
package com.example.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
import zombie.ui.UIElementInterface;
import zombie.ui.UIManager;
@Mixin(UIManager.class)
public interface UIManagerInvoker {
@Invoker("AddUI")
public static void invokeAddUI(UIElementInterface uiElementInterface) {
throw new AssertionError();
}
}
ExampleMixin.java
Are you using the minecraft plugin? You're not using the right syntax for the method names etc I think
what is that
please tell me you have some java experience going into this, you're not gonna like it if you dont, especially for a mod this size going that far into the engine
There's no reason to use UIElementInterface directly, it's an interface!
Oh I was thinking this was part of the UI not an actual Java interface
This is why I said do more simple stuff first. I can barely fathom of more technically challenging goals if I tried.
NewWindow implements the interface
Make a window
Pass it to AddUI
Where?
literally everywhere
@Override
public Boolean isCapture() {
return null;
}
return type Boolean
returns null anyway
in the interface you override..
I'm surprised it even compiles, new on an interface?
the hell does that even do.
maybe java interfaces are not like other languages
ยฏ_(ใ)_/ยฏ
test
why did my messag edelete
its the same as if you were to implement an interface
you know how you can create a class to implement an interface
sure, statically
Everywhere in which file?
I'm trying
@Inject(method = "enter", at = @At("RETURN"), cancellable = false)
private void enter(CallbackInfo ci) {
LOGGER.println("The game starts!");
NewWindow viewport;
viewport = new NewWindow(0, 0, 500, 500, true);
UIManagerInvoker.invokeAddUI(viewport);
}
thats what its doing basically but I think its anonymous class or something
huh, i see
this looks more correct
much more
but NewWindow is still the problem child ๐
waiot nvm thats the same mixin, all is well
so does it work?
YES ! Kinda
A small window appear in the upper right corner but not a 500*500 one
And there are errors in cascade
what is cascade
The ESC key doesn't work anymmore and produce errors
dunno, but you can share the errors
LOG : General f:148, t:1755356939703> -----------------------------------------
STACK TRACE
-----------------------------------------
function: updateTooltip -- file: ISScrollingListBox.lua line # 375 | Vanilla
function: prerender -- file: ISScrollingListBox.lua line # 520 | Vanilla
ERROR: General f:148, t:1755356939704> ExceptionLogger.logException> Exception thrown
java.lang.RuntimeException: attempted index: isMouseOver of non-table: zombie.ui.NewWindow@54bd31ff at KahluaThread.tableget(KahluaThread.java:1530).
Stack trace:
knot//se.krka.kahlua.vm.KahluaThread.tableget(KahluaThread.java:1530)
knot//se.krka.kahlua.vm.KahluaThread.luaMainloop(KahluaThread.java:502)
knot//se.krka.kahlua.vm.KahluaThread.call(KahluaThread.java:174)
knot//se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1826)
knot//se.krka.kahlua.vm.KahluaThread.pcallvoid(KahluaThread.java:1668)
knot//se.krka.kahlua.integration.LuaCaller.pcallvoid(LuaCaller.java:38)
knot//zombie.ui.UIElement.render(UIElement.java:1990)
knot//zombie.ui.UIElement.render(UIElement.java:2000)
knot//zombie.ui.UIElement.render(UIElement.java:2000)
knot//zombie.ui.UIManager.render(UIManager.java:419)
knot//zombie.gameStates.IngameState.renderFrameUI(IngameState.java:1331)
knot//zombie.gameStates.IngameState.renderframeui(IngameState.java:1317)
knot//zombie.gameStates.IngameState.renderInternal(IngameState.java:1456)
knot//zombie.gameStates.IngameState.render(IngameState.java:1406)
knot//zombie.gameStates.GameStateMachine.render(GameStateMachine.java:28)
knot//zombie.GameWindow.renderInternal(GameWindow.java:468)
knot//zombie.GameWindow.frameStep(GameWindow.java:940)
knot//zombie.GameWindow.mainThreadStep(GameWindow.java:642)
knot//zombie.MainThread.mainLoop(MainThread.java:76)
java.base/java.lang.Thread.run(Thread.java:840)
hmm
And also for the ESC key
LOG : General f:3105, t:1755357010553> -----------------------------------------
STACK TRACE
-----------------------------------------
function: setVisibleAllUI -- file: ISUIHandler.lua line # 15 | Vanilla
function: ToggleEscapeMenu -- file: MainScreen.lua line # 2060 | Vanilla
ERROR: General f:3105, t:1755357010553> ExceptionLogger.logException> Exception thrown
java.lang.RuntimeException: attempted index: isVisible of non-table: zombie.ui.NewWindow@54bd31ff at KahluaThread.tableget(KahluaThread.java:1530).
Stack trace:
knot//se.krka.kahlua.vm.KahluaThread.tableget(KahluaThread.java:1530)
knot//se.krka.kahlua.vm.KahluaThread.luaMainloop(KahluaThread.java:502)
knot//se.krka.kahlua.vm.KahluaThread.call(KahluaThread.java:174)
knot//se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1826)
knot//se.krka.kahlua.vm.KahluaThread.pcallvoid(KahluaThread.java:1653)
knot//se.krka.kahlua.integration.LuaCaller.pcallvoid(LuaCaller.java:66)
knot//se.krka.kahlua.integration.LuaCaller.protectedCallVoid(LuaCaller.java:139)
knot//zombie.Lua.Event.trigger(Event.java:72)
knot//zombie.Lua.LuaEventManager.triggerEvent(LuaEventManager.java:315)
knot//zombie.input.GameKeyboard.update(GameKeyboard.java:64)
knot//zombie.GameWindow.logic(GameWindow.java:308)
knot//zombie.GameWindow.frameStep(GameWindow.java:916)
knot//zombie.GameWindow.mainThreadStep(GameWindow.java:642)
knot//zombie.MainThread.mainLoop(MainThread.java:76)
java.base/java.lang.Thread.run(Thread.java:840)
That makes sense I guess
But the NewWindow poped !
But it do not refresh and the layout is weird
With a close button in the middle...
I will go soon for an hour or so
NewWindow doesn't call the super constructor
I will be back
The base classe of NewWindow, UIElement is the thing that sets the lua table
interesting
try
viewport.set_table(LuaManager.platform.newTable())
though you'll probably need an invoker heh
For LuaManager.platform.newTable() ?
set_table method not found
setTable
No build error with LuaManager.platform.newTable()
I try to launch the game and see what appen
I think you need an ISUIElementWrapper... ๐ค
I'm literally just browsing same time you are, I don't know anything for sure lol
Figured it out. Was trying to run example mod from workshop. Only when i run the game using leaf-loader repo via runClient task it gave me an error Mod 'Example mod' (modid) 1.0.0 requires version 1.2.0 or later of leafloader, which is missing! i don't know why it wasn't logging using real game client
Anyhow, (my leaf loader version was 1.4.1) rebuilding mod via specifying letest version of loader did the trick and now it loads ๐
Hmm that's odd, it should've respected the >=1.2.0
but yeah generally you want to update the example mod depending on the loader's version as well, or use * which means any version
This usually shows up in the form of a GUI with the error. Did it not do that?
No error both in GUI and logs
hmm weird
Not even in logs is weirder, but I am assuming that it didn't show in the log for some reason because the GUI was supposed to show...
Did it work for you in the IDE, even when the loader dependency was set to >=1.2.0
Any news about leaf in prod?
not really
you can use it, but it's limited to client for now, because I need to figure out how im going to edit the server scripts for each platform
They made a launcher for the client but no the server ๐ wheres the love lol
Anyway, im trying to take breaks over the weekends to prevent burnout, because if I don't like I have been, it's really annoying to work on anything
What I mean is wasn't it just not working at all?
uh it should work unless I'm forgetting something
Remember you were like "Just launch it from the IDE" something about not being able to find mappings in prod
there are no mappings used in prod
I assume you were talking about that one time where in prod the log just ended after only a few lines, which I couldn't replicate at all
@floral sluice I mean this
I don't think we ever resolved it. You recommened I just launch from IDE and I've been doing that ever since.
first KEE npcs with Leaf
although, they don't move in the metaverse and procedural generation doesn't work
but it was at least able to load the classes into JVM and expose them through Lua, so all of the Lua scripts are working fine
I would really love to be involved in java NPC modding. Are you guys working out of github?
If you'd like to contribute you would have to ask Snejk, we don't really have a true synced workspace, I just send patches to him over discord
I think I did ask in the past. If there's no room for other people, no worries
Hello @floral sluice @rare mural sorry for yesterday I didn't relog
I am only sorry that I didn't get to beat you to it XD
I wanted to see if I could surprise you but I got stuck polishing my own project's UI
wb
I think you need to use the wrapper class
It sets up the associated lua table
I'm not positive
but the ISUIElementWrapper seems to maintain a lua table that is wanted by UIManager
@rare mural I think I will search for the existing UI buttons to see how they achieve the display of a new window
Like the health button
Maybe in NewHealthPanel
extends NewWindow
Okay let's copy past this class to do my own window class
eh i dunno
seems like NewHealthPanel is exposed to the lua via the LuaManager.Exposer
and it's probably created in the lua
@jagged scarab what was the error you were getting yesterday
from UIManager
Reading the UIManager it really feels like you should be able to create something extending UIElementInterface and call UIManager.AddUI
Mostly LUA exception, anderrors coming from UIManager:update
what exactly was it though
STACK TRACE
-----------------------------------------
function: updateTooltip -- file: ISScrollingListBox.lua line # 375 | Vanilla
function: prerender -- file: ISScrollingListBox.lua line # 520 | Vanilla
ERROR: General f:52, t:1755357871100> ExceptionLogger.logException> Exception thrown
java.lang.RuntimeException: attempted index: isMouseOver of non-table: zombie.ui.NewWindow@6e5a2c3 at KahluaThread.tableget(KahluaThread.java:1530).
Stack trace:
knot//se.krka.kahlua.vm.KahluaThread.tableget(KahluaThread.java:1530)
knot//se.krka.kahlua.vm.KahluaThread.luaMainloop(KahluaThread.java:502)
knot//se.krka.kahlua.vm.KahluaThread.call(KahluaThread.java:174)
knot//se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1826)
knot//se.krka.kahlua.vm.KahluaThread.pcallvoid(KahluaThread.java:1668)
knot//se.krka.kahlua.integration.LuaCaller.pcallvoid(LuaCaller.java:38)
knot//zombie.ui.UIElement.render(UIElement.java:1990)
knot//zombie.ui.UIElement.render(UIElement.java:2000)
knot//zombie.ui.UIElement.render(UIElement.java:2000)
knot//zombie.ui.UIManager.render(UIManager.java:419)
knot//zombie.gameStates.IngameState.renderFrameUI(IngameState.java:1331)
knot//zombie.gameStates.IngameState.renderframeui(IngameState.java:1317)
knot//zombie.gameStates.IngameState.renderInternal(IngameState.java:1456)
knot//zombie.gameStates.IngameState.render(IngameState.java:1406)
knot//zombie.gameStates.GameStateMachine.render(GameStateMachine.java:28)
knot//zombie.GameWindow.renderInternal(GameWindow.java:468)
knot//zombie.GameWindow.frameStep(GameWindow.java:940)
knot//zombie.GameWindow.mainThreadStep(GameWindow.java:642)
knot//zombie.MainThread.mainLoop(MainThread.java:76)
java.base/java.lang.Thread.run(Thread.java:840)
LUA Error
scrolling list box..?
Yes it's the render function of UIManager
Look what I'm creating
package com.example;
import zombie.ui.NewWindow;
public /*final*/ class UIViewport
extends NewWindow {
public static UIViewport instance;
private static int UI_BORDER_SPACING;
public UIViewport(int n, int n2) {
super(n, n2, 10, 10, true);
this.ResizeToFitY = false;
this.visible = false;
instance = this;
this.width = 300 + UI_BORDER_SPACING;
this.height = 270 + this.titleRight.getHeight() + 5;
}
@Override
public void render() {
}
@Override
public void update() {
if (!this.isVisible()) {
return;
}
super.update();
}
static {
UI_BORDER_SPACING = 10;
}
}```
'titleRight' is not public in 'zombie.ui.NewWindow'. Cannot be accessed from outside package
Oh ya that should be fixed in loader 1.4.1 that i released the other day
The issue is that UIElement introduces this.table which its render and other logic depend on.
While NewWindow inherits UIElement, neither do anything to setup this.table
Let me know if you have any feedback or bugs to report!
UIElement() has a constructor which takes the table if one's already available. And it also has a setTable method for setting it after construction.
Inside ISUIElementWrapper you can see that it does things:
protected void instantiate() {
UIElement uIElement = new UIElement(this.table);
this.table.rawset("javaObject", uIElement);
uIElement.setX(LuaHelpers.castDouble(this.table.rawget("x")));
uIElement.setY(LuaHelpers.castDouble(this.table.rawget("y")));
uIElement.setHeight(LuaHelpers.castDouble(this.table.rawget("height")));
uIElement.setWidth(LuaHelpers.castDouble(this.table.rawget("width")));
uIElement.setAnchorLeft(LuaHelpers.castBoolean(this.table.rawget("anchorLeft")));
uIElement.setAnchorRight(LuaHelpers.castBoolean(this.table.rawget("anchorRight")));
uIElement.setAnchorTop(LuaHelpers.castBoolean(this.table.rawget("anchorTop")));
uIElement.setAnchorBottom(LuaHelpers.castBoolean(this.table.rawget("anchorBottom")));
uIElement.setWantKeyEvents(LuaHelpers.castBoolean(this.table.rawget("wantKeyEvents")));
uIElement.setWantExtraMouseEvents(LuaHelpers.castBoolean(this.table.rawget("wantExtraMouseEvents")));
uIElement.setForceCursorVisible(LuaHelpers.castBoolean(this.table.rawget("forceCursorVisible")));
LuaHelpers.callLuaClass(this.table.getMetatable().getString("Type"), "createChildren", this.table);
}
That looks correct. Its doing stuff you would normally do from Lua, in Java.
Well in lua I think you often need to call instantiate and initialise right?
Yes
This is likely the implementation of those
public void initialise() {
this.table.rawset("children", LuaManager.platform.newTable());
KahluaTable tablex = (KahluaTable)LuaManager.env.rawget("ISUIElement");
double double0 = LuaHelpers.castDouble(tablex.rawget("IDMax"));
this.table.rawset("ID", double0);
tablex.rawset("IDMax", double0 + 1.0);
}
and when you create your own UI in Lua, you add your own render, update, functions too
But its not required though like initialise is
I'm not sure if instantiate is needed (in lua) but I would use it anyway
Also what is the point of creating a lua ui on the first place?
Lua is slow ๐
Not the goal, he's trying to add something related to NewWindow to the UIManager but it ends up with the exception above
UIElement (base class of NewWindow) calls into lua during its java render
Once in the lua, it blows up because the UIElement's table is not properly configured
Once execution goes into lua though you don't get any useful information out of the stack trace:
knot//se.krka.kahlua.vm.KahluaThread.tableget(KahluaThread.java:1530)
knot//se.krka.kahlua.vm.KahluaThread.luaMainloop(KahluaThread.java:502)
knot//se.krka.kahlua.vm.KahluaThread.call(KahluaThread.java:174)
knot//se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1826)
knot//se.krka.kahlua.vm.KahluaThread.pcallvoid(KahluaThread.java:1668)
knot//se.krka.kahlua.integration.LuaCaller.pcallvoid(LuaCaller.java:38)
knot//zombie.ui.UIElement.render(UIElement.java:1990)
Game crashed ........
no doubt
No error messages, just a raw crash
i wouldn't expect the stuff you're doing above to work
Why
I doubt that you can just extend game classes like that... Maybe you can? Dunno..
Thinking about it you probably can?
You know, if you really need lua, you can create a submod and write Lua like a normal mod to extend your UI thing
I think it's just the dependence on UIElement that's the issue
UIElementInterface is all you technically need
So I would probably take a good look at UIElement and see how I can remove anything not needed (like all the lua stuff) and then focus on learning how to use SpriteRenderer to render my own window square, etc
There is no compilation errors. The game launch but when the game begin it crash. Also it's a pain because the game took forever to boot on every try
me too
UIManager only cares that you're a UIElementInterface that you have a .render() method etc, it's only UIElement that cares about this.table
i think you're gonna do it tonight
always show the code
package com.example;
import zombie.ui.NewWindow;
public class UIViewport
extends NewWindow {
//public static UIViewport instance;
private static int UI_BORDER_SPACING;
public UIViewport(int n, int n2) {
super(n, n2, 10, 10, true);
this.ResizeToFitY = false;
this.visible = false;
//instance = this;
this.width = 300 + UI_BORDER_SPACING;
this.height = 270;
}
@Override
public void render() {
//this.DrawTexture(this.BodyOutline, n - 123 + 2, n2 - 302 + 2, this.alpha);
//this.Hand_L.render();
}
@Override
public void update() {
if (!this.isVisible()) {
return;
}
super.update();
}
static {
UI_BORDER_SPACING = 10;
}
}```
@Inject(method = "enter", at = @At("RETURN"), cancellable = false)
private void enter(CallbackInfo ci) {
LOGGER.println("The game starts!");
UIViewport viewport;
viewport = new UIViewport(10, 10);
viewport.setTable(LuaManager.platform.newTable());
UIManagerInvoker.invokeAddUI(viewport);
}```
In fact it crash always now ?
I tried to remove everything from my project and it keep crashing
WARN : General f:0, t:1755420752524> AnimationAssetManager.loadCallback > Failed to load asset: AssetPath{ "bob/bob_bandagelowerbody.x.loomhash" }
WARN : General f:0, t:1755420752580> AnimationAssetManager.loadCallback > Failed to load asset: AssetPath{ "bob/bob_bandagerightarm.x.loomhash" }
WARN : General f:0, t:1755420752580> AnimationAssetManager.loadCallback > Failed to load asset: AssetPath{ "bob/bob_bandagerightleg.x.loomhash" }
LOG : General f:0, t:1755420752594> SandboxOptions.load() end
LOG : General f:0, t:1755420752594> ItemPickerJava.Parse() start
Is the last lines of log before the game crash
dunno
It's not due to my code apparently help me
how the fuck I'm I supposed to develop my mod
hehe not sure what advice to give, maybe aoqia does?
Game broke by itself it's lovely
How can I reset the cached game?
Just by deleting the run/ folder?
ye
you can set breakpoitns in the decompiled code
Where is it ? I don't use any debugger ?
I didn't modify the game itself
And I dunno how to reset the game to an anterior working one
Cause it brokes itself
Yesterday it worked as a charm and now it crashes constantly and I didnt touch anything
How the fuck this can append in a deterministic machine?
Bugs and corruption don't grow in the night like weed
You can verify your game files and delete the leaf-loom gradle cache if you really want
run genSources and use the decompiled source when you view a game class like IsoPlayer, breakpoints in game classes will work if you run in debug
Okay I delete this folder
Where is genSources
How can I set a breakpoint in directly in the game file ? Why not at this point mod directly by editing the game files?
its a gradle task
I explained most of this ages ago
there are many downsides to manually editing and replacing game class files
You're starting off the first introduction of leaf to you with a time consuming project idea, even more so than the already complex mods like NPCs and the like, so it's no wonder you're having issues. Most of the issues you're having aren't even with leaf but just writing code for the game
Barring that first issue that was some unexplained shit with NIO file channels
I just need to learn and get used to java/leaf/mixin modding
But this issue is not due to my code
gradlew.bat genSource
I fucking knew it was going to be a bandaid fix
it's because of the option I added yesterday to force loom attribute files
the game's trying to parse those as animations and some other shit
lol but its hashes
im not quite sure what to do with this
because literally every other person on a windows machine (and even people on Linux**) didn't have this issue with extended file attributes
and even only 1 person in Fabric had this issue
gradlew.bat genSource failed because Intellij is open (?)
The error do not come from the sources......
It's the game and there is no clue to debug
apparently it works now after genSource wich failed
STACK TRACE
-----------------------------------------
function: updateTooltip -- file: ISScrollingListBox.lua line # 375 | Vanilla
function: prerender -- file: ISScrollingListBox.lua line # 520 | Vanilla
ERROR: General f:73, t:1755425748504> ExceptionLogger.logException> Exception thrown
java.lang.RuntimeException: attempted index: isMouseOver of non-table: com.example.UIViewport@3e67dec8 at KahluaThread.tableget(KahluaThread.java:1530).
Stack trace:
knot//se.krka.kahlua.vm.KahluaThread.tableget(KahluaThread.java:1530)
knot//se.krka.kahlua.vm.KahluaThread.luaMainloop(KahluaThread.java:502)
knot//se.krka.kahlua.vm.KahluaThread.call(KahluaThread.java:174)
knot//se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1826)
knot//se.krka.kahlua.vm.KahluaThread.pcallvoid(KahluaThread.java:1668)
knot//se.krka.kahlua.integration.LuaCaller.pcallvoid(LuaCaller.java:38)
knot//zombie.ui.UIElement.render(UIElement.java:1990)
What should I add to my UIViewport class?
attempted index: isMouseOver of non-table: com.example.UIViewport@3e67dec8
idk, see what sets isMouseOver
oh wait, doesnt that mean the table itself is null?
anyway, im not sure, I've never tried doing what youre doing before
I'm trying
public int isMouseOver(int x, int y)
{
return 0;
}```
It's expecting a lua function I think?
If you create a java function but don't add it to the lua table, it won't exist from the lua context
Most people do UI in lua lol (including the game)
how to add to the LUA table? The patch does not qwork
I just forgot
this.visible = true;
Yea why are you doing Lua UI inside Java ๐
Now it display but I can't get rid of the errors
Combine both instead if you need to do Lua UI alongside custom Java stuff I think
Wait isMouveOver returns an int ?
But yea I really really don't think you should be doing an Lua UI stuff inside the Java
This is going to seriously limit modding capabilities of your mod, especially since you're forced to use Lua functions anyway, so simply define them in the Lua
For Java specific UI, you don't use the Lua UI anyway, so no reasons to do Lua UI inside the Java, unless you have specific limitations I suppose like not being able to expose your custom Java stuff to the Lua ?
The point I want to get across to people is to use Java to enhance the experience of mod making in Lua mainly.
Obviously doing stuff in Java is a no brainer when it comes to performance, but for example with @dull stirrup and the NPC mod. They could add the NPC logic in Java, and then control certain things in Lua, to possibly allow for custom NPC implementations by other mods. Exposing NPC logic such as pathfinding and emotion state for example
It's not meant to be a "do everything in Java" unless you don't need to interact with the end user who writes Lua mods
Though it depends on what type of mod you are making
So how can I display a viewport ?
Native Java stuff most likely due to how performance heavy it'll get
@Override
public void render() {
this.DrawTexture(this.viewport, 0, 0, 0);
}
How can I call the super method render?
super.render();
```?
I'm going to paste this here for you to read
To start modding Minecraft using Fabric, it's strongly recommended to know Java.
Minecraft, in its codebase, and mods, using Fabric API, use more advanced Java concepts like lambdas, generics and polymorphism.
If you don't know all of these concepts, you may have some difficulties modding.
Here are some online resources that will help learning Java
JetBrains Academy (free online course): https://www.jetbrains.com/academy/
Codecademy (free online course): https://www.codecademy.com/learn/learn-java
University of Helsinki (free online course): https://java-programming.mooc.fi/
Basic Java Tutorials: https://docs.oracle.com/javase/tutorial/
Introduction to Programming using Java by David J. Eck (free online textbook): http://math.hws.edu/javanotes/
This is from Fabric's helper discord bot, but it applies to leaf too
I already explained. Copy the code of UIElement. Delete everything related to lua. Inside the render, use SpriteRenderer to draw a square (your window)
(then add an instance of this new class to UIManager with AddUI)
public void AddChild(zombie.ui.UIElement uIElement) {
this.getControls().add(uIElement);
uIElement.setParent(this); // <---- Error, UIElement, not UIViewport
}
does my UIViewport class must extends UIElement?
you're totally confused
oh sorry my bad I misread the code
it's 7AM I've been up all night
you'd have to share more of the code
I literally took the UIElement class code and renamed the class "UIViewport"
And adapt?
change the .setParent method first
actually
you can't really support that stuff
you'll just have to delete anything involving other uiElements because they wont really be usable with your custom windowing stuff
but that's OK because you don't really need child ui elements because you're just gonna draw textures to your square during render
yeah?
Just derive the class
nah
exactly
we're not trying to inherit all of UIElement's stuff, it uses lua tables and other stuff
he just wants the part of UIElement that makes it a valid UIElementInterface implementation
so it can be passed to UIManager.AddUI and he implements totally custom .render() method
(instead of the stuff UIElement does to render child nodes, etc)
Didn't follow the whole thing sorry
np catching ya up ๐
@jagged scarab basically you need all the stuff from UIElement that you also see on UIElementInterface
at minimum
most everything else from UIElement can be tossed away
Ok so AddChild and his friend methods implementing UIElement goes to trash?
yeaha because that's related to UIElement's support for nesting child elements and stuff
public void bringToTop() {
UIManager.pushToTop(this);
if (this.Parent != null) {
this.Parent.addBringToTop(this);
}
}```
But these ?
`'pushToTop(zombie.ui.UIElementInterface)' is not public in 'zombie.ui.UIManager'. Cannot be accessed from outside package`
Okay I remove this....
public zombie.ui.UIElement Parent = null;
Is bringToTop in UIElementInterface?
no
What to do with the render function? It does not display anything
right, it's all on you
you're gonna delete what's inside
because it has no children etc
this is UIElement not UIWindow
public void render() {
Object object;
Object object2;
if (!this.enabled) {
return;
}
if (!this.isVisible().booleanValue()) {
return;
}
if (this.getTable() != null && (object2 = UIManager.tableget(this.table, "prerender")) != null) {
try {
LuaManager.caller.pcallvoid(UIManager.getDefaultThread(), object2, (Object)this.table);
}
catch (Exception exception) {
boolean bl = false;
}
}
for (int i = 0; i < this.getControls().size(); ++i) {
this.getControls().get(i).render();
}
if (this.getTable() != null && (object = UIManager.tableget(this.table, "render")) != null) {
LuaManager.caller.pcallvoid(UIManager.getDefaultThread(), object, (Object)this.table);
}
if (Core.bDebug && DebugOptions.instance.UIRenderOutline.getValue()) {
if (this.table != null && "ISScrollingListBox".equals(UIManager.tableget(this.table, "Type"))) {
this.repaintStencilRect(0.0, 0.0, (int)this.width, (int)this.height);
}
Double d = -this.getXScroll().doubleValue();
Double d2 = -this.getYScroll().doubleValue();
double d3 = 1.0;
if (this.isMouseOver().booleanValue()) {
d3 = 0.0;
}
double d4 = this.maxDrawHeight == -1 ? (double)this.height : (double)this.maxDrawHeight;
this.DrawTextureScaledColor(null, d, d2, 1.0, d4, d3, 1.0, 1.0, 0.5);
this.DrawTextureScaledColor(null, d + 1.0, d2, (double)this.width - 2.0, 1.0, d3, 1.0, 1.0, 0.5);
this.DrawTextureScaledColor(null, d + (double)this.width - 1.0, d2, 1.0, d4, d3, 1.0, 1.0, 0.5);
this.DrawTextureScaledColor(null, d + 1.0, d2 + d4 - 1.0, (double)this.width - 2.0, 1.0, d3, 1.0, 1.0, 0.5);
}
}
you added an instance of this to UIManager.AddUI?
yes
@Inject(method = "enter", at = @At("RETURN"), cancellable = false)
private void enter(CallbackInfo ci) {
LOGGER.println("The game starts!");
UIViewport viewport;
viewport = new UIViewport(300, 280);
viewport.setTable(LuaManager.platform.newTable());
UIManagerInvoker.invokeAddUI(viewport);
}
sure
ok
the last block in the render function
i think draws a square around the dimensions of the element
Can you give me an example of SpriteRenderer?
just search for it
it and uses
you gotta up your search game
look at this part:
if (Core.bDebug && DebugOptions.instance.UIRenderOutline.getValue()) {
if (this.table != null && "ISScrollingListBox".equals(UIManager.tableget(this.table, "Type"))) {
this.repaintStencilRect(0.0, 0.0, (int)this.width, (int)this.height);
}
Double d = -this.getXScroll().doubleValue();
Double d2 = -this.getYScroll().doubleValue();
double d3 = 1.0;
if (this.isMouseOver().booleanValue()) {
d3 = 0.0;
}
double d4 = this.maxDrawHeight == -1 ? (double)this.height : (double)this.maxDrawHeight;
this.DrawTextureScaledColor(null, d, d2, 1.0, d4, d3, 1.0, 1.0, 0.5);
this.DrawTextureScaledColor(null, d + 1.0, d2, (double)this.width - 2.0, 1.0, d3, 1.0, 1.0, 0.5);
this.DrawTextureScaledColor(null, d + (double)this.width - 1.0, d2, 1.0, d4, d3, 1.0, 1.0, 0.5);
this.DrawTextureScaledColor(null, d + 1.0, d2 + d4 - 1.0, (double)this.width - 2.0, 1.0, d3, 1.0, 1.0, 0.5);
}
if you remove the if
it should run all that code
remove the bit at the start about this.table and stuff
indeed !
and everything else should result in a square being drawn
cool
did it work?
It takes forever for each try lmoa
remove this part
if (this.table != null && "ISScrollingListBox".equals(UIManager.tableget(this.table, "Type"))) {
this.repaintStencilRect(0.0, 0.0, (int)this.width, (int)this.height);
}
since we dont' (or wont) have this .table
you mean to test faster ?
yeah
it works
๐
this.DrawTextureScaledColor(null, d, d2, 1.0, d4, d3, 1.0, 1.0, 0.5);
I must understand the drawing methods
it's a method on your class
lol wut
he got the custom java ui rendering
nice
public void DrawTextureScaled(Texture tex, double _x, double _y, double _width, double _height, double alpha) {
if (this.isVisible()) {
double double0 = _x + this.getAbsoluteX();
double double1 = _y + this.getAbsoluteY();
SpriteRenderer.instance
.renderi(tex, (int)(double0 + this.xScroll), (int)(double1 + this.yScroll), (int)_width, (int)_height, 1.0F, 1.0F, 1.0F, (float)alpha, null);
}
}
@jagged scarab
i'm just showing you the method
look at SpriteRenderer to see what it supports
but yeah you'll probably need to render into a texture and then blitting that to your window
how making the texture will work
if you end up having to make the texture on the cpu it'll be very very slow
alpha 1 just means fully opaque
not gonna lie this is probably not the way to go
you're probably gonna want to write a shader
but honestly you're getting to the point where you're on your own XD
viewport = new Texture(w, h, 1);
...
this.DrawTextureScaled(this.viewport, 0, 0, (double)this.width, (double)this.height, 1);
it wont be efficient to manipulate a texture and then blit it
you have to start thinking about how you actually want to render
like what do you want to see on screen
and the logic for drawing it
i don't mean texture vs shader i mean like what you visually wanna see and how will the viewport/rendering work
depending on that decision you chose cpu textures or gpu shaders
if you are making like a 2D tile-based game, then cpu textures are fine
if you're trying to make a low res raytracer, you might get away with CPU
anything more than that you're gonna want to use a shader
Okay so I replace Texture by shader
no idea how shaders are used
Doesn't render
How to blit a Shader object
And how to manipulate it?
m_floorRenderShader = new Shader("floorTile");
in IsoCell.java interesting
Can I use IndieGL.StartShader withoud doing a new Mixin class?
Does nothing
How to fill up a Shader ?
I must create a Texture to edit the Shader? How to access it fast?
private Texture m_tex;
Shaders hold Texture. Why I should use a Shader instead of Texture so?
Can I access the SpriteRenderer without Mixin class?
reading opengl docs will help you here
SpriteRenderer.instance.render(this.viewport2,
0,//d13 += this.getAbsoluteX() + d,
0,//d14 += this.getAbsoluteY() + d2,
this.width,//d15 += this.getAbsoluteX() + d,
this.height,//d16 += this.getAbsoluteY() + d2,
this.width,//d17 += this.getAbsoluteX() + d,
this.height,//d18 += this.getAbsoluteY() + d2,
this.width,//d19 += this.getAbsoluteX() + d,
this.height,//d20 += this.getAbsoluteY() + d2,
0,//(float)d4,
0,//(float)d5,
0,//(float)d6,
0,//(float)d7,
0,//(float)d4,
0,//(float)d5,
0,//(float)d6,
0,//(float)d7,
0,//(float)d4,
0,//(float)d5,
0,//(float)d6,
0,//(float)d7,
0,//(float)d4,
0,//(float)d5,
0,//(float)d6,
0,//(float)d7,
null);
Pain
Also not working
What is the use of all thoses parameters?
If your function have +8 argument it's a design issue...
you'll find that often in the code
I'm trying to
viewport2.setData(byteBuffer); // <---- GAME CRASH
And in render
this.DrawTexture(this.viewport2, 0.0, 0.0, 1);
But the game crash
viewport2 = new Texture(w, h, "3dviewport", 0);
viewport2.setWidth(w);
viewport2.setHeight(h);
ByteBuffer byteBuffer = ByteBuffer.allocate(4 * (w * h));
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int index = (i * w + j) * 4;
if (i > h / 2) {
byteBuffer.put(index, (byte)255);
byteBuffer.put(index + 1, (byte)0);
byteBuffer.put(index + 2, (byte)0);
byteBuffer.put(index + 3, (byte)255);
}
else
{
byteBuffer.put(index, (byte)255);
byteBuffer.put(index + 1, (byte)255);
byteBuffer.put(index + 2, (byte)255);
byteBuffer.put(index + 3, (byte)255);
}
}
}
Assuming it's RGBA ?
Any luck? Guess not
No the game crash
ByteBuffer byteBuffer = MemoryUtil.memAlloc((int)(w * h * 4));
for (int i = 0; i < w * h * 4; ++i) {
byteBuffer.put((byte)-1);
}
byteBuffer.flip();
GL11.glTexImage2D((int)3553, (int)0, (int)6408, w, h, (int)0, (int)6408, (int)5121, (ByteBuffer)byteBuffer);
MemoryUtil.memFree((ByteBuffer)byteBuffer);
I was almost right. But the game use flip and GL11...
Same code still crashing ๐คก
This line crash
GL11.glTexImage2D((int)3553, (int)0, (int)6408, w, h, (int)0, (int)6408, (int)5121, (ByteBuffer)byteBuffer);
ChatGPT says OpenGL must be initialized but the game already did (?)
GLFW.glfwInit(); // Do not prevent the crash
//GL.createCapabilities(); // Black screen after loading. Produce Exception
How the fuck I'm I supposed to use OpenGL as the game does?
@verbal panther has been doing shader stuff, maybe he can help
ERROR: General f:0, t:1755501083558> ExceptionLogger.logException> Exception thrown
java.lang.IllegalStateException: There is no OpenGL context current in the current thread. at GL.createCapabilities(GL.java:429).
Stack trace:
knot//org.lwjgl.opengl.GL.createCapabilities(GL.java:429)
knot//org.lwjgl.opengl.GL.createCapabilities(GL.java:358)
knot//org.lwjgl.opengl.GL.createCapabilities(GL.java:342)
knot//com.example.UIViewport.<init>(UIViewport.java:130)
knot//zombie.gameStates.IngameState.handler$zza000$modid$enter(IngameState.java:1928)
knot//zombie.gameStates.IngameState.enter(IngameState.java:846)
knot//zombie.gameStates.GameStateMachine.update(GameStateMachine.java:133)
knot//zombie.GameWindow.logic(GameWindow.java:382)
knot//zombie.GameWindow.frameStep(GameWindow.java:916)
knot//zombie.GameWindow.mainThreadStep(GameWindow.java:642)
knot//zombie.MainThread.mainLoop(MainThread.java:76)
java.base/java.lang.Thread.run(Thread.java:840)
No GL context
That's probably why
The game never call glfwMakeContextCurrent
Where the fuck it init OpenglContext
It uses
Display.getWindow()
But the Display class is not in the project or Java native
Okay intellij imports it
long window = Display.getWindow();
GLFW.glfwMakeContextCurrent(window); // <------- Exception
LOG : General f:0, t:1755502081932> [LWJGL] GLFW_PLATFORM_ERROR error
Description : WGL: Failed to make context current: La ressource demandรฉe est en cours dโutilisation.
Stacktrace :
knot//org.lwjgl.glfw.GLFW.glfwMakeContextCurrent(GLFW.java:5186)
knot//com.example.UIViewport.<init>(UIViewport.java:133)
knot//zombie.gameStates.IngameState.handler$zza000$modid$enter(IngameState.java:1928)
knot//zombie.gameStates.IngameState.enter(IngameState.java:846)
knot//zombie.gameStates.GameStateMachine.update(GameStateMachine.java:133)
knot//zombie.GameWindow.logic(GameWindow.java:382)
knot//zombie.GameWindow.frameStep(GameWindow.java:916)
knot//zombie.GameWindow.mainThreadStep(GameWindow.java:642)
knot//zombie.MainThread.mainLoop(MainThread.java:76)
java.base/java.lang.Thread.run(Thread.java:840)
OpenGL already initialized
@Jab can you help me please?
System.out.println("CONTEXT = " + GLFW.glfwGetCurrentContext());
Prints
CONTEXT = 0
But still, aside from the fact that there is no context,
WGL: Failed to make context current: The requested resource is currently in use.
How much software do I need to install to get working with this?
Iv no idea about compiling/decompiling java..
it is recommended to have at least a basic understanding of Java and mixin to use
Black Moons has a good head and is motivated
So I think we can help him out a little more. I'm sure he can use the internet to learn Java and Mixin as he goes but we can help him over hurdles
To get started, you should follow the readme of the example mod: https://github.com/aoqia194/leaf-example-mod
And I think you have to independently use the leaf-installer to install the leaf-loader into your Zomboid installation: https://github.com/aoqia194/leaf-installer
Maybe the example mod configuration does that automagically, I can't remember. @floral sluice
does what
@floral sluice does the example mod configuration automatically install leaf-loader?
or do you need to do that explicitly yourself
yes it does, without it you wouldn't be able to load the game
I think the order I did things in was:
- used steamcmd to install an extra copy of zomboid 42 in a custom location
- use leaf-installer to install leaf-loader into that zomboid
- set the environment variable to tell the example mod config where my zomboid was
- clone the example mod, edit that one configuration file to tell it to use the version of something for zomboid 42
- then gradle sync
if all is well at that point you're probably good to go
@fresh nexus but I guess you can skip the leaf-installer step
@fresh nexus also make sure you use IntelliJ IDEA
will make everything much smoother
Ah yes, make sure to install the minecraft idea plugin, it makes using Mixin a lot nicer
Eventually I can show you how to get hotswapping working, so you don't have to restart the game after changing your code
Soo few questions before I get started...
i bet
Will people need to 'manually install' my mod? (or just 'leaf' or whatever?)
People will indeed need to install leaf
The goal is that leaf becomes so valuable (and easy to use, make java mods in) that it's just a thing you do
the leaf installer is basic now
How likely is my mod to break next B42 update?
but it can be made nicer
depends on how much they change
it's all basically dependent on TIS
Ok, but its not guarenteed to break because of some annoying obfusicated api functions changing every single version right?
nope
(ala minecraft IIRC?)
Though Java is more likely to break compared to Lua purely because they consider Lua when changing method names but not really as much for Java. But it's not like a given statistic
PZ isn't obfuscated
Java is like an internal implementation detail, yeah
Yeaaa mainly im just trying to disable the godawful vehicle engine code and replace it with LUA
Iv already got an LUA functional 'torque boost'...
Also Fabric has intermediary mapping layer that gets rid of most of the hassle with obfuscation. Leaf has that stripped out because the game isn't obfuscated, so there's no need for it
Then again, lua is their scripting language, so you imagine that as the game matures, the Java will change less, and the lua more
Good good.
Much more attainable goal than the other guy in here ๐
doc is trying to write a custom 3D renderer for the game lol
And then maybe I'll reproduce my summer car in PZ.
If you get a handle on Leaf modding you'll be able to do a lot
And by using it you can help us (well aoqia) figure out how to make it better
I mean I can already do most of it in LUA
(Sure would be nice if horsepower worked in forward and not just reverse..)
@floral sluice It'd be kinda crazy if Leaf exposed a lua API that used Mixin under the hood, allowing Lua modders to effectively inject lua closures in the same places, etc that Mixin allows for
Still kinda sad that for as bad as PZ's vehicle code is, im pretty sure the transmission in snowrunner is even worse ๐
though I guess it's not a realistic idea because of how Mixin is annotation based, etc. It's not an imperative patching API.
I guess the other way is to just hook everything with Mixin, then build an API ontop of all those fixed extension points.
Not as flexible but, whatyagondo
true. but im not sure how possible that is for mixin
so, since PZ is not obfusicated, will I be able to see a rather clean version of the java source?
yeah i was reading more about mixin it's definitely not possible
we'd have to make our own mixin-like thing using ASM (bytecode library) directly
As far as I know about mixin, it's happens at a certain stage where mixins get put in-place into classes and then once the mixin stage is done then it doesn't do any more class modifications. you could maybe expose like bytecode patching but something like this is best suited for java mod
yes
And can I just copy that source into my own mod and start making changes, and override the java function with my own?
no
Class, method and field names are kept original human-readable names. Locals don't get names stored in compiled Java code, so they will be generic like string0 or int4
well, kinda, but it's more involved than just copy pasting
I'm working on a tool to help us share local-variable renames so that it can improve over time
Leaf isn't like normal Java patching where you copy paste a whole class and modify it where necessary. You use mixin to modify specific parts of the code with intention, like a surgeon
Ok but Im going to end up just throwing out half the vehicle movement code...
That's fine, that's something Mixin is good at
are you doing like an entire vehicle overhaul thing?
You inject at a point and completely take over a method, ignoring the original code
Yes.
And by that I mean Iv already done one in LUA, but the fact I can't edit the engine noise annoys me.
you would basically redirect the original methods to your custom implementation
yup, and you can cut it as high-level or low-level as you want
with Mixin you can literally hook anywhere, even in the middle of methods. O_O
Cool cool... So.. steamcmd for another install of PZ...
that's what I did to just keep it clean
ok but what command is it?
I don't chatgpt.
You're not executing code in the render context.
@verbal panther spill the beans
You're not going to be doing any render code execution outside the render context / render thread.
I'd go learn how to write a basic LWJGL application / demo game before trying to modify something as built / complicated as PZ's render thread / context.
In my case I've done several, specifically with LWJGL however it looks like this person hasn't or hasn't messed with LWJGL much.
why would you need to?
Leaf doesn't modify any game files, even in dev
I dunno, idlework said to.
It's what I did before I knew about run/
You can have a folder of different game versions, that what I have, but only because I need to test frequently between stable and unstable
im just gonna run unstable..
using steamcmd to get games is easy so i figured why not ยฏ_(ใ)_/ยฏ
...
that's what the steam client is for?
"its so easy, I can't even tell you how to do it!" isn't instilling confidence.
dude you haven't found it yet??
to be fair, there are docs available, just have to search for it on google
I believe there was a valve wiki page on it or something
steamcmd.exe
login anonymous
force_install_dir ./wherever_you_want
app_update 380870 validate
but I don't even know why you would use steamcmd over steam client
steamcmd is doing the exact same thing as installing your game does. and if you care about storage space, it'll make for 3 versions of the game
sure. it does depend on what you want
I mean, I have no clue either, im just trying to make the worlds simplest java mod for PZ.
hehe
but for 99% of people the plug and play solution of auto detecting the game is good
How is that automation vs clicking INSTALL?
i already had pz installed, that wasn't the issue
thats manualmation.
it's "this thing doesn't touch anything else so i don't have to think about that class of problems"
its good if you want multiple versions to test mod against
Yea I just want 42, the rest of you PZ players are outta luck. Nothing can fix the mess that is vehicles in PZ41 MP
lol
although most games are just 1 verify game files away from fixing random issues, like render engine guy who had pz's steam app id file set to a completely different game somehow
I literally can't decypher any of that because your using nothing but magic numbers instead of opengl constants -_-;
https://registry.khronos.org/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml Please use constants...
Yes I's constants from the decompiled source
@verbal panther got anymore you can say?
About?
So what are the actual steps to develope with leaf..
assuming I have.. 0 software for java in particular.
GL programming in PZ, maybe it'd be cool if you could show a minimal example that draws a square viewport with a shader that just draws a triangle
You mean my own stuff?
Yes how cqn I draw a square? in the rneder context
I just mean a minimal thing to help people around here get headed in the right direction
You won't be able to draw the world in the world layer without modifying the Java code.
Ouch.
We can look at it, and go research the related info
You're in #1379702489250529280
hehe
It'd take a bit of time to do any of that and I have active projects + a commission to work on atm so I couldn't be helpful.
Sorry for not responding Discord didn't load your messages
While doc's eventual goals are pretty grand, I think we're happy to just do baby's first opengl triangle in pz for now
well, alright no worries man
thanks for the context tip at least hehe
Sure. I can tell you what's wrong but a guide? Nah.
If PZ was my actual job then hell yeah
just a little code example is what i had in mind
if your gui stuff open source / on github @verbal panther ?
Like where is the render context thread ?
Maybe we could look at that stuff
Everything is.
Didn't think about using steamcmd to install two versions of the game. Tho the app ID you use here is not PZ. Unless you're not talking about pz ? I haven't read the full thing
(i asked gpt for the commands so i'm not surprised the id is wrong lol)
Bruh
i even said it above
If you use AI then I can't help you. It'll break.
But I'll look into it and add it to the steamcmd wiki page sibce that can be used to install both B41 and B42
But good luck.
Literally why... Lesson learned, don't ask idlework for help lol.
....
Yea I didn't read the full chat I was looking and saw you discussed steacmd so I got curious since I played a bit with it and made a wiki page about it
will get incorrect AI awnsers with no notice that they are AI generated or incorrect.
I literally joked about it!
I don't think idle here is stupid here and doesn't know about the risks of ai
I've been doing software engineering for 25 years professionally, but I don't need to give you help that's fine
Having run those steamcmds many times, I knew they were right.
except for the app ID, that would have caused me to download some random game...
illegally..
Getting the ID wrong was inevitable but an easy thing to look up
lol you can't just steamcmd any game
to that point, you need to login as yourself not anonymous which is only gonna work for dedicated servers and stuff
So yea, if anyone has a non AI generated guide on how to use leaf (getting that example mod to compile or whatever), without extra steps that I don't need to do if im not trying to develope for multiple versions of PZ, im interested.
Else i'll just go back to my LUA modding.
@verbal panther Why Texture::getWhite method have a GL context and not my function?
There is literally no keyword referring to the cretation or fetching of a GL context
380780 (0..4) is PZ dedicated server
But still the game accepts without crashing the call GL11.glTexImage2D
0 is shared resources depot, 1 2 3 are linux, mac, windows
same with 108601 (1..4) with PZ game client
why dont you hit F12 or CTRL+CLICK it and see where it gets used, maybe you will find th render thread there
Why the fuck drawing a square is so complicated?
did warn you ๐
There is no declaration
Only a Texture class
With no getter or setters
Well there is setData method for Texture
But it crashes
And when you read you see a bunch of stupid variables but not the actual data is absent
Where this stupid game stores pixels ? If not in Texture?
shrugs
Storing pixels ???
He's trying to figure out how to manipulate PZ Textures
public static final HashSet<String> nullTextures = new HashSet();// Unrealated
private static final long serialVersionUID = 7472363451408935314L;// Unrealated
private static final ObjectRenderEffects objRen = ObjectRenderEffects.alloc();// Maybe ?
public static int BindCount = 0;// Unrealated
public static boolean bDoingQuad = false;// Unrealated
public static float lr;// Unrealated
public static float lg;// Unrealated
public static float lb;// Unrealated
public static float la;// Unrealated
public static int lastlastTextureID;// Unrealated
public static int totalTextureID;// Unrealated
private static Texture white;// Unrealated
private static Texture errorTexture;// Unrealated
private static Texture mipmap;// Unrealated
public static int lastTextureID;// Unrealated
public static boolean WarnFailFindTexture;// Unrealated
private static final HashMap<String, Texture> textures;// Unrealated
private static final HashMap<String, Texture> s_sharedTextureTable;// Unrealated
private static final HashMap<Long, Texture> steamAvatarMap;// Unrealated
public boolean flip = false;// Unrealated
public float offsetX = 0.0f;// Unrealated
public float offsetY = 0.0f;// Unrealated
public boolean bindAlways = false;// Unrealated
public float xEnd = 1.0f;// Unrealated
public float yEnd = 1.0f;// Unrealated
public float xStart = 0.0f;// Unrealated
public float yStart = 0.0f;// Unrealated
protected TextureID dataid;// Unrealated
protected Mask mask;// Unrealated
protected String name;// Unrealated
protected boolean solid;// Unrealated
protected int width;// Unrealated
protected int height;// Unrealated
protected int heightOrig;// Unrealated
protected int widthOrig;// Unrealated
private int realWidth = 0;// Unrealated
private int realHeight = 0;// Unrealated
private boolean destroyed = false;// Unrealated
private Texture splitIconTex;// Unrealated
private int splitX = -1;// Unrealated
private int splitY;// Unrealated
private int splitW;// Unrealated
private int splitH;// Unrealated
protected FileSystem.SubTexture subTexture;// Unrealated
public TextureAssetParams assetParams;// Unrealated
private static final ThreadLocal<PNGSize> pngSize;// Unrealated
public static final AssetType ASSET_TYPE;// Unrealated
The Texture class variables
Full of random data
Do you see any 32bit element array? Do you see any pixel value?
Testures in openGl are just a 32bit int that references some internal thing for opengl...
(at least, in C++)
Sure. But why Texture do not hold the int array so ?
Oh ObjectRenderEffects do not hold anything
That means Texture is just a empty shell
actually no im wrong, im pretty sure it's 380870+
eh one number off
you sure texture isn't just a struct-style data object to store opengl outputs or something
No because you see it at low level rendering
But when you dig you find nothing
You'll find maybe OpenGL calls that are not possible to do anywhere outside because this is not the "Rendering context" @verbal panther
are you actually in the render thread or have access to the render context?
When I call getRenderContext I get zero. So I'm assuming I'm not in the render thread.
I don't know how to access the render context (the funny part is: the Texture class do not "access the render context" it just magically works ๐คก )
I like magik tricks too because I'm lazy
But this magik is too powerful I'm just a developer, not a wizard
@jagged scarab I think like this:
RenderThread.invokeOnRenderContext(() -> {
GL11.glTexImage2D(textureTarget, mipmapLevel, internalFormat, width, height, borderWidth, pixelFormat, pixelType, pixelData);
});
you pass a lambda/closure to invokeOnRenderContext
which I guess runs the closure on the render thread
For example, what's the point of a setWidth method if you cannot access the inner pixels?............. Is it some sort of design pattern do makes thing incomprehensible?..
Thanks I'm trying this
not even that, Texture literally has render functions as well
I just mean this is how you run stuff on the render thread
There's so much info here from just looking simply at the Texture class, I don't know how you could miss this
but yeah someTexture.render(x, y, renderWidth, renderHeight);
Literally in the constructor of TextureID - RenderThread.queueInvokeOnRenderContext(() -> this.createTexture(false));
Like even look at ```java
TextureID.generateHwId(boolean)
It crashes with no explanation
Yeah it call SpriteRenderer and it takes a Texture which is supposed to contain pixels
@jagged scarab try this
int size = 64;
Texture tex = new Texture(size, size, "whatever", 0);
int bytesPerPixel = 4;
int totalPixels = size * size;
ByteBuffer pixels = ByteBuffer.allocateDirect(totalPixels * bytesPerPixel);
pixels.put(2048, 255);
pixels.flip();
tex.setData(pixels);
tex.render(200, 200, size, size);
if it don't work, try using two for-loops to set every pixel
I try your snippet
i'm curious if it'll work
This is not the problem !
mmok
FYI setData crashes the game....
but ill try...
dont construct new texture, get it from game files
how are you using Texture exactly?
like whats the purpose of you using it
the whole point is to render something custom at realtime
like obviously it's not gonna be performant enough for what he needs
like an image?
using the cpu like that
but i think he's just demoralized
and wants to render literally anything
to keep the juices going
๐
Yes
I just want to render something the optimization part can be fixed later with the right method (maybe @Jab knows)
if he wants to render an image from the media folder you include, it can be done via
final int flags = 0;
Texture tex = Texture.getSharedTexture("media/path/to/YourTexture.png", flags);
๐
but it wouldn't be doing pixel stuff, that you need to go more internal to do
yeah rendering images from disk is ezpz
i think my snippet might work
if setData doesn't inexplicably crash the game
But you'd want to extend UIElement probably and override the functions like render.
Otherwise it won't display
I did this
nah there's no reason really to go through UIElement
we did it already
it just calls .render
and that ends up just using SpriteRender to draw stuff
so just take out the middleman
how to do thinnest draw shape to screen
essentially, but if you're having issues then that'd be the best place to look
yeah we got that working already at least
can fall back if need but I looked pretty good and UIElement just calls render on its children which potentially override .render to do spriterenderer stuff
like UIWindow, etc
Ah you know what
It looks like you do need to call setData on the render thread
so more liek this:
int size = 64;
Texture tex = new Texture(size, size, "whatever", 0);
int bytesPerPixel = 4;
int totalPixels = size * size;
ByteBuffer pixels = ByteBuffer.allocateDirect(totalPixels * bytesPerPixel);
pixels.put(2048, (byte)255);
pixels.flip();
RenderThread.invokeOnRenderContext(() -> {
tex.setData(pixels);
tex.render(200, 200, size, size);
});
I'm not on the render thread, I'm on context zero ๐คก
Though to @floral sluice's point, you'd want the render call to happen each frame
... Hmm, Don't have an IDE or a gradle.. or a loom.
RenderThread.invokeOnRenderContext crashes the game too !
welp, I guess that counts me out.
yea I see it UIElement does ```java
SpriteRender.instance.render(Texture, x, y, width, height, r, g, b, a, null);
What was the problem with this?
IDEA is free, so is gradle, so is loom
you only need IDEA, which comes with gradle and loom and everything else
@floral sluice is your recommendation to use a UIElement just for the benefit of getting your .render called each frame so you don't have to figure out a different way of rendering repeatedly?
And whats the website for 'IDEA' so I don't have to google a very common english word and hope to end up remotely in the correct place and not a malware lookalike site?
sure, but also, if you dont want to extend it, just look at what calls UIElementInterface.render and go up the callstack until you find a render loop that is worth injecting into
intellij IDEA
IntelliJ IDEA is an Integrated development environment (IDE) used by Project Zomboid modders. It is most useful to parse the Java files of the game.
Jetbrains IntelliJ IDEA Community Edition ^
Extending is perfectly fine
UIElement expects certain lua tables to be populated though, thats why I mention just injecting into the main render loop
Most likely, the main KahLua thread has it's own render method
I assume community edition?
Yeah that's what we were dealing with. What I had him do was take UIElement, and scrap all the functionality related to lua, children, etc etc
All that was left was the original .render and all we left in there was the debug outline code which we got to render by adding it to the UIManager
So it's a nice way to create a class that can be added to UIManager naturally ๐
lol love hollowing out existing code.
Most UI that was made in Java back then and still a little now, extend UIElement
"you do things, Kinda like I wanna do.. but.. not really. BUT NOW YOU WILL"
I think they have some boilerplate still in Lua to make it not die
rips out old code, does code transplant
I mean you can just implement UIElementInterface, but I didn't feel like guiding through that
"delete all the stuff that isn't also in UIElementInterface" was an easy directive to follow hehe
yeah but if all you want is for UIManager to call your .render each frame, all you need to be is a valid UIElementInterface
@jagged scarab so that's what I actually recommend
go back to our UIViewport or whatever you called it
and put this texture snippet I shared inside the render
you can delete that debug drawing code and just keep the new texture code
The compiler says
C:\Users\asdsadasd\.gradle\caches\leaf-loom\42.11.0-unstable.30715\dev.aoqia.leaf.yarn.42_11_0_unstable_30715.41.78.16+build.1-v2\mappings.jar: The process cannot access the file because it is being used by another process.
So I'm trying to kill processes but it still won't compile
Clone the repository or use the template feature provided by GitHub. so do I have to clone the repo or can I just download a copy to disk?
Just download the installer
.. I did
cloning the repo is the basically the same as downloading main as a zip
im talking about the mod template
no, you dont need the installer
you dont need to clone the installer, nor do you need to actually use it (for dev in IDE)
the build configuration in the example-mod does it magically
... so I download the example mod as a zip, extract it somewhere anddd...?
... why is the open project dialog *.*
I'm deleting the cache.........
@jagged scarab look at your dms
Oh. Its one of those file dialogs thats a folder dialog -_-
even though it says to open a filename...
Hmm, where are the enviroment variables...
it's because technically you can open a project just fro ma file
for the LEAF_CLIENT_GAME_PATH = D:\SteamLibrary\steamapps\common\ProjectZomboid thing..
if you select and open the build.gradle file
you have to set them based on your operating system
search up on google how to set environment variables
if you're using the default steam install and it's at the default location, you dont need to do this
.. oh, those enviroment variables...
please for the love of god people stop using those...
the 'fun' when you.. suddenly run outta space, because your path is like 900000000 long and has 3 compilers with the same damn name in them
??? the max path limit assuming its extended is fairly large
also they are objectively the best way to handle system-specific configuration
I tried having project-specific, but it's no wonder and I knew it wouldn't be good, because people commit their install path to git and then everyone cant build the project.
thats why I said it's super easy for most users that have everything default. Most people install their games on the drive Steam is installed (C:) and it auto detects it
I did think about parsing the regedit paths of Steam and the vdf files to get PZ game directory, but this is much code for only small benefit (dev environment only), and it's still not even guaranteed to work
.. despite setting the enviroment variable, I still get
Client game file 'C:\Program Files (x86)\Steam\steamapps\common\ProjectZomboid\media\AnimSets\player\climbwindow\end.xml' does not exist.
Yea it gets less fun when you install several bespoke development enviroments for various UC's at once ๐
Bonus points when your MMORPG's refuse to let you develope while running your shop in the background because 'omg GCC.exe must be some kinda hacker tool'
So any clue what I did wrong?
Sadly my steam is not in the default location
I won't question why it's at C:\Steam, in any case that should theoretically work
make sure you completely shutdown and restart the IDE, environment variables only update after the program is restarted
ah k
environment variables are imported once at hte start of a program and they dont change until you restart it
java.io.IOException: Failed to copy file from (C:\Steam\steamapps\common\ProjectZomboid\media\AnimSets\zombie\hitreaction\Shot\ShotChestStepR.xml) to (C:\Users\Black Moons.gradle\caches\leaf-loom\41.78.16\extracted\media\AnimSets\zombie\hitreaction\Shot\ShotChestStepR.xml)
(and many more like that)
update your game version in the example mod's gradle\libs.versions.toml
... why is it trying to copy to black moons.gradle\ ?
leaf-loader to 1.4.1, leaf-loom to 0.6.0 and game version (assuming you're unstable branch) is 42.11.0-unstable.20715
the game is copied to the gradle cache
No
im saying, that user doesn't exist
black moons\ exists, black moons.gradle\ is.. a failure to properly concat paths together
I am unsure. It might be an error with spaces in user folder. I've never seen a space personally in a user folder before
Sigh.
You can override that by doing GRADLE_HOME environment variable to C:\Users\Black Moons\.gradle
or I think that should work at least
oop it's GRADLE_USER_HOME
Failed to find zomboid version: 42.11.0-unstable.20715
30715, not 20715
I mispelt it
if only keys weren't right next to each other ๐ญ
also I forgot to mention, I added the clearLoomCache gradle task a version or two ago and forgot to mention it here I think. So here I was telling you to manually delete the cache when you can just run that lol
seems to be spending its time doing things.
that will be the game copying
it scales based on drive write speed, it will take not too long on a slow SSD, and if you're on a m.2 basically like 3-4 minutes at most. HDD as albion showed me (RIPPP) is like 50 minutes
ok like I mentioned 2 days ago, im going to be heavily focusing on everything docs related. It's mainly going to be going towards mod setup and the quirks with leaf. I don't think there is too much to document honestly
I do need to update the readme's for loom and loader, but these don't need as much attention as they are mainly for developing leaf and not the user
Ok it seems to be odne without exploding.
so.... do I now have a decompiled PZ somewhere for me to look at?
(I assume in IDEA?)
run the genSources gradle task to generate decompiled sources that you can look at
in IDEA, on the right sidebar I think is where the gradle drawer usually is
most of this is on the example mod readme, or it should be
the leaf->gensources task?
Generate decompiled game sources by running the genSources Gradle task. Oh yes, this totally tells me what to do.. if I was a hollywood hacker on CSI
yea, the readme doesn't help at all because it doesn't tell me where on earth of the 1000+ odd buttons this IDE has where to click
Well it's generally not IDE specific, you can even run it in the cli via .\gradlew genSources
No, I can't because I dunno where the CLI is.
I should really specify that people have an understanding of this stuff, since not to be harsh but I don't want leaf to be filled up with questions asking about how the IDE or gradle works, since all of this is very accessible with a quick google
cli is your terminal, command prompt, shell, etc
It would also help to say leaf->gensources since there is like 10 different tabs to look through on that page
Ok then I have no idea what a .\gradlew is
gpt, what is .\gradlew
Anyone who knows how to use Gradle with IDEA knows that a "leaf" tab would probably suggest something related to the leaf project you're using
gradlew is a gradle wrapper
Yea, I don't.
lol i know what it is
oh it wasn't a question ๐ญ
I thought I made that clear already?
Yes you did, I am telling you this because I really don't want this thread to be questions asking what gradle is and how they can order bread from their nearby grocer or something
It'll become a thread less about leaf and more of a general tech support for how to use java...
I never intended anyone unexperienced with Java and mixin to use leaf. That is the purpose of leaf, people who are experienced enough make java mods that expose functionality in Lua, so people who know Lua which is far simpler without the hassle of mixin can reap the rewards of Java modding
I'm not saying you can't become experienced either, it's just in general feels like a punch in the gut to have people ask more questions that are easily google like how to use their IDE rather than leaf-related questions, in the leaf mod project
Sorry, just no idea where else to even ask.
Where does GenSources put the PZ sources?
in the loom gradle cache
alongside the game files that were copied over
more specifically, %GRADLE_USER_HOME%\caches\leaf-loom\decompile
So.. .the .jar's in C:\Users\Black Moons.gradle\caches\leaf-loom\42.11.0-unstable.30715\extracted ?
no, that is the game
Oh, decompile
zomboidMaven is the folder that contains the final game files that are used by the IDE in dev environment only
and com.theindiestone is a fake maven prefix I've created because I felt zombie.* was a too broad and possibly conflicting prefix to have in buildscripts. THough, it is still zombie.* in the actual class structure and code
yes, they are hashes of decompiled classes
If you're trying to read them, you do it through the IDE via search files or control click when you import a class, not through reading the raw decompiled files
Though if you really really want to read the decompiled sources externally, they in the zomboidMaven with the suffix -sources.jar
yes, CTRL+SHIFT+F keybind, search for something
if you want to search the name of a class, I believe it's CTRL+N/CTRL+SHIFT+N but I've modified my keymap so im not sure
keep in mind that IDEA's default search filters might not search through sources of any kind, so you have to change those
Erm, do I have to extract the zip first?
trying find in files: C:\Users\Black Moons.gradle\caches\leaf-loom\decompile... getting nothing?
for things like 'log' and 'vehicle'
just do in project, yea?
dunno i don't have leaf stuff open atm