Jump to content

OVNI

Members
  • Posts

    18
  • Joined

  • Last visited

Nexus Mods Profile

About OVNI

OVNI's Achievements

Apprentice

Apprentice (3/14)

0

Reputation

  1. Sorry, I didn't come here for a while. To open multiple projects with full completion, I made a "vanilla" project that reference every source files in SrcOrig sdk's folder. Then for each instance of ModBuddy, I open this "vanilla" project first (so the extension build the DOM for the whole SDK), then I open the project I want to work with (eg: "MyModProject"). The "vanilla" project is indeed closed at this point, but I still have completion for the whole SDK while working with "MyModProject".
  2. Another scanner/parser bug report : "ref" keyword (which seems undocumented, and i didn't find any occurrences in EpicGame's UScript codebase ; maybe it's a Firaxis-specific addition ? ) makes the function definition using it not properly parsed (null nodes are created instead). note : subsequent statements seem properly parsed afterward. AFAIK this 'ref' keyword is only used in Helpers.uc ; X2EventManager.uc ; XComGameState_Unit.uc ; XComAISpawnManager.uc (all from XComGame package). example from XCom 2 SDK\Development\SrcOrig\XComGame\Classes\Helpers.uc : static native function bool IsUnitInRange(const ref XComGameState_Unit SourceUnit, const ref XComGameState_Unit TargetUnit, float MinRange = 0.0f, float MaxRange = 0.0f, float MaxAngle = 360.0f);
  3. Another issue : in comments, words are not correctly "separated". for example : /// creates a new Blablabla instance. If I double-click on a "Blablabla" it will select the whole line instead of just "Blablabla" And same thing with ctrl + left/right hotkey : it goes to beginning/end of line instead of word's.
  4. Sure, here's the class I use to store my global data. Some parts are specific to my framework obviously, you can replace PrototypeManager stuffs (and/or add new one) your own types. Or you can use the GetValue/SetValue map-like methods. use case : // store a databag object class'DataManager'.static.GetInstance().SetValue( "ModName", myModStuff ); myModStuff.foo = "bar"; ... // get it back myModStuff = class'DataManager'.static.GetInstance().GetValue( "ModName"); `log( myModStuff.foo ); // logs "bar" edit : spoiler tag edit2 : that map-like stuff should be in a separate class, it's a bit messy as it is :shameful smilley:
  5. Thanks, that helped to do some more tests. Unfortunately, it doesn't last during a whole game-session because the game de-references all actors (including screens) when the game's class changes (there's one for the lobby, one for HQ and one for tactical). But later I saw UIDataStore. UDK's doc make it looks incredibly painful to use, but in fact it's quite simple. Thankfully there's use-case in the Engine package, that helped me to figure how it works, eg : PlayerController.RegisterCustomPlayerDataStores()
  6. Only a minor issue so far, with nested multi-line comments. Parser assumes they works like C, but they don't ; they work like brackets. For example : /* /* */ This is still a comment ! (unlike in C) */ Firaxis' code relies on this behavior in multiple files, which aren't correctly parsed by Alex's extension. But we can still remove nested comments from the code to get proper color-syntaxing and get rid of false-positive syntax-errors... So once again it's a pretty minor bug. Edit : even this forum's code block can't handle those comments ! :)
  7. I've made some progress, and i'm pretty exited :smile: I've done a working proof-of-concept that allowed me to create one mod that replaces implementation of UIScreen.Show(), and another that replace UIScreen.Hide() (UIScreen being a native class). So it allows method-level overwriting instead of class-level. Both mods relies on a single highlander-style mod (which i called protolander for now) I'll probably create a public git repository for it soon, but for now, here's what the client-side code looks like : ModUsingProlander1 mod : ModUsingProlander2 mod : For now i've only created a UIScreenPrototype, and part of UIPanelPrototype (only for methods referenced by UIScreen using the super.SomeMethod() syntax or that aren't overriden). Now that the proof of concept works, the hard part would be to write a tool to generate the others 1929 prototypes ! I've investigated on the possibility to encapsulate implementation changes, eg : proto.SetImplementation('methodname', SomeDelegate) instead of proto.MethodName = SomeDelegate; but since delegates are strongly-typed reference, that would require to create a generic delegate signature, that would lead to terrible syntax overload, like "ValueWrapper MethodName( Object instance, array<ValueWrapper> arguments )" and client-code would have to unwrap and type-cast everything. Plus an array for arguments isn't very convenient... So i think i'll drop the idea of detecting mod incompatibilities like that. I think i'll just add an optional opt-in compatibility management class instead, and modders will be responsible and encouraged to declare the changes they make. eg : compatMgr.AnnouceMethodOverwritting( 'MyModName', 'UIScreen.Show') EDIT : Also, I need a globally accessible Object variable that last during the whole game session. For now I store my stuff in the game main menu but that's just a temp solution since prototypes state is reset as soon as we leave this menu... I'm not familiar at all with UDK, are gamestates object the only way to do it ? (even if i don't need my data to be stored permanently in the savegame files ?! )
  8. Only one "highlander" framework-mod that provides some prototype-based features For other mods, class overwriting would be forbidden (have to test, but the whole point is to avoid the need of overwriting classes, so...), but they could do without it : (temporary syntax, probably all wrong, making it up on the fly) // change implementation of XComCivilian.PostBeginPlay for all XComCivilian // instances *without* having to overwrite the whole XComCivilian class // so another mod could change the imp of another func and everyone will be happy // we could also make setImplementation() detect possible incompatibilites // if 2 mods try to change the impl of the same method `ENGINE.getPrototype('XComCivilian').setImplementation('PostBeginPlay', someFunction); // change implementation of XComCivilian.PostBeginPlay just for one civilian aCivilian.PostBeginPlayDelegate = someFunction; // changed my mind, use prototype's impl aCivilian.PostBeginPlayDelegate = none; // changes return value of XComCivilian.GetName (let's assume it exist) // this will work even if another mod changed GetName implementation ! `ENGINE.getPrototype('XComCivilian').listen('GetNameCalled', HandleGetNameCalled); [...] function HandleGetNameCalled( Object source ) { // vanilla implementation was called at this point (except if another mod switched it using the prototype) local XComCivilian civ; civ = XComCivilian(source); if( civ.PostBeginPlay_returnValue == "Bond" ) { // the current GetName impl returned "Bond", good, but not enought... civ.PostBeginPlay_returnValue $= "007"; // now the code that called GetName for this civilian in the first place will receive "Bond007" } } // get/set data (specific to this mod) on a civilian struct MyData { ... }; [...] local MyData data; data = MyData( aCivilian.getModData() ); data.foo = data.bar; // alternative version : we provide modname so getModData won't have to read stacktrace to determine it data = MyData( aCivilian.getModData('nameOfMyMod') ); // and maybe even implement equivalent of static fields MyStaticData( `ENGINE.getPrototype('XComCivilian').getModData() ).staticFoo = "bar";
  9. Didn't thought about the native classes, thanks. So the solution might be an "highlander" utility-mod that modify each classes so they : - dispatch events when methods are called, and allow modification of the wrapped function's inputs/output or whole method implementation if no other choice. This wrapper wont be in a subclass like in my previous example, but directly in the same class, stealing the name of the original method implementation. The original method implementation itself would be renamed, and become a delegate, used by default by the corresponding wrapping method. - make all members public - add an array of Objects that works like an hashtable with the name of the mod as key so mods could add datas (no hashtable in UnrealScript, but linear search should do : i don't think that enough mods would want store data in the same object instance to make it a performance issue). This would be a bit like using a dynamic prototype based language (javascript, lua,...) where we extend objects instead of classes. edit : hum, unrealscript doesn't allow static fields... That's a problem to mimic "prototype-like" behaviour (eg : to modify the method's implementation that will be used for ALL instances of a class). Have to think a bit more but it should be doable one way or another.
  10. Sound a good idea to solve my problem : I want to overwrite a class, but a mod i use already overwrite it... After some thought, i came with this pseudo-code : class Stuff_suffixDoesntMatter extends Stuff { var bool GetXXX_returnValue; function bool GetXXX( int i, bool b, string s ) { local ArgumentBag argumentBag; //TODO init argumentBag with given arguments `XEVENTMGR.TriggerEvent('Stuff.GetXXX:Start', argumentBag, self); GetXXX_returnValue = super.DoStuff( `SOME_MACRO(argumentBag) ); `XEVENTMGR.TriggerEvent('Stuff.GetXXX:End', argumentBag, self); return GetXXX_returnValue; }The class' behavior remains the same, it's only wrapped to dispatch events, and the modification logic would happen in the handler defined in a class specific to the mod. If both (ideally ALL) mods use the same convention, we could quite happily listen to "Start" event to modify arguments, and "End" event to modify return value (which i left public for readability, but should probably be encapsulated). Or course, to works best, once we overwrite a class when should fire those events for all its methods (not just one). Or that won't increase mod-compatibility that much... I see 2 solutions for that : 1) Create an utility-mod that overwrite every game classes, and tell the modders to not use class-overwriting anymore. Pros : - resolves compatibility problem once for all, if everybody adhere - Can overwrite X2EventManager, or even do an event system from scratch if needs be. Cons : - adds a dependency to a utility-mod that nobody would like to maintain... - Event dispatching is pretty cheap in any language... However firing 2 events for *every* function call might have a significative impact... 2) Provide auto-generation tool, and each modder will be responsible of using it when he wants to overwrite a class. Pros : - no dependency to other mod - only overwrite needed classes (and only fire event for them). Cons : - while classes from 2 mods would typically be the same, an old outdated mod could still break compatibility at some point. - Cannot overwrite X2EventManager class except if every mod includes it. I'm not sure which one i prefer (the second probably), either way a generation tool will have to be made. There's also possible enhancements i can think of : - Allow handlers to disable vanilla code (to no call super.DoStuff() in my example) - Allow to stop the event propagation (i'm really not sure if i would be an enhancement tho...). - Use it to detect probable mods incompatibilities more or less accurately, and warn the player (eg : if 2 different mods try to resign the return value of the same method, ...). That would probably imply a mechanism to deal with false positives (eg : AssumeCompatible("MyMod", "BobMod"). That would require to overwrite X2EventManager tho. I'll probably do a proof of concept soon since i'm stuck with my mod anyway, because of this very mod-compatibility issue... But the important things is to have an interface that wont change often (if at all) that everyone could be happy with ; because in the end this will only be useful if most modders use it. So i'd like to hear your suggestions.
  11. Hello, To help me figure what's going on, I managed to log (hopefully) every event calls, and function calls (with stacktrace) for XComGame package. To do that, you need to create a default mod, then go in its Src/XComGame/Classes folder with perl installed and in bash-compatible shell (should be fairy easy to convent to Windows' shell tho) execute : for i in {1..10}; do perl -pi -e 'undef $/; s/((?<!\/)\/\*((?!\/\*).)*?\*\/)//gs' *.uc; done perl -pi -e 'undef $/; s/(?<!img:)(?<!\/)\/\/.*(\n|$)/\n/g' *.uc perl -pi -e 'undef $/; s/(`if.*)\n|$/$1;\n/g' *.uc perl -pi -e 'undef $/; s/((?<!\S)event[^\=;]*?(\s*(?<name>\w*)\s*\().*?\)\s*\{(\s|((local\s)|`)(.|\n)*?;+)*)/$1\r\n\t`log("event called : $ARGV $+{name}");\n/gi' *.uc perl -pi -e 'undef $/; s/((?<!\S)function[^\=;]*?(\s*(?<name>\w*)\s*\().*?\)\s*\{(\s|((local\s)|`)(.|\n)*?;+)*)/$1\r\n\t`log("function called : $ARGV $+{name}"\$Chr(10)\$class'\''Object'\''.static.GetScriptTrace());\n/gi' *.uc Warning : if you let the whole XComGame package's files in the mod project, the game will log a HUGE amount of data (like 1GB / minute). So before building, it's better to remove everything from the project, except the classes you want to study. Build the mod (you don't need to enable it in game's launcher), then launch the game with -NOSEEKFREELOADING argument, the stuff will be logged (as usual) to %userprofile%\documents\My Games\XCOM2\XComGame\Logs\Launch.log I don't know if any other arguments are required so here's what i use : "PATH_TO\XCom2.exe" -nostartupmovies -FROMLAUNCHER -noRedScreens -review -nostartupmovies -allowconsole -LANGUAGE=INT -NOSEEKFREELOADING
  12. It would be awesome if Alex could add a tooltip to show doc-comments when pointing a type/method/class/etc. with the mouse ; while intellisense menu is visible ; and/or while typing method arguments. Sometimes when i put the mouse on an entity i see a tooltip doing just that (like "this function does stuff" ; or a less helpful "* Copyright EpicGames */"), so it looks half-implemented already. Unfortunately this doesn't show every time, and it never reappears if the source file containing the comment is opened. It doesn't need to be fancy (like pacing xml / javadoc tags) ; just showing inline/block comments written above the entity as is (even if it's just copyright header) would be very convenient already. NB : while i'm here, here's a project file referencing all SDK .uc files i use to "kickstart" Alex's extension : http://pastebin.com/arwtGDW6 Save it as "...\XCOM 2 SDK\Development\SdkProject.x2proj" (so it will use SDK files directly and stay in sync). Or save it with a copy of ...\XCOM 2 SDK\Development\SrcOrig folder (safer since you won't modify SDK's files by accident, but you'll have to keep the SrcOrig's copy up to date each time Steam/Firaxis update the SDK). Save the solution file when asked so it could show in ModBuddy's start page (you might also want to pin it).
  13. Tested the new version, but i saw no changes. I tried to create a default mod (XComGame's types completion worked for this project, no surprise) then opened an existing project (containing no SDK files) in the same ModBuddy instance, but no code-completion, nor "go to definition" (F12) for the same types. (I also tried to open both projects in 2 IDE instances, same thing). EDIT : I take that back, apparently it was because i just renamed the old version without removing it from ".../XCOM 2 SDK\Binaries\Win32\ModBuddy\Extensions" folder. I removed it, then tested to open my project containing ALL sdk .uc files, then open an empty project. Completion and go to definition works from all types from any sdk package (even those I never referenced before). Conclusion : it works perfectly, thanks.
  14. Hello, Visual Studio allows to double-click on paths logged in the output panel. For example double-clicking on "C:\MyMod\MyFile.cs(42) : Error, you can't do that !" will open MyFile.cs at line 42. Quite handy. The problem is : compilation task does not compile your source files directly, but a copy of them stored in a temporary folder (...\XCOM 2 SDK\Development\Src), and the UnrealScript compiler's output is passed to ModBuddy as is. So if you double-click on the error/warning this will open the temporary copy, and you'll have to manually open and browse the original file to fix the error/warning. The solution is to replace the compilation task, so it logs the path of original .uc file, instead of the temporary one. Let's say the SDK is stored in "C:\steam\steamapps\common\XCOM 2 SDK" 1) Create "C:\steam\steamapps\common\XCOM 2 SDK\Binaries\Win32\ModBuddy\Extensions\Application\ModdedCompileScripts.targets" (code based on decompiled XCOM2.Tasks.dll ) 2) Open "C:\steam\steamapps\common\XCOM 2 SDK\Binaries\Win32\ModBuddy\Extensions\Application\XCOM2.targets" in a text editor (make backup blahblahblah) 3) Add the following element after "<Project ...>" tag : <Import Project="ModdedCompileScripts.targets" /> 4) Replace "<CompileScripts" by "<ModdedCompileScripts"
  15. Sound interesting. DOM sharing between IDE instance is better than my walkaround IMAO, since we just need to create a project (once for all) referencing all SDK's .uc file, and open it aside our actual project. Same thing could be done for majors mods, for example a LongWar-like mod project opened in yet another IDE instance, while developing an LongWar-like addon. NB: meanwhile I edited my previous message with a new version (bug-fix) of my alternative XCOM2.targets file.
×
×
  • Create New...