New Project: Porting Saxton Hale mod for Source.Python

Please post any questions about developing your plugin here. Please use the search function before posting!
nergal
Member
Posts: 57
Joined: Sun Mar 15, 2015 2:58 pm

New Project: Porting Saxton Hale mod for Source.Python

Postby nergal » Tue Jun 30, 2015 1:45 pm

So everybody, I've decided that, for my first real plugin here, I'd port the popular saxton hale mod from SourcePawn to Python using real object-orientation!

so far, making a nice class for the bosses. I'm debating if I should encapsulate the class members or just leave them public as this will be my first real object-oriented plugin.

https://bitbucket.org/assyrian/source.py-saxton-hale-boss-mode/src/d1dfa78cbb2e0d62823670689d8c3fce0ff97c98/scripting/saxtonhale.py?at=default
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Tue Jun 30, 2015 1:53 pm

Did you have a specific question you wanted answered? I would highly recommend using math.pi instead of creating a variable to store pi's value:

Syntax: Select all

from math import pi

print(pi)

https://docs.python.org/3/library/math.html#math.pi

Also, lines 23 and 25 would cause errors, since you seem to be declaring the type which is not a part of Python. And you have a NameError in your __init__ method (bossname / name).

Not to mention, if you inherit from Entity/PlayerEntity, and you create your own __init__ method, you MUST call the super class' __init__. And there is exactly one argument that those classes take and it is an index, not a userid.
Image
necavi
Developer
Posts: 129
Joined: Wed Jan 30, 2013 9:51 pm

Postby necavi » Tue Jun 30, 2015 6:01 pm

I would strongly recommend running: https://www.jetbrains.com/pycharm/ as it would've picked up all of what satoon mentioned except for the pi constant. I can help you set it up with SourcePython if you'd like (the libraries can be a little tricky).
nergal
Member
Posts: 57
Joined: Sun Mar 15, 2015 2:58 pm

Postby nergal » Tue Jun 30, 2015 7:04 pm

satoon101 wrote:Did you have a specific question you wanted answered? I would highly recommend using math.pi instead of creating a variable to store pi's value:

Syntax: Select all

from math import pi

print(pi)

https://docs.python.org/3/library/math.html#math.pi

Also, lines 23 and 25 would cause errors, since you seem to be declaring the type which is not a part of Python. And you have a NameError in your __init__ method (bossname / name).

Not to mention, if you inherit from Entity/PlayerEntity, and you create your own __init__ method, you MUST call the super class' __init__. And there is exactly one argument that those classes take and it is an index, not a userid.


thx Sat :3 If I can call you that.

I've updated the OP with the suggested stuffs :)
User avatar
Mahi
Senior Member
Posts: 236
Joined: Wed Aug 29, 2012 8:39 pm
Location: Finland

Postby Mahi » Tue Jun 30, 2015 7:12 pm

I'm debating if I should encapsulate the class members or just leave them public as this will be my first real object-oriented plugin.
Rarely should you "encapsulate" (there's no true encapsulation in Python) anything. But if you want, you can mark attributes or methods "private" with a leading underscore -- though it doesn't actually do anything other than signals other programmers that "this variable should be used by this class only".

That being said: if you think nobody else should access an attribute, add an underscore in front of the attributes name. You're often better off not encapsulating anything than encapsulating too much.
nergal
Member
Posts: 57
Joined: Sun Mar 15, 2015 2:58 pm

Postby nergal » Wed Jul 01, 2015 12:08 am

I had a feeling encapsulation was unnecessary.
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Wed Jul 01, 2015 12:52 pm

You're still passing a second variable on __init__ which will cause an error. In Python, __new__ gets called prior to __init__. Our __new__ class method for Entity/PlayerEntity requires exactly 1 argument, the entity's/player's index. This is where the error would be encountered when you pass too many arguments. There has been minimal discussion about allowing for *args and **kwargs, but no decision has really been made on that.

For now, you can either pass only the index and then, after getting the object's instance, set the name variable:

Syntax: Select all

instance = CBoss(index)
instance.bossname = some_name

Or, overwrite __new__:

Syntax: Select all

class CBoss(PlayerEntity):

def __new__(cls, index, bossname):
super(CBoss, cls).__new__(cls, index)

def __init__(self, index, bossname):
super(CBoss, self).__init__(index)
self.bossname = bossname


Also, there is no reason to store the player's userid, since there is already a property that retrieves that value for PlayerEntity instances:
https://github.com/Source-Python-Dev-Team/Source.Python/blob/master/addons/source-python/packages/source-python/players/entity.py#L72


There is also a get-able only 'name' property for PlayerEntity instances, so you would encounter an AttributeError when trying to set that value in __init__. Is the bossname just the player's name? If so, there is no reason to even pass that value, as, again, there is already a property that retrieves that value:
https://github.com/Source-Python-Dev-Team/Source.Python/blob/master/addons/source-python/packages/source-python/players/entity.py#L82
Image
nergal
Member
Posts: 57
Joined: Sun Mar 15, 2015 2:58 pm

Postby nergal » Wed Jul 01, 2015 11:42 pm

satoon101 wrote:You're still passing a second variable on __init__ which will cause an error. In Python, __new__ gets called prior to __init__. Our __new__ class method for Entity/PlayerEntity requires exactly 1 argument, the entity's/player's index. This is where the error would be encountered when you pass too many arguments. There has been minimal discussion about allowing for *args and **kwargs, but no decision has really been made on that.

For now, you can either pass only the index and then, after getting the object's instance, set the name variable:

Syntax: Select all

instance = CBoss(index)
instance.bossname = some_name

Or, overwrite __new__:

Syntax: Select all

class CBoss(PlayerEntity):

def __new__(cls, index, bossname):
super(CBoss, cls).__new__(cls, index)

def __init__(self, index, bossname):
super(CBoss, self).__init__(index)
self.bossname = bossname


Also, there is no reason to store the player's userid, since there is already a property that retrieves that value for PlayerEntity instances:
https://github.com/Source-Python-Dev-Team/Source.Python/blob/master/addons/source-python/packages/source-python/players/entity.py#L72


There is also a get-able only 'name' property for PlayerEntity instances, so you would encounter an AttributeError when trying to set that value in __init__. Is the bossname just the player's name? If so, there is no reason to even pass that value, as, again, there is already a property that retrieves that value:
https://github.com/Source-Python-Dev-Team/Source.Python/blob/master/addons/source-python/packages/source-python/players/entity.py#L82


for the sake of keeping it simple (cuz im learning the API), I'll stick the 1st example of simply getting the instance and allow whatever name the coder wants.

The point of the bossUserID variable was to simply save the player's UserID so one can check who's a boss or not.

I'll figure out a different way I guess; as for bossname, that's the name of the Boss such as Saxton Hale or whatever the Boss Character's name will be.

Already updated the OP :)
nergal
Member
Posts: 57
Joined: Sun Mar 15, 2015 2:58 pm

Postby nergal » Sun Jul 05, 2015 10:06 pm

a small question with Python...

How would I carry over data from one Event function to another without using a global variable?

Example: I set the player's iLives field to '1' and I need to carry it to the player_death event so I can interpret the lives logic. How can I do this example without using global variables?
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Sun Jul 05, 2015 10:23 pm

I realize you said no global variables, but I really think that a global dictionary to store player instances by userid would be your best bet:

Syntax: Select all

class _PlayerDictionary(dict):

def __missing__(self, userid):
value = index_from_userid(userid, False)
if value is not None:
value = self[userid] = YourPlayerClass(value)
return value

player_dictionary = _PlayerDictionary()


@Event
def player_death(game_event):
victim = player_dictionary[game_event.get_int('userid')]
attacker = player_dictionary[game_event.get_int('attacker')]
Image
nergal
Member
Posts: 57
Joined: Sun Mar 15, 2015 2:58 pm

Postby nergal » Mon Jul 06, 2015 12:49 am

satoon101 wrote:I realize you said no global variables, but I really think that a global dictionary to store player instances by userid would be your best bet:

Syntax: Select all

class _PlayerDictionary(dict):

def __missing__(self, userid):
value = index_from_userid(userid, False)
if value is not None:
value = self[userid] = YourPlayerClass(value)
return value

player_dictionary = _PlayerDictionary()


@Event
def player_death(game_event):
victim = player_dictionary[game_event.get_int('userid')]
attacker = player_dictionary[game_event.get_int('attacker')]


I'd rather learn how to not depend on global variables but u know more than me on this so ok!
nergal
Member
Posts: 57
Joined: Sun Mar 15, 2015 2:58 pm

Postby nergal » Sun Jul 26, 2015 4:30 pm

update: made a repo for this plugin :)

https://bitbucket.org/assyrian/source.py-saxton-hale-boss-mode

Already field tested it yesterday and worked out all compiling errors.

a few questions.

1. How do I hook prethink/think functions?
2. How can I prehook and posthook an Event? There is certain data i need processed before the Event runs as I want to change the event's variables.

EDIT: Updated OP with repo link as well :3
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Mon Jul 27, 2015 1:09 pm

What is your purpose behind hooking think/pre-think? Just wondering if there is a better way to do what you are wanting to do.

There are pre and post event discussions on the forums already. I am interested, though, in what event variables you wish to change. Changing event variable values can be dangerous, as you potentially can break other plugins by doing so.
Image
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Postby L'In20Cible » Mon Jul 27, 2015 7:27 pm

Hooking Pre/Think is the way to go if you are manipulating entities often. A tick listener is costly since you also have to do all the loop/conversions to find your entity. Also, it allows clean viewmodel, addons change (weapons displayed on players), etc. They are definititely methods we need to add to our data at some point.
nergal
Member
Posts: 57
Joined: Sun Mar 15, 2015 2:58 pm

Postby nergal » Mon Jul 27, 2015 9:43 pm

satoon101 wrote:What is your purpose behind hooking think/pre-think? Just wondering if there is a better way to do what you are wanting to do.

There are pre and post event discussions on the forums already. I am interested, though, in what event variables you wish to change. Changing event variable values can be dangerous, as you potentially can break other plugins by doing so.


The purpose of hooking the thinks is give the boss the necessary abilities and boss/player specific code that requires being looped onto them.

L'In20Cible wrote:Hooking Pre/Think is the way to go if you are manipulating entities often. A tick listener is costly since you also have to do all the loop/conversions to find your entity. Also, it allows clean viewmodel, addons change (weapons displayed on players), etc. They are definititely methods we need to add to our data at some point.


yes! I also need to prehook Events such as player_death as I need to change certain damage before it's sent to the Event
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Mon Jul 27, 2015 10:08 pm

There is no 'damage' in the player_death event. To change damage, you would want to hook on_take_damage.
Image
nergal
Member
Posts: 57
Joined: Sun Mar 15, 2015 2:58 pm

Postby nergal » Mon Jul 27, 2015 10:25 pm

satoon101 wrote:What is your purpose behind hooking think/pre-think? Just wondering if there is a better way to do what you are wanting to do.

There are pre and post event discussions on the forums already. I am interested, though, in what event variables you wish to change. Changing event variable values can be dangerous, as you potentially can break other plugins by doing so.


player_hurt damage variable as well as the weapon variable used in player_death.

I'm aware that this would mess with other plugins but I require such a feature for my Saxton Hale port.

satoon101 wrote:There is no 'damage' in the player_death event. To change damage, you would want to hook on_take_damage.


sorry I meant player_hurt event.
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Mon Jul 27, 2015 11:31 pm

Then don't change it in the event, change it in the on_take_damage function. There are very few reasons to ever change event variable values. Also, just cause you change the damage amount in the event, doesn't change the actual damage done to the player. Same with the weapon. You need to change those in on_take_damage.
Image
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Tue Jul 28, 2015 12:56 am

L'In20Cible wrote:Hooking Pre/Think is the way to go if you are manipulating entities often. A tick listener is costly since you also have to do all the loop/conversions to find your entity. Also, it allows clean viewmodel, addons change (weapons displayed on players), etc. They are definititely methods we need to add to our data at some point.


I don't disagree, and those should be easy to add as, if I remember correctly, they are virtual. I just want to make sure that that functionality is what is needed in this instance.
Image
nergal
Member
Posts: 57
Joined: Sun Mar 15, 2015 2:58 pm

Re: New Project: Porting Saxton Hale mod for Source.Python

Postby nergal » Thu Aug 02, 2018 4:56 am

hello everybody, I have returned and I'm glad to say that I am reviving this project which is why I'm necroing this!

EDIT: Wow, how crazy that 3 exact years have passed since the last post

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 26 guests