[WIP] Node UTStats 1.12C
-
- Novice
- Posts: 5
- Joined: Sat Sep 20, 2008 9:54 am
Re: nodeJS UTStats
This is a very cool project. I'm not aware of how all of this is working since I've never gotten into UT99 development. Are the stats reported by an existing module (e.g. UTStats.u) and this just communicates to your web service that stores all the data? Does this visualize the replays in any fashion, if so how does that work?
-
- Inhuman
- Posts: 753
- Joined: Thu Jun 24, 2010 10:35 pm
- Personal rank: Retard
- Location: England
Re: nodeJS UTStats
Events of matches are stored in log files from servers, and there are mutators like utstats and smart ctf that add more data to log files. This project reads the log files and imports the data inyo a database which then can be used in different ways like hraphs, replays and so on.
-
- Masterful
- Posts: 717
- Joined: Fri Aug 12, 2011 9:38 pm
- Personal rank: masterfull
- Location: https://sites.google.com/view/unrealtou ... oject/home
Re: nodeJS UTStats
Where is the data now wich website do you use.UT Sniper (SJA94) wrote:Events of matches are stored in log files from servers, and there are mutators like utstats and smart ctf that add more data to log files. This project reads the log files and imports the data inyo a database which then can be used in different ways like hraphs, replays and so on.
Or are u still tweaking the program and needed a place for online usages?
Btw a very good project sind the ng worldstats went offline.
U must have a very large space to store this all,i dont know how big the website was who where holding the original ng worldstats.
https://web.archive.org/details/http:// ... stats.com/
unreal tournament 99
®https://sites.google.com/view/unrealtou ... oject/home mine home ut99 website.
https://richardmoust105.blogspot.com/20 ... ef-in.html dutch blog page about ut99 settings.
-
- Inhuman
- Posts: 753
- Joined: Thu Jun 24, 2010 10:35 pm
- Personal rank: Retard
- Location: England
Re: nodeJS UTStats
I think you miss understood what I meant. With my system you can have a load of different servers connected to one database/website module without the need of having a different website for each server. It's not a service like 333networks for example, where you send data to a master database and view all the data of all the connected servers, although with some tweaking that can be possible without having to share private db information.
What I've tried to do is make it as easy and fast as possible to get everything set up, it's really easy to set it up so it will automatically import logs every x seconds/minutes without having to set up cron jobs or something similar. I also recently added an install script that does everything automatically for the server module, like creating the database, tables, directories, and so on.
Here is a test version online here: http://cut99.ddns.net:1337/
What I've tried to do is make it as easy and fast as possible to get everything set up, it's really easy to set it up so it will automatically import logs every x seconds/minutes without having to set up cron jobs or something similar. I also recently added an install script that does everything automatically for the server module, like creating the database, tables, directories, and so on.
Here is a test version online here: http://cut99.ddns.net:1337/
-
- Masterful
- Posts: 717
- Joined: Fri Aug 12, 2011 9:38 pm
- Personal rank: masterfull
- Location: https://sites.google.com/view/unrealtou ... oject/home
Re: nodeJS UTStats
So it works differently but the main reason is the stats.You did a great job with that.UT Sniper (SJA94) wrote:I think you miss understood what I meant. With my system you can have a load of different servers connected to one database/website module without the need of having a different website for each server. It's not a service like 333networks for example, where you send data to a master database and view all the data of all the connected servers, although with some tweaking that can be possible without having to share private db information.
What I've tried to do is make it as easy and fast as possible to get everything set up, it's really easy to set it up so it will automatically import logs every x seconds/minutes without having to set up cron jobs or something similar. I also recently added an install script that does everything automatically for the server module, like creating the database, tables, directories, and so on.
Here is a test version online here: http://cut99.ddns.net:1337/
Maby you can add some search options also,searching for the names we all use in a different way on ut 99.
unreal tournament 99
®https://sites.google.com/view/unrealtou ... oject/home mine home ut99 website.
https://richardmoust105.blogspot.com/20 ... ef-in.html dutch blog page about ut99 settings.
-
- Inhuman
- Posts: 753
- Joined: Thu Jun 24, 2010 10:35 pm
- Personal rank: Retard
- Location: England
Re: nodeJS UTStats
I've been making smartCTF for match screenshots, I just added face image loading, and all an admin will have to do is save the faces to a folder and it will automatically load them now or default to faceless if taht certain face image doesn't exist.
-
- Godlike
- Posts: 1033
- Joined: Mon Aug 31, 2015 12:58 pm
- Personal rank: Dialed in.
-
- Inhuman
- Posts: 753
- Joined: Thu Jun 24, 2010 10:35 pm
- Personal rank: Retard
- Location: England
Re: nodeJS UTStats
After looking through the utstats uscript code, and license, I figure I will add a few small things(adding player faces loging, spawn kills) to go with my utstats system, I'm a noob at uscript but what I want to add seems simple enough to do.
----edit-------
Changed utstats mutator to save player faces including bots:
---------- another edit -------------------
After messing around in uscript, I've decided to not modify the current utstats mutator and create my own little mutator without worrying about breaking stuff/stepping on peoples toes. So if I decided at a later point I want to change/add something it won't involve repackaging the whole utstats package.
----edit-------
Changed utstats mutator to save player faces including bots:
---------- another edit -------------------
After messing around in uscript, I've decided to not modify the current utstats mutator and create my own little mutator without worrying about breaking stuff/stepping on peoples toes. So if I decided at a later point I want to change/add something it won't involve repackaging the whole utstats package.
-
- Inhuman
- Posts: 753
- Joined: Thu Jun 24, 2010 10:35 pm
- Personal rank: Retard
- Location: England
Re: nodeJS UTStats
I've been working on a mutator that will run alongside UTStats, so far it saves:
- Spawn kills,
- spawn kill sprees,
- best killing spree,
- best multi kill.
- Player Faces,
- Player Voices,
- Player netspeeds,
- Player fovs,
- Player MouseSens,
- Player DodgeClickTime
I would like to ask if I'm doing anything wrong with the code?
This is my first attempt at making a mutator, I've been scanning through the classes and learning by doing more than anything instead of doing tutorials.
I'm planning on adding support for MonsterHunt and Siege at some point.
https://github.com/scottadkin/NodeUTSta ... Mutator.uc
--------edit----------
Just noticed a load of accessed nones that weren't there before.....
- Spawn kills,
- spawn kill sprees,
- best killing spree,
- best multi kill.
- Player Faces,
- Player Voices,
- Player netspeeds,
- Player fovs,
- Player MouseSens,
- Player DodgeClickTime
I would like to ask if I'm doing anything wrong with the code?
This is my first attempt at making a mutator, I've been scanning through the classes and learning by doing more than anything instead of doing tutorials.
I'm planning on adding support for MonsterHunt and Siege at some point.
https://github.com/scottadkin/NodeUTSta ... Mutator.uc
Code: Select all
//=============================================================================
// NodeUTStatsMutator.
//=============================================================================
class NodeUTStatsMutator expands Mutator;
var int CSP;
var (NodeUTStats) float SpawnKillTimeLimit;
var (NodeUTStats) float MultiKillTimeLimit;
struct nPlayer{
var PlayerReplicationInfo p;
var Pawn pawn;
var int spawns;
var float lastSpawnTime;
var int id;
var int spawnKills;
var int spawnKillSpree;
var int bestSpawnKillSpree;
var float lastKillTime;
var int currentSpree;
var int bestSpree;
var int currentMulti;
var int bestMulti;
};
var nPlayer nPlayers[64];
function int getPlayerIndex(PlayerReplicationInfo p){
local int i;
for(i = 0; i < 64; i++){
if(nPlayers[i].id == p.PlayerID){
return i;
}
}
return -1;
}
function int insertNewPlayer(Pawn p){
local int i;
local StatLog log;
local int id;
log = Level.Game.LocalLog;
for(i = 0; i < 64; i++){
if(nPlayers[i].id == -1){
nPlayers[i].p = p.PlayerReplicationInfo;
nPlayers[i].id = p.PlayerReplicationInfo.PlayerID;
nPlayers[i].pawn = p;
id = p.PlayerReplicationInfo.PlayerId;
//LOG("Inseted new player "$p.PlayerName);
log.LogEventString(log.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"Face"$Chr(9)$id$Chr(9)$nPlayers[i].p.TalkTexture);
log.LogEventString(log.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"Voice"$Chr(9)$id$Chr(9)$nPlayers[i].p.VoiceType);
log.LogEventString(log.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"NetSpeed"$Chr(9)$id$Chr(9)$PlayerPawn(p).Player.CurrentNetSpeed);
log.LogEventString(log.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"Fov"$Chr(9)$id$Chr(9)$PlayerPawn(p).FovAngle);
log.LogEventString(log.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"MouseSens"$Chr(9)$id$Chr(9)$PlayerPawn(p).MouseSensitivity);
log.LogEventString(log.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"DodgeClickTime"$Chr(9)$id$Chr(9)$PlayerPawn(p).DodgeClickTime);
return i;
}
}
}
function updateSpawnInfo(int offset){
nPlayers[offset].spawns++;
nPlayers[offset].lastSpawnTime = Level.TimeSeconds;
//LOG(nPlayers[offset].p.PlayerName$" has spawned at "$nPlayers[offset].lastSpawnTime$" Total spawns = "$nPlayers[offset].spawns);
}
function PostBeginPlay(){
local int i;
LOG("��������������� NodeUTStats started ���������������");
for(i = 0; i < 64; i++){
nPlayers[i].id = -1;
nPlayers[i].lastSpawnTime = -1;
}
}
function bool HandleEndGame(){
local int i;
local StatLog log;
for(i = 0; i < 64; i++){
if(nPlayers[i].id == -1){
break;
}
updateStats(i);
updateSpecialEvents(i, true);
log.LogEventString(log.getTimeStamp()$Chr(9)$"nstats"$Chr(9)$"SpawnKills"$Chr(9)$nPlayers[i].id$Chr(9)$nPlayers[i].spawnKills);
log.LogEventString(log.getTimeStamp()$Chr(9)$"nstats"$Chr(9)$"BestSpawnKillSpree"$Chr(9)$nPlayers[i].id$Chr(9)$nPlayers[i].bestSpawnKillSpree);
log.LogEventString(log.getTimeStamp()$Chr(9)$"nstats"$Chr(9)$"BestSpree"$Chr(9)$nPlayers[i].id$Chr(9)$nPlayers[i].bestSpree);
log.LogEventString(log.getTimeStamp()$Chr(9)$"nstats"$Chr(9)$"BestMulti"$Chr(9)$nPlayers[i].id$Chr(9)$nPlayers[i].bestMulti);
}
if(NextMutator != None){
return NextMutator.HandleEndGame();
}
return false;
}
function updateStats(int PlayerIndex){
local int bestSpawnSpree;
local int currentSpawnSpree;
local int bestSpree;
local int currentSpree;
bestSpawnSpree = nPlayers[PlayerIndex].bestSpawnKillSpree;
currentSpawnSpree = nPlayers[PlayerIndex].spawnKillSpree;
bestSpree = nPlayers[PlayerIndex].bestSpree;
currentSpree = nPlayers[PlayerIndex].currentSpree;
if(currentSpawnSpree > bestSpawnSpree){
nPlayers[PlayerIndex].bestSpawnKillSpree = currentSpawnSpree;
Log(nPlayers[PlayerIndex].p.PlayerName$Chr(9)$" just got their best spawn kill spree ("$nPlayers[PlayerIndex].spawnKillSpree$") was ("$bestSpawnSpree$")");
nPlayers[PlayerIndex].spawnKillSpree = 0;
}
if(currentSpree > bestSpree){
LOG(nPlayers[PlayerIndex].p.PlayerName$" just beat their best killing spree "$currentSpree$" was ("$bestSpree$")");
nPlayers[PlayerIndex].bestSpree = currentSpree;
}
}
function UpdateSpecialEvents(int PlayerId, bool bKilled){
local int bestMulti;
local int currentMulti;
local int bestSpree;
local int currentSpree;
local float lastKillTime;
bestMulti = nPlayers[PlayerId].bestMulti;
currentMulti = nPlayers[PlayerId].currentMulti;
bestSpree = nPlayers[PlayerId].bestSpree;
currentSpree = nPlayers[PlayerId].currentSpree;
lastKillTime = nPlayers[PlayerId].lastKillTime;
if(bKilled){
nPlayers[PlayerId].currentMulti = 0;
nPlayers[PlayerId].currentSpree = 0;
if(currentSpree > bestSpree){
nPlayers[PlayerId].bestSpree = currentSpree;
}
if(currentMulti > bestMulti){
nPlayers[PlayerId].bestMulti = currentMulti;
}
}else{
nPlayers[PlayerId].currentSpree++;
if(Level.TimeSeconds - lastKillTime <= MultiKillTimeLimit){
nPlayers[PlayerId].currentMulti++;
}else{
if(currentMulti > bestMulti){
nPlayers[PlayerId].bestMulti = currentMulti;
}
nPlayers[PlayerId].currentMulti = 1;
}
}
}
function ScoreKill(Pawn Killer, Pawn Other){
local int KillerId, OtherId;
LOG(Other.Name);
if(Killer.PlayerReplicationInfo != None){
KillerId = getPlayerIndex(Killer.PlayerReplicationInfo);
}else{
KillerId = -1;
}
if(Other.PlayerReplicationInfo != None){
OtherId = getPlayerIndex(Other.PlayerReplicationInfo);
//LOG(Other.PlayerReplicationInfo);
}else{
OtherId = -1;
}
if(KillerId != -1){
UpdateSpecialEvents(KillerId,false);
nPlayers[KillerId].lastKillTime = Level.TimeSeconds;
if(OtherId != -1){
if(Level.TimeSeconds - nPlayers[OtherId].lastSpawnTime <= SpawnKillTimeLimit){
//LOG("SPAWN KILLLLLL");
nPlayers[KillerId].spawnKills++;
nPlayers[KillerId].spawnKillSpree++;
//nPlayers[KillerId].currentSpree++;
}
updateStats(OtherId);
UpdateSpecialEvents(OtherId, true);
}
}
if(OtherId != -1){
//nPlayers[OtherId]
}
if(NextMutator != None){
NextMutator.ScoreKill(Killer, Other);
}
}
function ModifyPlayer(Pawn Other){
local int currentPID;
LOG(Other.PlayerReplicationInfo.Name);
if(Other.PlayerReplicationInfo != None && Other.bIsPlayer){
currentPID = getPlayerIndex(Other.PlayerReplicationInfo);
if(currentPID == -1){
currentPID = InsertNewPlayer(Other);
//catch players that have killed themselves
//updateStats(currentPID);
//updateSpecialEvents(currentPID, true);
}
updateStats(currentPID);
updateSpecialEvents(currentPID, true);
updateSpawnInfo(currentPID);
}
if (NextMutator != None)
NextMutator.ModifyPlayer(Other);
}
defaultproperties
{
SpawnKillTimeLimit=2.000000
MultiKillTimeLimit=3.000000
}
--------edit----------
Just noticed a load of accessed nones that weren't there before.....
-
- Skilled
- Posts: 165
- Joined: Mon Jan 24, 2011 3:22 am
- Personal rank: Codezilla
Re: nodeJS UTStats
Is this thing
working alright? According to my memory, the default constructor of UnrealEngine sets int to 0. Maybe not set them to negative in the first place. What I do not remember is if the playerids begin from 0 or something else. Later Engine versions did and do support dynamic arrays hence lesser initialization time!
How does spawnkillspree work? I am assuming obtaining specific number of spawkills without getting killed yourself. If this is true, then there should be a corresponding code for counting spawnkills and resetting the spawnkillcounter. Besides that, rest looks good.
Code: Select all
nPlayers[i].id == -1
How does spawnkillspree work? I am assuming obtaining specific number of spawkills without getting killed yourself. If this is true, then there should be a corresponding code for counting spawnkills and resetting the spawnkillcounter. Besides that, rest looks good.
Patreon: https://www.patreon.com/FreeandOpenFeralidragon wrote:Trial and error is sometimes better than any tutorial, because we learn how it works for ourselfs, which kills any doubts about anything
-
- Inhuman
- Posts: 753
- Joined: Thu Jun 24, 2010 10:35 pm
- Personal rank: Retard
- Location: England
Re: nodeJS UTStats
nPlayers.id is a copy of PlayerReplicationInfo.PlayerId, or -1 if it's an unused nPlayer struct. When a new player has their first spawn the script looks for the next nPlayer struct with the id -1, then it changes the id to the pawns PlayerID, then adds a references to the pawns PlayerReplicationInfo(think it's unneeded now I changed some stuff).The_Cowboy wrote:Is this thingworking alright? According to my memory, the default constructor of UnrealEngine sets int to 0. Maybe not set them to negative in the first place. What I do not remember is if the playerids begin from 0 or something else. Later Engine versions did and do support dynamic arrays hence lesser initialization time!Code: Select all
nPlayers[i].id == -1
How does spawnkillspree work? I am assuming obtaining specific number of spawkills without getting killed yourself. If this is true, then there should be a corresponding code for counting spawnkills and resetting the spawnkillcounter. Besides that, rest looks good.
Lol thanks for pointing out the spawnkillspree thing, atm it only resets it if the spawnkillspree is their best, I didn't notice
Thanks for pointers.
I fixed all the accessed nones:
Code: Select all
//=============================================================================
// NodeUTStatsMutator.
//=============================================================================
class NodeUTStatsMutator expands Mutator;
var int CSP;
var (NodeUTStats) float SpawnKillTimeLimit;
var (NodeUTStats) float MultiKillTimeLimit;
struct nPlayer{
var PlayerReplicationInfo p;
var Pawn pawn;
var int spawns;
var float lastSpawnTime;
var int id;
var int spawnKills;
var int spawnKillSpree;
var int bestSpawnKillSpree;
var float lastKillTime;
var int currentSpree;
var int bestSpree;
var int currentMulti;
var int bestMulti;
};
var nPlayer nPlayers[64];
function int getPlayerIndex(PlayerReplicationInfo p){
local int i;
for(i = 0; i < 64; i++){
if(nPlayers[i].id == p.PlayerID){
return i;
}
}
return -1;
}
function int insertNewPlayer(Pawn p){
local int i;
//local StatLog log;
local int id;
// log = Level.Game.LocalLog;
for(i = 0; i < 64; i++){
if(nPlayers[i].id == -1){
nPlayers[i].p = p.PlayerReplicationInfo;
nPlayers[i].id = p.PlayerReplicationInfo.PlayerID;
//nPlayers[i].pawn = p;
//id = p.PlayerReplicationInfo.PlayerID;
//LOG("Inseted new player "$p.PlayerName);
if(nPlayers[i].p.TalkTexture != None){
Level.Game.LocalLog.LogEventString(Level.Game.LocalLog.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"Face"$Chr(9)$nPlayers[i].p.PlayerID$Chr(9)$nPlayers[i].p.TalkTexture);
}
if(nPlayers[i].p.VoiceType != None){
Level.Game.LocalLog.LogEventString(Level.Game.LocalLog.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"Voice"$Chr(9)$nPlayers[i].p.PlayerID$Chr(9)$nPlayers[i].p.VoiceType);
}
if(PlayerPawn(p) != None){
Level.Game.LocalLog.LogEventString(Level.Game.LocalLog.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"NetSpeed"$Chr(9)$nPlayers[i].p.PlayerID$Chr(9)$PlayerPawn(p).Player.CurrentNetSpeed);
Level.Game.LocalLog.LogEventString(Level.Game.LocalLog.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"MouseSens"$Chr(9)$nPlayers[i].p.PlayerID$Chr(9)$PlayerPawn(p).MouseSensitivity);
Level.Game.LocalLog.LogEventString(Level.Game.LocalLog.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"DodgeClickTime"$Chr(9)$nPlayers[i].p.PlayerID$Chr(9)$PlayerPawn(p).DodgeClickTime);
Level.Game.LocalLog.LogEventString(Level.Game.LocalLog.GetTimeStamp()$Chr(9)$"nstats"$Chr(9)$"Fov"$Chr(9)$nPlayers[i].p.PlayerID$Chr(9)$PlayerPawn(p).FovAngle);
}
return i;
}
}
return -1;
}
function updateSpawnInfo(int offset){
nPlayers[offset].spawns++;
nPlayers[offset].lastSpawnTime = Level.TimeSeconds;
//LOG(nPlayers[offset].p.PlayerName$" has spawned at "$nPlayers[offset].lastSpawnTime$" Total spawns = "$nPlayers[offset].spawns);
}
function PostBeginPlay(){
local int i;
LOG("��������������� NodeUTStats started ���������������");
for(i = 0; i < 64; i++){
nPlayers[i].id = -1;
nPlayers[i].lastSpawnTime = -1;
}
}
function bool HandleEndGame(){
local int i;
//local StatLog log;
for(i = 0; i < 64; i++){
if(nPlayers[i].id == -1){
continue;
}
updateStats(i);
updateSpecialEvents(i, true);
Level.Game.LocalLog.LogEventString(Level.Game.LocalLog.getTimeStamp()$Chr(9)$"nstats"$Chr(9)$"SpawnKills"$Chr(9)$nPlayers[i].id$Chr(9)$nPlayers[i].spawnKills);
Level.Game.LocalLog.LogEventString(Level.Game.LocalLog.getTimeStamp()$Chr(9)$"nstats"$Chr(9)$"BestSpawnKillSpree"$Chr(9)$nPlayers[i].id$Chr(9)$nPlayers[i].bestSpawnKillSpree);
Level.Game.LocalLog.LogEventString(Level.Game.LocalLog.getTimeStamp()$Chr(9)$"nstats"$Chr(9)$"BestSpree"$Chr(9)$nPlayers[i].id$Chr(9)$nPlayers[i].bestSpree);
Level.Game.LocalLog.LogEventString(Level.Game.LocalLog.getTimeStamp()$Chr(9)$"nstats"$Chr(9)$"BestMulti"$Chr(9)$nPlayers[i].id$Chr(9)$nPlayers[i].bestMulti);
}
if(NextMutator != None){
return NextMutator.HandleEndGame();
}
return false;
}
function updateStats(int PlayerIndex){
local int bestSpawnSpree;
local int currentSpawnSpree;
local int bestSpree;
local int currentSpree;
bestSpawnSpree = nPlayers[PlayerIndex].bestSpawnKillSpree;
currentSpawnSpree = nPlayers[PlayerIndex].spawnKillSpree;
bestSpree = nPlayers[PlayerIndex].bestSpree;
currentSpree = nPlayers[PlayerIndex].currentSpree;
if(currentSpawnSpree > bestSpawnSpree){
nPlayers[PlayerIndex].bestSpawnKillSpree = currentSpawnSpree;
Log(nPlayers[PlayerIndex].p.PlayerName$Chr(9)$" just got their best spawn kill spree ("$nPlayers[PlayerIndex].spawnKillSpree$") was ("$bestSpawnSpree$")");
nPlayers[PlayerIndex].spawnKillSpree = 0;
}
if(currentSpree > bestSpree){
LOG(nPlayers[PlayerIndex].p.PlayerName$" just beat their best killing spree "$currentSpree$" was ("$bestSpree$")");
nPlayers[PlayerIndex].bestSpree = currentSpree;
}
}
function UpdateSpecialEvents(int PlayerId, bool bKilled){
local int bestMulti;
local int currentMulti;
local int bestSpree;
local int currentSpree;
local float lastKillTime;
bestMulti = nPlayers[PlayerId].bestMulti;
currentMulti = nPlayers[PlayerId].currentMulti;
bestSpree = nPlayers[PlayerId].bestSpree;
currentSpree = nPlayers[PlayerId].currentSpree;
lastKillTime = nPlayers[PlayerId].lastKillTime;
if(bKilled){
nPlayers[PlayerId].currentMulti = 0;
nPlayers[PlayerId].currentSpree = 0;
if(currentSpree > bestSpree){
nPlayers[PlayerId].bestSpree = currentSpree;
}
if(currentMulti > bestMulti){
nPlayers[PlayerId].bestMulti = currentMulti;
}
}else{
nPlayers[PlayerId].currentSpree++;
if(Level.TimeSeconds - lastKillTime <= MultiKillTimeLimit){
nPlayers[PlayerId].currentMulti++;
}else{
if(currentMulti > bestMulti){
nPlayers[PlayerId].bestMulti = currentMulti;
}
nPlayers[PlayerId].currentMulti = 1;
}
}
}
function ScoreKill(Pawn Killer, Pawn Other){
local int KillerId, OtherId;
LOG(Other.Name);
if(Killer.PlayerReplicationInfo != None){
KillerId = getPlayerIndex(Killer.PlayerReplicationInfo);
}else{
KillerId = -1;
}
if(Other.PlayerReplicationInfo != None){
OtherId = getPlayerIndex(Other.PlayerReplicationInfo);
//LOG(Other.PlayerReplicationInfo);
}else{
OtherId = -1;
}
if(KillerId != -1){
UpdateSpecialEvents(KillerId,false);
nPlayers[KillerId].lastKillTime = Level.TimeSeconds;
if(OtherId != -1){
if(Level.TimeSeconds - nPlayers[OtherId].lastSpawnTime <= SpawnKillTimeLimit){
//LOG("SPAWN KILLLLLL");
nPlayers[KillerId].spawnKills++;
nPlayers[KillerId].spawnKillSpree++;
//nPlayers[KillerId].currentSpree++;
}
updateStats(OtherId);
UpdateSpecialEvents(OtherId, true);
}
}
if(OtherId != -1){
//nPlayers[OtherId]
}
if(NextMutator != None){
NextMutator.ScoreKill(Killer, Other);
}
}
function ModifyPlayer(Pawn Other){
local int currentPID;
LOG(Other.PlayerReplicationInfo.Name);
if(Other.PlayerReplicationInfo != None && Other.bIsPlayer){
currentPID = getPlayerIndex(Other.PlayerReplicationInfo);
if(currentPID == -1){
currentPID = InsertNewPlayer(Other);
//catch players that have killed themselves
//updateStats(currentPID);
//updateSpecialEvents(currentPID, true);
}
if(currentPID != -1){
updateStats(currentPID);
updateSpecialEvents(currentPID, true);
updateSpawnInfo(currentPID);
}
}
if (NextMutator != None)
NextMutator.ModifyPlayer(Other);
}
defaultproperties
{
SpawnKillTimeLimit=2.000000
MultiKillTimeLimit=3.000000
}
------------edit------------------
------------edit-----------------
My goal for today is to add monsterhunt support, I've already made the mutator log kills on monsters:
-
- Inhuman
- Posts: 753
- Joined: Thu Jun 24, 2010 10:35 pm
- Personal rank: Retard
- Location: England
Re: nodeJS UTStats
Just thought I would share a screenshot of the start of monster stats, I've made it simple enough for anyone to add custom monster images by just having a JSON object with the monster class name and image location:
Code: Select all
const MonsterImages = [
{"class": "unrealshare.brute", "image": "unrealshare.brute.png"},
{"class": "unreali.behemoth", "image": "unrealshare.brute.png"},
{"class": "unrealshare.lesserbrute", "image": "unrealshare.brute.png"},
{"class": "unrealshare.cow", "image": "unrealshare.cow.png"},
{"class": "unrealshare.babycow", "image": "unrealshare.cow.png"},
{"class": "unrealshare.devilfish", "image": "unrealshare.devilfish.png"},
{"class": "unrealshare.fly", "image": "unrealshare.fly.png"},
{"class": "unreali.gasbag", "image": "unreali.gasbag.png"},
{"class": "unreali.giantgasbag", "image": "unreali.gasbag.png"},
{"class": "unreali.krall", "image": "unreali.krall.png"},
{"class": "unreali.krallelite", "image": "unreali.krall.png"},
{"class": "unreali.leglesskrall", "image": "unreali.krall.png"},
{"class": "unrealshare.manta", "image": "unrealshare.manta.png"},
{"class": "unrealshare.cavemanta", "image": "unrealshare.manta.png"},
{"class": "unrealshare.giantmanta", "image": "unrealshare.manta.png"},
{"class": "unreali.mercenary", "image": "unreali.mercenary.png"},
{"class": "unreali.mercenaryelite", "image": "unreali.mercenary.png"},
{"class": "unrealshare.nali", "image": "unrealshare.nali.png"},
{"class": "unrealshare.nalipriest", "image": "unrealshare.nali.png"},
{"class": "unreali.pupae", "image": "unreali.pupae.png"},
{"class": "unreali.pupae", "image": "unreali.pupae.png"},
// a few custom ones added here
{"class": "pupae.energypupae", "image": "unreali.pupae.png"},
{"class": "pupae.electropupae", "image": "unreali.pupae.png"},
//------------------------------
{"class": "unreali.queen", "image": "unreali.queen.png"},
{"class": "unrealshare.skaarj", "image": "unrealshare.skaarj.png"},
{"class": "unreali.skaarjtrooper", "image": "unrealshare.skaarj.png"},
{"class": "unreali.skaarjgunner", "image": "unrealshare.skaarj.png"},
{"class": "unreali.skaarjinfantry", "image": "unrealshare.skaarj.png"},
{"class": "unreali.skaarjofficer", "image": "unrealshare.skaarj.png"},
{"class": "unreali.skaarjsniper", "image": "unrealshare.skaarj.png"},
{"class": "unrealshare.skaarjwarrior", "image": "unrealshare.skaarj.png"},
{"class": "unreali.iceskaarj", "image": "unrealshare.skaarj.png"},
{"class": "unreali.skaarjassassin", "image": "unrealshare.skaarj.png"},
{"class": "unreali.skaarjberserker", "image": "unrealshare.skaarj.png"},
{"class": "unreali.skaarjlord", "image": "unrealshare.skaarj.png"},
{"class": "unrealshare.skaarjscout", "image": "unrealshare.skaarj.png"},
{"class": "unrealshare.slith", "image": "unrealshare.slith.png"},
{"class": "unreali.squid", "image": "unreali.squid.png"},
{"class": "unrealshare.tentacle", "image": "unrealshare.tentacle.png"},
{"class": "unreali.titan", "image": "unreali.titan.png"},
{"class": "unreali.stonetitan", "image": "unreali.titan.png"},
{"class": "unreali.warlord", "image": "unreali.warlord.png"},
];
-
- Godlike
- Posts: 1963
- Joined: Sat Sep 17, 2011 4:32 pm
- Personal rank: Dame. Vandora
- Location: TN, USA
Re: nodeJS UTStats
Great job for a lot of stuff you have done. I've been quietly watching you doing improvement over the years and you are getting there.
Question tho, I notice you are using Windows OS, have you had it tested on Linux or plan to check it out in the future?
@KnoW , check this out.
Question tho, I notice you are using Windows OS, have you had it tested on Linux or plan to check it out in the future?
@KnoW , check this out.
-
- Inhuman
- Posts: 753
- Joined: Thu Jun 24, 2010 10:35 pm
- Personal rank: Retard
- Location: England
Re: nodeJS UTStats
I have a raspberry pi I can test it on, and can set up a vitual box on my main pc if needed.
Ive tried to make sure everthing I use will run fine on linux, expecially file names, thats why all map, face, and monster images are all lowercase. Im fully aware most people that will use this will be running linux, and have taken precautions from the start.
When ive done monsterhunt, I will start on bunnyyrack support.
------------edit----------------
I set up virtualbox, and installed linux, there were a few small problems most of it was me just being rusty with linux, but i've fixed the problems and both modules are working fine. (Biggest problem was me forgetting to update the install script after i added more database tables)
----------edit-----------------
Ive tried to make sure everthing I use will run fine on linux, expecially file names, thats why all map, face, and monster images are all lowercase. Im fully aware most people that will use this will be running linux, and have taken precautions from the start.
When ive done monsterhunt, I will start on bunnyyrack support.
------------edit----------------
I set up virtualbox, and installed linux, there were a few small problems most of it was me just being rusty with linux, but i've fixed the problems and both modules are working fine. (Biggest problem was me forgetting to update the install script after i added more database tables)
----------edit-----------------
-
- Inhuman
- Posts: 753
- Joined: Thu Jun 24, 2010 10:35 pm
- Personal rank: Retard
- Location: England