1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 | from copy import deepcopy
from collections import defaultdict
from operator import itemgetter
# Creates flags for states
def create_constants(*constants):
return {key: 2 ** index for index, key in enumerate(constants)}
for constant, value in create_constants("ROLE_SIMULATED", "ROLE_AUTONOMOUS", "ROLE_AUTHORITY").items():
exec("{0} = {1}; NOT_{0} = ~{1}".format(constant, value))
for constant, value in create_constants("NET_DIRTY", "NET_OWNER", "NET_INITIAL").items():
exec("{0} = {1}; NOT_{0} = ~{1}".format(constant, value))
class RoleSpecificFunction:
def __init__(self, func):
self.func = func
self.bound_func = None
def __get__(self, instance, base):
if self.bound_func is None:
self.bound_func = self.func.__get__(instance, base)
return self
def __call__(self, *args, **kwargs):
return self.bound_func(*args, **kwargs)
class Simulated(RoleSpecificFunction):
role = ROLE_SIMULATED
class Attribute:
def __init__(self, condition, value):
self.condition = condition
self.default = value
self.getter = self.setter = None
def register_access(self, getter, setter):
self.getter = getter
self.setter = setter
def __get__(self, instance, owner):
try:
return self.getter(self)
except TypeError:
if instance is None:
return self
raise NotImplementedError
def __set__(self, instance, value):
self.setter(self, value)
def __repr__(self):
return "<Attribute with condition {}, default value {}>".format(self.condition, self.default)
class ActorManager:
def __init__(self):
self.actors = []
def create_actor(self):
actor = Actor()
self.actors.append(actor)
return actor
class Scraper:
def __init__(self):
condition_to_attributes = {}
attributes_to_values = {}
current_role = 0
# Get attributes
for k, v in self.__class__.__dict__.items():
if isinstance(v, RoleSpecificFunction):
role = v.role
if role != current_role:
v.bound_func = lambda *a, **b: None
if not isinstance(v, Attribute):
continue
condition_to_attributes.setdefault(v.condition, dict())[v] = k
attributes_to_values[v] = deepcopy(v.default)
v.register_access(getter=attributes_to_values.__getitem__,
setter=self.on_attribute_changed(attributes_to_values.__setitem__))
# Sort by name within conditions
for condition, values in condition_to_attributes.items():
condition_to_attributes[condition] = sorted(values.keys(), key=values.__getitem__)
self.attr_by_condition = condition_to_attributes
self.value_by_attr = attributes_to_values
self.attributes_changed = False
def on_attribute_changed(self, dictionary):
def _wrapper(*args, **kwargs):
dictionary(*args, **kwargs)
self.attributes_changed = True
return _wrapper
class Actor(Scraper):
score = Attribute(NET_DIRTY|NET_OWNER, 0)
argon = Attribute(NET_DIRTY|NET_OWNER, 3)
aim = Attribute(NET_OWNER, 1)
@Simulated
def shoot(self):
return 2
class NetworkManager:
def __init__(self, actor_manager):
self.actor_manager = actor_manager
self.last_values = defaultdict(set)
self.replication_map = defaultdict(set)
def state_for_actor(self, actor_caller):
last_values = self.last_values
replication_map = self.replication_map
for actor in self.actor_manager.actors:
is_owner = NET_OWNER if actor is actor_caller else 0
is_dirty = NET_DIRTY if actor.attributes_changed else 0
is_initial = 0 if (actor_caller in replication_map[actor]) else NET_INITIAL
state = is_owner | is_dirty | is_initial
try:
attributes = actor.attr_by_condition[state]
except KeyError:
continue
actor_manager = ActorManager()
for i in range(60):
actor_manager.create_actor()
network_manager = NetworkManager(actor_manager)
def main():
# Not all actors are socket-owning players.
for actor in actor_manager.actors[:4]:
actor.shoot()
network_manager.state_for_actor(actor)
|