Tick Listeners causing Server Crashes

Please post any questions about developing your plugin here. Please use the search function before posting!
Predz
Senior Member
Posts: 158
Joined: Wed Aug 08, 2012 9:05 pm
Location: Bristol, United Kingdom

Tick Listeners causing Server Crashes

Postby Predz » Fri Feb 05, 2016 9:59 am

Hey, This is a problem I have encountered whilst working on WCGO.

I have a few servers I have access on to test stuff and am now testing on a new linux server. Muerte has supplied me with access to his server which runs linux on multiple virtual machines. I have tested all my heroes and items on "servers" I have purchased from companies with no issues. However I run the exact same plugins, and WCGO version onto Muerte's machine, and the server crashes upon Delays and TickRepeat being initialized.

Comes up with this in the logs when I have the config logger set to 5. This is spammed a few times and then the server just fails to respond, then crashes entirely.

Code: Select all

TickRepeat.execute - No limit


I have tested multiple heroes with and without Delays and TickRepeats. Only the heroes that use the TickListeners ever crash the server.

Muerte is currently running a RPG plugin which uses Delays and TickRepeats and it doesn't cause crashes like my versions, so I am completely unsure of the problem. I will provide a hero below to show what causes the issues.

Code: Select all

"""Default hero from WCGO core."""

# Python3
from random import randint

# Source.Python
from colors import Color
from mathlib import Vector
from entities.entity import Entity
from listeners.tick import Delay
from messages import SayText2
from players.constants import PlayerButtons

# Warcraft: GO
from wcgo.cooldown import cooldown, cooldownf
from wcgo.effects import models
from wcgo.entities import Hero, Skill
from wcgo.player import Player, PlayerIter

class Hunter(Hero):
    'Expert marksmen who use the concealing forests of Kalimdor.'

    max_level = 40
    category = 'DEFAULT'
    cost = 0


@Hunter.skill
class Hide(Skill):
    'Decreased visibility to enemies. Fully stealthed when stood still.'

    max_level = 8

    _is_invis = False

    _movement_buttons = (PlayerButtons.FORWARD,
        PlayerButtons.MOVELEFT,
        PlayerButtons.MOVERIGHT,
        PlayerButtons.LEFT,
        PlayerButtons.RIGHT,
        PlayerButtons.BACK)

    @property
    def _invis(self):
        return 255 - (self.level * 15)

    def player_death(self, player, **eargs):
        color = player.color
        color.a = 255
        player.color = color


    # This is just a hook on the player 'run_command' func
    def player_run_command(self, player, usercmd, **eargs):
        for button in self._movement_buttons:
            if usercmd.buttons & button:
                if self._is_invis:
                    color = player.color
                    color.a = self._invis
                    player.color = color

                    self._is_invis = False
                return

        if not self._is_invis:
            color = player.color
            color.a = 0
            player.color = color

            self._is_invis = True

@Hunter.ability
class Hunters_Mark(Skill):
    'Mark a random enemy, and deal extra damage to him.'

    ability = 1

    max_level = 8

    _effect = None
    _target = None

    _msg_a = '>> \x04Hunter\'s Mark: \x05{player} has \x02marked \x05{enemy} for \x02death!'

    @property
    def _multiplier(self):
        return 1.2 + (self.level * 0.1)

    def player_spawn(self, player, **eargs):
        self._target = None

    def player_pre_attack(self, player, victim, info, **eargs):
        if self._target and self._target.userid == victim.userid:
            info.damage *= self._multiplier

            if info.damage > victim.health:
                self._target = None

                self._effect.call_input('Kill')
                self._effect = None

    @cooldown(10, message='>> \x04Hunter\'s Mark: \x05On cooldown for \x04{remaining_cd:0.0f} seconds\x01.')
    def player_use(self, player, **eargs):
        targets = []
        for target in PlayerIter():
            if player.team != target.team and not target.isdead:
                targets.append(target)

        if len(targets) == 0:
            return

        index = randint(1, len(targets)) - 1
        target = targets[index]
        self._target = target

        SayText2(self._msg_a.format(player=player.name, enemy=target.name)).send()

        # EFFECT

        if self._effect:
            self._effect.call_input('Kill')

        self._effect = effect = Entity.create('env_smokestack')

        location = target.origin
        location.z += 96
        effect.teleport(location, None, None)
        effect.base_spread = 24
        effect.spread_speed = 0
        effect.start_size = 7
        effect.end_size = 7
        effect.jet_length = 10
        effect.angles = Vector(90, 90, 90)
        effect.rate = 60
        effect.speed = 40
        effect.twist = 720
        effect.render_mode = 18
        effect.render_amt = 100
        effect.render_color = Color(255, 255, 3)
        effect.add_output('SmokeMaterial Effects/Redflare.vmt')
        effect.turn_on()
        effect.set_parent(target.pointer, -1)

@Hunter.skill
class Serpent_Sting(Skill):
    'A chance for every target you injure to be poisoned.'

    max_level = 4

    _msg_a = '>> \x04Serpent Sting: \x04Poisoned \x01{name} for 6 seconds.'
    _poisoned = set()

    @property
    def _poison_damage(self):
        return 1 + self.level

    @property
    def _poison_chance(self):
        return 16 + (2 * self.level)

    def _kill_effect(self, effect):
        if not effect.basehandle.is_valid():
            return
        effect.call_input('Kill')

    def player_attack(self, player, victim, **eargs):
        if randint(1, 100) > self._poison_chance or victim.userid in self._poisoned:
            return
           
        self._poisoned.add(victim.userid)

        for index in player.weapon_indexes():
            break

        Delay(0.5, victim.take_damage, self._poison_damage, attacker_index=player.index, weapon_index=index)
        Delay(1, victim.take_damage, self._poison_damage, attacker_index=player.index, weapon_index=index)
        Delay(2, victim.take_damage, self._poison_damage, attacker_index=player.index, weapon_index=index)
        Delay(3, victim.take_damage, self._poison_damage, attacker_index=player.index, weapon_index=index)
        Delay(4.5, victim.take_damage, self._poison_damage, attacker_index=player.index, weapon_index=index)
        Delay(7, victim.take_damage, self._poison_damage, attacker_index=player.index, weapon_index=index)
        Delay(7, self._poisoned.discard, victim.userid)

        SayText2(self._msg_a.format(name=victim.name)).send(player.index)

        # EFFECT

        effect = Entity.create('env_smokestack')

        location = victim.origin
        location.z += 48

        effect.teleport(location, None, None)
        effect.base_spread = 12
        effect.spread_speed = 0
        effect.start_size = 3
        effect.end_size = 2
        effect.jet_length = 10
        effect.angles = Vector(90, 90, 90)
        effect.rate = 60
        effect.speed = 40
        effect.twist = 0
        effect.render_mode = 18
        effect.render_amt = 100
        effect.render_color = Color(0, 255, 0)
        effect.add_output('SmokeMaterial Effects/Redflare.vmt')
        effect.turn_on()
        effect.set_parent(victim.pointer, -1)

        Delay(7, self._kill_effect, effect)

@Hunter.skill
class Kill_Command(Skill):
    'Finish off any enemies you have damaged below 10-40HP.'

    max_level = 6

    _msg_b = '>> \x02Kill Command: \x0bNo enemies have been damaged heavily enough.'
    _players_to_kill = set()

    @property
    def _health(self):
        return 10 + (5 * self.level)

    def player_spawn(self, player, **eargs):
        self._players_to_kill.clear()

    def player_attack(self, player, victim, health, **eargs):
        if victim.health < self._health:
            self._players_to_kill.add(victim)
            if victim.health == 0:
                self._players_to_kill.discard(victim)

    @cooldown(20, message='>> \x02Kill Command: \x01On cooldown for \x04{remaining_cd:0.0f} seconds\x01.')
    def player_ultimate(self, player, **eargs):
        for index in player.weapon_indexes():
            break
        else:
            index = None

        for victim in self._players_to_kill:
            victim.take_damage(victim.health, attacker_index=player.index, weapon_index=index)
        else:
            self.player_ultimate.remaining_cooldown = 0
            SayText2(self._msg_b).send(player.index)
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Fri Feb 05, 2016 11:29 am

Can you reduce your example code to the absolute minimum? Preferably, a pure SP example without the need of installing WCGO.
User avatar
satoon101
Project Leader
Posts: 2698
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Fri Feb 05, 2016 11:41 am

I would bet it's because the player is dead when take_damage is called. We should probably add an override in Player to check if the player is alive prior to continuing the take_damage.
Image
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Fri Feb 05, 2016 4:31 pm

satoon101 wrote:I would bet it's because the player is dead when take_damage is called. We should probably add an override in Player to check if the player is alive prior to continuing the take_damage.

That could be the issue. But I don't think it's our responsibility to check that.

Return to “Plugin Development Support”

Who is online

Users browsing this forum: Bing [Bot] and 23 guests