Jump to content

"Aliased" function doesn't seem to work on clients


Recommended Posts

I'm trying to make a small change in builder component but while the changes work perfectly on host, nothing seems to happen client-side:

local require = GLOBAL.require
local Builder = require('components/builder')
--local Builder = require('components/builder_replica') --I've also tried this one but got nothing

local function IsInUnlockList(recname, unlocklist)
	if not unlocklist then return false end

	for i, v in ipairs(unlocklist) do
		if v == recname then
			return v
		end
	end
end

local my_CanBuild = Builder.CanBuild
function Builder:CanBuild(recname)
	print('ok')
	return my_CanBuild(self, recname) or IsInUnlockList(recname, self.inst.unlocklist)
end

I need to unlock a few items even if the player doesn't have the ingredients. Someone also told me that I could just copy the whole "builder.lua" and put into my mod to override it, but wanted to know if I can do like the way above.

Link to comment
Share on other sites

5 hours ago, Welpx said:

 

local function IsInUnlockList(recname, unlocklist)
	if not unlocklist then return false end
	for i, v in ipairs(unlocklist) do
		if v == recname then
			return v
		end
	end
end

local function BuilderReplicaPostInit(self)
	local _CanBuild = self.CanBuild
	self.CanBuild = function(self, recname)
		return _CanBuild(self, recname) or IsInUnlockList(recname, self.inst.unlocklist)
	end
end
AddClassPostConstruct("components/builder_replica", BuilderReplicaPostInit)

 

Link to comment
Share on other sites

Thanks, that works. I'm still having a problem with unlocklist. For some reason it always return nil when I call from inside builder replica with

print(self.inst.unlocklist, GLOBAL.ThePlayer.unlocklist) but when I use from the console (ThePlayer.unlocklist) it returns me the actual value (a table). Why it doesn't work inside the function?

Link to comment
Share on other sites

Here is the thing, it seems self.inst from inside _CanBuild isn't referencing to outside. I created a new component "unlocker" just to try this. When I call self.inst.components.unlocker:AddToList('hammer') from inside _CanBuild, it works but doen't work when I call from inside a prefab, in this case from:

local function onequip(inst, owner)
    owner.components.unlocker:AddToList('hammer')
end

 

@zUsername print(self.classified.inst.prefab) doesn't seem to work and just print(self.inst.prefab) returns me 'wilson'

Link to comment
Share on other sites

I have a feeling it might be because I use a little bit too much of "modimport" but I can't help myself, It feels so clearner that way (also easier to "comment" stuff in case of errors)

Spoiler

-- modmain.lua
------- LOAD ASSETS -----------------------------------------------------

PrefabFiles = {
	'deluxepencil',
	'diviningrod_ruins',
	'posternchest',
	'fakewings',
	'treeguard_caller',
	'groundpound_caller',
	'thelazypicker',
	'petcap',
	'petcollar',
}

------ IMPORTS ----------------------------------------------------------

modimport('debugstuff.lua')
modimport('my_postinits.lua')
modimport('my_recipes.lua')
modimport('my_strings.lua')

------ PATCHES --------------------------------------------------------------

modimport("scripts/patches/writeablehax.lua")
modimport('scripts/patches/petleashpatch.lua')
modimport('scripts/patches/builderpatch.lua')
modimport('scripts/patches/traderpatch.lua')

-- unlocker.lua (the custom component I used to test)

local Unlocker = Class(function(self, inst)
    self.inst = inst

    self.unlocklist = {'axe'}
end)

function Unlocker:AddToList(prefab)
	table.insert(self.unlocklist, prefab)
end

function Unlocker:GetList(test)
	return self.unlocklist
end

return Unlocker

 


-- mypostinits.lua

local function NewStuff(inst)
	--inst:WatchWorldState("isnight", OnIsNight)
	inst:AddComponent("corruption")
	inst:AddComponent('unlocker')
end

AddPlayerPostInit(NewStuff)

 


-- builderpatch.lua

local function IsInUnlockList(recname, unlocklist)
	if not unlocklist then return false end
	for i, v in ipairs(unlocklist) do
		if v == recname then
			return v
		end
	end
end

local function BuilderReplicaPostInit(self)
	local _CanBuild = self.CanBuild

	self.CanBuild = function(self, recname)
		self.inst.components.unlocker:AddToList('hammer') -- THIS one works
		return _CanBuild(self, recname) or IsInUnlockList(recname, self.inst.components.unlocker:GetList())
	end
end
AddClassPostConstruct("components/builder_replica", BuilderReplicaPostInit)

-- the prefab calling the cursed function

local assets = 
{ 
	Asset("ANIM", "anim/hat_catcoon.zip") 
}

local fname = "hat_catcoon"
local symname = "catcoonhat"
local prefabname = symname

local MAXPETS =  20

local function unlockpets(inst, owner)
	if owner.unlocklist == nil then
		owner.unlocklist = {
			'critter_kitten_builder',
			'critter_puppy_builder',
			'critter_lamb_builder',
			'critter_dragonling_builder',
			'critter_glomling_builder',
			'petcollar',
		}
	end

	if owner.components and owner.components.petleash then
		owner.components.petleash:SetMaxPets(MAXPETS)
	end

    if owner.components and owner.components.unlocker then
        owner.components.unlocker:AddToList('hammer')  -- THIS doesn't work
    end
end

local function lockpets(inst, owner)
	
end

local function onequip(inst, owner, fname_override)
    local build = fname_override or fname

    local skin_build = inst:GetSkinBuild()
    if skin_build ~= nil then
        owner:PushEvent("equipskinneditem", inst:GetSkinName())
        owner.AnimState:OverrideItemSkinSymbol("swap_hat", skin_build, "swap_hat", inst.GUID, build)
    else
        owner.AnimState:OverrideSymbol("swap_hat", build, "swap_hat")
    end
    owner.AnimState:Show("HAT")
    owner.AnimState:Show("HAIR_HAT")
    owner.AnimState:Hide("HAIR_NOHAT")
    owner.AnimState:Hide("HAIR")

    if owner:HasTag("player") then
        owner.AnimState:Hide("HEAD")
        owner.AnimState:Show("HEAD_HAT")
    end

    if inst.components.fueled ~= nil then
        inst.components.fueled:StartConsuming()
    end

    unlockpets(inst, owner)
end

local function onunequip(inst, owner)
    local skin_build = inst:GetSkinBuild()
    if skin_build ~= nil then
        owner:PushEvent("unequipskinneditem", inst:GetSkinName())
    end

    owner.AnimState:ClearOverrideSymbol("swap_hat")
    owner.AnimState:Hide("HAT")
    owner.AnimState:Hide("HAIR_HAT")
    owner.AnimState:Show("HAIR_NOHAT")
    owner.AnimState:Show("HAIR")

    if owner:HasTag("player") then
        owner.AnimState:Show("HEAD")
        owner.AnimState:Hide("HEAD_HAT")
    end

    if inst.components.fueled ~= nil then
        inst.components.fueled:StopConsuming()
    end

    lockpets(inst, owner)
end

local function fn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddNetwork()

    MakeInventoryPhysics(inst)

    inst.AnimState:SetBank('catcoonhat')
    inst.AnimState:SetBuild('hat_catcoon')
    inst.AnimState:PlayAnimation("anim")

    inst:AddTag("hat")
    inst:AddTag("writeable")

    if not TheWorld.ismastersim then
        return inst
    end

    inst:AddComponent("inventoryitem")
    inst.components.inventoryitem:ChangeImageName("catcoonhat")

    inst:AddComponent("inspectable")
    --inst:AddComponent('writeable')
    --inst:AddComponent("trader")

    inst:AddComponent("equippable")
    inst.components.equippable.equipslot = EQUIPSLOTS.HEAD
    inst.components.equippable:SetOnEquip(onequip)
    inst.components.equippable:SetOnUnequip(onunequip)

    MakeHauntableLaunch(inst)

    return inst
end

return Prefab('petcap', fn, assets)

 

 

Link to comment
Share on other sites

 I have changed my mind. But I found something interesting though. For some reason I can add a tag to owner in _Equip and retrieve it in _CanBuild. Everything else is nil. I'd love if someone explained to me why that happens.

local require = GLOBAL.require
--local Builder = require('components/builder')
local Equippable = require('components/equippable')
local Builder = require('components/builder_replica')

-----------------------------------

local unlocklist = {
	'axe',
	'hammer',
}

local function IsInUnlockList(recname, unlocklist)
	if not unlocklist then return false end

	for i, v in ipairs(unlocklist) do
		if v == recname then
			return v
		end
	end
end

local _Equip = Equippable.Equip
function Equippable:Equip(owner)
	owner:AddTag('unlock')
	owner.testvar = 'unlock'
	if owner.components.unlocker then 
		owner.components.unlocker:SetTest('unlock')
	end

	_Equip(self, owner)
end

local _CanBuild = Builder.CanBuild
function Builder:CanBuild(recname)
	print(self.inst:HasTag('unlock'))	-- TRUE		
	print(self.inst.testvar)	-- NIL
	if self.inst.components.unlocker then 
		print(self.inst.components.unlocker:GetTest('unlock'))	-- FALSE
	end
	
	return _CanBuild(self, recname) --or IsInUnlockList(recname, self.inst.unlocklist)
end


----------------------

local function onequip(inst, owner, fname_override)
    local build = "hat_catcoon"

    local skin_build = inst:GetSkinBuild()
    if skin_build ~= nil then
        owner:PushEvent("equipskinneditem", inst:GetSkinName())
        owner.AnimState:OverrideItemSkinSymbol("swap_hat", skin_build, "swap_hat", inst.GUID, build)
    else
        owner.AnimState:OverrideSymbol("swap_hat", build, "swap_hat")
    end
    owner.AnimState:Show("HAT")
    owner.AnimState:Show("HAIR_HAT")
    owner.AnimState:Hide("HAIR_NOHAT")
    owner.AnimState:Hide("HAIR")

    if owner:HasTag("player") then
        owner.AnimState:Hide("HEAD")
        owner.AnimState:Show("HEAD_HAT")
    end

    if inst.components.fueled ~= nil then
        inst.components.fueled:StartConsuming()
    end

end

local function postinit(inst)
	if not GLOBAL.TheWorld.ismastersim then return end

	inst.components.equippable:SetOnEquip(onequip)
end

AddPrefabPostInit("petcap", postinit)

 

 

Edited by Welpx
Link to comment
Share on other sites

This will works, but if you want to craft item on client you will need override MakeRecipeFromMenu.

local function IsInUnlockList(recname, unlocklist)
	if not unlocklist then return false end
	for i, v in ipairs(unlocklist) do		
		if v == recname then
			return true
		end
	end
end

local function BuilderReplicaPostInit(self)
	local _CanBuild = self.CanBuild
	self.CanBuild = function(self, recname)
		return _CanBuild(self, recname) or IsInUnlockList(recname, self.inst.unlocklist)
	end
end

if GLOBAL.TheNet:GetIsServer() then
	AddComponentPostInit("builder", BuilderReplicaPostInit)
else
	AddClassPostConstruct("components/builder_replica", BuilderReplicaPostInit)
end

local function onequip(player)
	table.insert(player.unlocklist, "axe")
end

local function onunequip(player)
	player.unlocklist = {}
end

AddPrefabPostInit("world", function(wrld)    
	wrld:ListenForEvent("playeractivated", function(wlrd, player)       
		if player == GLOBAL.ThePlayer then
			player.unlocklist = {}
			player:ListenForEvent("equip", onequip)
			player:ListenForEvent("unequip",onunequip)
		end    
	end)
end)

 

Link to comment
Share on other sites

That really worked wow, thanks. Just wondering what kind of tool do you use for debug? Is there a special app that I haven't heard about? (with breakpoints, listening to functions, watch variables, etc). Because trial and error on crash screen takes so much time T_T. I trying to override MakeRecipeFromMenu but idk what to change in there. 

Link to comment
Share on other sites

On 1/3/2017 at 9:51 PM, Welpx said:

That really worked wow, thanks. Just wondering what kind of tool do you use for debug? Is there a special app that I haven't heard about? (with breakpoints, listening to functions, watch variables, etc). Because trial and error on crash screen takes so much time T_T. I trying to override MakeRecipeFromMenu but idk what to change in there. 

SendRPCToServer will help you.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
  • Create New...