ProjectileTrails v1.0.0

Release your plugins here!
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

ProjectileTrails v1.0.0

Postby satoon101 » Sun May 13, 2018 4:15 pm

ProjectileTrails adds trails to projectiles (ie thrown grenades).

The configuration is based on the known projectiles for the specific game. For instance, in CS:S and CS:GO, both will have settings for hegrenade, flashbang, and smokegrenade, while CS:GO will also contain settings for decoy, molotov (which includes incgrenades), and tagrenade.

Here is the default configuration for CS:S:

Code: Select all

// Default Value: 7
// Set to the number of ticks to wait between each check.
   pt_ticks_between_check 7


// Default Value: 0
// Enable/disable only showing effects to teammates of the thrower.
   pt_team_only 0

// Trail Effect Options:
// "beam", "dust", "smoke", "sparks"

// ######################################################################### //
//                             FLASHBANG Settings                            //
// ######################################################################### //
// ---------------------------------------- //
//            TERRORIST Settings            //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for TERRORIST flashbang.
   pt_flashbang_terrorist_effect "beam"


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for TERRORIST flashbang.
   pt_flashbang_terrorist_beam_color "255,0,0"

// ---------------------------------------- //
//               CT Settings                //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for CT flashbang.
   pt_flashbang_ct_effect "beam"


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for CT flashbang.
   pt_flashbang_ct_beam_color "255,0,0"


// ######################################################################### //
//                             HEGRENADE Settings                            //
// ######################################################################### //
// ---------------------------------------- //
//            TERRORIST Settings            //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for TERRORIST hegrenade.
   pt_hegrenade_terrorist_effect "beam"


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for TERRORIST hegrenade.
   pt_hegrenade_terrorist_beam_color "255,0,0"

// ---------------------------------------- //
//               CT Settings                //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for CT hegrenade.
   pt_hegrenade_ct_effect "beam"


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for CT hegrenade.
   pt_hegrenade_ct_beam_color "255,0,0"


// ######################################################################### //
//                           SMOKEGRENADE Settings                           //
// ######################################################################### //
// ---------------------------------------- //
//            TERRORIST Settings            //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for TERRORIST smokegrenade.
   pt_smokegrenade_terrorist_effect "beam"


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for TERRORIST smokegrenade.
   pt_smokegrenade_terrorist_beam_color "255,0,0"

// ---------------------------------------- //
//               CT Settings                //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for CT smokegrenade.
   pt_smokegrenade_ct_effect "beam"


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for CT smokegrenade.
   pt_smokegrenade_ct_beam_color "255,0,0"


Currently, there are only 4 effects to choose from:

  • Beam (Note that with beam you also get to choose the RGB color of the beam)
  • Dust
  • Smoke
  • Sparks

To create the configuration file, load projectile_trails on the server once and the default file will be created at ../cfg/source-python/projectile_trails.cfg. Edit the file to your liking and then re-load projectile_trails.

If you have suggestions or notice any bugs for the plugin, please feel free to post them on the issues list:
https://github.com/satoon101/ProjectileTrails/issues

This plugin has been fully tested on CS:S and CS:GO, but could also work on other games as long as there are projectiles listed in ../addons/source-python/data/source-python/weapons/<game_name>.ini. I will work to verify support for other games when I have the opportunity.

Thanks, and enjoy :)

Current version download
projectile_trails - v1.0.0.zip
(11.53 KiB) Downloaded 764 times
Image
User avatar
Painkiller
Senior Member
Posts: 725
Joined: Sun Mar 01, 2015 8:09 am
Location: Germany
Contact:

Re: ProjectileTrails v1.0.0

Postby Painkiller » Wed Apr 15, 2020 8:38 am

Hello, Satoon,

I noticed the following error.
Could you please help me correct the error?

Greetings Painkiller

Code: Select all

[SP] Caught an Exception:
Traceback (most recent call last):
  File "../addons/source-python/packages/source-python/plugins/command.py", line 162, in load_plugin
    plugin = self.manager.load(plugin_name)
  File "../addons/source-python/packages/source-python/plugins/manager.py", line 194, in load
    plugin._load()
  File "../addons/source-python/packages/source-python/plugins/instance.py", line 74, in _load
    self.module = import_module(self.import_name)
  File "../addons/source-python/plugins/projectile_trails/projectile_trails.py", line 39, in <module>
    TRANSLATION_STRINGS['No Teams'].get_string().format(
  File "../addons/source-python/packages/source-python/translations/strings.py", line 265, in get_string
    return self[language].format(**exposed_tokens)

KeyError: 'game'


hl2mp.ini

Code: Select all

[properties]
    prefix = "weapon_"
    ammoprop = "localdata.m_iAmmo."
    myweapons = "m_hMyWeapons."


[special names]
    npc_tripmine = "slam"


[projectiles]
    crossbow_bolt = "crossbow"
    grenade_ar2 = "smg1"
    npc_grenade_frag = "frag"
    rpg_missile = "rpg"
    prop_combine_ball = "ar2"


[weapons]

    # =========================================================================
    # PRIMARY WEAPONS
    # =========================================================================
    # Snipers
    [[crossbow]]
        slot = 3
        maxammo = 10
        ammoprop = 6
        clip = 1
        tags = "all,primary,sniper"

    # Rifles
    [[ar2]]
        slot = 2
        maxammo = 60
        ammoprop = 1
        clip = 30
        secondary_fire_maxammo = 3
        secondary_fire_ammoprop = 2
        tags = "all,primary,smg"

    [[smg1]]
        slot = 2
        maxammo = 225
        ammoprop = 4
        clip = 45
        secondary_fire_maxammo = 3
        secondary_fire_ammoprop = 9
        tags = "all,primary,smg"

    # Shotguns
    [[shotgun]]
        slot = 3
        maxammo = 30
        ammoprop = 7
        clip = 6
        tags = "all,primary,shotgun"

    # =========================================================================
    # SECONDARY WEAPONS
    # =========================================================================
    [[357]]
        slot = 1
        maxammo = 12
        ammoprop = 5
        clip = 6
        tags = "all,secondary,pistol"

    [[pistol]]
        slot = 1
        maxammo = 150
        ammoprop = 3
        clip = 18
        tags = "all,secondary,pistol"

    # =========================================================================
    # MELEE WEAPONS
    # =========================================================================
    [[stunstick]]
        slot = 0
        tags = "all,hand,melee"

    [[crowbar]]
        slot = 0
        tags = "all,hand,melee"

    # =========================================================================
    # EXPLOSIVE WEAPONS
    # =========================================================================
    [[frag]]
        slot = 4
        maxammo = 5
        ammoprop = 10
        tags = "all,grenade,explosive"

    [[rpg]]
        slot = 4
        maxammo = 3
        ammoprop = 8
        tags = "all,rocket,explosive"

    [[slam]]
        slot = 4
        maxammo = 5
        ammoprop = 11
        tags = "all,explosive"

    # =========================================================================
    # OTHER WEAPONS
    # =========================================================================
    [[physcannon]]
        slot = 0
        tags = "all,tool"


projectile_trails.cfg

Code: Select all

// Default Value: 7
// Set to the number of ticks to wait between each check.
   pt_ticks_between_check 7


// Default Value: 0
// Enable/disable only showing effects to teammates of the thrower.
   pt_team_only 0

// Trail Effect Options:
// "smoke", "dust", "sparks", "beam"

// ######################################################################### //
//                             CROSSBOW Settings                             //
// ######################################################################### //
// ---------------------------------------- //
//           FREEFORALL Settings            //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for FREEFORALL crossbow.
   pt_crossbow_freeforall_effect "smoke"


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for FREEFORALL crossbow.
   pt_crossbow_freeforall_beam_color "255,0,0"


// ######################################################################### //
//                               SMG1 Settings                               //
// ######################################################################### //
// ---------------------------------------- //
//           FREEFORALL Settings            //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for FREEFORALL smg1.
   pt_smg1_freeforall_effect "smoke"


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for FREEFORALL smg1.
   pt_smg1_freeforall_beam_color "255,0,0"


// ######################################################################### //
//                               FRAG Settings                               //
// ######################################################################### //
// ---------------------------------------- //
//           FREEFORALL Settings            //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for FREEFORALL frag.
   pt_frag_freeforall_effect "smoke"


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for FREEFORALL frag.
   pt_frag_freeforall_beam_color "255,0,0"


// ######################################################################### //
//                                RPG Settings                               //
// ######################################################################### //
// ---------------------------------------- //
//           FREEFORALL Settings            //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for FREEFORALL rpg.
   pt_rpg_freeforall_effect "smoke"


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for FREEFORALL rpg.
   pt_rpg_freeforall_beam_color "255,0,0"


// ######################################################################### //
//                                AR2 Settings                               //
// ######################################################################### //
// ---------------------------------------- //
//           FREEFORALL Settings            //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for FREEFORALL ar2.
   pt_ar2_freeforall_effect ""


// Default Value: "255,0,0"
// Set to the RGB value if using 'beam' for FREEFORALL ar2.
   pt_ar2_freeforall_beam_color "255,0,0"

User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: ProjectileTrails v1.0.0

Postby satoon101 » Wed Apr 15, 2020 12:51 pm

Ok, so you will have 2 issues in total. If you are hitting that erroring line of code, that means the game isn't supported. Which game are you using this for that caused the error? For the error itself, did you add translations? The only language currently supported by the plugin itself is 'en'. It is fine to add your own, though I wish you would do a Pull Request to add them to the plugin for other users to use. But, when you added the "No Teams" translation, it seems you left out {game} which is the key causing the error.
Image
User avatar
Painkiller
Senior Member
Posts: 725
Joined: Sun Mar 01, 2015 8:09 am
Location: Germany
Contact:

Re: ProjectileTrails v1.0.0

Postby Painkiller » Wed Apr 15, 2020 4:51 pm

It was made for me once a long time ago.
The game is Half Life 2: Deathmatch

I hope you can help me.

Here again.

config.py

Syntax: Select all

# ../projectile_trails/config.py

"""Provides configuration based functionality for the plugin."""

# =============================================================================
# >> IMPORTS
# =============================================================================
# Python
from collections import defaultdict
from operator import attrgetter

# Source.Python
from config.manager import ConfigManager

# Plugin
from . import PROJECTILE_ENTITIES
from .effects import EFFECT_DICTIONARY
from .info import info
from .strings import CONFIG_STRINGS
from .teams import GAME_TEAMS


# =============================================================================
# >> ALL DECLARATION
# =============================================================================
__all__ = (
'EFFECT_CONVARS',
'team_only',
'ticks',
)


# =============================================================================
# >> CONFIGURATION
# =============================================================================
_variables = dict([
(key, instance[key]) for instance in list(
map(
attrgetter('variables'),
EFFECT_DICTIONARY.values()
)
) for key in instance
])

EFFECT_CONVARS = defaultdict(lambda: defaultdict(dict))

with ConfigManager(info.name, 'pt_') as _config:
ticks = _config.cvar(
name='ticks_between_check',
description=CONFIG_STRINGS['ticks'],
default=7,
)
team_only = _config.cvar(
name='team_only',
description=CONFIG_STRINGS['team_only'],
default=0,
)

_config.text(CONFIG_STRINGS['Options'])
_config.text('"' + '", "'.join(EFFECT_DICTIONARY) + '"')

for _proj, _weapon in PROJECTILE_ENTITIES.items():
_config.section(
CONFIG_STRINGS['Section:Weapon'].get_string(
weapon=_weapon.upper(),
)
)
for _team_num, _team_name in GAME_TEAMS.items():
_team_name = _team_name.lower()
_config.text('-' * 40 + ' //')
_config.text(
CONFIG_STRINGS['Section:Team'].get_string(
team=_team_name.upper(),
).center(40) + ' //'
)
_config.text('-' * 40 + ' //')
EFFECT_CONVARS[_proj][_team_num]['effect'] = _config.cvar(
name=f'{_weapon}_{_team_name}_effect',
default='beam',
description=CONFIG_STRINGS['Cvar:Description'].get_string(
weapon=_weapon,
team=_team_name.upper(),
)
)
for _variable, _instance in _variables.items():
EFFECT_CONVARS[_proj][_team_num][_variable] = _config.cvar(
name=f'{_weapon}_{_team_name}_{_variable}',
default=_instance.default,
description=_instance.description.get_string(
weapon=_weapon,
team=_team_name.upper(),
),
)


projectile_trails.py

Syntax: Select all

# ../projectile_trails/projectile_trails.py

"""Displays trail effects for projectile weapons."""

# =============================================================================
# >> IMPORTS
# =============================================================================
# Python
from random import choice

# Source.Python
from core import GAME_NAME
from engines.server import global_vars
from listeners import OnEntitySpawned, OnEntityDeleted, OnTick
from weapons.entity import Weapon

# Plugin
from . import PROJECTILE_ENTITIES
from .config import EFFECT_CONVARS, ticks
from .effects import EFFECT_DICTIONARY
from .strings import TRANSLATION_STRINGS
from .teams import GAME_TEAMS


# =============================================================================
# >> GAME VERIFICATION
# =============================================================================
# Are any projectiles listed for the game?
if not PROJECTILE_ENTITIES:
raise NotImplementedError(
TRANSLATION_STRINGS['No Projectiles'].get_string().format(
game=GAME_NAME,
)
)

# Are there any valid teams for the game?
if not GAME_TEAMS:
raise NotImplementedError(
TRANSLATION_STRINGS['No Teams'].get_string().format(
game=GAME_NAME,
)
)


# =============================================================================
# >> CLASSES
# =============================================================================
class _GameEntityManager(dict):
"""Class used to hold EntityManager instances for each entity."""

def __delitem__(self, index):
"""Remove the trail from the entity prior to removing it from dict."""
if index not in self:
return

self[index].remove_trail()
super().__delitem__(index)

def add_entity(self, entity, convars, team_index):
"""Add the entity to the dictionary if it needs a trail effect."""
effect = self._get_effect(convars)
if effect is not None:
self[entity.index] = effect(entity, convars, team_index)

@staticmethod
def _get_effect(convars):
"""Return the effect to be used for the entity."""
effect = str(convars['effect']).lower()
if effect in EFFECT_DICTIONARY:
return EFFECT_DICTIONARY[effect]

if effect == 'random':
return choice(EFFECT_DICTIONARY.values())

return None

def clear(self):
"""Stop all ongoing effects and clear the dictionary."""
for index in list(self):
del self[index]

def tick_listener(self):
"""Check to see if the effects need updated."""
# Are more ticks needed to update?
if global_vars.tick_count % int(ticks):
return

for instance in self.values():
instance.update_trail()

game_entity_manager = _GameEntityManager()


# =============================================================================
# >> LISTENERS
# =============================================================================
@OnEntitySpawned
def _entity_spawned(base_entity):
"""Add the entity to the dictionary if it is a projectile."""
if not base_entity.is_networked():
return

class_name = base_entity.classname
if class_name not in PROJECTILE_ENTITIES:
return

projectile = Weapon(base_entity.index)
team_index = projectile.owner.team_index
if team_index in EFFECT_CONVARS[class_name]:
game_entity_manager.add_entity(
entity=base_entity,
convars=EFFECT_CONVARS[class_name][team_index],
team_index=team_index,
)


@OnEntityDeleted
def _entity_deleted(base_entity):
"""Remove the entity from the dictionary if it is a projectile."""
if not base_entity.is_networked():
return

index = base_entity.index
del game_entity_manager[index]


@OnTick
def _on_tick():
"""Call the tick listener."""
game_entity_manager.tick_listener()


strings.py

Syntax: Select all

# ../projectile_trails/strings.py

"""Contains all translation variables for the base plugin."""

# =============================================================================
# >> IMPORTS
# =============================================================================
# Source.Python
from translations.strings import LangStrings

# Plugin
from .info import info


# =============================================================================
# >> ALL DECLARATION
# =============================================================================
__all__ = (
'CONFIG_STRINGS',
'TRANSLATION_STRINGS',
)


# =============================================================================
# >> GLOBAL VARIABLES
# =============================================================================
CONFIG_STRINGS = LangStrings(f'{info.name}/config_strings')
TRANSLATION_STRINGS = LangStrings(f'{info.name}/strings')


teams.py

Syntax: Select all

# ../projectile_trails/teams.py

"""Provides teams by number/name for the current game."""

# =============================================================================
# >> IMPORTS
# =============================================================================
# Site-Package
from configobj import ConfigObj

# Source.Python
from core import GAME_NAME
from filters.entities import EntityIter
from paths import PLUGIN_DATA_PATH
from players.teams import team_managers, teams_by_number

# Plugin
from .info import info


# =============================================================================
# >> ALL DECLARATION
# =============================================================================
__all__ = (
'GAME_TEAMS',
)


# =============================================================================
# >> GLOBAL VARIABLES
# =============================================================================
# Get any odd team names stored in ../data/plugins/projectile_trails/
_odd_teams = ConfigObj(
PLUGIN_DATA_PATH / info.name + '.ini'
).get(GAME_NAME, {})

GAME_TEAMS = {}
for manager in team_managers:
for entity in EntityIter(manager):
if teams_by_number[entity.team] in ('un', 'spec'):
continue

GAME_TEAMS[entity.team] = entity.team_name

GAME_TEAMS.update(_odd_teams)
User avatar
Painkiller
Senior Member
Posts: 725
Joined: Sun Mar 01, 2015 8:09 am
Location: Germany
Contact:

Re: ProjectileTrails v1.0.0

Postby Painkiller » Fri Apr 17, 2020 3:50 pm

I'm getting nowhere here either. I don't know what the problem is.
decompile
Senior Member
Posts: 416
Joined: Sat Oct 10, 2015 10:37 am
Location: Germany
Contact:

Re: ProjectileTrails v1.0.0

Postby decompile » Thu Apr 30, 2020 3:34 am

As satoon said, your error isn't related to the plugin itself, instead to the TranslationStrings file you must have edited.
User avatar
Painkiller
Senior Member
Posts: 725
Joined: Sun Mar 01, 2015 8:09 am
Location: Germany
Contact:

Re: ProjectileTrails v1.0.0

Postby Painkiller » Thu Apr 30, 2020 11:49 am

This is my strings.ini

Code: Select all

[No Projectiles]
en = "Game '{game}' has no known projectile weapons."


[No Teams]
en = "Game '{game}' has no known teams."


config_strings.ini

Code: Select all

[ticks]
en = "Set to the number of ticks to wait between each check."


[team_only]
en = "Enable/disable only showing effects to teammates of the thrower."


[Options]
en = "Trail Effect Options:"


[Cvar:Description]
en = "Set to the value for {team} {weapon}."


[Section:Weapon]
en = "{weapon} Settings"


[Section:Team]
en = "{team} Settings"


beam_strings.ini

Code: Select all

[Color]
en = "Set to the RGB value if using 'beam' for {team} {weapon}."


/addons/source-python/packages/source-python/translations/strings.py

Syntax: Select all

# ../translations/strings.py

"""Provides translation functionality."""

# =============================================================================
# >> IMPORTS
# =============================================================================
# Python Imports
# Binascii
from binascii import unhexlify
# Codecs
from codecs import unicode_escape_decode
# Re
from re import compile as re_compile
from re import VERBOSE

# Site-Package Imports
# Configobj
from configobj import Section

# Source.Python Imports
# Core
from core import GameConfigObj
# Paths
from paths import TRANSLATION_PATH
from paths import GAME_PATH
# Translations
from translations.manager import language_manager


# =============================================================================
# >> ALL DECLARATION
# =============================================================================
__all__ = ('LangStrings',
'TranslationStrings',
)


# =============================================================================
# >> GLOBAL VARIABLES
# =============================================================================
# Get an re.compile instance to correct all double escaped strings
_double_escaped_pattern = re_compile(
r"""(\\(?:(?P<octal>[0-7]{1,3})|x(?P<hexadecimal>[0-9|a-f|A-F]{2})|
(?P<notation>a|b|e|f|n|r|s|t|v)))""", VERBOSE)


# =============================================================================
# >> CLASSES
# =============================================================================
class LangStrings(dict):
"""Dictionary class used to store all strings for a plugin."""

def __init__(self, infile, encoding='utf_8'):
"""Add all strings and fix double escaped strings."""
# Initialize the dictionary
super().__init__()

# Get the path to the given file
self._mainfile = TRANSLATION_PATH / infile + '.ini'

# Does the file exist?
if not self._mainfile.isfile():

# Raise an error
raise FileNotFoundError(
'No file found at {0}'.format(self._mainfile))

# Get the path to the server specific file
self._serverfile = self._mainfile.parent / '{0}_server.ini'.format(
self._mainfile.namebase)

# Get the strings from the main file
main_strings = GameConfigObj(self._mainfile, encoding=encoding)

# Does the server specific file exist?
if not self._serverfile.isfile() and not infile.startswith('_core/'):

# Create the server specific file
self._create_server_file()

# Otherwise
else:

# Get any strings from the server specific file
server_strings = GameConfigObj(self._serverfile, encoding=encoding)

# Merge the two ConfigObj instances together
main_strings.merge(server_strings)

# Loop through all strings
for key in main_strings:

# Is the current string not a Section?
if not isinstance(main_strings[key], Section):

# No need to go further
continue

# Get a TranslationStrings instance for the current string
translation_strings = TranslationStrings()

# Loop through all languages for the current string
for lang in main_strings[key]:

# Get the shortname of the current language
language = language_manager.get_language(lang)

# Was the language found?
if language is None:

# Do not add this translation
# Possibly raise an error silently here
continue

# Get the language's string and fix any escaped strings
translation_strings[
language] = self._replace_escaped_sequences(
main_strings[key][lang])

# Add the TranslationStrings instance for the current string
self[key] = translation_strings

# Is there any default language specified into the main file?
if 'DEFAULT_LANGUAGE' in main_strings:

# Get the default language
default_language = main_strings['DEFAULT_LANGUAGE']

# Make sure it is not a Section
if not isinstance(default_language, Section):

# Get the given language code
language_code = language_manager.get_language(default_language)

# Is the language valid?
if language_code is not None:

# Set the default language
self.default_language = language_code

# Delete the key from the main file as we are done with it
del main_strings['DEFAULT_LANGUAGE']

def __setattr__(self, attribute, value):
"""Register the default language."""
# Is the given attribute the default language?
if attribute == 'default_language':

# Get the given language code
language_code = language_manager.get_language(value)

# Is the given language code valid?
if language_code is not None:

# Loop through all strings
for key in self:

# Set the default language to use for that string
self[key]._default_language = language_code

# Override the given value
value = language_code

# Set the attribute
super().__setattr__(attribute, value)

def _create_server_file(self):
"""Create a server specific langstrings file."""
# Get the server specific file's ConfigObj instance
server_file = GameConfigObj(self._serverfile)

# Set the initial comments to explain what the file is for
server_file.initial_comment = _translation_strings[
'Initial Comment'].get_string(
language_manager.default,
filename=self._mainfile.replace(GAME_PATH, '')).splitlines()

# Write the server specific file
server_file.write()

@staticmethod
def _replace_escaped_sequences(given_string):
"""Fix all double escaped strings."""
# Loop through all matches
for escaped_match in set(
_double_escaped_pattern.finditer(given_string)):

# Get the match as a string
matching_string = escaped_match.group()

# Get a dictionnary of all groups
matching_groups = escaped_match.groupdict()

# Are we matching any octal sequences?
if matching_groups['octal']:

# Replace it
given_string = given_string.replace(
matching_string, chr(int(matching_groups['octal'])))

# Otherwise, are we matching any hexadecimal sequences?
elif matching_groups['hexadecimal']:

# Replace it
given_string = given_string.replace(
matching_string, str(unhexlify(
matching_groups['hexadecimal']), encoding='ascii'))

# Otherwise, that means we are matching a notation
else:

# Replace it
given_string = given_string.replace(
matching_string, unicode_escape_decode(matching_string)[0])

# Return the replaced string
return given_string

def get_strings(self, key, **tokens):
"""Return a TranslationStrings object with updated tokens."""
strings = self[key]
strings.tokens.update(tokens)
return strings


class TranslationStrings(dict):
"""Stores and get language strings for a particular string."""

def __init__(self):
"""Store an empty dictionary as the tokens."""
super().__init__()
self.tokens = {}

def get_string(self, language=None, **tokens):
"""Return the language string for the given language/tokens."""
# Was no language passed?
if language is None:

# Set the language to the server's default
language = language_manager.default

# Get the language shortname to be used
language = self.get_language(language)

# Was a valid language found?
if language is None:

# Return an empty string
# Possibly raise an error silently here
return ''

# Expose all TranslationStrings instances in self.tokens
exposed_tokens = {}

# Pass additional kwargs - these will be used to format the string
self._update_exposed_tokens(
exposed_tokens, language, self.tokens, **tokens)

# Don't pass any additional kwargs, each token should either
# be trivial or rely on itself (self.tokens)
self._update_exposed_tokens(exposed_tokens, language, tokens)

# Return the formatted message
return self[language].format(**exposed_tokens)

@staticmethod
def _update_exposed_tokens(exposed_tokens, language, tokens, **kwargs):
for token_name, token in tokens.items():
if isinstance(token, TranslationStrings):
token = token.get_string(language, **kwargs)

exposed_tokens[token_name] = token

def get_language(self, language):
"""Return the language to be used."""
# Get the given language's shortname
language = language_manager.get_language(language)

# Was a language found?
if language is not None and language in self:

# Return the language
return language

# Is the server's default language in the dictionary?
if language_manager.default in self:

# Return the server's default language
return language_manager.default

# Is there any default language defined?
if hasattr(self, '_default_language'):

# Is the default language available for that string?
if self._default_language in self:

# Return the default language to use
return self._default_language

# Is the server's fallback language in the dictionary?
if language_manager.fallback in self:

# Return the server's fallback language
return language_manager.fallback

# Return None as the language, as no language has been found
return None

def tokenized(self, **tokens):
"""Create a new TranslationStrings instance and store tokens in it.

:param dict tokens: Tokens to store in the instance.
:return: New TranslationStrings instance with tokens stored in it.
:rtype: TranslationStrings
"""
result = TranslationStrings()
result.tokens.update(tokens)

result.update(self)

return result

# Get the translations language strings
_translation_strings = LangStrings('_core/translations_strings')
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: ProjectileTrails v1.0.0

Postby L'In20Cible » Fri May 01, 2020 6:25 am

decompile wrote:As satoon said, your error isn't related to the plugin itself, instead to the TranslationStrings file you must have edited.

Actually, the issue appears to be in the plugin itself. This:

Syntax: Select all

# Are any projectiles listed for the game?
if not PROJECTILE_ENTITIES:
raise NotImplementedError(
TRANSLATION_STRINGS['No Projectiles'].get_string().format(
game=GAME_NAME,
)
)

# Are there any valid teams for the game?
if not GAME_TEAMS:
raise NotImplementedError(
TRANSLATION_STRINGS['No Teams'].get_string().format(
game=GAME_NAME,
)
)


Should be:

Syntax: Select all

# Are any projectiles listed for the game?
if not PROJECTILE_ENTITIES:
raise NotImplementedError(
TRANSLATION_STRINGS['No Projectiles'].get_string(
game=GAME_NAME,
)
)

# Are there any valid teams for the game?
if not GAME_TEAMS:
raise NotImplementedError(
TRANSLATION_STRINGS['No Teams'].get_string(
game=GAME_NAME,
)
)


However, the fact this error happens mean the plugin isn't supported for that game as it raises while trying to raise a NotImplementedError.
User avatar
Painkiller
Senior Member
Posts: 725
Joined: Sun Mar 01, 2015 8:09 am
Location: Germany
Contact:

Re: ProjectileTrails v1.0.0

Postby Painkiller » Fri May 01, 2020 9:50 am

That's too bad,

I asked a while back if Satoon would handle this.
http://addons.eventscripts.com/addons/view/LooneyTrails

However, if I remember correctly he said that it should also work for HL2DM.

But I don't want to get stuck on it.

@Satoon I would be happy if you could take a look at it and make it work for HL2DM too.

(There are DM, TDM and Coop in HL2DM)

Thanks in advance
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: ProjectileTrails v1.0.0

Postby satoon101 » Fri May 01, 2020 10:21 am

Good catch, L'In20Cible. I will fix that when I get a chance.

It should support HL2MP, though, so I am not sure why it's even getting that error. I tested locally when Painkiller first reported the error, and it loaded just fine for me.
Image
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: ProjectileTrails v1.0.0

Postby L'In20Cible » Fri May 01, 2020 10:51 am

satoon101 wrote:Good catch, L'In20Cible. I will fix that when I get a chance.

It should support HL2MP, though, so I am not sure why it's even getting that error. I tested locally when Painkiller first reported the error, and it loaded just fine for me.

Which means it must have been partially installed and the ..\addons\source-python\data\plugins\projectile_trails.ini file is missing. That's the only way this error would happens.
User avatar
Painkiller
Senior Member
Posts: 725
Joined: Sun Mar 01, 2015 8:09 am
Location: Germany
Contact:

Re: ProjectileTrails v1.0.0

Postby Painkiller » Mon May 04, 2020 8:44 am

Okay, I looked at it. In fact, the file was missing.

I added it but you still don't see any effects.

The log files contained this.

Code: Select all

2020-05-04 10:36:37 - sp   -   EXCEPTION   
[SP] Caught an Exception:
Traceback (most recent call last):
  File "../addons/source-python/plugins/projectile_trails/projectile_trails.py", line 108, in _entity_spawned
    team_index = projectile.owner.team_index

AttributeError: 'NoneType' object has no attribute 'team_index'
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Re: ProjectileTrails v1.0.0

Postby satoon101 » Tue May 05, 2020 11:23 pm

I will take a look at that when I have time. Unfortunately, right now I don't have a lot of extra time, so it might be a couple weeks.
Image
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: ProjectileTrails v1.0.0

Postby L'In20Cible » Wed May 06, 2020 12:18 am

Try this:

Syntax: Select all

# ../projectile_trails/projectile_trails.py

"""Displays trail effects for projectile weapons."""

# =============================================================================
# >> IMPORTS
# =============================================================================
# Python
from random import choice

# Source.Python
from core import GAME_NAME
from entities.entity import Entity
from engines.server import global_vars
from listeners import OnEntitySpawned, OnEntityDeleted, OnTick
from weapons.entity import Weapon

# Plugin
from . import PROJECTILE_ENTITIES
from .config import EFFECT_CONVARS, ticks
from .effects import EFFECT_DICTIONARY
from .strings import TRANSLATION_STRINGS
from .teams import GAME_TEAMS


# =============================================================================
# >> GAME VERIFICATION
# =============================================================================
# Are any projectiles listed for the game?
if not PROJECTILE_ENTITIES:
raise NotImplementedError(
TRANSLATION_STRINGS['No Projectiles'].get_string().format(
game=GAME_NAME,
)
)

# Are there any valid teams for the game?
if not GAME_TEAMS:
raise NotImplementedError(
TRANSLATION_STRINGS['No Teams'].get_string().format(
game=GAME_NAME,
)
)


# =============================================================================
# >> CLASSES
# =============================================================================
class _GameEntityManager(dict):
"""Class used to hold EntityManager instances for each entity."""

def __delitem__(self, index):
"""Remove the trail from the entity prior to removing it from dict."""
if index not in self:
return

self[index].remove_trail()
super().__delitem__(index)

def add_entity(self, entity, convars, team_index):
"""Add the entity to the dictionary if it needs a trail effect."""
effect = self._get_effect(convars)
if effect is not None:
self[entity.index] = effect(entity, convars, team_index)

@staticmethod
def _get_effect(convars):
"""Return the effect to be used for the entity."""
effect = str(convars['effect']).lower()
if effect in EFFECT_DICTIONARY:
return EFFECT_DICTIONARY[effect]

if effect == 'random':
return choice(EFFECT_DICTIONARY.values())

return None

def clear(self):
"""Stop all ongoing effects and clear the dictionary."""
for index in list(self):
del self[index]

def tick_listener(self):
"""Check to see if the effects need updated."""
# Are more ticks needed to update?
if global_vars.tick_count % int(ticks):
return

for instance in self.values():
instance.update_trail()

game_entity_manager = _GameEntityManager()


# =============================================================================
# >> LISTENERS
# =============================================================================
@OnEntitySpawned
def _entity_spawned(base_entity):
"""Add the entity to the dictionary if it is a projectile."""
if not base_entity.is_networked():
return

class_name = base_entity.classname
if class_name not in PROJECTILE_ENTITIES:
return

projectile = Entity(base_entity.index)
owner = projectile.owner
if owner is None:
return
team_index = str(owner.team_index)
if team_index in EFFECT_CONVARS[class_name]:
game_entity_manager.add_entity(
entity=base_entity,
convars=EFFECT_CONVARS[class_name][team_index],
team_index=team_index,
)


@OnEntityDeleted
def _entity_deleted(base_entity):
"""Remove the entity from the dictionary if it is a projectile."""
if not base_entity.is_networked():
return

index = base_entity.index
del game_entity_manager[index]


@OnTick
def _on_tick():
"""Call the tick listener."""
game_entity_manager.tick_listener()


There was 2 issues, one has been fixed into aaf55e5 and the other being that EFFECT_CONVARS contains the team indexes as strings, while team_index is an integer.
User avatar
Painkiller
Senior Member
Posts: 725
Joined: Sun Mar 01, 2015 8:09 am
Location: Germany
Contact:

Re: ProjectileTrails v1.0.0

Postby Painkiller » Wed May 06, 2020 7:54 am

It works without crashes so far.

It works so far with the RPG,smg1_grenade,grenades.
It did not work for slams when they are laid,combine_ball,crossbow_bolt.

I added this to the projectile_trails.cfg

Code: Select all

// ######################################################################### //
//                                SLAM Settings                               //
// ######################################################################### //
// ---------------------------------------- //
//           FREEFORALL Settings            //
// ---------------------------------------- //

// Default Value: "beam"
// Set to the value for FREEFORALL slam.
   pt_slam_freeforall_effect "smoke"


// Default Value: "255,0,0"
// Set to the RGB value if using 'smoke' for FREEFORALL slam.
   pt_slam_freeforall_beam_color "255,0,0"

Return to “Plugin Releases”

Who is online

Users browsing this forum: No registered users and 17 guests