[饥荒联机版模组]修改制作栏中的合成物品时的需要资源和其它相关技巧

此文章只是记录编写联机版mod时做的记录,不是一篇很正式的文档

想要入门饥荒mod制作,可以看同站的夏湾作者文章,很详细~

直接给代码和结论,目前在饥荒是可用的

修改制作栏中的合成物品时的需要资源

--有需要直接拿来用就行
--可通过AddRecipePostInit方法修改,第一个传入需要合成的物品的prefab名字,第二个是制作栏修改的方法,self不是预制体而是另外一个东西,这不用在意
AddRecipePostInit("armorwood",function(self)
    --print("AddRecipePostInit") --log语句
    if  IsRecipeValid(self.name) then--判断prefab的名字是否可制作(暂时这样理解把)
    	--ingredients是合成该prefab所需要的资源,在后面以数组(应该)的方式放入
        GetValidRecipe(self.name).ingredients={Ingredient("log", 6),Ingredient("rope", 2)}
        --这里的意思六个木头和两个绳索合成木甲
    end
end)

在制作栏中添加一个prefab的多个合成方式

--向物品栏(合成栏)添加合成方式,这是官方的新的方法,用这个是没问题的
AddRecipe2(
    "blowdart_pipe1", --当前Recipe的名称,不能用已经存在的于物品栏的prefab的名字,得另起一个
    --合成所需要的材料,按格式添加即可
    {Ingredient("cutreeds", 1),Ingredient("rocks", 2),Ingredient("feather_robin_winter", 1)},
    --合成所需要的条件,需要解锁科技?解锁魔法?还是远古等等
    TECH.SCIENCE_TWO,--SCIENCE_ONE SCIENCE_THREE MAGIC_TWO MAGIC_THREE ANCIENT_TWO等等
    --这个是名字为config参数,一般可选有很多,但是在这里,我们只需要把product 设置为已经存在的于物品栏的prefab的名字,即你需要的prefabs,numtogive 的意思是制作后会给你几个该物品
    {product ="blowdart_pipe",numtogive = 2},
    --最后这个是filters参数,就是制作栏(合成栏)的分累,比如武器建筑生存什么的,这些东西的tag或者flag暂时可以这样理解
    {"WEAPONS","MODS"})--不会填就填个MODS,具体的需要看文件\scripts\recipes_filter.lua 中的CRAFTING_FILTER_DEFS 这个table里的第一个字段的内容

放个效果图把

多个吹箭制作方式
这里如果你想说我自己创建一个新的prefab然后配置同样的参数,添加到物品栏中不是也可以实现这个需要
答案是可以这样做,我也这样做了,我发现这个有几个不好的地方,一个是贴图要配置(物品栏的和背包里面的都需要),另一个是然后你这个预制体其实是一个新的prefab和之前的都不一样,所以和之前的或者新的不能叠加在一起,如果还得非有说一点的话就是为了更好管理mod,你可能需要新起大目录(或者叫模块?)专门放置你新建的预制体,然后在添加进入modmain中去

进阶(如果你还想更深入的了解的话,继续看吧,不保证完全对)

上述的AddRecipe2方法,其实在/scirpts/modutil.lua里面有具体实现

env.AddRecipe2 = function(name, ingredients, tech, config, filters)
	require("recipe")--引入scripts\recipe.lua,需要用到里面的Recipe2
	mod_protect_Recipe = false --recipe.lua 中的一个变量在Recipe2中有用到
	local rec = Recipe2(name, ingredients, tech, config) --结果存下来
	--如果不是可分解或者可被锤子敲的物品
	if not rec.is_deconstruction_recipe then 
	--就进入这里主要是给当前合成栏的物品进行分类,把其和某个Filter关联在一起
	--也就是我们进游戏后制作栏看到各种物品被分类到不同的地方用的,比如武器/防具/光源等
		if config ~= nil and config.nounlock then
			env.AddRecipeToFilter(name, CRAFTING_FILTERS.CRAFTING_STATION.name)
		else
		--AddRecipeToFilter这个方法稍后说
			env.AddRecipeToFilter(name, CRAFTING_FILTERS.MODS.name)
		end
		if filters ~= nil then
			for _, filter_name in ipairs(filters) do
				env.AddRecipeToFilter(name, filter_name)
			end
		end
	end
	mod_protect_Recipe = true --结束再把这个状态置回来
	rec:SetModRPCID() --这是和网络相关的,目前我也不太了解
	return rec
end

其实到目前为止还没有做什么很明显的动作,重点主要是在Recipe2中
我们看到Recipe2的代码

--scripts\recipe.lua文件
--Class是klei自己写的东西,调用Recipe2()主要是调用function中的内容
Recipe2 = Class(Recipe, function(self, name, ingredients, tech, config)
	--最后是调用了Recipe的_ctor函数,在这里可以看到config内的参数有很多
	if config ~= nil then
		Recipe._ctor(self, name, ingredients, nil, tech, config, config.min_spacing, config.nounlock, config.numtogive, config.builder_tag, config.atlas, config.image, config.testfn, config.product, config.build_mode, config.build_distance)
	else
		Recipe._ctor(self, name, ingredients, nil, tech)
	end
	self.is_deconstruction_recipe = false
end)

可以看到最终是调用了Recipe,那继续来看看Recipe,下面代码有点长

Recipe = Class(function(self, name, ingredients, tab, level, placer_or_more_data, min_spacing, nounlock, numtogive, builder_tag, atlas, image, testfn, product, build_mode, build_distance) -- do not add more params here, add them to "placer_or_more_data"
    if mod_protect_Recipe then --这个就是之前AddRecipe2中设置为false
        print("Warning: Calling Recipe from a mod is now deprecated. Please call AddRecipe from your modmain.lua file.")
    end--可以避免输出这句话 其实主要是针对一些过期的接口的警告
	--没细看不明白
	local placer = nil
	local more_data = {}
	if type(placer_or_more_data) == "table" then
		placer = placer_or_more_data.placer
		more_data = placer_or_more_data
	else
		placer = placer_or_more_data
	end
	--从这里开始就是设置这个Recipe的属性
	--Recipe名字,但是这个名字和最终生成的prefab关联不大
    self.name          = name
	--合成所需要的资源
    self.ingredients   = {}
   	--看了下好像是根据某些特定字符串来放入这里面的,暂时不知道有什么用
    self.character_ingredients = {}
    --和上面类似暂时不知道用处
    self.tech_ingredients = {}
	self.filter = more_data.filter
	--这里通过上面传入的ingredients 来判断将每一个ingredient插入那个上述哪个表中
    for k,v in pairs(ingredients) do
        table.insert(
            (IsCharacterIngredient(v.type) and self.character_ingredients) or
            (IsTechIngredient(v.type) and self.tech_ingredients) or
            self.ingredients,--表格选择
            v--数据
        )
    end
	--这个就是最终生成的prefab的名字(关键),如果传入了product名字就会用product名字不然就是用传入的name名字
	--在饥荒里面一般的物品的制作名字和最终的prefab都是一样的
	--所以大多数的时候product是空值,这个就是AddRecipe2中config参数里面配置的
	--我们上面的"在制作栏中添加一个prefab的多个合成方式" 就是用到了这个参数
    self.product       = product or name
    self.tab           = tab					-- DEPRECATED
	--在制作栏的中的描述
	self.description   = more_data.description -- override the description string in the crafting menu

    self.imagefn       = type(image) == "function" and image or nil
    --图片什么的
    self.image         = self.imagefn == nil and image or (self.product .. ".tex")
    self.atlas         = (atlas and resolvefilepath(atlas))-- or resolvefilepath(GetInventoryItemAtlas(self.image))
	self.fxover        = more_data.fxover

    --self.lockedatlas   = (lockedatlas and resolvefilepath(lockedatlas)) or (atlas == nil and resolvefilepath("images/inventoryimages_inverse.xml")) or nil
    --self.lockedimage   = lockedimage or (self.product ..".tex")
	--排序时候用到的,涉及到在制作栏(合成栏)中先后顺序,num是这个文件的全局变量,永不妥协模组就有用这个然后进行重新排序
    self.sortkey       = num
    self.rpc_id        = num --mods will set the rpc_id in SetModRPCID when called by AddRecipe()
    --需要科技等级
    self.level         = TechTree.Create(level)
    --不懂
    self.placer        = placer
    self.min_spacing   = min_spacing or 3.2

    
    self.testfn        = testfn					-- custom placer test function if default test isn't enough
	self.canbuild      = more_data.canbuild		-- custom test function to see if we should be allowed to craft this recipe, return a build action fail message if false
	--不懂
    self.nounlock      = nounlock or false
	--制作一次物品最终会产生几个prefab 上面示例就用到了
    self.numtogive     = numtogive or 1
	--不懂
    self.builder_tag   = builder_tag or nil
	self.sg_state      = more_data.sg_state or more_data.buildingstate or nil -- overrides the SG state to use when crafting the item (buildingstate is the old variable name)
	--建造模式在陆地上 ,海上之类的,不是很清楚
    self.build_mode    = build_mode or BUILDMODE.LAND
    self.build_distance= build_distance or 1
	--都不懂啦
    self.no_deconstruction = more_data.no_deconstruction -- function or bool
    self.require_special_event = more_data.require_special_event

	self.dropitem      = more_data.dropitem

	self.actionstr     = more_data.actionstr
	self.hint_msg      = more_data.hint_msg

	self.manufactured = more_data.manufactured -- if true, then it is up to the crafting station to handle creating the item, not the builder component
	--这个值根据不同接口最后会设置不同值
	self.is_deconstruction_recipe = tab == nil
	--全局num自增
    num                = num + 1
    --这里也是一个比较关键的参数,用一个AllRecipes全局变量存储下来当前的物品制作的Recipe
    --其实意味着你可以直接根据名字去修改上述所有数据,永不妥协获取AllRecipes去修改数据的
    AllRecipes[name]   = self
    --不懂看看翻译吧
    if self.builder_tag ~= nil and more_data.allowautopick == nil then -- NOTES(JBK): "donotautopick" filtered items should set allowautopick in the recipe if they are to be picked up by things for the player.
        AllBuilderTaggedRecipes[name] = self.builder_tag
    end
	--最后你会发现这里会调用RecipePostInit函数,很重要啊,文章第一个方法就是这里被调用的
    if ModManager then
        for k,recipepostinit in pairs(ModManager:GetPostInitFns("RecipePostInit")) do
            recipepostinit(self)
        end

        for k,recipepostinitany in pairs(ModManager:GetPostInitFns("RecipePostInitAny")) do
            recipepostinitany(self)
        end
    end
end)

看了这么多要我总结的话就是注意Recipe中name和product可以不一样,
第二点就是ingredients sortkey numtogive实际上作用比较大,
还有一个AllRecipes全局变量很关键存储了所有制作的Recipe
其实这里你还会发现和我们第二个方法的代码还是有点不一样,在我们第二个方法里面用的是IsRecipeValid(self.name) GetValidRecipe(self.name)
这个其实在这个文件里有定义的啦

function GetValidRecipe(recname)
    if not IsRecipeValidInGameMode(TheNet:GetServerGameMode(), recname) then
        return
    end
    local rec = AllRecipes[recname]
    return rec ~= nil and not rec.is_deconstruction_recipe and (rec.require_special_event == nil or IsSpecialEventActive(rec.require_special_event)) and rec or nil
end

function IsRecipeValid(recname)
    return GetValidRecipe(recname) ~= nil
end

其实就是从AllRecipes全局变量根据name取到对应的Recipe就是中间帮我们做了一些有效性的判断,这个当然很重要,所以我就直接用它里面的函数了

好了讲了这么大一块,应该快累了,没事加加油,我们还有最后一块内容
就是上面的AddRecipeToFilter函数,这又是另外一个故事了,从这个名字来说就是把Recipe加入到Filter中去可能会觉得奇怪,Filter难道是一个实际的数据结构么,我告诉你还真是,可能和平常用的Filter不一样,这里按照德语?来说的话应该是一个名词,而不是一个形容词或者动词的用法,说了一些没用的话,那看代码把

	--函数传入两个参数,都是字符串,一个是制作物品(recipe_name)的名字,一个是过滤器(filter_name)的名字
	env.AddRecipeToFilter = function(recipe_name, filter_name)
		initprint("AddRecipeToFilter", recipe_name, filter_name)
		--这里你会发现它CRAFTING_FILTERS中根据filter_name取得了一个什么东西,一般饥荒里面全大写加下划线的名字组合用来表示某些全局常量或者一些全局数据结果(不知道说法是不是对的)
		local filter = CRAFTING_FILTERS[filter_name]
		--先不管CRAFTING_FILTERS继续看,一个判断,取到了这个东西,而且这个东西里面的default_sort_values表中查不到recipe_name的值,说明是一个新的值,要加入,这里主要是判断过滤器是否有效和防止重复加入
		if filter ~= nil and filter.default_sort_values[recipe_name] == nil then
		--用一个insert把recipe_name插入到上面取到的filter.recipes的末尾
			table.insert(filter.recipes, recipe_name)
			--给这个赋上一个排序值
			filter.default_sort_values[recipe_name] = #filter.recipes
		end
	end

最后我们就来讲讲CRAFTING_FILTERS是一个什么东西
这个在scripts\recipes_filter.lua文件中

--这里就是数据结构,第一个是名字,然后atlas image是制作栏每个菜单的图标
--custom_pos不晓得 recipes就是当前制作栏过滤器存下的制作物品的Recipe的名字
--把CRAFTING_FILTER_DEFS的数据 根据名字插入CRAFTING_FILTERS表中
CRAFTING_FILTERS = {}
for i, v in ipairs(CRAFTING_FILTER_DEFS) do
	CRAFTING_FILTERS[v.name] = v
end
CRAFTING_FILTER_DEFS =
{
	{name = "FAVORITES",			atlas = GetCraftingMenuAtlas,	image = "filter_favorites.tex",		custom_pos = true},
	{name = "CRAFTING_STATION",		atlas = GetCraftingMenuAtlas,	image = "filter_none.tex",			custom_pos = true},
	{name = "SPECIAL_EVENT",		atlas = GetCraftingMenuAtlas,	image = "filter_events.tex",		custom_pos = true},
	{name = "MODS",					atlas = GetCraftingMenuAtlas,	image = "filter_modded.tex",		custom_pos = true, recipes = {}},

	{name = "CHARACTER",			atlas = GetCharacterAtlas,		image = GetCharacterImage,			image_size = 80},
	{name = "TOOLS",				atlas = GetCraftingMenuAtlas,	image = "filter_tool.tex",			},
	{name = "LIGHT",				atlas = GetCraftingMenuAtlas,	image = "filter_fire.tex",			},
	{name = "PROTOTYPERS",			atlas = GetCraftingMenuAtlas,	image = "filter_science.tex",		},
	{name = "REFINE",				atlas = GetCraftingMenuAtlas,	image = "filter_refine.tex",		},
	{name = "WEAPONS",				atlas = GetCraftingMenuAtlas,	image = "filter_weapon.tex",		},
	{name = "ARMOUR",				atlas = GetCraftingMenuAtlas,	image = "filter_armour.tex",		},
	{name = "CLOTHING",				atlas = GetCraftingMenuAtlas,	image = "filter_warable.tex",		},
	{name = "RESTORATION",			atlas = GetCraftingMenuAtlas,	image = "filter_health.tex",		},
	{name = "MAGIC",				atlas = GetCraftingMenuAtlas,	image = "filter_skull.tex",			},
	{name = "DECOR",				atlas = GetCraftingMenuAtlas,	image = "filter_cosmetic.tex",		},

	{name = "STRUCTURES",			atlas = GetCraftingMenuAtlas,	image = "filter_structure.tex",		},
	{name = "CONTAINERS",			atlas = GetCraftingMenuAtlas,	image = "filter_containers.tex",	},
	{name = "COOKING",				atlas = GetCraftingMenuAtlas,	image = "filter_cooking.tex",		},
	{name = "GARDENING",			atlas = GetCraftingMenuAtlas,	image = "filter_gardening.tex",		},
	{name = "FISHING",				atlas = GetCraftingMenuAtlas,	image = "filter_fishing.tex",		},
	{name = "SEAFARING",			atlas = GetCraftingMenuAtlas,	image = "filter_sailing.tex",		},
	{name = "RIDING",				atlas = GetCraftingMenuAtlas,	image = "filter_riding.tex",		},
	{name = "WINTER",				atlas = GetCraftingMenuAtlas,	image = "filter_winter.tex",		},
	{name = "SUMMER",				atlas = GetCraftingMenuAtlas,	image = "filter_summer.tex",		},
	{name = "RAIN",					atlas = GetCraftingMenuAtlas,	image = "filter_rain.tex",			},
	{name = "EVERYTHING",			atlas = GetCraftingMenuAtlas,	image = "filter_none.tex",			show_hidden = true},
}

下面就是很多插入某个过滤器的Recipe名字的表

CRAFTING_FILTERS.TOOLS.recipes =
{
	"axe",
	"pickaxe",
	"shovel",
	"hammer",
...
}

最后设置CRAFTING_FILTERS每个recipe对应的default_sort_values 排序值 table.invert这个没查到啊,只能猜,有没有大佬告知一下是什么意思

for _, filter in pairs(CRAFTING_FILTERS) do
	if filter.recipes ~= nil then
		filter.default_sort_values = table.invert(filter.recipes)
	end
end
--这里就没仔细追了,看名字的含义就是从TheCraftingMenuProfile这里取出:被你设为常用的(喜爱的)物品GetFavorites() 
--玩过游戏应该都能猜出来把
CRAFTING_FILTERS.FAVORITES.recipes = function() return TheCraftingMenuProfile:GetFavorites() end
--设置其排序顺序
CRAFTING_FILTERS.FAVORITES.default_sort_values = function() return TheCraftingMenuProfile:GetFavoritesOrder() end
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
饥荒联机游戏,最大玩家数默认只能为6人。但是,根据引用的描述,可以通过修改游戏的服务器设置来提高人数上限。具体操作步骤如下: 1. 打开饥荒联机游戏,并进入主菜单界面。 2. 在主菜单界面,找到"设置"选项。 3. 在"设置"选项,选择"服务器设置"或类似的选项。 4. 在服务器设置界面,可以看到"最大玩家数"或类似的选项。 5. 点击或选择"最大玩家数"选项,并修改人数上限为你想要的数量。 6. 保存设置并退出服务器设置界面。 7. 现在你的服务器人数上限已经成功修改需要注意的是,修改服务器人数上限可能会对游戏的性能和稳定性产生影响。如果你的电脑或服务器配置较低,增加太多的玩家数量可能会导致游戏运行缓慢或出现延迟。因此,建议根据你的设备和网络情况来合理调整人数上限,以保证游戏的流畅性和稳定性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [《饥荒联机》房间人数上限修改图文教程](https://blog.csdn.net/weixin_36087083/article/details/119288937)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* [饥荒联机房间人数上限修改图文教程_饥荒联机房间人数上限怎么修改_牛游戏网](https://blog.csdn.net/weixin_39845113/article/details/119288939)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值