Lua:Callins: Difference between revisions

From Spring
Jump to navigationJump to search
Flozi (talk | contribs)
fancify with templates - unsynced callins so far
Line 14: Line 14:
{{LuaCallin
{{LuaCallin
|name = Initialize
|name = Initialize
|params =
|return = none
|description = Called when the addon is (re)loaded.
|description = Called when the addon is (re)loaded.
}}
}}
Line 21: Line 19:
{{LuaCallin
{{LuaCallin
|name = Shutdown
|name = Shutdown
|params =
|return = none
|description = Called when the addon or the game is shutdown.
|description = Called when the addon or the game is shutdown.
}}
}}
Line 32: Line 28:
|name = DefaultCommand
|name = DefaultCommand
|params = type, id
|params = type, id
|return = number cmdID
|return = {{type|number}} cmdID
|description = Used to set the default command when a unit is selected. First parameter is the type of the object pointed at (either "unit or "feature") and the second is its unitID or featureID respectively.  
|description = Used to set the default command when a unit is selected. First parameter is the type of the object pointed at (either "unit or "feature") and the second is its {{var|unitID}} or {{var|featureID}} respectively.  
}}
}}


Line 39: Line 35:
|name = CommandNotify
|name = CommandNotify
|params = cmdID, cmdParams, cmdOptions
|params = cmdID, cmdParams, cmdOptions
|return = bool removeCmd
|return = {{type|bool}} removeCmd
|description = Called when a command is issued. Returning <code>true</code> deletes the command and does not send it through the network.
|description = Called when a command is issued. Returning {{value|true}} deletes the command and does not send it through the network.
}}
}}


Line 53: Line 49:
|name = WorldTooltip
|name = WorldTooltip
|params = ttType, data1, data2, data3
|params = ttType, data1, data2, data3
|return = string newTooltip
|return = {{type|string}} newTooltip
|description = The parameters can be <code>"unit"</code>, <code>unitID</code>; <code>"feature"</code>, <code>featureID</code>; <code>"ground"</code>, <code>posX</code>, <code>posY</code>, <code>posZ</code> or <code>"selection"</code>.
|description = The parameters can be {{value|"unit"}}, {{var|unitID}}; {{value|"feature"}}, {{var|featureID}}; {{value|"ground"}}, {{var|posX}}, {{var|posY}}, {{var|posZ}} or {{value|"selection"}}.
}}
}}


Line 60: Line 56:
|name = UnsyncedHeightMapUpdate
|name = UnsyncedHeightMapUpdate
|params = ???
|params = ???
|return = none
|description = Called when the unsynced copy of the height-map is altered.
|description = Called when the unsynced copy of the height-map is altered.
}}
}}
Line 67: Line 62:
|name = GameProgress
|name = GameProgress
|params = serverFrameNum
|params = serverFrameNum
|return = none
|description = Called every 60 frames, calculating delta between GameFrame and GameProgress. Can give an ETA about catching up with simulation for mid-game join players.
|description = Called every 60 frames, calculating delta between GameFrame and GameProgress. Can give an ETA about catching up with simulation for mid-game join players.
}}
}}
Line 74: Line 68:
|name = GameSetup
|name = GameSetup
|params =  state, ready, playerStates
|params =  state, ready, playerStates
|return = bool success, bool newReady
|return = {{type|bool}} success, {{type|bool}} newReady
|description = ???
|description = ???
}}
}}
Line 81: Line 75:
|name = SunChanged
|name = SunChanged
|params = ???
|params = ???
|return = none
|description = ???
|description = ???
}}
}}
Line 88: Line 81:
|name = AddConsoleLine
|name = AddConsoleLine
|params = msg, priority
|params = msg, priority
|return = none
|description = Called when text is entered into the console (e.g. Spring.Echo).
|description = Called when text is entered into the console (e.g. Spring.Echo).
}}
}}
Line 102: Line 94:
|name = RecvFromSynced
|name = RecvFromSynced
|params = ...
|params = ...
|return = none
|description = Receives data sent via [[Lua_System#Synced|SendToUnsynced]] callout.
|description = Receives data sent via [[Lua_System#Synced|SendToUnsynced]] callout.
}}
}}
Line 109: Line 100:
|name = Save
|name = Save
|params = zip
|params = zip
|return = none
|description = Called when a chat command '/save' or '/savegame' is received. The single argument is a userdatum representing the savegame zip file. See [[Lua_SaveLoad#Save_.28_zip_.29_-.3E_nil|Lua_SaveLoad]].
|description = Called when a chat command '/save' or '/savegame' is received. The single argument is a userdatum representing the savegame zip file. See [[Lua_SaveLoad#Save_.28_zip_.29_-.3E_nil|Lua_SaveLoad]].
}}
}}
Line 116: Line 106:
|name = LoadProgress
|name = LoadProgress
|params = message, replaceLastLine
|params = message, replaceLastLine
|return = none
|description = Only available to LuaIntro.
|description = Only available to LuaIntro.
}}
}}
Line 123: Line 112:
|name = GroupChanged
|name = GroupChanged
|params = groupID
|params = groupID
|return = none
|description = Called when a unit is added to or removed from a control group. Currently implemented for widgets only.
|description = Called when a unit is added to or removed from a control group. Currently implemented for widgets only.
}}
}}
Line 138: Line 126:
|name = IsAbove
|name = IsAbove
|params = x, y
|params = x, y
|return = bool isAbove
|return = {{type|bool}} isAbove
|description = Called every Update. Must return <code>true</code> for <code>Mouse*</code> events and <code>GetToolTip</code> to be called.
|description = Called every Update. Must return {{value|true}} for {{name|Mouse*}} events and {{name|GetToolTip}} to be called.
}}
}}


Line 145: Line 133:
|name = GetTooltip
|name = GetTooltip
|params = x, y
|params = x, y
|return = string tooltip
|return = {{type|string}} tooltip
|description = Called when <code>IsAbove</code> returns true.
|description = Called when {{name|IsAbove}} returns {{value|true}}.
}}
}}


Line 152: Line 140:
|name = KeyPress
|name = KeyPress
|params = key, mods, isRepeat
|params = key, mods, isRepeat
|return = bool becomeOwner
|return = {{type|bool}} becomeOwner
|description = Called repeatedly when a key is pressed down. If you want an action to occur only once check for <code>isRepeat == false</code>. The <code>mods</code> parameter is a table, with keys <code>alt</code>, <code>ctrl</code>, <code>meta</code> and <code>shift</code> each having a boolean value. Return <code>true</code> if you don't want other callins or the engine to also receive this keypress.
|description = Called repeatedly when a key is pressed down. If you want an action to occur only once check for {{var|1=isRepeat == {{value|false}}}}. The {{var|mods}} parameter is a {{type|table}}, with keys {{value|"alt"}}, {{value|"ctrl"}}, {{value|"meta"}} and {{value|"shift"}} each having a boolean value. Return {{value|true}} if you don't want other callins or the engine to also receive this keypress.
}}
}}


Line 159: Line 147:
|name = KeyRelease
|name = KeyRelease
|params = key
|params = key
|return = bool
|return = {{type|bool}}
|description = Called when the key is released.
|description = Called when the key is released.
}}
}}
Line 167: Line 155:
|name = TextInput
|name = TextInput
|params = utf8char
|params = utf8char
|return = none
|description = Called whenever a key press results in text input. Introduced in 97.0.
|description = Called whenever a key press results in text input. Introduced in 97.0.
}}
}}
Line 174: Line 161:
|name = JoystickEvent
|name = JoystickEvent
|params = ???
|params = ???
|return = none
|description = ???
|description = ???
}}
}}
Line 181: Line 167:
|name = MousePress
|name = MousePress
|params = x, y, button
|params = x, y, button
|return = bool becomeMouseOwner
|return = {{type|bool}} becomeMouseOwner
|description = Called when a mouse button is pressed. The <code>button</code> parameter supports up to 7 buttons. Must return <code>true</code> for <code>MouseRelease</code> and other functions to be called.
|description = Called when a mouse button is pressed. The {{var|button}} parameter supports up to 7 buttons. Must return {{value|true}} for {{name|MouseRelease}} and other functions to be called.
}}
}}


Line 189: Line 175:
|params = x, y, button
|params = x, y, button
|return = bool becomeMouseOwner
|return = bool becomeMouseOwner
|description = Called when a mouse button is released. Please note that in order to have Spring call <code>MouseRelease</code>, you need to have a <code>MousePress</code> call-in in the same addon that returns <code>true</code>.
|description = Called when a mouse button is released. Please note that in order to have Spring call {{name|MouseRelease}}, you need to have a {{name|MousePress}} call-in in the same addon that returns {{value|true}}.
}}
}}


Line 195: Line 181:
|name = MouseWheel
|name = MouseWheel
|params = up, value
|params = up, value
|return = none
|description = Called when the mouse wheel is moved. The parameters indicate the direction and amount of travel.
|description = Called when the mouse wheel is moved. The parameters indicate the direction and amount of travel.
}}
}}
Line 202: Line 187:
|name = MouseMove
|name = MouseMove
|params = x, y, dx, dy, button
|params = x, y, dx, dy, button
|return = none
|description = Called when the mouse is moved. The {{var|dx}} and {{var|dy}} parameters indicate the distance travelled, whereas the first two indicate the final position.
|description = Called when the mouse is moved. The <code>dx</code> and <code>dy</code> parameters indicate the distance travelled, whereas the first two indicate the final position.
}}
}}


Line 210: Line 194:
|name = PlayerChanged
|name = PlayerChanged
|params = playerID
|params = playerID
|return = none
|description = Called whenever a player's status changes e.g. becoming a spectator.
|description = Called whenever a player's status changes e.g. becoming a spectator.
}}
}}
Line 217: Line 200:
|name = PlayerAdded
|name = PlayerAdded
|params = playerID
|params = playerID
|return = none
|description = Called whenever a new player joins the game.
|description = Called whenever a new player joins the game.
}}
}}
Line 224: Line 206:
|name = PlayerRemoved
|name = PlayerRemoved
|params = playerID, reason
|params = playerID, reason
|return = none
|description = Called whenever a player is removed from the game.
|description = Called whenever a player is removed from the game.
}}
}}
Line 233: Line 214:
|name = ViewResize
|name = ViewResize
|params = viewSizeX, viewSizeY
|params = viewSizeX, viewSizeY
|return = none
|description = Called whenever the window is resized.
|description = Called whenever the window is resized.
}}
}}
Line 240: Line 220:
|name = Update
|name = Update
|params = dt
|params = dt
|return = none
|description = Called for every draw frame. The parameter is the time since the last update. Perform calculations in here and only drawing in Draw* callins.}}
|description = Called for every draw frame. The parameter is the time since the last update. Perform calculations in here and only drawing in Draw* callins.}}


Line 247: Line 226:
{{LuaCallin
{{LuaCallin
|name = DrawGenesis
|name = DrawGenesis
|params =
|return = none
|description = Doesn't render to screen! Use this callin to update textures, shaders, etc.
|description = Doesn't render to screen! Use this callin to update textures, shaders, etc.
}}
}}
Line 254: Line 231:
{{LuaCallin
{{LuaCallin
|name = DrawWorldPreUnit
|name = DrawWorldPreUnit
|params =
|return = none
|description = Spring draws units, features, some water types, cloaked units, and the sun.
|description = Spring draws units, features, some water types, cloaked units, and the sun.
}}
}}
Line 261: Line 236:
{{LuaCallin
{{LuaCallin
|name = DrawWorld
|name = DrawWorld
|params =
|return = none
|description = Spring draws command queues, 'map stuff', and map marks.
|description = Spring draws command queues, 'map stuff', and map marks.
}}
}}
Line 268: Line 241:
{{LuaCallin
{{LuaCallin
|name = DrawWorldShadow
|name = DrawWorldShadow
|params =
|return = none
|description = ???
|description = ???
}}
}}
Line 275: Line 246:
{{LuaCallin
{{LuaCallin
|name = DrawWorldReflection
|name = DrawWorldReflection
|params =
|return = none
|description = ???
|description = ???
}}
}}
Line 282: Line 251:
{{LuaCallin
{{LuaCallin
|name = DrawWorldRefraction
|name = DrawWorldRefraction
|params =
|return = none
|description = ???
|description = ???
}}
}}
Line 289: Line 256:
{{LuaCallin
{{LuaCallin
|name = DrawScreen
|name = DrawScreen
|params =
|return = none
|description = ???
|description = ???
}}
}}
Line 297: Line 262:
|name = DrawScreenEffects
|name = DrawScreenEffects
|params = vsx, vsy
|params = vsx, vsy
|return = none
|description = Where {{var|vsx}}, {{var|vsy}} are screen coordinates.
|description = Where <code>vsx</code>, <code>vsy</code> are screen coordinates.
}}
}}


{{LuaCallin
{{LuaCallin
|name = DrawLoadScreen
|name = DrawLoadScreen
|params =
|return = none
|description = {{new|95.0}} Only available to LuaIntro, draws custom load screens.
|description = {{new|95.0}} Only available to LuaIntro, draws custom load screens.
}}
}}
Line 311: Line 273:
|name = DrawInMinimap
|name = DrawInMinimap
|params = sx, sy
|params = sx, sy
|return = none
|description = Where {{var|sx}}, {{var|sy}} are values relative to the minimap's position and scale.
|description = Where <code>sx</code>, <code>sy</code> are values relative to the minimap's position and scale.
}}
}}


Line 318: Line 279:
|name = DrawInMinimapBackground
|name = DrawInMinimapBackground
|params = sx, sy
|params = sx, sy
|return = none
|description = Where {{var|sx}}, {{var|sy}} are values relative to the minimap's position and scale.
|description = Where <code>sx</code>, <code>sy</code> are values relative to the minimap's position and scale.
}}
}}


=== Custom Object Rendering ===
=== Custom Object Rendering ===
For the following calls <code>drawMode</code> can be one of the following, <code>notDrawing = 0</code>, <code>normalDraw = 1</code>, <code>shadowDraw = 2</code>, <code>reflectionDraw = 3</code>, <code>refractionDraw = 4</code>.
For the following calls {{var|drawMode}} can be one of the following, {{var|1=notDrawing = {{value|0}}}}, {{var|1=normalDraw = {{value|1}}}}, {{var|1=shadowDraw = {{value|2}}}}, {{var|1=reflectionDraw = {{value|3}}}}, {{var|1=refractionDraw = {{value|4}}}}.


{{LuaCallin
{{LuaCallin
|name = DrawUnit
|name = DrawUnit
|params = unitID, drawMode
|params = unitID, drawMode
|return = bool suppressEngineDraw
|return = {{type|bool}} suppressEngineDraw
|description = For custom rendering of units, [[Lua_UnitRendering#Lua.27s_DrawXYZ-Callin|enabled here]].
|description = For custom rendering of units, [[Lua_UnitRendering#Lua.27s_DrawXYZ-Callin|enabled here]].
}}
}}
Line 335: Line 295:
|name = DrawFeature
|name = DrawFeature
|params = unitID, drawMode
|params = unitID, drawMode
|return = bool suppressEngineDraw
|return = {{type|bool}} suppressEngineDraw
|description = For custom rendering of features, [[Lua_UnitRendering#Lua.27s_DrawXYZ-Callin|enabled here]].
|description = For custom rendering of features, [[Lua_UnitRendering#Lua.27s_DrawXYZ-Callin|enabled here]].
}}
}}
Line 342: Line 302:
|name = DrawShield
|name = DrawShield
|params = unitID, weaponID, drawMode
|params = unitID, weaponID, drawMode
|return = bool suppressEngineDraw
|return = {{type|bool}} suppressEngineDraw
|description = For custom rendering of [[Gamedev:WeaponDefs#Shield_(WeaponType)|shields]].
|description = For custom rendering of [[Gamedev:WeaponDefs#Shield_(WeaponType)|shields]].
}}
}}
Line 349: Line 309:
|name = DrawProjectile
|name = DrawProjectile
|params = projectileID, drawMode
|params = projectileID, drawMode
|return = bool suppressEngineDraw
|return = {{type|bool}} suppressEngineDraw
|description = For custom rendering of weapon (& other) projectiles.
|description = For custom rendering of weapon (& other) projectiles.
}}
}}

Revision as of 23:00, 17 June 2016

Lua Callins

This page is future looking to unified widget/gadget (aka "addon") handler, which may yet be some way off, c.f. the changelog.

For now, to use these addons in a widget, replace addon with widget and, for a gadget, replace addon with gadget. For example,

    function widget:UnitCreated(unitID, unitDefID, unitTeam, builderID)
        ...  
    end

Some functions may differ between (synced) gadget and widgets; those are in the #Synced_-_Unsynced_Shared section. Essentially the reason is that all information should be available to synced (game logic controlling) gadgets, but restricted to unsynced gadget/widget (e.g. information about an enemy unit only detected via radar and not yet in LOS). In such cases the full (synced) param list is documented.

Common

addon.Initialize()

{{{info}}}


addon.Shutdown()

{{{info}}}


Unsynced Only

addon.DefaultCommand()
return: number cmdID

{{{info}}}


addon.CommandNotify()
return: bool removeCmd

{{{info}}}


addon.CommandsChanged()
return: ?

{{{info}}}


addon.WorldTooltip()
return: string newTooltip

{{{info}}}


addon.UnsyncedHeightMapUpdate()

{{{info}}}


addon.GameProgress()

{{{info}}}


addon.GameSetup()
return: bool success, bool newReady

{{{info}}}


addon.SunChanged()

{{{info}}}


addon.AddConsoleLine()

{{{info}}}


addon.RecvSkirmishAIMessage()
return: ???

{{{info}}}


addon.RecvFromSynced()

{{{info}}}


addon.Save()

{{{info}}}


addon.LoadProgress()

{{{info}}}


addon.GroupChanged()

{{{info}}}


addon.ConfigureLayout()
return: ???

{{{info}}}


Input

addon.IsAbove()
return: bool isAbove

{{{info}}}


addon.GetTooltip()
return: string tooltip

{{{info}}}


addon.KeyPress()
return: bool becomeOwner

{{{info}}}


addon.KeyRelease()
return: bool

{{{info}}}


addon.TextInput()

{{{info}}}


addon.JoystickEvent()

{{{info}}}


addon.MousePress()
return: bool becomeMouseOwner

{{{info}}}


addon.MouseRelease()
return: bool becomeMouseOwner

{{{info}}}


addon.MouseWheel()

{{{info}}}


addon.MouseMove()

{{{info}}}


Players

addon.PlayerChanged()

{{{info}}}


addon.PlayerAdded()

{{{info}}}


addon.PlayerRemoved()

{{{info}}}


Drawing

addon.ViewResize()

{{{info}}}


addon.Update()

{{{info}}}


Inside the Draw* functions, you can use the Lua OpenGL Api to draw graphics.

addon.DrawGenesis()

{{{info}}}


addon.DrawWorldPreUnit()

{{{info}}}


addon.DrawWorld()

{{{info}}}


addon.DrawWorldShadow()

{{{info}}}


addon.DrawWorldReflection()

{{{info}}}


addon.DrawWorldRefraction()

{{{info}}}


addon.DrawScreen()

{{{info}}}


addon.DrawScreenEffects()

{{{info}}}


addon.DrawLoadScreen()

{{{info}}}


addon.DrawInMinimap()

{{{info}}}


addon.DrawInMinimapBackground()

{{{info}}}


Custom Object Rendering

For the following calls drawMode can be one of the following, notDrawing = 0, normalDraw = 1, shadowDraw = 2, reflectionDraw = 3, refractionDraw = 4.

addon.DrawUnit()
return: bool suppressEngineDraw

{{{info}}}


addon.DrawFeature()
return: bool suppressEngineDraw

{{{info}}}


addon.DrawShield()
return: bool suppressEngineDraw

{{{info}}}


addon.DrawProjectile()
return: bool suppressEngineDraw

{{{info}}}


Synced - Unsynced Shared

addon.GotChatMsg()
return: none

{{{info}}}


Game

addon.GameID()
return: none

{{{info}}}


addon.GamePaused()
return: none

{{{info}}}


addon.GameOver()
return: none

{{{info}}}


addon.GameFrame()
return: none

{{{info}}}


addon.GamePreload()
return: none

{{{info}}}


addon.GameStart()
return: none

{{{info}}}


Teams

addon.TeamChanged()
return: none

{{{info}}}


addon.TeamDied()
return: none

{{{info}}}


Units

addon.UnitCreated()
return: none

{{{info}}}


addon.UnitFinished()
return: none

{{{info}}}


addon.UnitFromFactory()
return: none

{{{info}}}


addon.UnitGiven()
return: none

{{{info}}}


addon.UnitTaken()
return: none

{{{info}}}


addon.UnitDamaged()
return: none

{{{info}}}


addon.UnitDestroyed()
return: none

{{{info}}}


addon.RenderUnitDestroyed()
return: none

{{{info}}}


addon.UnitStunned()
return: none

{{{info}}}


addon.UnitUnitCollision()
return: none

{{{info}}}


addon.UnitFeatureCollision()
return: none

{{{info}}}


addon.UnitCommand()
return: none

{{{info}}}


addon.UnitCmdDone()
return: none

{{{info}}}


addon.UnitLoaded()
return: none

{{{info}}}


addon.UnitUnloaded()
return: none

{{{info}}}


addon.UnitExperience()
return: none

{{{info}}}


addon.UnitIdle()
return: none

{{{info}}}


addon.UnitCloaked()
return: none

{{{info}}}


addon.UnitDecloaked()
return: none

{{{info}}}


addon.UnitMoved()
return: none

{{{info}}}


addon.UnitMoveFailed()
return: none

{{{info}}}


addon.StockpileChanged()
return: none

{{{info}}}


addon.UnitEnteredLos()
return: none

{{{info}}}


addon.UnitLeftLos()
return: none

{{{info}}}


addon.UnitEnteredRadar()
return: none

{{{info}}}


addon.UnitLeftRadar()
return: none

{{{info}}}


addon.UnitEnteredAir()
return: none

{{{info}}}


addon.UnitLeftAir()
return: none

{{{info}}}


addon.UnitEnteredWater()
return: none

{{{info}}}


addon.UnitLeftWater()
return: none

{{{info}}}


addon.UnitSeismicPing()
return: none

{{{info}}}


Features

addon.FeatureCreated()
return: none

{{{info}}}


addon.FeatureDamaged()
return: none

{{{info}}}


addon.FeatureDestroyed()
return: none

{{{info}}}


addon.FeatureMoved()
return: none

{{{info}}}


Projectiles

The following Callins are only called for weaponDefIDs registered via Script.SetWatchWeapon.

addon.ProjectileCreated()
return: none

{{{info}}}


note1 weaponDefID is missing in case the projectile is spawned as part of the burst
note2: Spring.GetProjectileDefID and Spring.GetProjectileName still work in callin scope using proID

addon.ProjectileDestroyed()
return: none

{{{info}}}


Synced Only

addon.CommandFallback()
return: bool used, bool finished

{{{info}}}


addon.AllowCommand()
return: bool allow

{{{info}}}


addon.AllowUnitCreation()
return: bool allow

{{{info}}}


addon.AllowUnitTransfer()
return: bool allow

{{{info}}}


addon.AllowUnitBuildStep()
return: bool allow

{{{info}}}


addon.AllowFeatureCreation()
return: bool allow

{{{info}}}


addon.AllowFeatureBuildStep()
return: bool allow

{{{info}}}


addon.AllowResourceLevel()
return: bool allow

{{{info}}}


addon.AllowResourceTransfer()
return: bool allow

{{{info}}}


addon.AllowStartPosition()
return: bool allow

{{{info}}}


addon.AllowDirectUnitControl()
return: bool allow

{{{info}}}


addon.AllowWeaponTargetCheck()
return: bool allowCheck, bool ignoreCheck

{{{info}}}


addon.AllowWeaponTarget()
return: bool allowed, number newPriority

{{{info}}}


addon.AllowWeaponInterceptTarget()
return: bool allowed

{{{info}}}


addon.AllowBuilderHoldFire()
return: bool actionAllowed

{{{info}}}


addon.Explosion()
return: bool noGfx

{{{info}}}


addon.TerraformComplete()
return: bool stop

{{{info}}}


addon.MoveCtrlNotify()
return: bool moveCtrlComplete

{{{info}}}


addon.RecvLuaMsg()
return: none

{{{info}}}


addon.Load()
return: none

{{{info}}}


Damage Controllers

For the following callins, in addition to being a regular weapon, weaponDefID may be one of the following:

  • -1 - debris collision, also default of Spring.AddUnitDamage
  • -2 - ground collision
  • -3 - object collision
  • -4 - fire damage
  • -5 - water damage
  • -6 - kill damage
  • -7 - crush damage

addon.UnitPreDamaged()
return: number newDamage, number impulseMult

{{{info}}}


addon.ShieldPreDamaged()
return: bool handleCollision

{{{info}}}


addon.FeaturePreDamaged()
return: number newDamage, number impulseMult

{{{info}}}