Accessing math_counters from SP

Please post any questions about developing your plugin here. Please use the search function before posting!
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Accessing math_counters from SP

Postby iPlayer » Thu Nov 26, 2015 4:17 pm

I invite everybody to continue this old discussion on math_counter's, but now in terms of accessing these entities from inside of Source.Python.

The issue me, Ayuto and Absolute discovered is that logic entities like logic_branch, math_counter etc don't get networked. The only thing I did not understand is why we still can't get access to them from server-side plugin even though they don't get networked to clients.

To setup some testing environment
So. I've just created a sample map. It basically consists of func_button, math_counter, light and prop_dynamic.
es_math_counters.bsp | es_math_counters.vmf
Soon as player presses func_button 3 times (math_counter is responsible for counting), light will turn on and prop_dynamic will change its skin.

Here it is in Hammer:
Image

Everything works in-game:
Image



Now let's load the following script

Syntax: Select all

from filters.entities import EntityIter


def dump_entity(classname):
print("Number of '{0}' entities on the map: {1}".format(classname, len(EntityIter(classname))))


def load():
dump_entity("func_button")
dump_entity("prop_dynamic")
dump_entity("math_counter")


Once we load it, we get:

Code: Select all

sp load math_counters
Number of 'func_button' entities on the map: 1
Number of 'prop_dynamic' entities on the map: 1
Number of 'math_counter' entities on the map: 0


So. I need to work with logic_ entities. For now I'm bound to using ent_fire, fortunately I only need to fire inputs on them. But still, isn't there any possibility to gain access to them?
User avatar
satoon101
Project Leader
Posts: 2703
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Thu Nov 26, 2015 4:19 pm

Try using BaseEntityIter instead of EntityIter.
Image
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Postby iPlayer » Thu Nov 26, 2015 4:27 pm

Code: Select all

sp load math_counters
Number of 'func_button' entities on the map: 1
Number of 'prop_dynamic' entities on the map: 1
Number of 'math_counter' entities on the map: 1


Thanks! That worked, SP found math_counter. Though I'm still unable to use .call_input, .get_input on it because all these useful methods are only implemented for Entity, not BaseEntity. Any suggestions?

Oh, their index is -1. I guess there's not much we can do.
User avatar
satoon101
Project Leader
Posts: 2703
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Thu Nov 26, 2015 5:23 pm

You can do what Entity does internally. Most of the Entity class does not necessarily require the index, so we could create a new class that does all of the stuff accessible by the BaseEntity objects themselves that Entity can sub-class to do the rest. Maybe the new class could take an Edict object or something.
Image
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Postby iPlayer » Thu Nov 26, 2015 5:27 pm

This is the furthest I got:

Syntax: Select all

from entities.classes import server_classes
from entities.datamaps import FieldType
from memory import make_object


_input_types = {
FieldType.BOOLEAN: bool,
FieldType.FLOAT: float,
FieldType.INTEGER: int,
FieldType.STRING: str,
FieldType.VOID: None,
}


def get_input(target, input_name):
"""Build an input function based on target's edict."""
for server_class in server_classes.get_entity_server_classes(target):
if input_name in server_class.inputs:
return getattr(
make_object(server_class._inputs, target.pointer), input_name)

return None


def call_input(target, input_name, parameter, caller, activator):
"""Call an input function"""
# We are not sure if the entity actually supports this input
input_function = get_input(target, input_name)

# If not, we don't work with this entity
if input_function is None:
return

caller_index = None if caller is None else caller.index
activator_index = None if activator is None else activator.index

# Check if type is unsupported, but we actually support all types that can possibly
# be passed as a string to input: int, float, bool, str
if input_function._argument_type not in _input_types:
return

type_ = _input_types[input_function._argument_type]

# Case: input does not require parameter
if type_ is None:
parameter = None

# Case: input does require parameter
else:
# Try to cast the parameter to the given type
try:
parameter = type_(parameter)

# We don't give up the target if the value can't be casted;
# Instead, we fire its input with a default value just like ent_fire does
except ValueError:
parameter = type_()

# Fire an input
input_function(parameter, caller_index, activator_index)


server_class on line 17 seems to be fine (<class 'memory.manager.CLogicBranch'>), for example server_class.inputs contains SetValueTest but doesn't contain DummyInput. And the input function gets built correctly. And it's fired with no exceptions raised.
The problem is that nothing happens, input doesn't work.

EDIT: Got ninja'd here. Yes, all this time I actually was trying to recreate what Entity does internally.
User avatar
Ayuto
Project Leader
Posts: 2209
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Thu Nov 26, 2015 5:29 pm

Yes, math_counter is a non-networked entity. That means that it doesn't have an index (and edict).

Instead of creating another class we would ideally move the shared code to the BaseEntity class.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Postby iPlayer » Thu Nov 26, 2015 5:47 pm

I take it back. It actually works. Problem on my side.

Big thank you. I almost (again) switched to using ent_fire.

The issue I ran into is that I forgot that my parameter is a string, and when casting to boolean, '0' would cast to True. So my input always fired with True argument and it didn't actually do anything on my screen in my case.
So, re-creating some of the internal Entity functionality (get_input) works. I hope you will move get_input and call_input to BaseEntity.

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 109 guests