Jump to content

Amineri

Premium Member
  • Posts

    1779
  • Joined

  • Last visited

Everything posted by Amineri

  1. There's nothing magical about the 0.08 seconds number. In fact, I think I wanted a longer time, but JC exported from Blender with that time-line, so we called it "good enough". The other option is to copy the full-body animation of the soldier, and attach the sound in there. This works for single-shot weapons (like Laser Sniper Rifle), but we didn't use that generally because most of our lasers use multiple shots, with multiple projectiles, and we wanted a sound for each projectile. I believe the base-game Cannon_CV does something similar -- it doesn't have a sound/projectile, but instead a single "buzz" sound that plays for the entire firing duration.
  2. The assumed framerate is 30 FPS, so 0.033 seconds is basically the length of one frame. So if/when framerate drops below 30, that sounds can get skipped over ... a bit of weirdness from Unreal Engine. During our initial testing we were either running with low graphics settings or on beefy machines, so it didn't get caught until QA was testing it. We ended up exporting and extending/re-importing the animations out to 0.08 seconds, which is good to 12.5 FPS. Below that the game is pretty unplayable anyhow, and we figure that not playing sounds is the least of concerns.
  3. I guess my checklist would be something like this : 1) Does the SoundWaveNode play in UnrealEd ? 2) Does the SoundCue play in UnrealEd ? 3) Does the sound play when playing animation in UnrealEd? 4) With graphics settings at min (for max framerate), does sound play in game ? 5) Raise graphics settings, use \slomo 1.x command to stress game until sound no longer plays #5 is to give an idea of how much margin there is, so that people with slower systems won't get missing sounds.
  4. Back on sound topic, another thing to check is that the SoundCue is part of the correct "Sound Class". This is shown underneath the SoundCue, and can be changed by right-clicking on the SoundCue in the Content Browser, and selecting : Sound Classes / Sound FX. Grouping new weapon sounds into Sound FX class allows their volume to be controlled properly by the Audio Sound Effect Volume slider.
  5. Further, the WWise toolset only allows a single project per game, adding in new WWise sounds is extra difficult. We did explore this option a bit, but the obstacles are high. You are correct that the X2UnifiedProjectileArchetype isn't currently set up for SoundCues -- only akEvents allowed.
  6. There is also an issue with config files that I've run across. If any of the config files in your mods in the SDK folder have \\ line continuations, and if any of those have whitespace after the \\ it tends to cause UnrealEditor to crash when loading. These config files are no problem when loading into the game, it's just some quirk of the UnrealEd script package. The simplest way to test this is to move your mod folders out of the SDK and try and launch UnrealEd. This will prevent UnrealEd from loading your mod script/config packages to quickly determine if it is the problem.
  7. So a little background on what's going on with the XComGame.upk replacement ... The issue before this patch 6 was that there was code to access the Steam API dll residing inside XComGame.upk. And that access was needed in order to find the mods in order to load them. This is what made it impossible to load XComGame replacements from workshop mods -- Nexus-style mods reside in the game folder, and have worked pretty much since release. Patch 6 moved the Steam API calls into the XCom2.exe, thus allowing the workshop mods to be loaded prior to XComGame.upk being loaded. However, there is currently a bug in the ported code which breaks the XComGame.upk replacement for both the workshop and Nexus-style mods XComGame replacements. I've been in contact with Firaxis to help troubleshoot the issue, so they are aware of and working it.
  8. This is a perfectly valid approach, in my humble opionion. I just decided to go down the other road, leaving more things up to the modders, which also gives (I think) more flexibility in terms of how to set it up. Plus you also went the other route of having it save to config (which is persistent across all campaigns) instead of saving into the savefile (which is only per-campaign). I debated a lot trying to decide between these two options, and I don't feel that one is necessarily clearly superior to the other in all cases, so I'm glad that the other option has been released via MCM :smile:
  9. So the issue here is that the function is called, it's just called from another native function. Unfortunately this means that you can't intercept it, as native-to-native calls don't pass through unrealscript to check for the override. To override this practically, what I've had to do is to override the upstream native function that is calling GetMultiTargetOptions. Since it is a member of X2AbilityMultiTargetStyle, the options are fairly limited. This is the method I used in the OfficerPack override to create the variable range Leader abilities. However in that case I skipped on re-implementing the GetValidTiles, since I didn't want a tile preview (having built a separate preview mechanic), and was worried about the overhead of computing all of the valid tiles in unrealscript -- things generally get optimized into native code for a reason. There are some other tricks possible to get around X2AbilityMultiTargetStyle native code, depending on the situation, which don't require completely rewriting the native code functionality in UScript. Since you are extending X2AbilityMultiTarget_Radius, what you can do is override all of the native classes, with each calling a helper that will update the fTargetRadius value based on your criteria, then continue on calling the super. native function. For example : simulated function float GetTargetCoverage(const XComGameState_Ability Abillity) { fTargetRadius = MyTargetRadiusHelper(Ability); super.GetTargetCoverage(Ability); } If you do this for each native function in the class (and the ancestor classes), as well as override GetTargetRadius completely, then whatever the hidden call order is in native code, your fTargetRadius will get set.
  10. So another thing I discovered just recently ... If you try and launch uncooked (like say want to run the debugger through some base-game code, or trying to build an XComGame replacement), you can't run with the AlienHunters DLC. I just tried, and the game hangs while trying to load a strategy savefile, with the log spamming the message : [0119.92] ScriptWarning: Accessed None 'Level' XGBase Avenger_Root.TheWorld:PersistentLevel.XGBase_0 Function XComGame.XGBase:AreAuxMapsLoaded:040C This is because the DLC is only shipped in cooked fashion, so when running uncooked it can't load what it needs to in terms of content packages. I had this problem with Anarchy's Children as well, but in that case at least I'd only get missing body part content, which was fine for debugging. In this case my suspicion is that it is trying to load the new Armory backdrop and failing, and falls into an infinite loop because of it. For now the solution is to simple turn off the DLC while doing such tests.
  11. I'll try and explain it in simple terms :) As an example, I'll mention a couple of things coming up in PerkPack, which I was able to implement without so many explicit class overrides. However, I still needed to provide some measure of the functionality needed. There were two particular cases where this came up : 1) UIArmory_Promotion -- the thing that displays the perks. We're going to have a lot more perks, so I built a new perk tree. Probably not a big surprise :) 2) Ability bar -- with more abilities (like from LeaderPack, etc), we're crowding the 15 ability limit. So we needed some solution handle 16+ active abilities on a soldiers. In both of these cases I I built a solution that swaps out the relevant class at run-time, rather than using the built-in class override system. What's the difference? 1) Built in class override. This is built into the game Engine itself. It's not code that resides in XComGame.upk, but in Engine.upk and Core.upk -- these are Epic's Unreal Engine packages that Firaxis has altered. What happens is that they overrode the Spawn and new functionality, so that when code requests to create one type of class, it actually builds another (child) class instead. Neat, and it effectively changes all instances where it's created, for those places in code that are hard to get to. The problem is that only one mod can override in this fashion, and there's no clean way to disable it, save requiring your player to go into and edit config files -- messy. 2) Replace the calling instances. This is more similar to what I did with LeaderPack, which has no explicit overrides (but does so indirectly at run-time). For PerkPack and the ability bar, for instance, instead of an explicit class override like above, I use a listener that listens for the UITacticalHUD to be created, then digs into that and finds the UITacticalHUD_AbilityContainer, and swaps it out for my customized version. The advantage here is that I can use an in-game configuration menu to turn that off and revert back to "default". Which can be either the base-game version, or one supplied by another mod. In all the cases where I can, this is what I do. However, in some cases option 2 isn't available, either because the code where the class is created is buried someplace inaccessible (like SquadSelect) or there are just too many places that call it. In that case I either have to resort to option 1, or abandon the functionality.
  12. If you mean "Are we going to break Toolbox into 4 or 5 separate mods?", then we have no plans to right now. Managing 7 mods is enough for me ... that's a lot of possible combinations to troubleshoot, plus a lot of different forums to keep up with, and mods to update with patches. In terms of separating out the class overrides, arguably the UI changes to support 12 soldiers in squad select is one of the core features. Unfortunately, there's no option at run-time to enable/disable class overrides in the general case. Where I've been able to, I've avoiding using the class override system in favor of extending the class and swapping it run-time (PerkPack actually will support this option). Unfortunately UISquadSelect is triggered in such a way that run-time swapping of the UIScreen class just isn't possible -- otherwise I would have done so on the LeaderPack. The Tuple thing is isolated -- we made it a separate mod script package for that very reason. The ModOptions was another case like SquadSelect -- called from too many places and in ways difficulty to intercept to swap in a new one at run-time.
  13. A note on manipulating cosmetic pawns... In X2CharacterTemplate, was added : var(X2CharacterTemplate) delegate<OnCosmeticUnitCreated> OnCosmeticUnitCreatedFn; However, this is used when cosmetic attachment units are created on a unit -- e.g. gremlin. This doesn't work generically whenever a cosmetic pawn is created. For that functionality, you need to use the : //Trigger to allow mods access to the newly created pawn `XEVENTMGR.TriggerEvent('OnCreateCinematicPawn', SpawnedPawn, self); called in XComGameState_Unit.CreatePawn
  14. Have verified via running it that the new X2DownloadableContentInfo.OnLoadedSavedGameToStrategy works as advertised. It runs whenever loaded into the strategy, even if the DLC/Mod was already installed. For tactical, looks like we still have to rely on UITacticalHUD screenlistener, though.
  15. So a common thing that may affect any mod that adds new abilities ... In X2Effect_Persistent.GetAttackingDamageModifier, the prototype has changed from : function int GetAttackingDamageModifier(XComGameState_Effect EffectState, XComGameState_Unit Attacker, Damageable TargetDamageable, XComGameState_Ability AbilityState, const out EffectAppliedData AppliedData, const int CurrentDamage) { return 0; } to function int GetAttackingDamageModifier(XComGameState_Effect EffectState, XComGameState_Unit Attacker, Damageable TargetDamageable, XComGameState_Ability AbilityState, const out EffectAppliedData AppliedData, const int CurrentDamage, optional XComGameState NewGameState) { return 0; } This will result in compile-time errors when building the mod against the new SDK. For mods that haven't been updated, I think this results in a CTD since there is a call in X2Effect_ApplyWeaponDamage where the NewGameState parameter is passed, and mods built under previous SDK won't be able to handle them. --------------------------------------- In terms of new functionality, some of the nicest is a series of new additions to X2DownloadableContentInfo. This includes : OnLoadedSavedGameToStrategyThis method is run when the player loads a saved game directly into Strategy while this DLC is installedOnPreMissionCalled just before the player launches into a tactical mission while this DLC / Mod is installedOnPostMissionCalled when the player completes a mission while this DLC / Mod is installedOnExitPostMissionSequenceCalled after the player exits the post-mission sequence while this DLC / Mod is installedOnPostTemplatesCreatedCalled after the Templates have been created (but before they are validated) while this DLC / Mod is active --------------------------------- One of the other nice changes in X2DownloadableContentInfo is that exec functions can now be created. For those not up-to-date on this : https://udn.epicgames.com/Three/ExecFunctions.html . This basically allows a modder to create her own console commands. Handy for testing out that big mod! :smile:
  16. Veerrry interesting idea. Basically intercepting/overriding the interface between the UScript and the Flash code to intercept imagepath string and replace them. I don't believe that this will for for retexturing 3D models, though. 3D models don't use imagepaths, and by default their textures support multiple LOD. Typically to change a model texture at run-time you have to get into the MIC (material instance constant) and change the appropriate parameter with a command like : MIC.SetTextureParameterValue('FacePaintDiffuse', FacePaintContent.texture); Textures on materials are incredibly optimized by the cooking process, with everything above 64x64 (I think) pixels being stripped from the package and being placed into a Texture File Cache (tfc). The TFC is optimized for streaming from linear media (e.g. BD/DVD). Textures get pulled at run-time from the TFC via an offset table into the TFC. ------------------------ This method as demonstrated for replacing paths works, but it may come at a heavy performance cost -- I don't think it will scale well. It is intercepting *every* QueueString call to the Flash. This includes every plain-old text and HTML formatted string being passed to display as actual text, as well as imagepaths that the Flash uses to load the image from the Unreal package. Then as the number of replacements grows, each possible replacement has to be tested against every QueueString call. Finally, this is doing a Repl operation on a (potentially) long string, which is not a constant-time operation either. Overall I'd say this is somewhere between O(n^2) and O(n^3). Another issue is enabling this for multiple mods. Since this relies on a class override, only one mod could do this. It is possible to address using tracktwo's Tuple class and a TriggerEvent, however. So I'd recommend the following : 1) Do an initial filter with an equivalent of StartsWith to check if the string begins with "img:///" which will identify it as an imagepath or not more quickly, before having to go through the Repl operation. 2) Add a TriggerEvent inside the filter to allow other mods to hook up to the same functionality. Something like the code: struct StringReplacement { var string SearchFor; var string ReplaceWith; }; var config array<StringReplacement> PathReplacements; simulated function QueueString(string Param) { local StringReplacement Path; local LWTuple StringTuple; if(Param.Left(4) == "img:") { foreach default.PathReplacements(Path) { Repl(Param, Path.SearchFor, Path.ReplaceWith); } StringTuple = new class'LWTuple'; InitTuple(StringTuple, Param); `XEVENTMGR.TriggerEvent('OnOverrideImagePath', StringTuple, self); Param = StringTuple.Data[0].s; } super.QueueString(Param); } simulated function InitTuple(out LWTuple StringTuple, string Param) { StringTuple.Id = 'OverrideImagePath'; StringTuple.Data.Add(1); StringTuple.Data[0].kind = LWTVString; StringTuple.Data[0].s = Param; } With this, any other mod that wanted to replace imagepaths could set up a listener via RegisterForEvent, and do a similar set of Repl operations on the Data[0].s value of the Tuple. Anyhow, my thoughts on this -- it looks promising!
  17. An alternative way compared to searching the ModClassOverrides list is simply to cast the screen to the base class you are expecting. For example, suppose you wanted to create a listener that listens to UISquadSelect, but want it to handle cases when UISquadSelect has been overridden. The following code will do that : class UIScreenListener_SquadSelectPlusOverrides extends UIScreenListener; event OnInit(UIScreen Screen) { if(UISquadSelect(Screen) != none) { // do stuff here } } defaultproperties { ScreenClass = none; } This works because overrides are required to be a child of the class they are overriding, so you can always cast to the parent class. Basically what we are doing here is moving the filtering from the native code backing the UIScreenListeners into the ScreenListener itself. Because the ScreenListeners only check for an exact match, and there's no option to check for child classes (as yet). So there's some performance hit because the filtering is happening in the slower unrealscript, but in practice its not a huge deal since these aren't called as part of any sort of frame-update. If you want to add a special-check case listening for a particular mod's override implementation, you can do that with the code : if(Screen.IsA('UISquadSelect_LW')) { //Do a mod specific action } Note that the argument to IsA is a name, not a Class, so you don't have to have access to the source of the other mod to check this -- just the name of the class.
  18. Right, I forgot to mention that bit! :) That's the reason we split out LWTuple from the ModOptions, so that they didn't have to come together as a "package deal". LWTuple is what you add to enable using X2EventManager for inter-mod communication, while ModOptions is what you add to interface to the Toolbox UIOptionsPCMenu system.
  19. Thanks for the kind words. Tracktwo and I worked out most of how to do that -- it was he that actually wrote the LW_Tuple class we use to pass data back and forth. As is usual, all of code is free to be re-used in other mods. In fact, the LW_XCGS_ModOptions and LW_Tuple Src folders are designed to be used exactly as is with no additional changes.
  20. Shoot, I didn't add an access method to allow other mods to change that. I'll take note of QoL features that people want -- we have to update anyhow for future DLC, so I'll see what I can get added and stable. That one should be pretty simple.
  21. Yes, fairly late in the process it was suggested that we add Shell-level access for Toolbox, and allow it to change the default config settings, but at that point the mod had been tested to be pretty stable, so we wanted to release rather than add another feature. It is a great idea, and I wish I'd thought of it sooner. The reason there's no access in the Shell is because I decided to store the mod option setting in a gamestate, attached to the CampaignSettings gamestate. The advantage here is that such settings are stored separately per campaign, making it possible to have multiple campaigns with different settings. Handy especially if two people share the same computer, for example. The downside, of course, is that the settings have to be set for each campaign.
  22. So I have just one place to check, I'm going to ask that people ask technical questions about Toolbox in this thread. There's not a whole ton of code in there, but there are few bits of tricky business involved. 1) Multiple script files in a single mod. This is done via the XComEngine.ini lines : [UnrealEd.EditorEngine] +ModEditPackages=LW_XCGS_ModOptions +ModEditPackages=LW_Tuple +ModEditPackages=LW_XCGS_ToolboxOptions Each ModEditPackage defines an additional package that should be created during the make commandlet. For Toolbox, we used this to break out separate API chunks -- lightweight interface-like classes that provide a mechanism for mods to share code. There are three of them in Toolbox : LW_XCGS_ModOptionsLW_TupleLW_XCGS_ToolboxOptionsThe ModOptions API package is the interface another mod uses to interface with the Options Menu code. You basically copy the ModOptions Src folder into your project, and it gets built and added to the other mod. Multiple mods may have this, but since it's a fixed interface, it doesn't matter which one gets loaded (so load order doesn't matter). Just doing go changing it! :smile: We are already using ModOptions in the current PerkPack to enable in-game options specific to that mod. LW_Tuple is a basic Tuple class that was built to allow inter-mod communication via the X2EventManager. If you look at the most recent version of LeaderPack, you'll see that we had added this in advance, and registered listeners to receive events that would be created by Toolbox. Toolbox Options API package is a separate bit that provides access to Toolbox specific things such as RedFog settings and SquadSize, so that other mods can directly make changes to those settings via code, without requiring users to change config, or requiring a particular load order. This is an alternative method of inter-mod communication, which has some pros and cons versus using the X2EventManager. -------------------------- 2) Inter-Mod communication As mentioned before, Toolbox implements two different mechanisms to allow inter-mod communication. A) X2EventManager -- This is the most general method, which utilizes the LW_Tuple class to pass data bi-directionally between multiple mods. One mod has the TriggerEvent, and other mods (or it) can set up RegisterForEvent methods to listen for the event. I used this to pass data between OfficerPack and Toolbox, so that OfficerPack makes use of the more-refined UISquadSelect built in Toolbox B) ModEditPackage -- This (I feel) is a more targeted method, but is useful for other things besides just inter-mod communication. It basically allows building of multiple script packages within a single mod. Using small, simple API packages allows for mods to share code-sets, which allows a richer amount of interoperability. ---------------------- I'll add more to the post as I think of things, and as questions arise! ^_^
  23. Currently we're not heavily exploring re-use of XCOM EU/EW models. Given the differences in skeletons, rigging, and materials, it's still quite a bit of work to import those models (as I see you've been doing).
  24. Yay, I can finally post here and say what I've been working on! :D As per the announcement made by 2K, we've been working on (and will be continuing to work on) 5 mods : Toolbox -- released 29 April 2016, has new squadselect/afteraction UI that supports up to 12 soldiers, plus other little goodiesPerkPack -- A bunch of new abilities we've been coding, together with some UI stuffLaserPack -- Models and code for adding a new weapon tier to the gameAlienPack -- This will be an update to the existing AlienPack (which had just the lonely Muton Centurion), adding a bunch of new enemiesMysteryMod -- I can't say what this one will be yet, but I'd imagine you all can guess :)
  25. This sounds a lot like you've got some persistent reference to UITacticalHUD (or possibly a sub-element of it), which is preventing garbage collection on the re-load process. The simplest example of how this can occur is if a UIScreenListener maintains a class reference to UITacticalHUD.
×
×
  • Create New...