"Observer" patterns in UScript - possible?

Discussions about Coding and Scripting
Post Reply
User avatar
Dizzy
Experienced
Posts: 109
Joined: Tue May 21, 2013 3:57 pm
Personal rank: Oaf
Contact:

"Observer" patterns in UScript - possible?

Post by Dizzy »

I have a limited understanding of UScript. I am a JavaScript programmer and I am used to thinking of code in terms of events which can be observed by other pieces of code.

In UScript, it seems this isn't really a built-in concept, or at least not one I've come across.

For example, I recently wanted to execute some UScript code when any player in a match fires a shock rifle and hits any surface within a specific zone.

In an event or observer-based language, to achieve this you might write something like the following pseudocode:

Code: Select all

foreach (Level.PlayerList as Player)  {
	Player
		.on("PrimaryWeaponFire", function(Event) {
			Player.ClientMessage("You used your weapon's primary fire");
			Player.ClientMessage("Your weapon was " $ Event.Weapon.Name);
		})
		.on("PrimaryWeaponImpact", function(Event) {
			Player.ClientMessage("Your primary weapon impacted something.");
			Player.ClientMessage("The impact ocurred in zone: " $ Event.Impact.Zone.Tag);
			Player.ClientMessage("The impact ocurred at co-ordinates: " $ (string) Event.Impact.Location);
			
			foreach (Event.Impact.Victims as Victim) {
				Player.ClientMessage("The impact injured " $ Victim.Name);
				Player.ClientMessage("It caused them  " $ Victim.DamageTaken $ " damage");
			}
		})
}
As I understand it, to achieve something like the above in vanilla UScript would require a lot of work.

If I understand correctly, even the first example -- triggering the message "You used your weapon's primary fire" when someone shoots -- would involve a lot of complexity such as:
• Creating a custom weapon which subclasses existing weapon(s)
• Using the `ReplaceWith` function to replace the level's existing weapons with your custom weapon(s)
• Using the `Fire()` function in your custom weapon to send the ClientMessage to the owner

But what would happen if you had multiple weapons in a map? Would you need to create new subclassed weapons for all of them just so you can observe their primary fire events?
What if the map contained a mutator which already used the ReplaceWith function to replace all the weapons with another custom weapon? Would your script just fail in that case?

So... am I completely missing something or is there just no simple way to generically and agnostically observe events like this in UScript?
Join the BunnyTrack.net Discord chat server: https://www.bunnytrack.net/discord
User avatar
Barbie
Godlike
Posts: 2802
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: "Observer" patterns in UScript - possible?

Post by Barbie »

Have a look how it is done in Nexgen:

Code: Select all

simulated function tick(float deltaTime) {
...
if (player.bFire != 0 && !bFirePressed) {
	// Fire button press.
	bFirePressed = true;
	firePressed();
} else if (player.bFire == 0 && bFirePressed) {
	// Fire button release.
	bFirePressed = false;
}
So polling is used to detect the fire button and the event firePressed() is risen then.
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
User avatar
PrinceOfFunky
Godlike
Posts: 1200
Joined: Mon Aug 31, 2015 10:31 pm

Re: "Observer" patterns in UScript - possible?

Post by PrinceOfFunky »

Dizzy wrote: Thu Apr 08, 2021 2:07 am For example, I recently wanted to execute some UScript code when any player in a match fires a shock rifle and hits any surface within a specific zone.
I created AdvancedMutator to perform these kind of tasks, you can observe an event and do stuff when that event happens. Although I never made a tutorial on how to use it, you can still check the examples.
"Your stuff is known to be buggy and unfinished/not properly tested"
1337GameDev
Skilled
Posts: 198
Joined: Thu Apr 16, 2020 3:23 pm
Personal rank: GameDev

Re: "Observer" patterns in UScript - possible?

Post by 1337GameDev »

Honestly, I wanted this too.

What I did was make a "CallbackFn" object with a function that can be overridden in subclasses and made the parent have an essentially empty function.

Each subclass can have vars that act as parameters, and are set when instantiated and added to the chain.

Then, I used the idea of "object chaining" that's used for Mutators and Inventory objects, with a reference to the next instance in the chain.

Then I added functions to remove / add instances to the chain when given an instance / name.

Then, I added a chain for every "event" that can be fired.

Then, I simply made this object a Mutator, Inventory, singleton actor, etc that has a timer that checks for certain conditions and then iterates through the relevant chains and calls the "callback" of each instance.

It's a bit annoying having to subclass each time I make a new callback and adds to build times.
Post Reply