Hello 3.0.5093 with support for event dispatchers, delegates, Blueprint functions, custom events, name collision resolution and more!


#1

Brace for another totally skookum release of your favorite game scripting language, compatible with 4.11 through 4.16!

What’s new?

In a nutshell

  • UE4 event dispatchers, delegates and multicast delegates now supported
    • event dispatchers placed in your Blueprint will show up in SkookumScript, and you can invoke them (“broadcast”) just like a closure or method simply by my_character.@my_event_dispatcher("String Parameter" 42)
    • any multicast delegate event declared and reflected in C++ with supported parameters can also be invoked via SkookumScript
    • however, listening/subscribing to event dispatchers and multicast delegate events is not yet supported - stay tuned
  • UE4 Blueprint functions and custom events now supported
    • any Blueprint function or custom event with Sk-compatible signature is now available in Sk to invoke
    • this allows you better integrate with your existing Blueprint scripts, and more easily convert Blueprint graphs over to SkookumScript
  • arrays can now be passed into and returned from SkookumScript graph nodes
  • we created a new class/struct/enum and property renaming system to resolve name collisions
    • in your project’s Config/SkookumScript.ini file, you can now add entries like this:
      +RenameProperties=Hero.My Best Enemy->@my_nicest_enemy
      +RenameClasses=Hero->Protagonist
      +RenameClasses=/Game/MyBPStruct.MyBPStruct->MyBPStruct2
    • you can use the package name (asset path) to resolve name clashes between assets with the same name located in different folders
    • the generic syntax is:
      +RenameClasses=[/Path/To/AssetPackage.]UE4ClassOrStructOrEnumName->SkookumScriptClassName
      +RenameProperties=[[/Path/To/AssetPackage.]UE4ClassOrStructName.]UE4PropertyName->@skookumscript_data_member_name
    • when you make changes to the SkookumScript.ini file, and change focus back to UE4Editor, the SkookumScript.ini file gets reloaded and script files regenerated based on the changes - then changing focus to the IDE and compiling applies the changes to the compiled binaries
  • the :sk: button in the plugin now changes state based on connection status
  • invocations of Debug.something are now stripped from code blocks in shipping builds, so you can use Debug.assert(some_test?) without slowing down your shipping game
  • lots and lots of optimizations and stability improvements

Detailed release notes

UE4 Plugin

  • UE4 delegate support V1.0
  • new Sk classes Delegate and MulticastDelegate
  • Blueprint array support V1.0
  • new UE4->Sk rename system V1.0
  • in SkookumScript.ini, a new key +RenameClasses exists, specifying a rename rule for a class/struct/enum in the format [package_name.]UE4TypeName->SkookumScriptClassName
  • in SkookumScript.ini, a new key +RenameProperties exists, specifying a rename rule for a property/data member in the format [[package_name.]owner_name.]UE4PropertyName->@skookumscript_data_member_name
  • finally (re-)enabled Blueprint function and custom event support
  • Sk button changes state based on connection status
  • SkookumScriptGenerator generates script code for delegate data types
  • fixed error where the parent meta file Enum was not generated for user defined enums
  • fixed case of #included files to be consistent
  • treat empty ctors/dtors as absent when checking if a class needs a SkookumScriptInstanceProperty
  • fixed timing of deleting project-generated script files in read-only project mode that would cause compile errors
  • fixed bug where deleting a Blueprint without generated class would not properly delete the associated Sk script files
  • when the runtime skips binary loading due to errors, recompiling on the IDE now triggers a reload of the binaries on the runtime
  • enabled storage of SkookumScriptInstanceProperties in cooked data
  • simplified runtime type checks
  • include project debug info (project name, project paths) in compiled binary so that on a remote connection, the IDE knows where to look for the project file
  • in cooked builds, do not request the binaries to be compiled, as they might be on a different host - instead, load binaries, then connect to host
  • fixed bug in raw Enum accessor function
  • skookification of all class/struct/enum and data member names gets routed through the renaming system
  • when UE4Editor gains focus, SkookumScript.ini gets reloaded and, if changes are detected, all project-generated classes are regenerated
  • new runtime callback on_application_focus_changed
  • bind name support V1.0
  • SkTypedNameRaw now stores a bind name which is implemented in the UE4 plugin as the FName of the original UE4 UProperty
  • SkAppInfo now has a number of new functions related to handling app-sepcific bind name construction/destruction/getting
  • SkClass now has a bind name member that is used for UE4 class lookup
  • optimized bind name serialization functions
  • fixed some raw data member mapping issues by comparing FNames irrespective of their number
  • added code to ensure that in read-only mode, upon connection to IDE, classes are generated first, then binaries are compiled, then data is generated, to ensure that known types are properly recognized
  • improved error message when a reparented class is detected during incremental update
  • added text serialization functionality to USkookumScriptInstanceProperty so that Sk actors can be copied & pasted
  • added missing include statement to SkookumScriptGenerator
  • properly support classes exported from project folder that are not script supported, just referenced
  • fixed skookification of boolean data member names
  • fixed misalignment of data members in !Data.sk file
  • fixed compile errors caused by complete skipping of classes in runtime generator - classes are now always generated, just data and method generation is skipped on classes marked as skipped
  • integrated PS4-specific fixes from Roberto

SkookumIDE

  • updated New Class or Member pane to only expand if Skookified and there is an editable overlay
  • modified New Class or Member pane messages - Skookify, Need Connection, Need editable overlay - to be more clear and friendly since they are some of the first prompts experienced by new users.
  • meta files are now parsed in first pass when classes are discovered to pick up annotations before declaration parsing begins
  • fixed crash when deleting a class while a member is open in the IDE
  • fixed improper handling of default project path when IDE and game are launched from different UE4 versions
  • fixed bug with invalidation of deleted classes
  • fixed a number of asserts related to discovery of class/member deletion
  • made error message clearer when trying to edit a file in a read-only overlay
  • fixed overlay default folder paths as the current paths were causing issues
  • fixed bug when receiving data in multiple packets
  • in New Class or Member changed hint string to use pipes “|” rather than commas to indicate alternate choices
  • updated New pane error text
  • fixed bug in incremental update logic
  • fixed graphical glitch in source control settings widget
  • fixed crash happening on source files larger than 64K by replacing a number of 16-bit variables with 32-bit equivalents

SkookumScript

  • invocations of Debug.something are now stripped from code blocks in shipping builds
  • optimized List methods by writing them in C++: all?(), any?(), do_idx(), find?()
  • optimized List methods by writing them using do(): !fill(), do_branch(), do_reverse()
  • changed SkIntegerType, SkRealType etc. typedefs to tSkInteger, tSkReal etc.
  • new annotation &invokable for classes to mark as invokable
  • &raw annotation now takes an optional name argument that represents the original UE4 FName
  • added &name annotation for classes to specify an optional bind name
  • new syntax for invokable classes that allows the class descriptor to be prefixed with a specific class, e.g. MulticastDelegate(Actor the_actor)
  • abstracted closure invocation into a polymorphic mechanism that allows to “invoke” any instance not just closures (new virtual invoke and invoke_as_method methods on SkInstance)
  • new struct SkClosureInvokeInfo for passing invocation information to invoked SkInstances, and to hide SkExpression implementation
  • have Integer@to_pre() do nothing if first and last indexes are the same
  • added new SkInvokableBase::is_empty() that determines if a routine is empty (i.e. if its expression is a single nil)
  • bodies of SkMethodCall<SkInvokeType_method_assert>::invoke_call() and SkMethodCall<SkInvokeType_method_assert_no_leak>::invoke_call() are stripped out in shipping builds
  • fixed potential instance leak in SkList
  • fixed DLL linkage issues with static members
  • fixed faulty tallying of data member count
  • added proper handling for typed/union/invokable classes that reference deleted SkClasses (so that no stale class references get written to binary which cause crash on runtime)
  • added proper transitive closure loop for purging unreferenced typed/union/invokable classes
  • added parser error when actor class can not be determined
  • converted SkObjectID to use the new bind name system
  • removed knowledge of SkObjectID from public Sk files in preparation for making the files private
  • made SkObjectID header files private as they no longer need to be public
  • added convenience member functions to SkBindName that all ow more elegant use of the structure
  • SkookumScriptRuntime::on_struct_added_or_modified now also always generates a root UStruct class

AgogCore

  • new enum eALeaveMemoryUnchanged to use a ctor argument to indicate the ctor should not alter memory at all (for vtable hot-swapping)

Get the new plugin from our GitHub repository or as a good old precompiled zip file for Epic Games Launcher users. It will also be available on the Marketplace very soon!

As usual, don’t hesitate to ask us for help if you encounter any issues!

Enjoy!!

See previous update:


Trying To Call Custom Functions on Custom Pawn From C++
Minor update (P4 + GitHub only): Unreal Tournament support, tweaks and stability improvements
SkookumScript for UnrealTournament?
#2

#3

Argh!

However, in every other way, amazing release!
Those notes are almost as large as the Unreal Engine release notes =P


#4

4 posts were split to a new topic: Enum typing issues


#5

I suddenly find myself in the same boat as you Jacob. :cry:

I just wrote up some requirements for the condition/buff/debuff system in my toy rpg project. Was all excited about finally having worked out exactly what/how I wanted it to work/do both from a gameplay perspective and a c++/sk/bp perspective. The whole thing centres on being able to sub to delegate events fired off from c++. I could go through blueprints to do it, but I find bp so cumbersome.

Oh well, I have a million other things I can do in the meantime, :smile: all accelerated by :sk:

By chance is there a rough time frame for that feature?


#6

Subscribing to delegate events declared in C++ is already supported!

For an example, look at AActor::OnActorBeginOverlap. The generator plugin automatically generates three coroutines from it: _on_actor_begin_overlap_do, _on_actor_begin_overlap_do_until, and _wait_actor_begin_overlap. If you declare your own delegate in C++, Sk can listen to it. The feature that is still unsupported is listening to Blueprint event dispatchers.


#7

OH! Oops :smiley:

You just made my day!


#8

Just in case anyone has any trouble with it I figured I would quickly jot down how I got the :sk: side of things working in regards to “binding” the delegates in :sk:. It’s been a long day without enough coffee and I’m still an :sk: noob so I was a tad confused for a bit.

After making my delegate in C++ and setting up a quick test in BP to make sure everything was sane and working, I went into the :sk: class I wanted to have listen to that particular delegate and added this line to my constructor (doesn’t have to go there, just wanted to have it sub to the delegate right away):

branch [objectIWantToListenTo._my_first_sk_delegate_do [this.delegate_test]]

where delegate_test is just a function defined in the class I wanted to listen for the event.

()
    [
    println("Success!")
    ]

Pretty simple, incredibly useful.

As always thanks to our resident mad compsci guys!

Edit: Oh, the delegate signatures in :sk: don’t seem to need to match the signatures in C++ so don’t worry about that.


Delegates defined in C++ and their inputs
#9

I would like it if skookum had its own event system built into the language much like we have behaviors now. We can write our events in skookum and consume them in skookum. Basically, I want skookum to take over the world.


#10

Yes, world domination is our ultimate goal :grin:

You can easily build an event system in SkookumScript using a list of closures, e.g. like this:

!my_event_dispatcher: List{(Actor input_actor)}! 
my_event_dispatcher.append(^[println("Hello my name is " input_actor.name)])
my_event_dispatcher.append(^[println("I am at " input_actor.transform.@translation)])
my_event_dispatcher.do[item(Hero.instances_first)]

This creates a list of closures taking an Actor as argument. It adds two different listeners to the list, one that prints the actor’s name, and one that prints the actor’s location. It then invokes all closures in the list with an instance of the actor class Hero.

Is this what you had in mind?


#11

It would be more like this crappy, suspiciously similar to skookum, psuedocode(not saying skookum is crappy just my psuedocode is, I was never good at that stuff)…

somewhere in hero:
subscribe(“goblin_damage” take_damage)

take_damage[
take some damage if hero was the one who was hit
]

somewhere in goblin:
if weapon collides with something [
broadcast(“goblin_damage”)
]

I know something like this can easily be built by me, but I would like it to be part of the language, just like behaviors are, since this is such a common pattern. That way, I can use even more marketing terms for advertising skookum… A time sliced, event oriented, super bodacious language you always needed but never knew it! It will make all you dreams come true! You can make games without even thinking, you can just drool at your keyboard and a game will pop out!

Lol, ok, I will not go that far with marketing :stuck_out_tongue_winking_eye:


#12

Well you could do something very similar with the system I just outlined.

You’d have an EventManager class with a static (class member) event list for each event type you want to trigger:

List{(Integer damage_points)} !@@goblin_damage
List{(Vector3 blast_center)}  !@@grenade_blast

Then in your hero constructor, you’d say
@goblin_damage_handler : ^[println("OMG a goblin dealt me " damage_points " points of damage!")] and then
EventManager.@@goblin_damage.append(@goblin_damage_handler) to subscribe to the goblin damage event

(and in the destructor EventManager.@@goblin_damage.remove_same(@goblin_damage_handler)).

Then in the goblin class you’d trigger it via EventManager.@@goblin_damage.do[item(42)]

You can wrap both of these into subscribe_goblin_damage and broadcast_goblin_damage methods if you like.

We are always thinking to expand and improve the language and events is definitely such an area. Will give it some more thought!


Trying To Call Custom Functions on Custom Pawn From C++
Is there something analogous to callbacks as opposed to closures?
#13

I think this example belongs in the Primer under the closures section as it is a great example of using them. I read it a long time ago and it really stretched my mind and I’ve had a difficult time finding it again until today. This is a super straight-forward way to do an event system once the basic concept and parts sink in.