Civ specific events

whoward69

DLL Minion
Joined
May 30, 2011
Messages
8,727
Location
Near Portsmouth, UK
If your mod contains an InGameUIAddin Lua file, it will ALWAYS execute if the player has enabled the mod - which is good.

If the Lua hooks an event, the event handler will be installed for every game and catch every event during that game - which is also good.

However, if your event handler adds functionality for a specific civ only, and that civ is not in play for a particular game, the event handler will still be installed and catch every event during that game, even though it will never actually do anything. Depending on the event hooked this can be bad!

Consider the following typical code to protect an event handler

Code:
iMyCiv = GameInfoTypes.CIVILIZATION_MYCIV

function OnSomeEvent(iPlayer, ...)
  local pPlayer = Players[iPlayer]
  if (pPlayer:GetCivilizationType() == iMyCiv) then
    -- Do something civ specific
  end
end
GameEvents.SomeEvent.Add(OnSomeEvent)

assuming the MyCiv mod is enabled, even if MyCiv is not in play, the SomeEvent is hooked and the OnSomeEvent() handler will catch every event. Most of the code (-- Do something civ specific) will never execute, but the system will still spend time calling the event, getting the player object and then deciding not to do anything.

This usually isn't a problem. Events call their handlers relatively quickly, so why should we bother?

There are several reasons why we as modders should care.
1) The event we're hooking is called many hundreds, possibly thousands of times per turn, eg UnitSetXY or LocalMachineUnitPositionChanged
2) The civ hooks many events, for example, The Morindim civ mod hooks 37 events
3) The player may have tens of custom civ mods installed and enabled, most of which are not in play

The solution is simple, only hook the event(s) if the civ is actually in play

Code:
iMyCiv = GameInfoTypes.CIVILIZATION_MYCIV

function IsCivInPlay(iCivType)
  for iSlot = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
    local iSlotStatus = PreGame.GetSlotStatus(iSlot)
    if (iSlotStatus == SlotStatus.SS_TAKEN or iSlotStatus == SlotStatus.SS_COMPUTER) then
      if (PreGame.GetCivilization(iSlot) == iCivType) then
        return true
      end
    end
  end
  
  return false
end

function OnSomeEvent(iPlayer, ...)
  local pPlayer = Players[iPlayer]
  if (pPlayer:GetCivilizationType() == iMyCiv) then
    -- Do something civ specific
  end
end
if (IsCivInPlay(iMyCiv)) then
  GameEvents.SomeEvent.Add(OnSomeEvent)
  GameEvents.SomeUbEvent.Add(OnSomeUbEvent)
  GameEvents.SomeUaEvent.Add(OnSomeUaEvent)
end

The small amount of time spent testing for the civ being in play right at the start of the game will be more than offset by the time not spent calling the event handler(s) and deciding not to do anything with the event during the game
 
Actually, IsEverAlive never failed me, but maybe I will find time to replace it with SlotStatus.
What can I say, all my mods work these way since 2013 and I recommend it for anyone. Obviously, you will not notice visible change, but it will truely matter.
 
Back
Top Bottom