#mod_development
1 messages ยท Page 34 of 1
Looks like getFileReader is getting called with invalid parameters (are you calling it directly and passing it a modid, which is doesn't accept?) Can you show me how you're calling getFileReader or ArendamethUtils.readFile or getModFileReader or ArendamethUtils.readModFile?
not that I know of
function CharacterCreationMain:getBackstory()
local jsontext = ArendamethUtils.readFile("CharacterBackstory", "media/lua/client/backstories.json")
if not jsontext then error("do your error handling") end
--local object = CharacterBackstory.JSON:decode(jsontext)
--print(jsontext)
--print(object)
local backstory_text = "{forename} {surname} was born on the 19th of December, 1999"
local forename = CharacterCreationMain:getForenameText()
backstory_text = backstory_text:gsub("{forename}", forename)
local surname = CharacterCreationMain:getSurnameText()
backstory_text = backstory_text:gsub("{surname}", surname)
return(backstory_text)
end```
change readFile to readModFile. You're using the wrong api to read from a mod's file, but you are passing it a modid
yup that fixes the error. Didn't even notice I am using different params from the ones defined in ReadFile func ๐คฆโโ๏ธ
Unrelated, in lua, doing return(foo) causes multiple return values to be lost. It's not an issue here, because you only have one variable which can't have multiple return values, but if it were a function call result e.g. return foo(), that would have that effect. In lua return isn't a function call, so it doesn't need parens and has an effect you might be unaware of.
ooh I see, so its generally better in lua to just return foo instead of return(foo)
yea
function f1()
return 1, 2
end
function f2()
return f1()
end
function f3()
return (f1())
end
print(f2()) -- prints: 1 2
print(f3()) -- prints: 1
i see, thanks so much for the tip!
definitely saves me a lot of potential problem-solving in the future lol
You might consider arranging the json data in your files outside of the lua directories. There's no need for them to be there just because that's where your lua code that reads them lives.
Could do something like this if you think it organizes your mod files better:
media/lua/client/mymod_charcreation.lua
data/backstories/officeworker.json
data/backstories/videogamedeveloper.json
data/backstories/pzmodauthor.json
local jsontext = ArendamethUtils.readModFile("CharacterBackstory", "data/backstories/pzmodauthor.json")
Doesn't hurt if they are in the lua folder afaik though
So far I think I won't need more than one JSON files to have all stories entries, and the code will just pick one of them randomly, like so:
{"stories": ["test1", "test2", "test3"]}```
```lua
local jsontext = ArendamethUtils.readModFile("CharacterBackstory", "media/lua/client/backstories.json")
if not jsontext then error("do your error handling") end
local object = CharacterBackstory.JSON:decode(jsontext)
myTable = object["stories"]
print(myTable[ZombRand(#myTable)])```
Could definitely do with some structural organising though.
@undone elbow Was messing with mod options yesterday, and it seemed that there are only two types of UI widgets to modify options (checkbox for boolean and dropdown for table). Did I miss anything else e.g. a string input?
I think you want #myTable + 1 there, if I understand how ZombRand works correctly
err
no
1+ZombRand(#myTable)
ZombRand returns 0 (inclusive) up to the first parameter (exclusive), if I understand right
so ZombRand(5) returns 0 to 4 (Someone correct me if I'm wrong please)
no wonder it never printed the last entry in the table, and sometimes printed nil instead
ModOptions was a fast tiny mod for myself. I didn't think it would become popular. Yes, I wanted to add a string and color inputs. But it' still WIP ๐คทโโ๏ธ
alriight so new problem. I am trying to set the backstory variable when the player enters the customization window
CharacterBackstory = CharacterBackstory or {}
CharacterBackstory.JSON = require("lib/JSON")
local original_create = CharacterCreationMain.create
local backstory = nil
function CharacterCreationMain:getRandStory()
local jsontext = ArendamethUtils.readModFile("CharacterBackstory", "media/lua/client/backstories.json")
local object = CharacterBackstory.JSON:decode(jsontext)
local myTable = object["stories"]
local backstory_text = myTable[1+ZombRand(#myTable)])
backstory = backstory_text
end
function CharacterCreationMain:create()
original_create(self)
local x = self.randomButton:getAbsoluteX() - 150
local y = self.playButton:getAbsoluteY()
local w = 70
local h = self.playButton:getHeight()
self.backgroundButton = ISButton:new(x, y, w, h, "Character Backstory", self, self.onBackgroundButton);
self.backgroundButton:initialise()
self.backgroundButton:instantiate()
self.backgroundButton.borderColor = {r=1, g=1, b=1, a=0.1}
self:addChild(self.backgroundButton)
CharacterCreationMain:getRandStory()
end```
Apparently, something's wrong with the way I am implementing ``CharacterCreationMain:getRandStory()``
What's wrong with it? I only see backstory set in that code. Is it referenced elsewhere?
It's local to the file too btw, in case you were trying to reference it outside the file
no, its set in that code only, also no I am not trying to reference it outside the file
I get error code 1 whenever i launch the game and the button won't appear when I enter the customization window when I add the CharacterCreationMain:getRandStory()
No errors in console, no error window appears
actually I just commented that line and I still get Error 1, i think the issue is elsewhere
What's the filename you have that code in? I could test it to repro that error probably
commenting the getRandStory function fixes it
file is called CharacterBackstory.lua
lemme know if you need all the mod files sent if that'll make things easier
local backstory_text = myTable[1+ZombRand(#myTable)]
had a syntax error
Is there a way to access the output log?
Zomboid/console.txt in your user directory
Yeah that's why I've been bleh on working on my stuff
Also the tostring method does not seem to want to work
It did hehe ```lua
ERROR: General , 1665649145602> DebugLogStream.printException> Stack trace:
se.krka.kahlua.vm.KahluaException: CharacterBackstory.lua:14: unexpected symbol near )
wat why didn't it show anything in my console.txt
smh
oki i think that should be mod fundamentals done. Only hours left to spend writing stories lol
thanks for the help though! I really appreciate it
I have a cygwin terminal open running tail -F Zomboid/console.txt on a second monitor. It helps to catch and read errors
think i need at least four monitors for modding projects ๐
LOG : General , 1665650333419> ----- arg 1/6: userdata -----
(userdata) zombie.erosion.ErosionMain@cb6013e <
<METATABLE> => table 0x623182521 {
. [__index] => table 0x479642794 {
. . [snowCheck] => function 0x835583311
. . [isSnow] => function 0x1284537734
. . [getSnowFraction] => function 0x1401699038
. . [mainTimer] => function 0x789801401
. . [getSeasons] => function 0x1911213713
. . [equals] => function 0x1774346350
. . [toString] => function 0x230481736
. }
}
>
It's quite handy when debugging in the lua console too. I can print out objects to see what functions or data they contain.
soo I am using this to fetch current profession in customization window:
function CharacterCreationMain:getCharProfession()
local desc = MainScreen.instance.desc;
local profession = desc:getProfession()
return profession
end```
problem is, If I go back and change from Unemployed to Fire Officer for example, It'll stay the same, "Unemployed"
Am I using it incorrectly/Is there a better way to do this? or do I have to add another piece of the code to catch the new profession when the player changes it?
so im new to modding the game, what is the main folder to go into just to mess with stuff and experiment?
C:\Program Files (x86)\Steam\steamapps\common\ProjectZomboid\media\lua
and
C:\Program Files (x86)\Steam\steamapps\common\ProjectZomboid\media\scripts
@zenith tangle
thank you man
Is normal that the progress bar appears above me while the action is done by another IsoPlayer?
I missed some update(?, a few weeks ago this didn't happen :/
that the?!
how did that happen u just enclosed the (f1()) with iuter parenthesis and it will pront only the first variable? why is that?
goodluck .. thats gona burn your eyes dude
True...true....couldn't be worse than playing Dead By Daylight tho
Also I feel silly but the thing I was looking for earlier was just the print command. So the output shows up in the Output Log that appears in the bottom left corner of the game screen
It converts everything to a string for me, which is nice
Well idk if it converts stuff but itll print it and that's all that matters
You mean it isn't updating in the UI? You might need to call some method to redraw the UI
That's just an effect of () according the the lua specification
Not quite. return profession gets called and stored in a variable, then that variable is used when openning a textbox. Assuming i chose unemployed, then opened the textbox, the profession variable in the textbox will show as unemployed. However if you go back and change, then open the textbox again, it'll remain as unemployed
Can you redraw the textbox? Or create a new textbox to replace that one? Sounds like perhaps it is drawn once based on the value in a variable and never redrawn after changing the variable
Hard to give more specific advice not being familiar with this UI code
In your shoes, I'd grep around for references to that variable that contains the value that is being changed and used to draw the textbox
It's rather weird, since the variables should be randomized anyways when the player enters the customization window, yet if I leave the customization window and go back to main screen, then go back in, everything remains the same, they don't get randomized again
I'll try to look around the vanilla code to see if anything helps
How to change BodyLocation using Lua?
local item = ScriptManager.instance:getItem("Base.CBX_ST4")
if item then
item:DoParam("Weight = 33") -- works
item:DoParam("BodyLocation = Skirt") -- doesn't work
item:setBodyLocation("Skirt") --doesn't works
end```
good to know.
u saved from a potential thing where i cant figure out whats going on and why
is it possible to be able to access the character creation menu . even after u spawn ?
could be a good mod idea.
ow i have a snippet abt this but im afk..darn it
not sure but i think i was able to change profession of a player before
but the added stats bonus dont apply anymore as i recall
Appreciate the help but I am trying to update the profession variable if the player changes from the character creation window, not change it myself from the code
so what you planning to mod? just curious ๐
might try ```lua
item:setBodyLocation(...)
Oh, that doesn't work either, hrm
How do you get the parent modal from a button?
A lot of the UI elements that I looked at have a parent field. Might check that
lemme see
If you still have that ArendamethUtils.inspect function, you could try calling it on that UI element to see what it has. It will dump it into console.txt
getParent might be it
just planning to tweak some stuff
always felt that zomboid hasnt reached that nirvana of survival games
think fallout: dust if you've ever played it
everything is a trade-off, you're always barely managing it to the next objective etc
ArendamethUtils = ArendamethUtils or {}
ArendamethUtils.InspectMetatables = ArendamethUtils.InspectMetatables or true
ArendamethUtils.InspectDefaultDepth = ArendamethUtils.InspectDefaultDepth or 3
ArendamethUtils.InspectTableIndentWidth = ArendamethUtils.InspectTableIndentWidth or 4
ArendamethUtils.inspect = function(t, depth, header)
depth = depth or ArendamethUtils.InspectDefaultDepth
header = header or string.format("---------- %s ----------", type(t))
local printOutput = {}
table.insert(printOutput, header)
local table_cache = {}
local function inspect_impl(t, depth, indent, prefix)
local indentLead = prefix and "." or " "
prefix = prefix or ""
depth = depth - 1
local tableIndent = indentLead..string.rep(" ", ArendamethUtils.InspectTableIndentWidth - 1)
local prefixIndent = string.rep(" ", string.len(prefix))
if type(t) == "table" then
if table_cache[t] then
table.insert(printOutput, indent..prefix..tostring(t).." ** PRUNED. Cycle/duplicate detected **")
return
end
if depth < 0 then
table.insert(printOutput, indent..prefix..tostring(t).." ** PRUNED. Max depth reached **")
return
end
table_cache[t] = true
table.insert(printOutput, indent..prefix..tostring(t).." {")
for k, v in pairs(t) do
inspect_impl(v, depth, indent..prefixIndent..tableIndent, "["..tostring(k).."] => ")
end
local metatable = getmetatable(t)
if ArendamethUtils.InspectMetatables and metatable ~= nil then
inspect_impl(metatable, depth, indent..prefixIndent..tableIndent, "<METATABLE> => ")
end
table.insert(printOutput, indent..prefixIndent.."}")
elseif type(t) == "userdata" then
local metatable = getmetatable(t)
if not ArendamethUtils.InspectMetatables or metatable == nil then
table.insert(printOutput, indent..prefix.."("..type(t)..") "..tostring(t))
return
end
if depth < 0 then
table.insert(printOutput, indent..prefix.."("..type(t)..") "..tostring(t).." ** PRUNED. Max depth reached **")
return
end
table.insert(printOutput, indent..prefix.."("..type(t)..") "..tostring(t).." <")
inspect_impl(metatable, depth,
indent..prefixIndent..indentLead..string.rep(" ", string.len("("..type(t)..") ") - 1),
"<METATABLE> => ")
table.insert(printOutput, indent..prefixIndent..">")
elseif type(t) == "string" then
table.insert(printOutput, indent..prefix..'"'..t..'"')
else
table.insert(printOutput, indent..prefix..tostring(t))
end
end
inspect_impl(t, depth, "")
print(table.concat(printOutput, "\n"))
end
ArendamethUtils.inspectAll = function(...)
local args = ArendamethUtils.pack(...)
if args.n == 0 then
print("Zero objects to inspect")
return
end
for i=1,args.n do
local header
if args.n > 1 then
header = string.format("----- arg %d/%d: %s -----", i, args.n, type(args[i]))
end
ArendamethUtils.inspect(args[i], nil, header)
end
end
Current version. It makes it a lot easier to visually parse the output of tables. Also prints the metatables too (for tables and userdata like java objects)
All the java methods are in the objects' metatables
I assume .inspect is the "new version" of "printR"?
oh, yea. I renamed it
what's header? I noticed its a new arg
Just the first line it prints above to separate it from the preceding text. Makes it a little easier to parse visually I think
It's not a parameter you need to provide when calling it
(optional)
[parent] => table 0x1597117992 ** PRUNED. Max depth reached **
function CharacterCreationMain:updateBackstory(button)
ArendamethUtils.inspect(button, 1)
end```
Soo.. If I am not mistaken, parent can be returned using sth like
```lua
local parent = button.parent?```
I see, that's nice.
yea
and it is a table (per that output)
well I tried parent:setText("test") but obv it wasn't that easy and threw and error so I ran an "inspection" on the parent and I got [defaultEntryText] => "bla bla bla" but apparently its not easy either, as parent.defaultEntryText = "test" wouldn't work either
the error's LOG : General , 1665662575296> Object tried to call nil in updateBackstory on parent:setText("test") which is weird considering parent wasn't nil when it was printed
That's because you're referencing a variable parent instead of getting the parent field from button
local parent = button.parent is defined before it
parent:setText()
vs
button.parent:setText()
function CharacterCreationMain:updateBackstory(button)
local parent = button.parent
parent:setText("test")
ArendamethUtils.inspect(parent, 1)
end```
Is there a setText field on the parent with a function value?
[setText] => function 0x123123123
It would look like this ๐
You can inspect(parent.setText) too
are u sure parent of button have setText?
usually buttons creates exactly on plain panel
mb u want to set text of button?
wtf
Anyone else here ever find that trying the wrong thing can result in game throwing errors from a file even after you have reverted to a version that did not throw errors before?
did u reload file via debug console?
Yes
no I am trying to set the text of the textbox which is present in the parent of the button
Also it doesn't have setText function which is rather weird considering it works in the same way in vanilla
function ISDebugUtils.addTextEntryBox(_self, _data, _title, _x, _y, _w, _h)
local entryBox = ISTextEntryBox:new(_title, _x, _y, _w, _h);
entryBox:initialise();
entryBox:instantiate();
entryBox:setText("");
entryBox.customData = _data;
_self:addChild(entryBox);
return entryBox:getY() + entryBox:getHeight(), entryBox;
end```
This is from vanilla
um hold on
local entryBox = ISTextEntryBox:new(_title, _x, _y, _w, _h);
self.modal = ISTextBox:new(660, 250, 600, 500, "Character Background Story", self.getBackstory(), nil, self.buttonConfirm);
try to select file and twice click Reload file not just reload button on file in list
debug menu working by strange way everytime
ye they're different kind of modals ๐คฆโโ๏ธ
I actually did that. It's very odd... Specifically, I have this function that was responding to presses of joypad buttons... I added stuff to try to output info about the UI during that press, and it partly worked (successfully printed UI element indices) but threw exceptions anyway. Upon reverting, pressing a button kept throwing exceptions.
button literally on textentry? bruh...

wait what? lemme ss
oh sec
Don't mind the location of the update button
so I am basically trying to, when pressing the "update" button, change the text of the textbox
Also I just restarted server to confirm, and restarting fixed server, but no amount of file reloading would do so
zomboid 
I bet I could replicate the issue if anyone smart wants to watch it happen and maybe see more than I see
I bet if I make the same edits in the same order on a live server I will see the same mysterious exceptions
doesn't seem to do anything either
function CharacterCreationMain:updateBackstory(button)
local parent = button.parent
parent.textEntry = "test"
end```
They involve java.reflect invocation target exceptions that don't tell you much
don't add elements on panel just like parent:addChild(panel)
after of it add it exactly in parent like
parent:addChild(panel)
parent["ICanEasilyUseThisPanelLater"] = panel
so
parent["ICanEasilyUseThisPanelLater"]:setText("blablabla")
parent doesn't have textEntry key
Oh I completely see what's happening now
huh?
When I update one of my files, the old version keeps running
It's so odd
But I just edited the file very simply
To add an extra speech line
Both the new and old ones are printing
Even though function has 100% been changed
The game is holding on to the old version and running both until I restart server
How even
These functions have the same name
idk what u did there to keep running both versions of file
Ik only one way it's event.add with anonymous function
My position is that I did nothing unusual. You are welcome to watch this happen and prove me wrong.
they can't have same name literally
so overall it should be like:
it's overrides in global table
I think u use local functions with some local inf running
function CharacterCreationMain:onBackgroundButton()
self.modal = ISTextBox:new(660, 250, 600, 500, "Character Background Story", self.getBackstory(), nil, self.buttonConfirm);
self.modal:setNumberOfLines(15)
self.modal:setMultipleLine(true)
self.modal:initialise();
self.modal:addToUIManager();
local w = 70
local h = self.playButton:getHeight()
self.testButton = ISButton:new(10, 10, w, h, "Update", self, self.updateBackstory);
self.testButton:initialise()
self.testButton:instantiate()
self.testButton.borderColor = {r=1, g=1, b=1, a=0.1}
self.modal:addChild(self.testButton)
self.modal["ICanEasilyUseThisPanelLater"] = self.testButton
end
function CharacterCreationMain:updateBackstory(button)
local parent = button.parent
parent["ICanEasilyUseThisPanelLater"]:setText("blablabla")
end```?
ah hold on
Exactly, so how the hell is this happening?
When my code says this:
for elementIndex = 0, 1 do
player:Say("You keep pushin' my buttons and see what happens . . ." .. elementIndex)
-- uiElements:get(elementIndex)
end
The answer is that it USED to say this (no loop)
player:Say("You keep pushin' my buttons and see what happens . . .")
nope, still errors out
if u want to change text of textentry then here should be this one not button
8 gb of my ram it's just a win 10 itself 
Omg I hate Windows so much
It will not take the screenshot at the right time
So it keeps coming out without the crucial info in the screen
Driving me insane that print screen hasn't worked right during games for years
Needing to do that when print screen exists infuriates me beyond measure but okay fine
wait what? I am confused.
self.modal["ICanEasilyUseThisPanelLater"] = self.modal?
self.modal["ICanEasilyUseThisPanelLater"] = self.textEntry
u need to save textentry panel to use it later
(on button press)
Omg I am taking screen after screen in ShareX and it is not taking the screen
Windows is too crap to properly screenshot itself
shouldn't it be self.modal["ICanEasilyUseThisPanelLater"] = self.modal.textEntry?
cause rn it's not working either
ah, yea
xp
Yeah ShareX clearly relies on Windows screenshot doing its job correctly
Which it's not
So unfortunately no help
Steam knows better
"That OS is trash, we've worked with it for years. We have other ways."
Anyway, if you refer to my screen and above code, you'll clearly see there is no line that would not post a number at the end of it in the current looping version of the function
But in the OLD version, with no loop, I had a version with no numbers, and that version is still printing
neither work apparently ๐คฆโโ๏ธ
Ahaaaaaaaaaaaa
I figured out why this is happening ๐
I think u made smth really wrong 
lemme upload whole code in a pastebin
I'm following Tyrir's style of overwriting functions by grabbing the old copy and calling the old copy from the new version
It's continuously absorbing MY new version as "the old copy"
Or, my old new version
Doh.
lmao
https://pastebin.com/iBdU3Va3
You're looking for the lines starting from 153
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
where even u creating textentry...
I see nothing
self.modal = ISTextBox:new(660, 250, 600, 500, "Character Background Story", self.getBackstory(), nil, self.buttonConfirm);
``` Creates the textbox when a button defined previously is clicked, if that's what you mean, otherwise I have no clue lool
my codes tend to be messy ngl xd
what're you confused with tho? If its anything I can clear up
Decorating/decorator is what that pattern is called. Smarter people came up with that (or probably more accurately it's just emerged as a pattern in software development). It's a lua-specific way of implementing that pattern
Made my first mod :D! https://steamcommunity.com/sharedfiles/filedetails/?id=2874678809
Thanks for the vocab lesson. Had not heard that term. Guessing you followed my issue and see where everything went wrong, since you're jumpin in. ๐
Nope. Just skimmed ๐
strange but first version should work
local parent = button.parent
parent:setText("blablabla")
it's not working as I remember, right?
yea it didn't
wtf 
It'd print parent as a table
but then it'd throw an exception at parent:setText("blablabla") that an object tried to be called at a nil or something along those lines
I'm don't make mods for pz for a long time ago but I think pz haven't exact "class" for panels so it's just a table
I'm not sure so it's just my mind
@hearty dew For you, good sir.
-- Format based on modding a joypad button press response.
local originalFunction = ClassInThisGame.FunctionInThisGame
function decorateFunction()
-- New code goes here.
end
function ClassInThisGame:FunctionInThisGame(original, input, to, this, function)
decorateFunction()
-- Original function likely needs self if it was called using a colon.
originalFunction(self, button)
end
Edit: Upon reflection, this could be improved further with something to prevent it from being repeatedly called when you decorate. Might require a second file for initializing a boolean variable that tells this program whether the original function is already decorated. Preventing double-calls during debug may be more trouble than it's worth. Depends on use case.
For the next newb like me who perhaps won't figure this one out on their own
Allows you to safely reload during debugging
after looking into a mod source code, he apparently changed the text of vanilla text boxes in that way:
function CharacterCreationHeader:onNRKButton()
SurvivorFactory.randomName(MainScreen.instance.desc)
self.forenameEntry:setText(MainScreen.instance.desc:getForename())
self.surnameEntry:setText(MainScreen.instance.desc:getSurname())
end```
anyone have ever did any tile related mod or moveables or traps or radio?
this is how forenameEntry is defined in vanilla
self.forenameEntry = ISTextEntryBox:new(MainScreen.instance.desc:getForename(), entryX, 64, 200, entryHgt);```
i cant seem to spawn tile no matter what i do and from time to time i attempt to do just this and always fail
yea it's saving self.forenameEntry to use it later
it's correct way
congrats man
I am trying to create an item that can push back and knockdown all zombies surrounding a player within a small radius. Is that possible? What item attributes would I be looking at modifying to make this happen?
This UI business is either going to fix this game entirely for me as a controller player or kill me.
Can't tell, hold for more info
Thanks ๐ Added in some screenshots due to request
OMG
OMG I DID IT
I can't even quit the game and I've never been so happy in my whole entire life
Proof of concept established
UI defeated
Errors, sure, we'll figure it out
?
@fast galleon I've been looking for a way to kill UI elements from a button press
That screenshot is a screen of the entire UI dead
Now I need to kill the right UI elements under the right conditions
press v?
Pressing v closes all UI elements or holding v hides them? I don't use v. I am trying to close them when I press a button on a gamepad. There is currently no way to do what I'm talking about to my knowledge.
Look, it's just me, I killed the UI window that lets you respawn, too!
It's Zombified: the Movie
Hello. Is it possible to somehow start the sound from the file for each player on the server?
@thick karma fun fact, I once mistakenly killed the whole UI by causing an issue in code. I had some kind of a typo that was related to inventory and the whole UI would get killed instantly
Including the start menu and such?
I could not even use start menu to exit game because my mod was 2 gud
Everything that was considered UI was killed if I'm not mistaken
Had to alt + f4 lol
working on ui i've managed to totally brick the game about a thousand times
Lmao
and i've barely done any ui lol
Yeah game routinely kicks me from my own server when I push updates to UI it seems
UI is a heartache to work with ngl
Happened to me just a bit ago when I was reproing that issue you had earlier :p
Headache*
the ui code is so weird
We would like to record cinematics in a server, however the fact your own character is always visible makes it very tedious to do
Is it possible to make your character model completely invisible for yourself et have a 360ยฐ infinite field of view?
If there is a mod that already exists or feasible?
Thank you a lot โค๏ธ
My goal is very modest and when I am done I am never touching UI again until next time
lool
Opened the game and there was only the background with the husband and wife and spiffo doll ๐
Damn I guess Burry could've used reproing that error earlier ๐
when they added that reload lua button i was like 'finally i can stop rebooting the game every five seconds' and then i found out that the ui breaks if the professions are messed up
... there's a reload lua button?
I hate myself for never noticing it
Thanks man. I started a new game with no mods except one and set it to Maintenance 5 and Long Blunt 5. Spawned in a bat and still get a value of 2.
I guess it's just something with 41.71. .๐คทโโ๏ธ
Does anyone have a clue on how to do that please? Willing to commission a modder for this ๐
If you go into Debug mode and hit F3, your character disappears.
Yeah. The shadow for the character is still there, though. ๐
oh crap
Not sure how to hide the UI, either.
i know a keybind for it, but maybe it doesn't work in debug mode
That's why I would love a spectator mod, that when you enable it, your model disappears with shadow and your field of view is 360ยฐ infinite
so you can really record cinematics
cause right now it's HORRIBLE to do
right now I need to move my character far away from the scene and pan the mouse to the zone I want to record, then I need to wait for the camera to be completely stable at my mouse position, and then I have my record
And afterwards I add the camera movement in editing
Yeah, a mod like that would be nice. The next best thing might be to find some videos of YTers who are creating a similar effect and hope one of them reads and responds.
what do you mean?
To ask a YTer who used cinematics in their video, similar to what you want, and hope they read+respond.. Sorry, forgot to include the "ask" part.
ahhh okay
but most of the time what they do is integrate their character in the cinematic
but then the cinematic is always centered around the character
I will be making similar and other Zomboid videos in the future so feel free to subscribe!
Please feel welcome to join my little discord community here to keep up to date, and have a chat with other Zomboid enthusiasts!: https://discord.gg/FTPcfMTFWv
The server I recorded about half of this on is called ''Death's Door RP''
They're a great com...
like this for example
which is a very beautiful video
@thick karma was working on a mod to hide the UI. No idea about the character though
My best guess to hide the character would be removing its textures so the mesh won't appear in game
Not tested though so can't tell for sure
there's already a mod to hide ui, burryaga's thing was slightly different
no idea about hiding the player though
but isn't UI hiding already in vanilla?
I can already hide the full UI by pressing a key
The one I had in mind is where they pan the camera and the character is not in sight, but I'm not 100% sure if they were able to remove the character or just clipped the video to where they were already out of the view.
yeah not bad idea, and delete the shadow hoping it won't hide all models shadows
If you pan the camera very far away from your character and you are zoomed enough, you can't see your character anymore, but it's very tedious
Is there an elegant way to append additional components as being acceptable ingredients to a given recipe without overwriting the recipe entirely? Is there a way to do it additively? E.g. trying to account for multiple mods that have viable ingredients which may or may not be in a given player's mod setup so that any / all that -are- present will be appropriately included.
๐ so many people think I am trying to write a mod to perform the v-key function
getScriptManager():getRecipe():DoSource()
My actual goal if you're curious is to close all popup UI elements with a single button press, which to me includes the chat box, the server message box, the inventory screen, and basically anything else that cannot be closed immediately when a player needs to get away
oh okay!
hold V
:P
just make that function on a keypress
done

it doesn't? i thought it did
huh
i disabled the hotkey ages ago due to accidental use
guess my memory fails me
well easy enough to also tap into the inventory and any X buttons, etc.
But yeah I may ultimately settle for the lesser but still useful goal of autoclosing inventory when I aim my weapon
That I have already figured out
that does sound useful
Esp on controller where Back does not close Inventory
i'd use that more readily than the other function
Because someone special was on UI that week
though a screenshot mode with UI yeeted would be nice
maybe even with player name(s) hidden
should u care to continue down the road of hiding UI elements
i made a composite image of clearing muldraugh on my server, the piles of bodies, but i had to crop to the center bit of the screen due to ui being in the way
Can share later if anyone wants it
could be a much wider nicer composite
if the UI had been toggleable fully and easily
But they do not actually cease to exist so they retain focus esp gamepad focus
(i'd forgotten about V lol)
I can probably make a mod for that
When I get home I'll try
it would see use - people love screenshots
@austere finch don't think you saw this
Strange. When I use the HideUI keybind option everything gets hidden except character names (and one mod's UI element that reappears after it does an update).
Hi, I'm starting my foray into the modding world of PZ. I was wondering where can I find detailed lua api documents or is it only https://zomboid-javadoc.com/ ?
Also, how can I remove a recipe from the vanilla? I've done overwriting script with recipe block with Learn value but I wanted to remove the recipe entirely. I don't think it's ideal to overwrite the original script files (in steam/projectzomboid/media)?
that was my recollection as well
decompile game
see the pins
you essentially can't
you can use "Obsolete:true," but it seems iffy and does not always remove things
and certainly doesnt work to do more than one reciep with the same name
i made a thing to perform a hackish removal
using the learn thing and hidden and scanning through all books and removing it from book lists
pain in teh butt
yeah.
planning to release said script
as a standalone dep mod
so only one looping through every recipe and book needs to happen
that would be awesome.
trying to do a total conversion mod
and i'm trying to avoid requiring to edit base game files
no i know
u can override things they contain
right
i'm trying to avoid having people needing to edit the base game files to achieve what i wanted if they wanted to run the mod
in ur particular case, as a TC
you could just override the files instead of the recipes
by matching the path/filename
with ur edited copies
usually not advisable but the scope here

Hello, Im having trouble getting my mods to work on a multi player server, have any advice?
question is too vague
well when I make the server I put in all the mods I intend to play with, the some ones I use in single player, but when I start them up it doesn't seem to have applied them. in particular those which give more options for character creation.
Local or dedicated server?
local,
Is it possible to modify how many zombies are required to perform an insta-kill drag-down on the player?
I think I might have found the problem, there is a steam workshop page as well as a modding 1, I filled the modding, but not the workshop, ill see if that changes anyrhing.
u mean in the ini file? yeah it wont download the mods if u dont put anything in the workshop thing
im beginning to think u dont mean "my mods"
and u mean "the mods i installed"
in which case u might wanna be in #mod_support
you probably need to have those mods activated also in the main menu not just the server settings for the hosted server.
int n8 = 3;
if (SandboxOptions.instance.Lore.Strength.getValue() == 1) {
n8 = 2;
}
if (SandboxOptions.instance.Lore.Strength.getValue() == 3) {
n8 = 6;
}
Looks like it's hard coded in java to those values based on zombie strength
Anyone knows where are the structures scripts located?
If I'm reading that correctly it takes 3 zombies to drag you down on default strength and 2 on higher strength?
what do you mean by structures? if you mean stuff in the world, they don't have scripts, as they are defined by their tiles
And playerbuild structures?
yeah they are tiles
Interesting, know the path?
can't quite remember. its a file with the file type ".tiles"
Yea, among a few other conditions```java
int n7 = this.getParentChar().getSurroundingAttackingZombies();
n7 = Math.max(n7, 1);
n4 -= (n7 - 1) * 10;
n5 -= (n7 - 1) * 30;
n6 -= (n7 - 1) * 15;
int n8 = 3;
if (SandboxOptions.instance.Lore.Strength.getValue() == 1) {
n8 = 2;
}
if (SandboxOptions.instance.Lore.Strength.getValue() == 3) {
n8 = 6;
}
if (this.ParentChar.Traits.ThickSkinned.isSet()) {
n4 = (int)((double)n4 * 1.3);
}
if (this.ParentChar.Traits.ThinSkinned.isSet()) {
n4 = (int)((double)n4 / 1.3);
}
if (!"EndDeath".equals(this.getParentChar().getHitReaction())) {
if (!this.getParentChar().isGodMod() && n7 >= n8 && SandboxOptions.instance.Lore.ZombiesDragDown.getValue() && !this.getParentChar().isSitOnGround()) {
n5 = 0;
n6 = 0;
n4 = 0;
this.getParentChar().setHitReaction("EndDeath");
this.getParentChar().setDeathDragDown(true);
} else {
this.getParentChar().setHitReaction(string);
}
}
Might can do something tricky by having a mod call `setDeathDragDown` (and `setHitReaction`?) on the player object based on different conditions though
Hmmm. Another rabbit hole with PZ. Armor values are ultimately sort of meaningless if the dragdown is the result of concurrent bites landing but zombies can still 'stunlock' a player and effectively just keep rolling attempts until they score the necessary hits.
Yeah, odd, after you said this I retested. When playing in gamepad mode with -debug (very possibly relevant), V only hid my gamepad controller icons... Not the debug console, nor the minimap, nor my inventory... If it has a different behavior in other modes I wouldn't know.
V toggled hide icons, and hold d-pad left (iirc) held hide icons, but nothing hid everything that potentially clutters the screen when you're about to be bitten
On debug and non-debug while only using Keyboard controls, it hid everything for me (aside from the previously mentioned exceptions).
So probably just more lackluster controller support.
Understood. Maybe joypad presence highly relevant. Maybe a mod issue. I'll explore further
Appreciate feedback
Hello modders, I was looking through the BodyPart class a way to check whether or not the body part has a laceration. But, I couldn't find a way. I see methods like scratched() or bleeding(), or even deepwound(), but nothing about lacerations. Do you have any idea how to check this?
Yeah thanks, just realised right now ๐
VehicleTweaker uses VehicleScript:load(scriptname, addendum) to add or change something about the vehicle script loaded into memory. Is it possible to revert those changes ๐ค
o.maxTime = -1;in TimedAction alway show the progressBar, this should not be like that?
recent post by the devs mentioned something about changing progress bars to better represent things that don't have a defined end, I bet its related
@ruby urchin
Added a looping progress bar for timed actions that have no defined end. This is mainly a stopgap "fix" for entering cars, to visualize that there is an ongoing unfinished action until we can have visually open doors, etc.
Specifically added for the scenarios where players reported being bitten through the car door after they had entered a car and interrupted the "enter car" action before it could finish (e.g. by opening the map, etc), i.e. before the door was "closed".
This bar extends to other "infinite" actions like Walk To.
read from last changelist
Ohh I see, well, that's why some things have changed, honestly don't know if it was for the better, so far I found 2 issues:
- No matter the target character, always progressBar shows to local player.
o.maxTime = -1alway show progressbar (useProgressBar,forceProgressBarandsetUseProgressBarare ignored), but ifo.maxTime ~= -1progressBar is gone.
ah ya, you were mentioning the first point earlier
I bet they test everything singleplayer first, haha
I am trying to create an item that can push back and knockdown all zombies surrounding a player within a small radius. Is that possible? What item attributes would I be looking at modifying to make this happen?
๐ค๐ค๐ค๐ค๐ค๐ค๐ค๐ค๐ค๐๐๐
Everyone needs to praise mlem
hey guys I am trying to add bedford to my server but I kept getting this error
but the file do exist in my file so I don't know why it kept showing me this error
much appreciate for any help
this channel is for mod devs, fam. You want #mod_support
@sour island
- Fixed Walking and sprinting not burning more calories than standing still.
in the 41.78 preview notes
make sure u get eyes on that and update ur calorie mod
as appropriate
I could not for the life of me eat enough to avoid losing 15 weight in a month using that rebalanced calorie mod
When I get home today Iโm gonna start working on my first Java mod for pz
Any suggestions?
Can anyone help me figure out why I get an error when I run a third if in the ISTimedAction:perform()?
I tried putting it as a separate if below the second and it doesnt work either
It seems to be a simple if condition check for inventory items which works with isHaveVirus but for some reason same function for a different item doesn't work.. anyone any ideas?
So this doesn't work either
What do you mean by that function name ๐คจ๐คจ
I assume it's about the zombie virus
Ok buddy
I sent that message for you to see what line 54 is (EDITED)
simple inventory check for said item
It confuses me since it works with the one that checks for virus in a syringe but for this one it doesn't
these two work fine in perform()
the cotton one works fine in all other parts of the code-- just in TImedAction it gets this Stack Error
If itโs a timed action could it be trying to perform the check when the local player isnโt initialized yet?
Initialized?
Do timed actions only happen while you are in world?
Or do they also happen while in the main menu
If they did the player wouldnโt be initialized yet
Only in world when I trigger it using context menu
So you are calling nothing
Ah my bad
Maybe a scoping issue since the function causing problems is the only one of those that is defined as local? Does it work if you remove the 'local' off HaveCotton?
The log file would probably give a more detailed reason on why there is an error.
log file being a console.txt right?
scoping issue seems likely, but also you are passing true into that function in the first picture, but the function has no arguments?
C:\Users\[user]\Zomboid\Logs\[timestamp]_DebugLog.txt
does this help?
Yeah, scoping issue it looks. The code doesn't know what function you are trying to call there.
Alright-- now you confused me with scoping issue.. I'm still an amateur, so I don't know what you are talking about..
arguments were always confusing me when using functions.. never knew what to put in the brackets
How do I show it which one?
those functions have no inputs, so you put nothing in the brackets
scoping is when you restrict what code can call what other code. You marked your cotton function as local, which means it can only be accessed by other code in the same context
But how do I say if that function ends up being true-- it does something.
It seemed to have worked for the FIL_isPlayerHaveVirus(true) then
It does that by the 'return' statment
in lua, if the function returns anything besides false or nil, its considered true
your functions are returning the item, so its true
if the item doesn't exist, they would return nil which is false
I'm not able to see any changes yet
So what you are saying is all it takes for me to do is turn the has_cotton into public variable instead of a local one
And then change if FIL_isPlayerHaveCotton(true) then into if FIL_isPlayerHaveCotton() then?
looks like it works regardless of you putting extra arguments in, because it just ignores them. I'd remove the trues anyway, cuz they shouldn't be there. Otherwise, yes, remove the local keyword from in front of your cotton function
I'll try that and inform you about the results, thank you
ah maybe it's not actually in the unstable then, false alarm, but soon i suppose
unstable seems to be 41.77.7
Ah yikes-- mmm-- that hurts. We were talking about local function and not the has_cotton variable.
Oh my-- sometimes it takes me hours upon hours of looking through the code and I don't see such a simple mistake ... oh it was so obvious.
I guess I lack experience-- uhh
@astral dune @vast nacelle Thank you so much for the help
You are amazing โค๏ธ
local functions need to be defined above where they're called in the code
one other thing, which isn't important in what you're currently doing but will come up later when performance is important:
you're calling self.surgeon:getInventory() a bunch of times in your perform function, its good practice to do something like local Inventory = self.surgeon:getInventory() early on in the function and then just do your Inventory:Remove() and Inventory:AddItem() like that
I am a little confused about the scope of local functions myself. Is it the file its in?
yeah
even vanilla does this a ludicrous amount
it drives me crazy
it made me wonder if it doesnt matter in lua
cuz how could ppl do this so much
mods and vanilla alike
it's the file if it's not in another scope
scopes are defined with do/end
rarely will u see scopes explicitly defined tho
i assume if u define a local function (strangely) within a function or for loop it would also be local to that inner scope
how would i get the player?
i'm doing a java mod but i assume it would be relatively close
or is there a universal method to be able to access all the stuff i need
like how minecraft has Minecraft.getMinecraft()
and that is where the data for everything is stored
there are some weird things about lua. Like String comparisons are essentially free, since all Strings with the same content are the same string!? truly bizarre
In Java there seems to be a method called getPlayers() within a GameServer object that lets you get an ArrayList<IsoPlayer> which is what you probably need. No idea how Storm wants you to access said GameServer object.
declaration: package: zombie.network, class: GameServer
dude ty so much
there is just so little documentation on it
so it is hard to find anything
We loop through an array using a global LUA function you would not have.
Called getSpecificPlayer
you can do that ez
We don't even import it or anything
declaration: package: zombie.Lua, class: LuaManager, class: GlobalObject
The search tool on that link is very well made
Not sure you want the LuaManager version
I believe this also works but only in Single Player if I'm not mistaken
declaration: package: zombie.Lua, class: LuaManager, class: GlobalObject
hey
hi
prob
there is usually work arounds to that kind of thing
i do really need that lol
you should use this version instead https://zomboid-javadoc.com/41.65/
Javadoc Project Zomboid Modding API package index
holy jesus im fucking dumb
the one you linked is from build 2 or something lol
I was thinking that textures should have 32x32 colour on the models
it was the png that needs to be 32x32
@thick karma ty i think i am getting closer but i feel like there is a better way to do this
how would you specificy in Lua which player is THE player
like the user playing the game rn
Is there a mod that adds wandering hordes of zombies?
I've seen a few zombie horde mods, but they're less "wandering" and more "know where you live" hordes. #mod_support may have a better idea of what you're looking for. Messing with the normal vanilla settings can get you close, just by upping the frequency of meta events and the spawn rate
Ok thanks
Lol isn't my link from the devs' website?
projectzomboid.com/modding isn't the best place to look? Why am I America?
yeah the one on the official website is super old
I believe it's usually player index 0 but we use a process that generally targets the players local to an instance of the game afaik, so we use a tiny loop that doesn't assume player's index is 0
wow
We use getNumActivePlayers() to end the loop, which causes us to do index 0 if only 1 active player
is there is a way to get to the getPlayer function in java
like which class it would be in
ik it is in the global class in lua
Again that would probably be Storm-specific and I have not learned Storm
Something in the API can probably talk to the player
I just don't know
public class Mod implements ZomboidMod {
@Override
public void registerEventHandlers() {
StormEventDispatcher.registerEventHandler(this);
}
@SubscribeEvent
public void handleGameStartEvent(OnGameStartEvent gameStartEvent) {
IsoPlayer player = LuaManager.GlobalObject.getPlayer();
}
}```
i would imagine this doesn't work but i will give it a try later
There can be multiple local players (possibly 4 split screen players). You have to get the appropriate player through some context. There isn't a method that just knows which player you need without context
what does the getPlayer return then?
Lots of mods use getSpecificPlayer(0) (from the GlobalObject), which returns the first player, but said mods don't work correctly in split screen
hm
are you a dev by any chance?
or have some knowledge of the way the java code works in game
I'm not an indie store dev, if that's what you mean, no
ah
only looked through it on occasion
oh wait
IsoPlayer.getInstance();
is what getPlayer returns
:/
it seems like everything is done through instances
IsoWorld.instance
IsoPlayer.getInstance
yuh it also has a hasInstance
so ig a check if you are in a game or not
As I recall when looking at that and testing it, it just returns the first player on the local client
so you?
yep
unless you are in split
Not if you are the second player to join split screen, nope
Then that's sufficient for your requirements
ty very much
do you by any chance know how to make a new weapon?
like
instead of using lua scripts
you do it in hava
java
Just be aware that the people who review your mod will not care about your average score if you fail to warn them that it's only for singleplayer, singlescreen multiplayer, or whatever. If it's not full-game compatible, warning people will probably get more people to take interest in your mod.
Not specifically. I'd look at what ItemPickerJava class does when parsing items and/or the Item class (probably will have to create a new instance) and/or ScriptManager
idc
before ending up here
i spent the past 2 years making utility mods for anarchy mc
but the community is finally kinda dead
and i don't wanna give any more of my life to it
started when i was like 13/14
now i'm 17 almost 18
so i quit like a month ago
When you do local function foo()..end, foo is just a variable the same as if you had done local foo = 5. It is equivalent to local foo; foo = function()..end. The difference is that the value of that variable is a function rather than a number
local function a()
local function b()
end
local c = 5
-- stuff
end
you can tell what a local variable's scope is easily when its within a function, but outside that its not as obvious to the uninitiated
There, b and c have the same scope local to the chunk defined by the function body of a.
a has a scope local to the chunk defined by the file it is contained in.
Lua basically compiles a file into a chunk (just as it does a function body) and runs that chunk. That's why you can do return foo in a file context and you can get that return value e.g. local the_thing_returned_by_the_file = require('the_file')
Long way of saying the scope is the file ๐
lol
so for example, VehicleCommands.lua contains local functions, the only way I've found to get access to them is to put return VehicleCommands at the end of it, and then requireing it later. But I'm not requireing the file, but the table defined in the file. Could I just require the file and not have to overwrite it with the return?
waitwait
@hearty dew
could you also use the IsoPlayer in ItemPickerJava to get the player?
public final class ItemPickerJava {
private static IsoPlayer player;```
i had a real weird bit of code i inherited where it was like.. local functionName do --[[things]] function functionName() --[[more things]] end end
took me a bit to understand wtf was going on
you can overwrite the file and redefine them then use them as u please but then u break compat :p
that kind of shit really depends on use case, often it's best to reimplement or etc
If that file is declaring local functions within it and not returning an object that you can use to get access to those objects via require, then you have to do tricky things to get access to the objects stored in local variables within that file
can't be reimplemented as I need access to those specific commands, lol
lol, no it would have to be those commands, since its local I can't overwrite them
ya
then copy the file to ur mod in the exact same path
Idk what instance of IsoPlayer that field contains. The pattern the rest of their java code uses is to use the static instance of IsoPlayer (this is for client-side code, btw)
breaks compat, lol
what will it break compat with
ยฏ_(ใ)_/ยฏ
if two ppl overwrite the file sure it'll break compat between those two
but that's inevitable at that point and a patch can be made if needed
this is why TIS shouldnt use locals in a moddable game
or why we need a java hook
ya,, its pretty weird how they implemented VehicleCommands, but its not the only place like that
I was able to bypass needing it for a bit, but now I absolutely need to overwrite it
was just hoping there were some shenanigans I could use to continue to avoid it
wait what is the difference between IsoPlayer and IsoGameCharacter
oh also @hearty dew i think i know how you would discern between the 4 different screens
in split screen
public final class IsoPlayer extends IsoLivingCharacter implements IHumanVisual {
private String attackType;
public static String DEATH_MUSIC_NAME = "PlayerDied";
private boolean allowSprint;
private boolean allowRun;
public static boolean isTestAIMode = false;
public static final boolean NoSound = false;
private static final float TIME_RIGHT_PRESSED_SECONDS = 0.15F;
public static int assumedPlayer = 0;
public static int numPlayers = 1;
public static final short MAX = 4;
public static final IsoPlayer[] players = new IsoPlayer[4];```
look at that last value
pretty sure it makes that to be all players currently playing
I haven't tried this, but you might could try using setfenv (if kahlua implements this function) to get a foothold into the objects you need inside the file
looking for docs on that function now
why do you need the commands?
i can't think of anything you would need them for unless you need to completely overwrite something they do
the java fires VehicleCommands.damageWindow() when a zombie damages a car window. I want to intercept that.
Mm, that still doesn't answer your original question of how to get the appropriate character. You need some context to know which of the 4 to get. In GameClient, there is some method to get the local players if all you need is to iterate over the 4 players. Can't recall its name atm
the java fires it? that's weird
i would imagine it goes top left 1 top right 2 bottom left 3 bottom right 4
but i would have to test
If I recall LuaScriptManager.GlobalObject.getSpecificPlayer() uses that api, so can look there
ya, its pretty weird, it does the same thing for VehicleCommands.crash when you hit a tree or wall or whatever
damage is handled lua-side
in those instances
how is the java calling it if it's local?
so just hook into those commands?
the commands are also local
I can listen for the commands, but I want to alter how they work
haha, ya, but like Evelyn was saying, breaking compat will likely be fairly rare, especially since I'm only exposing the commands rather than changing the file in a more serious way
I want to see a mod that recreates the entire maps from Fallout 1-2
@astral dune This might not be enough for your requirements, but because VehicleCommands.lua calls Events.OnClientCommands.Add(), you could patch that function in order to get the function object stored locally in VehicleCommands.OnClientCommand. Could then use that to decorate the other functions indirectly (doing something before/after the commands are called by VehicleCommands.OnClientCommand)
๐ค
Oh, you might not be able to because of the order pz loads the files. It loads the vanilla server/ files alphabetically before loading the mods' server/ files alphabetically. Hrm.. Might can control when VehicleCommands.lua is loaded with a require("VehicleCommands") in a shared/ file. Idk if pz lets you require files from server/ inside a shared/ file though, never tested that specifically
If require allows you to do that, this should work, but I'm not exactly sure what your requirements are
Is being able to run your own code before/after those vehicle commands sufficient?
Or do you need to be able to call those functions in Commands?
Or do you need to modify something inside those command functions i.e. change their implementation?
depends, can I alter the args of the command that the other code will see?
yea
if require of this file (it is in server/) works from a shared/ mod file
I'll go try it real quick. sec
LOG : Lua , 1665707400054> Loading: C:/Users/Tyrir/Zomboid/mods/miscpatches/media/lua/shared/!_!miscpatches_utils.lua
WARN : Lua , 1665707400060> LuaManager$GlobalObject.require> require("Vehicles/VehicleCommands") failed```
:/
There's probably another way to intercept the events and change the parameters if that's all you need...
You said these events are raised from java or lua?
java
yeah you should look into grabbing the function from the event
require('VehicleCommands') doesn't do anything because vanilla already loads before all mods
I was trying to load from a file in shared/ which loads before server/ files (including vanilla)
Also, if it had been already loaded, it wouldn't give that error
Lua files are loaded in this order:
shared/ vanilla files alphabetically
shared/ mod files alphabetically
client/ vanilla files alphabetically (skipped for server processes)
client/ mod files alphabetically (skipped for server processes)
server/ vanilla files alphabetically
server/ mod files alphabetically
it makes absolute sense for it to do that but i always had 'vanilla always goes first' in my head
yea, modded shared/ loads 2nd in that list. Vanilla server/ is 5th
could you add to the metatable for Event.Add to save the function into a variable...?
yea, that's the idea
I wanted to be able to made the change to Add to intercept calls, then require VehicleCommands.lua, then remove it after VehicleCommands.lua had loaded (manually using require). That way it would limit messing up other calls to Add
Can still take the same approach of intercepting calls to Add, but might catch other files that call it and muck with the event handlers they add
May or may not be an issue
yeah i can't think of a way to identify a function right now
Only way I know of it via lua's stdlib debug apis, but kahlua doesn't implement them
@astral dune ```lua
local og = Events.OnClientCommand.Add
Events.OnClientCommand.Add = function(fn)
print("DEBUG: Events.OnClientCommand.Add called")
return og(function(module, command, player, args)
print(string.format("DEBUG: OnClientCommand(%s, %s, %s, %s)",
tostring(module), tostring(command), tostring(player), tostring(args)))
return fn(module, command, player, args)
end)
end
Something like that should work in `media/lua/shared/~~mymodid_intercept_OnClientCommand.lua`. The `~~` to load it as the last shared file to try to minimize affecting other mods.
I worry slightly it may cause more conflicts than solve compared to making your own media/lua/server/Vehicles/VehicleCommands.lua ๐
If a mod has something like ```lua
Events.OnClientCommand.Add(myfn)
Events.OnClientCommand.Remove(myfn)
it will break
The call to remove will have no effect because their function object is no longer registered (your wrapper function is)
This looks promising, I'll take a closer look on the next raid wipe, lol
Actually, you could patch Remove too to fix this
You would need to keep a table mapping their function object to your function object that wraps theirs. Then remove your associated wrapper function on a call to Remove
AnonymousUtils = AnonymousUtils or {}
AnonymousUtils.RegisteredEventHandlers = AnonymousUtils.RegisteredEventHandlers or {}
--[[
Usage example:
AnonymousUtils.interceptEventHandlerRegistration("OnClientCommand", function(originalEventHandler, module, command, player, args)
if module == "vehicle" and command == "attachTrailer" then
-- Change stuff in args
end
local result = originalEventHandler(module, command, player, args)
-- post-stuff
return result
end)
]]
AnonymousUtils.interceptEventHandlerRegistration = function(eventName, eventHandlerDecorator)
if not Events[eventName] then
error("AnonymousUtils.interceptEventHandlerRegistration: Unknown event name: "..tostring(eventName))
end
local originalAdd = Events[eventName].Add
Events[eventName].Add = function(eventHandler)
if isDebugEnabled() then
print(string.format("AnonymousUtils.interceptEventHandlerRegistration: Events.%s.Add(%s) called", eventName, tostring(eventHandler)))
end
local newEventHandler = function(...)
if isDebugEnabled() then
print(string.format("DEBUG: Decorated handler for Events.%s called", eventName))
end
return eventHandlerDecorator(eventHandler, ...)
end
local result = originalAdd(newEventHandler)
AnonymousUtils.RegisteredEventHandlers[eventName] = AnonymousUtils.RegisteredEventHandlers[eventName] or {}
AnonymousUtils.RegisteredEventHandlers[eventName][eventHandler] = newEventHandler
return result
end
local originalRemove = Events[eventName].Remove
Events[eventName].Remove = function(eventHandler)
if isDebugEnabled() then
print(string.format("AnonymousUtils.interceptEventHandlerRegistration: Events.%s.Remove(%s) called", eventName, tostring(eventHandler)))
end
if AnonymousUtils.RegisteredEventHandlers[eventName] and AnonymousUtils.RegisteredEventHandlers[eventName][eventHandler] then
local newEventHandler = AnonymousUtils.RegisteredEventHandlers[eventName][eventHandler]
AnonymousUtils.RegisteredEventHandlers[eventName][eventHandler] = nil
return originalRemove(newEventHandler)
else
-- Could be an event registered before we began intercepting
return originalRemove(eventHandler)
end
end
end
This seems to work on a quick test. I didn't test it with vehicles specifically
Hrm, might be unclear from the name, but have to call it before the event handlers of interest are Added. Maybe a different name would be more appropriate ๐ค
LOG : General , 1665712452224> 1,125,560,337> unknown option "-debug"```
How do you put the dedicated server into debug mode?
is it my eyes or are you still editing that code Tyrir? It seems to shift on occasion, lol
Yep. Forgot to initialize AnonymousUtils, left some stuff commented out, left in the namespace I use and wanted to change it to AnonymousUtils so it doesn't overwrite my namespace if someone puts it in their mod :p
Renamed some things bc I thought it'd be clearer :)
gotta do my daily but after that I'm gonna have some questions lol
you can do that?
i dont think u do that
u just join with a debug client
debug is entirely clientside and only gated to admin access.. from the client
"i can't do that im not an admin lol"
it's kinda awful security, ppl can use a javamodded client to just.. join servers with debug on..
:/
i hope it's got some checks on the other end at this point
friend tells me it dont
at that point u can execute random code
Iirc the dedicated server end does do auth checks
ah good
But it doesn't do client checks I dont think
Just user auth
I could be wrong though
this is a very "just play with friends" game
I want my debug statements server-side though! ๐ญ ```lua
if isDebugEnabled() print("DEBUG") end
Will have to use my verbose log flag in my util library, I suppose

if isTyrirDebugEnabled() print("DEBUG" end
function isTyrirDebugEnabled() return SandboxVars.TyrirToybox.MySpecialDebugUwU end
They do lua checksums but not java class file checksums? 
my friend tells me this but they last did this a long time ago
they affirmed it was still not fixed after diggin thru the code but idk
and yeah..
u can change it in memory tho
so
doesn't matter, still have to have some deeper auth going on for sec
that's why they've so heavily recommended to stick to pve with friends
mhm
and that's why some of the larger servers java mod the server to add extra security measures xD
okay, its a little bit late in the evening for me to grok this easily. If I follow, this function will sneak in and replace the Add and Remove functions for a target event. The new Add makes any handler added to that event get wrapped with my own handler, that has an extra input of the wrapped handler so I can call it after I'm done messing with the data, if I choose. ... is that right?
How do I make sure I get this to fire at the right time? Is this still me putting it in /shared with a __ prefix on the filename?
put it in shared and it'll run before vehiclecommands
yep
right, shared is always loaded before client, before server
Yea
so I can give it a normal file name, but giving it __ means it will interfere with a minimum amount of other mods?
or does __ come first, how does alphabetically work in this scenario
~ comes last. So it would load after all other shared/ mod files
Could also have a server/!mymod_unregisterAdd.lua that calls require("Vehicles/VehicleCommands") and reverts the Add function, but that code doesn't have a way to revert it atm
That way any Add calls that come later by mod files doesn't get intercepted
does require force it to load that file then, or force mine to wait until after its loaded to continue? I'm not really clear on how require works
But with the way that that code modifies Remove, I wouldn't expect any issues. From the pov of the other mods, Add and Remove should function normally
forces it to load then
I probably wouldn't even mess with the ~ or ! in filenames or require since Remove is also modified to function as expected by other mods
I have a strong compulsive urge to optimize performance at all opportunities, so I'm tempted to try to make it as surgical as possible, but ya adding a single check per command call probably wouldn't be noticeable
You wouldn't see any noticeable difference just checking a few strings.. Wouldn't even in something called every frame like OnTick
well you definitely earn your little spiffo beside your name. I've seen you post full out code like this for many people, and now for me. I appreciate it. Plus this approach could absolutely be used elsewhere
The spiffo is just from discord nitro boosting I think :p
could be, although I've gone from plant to something else to axe just from posting
so, how much do you now about creating custom UIs? ๐
Know it looked like a pain in the butt from looking at the Mod Manager code :p
haha, ya. Things like it and the lockpicking minigame in Better Lockpicking tell me what I want to do is possible, but if UI's in other games and even WPF stuff at work have taught me anything, its that UIs suck, all day every day
WPF stuff is quite a bit nicer since the view can be changed much easier than here. It's all code here, so you're tweaking elements pixel by pixel in code sometimes to line things up :p
You don't have a framework to separate your view and model. Have to do it yourself (or not)
Well, the ui I need to implement is very similar to the mechanics one, so hopefully I can lean heavily on ctrl-c ctrl-v to get it flanged up. The only slightly fancier thing I want to do is have some "parts" hidden/greyed out until you meet certain conditions
If it's one big window, hopefully it won't be too difficult. Plenty of examples of that, as you say
Tricky part would be any unusual things, like a lockpicking minigame or similar, which wouldn't have examples to go off oof
๐ค
hello, i'm trying to find the right action to log generator movement, can anyone put me in the right direction?
taking generators from the ground already works, but i'd like to log inventory movement and drops on the floor.
already experimented with ISDropItemAction.perform & ISDropWorldItemAction.perform but they don't seem to respond
@midnight mica
ProjectZomboid/media/lua/client/ISUI/ISInventoryPaneContextMenu.lua: context:addOption(getText("ContextMenu_GeneratorTake"), playerObj, ISInventoryPaneContextMenu.equipHeavyItem, generator);```
ProjectZomboid/media/lua/client/TimedActions/ISTakeGenerator.lua:function ISTakeGenerator:perform()```
Might look at those
thanks, i'll have a look
how does one load a square/chunk/cell without having a player there
there's tons of functions for doing these things but they don't seem to.. actually let things happen
Is there anyone here who can help a fella make a few professions for a mod?
IsoCell.getInstance():getChunkMap(playerNum):LoadChunkForLater(a,b,c,d)
Something like that maybe to load it in the client in multiplayer. Didn't try it. Just guessing from looking at the java, but those appear to be exposed to lua by the Exposer class.
The playerNum is the number, 0-3, for which of the 4 local players chunk map you want (each has their own). a,b,c,d are chunk coordinates. No idea how this coordinate system works yet. gl with that lol
Looks like that adds jobs to send server chunk requests too
That should return the chunk if it is loaded, or nil if the parameters are invalid
or LoadChunk(a,b,c,d). This one doesn't have a code path which appears to delay the server request..? Would try this one first (this one always returns nil, however)
gawd damn lua
starting indexes at 1
made for literal children
"junior engineers" ๐ค
with the help of mlem i am gonna be making a repo on my github related to solely making java mods for pz
"The Unofficial But Only Guide To Project Zomboid Java Modding"
if theres an item thats not vanilla i think you should put the module name
or you might want to import Base
on the error its saying it cant find glowstick
try to check the item and place the module as prefix
sample
Result:Base.GlowStick,
You are using "=" and ":". Is it not only "="? like
Category = Electrical,
@weak sierra Wanna test this with me sometime for MP use?
That hide-all UI mod is ready
Anyone know how to manually fire a keypress event from the Lua?
Normal keyboard press
Alright-- sorry for the long code-- but I need help figuring out why it doesn't send the right value of the variable and spawns the wrong item in
Any help is appreciated
This whole code is very confusing to me, the code that sends the functions to the other client. So there is no way for me to figure out the problem
Only idea I have is to change it from a variable (FIL_SendisPlayerHaveSyringe) to a function with arguments and then send it.. but idk much about use of arguments and if that would work
Without some lua api exposed from the java side, that'd be hard to do since key/mouse events come from the operating system.. If it is sufficient for the keyboard event to be surfaced only on the lua side, you could try triggerEvent to simply raise the lua event.
That'd be kind of fun though if there were a simple way to do that. Could write a bot within a lua mod ๐
@hearty dew Fair. I know UIManager is accessible because I use it to kill the UI, so I figured I'd try manually triggering UIManager:onKeyPress and sending it the key
Probably won't work but I'll lyk
Just calling functions within lua would work. I thought you meant sending a key event to the java side (as if it came from the OS)
I think perhaps you are trying to set FIL_SendisPlayerHaveSyringe in the client process and expecting it to be changed in the server process when the server runs the command?
That won't work. You need to plumb it through as an argument to the command
Where is your OnClientCommand event handler?
Could this example work-- this developer sets variable in the IsTimedAction:findArgs() and then does this local surgeonFact, useBandage, bandageAlcool, usePainkiller, painkillerCount = self:findArgs(); after which he just sends the whole function with all the args
Huh? Me being an amateur surely gives all of the pros here headaches when I come here asking questions while not understanding some more basic things xD
OnClientCommand event handler? .. lelt me take a look but I'm not sure what you are referring to
I have this in the code
and this
You are calling sendClientCommand. What that does is raise a OnClientCommand event on the server side
okay
addition to this -- is something like this going to solve the variables not reaching the server and then other client?
Is the syringe item with blood supposed to appear on the client that performs that action? Or the player on the client it is performed on?
I need to find the correct Lua function... it didn't like that one
Do you know the Lua function for triggering a keyboard key event?
You mentioned triggerEvent or something? How does that work?
Well for now it is supposed to appear on the one the action is being performed on (patient)
But it is only the case because I couldn't figure out a way to send back the ModData from the patient to the surgeon after all the actions are done
Noper. You could raise an event with triggerEvent, but that only raises events for clients who have registered an event handler via that Events.OnKeyPress.Add api
I know that I can send functions through ISTimedAction.. but patient isnt performing any so Idk how to make him send something back to the surgeon. So I'm still sticking with the simple but dumber way where it spawns the syringes on the patient
Okay, just wanted to make sure bc it seemed odd conceptually for a dr to take my blood sample and a syringe with my blood appear in my backpack ๐
Ik-- but I'm not that smart to figure that part out yet, I can't even figure this one out and it is supposed to be simpler xD
(EDITED) the issues is I need to spawn the syringe with specific ModData.. and idk how to transfer that back to the doctor and spawn the right blood in the syringe.. so I just make ModData on patient and spawn the syringe there without much complications
Hmmm so can I trigger my local OnKeyPress event by using triggerEvent? But I cannot trigger the default behavior that occurs when that key is pressed?
I wonder if I even need to send a keyboard signal... maybe the way the code is written, sending a Y-button signal artificially will work even without a keyboard connected...
(Y-button signal already working)
JoypadControllerData:onPressButton(Joypad.ButtonY)
SendTakeBloodSample(self.patient, FIL_SendisPlayerHaveSyringe)
function SendTakeBloodSample(patient, isPlayerHaveSyringe)
...
arg["isPlayerHaveSyringe"]
Commands["TakeBloodSample"] = function(arg)
TakeBloodSample(arg.isPlayerHaveSyringe)
end
function TakeBloodSample(isPlayerHaveSyringe)
-- use isPlayerHaveSyringe to determine the type
end
Try doing that
instead of the boolean, you could send the item type or whatever
as a string
That's correct as far as I know. I'm unaware of a way to send a keypress event back into java
Hmmm thanks for all the constantly useful feedback. Your brilliance is appreciated.
...
arg["isPlayerHaveSyringe"]```
where should the arg["isPlayerHaveSyringe"] go exactly in here?
after local arg and before sendClientCommand
Would this be it?
arg["isPlayerHaveSyringe"] = isPlayerHaveSyringe
also this.. forgot arg.
yea
Your call to TakeBloodSample in perform, pass in as a param FIL_Sendetcetcetc
Wdym?
btw, it's much easier with copy-paste, like
```lua
function foo(blah)
-- blah
end
```
because then I can copy it and fix it ๐
Didn't know that
will copy it
function ISTakeBloodSample:perform()
self.surgeon:getXp():AddXP(Perks.Doctor, 2);
FIL_SendisPlayerHaveSyringe = nil;
if FIL_isPlayerHaveSyringe(true) then
self.surgeon:getInventory():Remove('LabSyringe');
FIL_SendisPlayerHaveSyringe = true;
else--if
if FIL_isPlayerHaveSyringeRE(true) then
self.surgeon:getInventory():Remove('LabSyringeReusable');
FIL_SendisPlayerHaveSyringe = false;
end--if
end--if
if self.patient ~= self.surgeon and isClient() then
SendTakeBloodSample(self.patient, FIL_SendisPlayerHaveSyringe);
else
TakeBloodSample();
end
if FIL_isPlayerHaveCotton(true) then
self.surgeon:getInventory():Remove('AlcoholedCottonBalls');
else--if
if FIL_isPlayerHaveAlcoholWipes(true) then
self.surgeon:getInventory():Remove('AlcoholWipes');
end--if
end--if
ISBaseTimedAction.perform(self);
end
function SendTakeBloodSample(player, isPlayerHaveSyringe)
local arg = {};
arg["From"] = getPlayer():getOnlineID();
arg["To"] = player:getOnlineID();
arg["command"] = "TakeBloodSample";
arg["isPlayerHaveSyringe"] = isPlayerHaveSyringe;
sendClientCommand("FIL", "SendServer", arg);
end
Commands["TakeBloodSample"] = function(arg)
local arg = arg["toSend"];
TakeBloodSample(arg.isPlayerHaveSyringe);
end
function TakeBloodSample(isPlayerHaveSyringe)
local player = getPlayer();
if isPlayerHaveSyringe == true then
local FIL_bloodsample = player:getInventory():AddItem("LabItems.CmpSyringeWithBlood");
FIL_bloodsample:getModData().IsInfected = player:getBodyDamage():isInfected();
FIL_bloodsample:getModData().InfectionRate = FIL_InfectionRate(player);
else--if
local FIL_bloodsamplere = player:getInventory():AddItem("LabItems.CmpSyringeReusableWithBlood");
FIL_bloodsamplere:getModData().IsInfected = player:getBodyDamage():isInfected();
FIL_bloodsamplere:getModData().InfectionRate = FIL_InfectionRate(player);
end--if
player:getBodyDamage():ReduceGeneralHealth(5);
end--function
line ~15 in perform, you call TakeBloodSample with no parameter, but now with your changes, it expects one parameter
function ISTakeBloodSample:perform()
self.surgeon:getXp():AddXP(Perks.Doctor, 2);
FIL_SendisPlayerHaveSyringe = nil;
if FIL_isPlayerHaveSyringe(true) then
self.surgeon:getInventory():Remove('LabSyringe');
FIL_SendisPlayerHaveSyringe = true;
else--if
if FIL_isPlayerHaveSyringeRE(true) then
self.surgeon:getInventory():Remove('LabSyringeReusable');
FIL_SendisPlayerHaveSyringe = false;
end--if
end--if
if self.patient ~= self.surgeon and isClient() then
SendTakeBloodSample(self.patient, FIL_SendisPlayerHaveSyringe);
else
TakeBloodSample();
change to:
function ISTakeBloodSample:perform()
self.surgeon:getXp():AddXP(Perks.Doctor, 2);
FIL_SendisPlayerHaveSyringe = nil;
if FIL_isPlayerHaveSyringe(true) then
self.surgeon:getInventory():Remove('LabSyringe');
FIL_SendisPlayerHaveSyringe = true;
else--if
if FIL_isPlayerHaveSyringeRE(true) then
self.surgeon:getInventory():Remove('LabSyringeReusable');
FIL_SendisPlayerHaveSyringe = false;
end--if
end--if
if self.patient ~= self.surgeon and isClient() then
SendTakeBloodSample(self.patient, FIL_SendisPlayerHaveSyringe);
else
TakeBloodSample(FIL_SendisPlayerHaveSyringe);
got it
If that is basically it I'll test it later when my testing buddy is online
Is it okay if I DM you if that doesn't work? No hard feelings if your answer is 'no'
That's okay
tnx โค๏ธ
There's a mod that replaces the moodles with different sprites. Could similarly replace them, but with 100% transparent sprites ๐
...
Ok I'm missing something, any exact guide or page that explains How zomboid runs the mod scripts?
omfg @hearty dew
This exists: ISUIHandler.setVisibleAllUI(bool)
And works
And I am now going to publish a mod
could you show the script for the glowstick item?
yeah sure
just wanted to do some baby steps and see whats happening
in the recipe script, you've set the result to GlowStick, but the item is called MikusGlowStick here
happens to the best of us!
check the script.txt for the name and module
ow nvm uve done this haaha
Y'all ever try to post too quick on Discord and get an error stuck in Discord's memory, causing previews to be bugged? If so, any way to clear that? Or just wait for Steam or Discord cache refresh?
i think something might just be going on with steam's servers
Oh word
i can't download your mod right now
Oh odd
could be something weird on my end though
Can you see it?
yeah it's there the download just doesn't work
completely stuck here with no disk activity and very low network activity
That could be my fault, I was trying to trip the gd preview to reset and briefly hid the mod... for literally 7 secs
If you were installing during that 7 secs, could've caused that Idk
it looks like i have the whole mod in the download folder lol
lol so odd
Well I'll tell you what when the mod works it's gonna be glorious
lmao
It's so nice being able to hide my UI with a quick R3
yeah i think this might be a me-specific issue lol, i restarted steam and deleted the files and it redownloads the whole thing and gets stuck again
๐จ
must be!
oh yeah i went onto the workshop to try resubbing to a different mod
and half the thumbnails won't load now
some steam engineer is about to have a really bad day
Dang this sucks lol I hope people don't try installing my mod and think it's busted and spam downthumb
May hide it for now f.r.
hmm - how does one load custom script? using same file name as base scripts works but if i try to use my own names ie mod_name.txt, it doesn't seem to load or overwrite some stuff that I intend to overwrite (mainly recipes)
Naming your file the same as the base game file overwrites that entire file. Try adding a line like this to your recipes (and name your file whatever you want; just not the exact same name as the vanilla file)...
Override:true,
thanks. also is there a way to reload the mod without having to close and start game?
nevermind, i just found out.
also thank you for the overwrite, that worked
Is there an event that is triggered when a zombie damages a player? OnBeingHitByZombie is obsolete and OnWeaponHitCharacter doesn't trigger when a zombie hits a character.
Be aware that this can break decorator functions
has anyone got an example of initialising a zombie.core.physics.Transform in a lua script? Im trying Transform.new() and getting an error
or, more specifically, does anyone know what the correct method is for setting the x,y position of a vehicle, more precisely than just a grid square?
i want to change "rugged recipe" mod to make it only have dried food and it's recipe, someone please help me
How to change mod data of an item on the ground in multiplayer?
OnPlayerGetDamage is to be added in the changelist for the next patch, maybe wait until then?
that'll probably pass what's damaging the player
marketing-wise that is a terrible name for your mod, but thank u lol
many screenshots will be nicer because of this 
Oh, neat. Thanks for the heads up.
Now more colorfully announcing Dawn of the Zed, which adds a hotkey on keyboard and gamepad for quickly hiding your entire UI. Film the next great zombie movie in Project Zomboid (or just see more of the horde coming while they approach to devour you). https://steamcommunity.com/sharedfiles/filedetails/?id=2875062853
Entirely fair, bahahaha, I almost named it something very boring and descriptive, but hated it and went with something flashy. Idrc who uses it. If it does its job, I'm sure it'll be used.
I made it for you & me tbh lmao
It was not a terrible amount of extra work on top of the other crap I'm already neck-deep in sorting.
If 3 people use it, victory
xD
I need to figure out Mod Options now
i will be putting it on a server which should grow to hundreds-to-thousands of users
already around 100
Because I'm sure people will post wanting to change the hotkey
lmao hell yeah
Mmm I don't know, it hides the UI but I don't know that name text is part of UI. I hide my own name text in the menu... do other players still show?
Is this some big well-known issue?
I have no friends in Zomboid lol
Joking but the 2 people who play with me are rarely on
So I haven't gotten to see how it looks when I'm playing with a friend
I just know I can host and hide everything by pressing R3 or apostrophe
๐ฆ