Skip to content

[MOD] EEex (v0.10.2-alpha)

1383941434448

Comments

  • OlvynChuruOlvynChuru Member Posts: 3,079
    So right now I'm trying to make my mods work with the new EEex, and I'm having quite a lot of trouble. How exactly do I get offset 0 of a creature's data? In the old version of EEex, I could simply do EEex_GetActorShare(EEex_GetActorIDSelected()). But now, if I do EEex_GameObject_Get(EEex_Sprite_GetSelectedID()), it doesn't return the same thing. Am I just using the wrong function?
  • BubbBubb Member Posts: 1,005
    edited January 2023
    The new EEex model is to use field names instead of memory offsets. Memory offsets are prone to changing between versions, which was a big part of why v2.6 broke old-EEex. New-EEex uses a bindings layer to access the correct offsets behind the scenes.

    For example, see the following old-EEex function:
    function EEex_GetActorClass(actorID)
        if not EEex_IsSprite(actorID, true) then return 255 end
        return EEex_ReadByte(EEex_GetActorShare(actorID) + 0x24, 0x3)
    end
    

    and a comparable version using new-EEex:
    function B3GetClass(sprite)
        if not EEex_GameObject_IsSprite(sprite, true) then return 255 end
        return sprite.m_typeAI.m_Class
    end
    

    To migrate old code, you can look at the x86 reference to figure out what field(s) you were accessing using offsets. Note that offset 0 is often a baseclass represented as a field; these baseclass "fields" should be omitted when accessing one of their underlying fields. The x64 reference clearly defines which fields are a baseclass.

    If you are unsure which engine type has been returned by a new EEex function, you can use EEex_GetUT() for a string representation of the type name. If for any reason you need to cast a userdata object to another usertype, you can use EEex_CastUD(), (usually you don't need to worry about this, EEex tries to return the most specific type). For example, to cast a CGameObject userdata into a CGameSprite userdata:
    local sprite = EEex_CastUD(gameObject, "CGameSprite")
    

    If you really want to get a raw memory address in new-EEex, you can use EEex_UDToPtr() on a returned userdata object, and use the following functions to read/write relative to it:
    EEex_Read8(address)
    EEex_Read16(address)
    EEex_Read32(address)
    EEex_Read64(address)
    EEex_ReadU8(address)
    EEex_ReadU16(address)
    EEex_ReadU32(address)
    EEex_ReadU64(address)
    EEex_ReadPointer(address) / EEex_ReadPtr(address)
    EEex_ReadString(address)
    EEex_ReadLString(address, length)
    EEex_Write8(address, value)
    EEex_Write16(address, value)
    EEex_Write32(address, value)
    EEex_Write64(address, value)
    EEex_WritePointer(address, value) / EEex_WritePtr(address, value)
    EEex_WriteString(address, value)
    EEex_WriteLString(address, value, length)
    
    Code that uses these functions is typically NOT future proof.

    Edit: These tutorial pages might also help.
  • OlvynChuruOlvynChuru Member Posts: 3,079
    @Bubb

    Okay that helps. I didn't previously realize that the names of object properties were exactly the same as the names of fields in the EEex documentation. I was looking at, for example, the function EEex_Sprite_GetModalState and wondering where "sprite.m_nModalState" was defined; I did a search for "m_nModalState" in all Lua files and could not find any other references to it.
  • EndarireEndarire Member Posts: 1,519
    @Bubb
    REQUEST IF NOT ALREADY IMPLEMENTED: Add an option to ignore the need to gather our party before venturing forth to a different map. Instead, moving one character from the party to a map edge would be enough to move the entire party to the overworld.

    Thankee!
  • darkkhaine4594darkkhaine4594 Member Posts: 4
    I tried to install the mod on top of several others using Project Infinity, but the game crashes once I either click new game or load a save, any ideas why this is the case ?

    Most of the mods installed are the ones in the EET from morpheus562 shared on github here https://github.com/morpheus562/Baldurs-Gate-Install-Order-List-Repository, on a 2.6 BGEE version.

    Many thanks !
  • BubbBubb Member Posts: 1,005
    Hi @darkkhaine4594, the game should have created a .dmp file when it crashed. Could you zip that file and upload it here?
  • darkkhaine4594darkkhaine4594 Member Posts: 4
    @Bubb I can't find any .dmp file, neither in the game folder nor in my documents folder (alongside the saves and Baldur.lua files), it is supposed to be located there right ?
    To note, I have copied the game folder from steamapps to "D:\Games" (and my document folder is also on D drive).
  • BubbBubb Member Posts: 1,005
    @darkkhaine4594: Normally the engine saves crashes to <Drive Letter>:\Users\<User Name>\Documents\Infinity Engine - Enhanced Edition\crash

    I also fixed a crash earlier today. Might be a longshot, but could you try the attached version and see if the crash still occurs?
  • darkkhaine4594darkkhaine4594 Member Posts: 4
    @Bubb I don't know why, but I don't have dmp file for the crash mentionned (only dmp files from a previous install one year ago). Anyway, the new EEex you posted fixed the issue.

    Many thanks for your help :)
  • BubbBubb Member Posts: 1,005
    @darkkhaine4594: Glad that fixed it!


    v0.9.18-alpha:
    Fixed:
    • A serious crash in the projectile mutator code; commonly observed shortly after starting/loading a game.
    v0.9.17-alpha:
    Readded:
    • Time step module. Press 'd' while the game is paused to advance time by 1 tick, or hold to make time flow until the key is released.
    For modders:
    • Reimplemented op408, (ProjectileMutator).
    • op248/249 with (special & BIT0) != 0 now has its .EFF bypass op120.
  • Ludwig_IILudwig_II Member Posts: 379
    Hi Bubb, I have a report though not %100 sure if it's related to EEex. Whenever I open inventory, I start getting info messages like this:
    INFO: [string "menu"]:143: attempt to index field '?' (a nil value)
    stack traceback:
    return debug.traceback():1: in main chunk
    =[C]: in function '__index'
    menu:143: in function 'getItemSlot2'
    function valid000000000411EA70 () return getItemSlot2(4).valid end:1: in function <[string "function valid000000000411EA70 () return getI..."]:1>

    Of course there are no issues with getting info messages and it doesn't crash the game, however, it constantly writes these messages in a loop endlessly for all Item Slots. There is a huge feed of messages and it only stops printing these messages if I exit the inventory screen. I'm using Dragonspear UI ++ mod as well, maybe it's related to that?

    I tried the latest 0.9.18 version and it's still like this. Thanks.
  • EndarireEndarire Member Posts: 1,519
    REQUEST: Allow players to issue movement commands in areas concealed by the blackness AKA undiscovered areas. Other games at the time like StarCraft allowed this, and this helps players by saving time.

    Thankee!
  • OlvynChuruOlvynChuru Member Posts: 3,079
    Endarire wrote: »
    REQUEST: Allow players to issue movement commands in areas concealed by the blackness AKA undiscovered areas. Other games at the time like StarCraft allowed this, and this helps players by saving time.

    Thankee!

    On that note, I'd also like to request some way to enable movement commands to points that are normally not occupiable (this is so flying characters can fly to those points).

    Icewind Dale 2 actually has this feature already: if you select a character and click on a non-occupiable point, they receive an action telling them to move to that exact point.

    8sxicfop5l34.png

    Normally they immediately give up and don't actually reach their destination, but if I give them the ability to fly, I can make them move to that point correctly.

    In Beamdog's EEs however, as far as I recall, if you select a character and click on a non-occupiable point, they either won't receive any action or their move action will target the nearest occupiable point. This means I can't make flyers fly to those points, and I'd like them to be able to.
  • EndarireEndarire Member Posts: 1,519
    On a similar note, I'd also like to be able to cast spells or use abilities in black-covered areas because maybe there's something in that area worth using these abilities on.

    Thankee!
  • EndarireEndarire Member Posts: 1,519
    REQUEST: Configurable keys for EEex. Morpheus's Powergaming Scripts use an .ini.

    I mention this also because Diablo2 Kits have the D and N keys reserved.

    Thankee!
  • BubbBubb Member Posts: 1,005
    All EEex modules let you change which key(s) they use at the top of the relevant file. For example, the time step module (B3TimeStep.lua) defines B3TimeStep_Key = EEex_Key_GetFromName("d"). I admit it's not overly user friendly, but it's there.
  • EndarireEndarire Member Posts: 1,519
    Must the keys be changed before install?
  • BubbBubb Member Posts: 1,005
    You can change them before install (in the EEex/copy folder) or after install (in the override folder).
  • EndarireEndarire Member Posts: 1,519
    Thankee!
  • OlvynChuruOlvynChuru Member Posts: 3,079
    edited February 2023
    At this point, I am about 75% of the way to getting my mods to work with the current version of EEex. I only have a couple more requests:

    1. The current EEex still does not seem to have an equivalent of the EEex_HookAction function from the old EEex (which is called every time someone starts doing an action). My metamagic system requires this, as do several spells I've made.

    2. I really liked the hook for opcode 280 (trigger wild surge on spell cast) which made it so it would always do the wild surge specified in parameter1, and it could suppress the wild surge graphics and string. I used this to make Enoll Eva's Duplication (all spells trigger Wild Surge: Spell cast twice), Spellshaping: Fireball (all spells trigger Wild Surge: Fireball), and Mass Cast (the next spell triggers Wild Surge: Area effect).

    3. I'd just like to know how to call the internal function that teleports a creature to a target point without applying an effect or requiring an action (simply setting the X and Y coordinates of the creature doesn't work right). I need this in order to reimplement the flying mechanic in my mods.

    Never mind, I figured out a way to do this.

    4. On that note, how do I call the internal function you showed years ago that shatters a creature into a million pieces?
    txirarzzohba.gif
    I actually used this function at multiple points in one of my mods.
    Post edited by OlvynChuru on
  • EndarireEndarire Member Posts: 1,519
    edited February 2023
    Olvyn, thankee for the update!

    (PS: That animation was a pleasant surprise!)

    REQUEST FOR BUBB: Allow thieving skills (pick pocketing, etc.), trap placement (normal traps, Bounty Hunter traps, etc.), container manipulation (unlocking, opening, putting items in a container from inventory, and removing items from said container into a PC's inventory), and picking up items from the ground (if a character has inventory space) to be done from any distance so long as the party has sight to the destination, without moving the target character. This is meant to simulate telekinesis.

    Thankee!
    Post edited by Endarire on
  • shadowlichshadowlich Member Posts: 60
    edited February 2023
    Bubb wrote: »
    The new EEex model is to use field names instead of memory offsets. Memory offsets are prone to changing between versions, which was a big part of why v2.6 broke old-EEex. New-EEex uses a bindings layer to access the correct offsets behind the scenes.

    For example, see the following old-EEex function:
    function EEex_GetActorClass(actorID)
        if not EEex_IsSprite(actorID, true) then return 255 end
        return EEex_ReadByte(EEex_GetActorShare(actorID) + 0x24, 0x3)
    end
    

    and a comparable version using new-EEex:
    function B3GetClass(sprite)
        if not EEex_GameObject_IsSprite(sprite, true) then return 255 end
        return sprite.m_typeAI.m_Class
    end
    

    To migrate old code, you can look at the x86 reference to figure out what field(s) you were accessing using offsets. Note that offset 0 is often a baseclass represented as a field; these baseclass "fields" should be omitted when accessing one of their underlying fields. The x64 reference clearly defines which fields are a baseclass.

    If you are unsure which engine type has been returned by a new EEex function, you can use EEex_GetUT() for a string representation of the type name. If for any reason you need to cast a userdata object to another usertype, you can use EEex_CastUD(), (usually you don't need to worry about this, EEex tries to return the most specific type). For example, to cast a CGameObject userdata into a CGameSprite userdata:
    local sprite = EEex_CastUD(gameObject, "CGameSprite")
    

    If you really want to get a raw memory address in new-EEex, you can use EEex_UDToPtr() on a returned userdata object, and use the following functions to read/write relative to it:
    EEex_Read8(address)
    EEex_Read16(address)
    EEex_Read32(address)
    EEex_Read64(address)
    EEex_ReadU8(address)
    EEex_ReadU16(address)
    EEex_ReadU32(address)
    EEex_ReadU64(address)
    EEex_ReadPointer(address) / EEex_ReadPtr(address)
    EEex_ReadString(address)
    EEex_ReadLString(address, length)
    EEex_Write8(address, value)
    EEex_Write16(address, value)
    EEex_Write32(address, value)
    EEex_Write64(address, value)
    EEex_WritePointer(address, value) / EEex_WritePtr(address, value)
    EEex_WriteString(address, value)
    EEex_WriteLString(address, value, length)
    
    Code that uses these functions is typically NOT future proof.

    Edit: These tutorial pages might also help.


    Well, it's very embarrassing but I cannot make it after hours of tries :'(

    Can you show how, for example, one should read a sprite current HP ?
    Explain me as if I am a 3 years old child, please...
  • OlvynChuruOlvynChuru Member Posts: 3,079
    @shadowlich

    To get a field like a sprite's current HP, you look at the EEex documentation and find the name of the particular field. If you have an object called sprite then their current HP would be accessed by

    sprite.m_baseStats.m_hitPoints

    9uba24ccgueb.png
    nqybxrchd44t.png


    If you'd like to print the current hit points of the party member you have selected (make sure to only select one party member), enter this into the console:

    Infinity_DisplayString(EEex_Sprite_GetSelected().m_baseStats.m_hitPoints)
  • shadowlichshadowlich Member Posts: 60
    edited February 2023
    NICE :p - ty OlvynChuru

    So simple and nothing related to EEex_CastUD() or EEex_GetUT() ...
  • OlvynChuruOlvynChuru Member Posts: 3,079
    @Bubb

    Thanks for reimplementing the action hooks!

    I'm currently trying to get my metamagic system to work, and I'm encountering a problem. What exactly is being passed to the "projectile" parameter of EEex_Projectile_Hook_BeforeAddEffect? It doesn't seem like it's actually being passed the projectile object. If I insert "Infinity_DisplayString(projectile.m_projectileType)" into that function and have my character cast a fireball, it prints 19456 when it should probably print 233 (the PROJECTL.IDS index of the projectile), which is what it does print if the same print statement is put in the earlier function EEex_Projectile_Hook_OnAfterDecode.

    Also, where exactly are errors supposed to be logged in the new EEex? I can't find EEex.log in my game folder. Is the file named something different or put in a different location?
  • GraionDilachGraionDilach Member Posts: 590
    Start the game via a bat file or from the console and you get out the debug info. I was also surprised on it on the other day.
  • OlvynChuruOlvynChuru Member Posts: 3,079
    edited February 2023
    @GraionDilach
    Start the game via a bat file or from the console and you get out the debug info. I was also surprised on it on the other day.

    I tried starting the game from the Command Prompt after inserting some code that would cause a Lua error during the game, and I didn't see any error message after running that code.
  • BubbBubb Member Posts: 1,005
    OlvynChuru wrote: »
    I'm currently trying to get my metamagic system to work, and I'm encountering a problem. What exactly is being passed to the "projectile" parameter of EEex_Projectile_Hook_BeforeAddEffect? It doesn't seem like it's actually being passed the projectile object. If I insert "Infinity_DisplayString(projectile.m_projectileType)" into that function and have my character cast a fireball, it prints 19456 when it should probably print 233 (the PROJECTL.IDS index of the projectile), which is what it does print if the same print statement is put in the earlier function EEex_Projectile_Hook_OnAfterDecode.

    This should be fixed. Instead of reading a projectile you were reading the game's code; how fun!
    OlvynChuru wrote: »
    I tried starting the game from the Command Prompt after inserting some code that would cause a Lua error during the game, and I didn't see any error message after running that code.

    That should work. I personally use this command to both log and display the output:
    InfinityLoader.exe > log.txt 2>&1
    

    Can you give an example of something that isn't logging? EEex might be eating the error message, though I thought I eliminated all those cases.
  • shadowlichshadowlich Member Posts: 60
    edited February 2023
    Ok, I met and get through the EEex_UDToPtr() function,
    now I m blocked by the EEex_Sprite_ForAllOfTypeStringInRange() / EEex_Sprite_GetAllOfTypeInRange() mainly because of the aiObjectTypeString / aiObjectType parameters

    Anyone has a dumb example ?
  • OlvynChuruOlvynChuru Member Posts: 3,079
    @shadowlich
    local canSeeTarget = false
    
    local targetID = sprite.m_curAction.m_acteeID.m_Instance
    if targetID > 0 then
    	EEex_Sprite_ForAllOfTypeStringInRange(sprite, "[ANYONE]", 600, function(object)
    		if object.m_id == targetID then
    			canSeeTarget = true
    		end
    	end, true, false)
    end
    

    This code checks if sprite can see the target of their current action. This is kind of slow code, though, and I suspect there's a better way to do this.
Sign In or Register to comment.