davidlallen Posted March 13, 2016 Share Posted March 13, 2016 (edited) A number of templates contain fields which are function pointers. I want to modify some of the game templates. The technique here does the modification in AmbientNarrativeCriteria: http://forums.nexusmods.com/index.php?/topic/3839560-template-modification-without-screenlisteners/ If the function I want to reuse is a static function, this is fine, I can use the syntax class'GameClassName'.static.functionName. If I have to write my own function, that is also fine; I put it in the same file. The problem comes when I need to refer to nonstatic functions from another file. The only solution appears to be to copy all the functions, and then all the functions they refer to, which can be hundreds of lines. See here for an example in practice: http://forums.nexusmods.com/index.php?/topic/3896370-new-mod-make-neutralize-all-enmies-objective-optional/ In this mod, the template modifier needs to refer to a number of nonstatic functions from another class, and the only solution he found is to bulk copy a few hundred lines of code. Is there a better way? Edited March 13, 2016 by davidlallen Link to comment Share on other sites More sharing options...
Amineri Posted March 13, 2016 Share Posted March 13, 2016 Sometimes functions that could be used as static aren't defined as such, which is a shame since then you have to workaround calling it. If it's not static, then there's a couple of options : 1) If it belongs to a singleton instance of a gamestate, simply retrieve the singleton instance from history and then access the function.2) If it belongs to another class, and it truly can be used as static (not calling any class variables), then you can simply define a local instance of it and use new/Spawn to create it, then use the function in your local instance. Link to comment Share on other sites More sharing options...
Solariz Posted March 13, 2016 Share Posted March 13, 2016 In the case mentioned, would extending X2StrategyElement_DefaultMissionSources and emptying CreateTemplates work? Link to comment Share on other sites More sharing options...
davidlallen Posted March 13, 2016 Author Share Posted March 13, 2016 (edited) 2) If it belongs to another class, and it truly can be used as static (not calling any class variables), then you can simply define a local instance of it and use new/Spawn to create it, then use the function in your local instance.The functions are being used as callbacks, or they are called by another function doing a callback. See game file X2StrategyElement_DefaultMissionSources.uc, function CreateGuerillaOpTemplate. Field OnFailureFn is being set to a local, nonstatic function GuerillaOpOnFailure. This function calls bunch of other local, nonstatic functions in the file such as StopMissionDarkEvent, GiveRewards, SpawnPointOfInterest, etc. Once the first function is needed, then all the other functions need to get copied. For this particular case, does the new/spawn method work? What would the code look like? (The code in the mod is only one file and I can attach it if that will help.) Edited March 13, 2016 by davidlallen Link to comment Share on other sites More sharing options...
Amineri Posted March 13, 2016 Share Posted March 13, 2016 Hmm, yes, in that example, it looks to me as if the StartOnComplete should be defined as static. It's only some unrealscript delegate weirdness that is preventing it from throwing errors, I suspect. That and the native code that finds the X2DataSet-derived classes must be keeping the instances around so that the delegate can find something. Unfortunately, it seems that the handling of the X2DataSet-derived classes is only done by native code, and there's no way to access them via mod code. You might try something like : local X2StrategyElement_DefaultMissionSources MissionSources; MissionSources = new class'X2StrategyElement_DefaultMissionSources'; Template.OnFailureFn = MissionSources.StartOnComplete; However, since MissionSources is local in scope, I'm not really sure if the delegate would be able to trace back to it. Link to comment Share on other sites More sharing options...
davidlallen Posted March 13, 2016 Author Share Posted March 13, 2016 (edited) In C++, that would definitely crash. I dunno about uc. The code is declaring a local object, which is deallocated when the function exits. Later on, when the callback is actually called, that particular object instance will be long gone, and the function pointer doesn't point to anything valid. There are other cases where you want to immediately call the function, rather than registering it as a callback for later. In those cases, I agree this will work. I have done this to get the name generator, for example. I allocate the object, call the non-static function, and it works. In C++, the object I created gets deallocated, and I assume if that *doesn't* happen in uc, then the memory leak is a small one. EDIT: hm, when a class declares a variable outside the scope of any function, is that considered static? Maybe: class MyClass extends X2AmbientNarrativeCriteria; var X2StrategyElement_DefaultMissionSources MissionSources; static function DoMyWork (...) MissionSources = new class'X2StrategyElement_DefaultMissionSources'; Template.OnFailureFn = MissionSources.StartOnComplete; Edited March 13, 2016 by davidlallen Link to comment Share on other sites More sharing options...
Amineri Posted March 13, 2016 Share Posted March 13, 2016 If you need something to be ultra-persistent, you can create a UIScreenListener child class. These are created when the game loads up and aren't even destroyed/recreated when the game does a load-game. So you could create a persistent instance of X2StrategyElement_DefaultMissionSources in the ScreenListener, and reference that from your template definition. Of course, these is getting really ugly/hack-ey, basically trying to work around something that wasn't created as a static function. It may be cleaner to duplicate the code (as a static function) into your new class. Link to comment Share on other sites More sharing options...
davidlallen Posted March 13, 2016 Author Share Posted March 13, 2016 I was hoping to avoid copying code. As you know, when hundreds of lines are copy/pasted, and then a bug is fixed in the original code, the pasted version usually doesn't get maintained. Maybe future, more mod-friendly code releases can make these functions static. Is there a performance/memory reason for not doing that in the first place? Link to comment Share on other sites More sharing options...
davidlallen Posted March 23, 2016 Author Share Posted March 23, 2016 One possible approach suggested by /u/fxsjosh is here: http://forums.nexusmods.com/index.php?/topic/3839560-template-modification-without-screenlisteners/page-2&do=findComment&comment=35870935 Link to comment Share on other sites More sharing options...
zingfharn Posted March 23, 2016 Share Posted March 23, 2016 So, first up, Delegates. These little bastards are different to everything else.Most importantly, garbage collection is, while not entirely switched off, strongly discouraged, which probably bleeds into how static is used in them. As for your question, I don't think I understand the question properly, because my answer seems too easy. But. Can't you just override the class, replace the template, and build the new functions you've defined in the delegate? If you wanted to go one step further, you can hack the template in real-time, but since you'd still need to extend the class, you might as well not bother. I understand that overriding classes is not always desirable, but it seems to me like this is the perfect usecase. Link to comment Share on other sites More sharing options...
Recommended Posts