#mod_development

1 messages ยท Page 38 of 1

ancient grail
#

what is it are you building again?

#

look at teleport mod ๐Ÿ˜‰

#

if he do this then he use his own util function using

Padd_Utils[3]()<
????

gaunt meteor
#

why are there separate perks for Maintenence, BladeMaintenence and BluntMaintenence?

kindred dagger
#

Anyone knows how to get the item type of a placed world object? I don't have issue finding the objects with a cell:getObjects() just getting the string I need.
Specifically I'm trying to have Ham Radio placed in the world (like furniture) to return me "HamRadio1" or "Base.HamRadio1" whatever works. I've tried to do getName() or getType() with no luck so far.

blissful salmon
#

I think I can store mysettings in the moddata of a zombie. and load from there if I restart the game. Where do I find " onload chunks" I didn't find any event or something like this.

ancient grail
thick karma
#

I'm considering the implications of playing with setHoursSurvived clientside. So far, I've heard that getHoursSurvived may play a role in certain rates, e.g., panic reduction, but I don't see that in the Lua. In the Lua, however, I do see getHoursSurvived being used to determine whether it's too soon to sleep. Does it get used all over the place on the Java side or something?

hearty dew
#
$ grep -r getHoursSurvived ProjectZomboid/zombie/
grep: ProjectZomboid/zombie/ai/sadisticAIDirector/SleepingEvent.class: binary file matches
grep: ProjectZomboid/zombie/ai/ZombieGroupManager.class: binary file matches
grep: ProjectZomboid/zombie/characters/BodyDamage/BodyDamage.class: binary file matches
grep: ProjectZomboid/zombie/characters/Faction.class: binary file matches
grep: ProjectZomboid/zombie/characters/ILuaGameCharacter.class: binary file matches
grep: ProjectZomboid/zombie/characters/IsoGameCharacter.class: binary file matches
grep: ProjectZomboid/zombie/characters/IsoPlayer.class: binary file matches
grep: ProjectZomboid/zombie/GameTime.class: binary file matches
grep: ProjectZomboid/zombie/iso/areas/SafeHouse.class: binary file matches
grep: ProjectZomboid/zombie/network/GameClient.class: binary file matches
grep: ProjectZomboid/zombie/network/GameServer.class: binary file matches```
It's referenced in those classes
thick karma
#

Hmmm yeah I'm not going to be able to counteract all that realistically. Hmmm...

#
            if (isoPlayer != null && !"Tutorial".equals(Core.GameMode) && this.getHoursSurvived() > 0.016666666666666666) {
                HaloTextHelper.addTextWithArrow(isoPlayer, invokedynamic(makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;, perk.getName()), true, HaloTextHelper.getColorGreen());
            }

This chunk of Java in LevelPerk is proving to be the bane of my existence.

#

I wrote a sneaky way of making it not happen by playing with getHouseSurvived() (locking it to 0 and storing it elsewhere while the HUD is off).

#

But this unfortunately has gameplay side effects, and aside from the sleeping side-effects I do not know how to mitigate them... and mitigation of the sleeping side effects could have other side effects. (Also likely Agoraphobic and Claustrophobic panic-related side effects.)

#

I kinda wish I could just mod that Java class and rewrite that condition with an extra boolean variable, "burryagaWantsToSeeYou" ๐Ÿคช

hearty dew
#

Is the method with that conditional called from lua? If so, you could set hours survived before it is called and revert it immediately after

thick karma
#

Unfortunately I don't know. Maybe? Possibly in ISPlayerStatsUI?

    if button.internal == "LEVELPERK" then
        self.char:LevelPerk(self.selectedPerk.perk, false);
        self.char:getXp():setXPToLevel(self.selectedPerk.perk, self.char:getPerkLevel(self.selectedPerk.perk));
        SyncXp(self.char)
        self:loadPerks();
        if self.selectedPerk.perk == Perks.Strength or self.selectedPerk.perk == Perks.Fitness then
            self:loadTraits();
        end
    end
#

I don't know if LevelPerk above is the correct or only important place LevelPerk gets called

#

And also in tons of debug scenarios maybe?

#

Those shouldn't matter because when you're initializing those scenarios getHoursSurvived would be < .01666 [1 minute]

#

I see a lot of getPlayer():LevelPerk(...) in Steps.lua

#

Idk what Steps is for... just to track walking stuff?

#

XpUpdate.lua seems to have its own special levelPerk function, but it doesn't explicitly call LevelPerk anywhere, so that's confusing.

#

This chunk seems to call LevelPerk... not sure what the ISSkillProgressBar refers to.

function ISSkillProgressBar:onMouseUp(x, y)
    -- our selected lvl
    local lvlSelected = math.floor(self:getMouseX()/20);
    -- if you have skill pts and the skill is ready to evolve and if you clicked on the right lvl
    if self.xp >= self.xpForLvl and self.level == lvlSelected and not self.perk:isPassiv() then
        self.char:LevelPerk(self.perk:getType());
      ...
      ...
      ...
end
#

Also

function ISChallenge2PlayerUpWindow:onOptionMouseDown(button, x, y)
    local playerObj = self.char
    -- manage the item
    playerObj:getModData()["challenge2Xp"] = playerObj:getModData()["challenge2Xp"] - button.cost;
    if button.internal == "skills" then
        -- we add the xp for this skill, so the xp panel will be updated
        playerObj:LevelPerk(button.perk);
      ...
      ...
      ...
#

All these different params are confusing me, too. Not clear if LevelPerk needs 1 or 2 or what. Not sure if they're even calling same function

#

Assuming it's a function with optional params but that's an assumption

#

Okay on the Java side it's these two functions:

#

That keep getting called mostly

#

afaik

#

I don't think I have a corresponding function I can decorate but idk I could be missing it

#

I mean I think I would still release the mod as is and just warn people that the No-XP mode is only for making movies, and causes issues for gameplay, but I would greatly prefer to find a workaround that hides XP harmlessly ๐Ÿ˜ญ

#

But then again they can just turn off XP growth if they want to make movies...

#

sigh

#

So close

hearty dew
thick karma
#

Really??? I can just do


function __classmetatables[zombie.characters.IsoPlayer.class].__index.LevelPerk(...) 

end```
?
hearty dew
#

--[[
    Usage example:
    
    BurryagaUtils.patchClassMethod(zombie.inventory.types.Moveable.class, "getDisplayName", function(original_fn)
            return function(self, arg1, arg2, ...)
                local modData = self:getModData()
                if modData and modData.new_value then
                    return modData.new_value
                end
                local result = original_fn(self, arg1, arg2, ...)
                result.someProperty = false
                return result
            end
        end)
]]
BurryagaUtils.patchClassMethod = function(class, methodName, createPatch)
    local metatable = __classmetatables[class]
    if not metatable then
        error("Unable to find metatable for class "..tostring(class))
    end
    local metatable__index = metatable.__index
    if not metatable__index then
        error("Unable to find __index in metatable for class "..tostring(class))
    end
    local originalMethod = metatable__index[methodName]
    metatable__index[methodName] = createPatch(originalMethod)
end

Can use that to simply doing it in general

thick karma
#

Stfu really that would work?

#

Where did you find this insanity? Where is __classmetatables anywhere?

hearty dew
#

Looks to be how kahlua exposes java objects to the lua side. @undone elbow mentioned it a few days back

thick karma
#

Can I write [anything].[anything] is is [anything].patchClassMethod a key function that Lua has somewhere?

hearty dew
#

__classmetatables is in _G

hearty dew
thick karma
#

So I just call it once and the method is patched?

#

And I can name the method patcher essentially anything?

hearty dew
#
    BurryagaUtils.patchClassMethod(zombie.characters.IsoPlayer.class, "LevelPerk", function(original_fn)
            return function(self, perk, b1)
                -- pre stuff
                local result = original_fn(self, perk, b1)
                -- post stuff
                return result
            end
        end)
thick karma
#

Whoa.

hearty dew
#

It patches the calls to that java method from the lua code. Doesn't affect java->java calls of that method

thick karma
#

Whoa.

thick karma
visual abyss
#

it's a global table that is built in lua language

#

basically think of it as Lua lives inside _G

hearty dew
#

Anything that's not declared local goes into _G. Can think of it is as the table that implements the broadest scope.

function myGlobalFunction() end
myGlobalVariable = 5
print(_G.myGlobalFunction)
print(_G.myGlobalVariable)
thick karma
#

Is there a way to see this info online anywhere? Are y'all just decompiling the Java? Where is this information discovered? How did anyone figure out __classmetatables was hiding in the global scope?

visual abyss
#

it's completely built into lua

#

every application that uses lua has it

#

even wow's addon system

#

it's how lua operates

#

Read the answer

thick karma
#

Damn okay thanks

#

This is straight-up black magic

hearty dew
#
GitHub

Kahlua main development. Contribute to krka/kahlua2 development by creating an account on GitHub.

GitHub

Kahlua main development. Contribute to krka/kahlua2 development by creating an account on GitHub.

thick karma
#

I hear what you're really telling me

#

@visual abyss @hearty dew I'm gonna try this and if it works I'm reading both of these links until I cry

visual abyss
#

is there a list of modifiers that weapon part can improve/decrease

hollow current
#

How do you add a mod option that is modifiable only in mp servers by server admins?

hearty dew
#

Wouldn't sandbox vars do the trick?

#

Do you mean modifiable while the server is running?

hearty dew
thick karma
#

Halp? @hearty dew

#

Seems to imply metatable__index is not a table?

#

Even though it does exist?

gilded hawk
#

Can someone explain me why this works

FactionMapClass = {}

function FactionMapClass:new()
    local o = {}
    setmetatable(o, self)
    self.__index = self
    return o
end

function FactionMap()
    FactionMapClass.instance = FactionMapClass.instance or FactionMapClass:new()
    return FactionMapClass.instance
end

But this, does not work

FactionMapClass = {}

function FactionMapClass:new()
    --
    local o = FactionMapClass
    setmetatable(o, self)
    self.__index = self
    return o
end

function FactionMap()
    FactionMapClass.instance = FactionMapClass.instance or FactionMapClass:new()
    return FactionMapClass.instance
end

@hearty dew If you can help, this is about what we talked yesterday about making classes, and singletons

#

When I use the second code vscode gives me auto complete and intellisense on FactionMap

#

While on the first one it does not

hollow current
gilded hawk
hollow current
#

Ah, thanks!

gilded hawk
hearty dew
# thick karma

Idk what that is. Need the actual error message from the console.txt ๐Ÿ˜…

thick karma
#

Attempted index of non-table?

#

I tried scrolling to most recent

hearty dew
#

The debug ui breaks before printing the error message

#

so it will highlight the problem and not tell you what it is until you step forward

thick karma
#

I did step forward

hearty dew
#

often easier to just look at console.txt imo

thick karma
#

I took one step past the break

#

But I can open console.txt

#

That's in user/Zomboid right?

hearty dew
#

yea

thick karma
#

Uhhhh lmao

#

Something about trying to patch this way is really making Zomboid mad

#
function: DawnOfTheZed.lua -- file: DawnOfTheZed.lua line # 156 | MOD: Dawn of the Zed (Hide XP Notifications)

LOG  : General     , 1666181454514> attempted index of non-table
LOG  : General     , 1666181454642> creating new sourcewindow: C:/Users/Zen/Zomboid/Workshop/Dawn of the Zed/Contents/mods/DawnOfTheZedHideXP/media/lua/client/DawnOfTheZed.lua
LOG  : General     , 1666181493592> UNKNOWN GLFW KEY CODE: 283
LOG  : General     , 1666181493592> UNKNOWN GLFW KEY CODE: 283
LOG  : General     , 1666181493753> UNKNOWN GLFW KEY CODE: 283
LOG  : General     , 1666181493753> UNKNOWN GLFW KEY CODE: 283
LOG  : General     , 1666181493909> UNKNOWN GLFW KEY CODE: 283
LOG  : General     , 1666181493910> UNKNOWN GLFW KEY CODE: 283
LOG  : General     , 1666181531085> EXITDEBUG: RenderThread.isCloseRequested 1
hearty dew
hearty dew
thick karma
#

Okay, I launched without this, and then reloaded Lua with this, and got the errors above... so I think this is the fundamental issue, one way or another:

    local metatable = __classmetatables[class]
    if not metatable then
        error("Unable to find metatable for class "..tostring(class))
    end
    local metatableIndex = metatable.__index
    if not metatableIndex then
        error("Unable to find __index in metatable for class "..tostring(class))
    end
    local originalMethod = metatableIndex[methodName]
    metatableIndex[methodName] = createPatch(originalMethod)
end```
#

(Tried with metatable__index, too, I just renamed it. Neither works.)

gilded hawk
hearty dew
hearty dew
#

Maybe there is a way to annotate the code so that intellisense can do the autocompletion you want

thick karma
hearty dew
#
LOG  : General     , 1666182204624> 328,279,713> -----------------------------------------
STACK TRACE
-----------------------------------------
function: stuff -- file: objects.lua line # 221 | Vanilla
function: console -- file: objects.lua line # 1 | Vanilla

LOG  : General     , 1666182204629> 328,279,718> attempted index of non-table
ERROR: General     , 1666182204634> 328,279,723> ExceptionLogger.logException> Exception thrown java.lang.RuntimeException: attempted index of non-table at KahluaUtil.fail line:82.
ERROR: General     , 1666182204639> 328,279,728> DebugLogStream.printException> Stack trace:
java.lang.RuntimeException: attempted index of non-table
        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.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:1991)
        at zombie.core.Core.updateKeyboard(Core.java:2322)
        at zombie.core.Core.DoFrameReady(Core.java:3083)
        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)
LOG  : General     , 1666182204645> 328,279,734> -----------------------------------------
STACK TRACE
-----------------------------------------
function: stuff -- file: objects.lua line # 221 | Vanilla
function: console -- file: objects.lua line # 1 | Vanilla

That's the error I got when running that

#

line 221 is

BurryagaUtils.patchClassMethod = function(class, methodName, createPatch)```
#

Add ```lua
BurryagaUtils = BurryagaUtils or {}

above that line
thick karma
#

Ohhhhhhhhhhhh

#

That explains why I didn't get stuck there the first time I ran your code

#

The first time I ran it I renamed that to a normal function and got all the way into the game

#

No issues, but it didn't work, so I reverted to your version verbatim and got that error

hearty dew
#

๐Ÿ‘

thick karma
#

Okay error is good now, relaunching to see if verbatim version works

hearty dew
#

Maybe your line numbers were off? Sometimes you have to click reload file in the debug ui's file viewer to get the correct lines

thick karma
#

I don't know why that happened that way, but it identified the end of the function instead of the call to it as the issue. It seemed to know that function was an issue but didn't tell me why very well

#

the end caught the highlight in my debug even though it told me to check line 156

hearty dew
#

The debug ui is trying to be too helpful maybe, heh

thick karma
#

line 156 was just the last line of the function that went bad though

#

I think that was why it got flagged

#

๐Ÿ˜ญ no dice @hearty dew

#

Hmmm

#

let me see

gilded hawk
thick karma
#

@hearty dew Okay, so I tried this... no errors, but it doesn't seem to 0 the HoursSurvived before the crucial moment, because I am still seeing the level-up notifications... Any brilliant suggestions?

local function zeroSurvivedTime()

    for playerIndex = 0, getNumActivePlayers() - 1 do

        local player = getSpecificPlayer(playerIndex)

        if player and not ISUIHandler.allUIVisible then 

            player:Say("I'm patched mothafucka")
        
            backupHoursSurvived = backupHoursSurvived + player:getHoursSurvived()
            player:setHoursSurvived(0.0)
        
        end

    end

end

patchJavaMethodB = function(class, methodName, createPatch)
    local metatable = __classmetatables[class]

    if not metatable then
        error("Unable to find metatable for class " .. tostring(class))
    end

    local metatableIndex = metatable.__index

    if not metatableIndex then
        error("Unable to find __index in metatable for class " .. tostring(class))
    end

    local originalMethod = metatableIndex[methodName]
    metatableIndex[methodName] = createPatch(originalMethod)
end

patchJavaMethodB(zombie.characters.IsoPlayer.class, "LevelPerk", 
    function(metatableMethod)
        return function(self, perk, booleanFlag)
            zeroSurvivedTime()
            local result = metatableMethod(self, perk, booleanFlag)
            -- restoreSurvivedTime()
            return result
        end
    end
)```
#

(Doesn't work when named Burryaga.etc either, tested that first.)

#

The call to zeroSurvivedTime should fire every time LevelPerk gets a call from Lua, right?

#

Wait.... idea

thick karma
#

There are 2 LevelPerk functions on Java side

#

Is it possible this only targets one?

#

Is there a way to target both? I seem to only ID the method by its name, but Java IDs by name and # of params

hearty dew
#

No, it will handle both. There is only one lua side

#

lua doesn't have function overriding like java

thick karma
#

Hmmm well it does not seem to be patching... I can't even get it make the player talk

#

I tried including a player:Say() in my patched function and nothin came out

hearty dew
#
            zeroSurvivedTime()
            print("Hours survived after zeroing are: "..self:getHoursSurvived())
            local result = metatableMethod(self, perk, booleanFlag)
#

would do something like that to verify the code does what I expect

thick karma
#

On it

hearty dew
#

btw, you could pass in self as a param to zeroSurvivedTime to limit the change to that player

#

(self is a player object in that context)

hollow current
thick karma
#

zeroSurvivedTime WILL hide the xp notice if I run it OnTick

hearty dew
gilded hawk
hollow current
#

i will give it a look, thanks!

hearty dew
#

I'd try calling the method via the player object in the lua console

#
getSpecificPlayer(0):LevelPerk(foo, bar)
thick karma
#

Hmmmmmmm that actually did get a reaction.

#

Also, an error I believe

#

Hmm I need a real perk ref

hearty dew
#

If in this scenario you are testing the method is being called java->java, that would explain it not firing because this approach only will patch the method when called from lua

thick karma
#

I see.

#

Dang.

#

So my wonky method remains the best option I have

#

Oof

hearty dew
#
$ grep -r LevelPerk ProjectZomboid/zombie/
grep: ProjectZomboid/zombie/characters/ILuaGameCharacter.class: binary file matches
grep: ProjectZomboid/zombie/characters/IsoGameCharacter$XP.class: binary file matches
grep: ProjectZomboid/zombie/characters/IsoGameCharacter.class: binary file matches
grep: ProjectZomboid/zombie/Lua/LuaEventManager.class: binary file matches

Not that many classes call LevelPerk though

thick karma
#

Is there something I could do to mod the calls Java->Java from those classes?

#

To zero the offending variable at the perfect times?

hearty dew
#

depends on how they are called

#

Wouldn't be able to intercept the call, but perhaps could patch the calling method

thick karma
#

What tool do y'all recommend to decompile the Java?

#

I clearly need to read those files

#

And possibly others

hearty dew
hearty dew
thick karma
#

Thanks

thick karma
#

(Creating a search flag for myself ๐Ÿคช )

#

I'm going to need these when I get this decompiled

#

Not sure if I'll have time to finish this morning

hearty dew
#
 player:getXp():AddXP(Perks.MetalWelding, 15)
#

Looks like most of the ways vanilla lua-side adds xp is this way, not using LevelPerk

#

What exactly is the problem you are trying to solve by stopping xp additions?

thick karma
#

My goal is to mute the popup that tells you when you've leveled up... If I could jump in before AddXP and jump out after the determination has been made regarding whether that XP levels you up, that would be perfect. I tried earlier to hook AddXP using Events.Add but it didn't work because my function would fire after the player was already done leveling.

#

I just do not want to see the green text above character's head

#

The sound is acceptable, though tbh I'd also love to get rid of that. (But only while the HUD is invisible.)

thick karma
fast galleon
#

Maybe patch the halonote altogether?

hearty dew
#

I presume you looked into patching IsoPlayer:Say already? That's a quick thing to try

thick karma
#

I don't know how I would patch Say to prevent that... This seems to be crucial afaik, courtesy of albion:

public void LevelPerk(final PerkFactory.Perk perk, final boolean b) {
        Objects.requireNonNull(perk, "perk is null");
        if (perk == PerkFactory.Perks.MAX) {
            throw new IllegalArgumentException("perk == Perks.MAX");
        }
        final IsoPlayer isoPlayer = (IsoPlayer)Type.tryCastTo((Object)this, (Class)IsoPlayer.class);
        final IsoGameCharacter.PerkInfo perkInfo = this.getPerkInfo(perk);
        if (perkInfo != null) {
            final IsoGameCharacter.PerkInfo perkInfo2 = perkInfo;
            ++perkInfo2.level;
            if (isoPlayer != null && !"Tutorial".equals(Core.GameMode) && this.getHoursSurvived() > 0.016666666666666666) {
                HaloTextHelper.addTextWithArrow(isoPlayer, invokedynamic(makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;, perk.getName()), true, HaloTextHelper.getColorGreen());
            }
            if (perkInfo.level > 10) {
                perkInfo.level = 10;
            }
            if (GameClient.bClient && isoPlayer != null) {
                GameClient.instance.sendSyncXp(isoPlayer);
            }
            LuaEventManager.triggerEventGarbage("LevelPerk", (Object)this, (Object)perk, (Object)perkInfo.level, (Object)true);
            if (GameClient.bClient && isoPlayer != null) {
                GameClient.sendPerks(isoPlayer);
            }
            return;
        }
        final IsoGameCharacter.PerkInfo e = new IsoGameCharacter.PerkInfo(this);
        e.perk = perk;
        e.level = 1;
        this.PerkList.add(e);
        if (isoPlayer != null && !"Tutorial".equals(Core.GameMode) && this.getHoursSurvived() > 0.016666666666666666) {
            HaloTextHelper.addTextWithArrow(isoPlayer, invokedynamic(makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;, perk.getName()), true, HaloTextHelper.getColorGreen());
        }
        if (GameClient.bClient && this instanceof IsoPlayer) {
            GameClient.instance.sendSyncXp(isoPlayer);
        }
        LuaEventManager.triggerEvent("LevelPerk", (Object)this, (Object)perk, (Object)e.level, (Object)true);
    }
#

Notice it only calls addTextWithArrow when your HoursSurvived is above a minute

thick karma
thick karma
hearty dew
thick karma
#

Fair.

hearty dew
#

idk, I'd figure out what's actually causing those messages overhead, and try to work from there how to prevent it from occurring for the cases you're interested in

thick karma
#

That is the only thing I seek to prevent from happening by setting HoursSurvived to 0

hearty dew
#

Ah, okay. So either in that method call, addTextWithArrow, maybe there is some way to prevent it, or calls to LevelPerk or AddXp could be patched (which is the direction you were going)

thick karma
#

And afaik the only ways to prevent it are for HoursSurvived being 0, or being in Tutorial, or not having a valid player object.

thick karma
#

I need to see that function probably

#

Events on AddXp and LevelPerk were a bust because they always fire after I level

#

If only there were an Xp message duration variable somewhere

#

and I could just make that 0

#

Wouldn't that be nice

hearty dew
#

Didn't see a way to do it down the addTextWithArrow route. That seems to all be done java side as far as I checked.

#

That's the IsoPlayer:getXp() object. I'd try patching AddXP

thick karma
hearty dew
#

zombie.characters["IsoGameCharacter$XP"].class believe it would be

thick karma
#

Oh you mean patch the actual call to AddXP

#

From Lua->Java

hearty dew
#

yea

thick karma
#

Not just Events.AddXP.Add

#

Mmmm I will try that actually

thick karma
hearty dew
#

They are this

thick karma
#

How the heck can Lua take such a range of inputs for various Java methods and send them where they belong? return function(self, perk, float, boolean1, boolean2, boolean3)?

#

What single super-return would apply to all three versions of AddXP ?

#

if they're so wildly different?

#

Is Handweapon even a Perk?

#
patchJavaMethodB(zombie.characters["IsoGameCharacter$XP"].class, "AddXp", 

    function(metatableMethod)

        return function(self, perk, booleanFlag)

            -- Hopefully before.
            zeroSurvivedTime()
            self:Say("Why, hello, there!")
            print("Hours survived after zeroing are: "..self:getHoursSurvived())
            
            local result = metatableMethod(self, perk, booleanFlag)
            
            -- Hopefully before.
            restoreSurvivedTime()
            
            return result

        end

    end

)
```?
#

Would (self, perk, booleanFlag) become (self, perk, float, boolean1, boolean2, boolean3)?

fast galleon
#

btw why you're on it, can you tell me why most times I won't get the skill level up note above player

hearty dew
hearty dew
thick karma
#

Really???!?

#

Like this?

patchJavaMethodB(zombie.characters["IsoGameCharacter$XP"].class, "AddXp", 

    function(metatableMethod)

        return function(...)

            zeroSurvivedTime()
            self:Say("Why, hello, there!")
            print("Hours survived after zeroing are: "..self:getHoursSurvived())
            local result = metatableMethod(...)
            restoreSurvivedTime()
            return result

        end

    end

)
hearty dew
#
return function(self, ...)
  metatableMethod(self, ...)
end

(I presume you want to use self?)

thick karma
#

yeah good idea

hearty dew
thick karma
#

Yeah I forgot but thank you

#

Wow

#

So AddXp is void so I can stop returning the void, yeah?

hearty dew
#

yea

hollow current
#

also are there more fields that can be utilized apart from those 3?

pine fiber
hollow current
#

was struggling to find mods that used sandbox options, but thanks!

pine fiber
thick karma
# hearty dew yea

Omg I think I hooked AddXP (which apparently is the spelling in Java, WHYYYYYYY?)

#

I don't know if it's gonna work yet because I threw an error from it, but progress!

#

OMFG I THINK IT WORKED

#

@hearty dew You truly must let me send you coffee

placid delta
#

is there an Event for pickup item / transfer item to inventory?

hollow current
summer rune
#

can u use lua to spawn an ATM in the game at a specific coordinate? (like if someone would have placed it in the game by hand)

pine fiber
thick karma
#

@hearty dew Omg it works perfectly

hollow current
#

aaa okay thanks!

thick karma
#

It's tracking HoursSurvived and acting like it's not

#

It's so beautiful, kill me now while I'm happy guys

marble lynx
#

face the wall

visual abyss
#

so i'm wondering if it's possible to have a gun support different type of mags (like 5 round mag and 10 round mag)

#

or do i need to make new item gun for each mag supported?

#

i tried magtype=mag1;mag2,

hearty dew
#

Believe arsenal mod does that. I don't know offhand how though

visual abyss
#

or whatever it was

hollow current
#

soo is it normal for it to look like this?

visual abyss
#

but it didnt really wor klolol

visual abyss
hearty dew
hearty dew
#

yea

fast galleon
pine fiber
hollow current
#

Got it it to work, thanks so much!

hearty dew
#

@hollow current
media/sandbox-options.txt

VERSION = 1,

option nostartingbelts.blacklist
{
    type = string,
    default = Belt;Belt2,
    page = nostartingbelts,
    translation = nostartingbelts_blacklist,
}

media/lua/shared/Translate/EN/Sandbox_EN.txt

Sandbox_EN = {

    Sandbox_nostartingbelts = "No Starting Belts",

    Sandbox_nostartingbelts_blacklist = "Blacklisted items",
    Sandbox_nostartingbelts_blacklist_tooltip = "Semicolon separated list of blacklisted item identifiers. Only these items will be removed on newly created characters. Any other items will allowed on newly created characters. Only use either the Blacklist or Whitelist. Do not use both. E.g. Belt2;Base.Belt;Glasses_Normal",
}

Some lua file

print(SandboxVars.nostartingbelts.blacklist)
visual abyss
#

interesting. i see it now. using moddata to add another mag

#

then basically editing the actual item's mag type

#

oh man this will do.

#

i need to learn moddata

#

i know of it but i'm not well informed with it. is there any info on it that i can read?

fast galleon
#

I want to get the same time for a time action, independent of sandbox.
120 * getGameTime():getMinutesPerDay()
This is some code I found ways back, will it work?

visual abyss
#

that makes sense to me on paper

#

well

#

maybe

blissful salmon
#

Is it possible to print to the console.txt from lua? print only appears in the debug console...

visual abyss
#

it already prints to it

#

print() prints to the console and console.txt

visual abyss
blissful salmon
#

I'm confused now... I'll check again... Maybe I need a break...

visual abyss
#

if the time was left alone, it would be just 100% (normal speed)

visual abyss
blissful salmon
#

Sorry, I just was blind...

visual abyss
#

no worries

fast galleon
#

Is default something constant or does it change

visual abyss
#

idk. i'm sure you can find it somewhere

#

i've never touched that sort of thing yet

#

just giving you the math

#

basically you want to get the % change from the default time

#

so if the gametime was 2x faster

#

that's 150%

#

60 * 1.50 = 90 which should be at same pace

#

as 60

hollow current
#

quick question, so the sandbox option appears in SP options, but not when creating the world in say, Hosted server, any idea why?

visual abyss
#

tail txt in terminal

#

here

#

if you need - i use powershell: Get-Content PATH_TO_CONSOLE_TXT -Tail 100 -Wait

#

it'll act like a live feed logger for you in the terminal

fast galleon
visual abyss
#

you probably could try finding out what the default speed

#

and just set it as a constant in your lua scripts

blissful salmon
#

Did you managed to solve the object problem?

visual abyss
#

nah

#

i dropped it for now

#

i'd like some actual progress so i'm working on other stuff lol

#

i'll circle back around later

#

beside it's not too important right now in term of required mechanism

blissful salmon
#

ok... did my last suggestion with getting the object also fail or is the object not on the square itself? I did this to check if there is a fence on the square...

#

ok

visual abyss
#

so if i understand how moddata() works, it's a table with extra entries that isnt supported by vanilla in txt script?

#

its already done automatically by their vanilla parsing so i don't need to do anything to parse it

fast galleon
#

I don't see a default minutes per day, but there is a getDeltaMinutesPerDay which returns MinutesPerDayStart / MinutesPerday

undone elbow
#

What is the most early event when sandbox vars are already loaded from save or received from server?

visual abyss
fast galleon
#

InitGlobalModData is the one that works for both I think

visual abyss
#

idk

hearty dew
#

The tricky thing is that the sandbox variables can be created earlier (and populated with the default), but the configured values aren't loaded until later

fast galleon
#

sandbox are loaded after onInitWorld

placid delta
#

does the event
Events.EveryOneMinute
happen every minute ingame time? or in real life time 1 minute?

hearty dew
#

in game time

hearty dew
#

They behave differently

visual abyss
#

i'm guessing the former

#

looking at arsenal

#

Gun:getMagazineType() ~= "Base.Fixed"

#

err

#

wrong one

#

local Ext = Gun:getModData().ExtMagType

#

ExtMagType is an entry in the item script

#

which is obviously not supported by vanilla

hearty dew
#

That's mod data on that object (gun inventory item, I presume)

#

global mod data is accessed through functions in the GlobalObject. I think it's modData()?

#

There's a nice writeup for global mod data. I'll try to find it

visual abyss
#

that would be appreciated

hearty dew
#

global mod data has to be manually synchronized

#

Mod data on objects, I understand, is synchronized automatically.

#

I haven't used it personally, so I'm not 100% certain

hearty dew
#

Think of (non-global) mod data as a table that pz will persist automatically for you on that object. In it you can put basic lua types, nested tables, strings, numbers, etc

hearty dew
#

When you go through that UI to mess with server configurations, it doesn't automatically reload the lua files for the mods that should be activated as it does in singleplayer. So you run into situations where sandbox vars are missing

glacial flicker
#

Quick question, is there a mod that disables military gear and zombies?

#

I need that

hearty dew
safe silo
#

I have two questions:

  1. Is it possible to remove an item from being wieldable? (Wield as Primary, Wield as Secondary)

  2. Is it possible to TURN OFF a drainable item when it enters the inventory? Best example would be for turning a flashlight off once it enters the inventory. I could probably adapt the vanilla code for attaching walkie-talkies to the belt would turn it off but cant find that code

visual abyss
#
  1. wouldn't that be determined by type?
jade chasm
#

hey does anyone know where the scripting is that starts spawning katanas in zombies after 60 days?

safe silo
hearty dew
#

believe it was the attachedWeapon loot table

#

.

undone elbow
#

What function of IsoPlayer returns the visible name in mp?

hearty dew
#

that's getDisplayName, I believe

bronze yoke
blissful salmon
#

I played with the walktypes of the zombies. Personally I think there is a big gap between "5" and "sprint1". Is it possible to speed up walking a bit? I tried it with setSpeedMod (IsoGameCharacter) but I didn't notice a speedchange.

zombieData.WalkType = "5"
zombie:setSpeedMod(2)
undone elbow
hearty dew
#

Maybe getForname?

#

I'm not sure which is displayed tbh. It might change in steam/nosteam. And I vaguely remember there an option to change whether the player name or username/steamid is shown.. I don't know ๐Ÿ˜…

#

getForname is wrong. It returns some hardcoded string, 'Bob'. getFullName returns the characters name

undone elbow
#
player:getForname() -- just "Bob", despite the full name is "Kathie Robb"
visual abyss
#

I have a gun with a custom entry

item gun
{
    AmmoType1 = ammo1,
}

and when i try to do gun:getModData().AmmoType1 it just returns nil

#

am I missing something

hearty dew
#

Moddata doesn't read from custom entries like that as far as I know. I haven't seen that before, at least

undone elbow
#

@hearty dew Okay, nevermind and thanks. I guess it's too difficult to get quick workaround.

visual abyss
#

This is in vanilla source

#

so on forth

#

๐Ÿค”

hearty dew
#
        _obj:getModData().RadioItemID = worldItem:getID()

Is it not set via lua as well?

visual abyss
#

i know the param is successfully added LOG : General , 1666197757747> adding unknown item param "AmmoType1" = "newammo2""

#

in Item.java line 2623

#

in void DoParam()

blissful salmon
hearty dew
#
     key.copyModData(this.DefaultModData);

Hmm.. yea, it looks like it puts it into DefaultModData and, it should copy over the default when creating an item instance

jade chasm
visual abyss
#

yeah

visual abyss
#

its because of that

#

had to delete gun in my inventory

hearty dew
visual abyss
#

and spawned another one

blissful salmon
visual abyss
#

awesome thanks

blissful salmon
#

this works for me...

fallow nova
#

allo, is it possible to check if another mod is enabled using lua? google isn't helping much

hearty dew
#
if getActivatedMods():contains("modidnotworkshopid") then
fallow nova
#

legend

#

thanks

blissful salmon
#

Someone has an suggestion about my zombie speed problem?

hearty dew
#

Are you trying to adjust a zombie's speed beyond the sprint/shamble/fast-shamble discrete options?

blissful salmon
#

I copied the text from my message above:
I played with the walktypes of the zombies. Personally I think there is a big gap between "5" and "sprint1". Is it possible to speed up walking a bit? I tried it with setSpeedMod (IsoGameCharacter) but I didn't notice a speedchange.

zombieData.WalkType = "5"
zombie:setSpeedMod(2)
blissful salmon
hearty dew
#

Then I think you're in uncharted territory :)

#

Might need to dig into the java side to see what setSpeedMod does, and how that factors in or doesn't to the zombie speed

blissful salmon
#

ok... then I'll look at this later. It's not the most importet.
Unfortunatly I have no clue what I'm doing. I just searched the docs for "speed" stuff.

visual abyss
#

inventory context menu is client right?

hearty dew
#

yea

#

ISInventoryPaneContextMenu.lua

drifting ore
#

How do I get started?

gilded hawk
#

The best way is to look at somebody else mod, and try to edit it to fit your needs

#

And then ask yourself "why is this working/not working"

drifting ore
gilded hawk
#

Most traits don't need server side stuff, what are you trying to do?

bronze yoke
#

it simplifies the process and ensures compatibility, and it has some documentation

drifting ore
#

to modify player stats and things doesn't need to be serversided?

#

and how do i tell what realm a function needs to run in then?

gilded hawk
bronze yoke
#

they've mentioned moving certain stuff to the server but you can worry about that when that actually happens

drifting ore
#

huh, how do other players get your stats and things?

#

are injuries server sided at the least?

#

and i don't even need to register traits serverside? huh.

safe silo
#

How to remove something from context menu in inventory?

bronze yoke
#

injuries are client side

bronze yoke
drifting ore
#

gotcha

ancient grail
drifting ore
#

is there a way to view the base game code?

ancient grail
#

nvm

blissful salmon
bronze yoke
#

flickering lights would be cute actually

#

i want that after that light propagation update

safe silo
gilded hawk
#

Soooo, I do not know why, or how, but this works as a singleton in lua shrug

FactionMapClass = {}

function FactionMapClass:new()
    return self
end

-- This is a singleton
function FactionMap()
    FactionMapClass.instance = FactionMapClass.instance or FactionMapClass:new()
    print('FactionMapClass.instance'..tostring(FactionMapClass.instance))
    return FactionMapClass.instance
end

And I can access it's instance from everywhere like as example, this

if FactionMap():isShowFactionMap() then
        FactionMap():restoreFactionPlayerSymbols()
    else
        FactionMap():restoreVanillaPlayerSymbols()
    end

And, the self works inside the functions, so, I know it works, nice.

But, whyyyyyyyyyyyyyyyyyyyyyyyyyyyy

#

Like, this confuses the hell out of me, zomboid classes are implemented in a complete different way

#

like this:

function ISUIElement:new (x, y, width, height)
   local o = {}
   setmetatable(o, self)
   self.__index = self

   local maxY = getCore():getScreenHeight();
   local maxX = getCore():getScreenWidth();

   o.x = math.max(0, math.min(x, maxX - width));
   o.y = math.max(0, math.min(y, maxY - height));
   o.width = width;
   o.height = height;
   o.anchorLeft = true;
   o.anchorRight = false;
   o.anchorTop = true;
   o.anchorBottom = false;
   o.dock = "none";
   o.minimumWidth = 0;
   o.minimumHeight = 0;
   o.scrollwidth = 0;
   o.removed = false;
   return o
end
#

Why is my code working pipbconfuse

blissful salmon
#

I forgot to mention I think of the event: OnFillInventoryObjectContextMenu

bronze yoke
blissful salmon
#

Is it "good coding" if I put my function which I expect to execute in Solo and on the Server in a lua file in the server directory in my mod.

#

I still struggle a bit with the Server/Client/Shared and Solo concept...

gilded hawk
#

So, I managed to make* instant sync maps between faction members in MP

||*atm it only works on my PC tho :(||

visual abyss
#

hmm so.. I've add submenu to submenu

#

it works but the submenu of submenu doesnt go away after clicks

safe silo
visual abyss
#

yes to first

#

inventoryitemcontextmenu

#

that's what i'm working on right now

safe silo
#

Thank you! Does it need to be placed somewhere specific folder wise? Saw someone do Lua/Client/Context/Inventory/file

visual abyss
#

afaik no

#

i just did lua/client/mod_inventorycontext.lua

#

as long as it in client folder i mean

safe silo
#

And "require 'ISUI/ISInventoryItemContextMenu';" would be correct too?

#

Sorry for all the questions

visual abyss
#

i didnt

#

ยฏ_(ใƒ„)_/ยฏ

safe silo
#

Oh LMAO

#

if it works it works

visual abyss
#

yeah lol

#

just need to figure how to get rid of the submenu once its clicked

#

:hmm

blissful salmon
safe silo
#

I didn't get that far yet. Still unsure how to remove it tbh

#

I think I got the object now or w.e to remove it from

#

But unsure where I can find the names of the entires like if it's ContextMenu_Turn_On/ContextMenu_Turn_Of or something different

blissful salmon
#

I never did it by myself but I used the function to add my element on top. I thought about the following steps:

local function addProceedWorkMenu(player, context, items)
  --your conditions
  context:removeOptionByName(optName)
end

Events.OnFillInventoryObjectContextMenu.Add(addProceedWorkMenu)

I don't know if you have to use the getText like
getText("ContextMenu_Unfavorite")
for the name. Look in the ISInventoryPOaneContextMenu.lua.

safe silo
blissful salmon
#

client/isui/

#

in the first function createMenu they do a lot of tests... followed by the first triggerevent() and then based on the tests the menu entries are created...

blissful salmon
safe silo
#

so like a search through PlayerInv

blissful salmon
#

the event triggers if your rightclick one or more items. so you should check if the items or the item is the one you want to remove the menuitem.

safe silo
#

I assume I would need two instances right? Can't remove multiple options in one call?

context:removeOptionByName("ContextMenu_Turn_On");
context:removeOptionByName("ContextMenu_Turn_Off");
blissful salmon
#

A codesnippet from a context menu I used:

    local invItem = items[1];
    if not instanceof(invItem, "InventoryItem") then
        invItem = items[1].items[1];
    end```
Note: I didn't do the same. I checked if its one or more items on the stack and used the first if their are multiple.
safe silo
#

Okay so something like this with pseudo code lol

require 'ISUI/ISInventoryItemContextMenu';

function removeContextMenuEntries(player, context, item)

    local playerObj = getSpecificPlayer(player)
    local playerInv = playerObj:getInventory()

    if instanceof(playerInv, "ElectricHeater")

    -- loop through the inventory and if it finds the ITEM we'll do below else return

    context:removeOptionByName("ContextMenu_Turn_On");
    context:removeOptionByName("ContextMenu_Turn_Off");

Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);

UPDATED

hearty dew
jade chasm
#

does anyone have a short explanation for suburbs distribution? I have read the dist files and I have no idea what they are. seems like distribution is covered comprehensively in the other dist files

blissful salmon
hearty dew
#

@blissful salmon

gilded hawk
#

We should make a statue of you, and pin this message

blissful salmon
hearty dew
safe silo
#

Okay so this should work? I mean as it's correctly formatted?

require 'ISUI/ISInventoryItemContextMenu';

function removeContextMenuEntries(player, context, item)

    local playerObj = getSpecificPlayer(player)
    local playerInv = playerObj:getInventory()

    if instanceof(playerInv, "InventoryItem") then
        local item = object:getItem()
        if item:getType() == "ElectricHeater" then
            context:removeOptionByName("ContextMenu_Turn_On");
            context:removeOptionByName("ContextMenu_Turn_Off");
        end
    end
end

Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);
hearty dew
hearty dew
gilded hawk
#

No worries dude, I'm joking. hughug

blissful salmon
hearty dew
#

because new() returns self (which is a reference to FactionMapClass when called as FactionMapClass:new()), FactionMapClass.instance = FactionMapClass:new() sets instance to reference FactionMapClass. Then that reference is returned by FactionMap()

hearty dew
gilded hawk
ancient grail
blissful salmon
#

At least I understood it this way as I read through one of the luas...

gilded hawk
#

Problem solved ๐Ÿ’ฏ 1000 10000

-- This is an overly complex singleton, but I kinda like it
function FactionMap()
    FactionMapClass.instance = FactionMapClass.instance or FactionMapClass:new()
    return FactionMapClass.instance
end

I want to belive I have a real class

hearty dew
blissful salmon
safe silo
gilded hawk
blissful salmon
#

ah sorry...

#

you still need this:
f item[1]:getType() == "ElectricHeater" then

safe silo
#

But wouldn't it remove the context menu from all items? Looking to remove it from one specific

#

Okay thank โค๏ธโค๏ธ

blissful salmon
#

thank if it works :-p

safe silo
#

I will LMAO

hearty dew
gilded hawk
#

This thing about : and . is really confusing but you made it clear, thank you tyrir

drifting ore
#

Is there a mod to make Zomboid set in the present day?

hearty dew
#

You can set the start date to 30 years forward maybe ๐Ÿ˜…

ancient grail
ancient grail
#

wow how many modder do you manage to solve problems? @hearty dew i saw loads of thnx haha

#

your awsome man

bronze yoke
#

i think they were hoping for more than changing a number

gilded hawk
#

I vote for Tyrir as "the Saint of the church of Spiffo"

drifting ore
#

I meant more like a mod that adds cell phones and electric cars and stuff like that

bronze yoke
#

you'd be able to find bits and pieces, but i don't think there's any kind of big overhaul mod like that

tough stone
#

Heyo. Haven't done any modding with PZ yet, but I've been teasing around with an idea since I saw a few different mods on the Workshop... Would it be possible to enable weather damaging structures?

thick karma
#

I am working on a couple mods adjacently.

ancient grail
jade chasm
#

anyone know what kind of display cases are in the ary gallery? I want to add a spawn specific to those cases

#

*art gallery

ancient grail
tough stone
# ancient grail not an easy mod to build but you can do it..

My interest is in turning PZ into a survival game with a different opponent than zombies. I'm fine with zombies, but my wife is phobic. I've always enjoyed inclement weather as a challenge. Things like Toxic Fog and Anomalous Storm got me thinking about it.

ancient grail
tough stone
ancient grail
ancient grail
jade chasm
#

ok so you can actually limit loot spawns to a tile in game? I saw in the distriubtions but I thought it was a texture not an actual coordinate

ancient grail
#

which is the most intensive event when it comes to ram usage i believe
as it loads every time a player moves and tiles within his radius loads so you load alot of tiles i believe

#

but im not really sure ihavent learned to use it yet

ancient grail
#

on a custom map

tough stone
ancient grail
#

i guess
or maybe you can create custom tiles that after a certain period of time changes its sprite and its health?

tough stone
ancient grail
#

not sure either. just throwing ideas. brain storm

gilded hawk
#

Is there an event fired when the player updates their map?

tough stone
#

(couldn't help myself lmao)

ancient grail
#

what do mean by update? like discover? i guess since thats when vehicle spawn right?

ancient grail
#

or if it hits u learn a random recipe each time

tough stone
ancient grail
#

loool

ancient grail
gilded hawk
ancient grail
#

ow im not sure ..probably UI does it

#

it writes on the clients save i bet

gilded hawk
#

Yeah it does, I saw it in the logs

LOG  : General     , 1666210390524> reading D:\ZomboidDevCache\Saves\Sandbox\18-10-2022_06-57-22\InGameMap.ini
LOG  : General     , 1666210400465> writing D:\ZomboidDevCache\Saves\Sandbox\18-10-2022_06-57-22\InGameMap.ini
#

But I did not see any event fire by it

safe silo
#

I will post this again as I'm still having issues ๐Ÿ˜ฆ Soul your solution didn't work either but thank you so much for trying โค๏ธ

I'm trying to remove the "Wield as Primary" and "Wield as Secondary" in the context menu of my item "ElectricHeater". Here's my attempt.

require 'ISUI/ISInventoryItemContextMenu';

function removeContextMenuEntries(player, context, item)

    local playerObj = getSpecificPlayer(player)
    local playerInv = playerObj:getInventory()

    if instanceof(playerInv, "InventoryItem") then
        local item = object:getItem()
        if item:getType() == "ElectricHeater" then
            context:removeOptionByName("ContextMenu_Equip_Primary");
            context:removeOptionByName("ContextMenu_Equip_Secondary");
        end
    end
end

Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);
blissful salmon
calm acorn
safe silo
#

Do I even need the variables playerObj and playerInv?

blissful salmon
#

no

calm acorn
#

just use player whats the problem?

safe silo
#
require 'ISUI/ISInventoryItemContextMenu';

function removeContextMenuEntries(player, context, item)

    print(tostring(item[1]:getName()))

    if item:getType() == "ElectricHeater" then
        context:removeOptionByName("ContextMenu_Equip_Primary");
        context:removeOptionByName("ContextMenu_Equip_Secondary");
    end
end

Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);

Like so?

calm acorn
#

the only time you need getspecificplayer is when you mess with stuff i think across send client/servercommand.

blissful salmon
#

in the if you also should use item[1]

calm acorn
#

isnt that item:get(0)

blissful salmon
#

and make a print if you get in.

blissful salmon
safe silo
#

Getting errors when using it with the added [1] after IF statement

blissful salmon
#

but I think I only used get() on arrays so far.

safe silo
#
function: removeContextMenuEntries -- file: HeaterISInventoryItemContextMenu.lua line # 5 | MOD: Sapphire's Playground

Line 5 is the print

#

Object tried to call nil

calm acorn
#

off the top of my head lua doesnt use Array[#]

blissful salmon
#

do you see the print in your console and the error?

safe silo
#

no print in the console no

#

It says error on createMenu and onRightMouseUp, "Object tried to call nil in removeContextMenuEntries"

#

The lua file is located in lua/client/ISUI/FILE

blissful salmon
calm acorn
#

oh wait i guess you do yeah ignore me im still at work messing with powershell

safe silo
#

Sure pastebin?

blissful salmon
#

yes

safe silo
jade chasm
#

hey sorry for spamming the question but im modding item spawning and i'm

safe silo
#

It sounds like the object isn't indexed or w.e since it's getting nil? assuming nil = null

jade chasm
#

i'm in need of an answer about the point of suburbs.distribution

blissful salmon
safe silo
#

the print

hearty dew
safe silo
#

Same error if I remove the print

blissful salmon
#

I have to check the item class.

hearty dew
safe silo
#

oh ok

hearty dew
#

getText instead of getName

safe silo
hearty dew
#

(If you reloaded the save game, it would have done this)

safe silo
#

This is what I got right now:

require 'ISUI/ISInventoryItemContextMenu';

function removeContextMenuEntries(player, context, item)

    if item[1]:getType() == "ElectricHeater" then
        context:removeOptionByName(getText("ContextMenu_Equip_Primary"));
        context:removeOptionByName(getText("ContextMenu_Equip_Secondary"));
    end
end

Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);

Unsure if it answers your question

gilded hawk
#

Is there an event for when this function is called? playSoundLocal

safe silo
blissful salmon
safe silo
#

on it!

#

error again

#

sec

#

tried renaming my function variable from item to items and see if it works

#

since I saw the new code used items and not item

blissful salmon
#

ah damn... you called the parameter item not items.

safe silo
#

I get

table
not instance of

blissful salmon
#

I also saw it right now...

safe silo
#

so just rename to items?

hearty dew
#
SAPPHIREUtils = SAPPHIREUtils or {}

SAPPHIREUtils.InspectMetatables = SAPPHIREUtils.InspectMetatables or true
SAPPHIREUtils.InspectDefaultDepth = SAPPHIREUtils.InspectDefaultDepth or 3
SAPPHIREUtils.InspectTableIndentWidth = SAPPHIREUtils.InspectTableIndentWidth or 4

SAPPHIREUtils.inspect = function(t, depth, header)
    depth = depth or SAPPHIREUtils.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(" ", SAPPHIREUtils.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 SAPPHIREUtils.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 SAPPHIREUtils.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"))
    return t
end
function removeContextMenuEntries(player, context, item)
    SAPPHIREUtils.inspect(item)
    if item[1]:getType() == "ElectricHeater" then
        context:removeOptionByName(getText("ContextMenu_Equip_Primary"));
        context:removeOptionByName(getText("ContextMenu_Equip_Secondary"));
    end
end

Events.OnFillInventoryObjectContextMenu.Add(removeContextMenuEntries);
#

It will print out what item is

safe silo
#

gawdamn ๐Ÿ’€

blissful salmon
#
local invItem = items[1];
  print(type(invItem))
    if not instanceof(invItem, "InventoryItem") then
      print("not instance of")
        invItem = items[1].items[1];
        if instanceof(invItem, "InventoryItem") then
          print("now is instance of")
        end
    else
      print("is instance of")
    end```
safe silo
#

on it

blissful salmon
#

if this doesn't work try the print of Tyrir

safe silo
#

sure thing sec

#

table
not instance of
now is instance of

blissful salmon
#

ok... so the items[1].items[1] is your heater...

safe silo
#

okay that's odd lol

blissful salmon
#

For me this was only the case if I had a stack of items. So when you click the plus in inventory do you have more then one?

#

so you can remove the prints and work with invItem.

safe silo
#

It works now with only ONE heater

#

I just did if items[1].items[1] ==

blissful salmon
#

yes. if there are multiple items you have to loop through item[1].items instead of using the first one like i did.

safe silo
#

Only one heater is still items[1].items[1]

blissful salmon
safe silo
#

Ohhh!!!!

blissful salmon
#

no... i think if its one item then you should use items[1]

safe silo
#

Yea that makes more sense to me now lol

blissful salmon
#

my code check first if the items[1] is the instance and if not i selected the first one of items[1].items ...

safe silo
#

Yup! It works, thx!!

blissful salmon
#

And you should probably loop throught it.

safe silo
#

Yup took the code โค๏ธ

#

And then check with invItem

blissful salmon
#

I don't know if there is a function to check if all items are heater. Else maybe the turn on or off should not appear I thing.

safe silo
#

It worked, thank you so much!!

#

โค๏ธโค๏ธโค๏ธ

steep copper
#

Hi, ho we can tell how many units to use in a recipe ? Like BlowTorch units ?

jade chasm
#

there you can see what items are required in a recipe. you can decide what amount of blowtorch units you want to use in a recipe based the amount of blowtorch units used in other recipes

steep copper
#

Yes, actually the propane from blowtorch doesn't go down when i craft things

#

`recipe Craft Scrap Metal
{
Category : Welding,

    UnusableMetal=2,
    keep BlowTorch,
    keep WeldingMask,
    
    Result        : ScrapMetal,
    OnGiveXP         : Recipe.OnGiveXP.MetalWelding25,
    Sound        : BlowTorch,
    Time        : 30,
    AnimNode    : Disassemble,
    
}`

So, what i need to add here ?

jade chasm
#

you need to add BlowTorch=x, with the unusable metal command to make the recipe consume fuel

steep copper
#

Okay thanks you, i will add this

jade chasm
#

is it possible to force distribution for certain grids?

#

I want to add loot spawns to the art gallery displaycases specifically but they are generic shop locations. Would it be better to change the tile type??

safe silo
#

If I have two items from a mod I want to have the exact same functions how would I use the item:getType == ?

I mean rn for one item it'd be item:getType == "ModdedItem"

Would I just do item:getType == "ModdedItem1" or item:getType == "ModdedItem2"?

blissful salmon
#

seems correct... i already had something similar... give me a second...

blissful salmon
blissful salmon
thick karma
#

Anyone know how to catch a signal the moment after your player spawns into the game and becomes physically controllable?

#

Or alternatively the moment the UI is drawn after spawning?

hearty dew
#

Maybe the first OnTick?

thick karma
#

Hmmm interesting

#

Oh wait I have an idea that might work...

#

Hmmm

#

I think I know the show UI function that gets used, I can just decorate it

#

I had to ask to think of this, sorry.

abstract raptor
#

Yo yo yo -- so I'm getting requests on making the Graffiti mod work better in MP. Right now, if you leave the chunk in MP the graffiti dissapears -- and it seems like it doesn't get added to the server side so other players also can't see it. Any help would be appreciated as I have no clue wtf i am doing XD

bronze yoke
thick karma
#

Didn't work for me, maybe I did it wrong?

#

I tried simply Saying something

#

But it didn't talk

bronze yoke
#

maybe it gets called too early

thick karma
#

I thought maybe player gets created shortly before it appears and become useable, moveable, can talk, etc

#

I guess I could have triggered it wrong

bronze yoke
#

i had an issue where server commands sent after that event didn't actually get received

thick karma
#

If anyone knows Say DOES work to talk when you spawn, I did it wrong, and I'd love to be corrected

#

That would be the absolute easiest way

bronze yoke
#

so some weird stuff does happen with that event for sure

thick karma
#

I think I may know a way. I am gonna give it a shot. A little wonky but it should work.

small topaz
#

hey there! I tried your proposal but doesn't work for me. with such a recipe, the game allows me to use a single berry to realize the recipe instead of requiring 5 (and then may produce and error depending on whether I separate the lines with a comma or not). hmmm... strange because from a logical point of view, it would be reasonable that it works exactly as you suggested...

abstract raptor
drifting stump
thick karma
#

Oh crap it seems so obvious in retrospect โค๏ธ

odd notch
#

so, i know how to log data in the server's log folder, but how does one log data into the client's c users username zomboid logs folder?

hearty dew
odd notch
#

with serverside logging, we can run
sendClientCommand(getPlayer(), 'ISLogSystem', 'writeLog', {loggerName = "foo", logText = "foo!"})
and this will create a file ending in _foo.txt in the server's ./Logs directory, with an entry that says after a timestamp foo!

#

what i'm wondering is, how doth one create a file in the client's ./Logs directory with a specific filename and content

hearty dew
odd notch
hearty dew
#

Hadn't seen this before

odd notch
#

i shall try this when i get a chance ty!!!!!!

hearty dew
#

Might check if LoggerManager is exposed to lua as well. If so, it might have have other interesting logging facilities on it

odd notch
#

it appears to only log to the client!!! perfect!!!! thank you!!!!!!!!!!

visual abyss
#

so is it possible to wrap text in tooltip if it's too long?

abstract raptor
#

Anyone know a good program to edit just strings ๐Ÿค” I want to edit all instances of strings in a file but keep the rest of the formatting

visual abyss
#

notepad

#

in all seriousness, visual studio code is great

abstract raptor
#

yeah?

#

Would I be able to edit just the strings and leave all the formatting and position of the text in tact?

#

ok i got visual studio code

undone elbow
#

How to play a sound on red popup?

visual abyss
marble lynx
#

Hi, extremely simple modding question (lua distributions)

#

Why is it that an item with a weight of 0.001 seems to show up more frequently than it should?

#

Eg. For every 1k zeds killed, I seem to find it at least twice.

#

Or am I misinterpreting the scale of the weight?

abstract raptor
marble lynx
#

Or perhaps there's a lower limit to the weight so 0.001 is actually 0.01?

#

etc

hearty dew
vast nacelle
#

@marble lynx It's proportional to whatever else could possibly drop.
Like if the list you are adding it to has
ItemA = 0.1
ItemB = 0.1
YourItem = 0.001
Your item will have a 0.5% chance or so of dropping.
And that's for each possible roll the container has.

marble lynx
#

No wonder stuff like Brita's ammo and guns seem to spawn like crazy

abstract raptor
#

But only the strings

#

that's the problem

#

Like I'm not replacing all the text with just one bit of text

#

I'm running the text through a converter that changes it

#

i could use a regular expression to change all the text to be the same thing sure, but that would be boring

hearty dew
#

What is the converter?

abstract raptor
#

the Uwuifier hahah

#

"In 1992 Guvwnyow Caw Faiwweathew made a pwomise."

vast nacelle
#

Is this conversion being done while the game is running, or are you converting it while making the mod?

abstract raptor
#

nah I'd just be doing it while making the mod

#

it'd be way more work to convert it while the game is running

#

I know the end result is cringe, but this is a weird problem to try and solve

#

XD

vast nacelle
#

Then you could use the Translate files.
Have entries like
IGUI_Say_Something = [text]
IGUI_Saw_Something_UWU = [uwu text]

Then anywhere you need to add these strings, you can call getText(IGUI_Say_Something_UWU)

abstract raptor
#

Well I was just aiming to quickly edit all the radio

hearty dew
#

awk might can do something like that if the lines are structured so the strings can be parsed out. If there's a lot to the converter, might be best off writing a perl or python script to parse each line, run it through uwuing and then insert the uwu'd text back

abstract raptor
#

I should probably just go to the uwuifer github thing and download that package and just edit it to suit my needs

small topaz
hearty dew
#

i.e. entirely in lua?

bronze yoke
#

getScriptManager():getRecipe('Recipe Name')

small topaz
# hearty dew i.e. entirely in lua?

No. The recipe also has a script definition. I just need to make the corresponding recipe object out of it so that I can modify and access it's data via lua code.

hearty dew
#

Then you can get a Recipe object via the ScriptManager like albion illustrated

small topaz
limpid moon
#

hello I just got into modding and was wondering if anyone could help me

#

I have been looking at tutorials but they all seem to be dated

limpid moon
#

This is for a school project so if anyone is available please dm me and I will ask my questions.

ruby urchin
drifting ore
#

does anyone have an event for sleeping/going to sleep i can use?

limpid moon
#

The part i'm at with mod making im just writting the starting scripts media and textures folders. for some reason my images (such as my poster for the mod) wont load. I dont know if my syntax is wrong because the video is dated or if I didnt follow the guide properly

#

does the name of the image for the poster have to be poster.png

ruby urchin
bronze yoke
drifting ore
#

yeahh, that's what i'm thinking. well. another question, how do you just, kill a player?

limpid moon
#

ok then man I ask. my png has a space in it. Do i need to add that space when i put it in the mod.info

bronze yoke
#

yeah

ruby urchin
drifting ore
#

this works apparently

ruby urchin
#

nice

limpid moon
#

it still didnt work

drifting ore
#

or just dont use spaces

bronze yoke
#

yeah i'd stay away from spaces

#

no idea if they're okay or not in this context but it's generally something you avoid with things like this

limpid moon
#

Yea i know i just kinda typed in the name fast

drifting ore
#

how do i send a message to chat? this documentation hurts to look at

#

or how do i see where print statements go?

ruby urchin
drifting ore
#

yeah

ruby urchin
#

just to be sure, you're asking how to see the variables print or..(?

drifting ore
#

like, print()

#

is there some kinda console?

ruby urchin
#

yeah, you should see one on bottom left of the screen, this only shows if you enable debug mode

#

like that

ancient grail
hearty dew
#

There is also Zomboid/console.txt in your user directory. Best to tail that file in a bigger console than use the one in game imo

ancient grail
weak sierra
#

so i've discovered at least one cause of the nonsense that is the game telling the client a file doesn't exist that does - for an unrelated mod - issue.

weak sierra
#

it's transmitCompleteObjectToServer()

#

called on whatever the thing was u need to sync

#

if u create something purely clientside this is necessary

weak sierra
#

if you have two folders with different capitalizations but the same name

#

which is possible on linux, but not windows

#

the lua system will throw a fit

ancient grail
weak sierra
#

the script system on the other hand doesn't care

#

media/lua/items/something.lua

#

and media/lua/Items/somethingElse.lua

#

and ur getting a random "file missing on client"

limpid moon
#

my in game icons arent working either

weak sierra
#

but u dont enter it in the text

#

so if u name ur icon Something.png

ancient grail
weak sierra
#

it won't work, u need Item_Something.png

limpid moon
#

gotcha. Thank you so much

ancient grail
#

thats what i did before and it fixed it

limpid moon
#

do i rename my pngs or my mod info

weak sierra
#

it was every member of the server, glytch3r

ancient grail
#

modinfo

weak sierra
#

caused by my mod

#

an update to it

#

and i know the lua subsystem is fucky because i put it in Items instead of items

#

and it still overrides the original file

#

so it clearly isn't case sensitive

#

yet linux lets it be

#

which makes it breakkkk

#

and mac is also case sensitive

#

so anyone who mods on mac or linux will run into this potentially

ancient grail
#

ouch .

#

so i guess they have to unsub and resub to a new version if thats the case? if i understood it correctly... else they will have misdirectory issues..

weak sierra
#

well no i just rolled back the change and will now roll out new version

#

that's not my point tho it's to document the problem for other modders

#

gonna go report to TIS on the forum now

ancient grail
#

hope it works ..

weak sierra
#

dont need to hope i tested it locally lol

ancient grail
undone elbow
#

How to make custom BloodLocation?

ancient grail
limpid moon
#

may i send another screen shot. One of my mod info. Its still not working. Neither my poster or in game icons

undone elbow
#

Okay, I've found ๐Ÿ™‚

Example, i want to do metal socks that protect both feet and lower legs, i'll simply add a BloodLocation = Feet;LowerLegs, in the item script.
Full list of per-bodypart location: Bag (back), Hands, Head, Neck, UpperBody, LowerBody, LowerLegs, UpperLegs, LowerArms, UpperArms, Groin.

ancient grail
#

if your dimension is off it will not work

limpid moon
#

so i got the image off the internet

#

then went to gimp

#

made it transparent

#

resized to 35 by 35

#

and exported as png

glacial flicker
#

Any way to give drainable uses to an item in the script file?

#

I want to use an item like 10 times

ancient grail
fast galleon
#

Anybody know what the onTabTornOff in some UI is for? Can you like pull a tab off the window?

#

or is it supposed to be TurnOff

blissful salmon
#

Does someone know why I get "userdata" as datatype when I call the following code? I wanted to get a zombie by its ID:

print("gameClient: " .. type(gameClient))
local zombie = gameClient:getZombie(soundZombieId)```
The last line fails because gameClient isn't a table with this function.
jade chasm
#

^hey so I did some digging and found that "gallery" is actually a room type that is not included in the distribution files and therefore I am able to target the Art Gallery displaycases with forceForRooms. Just thought i'd drop that in case anyone else has the same question. You can also target specific containers by using forceForTile. You can find the tile info by using the debug chunk inspector. So location specific spawning is actually quite simple.

visual abyss
#

how does one skip the night

#

it's getting annoying when night hits while i'm trying to test shit

#

and fast forward takes forever

fast galleon
hearty dew
#

If pz doesn't account for filesystem case differences, that's going to result in issues about files appearing in different paths or not found when the server and client have different case sensitivities when looking up files

hearty dew
hearty dew
#
local gameClient = getGameClient()
SoulUtils.inspectJava(gameClient, "getZombie")
blissful salmon
blissful salmon
hearty dew
#

It shows you getZombie is a static method

blissful salmon
hearty dew
#

You could call it if it were exposed. It appears to not be exposed to lua side.
Technically, you can call it in debug mode because java.lang.reflect.Method is exposed only in debug mode, but that's not going to help you except in making some debug tools

hearty dew
#

Can also get static fields that way (but they have stale data)

visual abyss
#

How does one translate item? ItemName_EN.txt?

blissful salmon
hearty dew
#

Yea, you can decompile zombie.Lua.LuaManager$Exposer. You'll find IsoPlayer exposed in there but not GameClient

#

You can check quickly in code by seeing if the functions are there or not :)

#

or just print(GameClient)

#

If it is exposed, you'll get a table. If not, it will be nil

vast nacelle
#

Then have entries 'ItemName_[module].[itemname] = "itemname but in EN",'

thick karma
#

My best solution... works perfectly, but I'm wondering if anyone can think of a faster way? It's awkward that I have to double-toggle the UI to get it to hide on respawn. It works, but I hate how it looks. โค๏ธ to anyone who can explain to me why the game takes the next toggle after respawn as a toggle ON event if the UI was OFF before death, yet clearly SHOWS the UI already after respawn. If the UI is showing (i.e., ON), why does toggle after respawn send yet another ON signal? Exhausted from trying to solve this, tbh.

-- Death Loop

-- This is the best way I can find to rapidly rebind sidebar
-- to the rest of the UI hiding process after respawn.
-- PLEASE send me a better way if you know one. Basically,
-- this says, "The tick after the sidebar becomes visible again,
-- hide it if it was hidden when you died." 

-- isVisiblePreferred is established elsewhere in my code.
-- It is equivalent to the visibility of the HUD, unless you 
-- (A) enter the Main Menu, or (B) die. In these two cases, it 
-- retains its state as a way of reverting to your preferred 
-- state when you (A) unpause or (B) respawn.

-- hideAgainOnRespawn(ticks) is not added to OnTick 
-- unless you had hidden UI before death.

local function hideAgainOnRespawn(ticks)

    for playerIndex = 0, getNumActivePlayers() - 1 do

        local player = getSpecificPlayer(playerIndex)

        if not player then return end

        local isVisibleSidebar = UIManager.getUI():get(4):isVisible()

        if isVisibleSidebar then

            Events.OnTick.Remove(hideAgainOnRespawn)

            ISUIHandler.toggleUI()
            ISUIHandler.toggleUI()
            
        end

    end

end

local function OnPlayerDeath(player)

    if not isVisiblePreferred then

        Events.OnTick.Add(hideAgainOnRespawn)
    
    end

end

Events.OnPlayerDeath.Add(OnPlayerDeath)
ancient grail
#

took me roughly 3hrs just to do this poster
OCD kicked it.. lol

ancient grail
thick karma
# ancient grail maybe because the first toggle created an instance or activated a variable which...

I meant exactly. I understand abstractly that something in the code that determines whether the UI needs to be hidden or shown is determining that it needs to be shown while that side panel is visible after a no-HUD respawn. I just don't know exactly where that variable is or what it's called or how it's being used. I tried decorating ISUIHandler.setVisibleAllUI and I also tried patching UIManager.setVisibleAllUI, but to no avail in either case. It's not based on ISUIHandler.isVisibleAllUI or UIManager.VisibleAllUI either, as far as I can tell. The only way I can detect it and turn it back off is by listening for a change in the specific visibility value of that side panel. (But, even so, to get the toggle working again, I have to do it twice at that moment, because this doesn't tell me why the toggle isn't working, only when it can be fixed.)

ancient grail
#

what is side panel?

visual abyss
#

would anyone happen to know why the first recipe doesnt show up

#

the box recipe does

#

like wtf

#

and yes, the OnCreate function exists

#

good lord

#

i dont know how i missed that ending comment on 2nd line

#

and i was trying to figure out why the past hour

#

i need to make a syntax highlight for this

hearty dew
#

json syntax highlighting might do a good enough job on it

gilded hawk
hearty dew
#

Ah :/

gilded hawk
#

I was planning to make a vscode extension to help with formatting and hight lighing this scrip files

#

Also, Tyrir since you are online, do you know a simple way to broadcast globalmoddata from a client to all the other clients?

hearty dew
#

Afaik global mod data transmissions (as well as commands you can do via lua) all are between server and client. So probably would need to setup an event handler on the server for OnReceiveGlobalModData that transmits your moddata to clients when it receives the update from a client

#

or just have clients request it when needed if possible

gilded hawk
#

๐Ÿค”
Interesting, thank you tyrir

thick karma
#

I'm not sure it has a name

#

I tried printing its name once and got nothing

#

But I call it side panel

weak sierra
#

u'd think one OS or the other wouldnt care

#

but it broke both

#

at least the particular issue i reported

#

im aware of the STALKER mod's issues

#

i know the maker of that

#

@autumn stump

#

speaking of u

#

i found potential cause and Tyrir points out one

#

maybe u can check ur mod

autumn stump
#

Oh. Damn I will check if thatโ€™s the issue. It makes sense. Thank you Evelyn and @hearty dew ! You think if I change that folder name and update the mod, it wonโ€™t break anything? Iโ€™m always a bit scared of changing folder names and updating in case it breaks it for people. Thanks a lot!

bronze yoke
ancient grail
ancient grail
weak sierra
#

in the SAME mod

#

cuz it was a server override/tweak mod

#

and i was tweaking mods with diff capitalizations

#

that's how i got onto this

#

if this fixes it please post on the bug report thread to add info

#

more chance they fix the problem

fast galleon
autumn stump
visual abyss
#

i removed the module cause i was just trying to experiment with solutions

#

when i shared the pic

gilded hawk
#

Is there a way to make a function run every X seconds instead of every frame or very tick?

I think a function I'm using is running a little too often

ancient grail
#

is it possible to change an items attachment location via console? just for that 1x spawn instance.. and or its sprite?

thick karma
#

First line of the OnTick

hearty dew
visual abyss
#

there we go

#

that took forever to implement that syntax highlight

#

now i shouldnt miss any comments

hearty dew
thick karma
#

@gilded hawk My solution would be approximately close. Not sure if you need exact.

#

It sounded like you did not need precision

#

Like you just want to slow down how often you do a complicated thing

gilded hawk
#

The solution is interesting, and what tyrir said it's also interesting, I'll think about it ๐Ÿ‘

thick karma
#

I think Tyrir is talking about what I did

#

In his own terms

#

"counting frames" = using the tick variable

#

I could be wrong

#

Pointing out the problem with what I offered

hearty dew
# hearty dew There's the `OnEveryTenMinutes` event for in-game 10 mins. If you want a functio...
MxUtils = MxUtils or {}

MxUtils.IntervalTimers = MxUtils.IntervalTimers or {}

--[[
    Usage example:
    
    local intervalTimerID = MxUtils.createIntervalTimer(5000, function()
        print("5 seconds have elapsed!")
    end)
    
    MxUtils.deleteIntervalTimer(intervalTimerID)
]]
MxUtils.createIntervalTimer = function(intervalInMilliseconds, intervalElapsedEventHandler, runOnce)
    local id = #MxUtils.IntervalTimers + 1
    local lastIntervalTime = math.floor(os.time() * 1000)

    MxUtils.IntervalTimers[id] = function(tickCounter)
        local time = math.floor(os.time() * 1000)
        if os.difftime(time, lastIntervalTime + intervalInMilliseconds) >= 0 then
            if runOnce then
                MxUtils.deleteIntervalTimer(id)
            end
            lastIntervalTime = time
            intervalElapsedEventHandler(id)
        end
    end

    -- Other events to consider
    -- Events.OnRenderTick.Add(MxUtils.IntervalTimers[id])
    -- Events.OnTickEvenPaused.Add(MxUtils.IntervalTimers[id])
    Events.OnTick.Add(MxUtils.IntervalTimers[id])

    return id
end

MxUtils.deleteIntervalTimer = function(id)
    if MxUtils.IntervalTimers[id] then
        Events.OnTick.Remove(MxUtils.IntervalTimers[id])
        MxUtils.IntervalTimers[id] = nil
    else
        print(string.format("WARNING: Unknown interval timer id %s", tostring(id)))
    end
end
gilded hawk
#

WOW!

#

That's amazing

thick karma
#

Is this using background tasks?

#

Or synchronous?

hearty dew
#
local intervalID = MxUtils.createIntervalTimer(5000, function() print("It's been 5 seconds!") end)
-- then later to stop it
MxUtils.deleteIntervalTimer(intervalID)
hearty dew
#

so polling basically

thick karma
#

Oh. So you call the function to add the listener and then you use the clock to count time passed when each tick lands?

hearty dew
#

lua doesn't have any ways to use OS timers to avoid the polling

thick karma
#

I see so the reason you have the array is to time different events?

#

And you can store their IDs separately?

#

Events that could begin at arbitrary times?

hearty dew
thick karma
#

Wow crazy

#

That is a next level solution

hearty dew
#

It's a basic way to implement timers by polling if you don't have OS timers

visual abyss
#

send a request to TIS

hearty dew
#

I wanted to extend it to run lua coroutines, so you could give it a thread to run periodically, something like this:```lua
function foo()
print("starting routine")
wait(seconds(5))
print("5 seconds later")
wait(minutes(1))
print("one min after that")
end

But I haven't yet found a good use case for doing it in pz
hollow storm
#

Good day! Me and a friend are big fans of the "Crossed" comic series and wanted to make some mods for Zomboid. If someone has time and wants to work on such a project, please write to me via Discord.
You don't have to know the comic series!

hearty dew
#

If someone can think of when something like that'd be useful, that'd be interesting to hear ๐Ÿ™‚

calm acorn
hearty dew
#

Do you have any use cases for it yet? I was thinking it might be good for scripting events, but that doesn't seem too common in pz mods that I've seen (at least the ones I play with)

ruby urchin
#

Hmm I have this at the moment

---@deprecated
IsoDog.update = function(self, thread)
    while true do

        if self:getState() == "Wander" and #self:getActionQueue() == 0 then
            local currentSquare = self.character:getCurrentSquare();
            local squares = UTILS.getSquareAround(currentSquare, 5);
            local squaresFiltred = UTILS.Table.filter(squares, function(element) return element and element ~= currentSquare end);
            local goToSquare = squaresFiltred[ZombRand(1, #squaresFiltred)];


            local action = ISWalkToTimedAction:new(self.character, goToSquare)
            action.maxTime = 1000; -- BUILD 41.77 Broken something.
            action.useProgressBar = false;
            self:addAction(action);
            print("Dog walking around");

            --thread:Wait(ZombRand(1000, 5000));
        end

        if self:getState() == "Follow" then
            local owner = self:getOwner();

            if owner  then
                local ownerCoords = Vector3f.new(owner:getX(), owner:getY(), owner:getZ());
                local distance = ownerCoords:distance(self.character:getX(), self.character:getY(), self.character:getZ());

                if distance >= 3 then
                    self:clearActions();
                    local action = TASK_GO_TO_LOCATION_OFFSET:new(self.character, owner, 3.0);
                    action.maxTime = 1000; -- BUILD 41.77 Broken something.
                    action.useProgressBar = false;
                    self:addAction(action);

                    if distance >= 7 then
                        
                        self.character:NPCSetRunning(true);
                        --self.character:setSprinting(true)
                    else
                        self.character:NPCSetRunning(false);
                        --animal:setSprinting(false)
                    end
                end

                print("Dog following owner")
            end

            thread:Wait(1000);
        end

        thread:Wait(20)
    end
end
hearty dew
#

Like the ai thread for creatures. Nice :)

calm acorn
#

Event.OnTick.Add( Your scientists were so preoccupied with whether they could, they didn't stop to think if they should. )

#

man like literally every mod that uses this lags out every server

#

theres a couple of okay ones but more often than not ontick is laggy if it runs on the server once you get past a certain number doing anything more than basic checks to fire off some other event, that angry turrets mod was killing my server the other day.

safe silo
#

What would be the best way to make sure a tile is placed indoors with a roof above it? I want to add a check for placing my heater down so it can't heat outside.

Would it be square:getRoof() and square:getRoom()? Not sure if it's the exact names but I know they exist

calm acorn
#

isnt there a IsIndoor or isInside() check for isosquare

safe silo
#

oh it might be one yea

calm acorn
#

oh im stupid its isOutside

safe silo
#

So I should be able to call if square:isOutside() == FALSE I'll allow it?

calm acorn
#

(not square:isOutside())

safe silo
#

ah okay, man lua is weird ๐Ÿ’€

#

but thank u โค๏ธ

calm acorn
#

np mate

hearty dew
autumn sparrow
#

are there any good references or source information for getting started to learn lua gui specifically for Project Zomboid?

safe silo
autumn sparrow
safe silo
autumn sparrow
safe silo
#

And look through the LUA, it's more like a framework but could be good for starts

hearty dew
safe silo
autumn sparrow
safe silo
#

No worries! I sadly can't help you with any code related questions as I'm just starting myself but those two projects had me get a easy head start!

autumn sparrow
autumn stump
vast nacelle
#

How does noise propagate? Like say you generate a noise that is 100 range and 100 loudness.
Does the noise attract zombies within 100 tiles of the source with 100 loudness through out then stop cold after that?
Does the noise's loudness decay from 100 at the source to 0 at 100 tiles away?
Or is the noise at full loudness up to 100 tiles then decays after that that until the loudness falls to 0?