#mod_development
1 messages Β· Page 35 of 1
I'm working on creating a mod that adds a simple magic system to the game. I want generating magic to burn calories, increase hunger, and increase fatigue (think Lyft from Stormlight Archives). I've found that I can set the hunger, calories, and fatigue to specific values, but is there a better way to do this?
Does anyone know why the item is not spawning with a model?
I used the FBX from the original ingame model: media\models_X\WorldItems\FishingLine.FBX
Attached screenshot of my files and missing in game model
Did you set the texture to that item? If not, it won't appear
@weak sierra Oof, no, it does not hide my username, unfortunately. I will try to explore how the UI manages usernames... for now, videos will be most movie-like with username off in multiplayer settings and nobody else near you π
What do you mean by that? How do I set it ? π€
Just a pure guess but if it hides your name, shouldn't it hide others as well? Provided that the game treats them all the same
It doesn't, I just disable my own username in settings
So it never occurred to me to check
Effectively my entire hud was gone
I have no friends so didn't know they would still have usernames
I can see why there is demand to get rid of that
Okay just so we are clear, you know what textures are?
Yes, I even made my own custom texture for it #modeling message
@gilded hawk That "WorldStaticModel" doesn't connect directly to the FBX file. It's looking for a model entry like
{
mesh = WorldItems/BookClosed,
texture = WorldItems/UmbrellaBook,
scale = 0.4,
}```
Do you have one of those?
Oh, no I don't have this π€
You need to have a file like that in the scripts folder
Oh okay thank you ,I'll try now
I'm working on creating a mod that adds a simple magic system to the game. I want generating magic to burn calories, increase hunger, and increase fatigue (think Lyft from Stormlight Archives). I've found that I can set the hunger, calories, and fatigue to specific values, but is there a better way to do this?
model_TapeMeasure for example. and inside, you define which mesh to use, the texture to use, and the scale of the mesh. You can place the texture inside /media/textures
It works! Nice to have the scale settings in the model
To the best of my knowledge, that's as good as you can do. Having the script modify calories/fatigue/hunger whenever you generate magic
ayye glad to near its working for you!
Thank you again 
My pleasure :)
Thanks! Just making sure I wasn't missing some better way to handle it that would update all of those values at once as if a player exercised really hard in a short period of time.
It's my pleasure! The way I'd probably do it, if the values were always the same, is having a function that reduces all 3 and whenever I wanted to reduce them, I'd call that function
Also anyone aware what function to use to give the player a headache?
I don't think there's anything special about headaches. They are just pain added specifically to the head.
soo how do you add pain to a specific part of the body in general?
@weak sierra Did my mod get stuck in validation for you as well?
I am not able to pull it from Steam
For some odd reason
Nor was albion iirc
I waited like an hour but it's still failing and I'm a bit confused. Considering deletion and reupload.
Gonna restart PC though I dunno why
@thick karma funnily enough I got a MANIFEST UNAVAILABLE when I tried to download your mod
@hollow current I believe something like this should work
getPlayer():getBodyDamage():getBodyParts():get(BodyPartType.ToIndex(BodyPartType.Head)):setAdditionalPain(20.0)
or more simply
getPlayer():getBodyDamage():getBodyPart(BodyPartType.Head):setAdditionalPain(20.0)
Thanks I'm going to check it out
I don't know if upload bugged or I missed a line in a file somewhere but I'll figure it out
oh wow that's more complex than I thought. Thanks though, really appreciate it
@hollow current Yeah, its a bit of a rabbit hole to get to body part damage. Added a slightly more condensed example.
Can't check at the moment but you can't remove a car's trunk right?
The latter definitely looks simpler. Thanks once again
Just double checked, you can't
Its condition only decreases but you can't uninstall it
That means there's no way to check its repair stacks
Kind of an oversight when trunks are (for me) the most important part of a car lol
I'm trying to make a refurbish action for a mod but it only works on inventory items
Well I think the best course of action would be storing the number of repairs on a trunk in the mod's moddata
God I love ketamine
Omg this is infuriating
π΅βπ«π΅βπ«
I checked every line
lol
I reuploaded and the same thing is happening
What the heck does manifest unavailable meeeean
Whyyyyyyyy
lemme check if I get same problem with other mods
I have the same files in the same places!
I just reinstalled a bunch of mods, I think it's mine
But I don't know whyyyy
Or maybe my account
I have no clue
well downloading other mods work
maybe check your mod.info?
idk if it may cause such issue but it's my best guess for an issue like this
Omg I am so lost
I have triple-quadruple checked it so many times, it looks like it follows the same patterns as other mods I made
Why do you hate me Steam
π
Ugh this is so frustrating. I have no idea what to try because I have no idea what is wrong. It's all working locally. I submit to workshop., Workshop fails to let me sub. Kill me
have not installed it yet, that'll be a later-today task
i can try subbing rq tho
Nah don't bother
My account or upload is having issues
Idk why
I am troubleshooting
Mod works fine on my PC, but I cannot DL it from workshop and 2 others who have tried ran into the same issue
Something about a manifest being unavailable but all the files are in the normal places
Sure, I'll ping you if I get it fixed
Probably gonna keep banging head until I figure it out or it just starts working
Already tried waiting an hour and that failed
did u try just uploading a new copy
might have been bad upload
check ur workshop.txt tho
and mod.info
i think one of those might be the "manifest"
not sure
did anyone ever seen this error?
Left: Working
Right: Not Working
Left: Working
Right: Not Working
Left: Working
Right: Not Working
Anyone knows how to create recipe tag?
Left: Working
Right: Not Working
Left: Working
Right: Not Working
I am so confused
π someone please think of something
Check the image dude
Which image?
On g you should just use storm api
check if the .png file has the same width and height of the example file
ππ€ππ
π
Java > Lua
Okay grandpa go to bed and wake up once TIS allowed complied java to the workshop (very unlikely)
I'll re-export them to be super sure
Mlem is already working on a way to package up the mod and make it available for workshop
Also Java mods would prob never be a major thing in the workshop even if they could get added since I imagine most Java mods using the storm api will be bound mostly to GitHub
But you can always just go to the releases page and get a release of it
No user can be assed to download extra stuff while most mods are one click install
But you are using Lua so you prob donβt know how to use GitHub
Dude, are you serious?
<@&671452400221159444>
What are they gonna do again?
Have we broken any rules
We are discussing modding
And you want to go cry to the moderators before we can even start the talk about it?
Check the rules
But you are using Lua so you prob donβt know how to use GitHub
Have we broken any rules
Well you're being a bit of a dick is all
Ok, that is great?
Recommend you find another server for that
Good way to spread the word about a project...
Talking down on the defacto way to make mods so far. Smh
There are many instances of him being annoying and "doing a little trolling"
Just take a look at the history of the channel
#mod_development message
Yeah saw him before
lol imo he wasn't even doing that much @iron salmon. Really, he was just insulting people under the guise of having anything technical to say at all.
He's a highschooler that only knows how to code in Java and thus thinks its god's gift to computing and that all other languages are inferior.
Once or twice is tolerable, but doing it everyday is aggravating.
@gilded hawk omfg you're mf genius
Do you have a donation link fr
I had the issue so many times lol
I will straight buy you a coffee
I was going insane
Get this bro
When you said image I knew EXACTLY where I went wrong
I didn't flatten the image and it exported funny
Came out with a different bit depth
I checked file details
Resolution was perfect but the bit depth was a no go
It looked right on Steam and everything
What a weird issue.
Steam has hard set rules for the preview image
Omg I literally flattened the image and exported again
oh maaaan
Phew
I was literally going to jump
That was the last mod for me
@weak sierra @bronze yoke @hearty dew Okay, NOW I think it will actually work. Thanks 1,000,000 times over @gilded hawk https://steamcommunity.com/sharedfiles/filedetails/?id=2875149317
Can't wait to give a try to this mod

But Evelyn I still need to put time into figuring out how to hide other players' names. I'll update you on that one ASAP
isn't hiding player names a sandbox setting?
Hiding your own name definitely
Others idk
I hide my own name already but Evelyn asked if it hides other people's names and I assume it (my mod) does not because it doesn't hide mine (if my username is enabled in Multiplayer settings)
Oh wait you mean sandbox not options @gilded hawk
by default it shows them if moused over, but u can enable them at all times - you could hook that code that checks that setting (wherever it is) and just block the "is moused over" detection and not show it
Read better, me
Let me check that, I could've missed that
There are sooo many sandbox settings
this is one of those mods i could make but i have no time, but i wish existed, so im glad ur making this lol
So you're saying there is a sandbox setting to only show player names on mouseover?
yeah
Maybe this one?
yup
Mmmmm that's useful @gilded hawk
good place to follow the breadcrumbs
Because I was thinking about playing with DisplayName
search for the string, then find the translation file entry, then search for its name
I can both "get" and "set" DisplayName
I may be able to temporarily blank display names
that's not gonna really work it'll change the actual char data
Fair
might also rquire doing from server cuz perms
Also it'd get overwritten anyways whenever PlayerUpdate occurs, wouldn't it?
u wanna just change display not the data
what about this setting?
Ohhh I didn't know about that
yeah u cud turn those off on-the-fly perhaps
but uh
those are server settings
so no
u cant
however u can hook that code
server settings like that are INI file changes
require /reloadoptions
So I could mod the server ini live and somehow reload the server settings while it's running?
It's possible to change them from the lua for sure tho]
that requires admin access and affects all players
again, do not do this
Fair
i use a search that searches in all files in the media folder of zomboid, file content
search for the name of the setting
find the internal variable name
then search for that
that will return where it is in the codebase in lua
if it's not in lua then ur SOL ofc
Notepad++ is what I have been using to search within the folders.
function GetClothingToTailorMade(scriptItems)
local allScriptItems = getScriptManager():getAllItems();
for i = 1, allScriptItems:size() do
local item = allScriptItems:get(i - 1);
local isClothing = tostring(item:getType()) == "Clothing"
local isCosmetic = item:isCosmetic()
local isWorldRender = item:isWorldRender()
local hasRunSpeedModifier = item.runSpeedModifier
local hasCombatSpeedModifier = item.combatSpeedModifier
print('hasRunSpeedModifier '..tostring(hasRunSpeedModifier))
print('hasCombatSpeedModifier '..tostring(hasCombatSpeedModifier))
if not isCosmetic and isClothing and isWorldRender and (hasRunSpeedModifier or hasCombatSpeedModifier) then
scriptItems:add(item);
end
end
end
Does anyone know why do I keep getting nil at hasRunSpeedModifier and hasCombatSpeedModifier?
They should be defined in the script item, no? java\scripting\objects\Item.java
I bet it's got DisplayName in it
I will try to search it up
im pretty sure the ones ur looking at in those screenshots are actually the actual names
since they are INI ones
but for sandbox or context menus the method above applies
@gilded hawk It might just be an item that doesn't have those set so they are 'nil'. The java code probably doesn't initialize them to 1 or something and just checks for nil values before using them.
what's the correct way to use global moddata
there's a lot of functions there and it's a bit ambigous from the javadoc
getOrCreate to retrieve/make it and then.. save?
transmit?
Indexing my Lua for this now π
I was just trying to hunt that guide down, too slow
so it's implied
mk
so i can getOrCreate then do stuff then transmit at the end and i should be good
and as long as getOrCreate is within a local it should re-request every time
yeah?
Depends on where this globalmoddata is supposed to live.
If its on the server and needs to be sync between server and client, you'd transmit it out whenever you create it or update it.
And also you'd need to set it up so the client requests the moddata when they are not synced (like if they've joined the server after the moddata was last created/updated)
If its just being used by the server and not the clients or it is unique to the client and doesn't need to be shared, then you just need to make it and never bother with transmitting it out.
i want a table that is shared and modified by all clients
it'll act as a queue for a certain action
clients adding and removing from it
server just storing/passing it out
advice? :p
So it'd be
- Server creates moddata and transmits it
- Clients receive moddata using OnReceiveGlobalModData and then apply it
- If a client joins after this, they request the moddata (Events.OnGameStart or something)
- Client accesses it and modifies it then transmit it (sending it to the server)
- The server then transmits it to everyone else after one client updates it and sends the update to the server (Using OnReceiveGlobalModData event)
i could i guess set it up to just be stored and used on the server, and uninvolve the clients, instead making the clients just update position to the server every N so it can go over them every N and do the action
oh i'd just thrown getOrCreate in the function where i was using it hehe
on the client
i thought the first client to do so would end up populating it via transmit
race conditions tho i guess
which im generally worried about here the way i am thinking about this
i think i should instead redesign the way things will work to be more server-side
clients can add and server will just act on it
then there's less potential for race condition
in fact i dont need to sync it at all to the clients
i can just take in commands to update it
and do all of it from the server

You'd still need clients to create the moddata themselves if you were to share the moddata around. Just they need to sync their copy with the servers.
originally i had clients generating the data, then requesting the server act on it immediately
i think im gonna have clients generate the data then request the server put it in a list to act on periodically instead
mm
but it needs to involve the client's reality bubble and the OnPlayerMove filters out when they aren't moving
mmmmmm
maybe i can just ignore that and blindly attempt to use the data and if it fails then i just leave it in the list to try again.. might waste cycles tho
all comes down to "certain things can only happen if a square is loaded"
lol
and the idea of writing it to LoadGridsquare seems.. bad
This is kinda related to something I was thinking about this morning. How do you efficiently and elegantly request data from the server before performing an action? Seems like you have spend a bunch of time doing client and server commands
seems like it.
global moddata seems.. similar tbh
just already set up to persist and sync
I have found mods that use LoadGridSquare cause quite a bit of stutter when ripping down the highway tbh
do you want these things your storing to persist?
yeah that's why i am hesitating to do it, the code doesn't need to run for every square
yes
until used
ok so this is for my vehicle respawn mod
Yeah, LoadGridSquare cycles very, very fast. You don't want to spend much time in there.
it only works in loaded chunks atm
which is not good
i wanted to just force the squares to load
but that doesn't seem to work
e.g., load the square, spawn the vehicle
could not for the life of me get that
.... there is a mod that does that, just a sec
so my idea was to instead maintain a list of intended vehicles to spawn
have the clients feed that to the server
and then have the vehicles spawn when the squares become loaded
in some way or another
might want to check how this mod does its thing https://steamcommunity.com/sharedfiles/filedetails/?id=2761962764
which i was thinking poll distance around players
that mod is stupid
:p
well
it's not stupid but it's irrelevant
it just teleports the player around
to force things to load
then u uninstall the mod
oh? lol
I use a table with the key set to the square's coords for something similar. Haven't truly stress tested it, but doesn't seem to be too harmful so far.
local x, y, z = square:getX(), square:getY(), square:getZ();
local key = x .. "|" .. y .. "|" .. z;
local zombieGroup = objectiveZombies[key];
if zombieGroup then
[code stuff]
end
end```
i could leave an admin player logged in and TP them around to force squares to load
but that's a FILTHY hack
and requires an extra copy of PZ and a machine
which is nuts
are u putting that on LoadGridsquare?
Yes
i did consider whether i just should or not
it should be quick
but
what if 100-200 entries to loop thru
oh right keyedd
yeah
That's why I use the coords as key
derp
yeah
that certainly is the easy way to do this
can u LoadGridsquare on the server?
or just clients
yeah
good
Yeah, don't know if its the best way to handle this but it works for my needs.
it's the most efficient way CODE-wise
for what im doing
i just am afraid to fuck with LoadGridsquare given its rep and how often it runs
lol
so i was trying to code around it
OnLoadGridSquare runs on both client and server though, so you need to prevent clients from using it.
Events.LoadGridsquare.Add(onLoadGridSquare);
end```
yeah
It's all nil at the moment, which is odd
does getVehicleById() fail if the vehicle is in an unloaded square?
ah, thats too bad
im trying to spawn vehicles tho, and it fails a very specific way
ERROR: General , 1665722790309> 8,915,729> DebugLogStream.printException> Stack trace:
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at se.krka.kahlua.integration.expose.caller.MethodCaller.call(MethodCaller.java:62)
at se.krka.kahlua.integration.expose.LuaJavaInvoker.call(LuaJavaInvoker.java:198)
at se.krka.kahlua.integration.expose.LuaJavaInvoker.call(LuaJavaInvoker.java:188)
at se.krka.kahlua.vm.KahluaThread.callJava(KahluaThread.java:182)
at se.krka.kahlua.vm.KahluaThread.luaMainloop(KahluaThread.java:1007)
at se.krka.kahlua.vm.KahluaThread.call(KahluaThread.java:163)
at se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1980)
at se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1782)
at se.krka.kahlua.integration.LuaCaller.pcall(LuaCaller.java:76)
at se.krka.kahlua.integration.LuaCaller.protectedCall(LuaCaller.java:117)
at zombie.ui.UIDebugConsole.ProcessCommand(UIDebugConsole.java:278)
at zombie.core.Core.updateKeyboardAux(Core.java:1992)
at zombie.core.Core.updateKeyboard(Core.java:2323)
at zombie.core.Core.DoFrameReady(Core.java:3089)
at zombie.GameWindow.frameStep(GameWindow.java:780)
at zombie.GameWindow.run_ez(GameWindow.java:680)
at zombie.GameWindow.mainThread(GameWindow.java:494)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException: Cannot read field "x" because "<parameter4>" is null
at zombie.Lua.LuaManager$GlobalObject.addVehicleDebug(LuaManager.java:7218)
... 22 more```
@gilded hawk I think I remember hearing they've disabled RunSpeedModifier/CombatModifier for everything except not wearing shoes. Maybe they accomplished that by just never setting it when they read in item scripts?
Anyone know if Brita has a bug reporting pipeline for their armor mod? "Brita's Armor pack". I noticed the Office Cardigan + Long Office Cardigan are set as pants, in tailoring. Meaning their defense bonus from the item and patches go to the legs. (Bare skin if you're not wearing anything, looks funny)
they show up in the mouseover on items
so they clearly are still set
i too have heard this
could be an urban legend
Hey guys, pretty new to modding and lua in general (webdev), I'm trying to figure out how to get the object selected by the destroy cursor.
Running through the docs I can get the sprite name of an object with object:getSprite():getName but I'm struggling to find the object that is currently selected by the sledgehammer.
@main lion Can't help but feel bad about pinging, but I noticed a bug with your armor pack, there wasn't a stream thread for it (understandable). It appears both Office Cardigan types have been set as 'pants' for tailoring and defense bonuses. #mod_development message
My bad if you were aware of it already. π
Ah, could just have shot a DM. π€¦ββοΈ
does anyone know why calling setX() and setY() on a vehicle doesn't work to move it?
maybe its position is controlled by the physics engine
i tried updating the physics engine
i tried transmitting complete item to server
i tried update on the vehicle
@weak sierra @vast nacelle
I fixed it like this
local function addClothingsToRecipe(scriptItems, item)
local isClothing = tostring(item:getType()) == "Clothing"
local isCosmetic = item:isCosmetic()
local instancedItem = item:InstanceItem(nil)
local isWorldRender = item:isWorldRender()
if not isClothing or isCosmetic or not isWorldRender or not instancedItem then
return
end
local hasRunSpeedModifier = instancedItem:getRunSpeedModifier() < 1
local hasCombatSpeedModifier = instancedItem:getCombatSpeedModifier() < 1
if not (hasRunSpeedModifier or hasCombatSpeedModifier) then
return
end
scriptItems:add(item);
end
function GetClothingToTailorMade(scriptItems)
local allScriptItems = getScriptManager():getAllItems();
for i = 1, allScriptItems:size() do
local item = allScriptItems:get(i - 1);
addClothingsToRecipe(scriptItems, item)
end
end
i can even get it to return the new coords with getX and getY
the reason i was toyin with setting vehicle coordinates was twofold
- would be nice to tp vehicles
- if i can't spawn vehicles in unloaded cells can i spawn them out of view and tp them there?
lol
did you try playing with setWorldTransform()?
no cuz i looked at what it was and it looked like a matrix for 3d transformation
which i didnt expect to have bearing on the actual pos
but

sometimes pz weird
who knows
positions are matrices for 3d transformations
well
i tried that but it requires a Transform, and i couldn't find a way to create one in lua.
one row of the matrix, normally
the transform has an origin which looks like its position, so it might be right
but usually the matrix is updated automatically and position is stored separately in game engines
if PZ is using the matrix as storage for the position it'd be highly unusual
if i could only figure out the lua to make one
and i imagine it'd just visually move the vehicle not data-wise move it
but that's as a game designer who has made 3d game engines
not as a pz modder
lord knows what's going on in here
lol
pz has some weird stuff going on..
i thought it was Transform.new() from looking at the docs, but that threw an error that i was calling a method on nil, like it doesnt know what a Transform is
YourUtils.inspectJava(getScriptManager():getItem("Base.Pen"))
LOG : General , 1665773252747> ---------- Item{Module: Base, Name:Pen, Type:Weapon} ----------
---------- Fields -----------
String clothingExtraSubmenu : nil
String DisplayName : Pen
boolean Hidden : false
boolean CantEat : false
ArrayList<String> Categories : [Improvised]
ArrayList<String> Tags : [Write, Pen]
String IdleAnim : Idle_Weapon2
String RunAnim : Run_Weapon2
String WorldTextureName : media/inventory/world/WItem_Pen.png
---------- Methods ----------
void setType (Type)
boolean isManuallyRemoveSpentRounds ()
void setKnockBackOnNoDeath (boolean)
void Load (String, String[])
void setName (String)
Item$Type getType ()
void DoParam (String)
In-game java docs if anyone might find it useful
plus the position of vehicles, the real backing of it, is in vehicles.db
and it's stored as coords not as a transform
which would be weird to do if u were using the transform as storage
does lua require namespace imports or anything like that?
@weak sierra Did those apis I mentioned earlier work to force a chunk to load btw? I didn't have time to test them out yet
looks like transform isn't exposed to lua
you could spawn a vehicle where you want, save its transform to a variable, delete the vehicle and then set the original vehicle's transform to the stored one lol
there is a function to tell it whether bullet should be active, I wonder if you have to disable bullet on the vehicle before you can move the vehicle outside the physics engine
lol i actually considered that, but it looks like you cant spawn a vehicle any more precise than a grid square, so it would be weird
is that physicsActive ? ive messed with that but i might try again
setActiveInBullet
no idea what it does
I find it interesting there is a path finding class in zombie.vehicles. Is it time to make a knight rider mod?
the javadocs for setActiveInBullet say: Used in mechanics UI, we enable the vehicle in Bullet when starting mechanics so physic will be updated. When we close the UI, we should disable it in Bullet, expect if the engine is running.
if you figure out this vehicle moving stuff, wheel85, let me know
very much interested
maybe for eventual npc drivers
whatever java docs I have a link to has literally 0 docs for anything, I really only go there to look at method names, lol
so yes, Knight Rider
can u imagine how complex an AI driver would have to be in a world full of fucked up roads and zombies vs. just what we need irl? good thing they have all the data magically at their fingertips here instead of like IRL where it must be gathered and heuristics applied
lol
Kitt would only have to pathfind while within eyeshot of a player, even easier!
I am trying to figure out where recipe tags are stored within the game files. Is there a centralized location for this, and does it include modded recipes?
Maybe you will find more information in this folder and these files:
ProjectZomboid\media\scripts
- items.txt & newitems.txt
- recipes.txt
- ...
And sometimes it can be interesting to download a mod close to what you are looking for and look at how it was made. I often do this when I'm looking for information about this or that aspect.
Events.OnInitGlobalModData.Add(function(isNewGame)
print("[UdderlyVehicleRespawn] Initializing GlobalModData.")
UdderlyVehicleRespawn.VehiclesToSpawn = GlobalModData.instance:getOrCreate("udderly:VehiclesToSpawn")
end)```
is this not a valid approach to this, server-side?
at runtime i get this when trying to access it (well after things load)
STACK TRACE
-----------------------------------------
function: SpawnVehicle -- file: UdderlyVehicleRespawn_Commands_Server.lua line # 36 | MOD: Udderly Vehicle Respawn Testing
function: Add -- file: UdderlyVehicleRespawn_Commands_Server.lua line # 14 | MOD: Udderly Vehicle Respawn Testing
ERROR: General , 1665780699715> 66,825,144> ExceptionLogger.logException> Exception thrown java.lang.RuntimeException: attempted index: 10872_16653 of non-table: null at KahluaThread.tableget line:1689.
ERROR: General , 1665780699715> 66,825,144> DebugLogStream.printException> Stack trace:
java.lang.RuntimeException: attempted index: 10872_16653 of non-table: null
at se.krka.kahlua.vm.KahluaThread.tableget(KahluaThread.java:1689)
at se.krka.kahlua.vm.KahluaThread.luaMainloop(KahluaThread.java:492)
at se.krka.kahlua.vm.KahluaThread.call(KahluaThread.java:163)
at se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1980)
at se.krka.kahlua.vm.KahluaThread.pcallvoid(KahluaThread.java:1812)
at se.krka.kahlua.integration.LuaCaller.pcallvoid(LuaCaller.java:66)
at se.krka.kahlua.integration.LuaCaller.protectedCallVoid(LuaCaller.java:139)
at zombie.Lua.Event.trigger(Event.java:64)
at zombie.Lua.LuaEventManager.triggerEvent(LuaEventManager.java:214)
at zombie.network.GameServer.receiveClientCommand(GameServer.java:4163)
at zombie.network.PacketTypes$PacketType.onServerPacket(PacketTypes.java:1016)
at zombie.network.GameServer.mainLoopDealWithNetData(GameServer.java:1527)
at zombie.network.GameServer.main(GameServer.java:801)
LOG : General , 1665780699716> 66,825,144> -----------------------------------------```
if UdderlyVehicleRespawn.VehiclesToSpawn[key] ~= nil then
that's the line triggering the error
i hate lua so much lmao
"everything is a table" -> what does it mean when u load a table from the global moddata and then edit it, then there's no reference back? or is there?
Thank you! I like your mods too β€οΈ
wait.. do u not use GlobalModData class to access the GlobalModData
u literally use ModData?
wth
that's not fuckin confusing at all
is it a dog-drawn carriage?
lightning fast with that gif, wow
Oh shit I've been exposed
globalmoddata now working, and my code was flawless so now all i gotta do is make sure the backlog-spawned vehicles are actually spawned, and make sure the table is persisted..
im assuming it will persist it on its own during shutdown
and/or whenever it saves
can you give us a rundown of some of the hurdles?
Just for curiosity, does somebody knows what mean the prefix classes Iso...?
isometric
nice thx
so
do i really need to like
expressly save the global mod data every 10 mins or something
does the game really not do this for me
Isometric video game graphics are graphics employed in video games and pixel art that use a parallel projection, but which angle the viewpoint to reveal facets of the environment that would otherwise not be visible from a top-down perspective or side view, thereby producing a three-dimensional effect. Despite the name, isometric computer graphic...
i entered a few things into a table in the global mod data
on server end
then save/quit server
restart server
LOG : General , 1665788029509> 74,154,938> [UdderlyVehicleRespawn] Initializing global mod data.. Found 0 vehicles to spawn in backlog.
shudda had 5
even says this when u quit..

lua confuses the shit out of me, if it's just a raw table there's no reference back to the moddata from it right?
so do i need to like..
overwrite it
or something
yet it seems to work fine between restarts so clearly the data is there..
LOG : General , 1665786292200> 72,417,629> [UdderlyVehicleRespawn] Could not spawn vehicle at 5483, 12037 for player "UdderlyEvelyn" as a replacement because the selected square had no chunk, adding to backlog for later.
LOG : General , 1665786313362> 72,438,790> [UdderlyVehicleRespawn] Spawning "Base.88jetta4doorMk2" at 5483, 12037 from backlog (originally for player "UdderlyEvelyn").```
teleported to the coords after the first two lines in the log
so it's putting it in the moddata fine and taking it out fine
yet it doesn't persist?
nobody knows this?
ughh
is this code relevant https://github.com/Konijima/PZ-Community-API/tree/master/Contents/mods/CommunityAPI/media/lua/client/SpawnerAPI
ive no idea if it works i just found it through the docs site
LOG : General , 1665790052500> 76,177,928> [UdderlyVehicleRespawn] Spawning "Base.70dodgePD" at 9617, 12756 from backlog (originally for player "UdderlyEvelyn").
directly contradictory how fun
well god damn i just basically wrote that didnt i :p
yeah i literally wrote almost the same code today lol
they don't do anything to persist it there
this hurts my brain
time to go dig around in the java i guess :(
i hate this so much it's been like 8 hours
D:
Anybody know if it's possible to have animations affect the vehicle in PZ?
Besides just the player
Do you know the name of any so I can analyze it?
all of the vehicle mods by cytt0rak and by KI5, among others
most recent release is the 70 dodge on the front page of the workshop
Thank you
you could also check some of Autotsar Tuning Atelier vehicles mods like :
https://steamcommunity.com/sharedfiles/filedetails/?id=2681635926
https://steamcommunity.com/sharedfiles/filedetails/?id=2850439818
Now I just need somebody that knows the magic of animation
Is it possible to change map during game? Like treating each map as a zone that the player can go back and forth?
Could it be the type of data you're trying to store in the mod data? I've found you can put anything you want in moddata, but it only serializes and saves basic things
Hello everyone, 1st post and 1st mod attempt. I'm trying to add a new recipe (not overwrite old one) for smoke bombs based on kno3 and sugar. Below is my code...but when i load up the game with the mod loaded it doesn't actually work i.e. the only recipe visible for smoke bombs are the default vanilla recipe. Any help is appreciated:
recipe Make Smoke Bomb
{
GunPowder=10,
RippedSheets/RippedSheetsDirty,
Sugar=2,
Result:SmokeBomb,
Time:80.0,
NeedToBeLearn:true,
Category:Engineer,
}
NeedToBeLearn:true, did you learn it?
either remove that or add a new magazine that learns this recipe
hello
is this where i would ask for help with mods
one is doing weird stuff
oh wait #mod_support
does anyone know if i can kick players on server level, or even ban them?
i made a rules popup that requires new players to accept them, if they decline multiple times i would like to kick them but firing the kick command is not authorized from a non admin client, any ideas?
im putting tables
with a string key
and members that are two strings and two numbers
:P
well that ain't it then
and the last iteration of my code threw errors saving the global mod data tho
so im very confused
notably: i am putting things directly into the moddata as the table
not making a table in a key in the moddata
is that.. is that not ok?
i have it literally re-adding the table to the global moddata on the EveryTenMinutes event
because apparently the game can't handle that for me
:|
interesting, thanks. I just copied it from the original file for the original recipe. I suppose I can add it to the engineer magazine vol. 2. And that should give it to the engineer at spawn which was the intent.
how would i check if the players inventory contains a certain item?
I haven't tried it yet, so forgive me if I'm just treading over ground you've already been on, UdderlyEvelyn, but it looks to me that you have to put your table in with a string key, like your mod name or something, and that you have to transmit and request it manually. Even after that you still need event handlers on both ends to deal with the requested moddata when it shows up. Seems really manual
im doing it all on the server end
im just using it as "Someplace to store some data that persists"
so transmitting/requesting should be irrelevant
ok, so doing something like local laTable = ModData.getOrCreate("UdderlyRespawned") and then writing to it isn't working?
first iteration i was doing that kind of line in-line every time i used the table
just to make sure
and it saved things to it
and read them from it
and worked
---Gets player specific items.
---@param p1 IsoPlayer
---@param p2 table | string
---@return table
getItemsByFullType = function(p1, p2)
local inventory = p1:getInventory();
local items = inventory:getItems();
local t = {};
for i = 0, items:size() - 1 do
if type(p2) == "string" and p2 == items:get(i):getFullType() then
table.insert(t, items:get(i))
end
if type(p2) == "table" then
for k, v in pairs(p2) do
if v == items:get(i):getFullType() then
table.insert(t, items:get(i))
end
end
end
end
return t
end
but then if i shut the server down
and started it back up
the data was not restored
you tried with KickUserCommand ?
https://zomboid-javadoc.com/41.65/zombie/commands/serverCommands/KickUserCommand.html
Javadoc Project Zomboid Modding API declaration: package: zombie.commands.serverCommands, class: KickUserCommand
i have now abandoned working directly with the moddata and am operating on a table in memory
and persisting it to the moddata on EveryTenMinutes
and reading it from there on init global mod data
using ModData.add?
yes
is that this one ? SendCommandToServer("/kickuser "" .. username .. "" -r "" .. args.reason .. """)
u wanna see the code? :p
sure, if anything at least I can learn something :p
that's the server side code, which i just freshly merged two files together for cuz the global table didn't seem to propagate across to the other file
because i have no idea what lua is doing sometimes
everything is handled in there re: the mod data
clients call teh commands
commands try to spawn shit and fall back to adding it to the table
how would i add a item to the players inventory?
i get i use addItem but like
what do i put in it?
getPlayer():getInventory():AddItem("Module.ItemType")
something like that
if u wanna add more than one
then AddItems("Module.ItemType", N)
ahh ty
from what you've described it does seem like you're getting a copy of the table instead of a reference to it when you do getOrCreate, but that seems weird since pretty much every other table operation is by reference
how would i add a uiElement to the screen?
just to render some basic text
i imagine there is a manager somewhere but idk how to access it
@weak sierra Oh, this line
ModData.add("udderly:VehiclesToSpawn", UdderlyVehicleRespawn.VehiclesToSpawn)
Isn't doing what you think it is. You are storing a reference to your existing table. It's not doing a deep copy.
So when you reload your mod data after a server restart, you'd have a reference to something that no longer exists, which probably just gets determined to be 'nil' and thus getOrCreate will make a new table.
Maybe check this mod to help with this :
https://steamcommunity.com/sharedfiles/filedetails/?id=2760035814
isn't that line the only thing doing what they want?
so i have to serialize the data myself? the fuck good is global mod data then
xD
could just store it in a file..
You could test it by storing the data to ModData, editing the VehiclesToSpawn from the ModData, and then check if the change was also made to your original table.
that's a question i kept asking earlier
since it's "just tables" in lua
i imagine there's no propagation magic at all unless it lives in the java side
alright so
apparently i need to serialize the table now
I'd test it first. I picked up lua like 3 weeks ago.
So weird coming from a C/C++ focus.
i come from C# focus
and lua makes me want to literally die at least twice a week
it hurts
it hurts so much
just wanna bang my head into a wall
sigh
the table is just null all the time
with it set up like this
I like languages that have first Class functions π
i think i need to set it to {} at some point
i like languages that have motherfucking types
and OO that has constructors
OO without OO is pain
ya, doing OO in lua is a nightmare, lol
i hate it so much
fuckin every other class has .instance
to just get some mystery instance
I assume they're singletons
and then half the methods on that are just stuff that cud be static
IsoCell sure ain't a singleton
unless im misremembering that having one
there was one in the last 12 hours i saw that seemed very.. odd
I've already done my rant as to why toilet paper, light bulbs or comic books might possibly need a wheel friction field
suspension compression on a watermelon
in this lua file
i define this table as nil
UdderlyVehicleRespawn.VehiclesToSpawn = nil```
at the top
then in the initglobalmoddata event
i do this
UdderlyVehicleRespawn.VehiclesToSpawn = ModData.getOrCreate("udderly:VehiclesToSpawn")
then, ages after this occurs, and i see in the logs that it did occur
i reference UdderlyVehicleRespawn.VehiclesToSpawn
and i get
at se.krka.kahlua.vm.KahluaUtil.fail(KahluaUtil.java:82)
at se.krka.kahlua.vm.KahluaUtil.luaAssert(KahluaUtil.java:70)
at se.krka.kahlua.vm.KahluaThread.tableSet(KahluaThread.java:1726)
at se.krka.kahlua.vm.KahluaThread.luaMainloop(KahluaThread.java:594)
at se.krka.kahlua.vm.KahluaThread.call(KahluaThread.java:163)
at se.krka.kahlua.vm.KahluaThread.pcall(KahluaThread.java:1980)
at se.krka.kahlua.vm.KahluaThread.pcallvoid(KahluaThread.java:1812)
at se.krka.kahlua.integration.LuaCaller.pcallvoid(LuaCaller.java:66)
at se.krka.kahlua.integration.LuaCaller.protectedCallVoid(LuaCaller.java:139)
at zombie.Lua.Event.trigger(Event.java:64)
at zombie.Lua.LuaEventManager.triggerEvent(LuaEventManager.java:214)
at zombie.network.GameServer.receiveClientCommand(GameServer.java:4163)
at zombie.network.PacketTypes$PacketType.onServerPacket(PacketTypes.java:1016)
at zombie.network.GameServer.mainLoopDealWithNetData(GameServer.java:1527)
at zombie.network.GameServer.main(GameServer.java:801)
LOG : General , 1665796076766> 82,202,195> -----------------------------------------
STACK TRACE
-----------------------------------------
function: SpawnVehicle -- file: UdderlyVehicleRespawn_Commands_Server.lua line # 49 | MOD: Udderly Vehicle Respawn Testing
function: Add -- file: UdderlyVehicleRespawn_Commands_Server.lua line # 18 | MOD: Udderly Vehicle Respawn Testing
and it makes me wanna just strangle someone
like how is it null
how
how is it a non-table
doesn't moddata.getorcreate return a table
it's "or create"
you're not doing any script reloading or anything in that timeframe right?
its never even worked for me once, but just checking
plus u have to edit the copies in the workshop folders when debugging w/ a dedicated
and u cant reload the server end
so
ive gotten it to work but it's spotty and not worth the headache
this is the current copy of the code
which gives me that shit
oo, the lua color coding came through this time
cuz i uploaded the file instead of trying to paste it
discord is sandboxed on linux i had to copy the damn script to my home folder to upload it
<_<
UdderlyVehicleRespawn.VehiclesToSpawn = nil
UdderlyVehicleRespawn.VehiclesToRespawn[key] =
{
username = playerUsername,
vehicle = vehicleToSpawn,
x = spawnX,
y = spawnY,
}
changed to:
`module Base
{
item EngineerMagazine2
{
DisplayCategory = SkillBook,
Weight = 0.1,
Type = Literature,
DisplayName = Engineer Magazine Vol. 2,
Icon = MagazineMechanics,
TeachedRecipes = Make Smoke Bomb; Make Smoke Bomb Alternate,
ReplaceOnUse = EngineerMagazine2,
StaticModel = Magazine,
WorldStaticModel = MagazineEngi1Ground,
}
recipe Make Smoke Bomb Alternate
{
GunPowder=10,
RippedSheets/RippedSheetsDirty,
Sugar=2,
Result:SmokeBomb,
Time:80.0,
NeedToBeLearn:true,
Category:Engineer,
}
}
`
Unfortunately, engineer still didn't have on spawn. Now i'm guessing that engineer doesn't get the magazine knowledge on spawn but actually gets the recipe directly? That's what i'm gonna check next.
@weak sierra line 49 has you writing to UdderlyVehicleRespawn.VehiclesToRespawn, I think that's your problem
your table is UdderlyVehicleRespawn.VehiclesToSpawn
@limber summit Yes, the engineer is given recipes directly.
From 'ProjectZomboid\media\lua\shared\NPCs\MainCreationMethods.lua', line 568
engineer:addXPBoost(Perks.Electricity, 1);
engineer:addXPBoost(Perks.Woodwork, 1);
engineer:getFreeRecipes():add("Make Aerosol bomb");
engineer:getFreeRecipes():add("Make Flame bomb");
engineer:getFreeRecipes():add("Make Pipe bomb");
engineer:getFreeRecipes():add("Make Noise generator");
engineer:getFreeRecipes():add("Make Smoke Bomb");```
i get burned out after about 10 hours
and start making more and more stupid mistakes
but i don't like leaving things unfinished
and this clashes 
haha happens to the best of us. Fresh eyes are often helpful
so it apparently reflects changes in the original table
which means either
- it synchronizes the data super well
- it's a reference
:P
now i'll try exactly what u said i suppose
and edit the moddata copy
doing ModData.getOrCreate("test") and then trying to key into it
"attempted index of non-table"
the fuck does it mean
i know it exists
i know it's a table
what is it on about
:|
it'd be easier to just abandon this and write to a damn file
but i don't really wanna, i wanna understand
oh wait
quotes
ok now it works
and writing to the moddata retrieved does nothing to the stuff in the moddata proper
which would indicate that it is one-way, whatever it is
Events.OnInitGlobalModData.Add(function(isNewGame)
--print("[UdderlyVehicleRespawn] Initializing GlobalModData.")
UdderlyVehicleRespawn.VehiclesToSpawn = ModData.getOrCreate("udderly:VehiclesToSpawn") --Retrieve the data (or create new).
ModData.add("udderly:VehiclesToSpawn", UdderlyVehicleRespawn.VehiclesToSpawn) --Track the table we retrieved it to.
print("["..modName.."] Initializing global mod data - found "..#UdderlyVehicleRespawn.VehiclesToSpawn.." vehicles to spawn in backlog.")
--We do this here so that these don't run before the mod data is ready.
Events.LoadGridsquare.Add(UdderlyVehicleRespawn.OnLoadGridsquare)
end)```
so this should retrieve it and then tell it to track that table instead of its own internal whatever
at which point i should be able to write to the table and have the changes propagate fine
that said though, it worked fine when every call had ModData.getOrCreate("udderly:VehiclesToSpawn")[key]
for read and write
which would fly in the face of this test
it just didnt persist
also the similar thing (which i wish i knew about before i began) here doesn't seem to do any magic to cause persistence and has an even deeper table..
will try just nesting the table one layer down

anyone know if lua is one of those languages that let you do an assignment as part of a conditional? aka
if p = getPlayer() then
for me, such a code in lua will result in syntax error. so I guess no...
ah thats too bad
but why? isn't something like
local p = getPlayer()
if p then
working in your case?
sure, but I don't need p outside the if block, so syntactically its nicer to be able to do it the other way. Not really a big deal
@astral dune An online compiler like this is good for testing out those little questions. https://www.tutorialspoint.com/execute_lua_online.php
lua has almost no syntax sugar lol
this seems much nicer than that bare bones one on the lua website, thanks
I googled that the last time you mentioned it and couldn't find it for some reason
lol
i refactored the code
and managed to type VehiclesToRespawn 3 times
:|
it's hard to type UdderlyVehicleRespawn hundreds of times
and then be asked to not type "Re"
Then in your heart you really want to name the table that.
Just do what that other fellow did with his hide ui mod and name it something completely unrelated and unsearchable
Bug report: "Strangely the vehicle respawn can only spawn Ladas now"

is improvement
every car that despawns is replaced with lada
semechki and vodka hidden in each glovebox
tri paloski
I've been using the Samara mod, which is a Camaro, not what I expected
should have at least called it a Samaro
too modern for me
like aggressively modern
i let the 08 sable slide
but that camaro screams 2010s
thats because that model came out in 2010, lol
But I thought it was gonna be a lada samara
its nice because it has the option to put protection on it, which honestly all the vehicles should, but I'll probably leave it out of my next server
i run cyt and ki5 vehicles and some ATA vehicles
a few non-animated non-fancy ones too
but
i wish they all were
ki5 are all very nice, and I think cyt does the kentucky overhaul mod right?
I had the motorious zone or whatever ones, but wasn't really feeling all the supercars everywhere
i have that and it's driving me nuts yeah
that said
i have P.A.R.C. and fillibusters upping the trash cars
so
between them all u end up with mostly non-supercars
mostly non-mil

my first play through with ki5's cars I had one of the mercedes spawn in perfect condition with the key on the ground beside it... loved that thing. Never found it again
hehe
always end up driving a semi anyway
I prefer smaller, cheaper cars honestly. Pack light and find parts everywhere.
ya, finding performance parts can be a chore
just wait until I release my mod and you have to go looking for a 5/16" wrench
i drive a series of semis
i like the w900 w/ autotsar mega trailer
:P
i have two..
and more vehicles, all high cap
i want to mod the oshkosh semis to be compat with autotsar ones
harder than it sounds tho
also w900 has a shitty trailer interaction with the dry van
can't pull it for crap
due to angle
ya, I really like the oshkosh, I don't like that the w900 turns into a modern batmobile when you put the protection on it, or how high your skill needs to be to put it all on in the first place
i play on mp with mechanics grindable inside 30 mins
skill loss and zed difficulty in place of skill grind
u respawn w/ partial skill loss at random
but mech and a few other traditional ones are fully levelable from books
most skills partial
its kinda neat messing with how leveling works. Was thinking of trying that consumable book mod next time. One free level per book, but it disappears when you're done rading
LOG : General , 1665802371066> 88,496,494> [UdderlyVehicleRespawn] Spawning "Base.fhqoneviadrift" at 1320, 6367 from backlog (originally for player "UdderlyEvelyn").```
it works and works thru a restart
but
it claims there's 0 vehicles in the list
lol
im curious about the idea of making them consumable
it seems a bit much for how i run things atm
but
very curious
I noticed that if you focus on getting a library together, you can actually do it very quickly and then you pretty much stop entering bookstores or schools after that. I like the idea of still needing to hunt for books. ESPECIALLY if you lose your skills on death. Kinda needs to have loot respawn though, which is difficult to tune
Yeah, keeping bookstores and such still relevant looting spots sounds nice. Though I think I'd probably go for a hybrid thing. Like you still need to grind skills but those consumable books can bring you back up to your max skill level, one level at a time.
since books cover 2 levels, and you can't reread them even with that mod, you get one level for free and then the XP boost for the other level. Seems like a decent balance
yeah i do like that aspect
we have loot respawn and it's tuned but lord knows how well tuned for books
lol
i use more loot settings tho
so i can tweak
that said we prob need those fixes discovered recently for sandbox options at distribution time
oh I didn't see how that worked out when people were talking about it earlier
How to change mod data of an item on the ground in multiplayer?
I honestly don't know
finally wait() function
local i = 1
Threaded = THREAD:createThread(function(self)
while true do
--print(coroutine.status(self.coroutine))
print(i)
self:wait(5000)
print(i)
self:wait(5000)
i = i + 1
end
end);
kinda surprised kahlua has the coroutines, but thats handy
same here, I did just try in case if this will work, and... it did, so in a while I release the code
ho shit nice
i had to do all kinds of nonsense to achieve something like that..
with timestamps and a loop
and it had resolution nowhere near that good
(not that that mattered for my purposes)
There isn't a vanilla wait function?
well there is, that's what he's using, I assume it would stop the main thread though, haha
aah
So, I have a problem I can't find a solution around. In my mod that renames items, there are two classes in particular that can't be renamed via normal means, and via previous assistance here, I was able to get them to be renamed by storing their names in the item's moddata
zombie.inventory.types.Moveable
zombie.inventory.types.Radio
However, when the item is placed via the Furniture placing tool, then picked up again, the name resets back to its vanilla name. After further investigation, turns out the game treats items of those two classes differently before and after placing (as in, they're totally two different items). Thus, it's not able to retrieve the name previously stored in moddata
Any idea of how this can be solved?
are there any events associated with placing them?
ur gonna have to track the item from a tile to an item
cuz u can store moddata on a tile
but u can't store it on an item (won't persist)
so u will have to have some kind of table that is saved to track that
i think
and let the name follow it
and restore it to the moddata when it is placed again
ol' chuck is adamant that moddata does persist on items
well then wtf is going on when it doesn't
maybe they fixed it more recently..?
i think i last tried in 41.71
if u wanna verify it
test this mod
works great until u log out and log back into a server
nope, at least not in my code so far, unless you mean vanilla events, which I am not aware of
tho it has another bug
but, what if you have multiple items on one tile?
then u assign it to the square by sprite name or smth
-- multiple items of the same type? (Two premium technology walkie talkies for example)
they would have the same sprite name, no?
you can't have two of those placed in the same square
..?
that'd only be as items
when they are placed they are tiles
u can put them on the ground as items too
but that would retain the item ID tracking system
cuz it ain't a tile
didn't they change them to not be tiles recently
Yeah, just tested an item moddata usage I did for a friend. One weapon with two forms that have separate conditions in each form with the condition stored in the mod data.
The condition of the unused form persisted between restarts.
or did i completely make that up lol
tf
i swear it did not work when i last tried
just to be an even bigger shit disturber, albion here says moddata persists on vehicles too π
i think there's some complexity in moddata, as i've had multiple peopleβ yeah
oh
i guess couldn't hurt to try with tiles. Any sort of online guide though with working with tiles? My experience with tiles is REALLY brief
past me contradicts current me
it is because of what ur storing in the moddata
u can store stuff that won't persist and it'll stay there until u do
i took a look at the linked mod and it was trying to store objects
And what if an item is in a container?
some containers (if not all, no idea) are within the Moveable class, which has the same issue I am facing
Just reread the message, apparently didn't read it correctly the first time
you know what
i'm setting myself a reminder, tomorrow i am going to check what saves moddata and what doesn't
my predicted answer is 'everything' but i've heard so many people sure that vehicles and items don't that there must be some nuance to it
recently vehicles did not, they do now
that one was fact and now is not
the item one i apparently misremembered
i've heard other people say that too though, i wonder where these ideas come from
items in parts save but take a few ticks
bikinihorst stored moddata for vehicles on non-removable parts such as the engine
if I understand correctly, if you change something about an item, a stat or something, that doesn't persist, but moddata does
because it was not saving on a vehicle
it does now store on a vehicle
but for a long time u had to use that as a workaround
he warned me off copying his approach because it is no longer necessary
and he is correct
I use that approach because its actually useful to me, but ya I initially did it at your advice
heh sorry then if i misled u
no its cool
it's def useful to realize u can store it on parts tho
your stuff all runs off the engine right
i just use the vehicle itself now
it'd be a pain to retrieve everything from the vehicle
currently, yes, although I'm trying to flange up some suspension stuff too
im just tagging them with "udderly:lastseen" or something
right now however I'm refactoring because all my code so far has been exploratory and experimental and none of its consistent
i've been storing most of my mod data on parts because it was convenient, the thing i had on the vehicle for me to discover that was made redundant
If I understand correctly, the logic I need to follow is
-> When the player places an item of either classes, the moddata is transferred from the item to the tile
-> When a player picks up an item from a tile, code check if the tile has any moddata, and if so, transfers it to said item?
yes. I don't know if its possible. If there aren't any events then possibly you can decorate the place and pickup methods, but I have no experience with that side of things
also, when did we start calling that "decorating"? What happened to good old fashioned "wrapping"
i tend to call it 'hooking'
you have to sit in a penalty box for doing that where I come from
the image in my head of my code literally being a hook around the original function is strangely strong and pleasant
but items may be dismantled
ugh seems like too complex of an issue to work on at 6AM. I guess imma procrastinate it for now lol. At least I know the way it can be potentially fixed. Thanks for the help!
in my mod a player have to dismantle, clean it, and put in again
Threads with Wait(ms) function
usage:
---@module 'Thread'
local THREAD = require 'Thread'
local i = 1
THREAD:CreateThread(function(self)
while true do
print(i)
i = i + 1
self:Wait(200) -- 0.2 secs
print(i)
i = i + 1
self:Wait(5000) -- 5 secs
end
end);
Should probably upload to workshop as a framework
idk why, but I hate dependency mods, I hope someone finds it useful, (and maybe get some credits lmao)
oh it isn't a vanilla wait
its similar to your interval code from earlier, but using coroutines. neat
any idea what function is called when a player places an item in the world via the furniture tool?
I would've thought I'd find its timed action at least but no luck
did you check Moveables\ISMoveablesAction.lua?
nope, just did. It looks like the one I want, thanks!
okay a couple of questions
so apparently, the function where you place an item gets called after performing a timed action
function ISMoveablesAction:perform()
--some code
--some more code
elseif self.mode == "place" then
self.moveProps:placeMoveableViaCursor( self.character, self.square, self.origSpriteName, self.moveCursor );
buildUtil.setHaveConstruction(self.square, true);
--more code
end
ISBaseTimedAction.perform(self)
end```
What would be the way to fetch the square in my mod code and do stuff before the timed action begins? More precisely, how do I modify a vanilla timed action?
Also what's the difference between a tile, square, and a cell?
Usually you'd make your own subtype of one of the timed action classes to modify a vanilla one.
In this case, however, is there no parameter that's saved as a member of the class (as a field on the self object, in lua-speak)?
re:the tile question, I was looking through the java the other day to try to figure that out myself...
I absolutely have no idea what most of those two sentences meant ngl haha
ISMoveablesAction:new() has an argument called _moveProps which seems to contain the original object, maybe. Its the 3rd argument, if you can find somewhere where it is called
What I came away with was the following: ```
World has one Cell? (Verify this)
Cell is the entire world?
Arbitrary number of Chunks per Cell? (verify this?)
19x19 ish (see IsoChunkMap.ChunkGridWidth) GridSquares per Chunk.
10x10 Tiles per GridSquare.
Tile X/Y refers to a graphical unit within the Cell (World?)
IsoChunkMap.ChunkWidthInTiles -> 190
IsoChunkMap.ChunkGridWidth -> 19
Maybe more questions than answers π , but might help structure it somewhat
Can't find it mentioned anywhere except here in the timed action
well, and a few other places in a the same style
ya, in the perform, you need to find where the action is instantiated in the first place, to find out what data is passed into it
what's a gridsquare though? What's a chunk?
Basically, IsoWorld has an IsoCell (I think only one, but didn't verify).
IsoCell has IsoChunks (I think arbitrary number, but there may be some hardcoded limit which I didn't verify yet).
IsoChunk has around 19x19 (see IsoChunkMap.ChunkGridWidth) GridSquares.
Each GridSquare has 10x10 Tiles.
Tiles are the little units you see that fits a world object.
the files in the folders correspond to chunks if I had to guess... Pretty sure it even says chunks in the filename
I made a search on moveProps in vanilla files. Only mentioned in 3 files, and none of the mentions make a lot of sense to me lol
moveProps is its local name, you're not going to find it in other files
function ISMoveablesAction:new(character, _sq, _moveProps, _mode, _origSpriteName, _moveCursor )
local o = {};
setmetatable(o, self);
self.__index = self;
o.character = character;
o.square = _sq;
o.origSpriteName = _origSpriteName;
o.stopOnWalk = true;
o.stopOnRun = true;
o.maxTime = 50;
o.spriteFrame = 0;
o.mode = _mode;
o.moveProps = _moveProps;
o.moveCursor = _moveCursor;
...
The constructor save the _sq parameter to what should be accessible as self.square in the ISMoveablesAction:perform() function you pasted above.
I made a search on ISMoveablesAction:new as well. Returned the same results
looks like ISMoveablesAction is instantiated by ISMoveableCursor , which passes the props and original spritename and such down
so then we have to keep working our way up until we either find an inventory item or a dead end
another approach is to use debug mode and a breakpoint and see if you can inspect the contents of a ISMoveablesAction while its happening
Question. What happens if I just copy the whole timed action file into the mod files and modify it as needed, and have it overwrite the vanilla one. Is it an "unhealthy" way of doing things?
pitchforks and torches
local original_ISMoveablesAction_perform = ISMoveablesAction.perform
function ISMoveablesAction:perform()
ArendamethUtils.inspect(self.square)
original_ISMoveablesAction_perform(self)
end
What would be the way to fetch the square in my mod code and do stuff before the timed action begins?
squaremight be give you what you asked for originally
It will break any mod that decorates functions of ISMoveablesAction (as the code snippet above does) that loads its lua before yours
aah that makes a lot of sense
gonna try that code snippet
okay ye it does seem to work great after placing the object. My end goal though is trying to fetch the tile the object is placed on. I can't seem to find a getTile function but there is a [getTileInDirection] => function 0x869750, would that be it?
or are they different?
I think the author of that code named the variable square, but what you have represents a single tile (not a GridSquare)
aah interesting. Would moveProps be the item being placed though?
or maybe square and GridSquare are used to represent difference concepts in the design they have. I haven't fully grokked it yet
because I just realised there is no clear variable that defines the item being placed lol
I think so looking at how it is used in the code (o.moveProps.isMoveable, _moveProps:canRotateDirection(), etc). You can look at where it is called and see what variables are passed into the new() function to get a better idea
Oh, maybe _moveProps is not the actual item
--[[
-- The moveprops of the new facing (where applies) are always used to perform the actions, the origSpriteName is passed to retrieve the original object from tile or inventory.
]]
function ISMoveablesAction:perform()
if self.sound and self.sound ~= 0 then
self.character:stopOrTriggerSound(self.sound);
end
if self.moveProps and self.moveProps.isMoveable and self.mode and self.mode ~= "scrap" then
self.moveProps.cursorFacing = self.cursorFacing
if self.mode == "pickup" then
self.moveProps:pickUpMoveableViaCursor( self.character, self.square, self.origSpriteName, self.moveCursor ); --OrigSpriteName currently not used in this one.
elseif self.mode == "place" then
self.moveProps:placeMoveableViaCursor( self.character, self.square, self.origSpriteName, self.moveCursor );
buildUtil.setHaveConstruction(self.square, true);
elseif self.mode == "rotate" then
self.moveProps:rotateMoveableViaCursor( self.character, self.square, self.origSpriteName, self.moveCursor );
end
self.moveProps.cursorFacing = nil
elseif self.mode and self.mode=="scrap" then
self.moveProps:scrapObjectViaCursor( self.character, self.square, self.origSpriteName, self.moveCursor );
end
ISBaseTimedAction.perform(self)
end
The comment suggests the sprite is used to lookup the item in those function calls, self.moveProps:pickUpMoveableViaCursor, etc
lemme try it out since moveProps doesn't seem to work correctly
I am basically trying to retrieve the item's moddata
moveProps has a moveProps.object field, could be the item
function ISMoveableSpriteProps:placeMoveable( _character, _square, _origSpriteName )
... snip ...
local item = self:findInInventory( _character, _origSpriteName );
if item and self:canPlaceMoveableInternal( _character, _square, item ) then
self:placeMoveableInternal( _square, item, self.spriteName )
_character:getInventory():Remove(item);
ISMoveableCursor.clearCacheForAllPlayers();
end
It finds the inventory item there
Are you looking for the inventory item or world object? Or both?
inventory item
well, you'll need both if you're going to move the moddata from one to the other
btw didn't work
actually I am moving the moddata from the inventory item to the tile and then back to the inventory item when the item is picked up
actually may need to transfer moddata to the world object as well considering I'd want to change this
local original_ISMoveablesAction_perform = ISMoveablesAction.perform
function ISMoveablesAction:perform()
ArendamethUtils.inspect(self.square)
local invItem = self.moveProps:findInInventory(self.character, self.origSpriteName)
ArendamethUtils.inspect(invItem)
original_ISMoveablesAction_perform(self)
end
Yea, I presume that's how it'd need to work
was finally one step ahead before you sent this one and currently testing it haha
hold on
why the moveprops in self.moveProps:findInInventory?
function ISMoveableSpriteProps:pickUpMoveable( _character, _square, _createItem, _forceAllow )
if self.isMoveable and instanceof(_character,"IsoGameCharacter") and instanceof(_square,"IsoGridSquare") then
local obj, sprInstance = self:findOnSquare( _square, self.spriteName );
Prob can use findOnSquare like that to get the world object
because moveProps is a ISMoveableSpriteProps object (I hope π ) and you are calling the ISMoveableSpriteProps:findInInventory() function
aaah guess I wasn't one step ahead after all
You could also do ISMoveableSpriteProps.findInInventory(self.moveProps, self.character, self.origSpriteName). That is equivalent
yup I assume it works now since printing item returns zombie.inventory.types.Radio@randomnumber
imma stick to getting it working for now and then polishing to whatever looks better in the end
lemme see if it retains its moddata now
soo apparently local item = self.moveProps:findInInventory(self.character, self.origSpriteName ); works only for Place mode, however it'll return nil if you're attempting to pick that item up. I imagine it behaves differently when picking items up
That's expected. It didn't create the inv item yet
so how do you get the inventory item that it is going to create?
I thought of a logic to get the most recent item in the inventory right after the action is done
but I am not sure if that's even possible
When picking up, findOnSquare should give you the world object that will be picked up
but what if its the inventory item object I am looking for, not the world object?
Mm.. If you're going to copy over the moddata to/fro the inv item and world obj each time either is placed or picked, you'll need both at some point to do that
π€
i guess that's sensible but I am not sure how it helps in particular in fetching the object after its created in the inventory
The problem is basically that the item before its placed in the world is considered item x and after its picked from the world is considered item y
Well, the timed action perform code unfortunately doesn't even have a reference to either of those. You have to go searching for them in ISMoveableSpriteProps anyways... so I think what I'd do is instead of patching the timed action perform, I'd patch those ISMoveableSpriteProps pickup and place functions that perform calls to do the work
the game treats both as two different items and so the moddata isn't retained
aah lemme see how their code looks like in vanilla
function ISMoveableSpriteProps:pickUpMoveableViaCursor( _character, _square, _origSpriteName, _moveCursor )
self:pickUpMoveable(_character, _square, true);
if _moveCursor then
_moveCursor:clearCache()
end
end```
π€
lemme check pickUpMoveable instead
@ancient grail i checked out ur repairable power grid mod. good stuff π π₯
function ISMoveableSpriteProps:pickUpMoveable( _character, _square, _createItem, _forceAllow )
if self.isMoveable and instanceof(_character,"IsoGameCharacter") and instanceof(_square,"IsoGridSquare") then
local obj, sprInstance = self:findOnSquare( _square, self.spriteName );
local items = {};
if obj and (_forceAllow or ISMoveableDefinitions.cheat or self:canPickUpMoveable( _character, _square, not sprInstance and obj or nil )) then
if self.isMultiSprite then
local sgrid = self:getSpriteGridInfo(_square, true);
if not sgrid then return false; end
local createItem = _createItem and not self.isForceSingleItem;
for _,gridMember in ipairs(sgrid) do
table.insert(items, self:pickUpMoveableInternal( _character, gridMember.square, gridMember.object, gridMember.sprInstance, gridMember.sprite:getName(), createItem, _forceAllow ));
end
if _createItem and self.isForceSingleItem then
local spriteGrid = self.sprite:getSpriteGrid();
if not spriteGrid then return false; end
local item = self:instanceItem(spriteGrid:getAnchorSprite():getName());
_character:getInventory():AddItem(item);
end
else
--local obj, sprInstance = self:findOnSquare( _square, self.spriteName );
self:pickUpMoveableInternal( _character, _square, obj, sprInstance, self.spriteName, _createItem, _forceAllow );
end
ISMoveableCursor.clearCacheForAllPlayers();
return items;
end
end
end```
So I believe I just need to reference the ``item`` from that function and modify its moddata?
Need to reference both the inventory item and world object (or at least save their mod data temporarily) and transfer the moddata from the one being destroyed to the one being created. I'm just trying to find the most suitable place so the fewest number of functions have to be patched
There's a whole separate code path for multi-sprite objects. Not even sure what those are yet
is it not possible to just reference the item from the original function?
and then modify its moddata by fetching moddata previously stored on the tile it was placed on?
You could. You'd just need to get the item reference elsewhere e.g. by patching the function that adds the newly created item to the player's inventory
and sort of stitch it all together
In my mind, there is an ideal location where you only have to patch 1 or 2 functions and I'm looking for it even though it probably doesn't exist lol
lol this proves to be more complex that initially anticipated
ahh i have a suggestion.. create a skin texture thats just totaly empty png. wear that on the cameraman
and make him use debug follow player
so you have auto follow to the main character and you cant see yourself and he cant see u too.... pres record then viola. i dont have any ideas thats eadier to do excpt for this π¦
if self.isoType == "IsoRadio" or self.isoType == "IsoTelevision" then
if instanceof(_object,"IsoWaveSignal") then
local deviceData = _object:getDeviceData();
if deviceData then
item:setDeviceData(deviceData);
else
print("Warning: device data missing?>?")
end
end
end
You can see where the vanilla code conceptually does what you're trying to do, but with device data instead of mod data
and further below it does it with mod data, in fact
but that stores it in the world object, no?
That gets it from the world object and saves it to the inv item
oh
if instanceof(_object, "IsoThumpable") then
item:getModData().name = _object:getName() or ""
item:getModData().health = _object:getHealth()
item:getModData().maxHealth = _object:getMaxHealth()
item:getModData().thumpSound = _object:getThumpSound()
item:getModData().color = _object:getCustomColor()
if _object:hasModData() then
item:getModData().modData = copyTable(_object:getModData())
end
else
if _object:hasModData() and _object:getModData().movableData then
item:getModData().movableData = copyTable(_object:getModData().movableData)
end
if _object:hasModData() and _object:getModData().itemCondition then
item:setConditionMax(_object:getModData().itemCondition.max);
item:setCondition(_object:getModData().itemCondition.value);
end
end
similarly, here
That's sort of the idea of what you want to do
where is item defined?
It is created above, but it is stored in a local variable, so can't directly get a reference to it```lua
local item = self:instanceItem(_spriteName);
well its kind of the whole issue right now is that we can't reference the object that is being created in the inventory
at least not in a really elegant way
So for the pickup up case, I'd patch:```
ISMoveableSpriteProps:pickUpMoveable (transfers moddata: world object -> inv item. Uses findOnSquare to get the world object)
ISMoveableSpriteProps:pickUpMoveableInternal (need this only for multi-sprite objects, idk if that's important for you)
AddItem (to get the inv item reference)
based on your earlier code snippet, I believe this is the way you'd patch pickUpMoveable?
local original_ISMoveableSpriteProps_pickUpMoveable = ISMoveableSpriteProps.pickUpMoveable
function ISMoveableSpriteProps:pickUpMoveable()
--do stuff
original_ISMoveableSpriteProps_pickUpMoveable(self)
end
Yes, however you do need to pass along all the function parameters
and return the return value of the original
why didn't we do that here?
