Famine online version Mod development - commonly used inst method (8)

foreword

In Don't Starve Online Mod Development - Class, Prefab, component, debug (4),
we briefly introduced how to use game entities (Entity) and components. In this chapter, we will learn the common methods of Entity. Want to know more You can also look at the source code mentioned in the article

generate entity

Generating entities can be divided into two situations, one is console generation, and the other is code generation. The former is used for debugging after we enter the game, and the latter is used for daily code writing.

The console generates preset object entities

--consolecommands.lua
--在鼠标位置生成预设物实体,如猪人 "pigman"
function c_spawn(prefab, count=1) ... end
--给予玩家可放进物品栏的预设物实体,如树枝 "twigs"
function c_give(prefab, count=1) ... end

Generate preset objects and entities in the code

--mainfunctions.lua
--生成并返回预设物实体,一般只需要个name。如果creator没有对应皮肤,则显示默认皮肤
function SpawnPrefab(name, skin, skin_id, creator) ... end
--在原本的实体位置生成预设物实体,并删除原本的实体,一般只需要前两个参数
function ReplacePrefab(original_inst, name, skin, skin_id, creator) ... end

--生成并返回实体,name可省,常见于各prefab的fn中
function CreateEntity(name)
    local ent = TheSim:CreateEntity()	--C层的Entity数据,存放在inst.entity
    local guid = ent:GetGUID()	--GUID独一无二的标志数字
    local scr = EntityScript(ent)	--entityscript.lua,这就是inst
    if name ~= nil then
        scr.name = name
    end
    Ents[guid] = scr	--全部Entity都放到Ents这个全局表里(声明在main.lua)
    NumEnts = NumEnts + 1	--全部Entity的数量(声明在main.lua)
    return scr	--返回inst
end

From CreateEntity , we can see that the common inst:XXX() actually calls the method in entityscript.lua

In addition, other global functions are defined in mainfunctions.lua
, such as GetTick() for getting the time,
Start() when the game starts, SaveGame(...) for saving the game, Shutdown() for closing the game, SaveAndShutdown() for the
game callback OnFocusLost() , OnFocusGained(),
Entity callback OnEntitySleep(), OnEntityWake, OnPhysicsWake, OnPhysicsSleep,
GUID processing function GetEntityString, etc.; inst.GUID

Listen/Push Events

As an important way to transfer information in scripts, events play a vital role in reducing code complexity and providing scalability. The essence is to save the function (fn) first (ListenForEvent), and then pass in the parameters (source, data) at a specific time (PushEvent) to call the function (fn).

--entityscript.lua

--监听/取消监听事件
--event:string,独一无二的事件名,对应inst:PushEvent中的event
--fn:监听的函数,参数是 (source, data),source对应调用PushEvent的Entity,data对应PushEvent时的data,也可以print出来看看data是什么
--source:被监听的实体,默认监听自身
inst:ListenForEvent(event, fn, source=inst)
inst:RemoveEventCallback(event, fn, source=inst)
inst:RemoveAllEventCallbacks()

--推送事件,运行fn
--event:string,独一无二的事件名,mod的event推荐加个前缀		
--data:any,一般是个table
--如果inst有sg(stategraph状态图)且sg在监听这个事件,也会调用 inst.sg:PushEvent(event, data)
--如果inst有brain(大脑/AI)也会调用 inst.brain:PushEvent(event, data)
inst:PushEvent(event, data)

--table的key可以是任意非nil值,通过table[key]来访问,key是字符串时可以写成table.key
--当前source被监听的事件列表 source.event_listeners[event][inst] = {fn1, fn2, ...} 
--当前inst在监听的事件列表 inst.event_listening[event][source] = {fn1, fn2, ...}

When listening to the world (TheWorld), you can assign the source as TheWorld. However, if you want to monitor the state of the world (worldstate) (time, cave time, full moon, weather, season, temperature, humidity, snow, rain, etc.), it is recommended to use the
following function

--entityscript.lua

--TheWorld的预设物在prefabs/world.lua
--监听/取消监听世界TheWorld.state中的状态 (components/worldstate)
--var:components/worldstate.lua中 SetVariable(var, val, togglename)
--fn:一般参数为(inst, val),不过start或stop开头的var,只有inst。
inst:WatchWorldState(var, fn)
inst:StopWatchingWorldState(var, fn)
inst:StopAllWatchingWorldStates()

--inst.worldstatewatching[var] = {fn1, fn2, ...}
--_watchers[var][inst] = { {fn, inst}, ... }

--举个例子components/worldstate.lua中
--SetVariable(var, val, togglename)
--有第三个参数时,有start和stop开头var  (val and "start" or "stop")..togglename
SetVariable("cavephase", phase)	
-->	var="cavephase",  fn的val=phase,洞穴白天到黄昏等时期变化时推送
SetVariable("iscaveday", phase == "day", "caveday")		
--> var="iscaveday"	 fn第二个参数val=(phase == "day"),一个boolean
--> var="startcaveday",val为true时推送,fn参数只有inst
--> var="stopcavaday",val为false时推送,fn参数只有inst

Note:

  • TheWorld is an Entity, assigned in prefabs/world.lua, responsible for managing the world, maps, clocks, player generation, etc.
  • Determine whether it is an underground world, TheWorld:HasTag("cave")
  • Global variables such as The beginning and Ents (declared in main.lua), can be directly accessed in the game
  • The global variables in main can also be accessed in modmain, but they may not be assigned values ​​when they are accessed directly, so they are generally written in
    AddGamePostInit(fn()) -- first
    AddSimPostInit(fn()) -- and then, unlike stand-alone, fn There are no parameters, and ThePlayer is not assigned a value.
    If you need to access ThePlayer, use the following function
    AddPlayerPostInit(fn(player)) -- use ThePlayer==player in fn to determine whether the current player is

use tags

Tags are often used by Component to judge Entity, and also affect the AI ​​of creatures.
Tags starting with _ are special and will be introduced in the component section below.
Common tags are as follows:

  • NOCLICK: Non-clickable objects
  • FX: special effects
  • lightningtarget: lightning target (removed will not be struck by lightning)
  • electricdamageimmune: immunity to electrical damage (robots are immune to electrical damage)
  • irreplaceable: irreplaceable, players leave the world and drop automatically (eye bones, etc.)
  • player, playerghost: player status (can also be judged by inst.components.health:IsDead())
  • scarytoprey: scare away small animals (removed will not scare away small animals)
--tag: string
inst:AddTag(tag)
inst:RemoveTag(tag)
inst:HasTag(tag)
--tags = {"tag1", "tag2", ...}
inst:HasTags(tags)	--拥有全部 
inst:HasOneOfTags(tags)	--拥有其中一个标签

Add and remove components

--name:string, 对应components中文件夹中的文件名,组件的使用看第四章
inst:AddComponent(name)	--有_replica的同名组件会自动添加(服务器)
inst:RemoveComponent(name)

--inst.components.name
--inst.repica.name

network components

Components with the same name ending in _replica use network variables (netvars.lua) to communicate between the server and the client. Both the server and the client need to add components with the same name ending in _replica.
Let’s talk about the process of adding components first. After specific use, a tutorial related to network communication will be published. If you are interested, you can also go to the
official netvars tutorial.
Note: The network variable of the action is AddNetwork() of entityscript.lua , and most of the others in player_classified.lua

Take the player's health component as an example (the server modifies the blood volume, notification)

local inst = CreateEntity()
inst.entity:AddNetwork()	--网络通信当然要添加网络了
inst:AddTag("_health")	--添加网络组件标签
inst.entity:SetPristine()	--客户端根据添加的_开头的tag,添加xxx_replica组件
if not TheWorld.ismastersim then return inst end	--客户端返回,下面是仅服务器代码
inst:RemoveTag("_health")	--移除网络组件标签,等AddComponent会再次加上。官方书写习惯,不删问题应该也不大
inst:AddComponent("health")	--服务器添加health和health_replica组件,和_health标签。
--注:客户端只需要知道玩家的血量,其他生物的血量并不需要知道,所以其他生物的预设物fn中
--并不会有inst:AddTag("_health") 和 inst:RemoveTag("_health") 这两句

Timing/stage task

--entityscript.lua	scheduler.lua

--下面4个函数的返回值都是Periodic  可通过 :Cancel() 取消任务	
--定时任务,time秒后调用 fn(inst, ...)。仅调用一次,不需要手动取消
--注:inst:DoTaskInTime(0,...) 时会在下一帧调用; Sprite中是毫秒
inst:DoTaskInTime(time, fn, ...)	

--阶段任务,initialdelay秒后调用fn(inst, ...),之后每隔time秒调用一次fn,需要手动取消
--一般都是 inst.task = inst:DoPeriodicTask(...),某个时候 inst.task:Cancel()
inst:DoPeriodicTask(time, fn, initialdelay=time, ...)	

--和上面的类似,不过定时不受世界暂停时影响
inst:DoStaticTaskInTime(time, fn, ...)	
inst:DoStaticPeriodicTask(time, fn, initialdelay, ...)	

inst:CancelAllPendingTasks()	--取消上面所以的定时任务

Callback

-------- entityscript.lua---------
Fn: Corresponding function XXXCb: callback function, called when non-nil
Generally, ComponentCb is called first, and then EntityCb is called, unless it starts with Pre
EntityCb conventional writing: inst.OnXXX = function(inst, …) … end
ComponentCb conventional writing: function Cmpname:OnXXX(…) … end

  • refs: list of referenced Entity or nil, {Entity1, Entity2, ...}
  • cmpdata: generally a table, only saves values, does not save references
  • newents: Entitys generated when the server is restarted, generally not used
  • builder: generally the player's Entity
  • dt: deltatime, the time since the last update
Fn EntityCb ComponentCb
inst:GetPersistData() inst:OnSave(data) -> refs cmp:OnSave() -> cmpdata, refs
inst:SetPersistData(data, newents) inst:OnPreLoad(data, newents) inst:OnLoad(data, newents) cmp:OnLoad(cmpdata, newents)
inst:LoadPostPass(newents, savedata) inst:OnLoadPostPass(newents, savedata) cmp:LoadPostPass(newents, cmpdata)
inst:OnBuilt(builder) inst:OnBuiltFn(builder) cmp:OnBuilt(builder)
inst:Remove() inst:OnRemoveEntity() cmp:OnRemoveEntity()
inst:LongUpdate(dt) inst:OnLongUpdate(dt) cmp:LongUpdate(dt)

--------Update: update.lua--------
dt: deltatime, the time since the last update

  • WallUpdate: Wall update
  • Update: daily update
  • StaticUpdate: Start updating when the world is paused
  • LongUpdate: Updates at long intervals, such as entering and exiting caves, jumping days, etc.
Fn EntityCb ComponentCb
WallUpdate(dt) - cmp:OnWallUpdate(dt)
Update(dt) - cmp:OnUpdate(dt)
StaticUpdate(dt) - cmp:OnStaticUpdate(0)
LongUpdate(dt, ignore_player) inst:OnLongUpdate(dt) cmp:LongUpdate(dt)

--------Player: player_common.lua-----------.
Player specific callback
inst.OnNewSpawn = function() … end
inst.OnDespawn = function() … end

parent-child entity

--entityscript.lua
--child:Entity
inst:AddChild(child)
inst:RemoveChild(child)
--inst.children[child] = true
--child.parent = inst	child.platform = nil

platform

Currently only used on boats, allowing the player to move with the boat

--entityscript.lua
--child: Entity
inst:AddPlatformFollower(child)
inst:RemovePlatformFollower(child)
inst:GetPlatformFollowers()
inst:GetCurrentPlatform()

--inst.platformfollowers[child] = true
--child.platform = inst		child.parent = nil

delete

--移除自身和子Entity,从父Entity的孩子中移除
--触发事件onremove,OnRemoveEntity回调
--移除所以监听、组件、定时和阶段任务
inst:Remove()	
inst:IsValid()	--正常返true,被Remove返false

position, angle

inst:GetPosition()	--> Point(inst.Transform:GetWorldPosition())  一个table
inst:GetRotation() --> inst.Transform:GetRotation()

inst:FacePoint(x, y, z)	--> 面向某点
inst:ForceFacePoint(x, y, z)  --> 强制面向某点
inst:FaceAwayFromPoint(dest, force)

--DistanceSq: 距离的平方,少了sqrt,减少计算量
inst:GetDistanceSqToInst(inst) --> 距离的平方
inst:IsNear(otherinst, dist) --> inst:GetDistanceSqToInst(otherinst) < dist*dist
inst:GetDistanceSqToPoint(x, y, z)	--> 距离的平方
inst:IsNearPlayer(range, isalive)	--> range半径内是否有玩家
inst:GetNearestPlayer(isalive)	--> 最近的玩家
inst:GetDistanceSqToClosestPlayer(isalive)	--> 距离最近的玩家的距离的平方

show/hide

--显示/隐藏,仅改变显示
inst:Show()
inst:Hide()

--显示到屏幕,常用于物品被移出物品栏
--IsInLimbo()->false	inst:Show()
--开始brain,sg,Physics,Light,AnimState,DynamicShadow,MiniMapEntity
--inst:PushEvent("exitlimbo")
inst:ReturnToScene()

--从屏幕隐藏中,常用物品被放进物品栏
--IsInLimbo()->true		inst:Hide()
--停止brain,sg,Physics,Light,AnimState,DynamicShadow,MiniMapEntity
--inst:PushEvent("enterlimbo")
inst::RemoveFromScene()

judgment

inst:IsOnWater()	--是否在水上,即没船且脚下是海
inst:IsInLimbo()	--是否在物品栏,仅在mastersim(服务器)有效,客户端用INLIMBO标签判断?
inst:GetIsWet()		--是否是湿的,服务器客户端都可以使用
inst:IsInLight()	--是否在光照内
inst:IsValid()		--正常返true,被Remove返false

brain

--brainfn: require("brains/xxxbrain")
inst:SetBrain(brainfn)
inst:StopBrain()
inst:RestartBrain()

State diagram

--name: "SGXXX"		stategraphs文件夹下的文件名
inst:SetStateGraph(name)
inst:ClearStateGraph()

skin

--entityscript.lua
inst:GetSkinBuild()
inst:GetSkinName()
--inst.AnimState:SetSkin(build_name, def_build)

map

--entityscript.lua
--设置参数,具体应用在components/map.lua
inst:SetDeployExtraSpacing(spacing)
inst:SetTerraformExtraSpacing(spacing)
inst:SetGroundTargetBlockerRadius(radius)

inst:IsOnValidGround()	--是否在地面上
inst:IsOnOcean(allow_boats)	--是否在海上
inst:IsOnPassablePoint(include_water, floating_platforms_are_not_passable)  --是否可通过某点

inst:GetCurrentTileType()	--获得当前地皮,如果要获得有效地皮先判断inst:IsOnValidGround()

physics

When setting physics, the MakeXXXPhysics in standardcomponents.lua is generally used , but occasionally it is necessary to reset the physical collision radius

--entityscript.lua
inst:SetPhysicsRadiusOverride(radius)	--设置覆盖的物理碰撞半径
inst:GetPhysicsRadius(default)	--返回物理碰撞半径或default

Portal

→Mod development of Famine online version - production column (9)
←Mod development of Famine online version - making food that can be put into a pot, cooked, and dried (7)

Guess you like

Origin blog.csdn.net/weixin_46068322/article/details/126715859