class Shara_GameMod extends GameMod config(Mods); //Please change Class Name (Shara_GameMod) and expression component Class Name (Shara_ExpressionComponent) to your ones when using it. var private transient Array GhostPartyExpressions; simulated function AddGhostPartyExpression(Shara_ExpressionComponent e) //Adding OP's expression component to "updating" list. { if (IsObjectNone(e)) return; if (Hat_GhostPartyPlayer(e.Owner) == None) return; if (GhostPartyExpressions.Find(e) == INDEX_NONE) GhostPartyExpressions.AddItem(e); } simulated function IterateGhostPartyExpressions(float DeltaTime) { local class PlayerClass; local Hat_GhostPartyPlayer gpp; local int i; local bool DoUpdate; if (!IsOPARTExpressionUpdateOn()) //Don't need to update expressions if OPART already does it. DoUpdate = true; for (i = GhostPartyExpressions.Length-1; i > -1; i--) { if (IsObjectNone(GhostPartyExpressions[i])) //The Component may be destroyed. { GhostPartyExpressions.Remove(i, 1); continue; } if (!DoUpdate) continue; if (!GhostPartyExpressions[i].bAttached) //Is Component attached? continue; gpp = Hat_GhostPartyPlayer(GhostPartyExpressions[i].Owner); if (gpp == None) //Is Component owned by Online Player? continue; if (gpp.PlayerState == None) //Does Owner have Player State? continue; if (!gpp.IsTicking()) //Is Owner ticking? continue; if (gpp.WorldInfo != None && gpp.WorldInfo.Pauser != None && !gpp.bAlwaysTick) //Is game paused and Owner does not tick during pause? continue; if (gpp.PlayerState.UnreliableState.IsPaused) //Is Owner paused? { PlayerClass = gpp.PlayerVisualClass; if (PlayerClass == None) PlayerClass = class'Hat_Player_HatKid'; if (!PlayerClass.default.bAlwaysTick) //If Owner is paused and its PlayerClass does not allow it to tick during pause, we continue. continue; } GhostPartyExpressions[i].Update(Abs(gpp.WorldInfo != None ? DeltaTime/gpp.WorldInfo.TimeDilation*gpp.PlayerState.UnreliableState.CustomTimeDilation : DeltaTime), false); } } static function bool IsOPARTExpressionUpdateOn() { local class OPARTClass; if (!HasModInstalled("OnlineAnimationRepair.AnimationsRepair", OPARTClass)) return false; if (OPARTClass == None) return false; if (GetConfigValue(OPARTClass, 'mod_disabled') != 0) return false; if (GetConfigValue(OPARTClass, 'ExpressionUpdate') != 0) return false; return true; } static function bool HasModInstalled(string ModPath, optional out class ModClass) { local int i; local Array ModList; ModClass = None; if (ModPath == "" || ModPath == ".") return false; ModList = GetModList(); for (i = 0; i < ModList.Length; i++) { if (ModList[i].ModClass == None) continue; if (locs(PathName(ModList[i].ModClass)) != locs(ModPath)) continue; if (!ModList[i].IsSubscribed) continue; if (ModList[i].IsDownloading) continue; if (!ModList[i].IsEnabled) continue; ModClass = class(ModList[i].ModClass); return true; } return false; } simulated event Tick(float DeltaTime) { IterateGhostPartyExpressions(DeltaTime); } static function bool IsObjectNone(Object o) { if (o == None) return true; if (o.IsPendingKill()) return true; return false; } defaultproperties { bAlwaysTick = true }