Spawning system issue

Soul_RiderSoul_Rider Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
edited February 2012 in Modding
I'm looking at making an alternate spawning system for aliens, but I am getting confused in the current code, so some advice in the right direction would help.

Here is my plan:

Player dies and joins spectator.
Player specs for 2 secs
Hive then creates an egg for player and player is immediately placed in it.
Player spawns from egg after x secs.

I want to use the code for working out where to place an egg to immediately spawn and put the player in it, but only create it when needed, kind of like old NS used to :)

Any assistance is greatly appreciated, I'll post more on the topic when my head is a bit clearer :)

Comments

  • McGlaspieMcGlaspie www.team156.com Join Date: 2010-07-26 Member: 73044Members, Super Administrators, Forum Admins, NS2 Developer, NS2 Playtester, Squad Five Blue, Squad Five Silver, Squad Five Gold, Reinforced - Onos, WC 2013 - Gold, Subnautica Playtester
    You would be better served by not switching a player's team around. When doing so, you're going to effectively "reset" a player, so all their points and pres will be lost. Plus this would just jumble up some of the reported server data.

    It would make more sense to change the behavior of the current spawn queue system.

    I'm pretty sure the current egg placement uses the AI Pathing system to determine where and if a new egg can be placed in a specific spot.
  • Soul_RiderSoul_Rider Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
    Currently when a player dies, they join the relevant team spectator, they are queued to an available egg, and then placed inside it.
    Separately the hive checks for timing and location of placing an egg.

    I want to combine the two into one. There is no timing, and the finding of a suitable location for an egg is done, when the player is ready to be placed in the egg. It's just that code relevant to 'egg' spans 34 different files, and following the loop is getting me very confused :) Not all of it is relevant of course, and that makes it worse :)
  • McGlaspieMcGlaspie www.team156.com Join Date: 2010-07-26 Member: 73044Members, Super Administrators, Forum Admins, NS2 Developer, NS2 Playtester, Squad Five Blue, Squad Five Silver, Squad Five Gold, Reinforced - Onos, WC 2013 - Gold, Subnautica Playtester
    Take a look at the PlayingTeam.lua and AlienTeam.lua files (maybe the NS2GaemRules.lua too). I'm pretty sure that's where the spawn queue is handled and determined.
  • Soul_RiderSoul_Rider Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
    edited February 2012
    Thanks for your help McGlaspie :) If you want to check out the results, I've put the video in my mod thread :) Oh and it was too complicated undoing the aliens, so I've implemented it to marines only for now :)

    Oh and I'm looking forward to seeing your MvM mod :)
  • Soul_RiderSoul_Rider Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
    edited February 2012
    Ok, so my fix was a server side only fix :p

    I have been working on this for a while now and have got it working to a point, but I have now reached a stuck point.

    At the moment I check the team for all players who are not alive.

    For each person not alive, I increment a number ipsToBuild.

    When the IP is built, ipsToBuild is - 1.

    The problem is, I have had to put the check for not alive code in the marineteam:update code. This creates a rather large problem...

    Everytime the update code is run, it checks the queue for someone dead and adds an ip for them. So in the current code, a new Ip gets placed for each person in the queue each update. As you are queueing for quite a few updates, you can imagine what happens - Spam IPS!!! I was aware this would happen if the code worked, but I just wanted working code in the first instance :)

    There are 2 ways I can see to implement this, one is a hackaround, and the other is the graceful solution. As usual, I don't know how to do the graceful version so i'd like some help...

    Here is the current code:

    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function MarineTeam:UpdateIPBuild()

        for index, player in ipairs(self:GetPlayers()) do
            if not player:GetIsAlive() then
                ipsToBuild = ipsToBuild + 1
            end
        self:SpawnInfantryPortals(self:GetInitialTechPoint())
        end
    end<!--c2--></div><!--ec2-->

    The elegant solution I'd like to work out is:

    Initially all players are alive.
    Get the number of players in the dead queue
    No of players in queue should equal ipsToBuild + IP's built.
    If no of players in queue exceed this total, then ipstobuild +1


    The hack around idea is:
    Shorten the spawn time and only run the update every spawn time period, so in theory anyone in the queue will have spawned before the next update is run, resulting in 1 IP per person. That is a hack though so I'd rather not do it :)


    -----Edit----

    Little video of IP spam caused by mod...

    <center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/XRichLbIY70"></param><embed src="http://www.youtube.com/v/XRichLbIY70" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>

    -------Edit 2-----

    The problem is because I am trying to work off the dead queue, I need to trigger the IP spawn on player death. Is there any location other than onkill() that handles what happens when a player dies? I can't find anything. Preferably something within the team framework, but it is very small :P
  • Soul_RiderSoul_Rider Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
    edited February 2012
    This is driving me crazy. I have been working on this all day/night and don't feel like I've gotten anywhere. Here I'm going to post as much of the code and workings as possible, so hopefully someone can help me out :)

    Here is the original code that I wrote, that turned out to be server side only. This code works 100% of the time if you are hosting your own listen server:

    Marine_Server.lua:

    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Marine:SpawnInfantryPortals(techPoint)

        local techPointOrigin = techPoint:GetOrigin() + Vector(0, 2, 0)
        
        local origin = CalculateRandomSpawn(nil, techPointOrigin, kTechId.InfantryPortal, true, kInfantryPortalMinSpawnDistance * 1, kInfantryPortalMinSpawnDistance * 5, 3)
      
        if origin then

            local ip = CreateEntity(InfantryPortal.kMapName, origin, self:GetTeamNumber())
              
            SetRandomOrientation(ip)
                
            ip:SetConstructionComplete()
                        
        end
        
      
    end<!--c2--></div><!--ec2-->

    Also in the Marine:OnKill() function, I added the call to the create IP function:

    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Marine:OnKill(damage, attacker, doer, point, direction)
        self:SpawnInfantryPortals(self:GetTeam():GetInitialTechPoint())
        
        ......
        ... etc etc
        
    end<!--c2--></div><!--ec2-->

    Here is the code working on my listen server...

    <center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/6bU_5RlT9qY"></param><embed src="http://www.youtube.com/v/6bU_5RlT9qY" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>

    This works as the server host on a listen server, but not for anyone else playing the game. So how do I get this code to work for everyone and not just the server? How do I trigger it?

    I have tried many different ways around, but somewhere along the line the same problem occurs, the team information is lost. Here is the latest example, which I thought was the most promising:

    Marine_Server.lua:

    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Marine:OnKill(damage, attacker, doer, point, direction)
        
        // Drop main weapon, destroy the others.
        self:Drop(self:GetWeaponInHUDSlot(kPrimaryWeaponSlot), true)
        self:DestroyWeapons()    
        Player.OnKill(self, damage, attacker, doer, point, direction)
        self:PlaySound(Marine.kDieSoundName)
        MarineTeam:SpawnInfantryPortals(self:GetTeam():GetInitialTechPoint())
        
        // Don't play alert if we suicide
        if player ~= self then
            self:GetTeam():TriggerAlert(kTechId.MarineAlertSoldierLost, self)
        end
        
        // Remember our squad and position on death so we can beam back to them
        self.lastSquad = self:GetSquad()
        self.originOnDeath = self:GetOrigin()
        
    end<!--c2--></div><!--ec2-->

    Above I just added the line: MarineTeam:SpawnInfantryPortals(self:GetTeam():GetInitialTechPoint()) into the function.

    This calls the function in MarineTeam.lua:

    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function MarineTeam:SpawnInfantryPortals(techPoint)

        local techPointOrigin = techPoint:GetOrigin() + Vector(0, 2, 0)
        
        local origin = CalculateRandomSpawn(nil, techPointOrigin, kTechId.InfantryPortal, true, kInfantryPortalMinSpawnDistance * 1, kInfantryPortalMinSpawnDistance * 5, 3)
      
        if origin then

            local ip = CreateEntity(InfantryPortal.kMapName, origin, self:GetTeamNumber())
              
            SetRandomOrientation(ip)
                
            ip:SetConstructionComplete()
            
        end    
      
    end<!--c2--></div><!--ec2-->

    Now the IP is created and it tries to pull the player out of the respawn queue. This is where the code flags the loss of team value, in InfantryPortal.lua:

    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function InfantryPortal:QueueWaitingPlayer()

        if self:GetIsAlive() and self.queuedPlayerId == Entity.invalidId then

            // Remove player from team spawn queue and add here
            local team = self:GetTeam()
            local playerToSpawn = team:GetOldestQueuedPlayer()

            if playerToSpawn ~= nil then
                
                playerToSpawn:SetIsRespawning(true, self:GetId())
                team:RemovePlayerFromRespawnQueue(playerToSpawn)
                
                self.queuedPlayerId = playerToSpawn:GetId()
                self.queuedPlayerStartTime = Shared.GetTime()

                self:StartSpinning()            
                
                playerToSpawn:AddTooltipOncePer("SPAWNING_PORTAL_TOOLTIP")
                
                if Server then
                
                    if playerToSpawn.SetIsThirdPerson then
                        playerToSpawn:SetIsThirdPerson(3)
                    end
                
                    if playerToSpawn.SetSpectatorMode then
                        playerToSpawn:SetSpectatorMode(Spectator.kSpectatorMode.FreeLook)
                    end
                    
                    if playerToSpawn.SetOrigin then
                        playerToSpawn:SetOrigin(self:GetOrigin())
                    end

                end
                
            end
            
        end

    end<!--c2--></div><!--ec2-->

    Specifically the initial part of the function is pointed out in the error:


    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function InfantryPortal:QueueWaitingPlayer()

        if self:GetIsAlive() and self.queuedPlayerId == Entity.invalidId then

            // Remove player from team spawn queue and add here
            local team = self:GetTeam()
            local playerToSpawn = team:GetOldestQueuedPlayer()  <---------------------<!--c2--></div><!--ec2-->

    The complete error log for this is very short:

    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->Script Error #1: lua/InfantryPortal.lua:110: attempt to index local 'team' (a nil value)
        Call stack:
        #1: QueueWaitingPlayer lua/InfantryPortal.lua:110
            self = Entity{....reams of options.....}
            team = nil
        #2: lua/InfantryPortal.lua:359
            self = Entity{....reams of options......... }<!--c2--></div><!--ec2-->

    now as this is the first occurrence of nil value in team, it is important to remember team number is first passed in Marine:OnKill() so the loss of team may not be at this specific point. Saying that, I have lost team at other points using different methods, but have got passed the initial errors I had with those other methods, this time I have got as far as the ip being created, but it doesn't have a spawn queue to pull from, because it has no valid team.

    I am sure this is a fairly simple oversight, if anyone can help, I would greatly appreciate it. I've been working on this code for 12 hours straight and my mind is logic blocked :P

    Here is a video showing how far it gets in the process. I think I have resolved all the other team issues, as the IP now creates and everything, the only problem seems to be finding the spawn queue:

    <center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/ieqOhwectxE"></param><embed src="http://www.youtube.com/v/ieqOhwectxE" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>

    Any help greatly appreciated :)
  • YuukiYuuki Join Date: 2010-11-20 Member: 75079Members
    One possibility is that self:GetTeamNumber() in CreateEntity could return nil sometimes, but I guess you checked that, you could still put a check ( if nil print something ) to be sure.

    Otherwise it could go wrong on the GetTeam() side, it looks to be here :

    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->/**
    * The team object only exists on the Server.
    */
    function TeamMixin:GetTeam()

        assert(Server)
        
        if not GetHasGameRules() then
            return nil
        end
        
        return GetGamerules():GetTeam(self:GetTeamNumber())
        
    end<!--c2--></div><!--ec2-->

    Is everything done server side ? Is GetGamerules() defined ?
  • Soul_RiderSoul_Rider Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
    edited February 2012
    No, when everything is done serverside, the mod only works for the person hosting the server.

    I manually set team = GetGameRules():GetTeam1()

    So now I test it locally and it works, test it on the server and nothing. Marine:OnKill() seems to be the problem. Using this from the Marine_Server file seems to make the things only happen if the server and client are the same machine.

    I need another alternative instead of Marine:OnKill() to call the function, but there is nowhere that runs on both client and server related to the player dying. Team has OnKill function, which I tried in MarineTeam:OnKill() but the entities wouldn't pass through.

    I can't find, on the client code, anything to do with player death, except animate deathcam. I don't think it's right to try and create an IP in that code. One of my earlier versions had me writing 5 different functions in MarineTeam to try and handle the changes, but still didn't work properly. I am almost the certain that calling this on Marine_Server is the root cause of the issue only happening when machine is server and client. I need a way around that.

    It looks like I may need to go back to the first version posted and try and control the death queue through the hack I mentioned :)
Sign In or Register to comment.