Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added EventCode GO_FARTHEST, EQUIP_ITEM to track #52

Merged
merged 3 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 4 additions & 19 deletions nmmo/entity/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import numpy as np

from nmmo.core.config import Config
from nmmo.lib import utils
from nmmo.datastore.serialized import SerializedState
from nmmo.systems import inventory
from nmmo.lib.log import EventCode
Expand Down Expand Up @@ -153,6 +152,7 @@ def packet(self):
return data


# NOTE: History.packet() is actively used in visulazing attacks
class History:
def __init__(self, ent):
self.actions = {}
Expand All @@ -178,9 +178,6 @@ def update(self, entity, actions):
if entity.ent_id in actions:
self.actions = actions[entity.ent_id]

exploration = utils.linf(entity.pos, self.starting_position)
self.exploration = max(exploration, self.exploration)

self.time_alive.increment()

def packet(self):
Expand All @@ -193,21 +190,9 @@ def packet(self):
if self.attack is not None:
data['attack'] = self.attack

actions = {}
for atn, args in self.actions.items():
atn_packet = {}

# Avoid recursive player packet
if atn.__name__ == 'Attack':
continue

for key, val in args.items():
if hasattr(val, 'packet'):
atn_packet[key.__name__] = val.packet
else:
atn_packet[key.__name__] = val.__name__
actions[atn.__name__] = atn_packet
data['actions'] = actions
# NOTE: the client seems to use actions for visualization
# but produces errors with the new actions. So we disable it for now.
data['actions'] = {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wanna leave the code commented out for now?


return data

Expand Down
14 changes: 9 additions & 5 deletions nmmo/io/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,7 @@ def call(realm, entity, direction):
r_delta, c_delta = direction.delta
r_new, c_new = r+r_delta, c+c_delta

# CHECK ME: before this agents were allowed to jump into lava and die
# however, when config.IMMORTAL = True was set, lava-jumping agents
# did not die and made all the way to the map edge, causing errors
# e.g., systems/skill.py, line 135: realm.map.tiles[r, c+1] index error
# How do we want to handle this?
# CHECK ME: lava-jumping agents in the tutorial no longer works
if realm.map.tiles[r_new, c_new].impassible:
return

Expand All @@ -143,6 +139,14 @@ def call(realm, entity, direction):
realm.map.tiles[r, c].remove_entity(ent_id)
realm.map.tiles[r_new, c_new].add_entity(entity)

# exploration record keeping. moved from entity.py, History.update()
dist_from_spawn = utils.linf(entity.spawn_pos, (r_new, c_new))
if dist_from_spawn > entity.history.exploration:
entity.history.exploration = dist_from_spawn
if entity.is_player:
realm.event_log.record(EventCode.GO_FARTHEST, entity,
distance=dist_from_spawn)

# CHECK ME: material.Impassible includes lava, so this line is not reachable
if realm.map.tiles[r_new, c_new].lava:
entity.receive_damage(None, entity.resources.health.val)
Expand Down
15 changes: 13 additions & 2 deletions nmmo/lib/event_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@

LEVEL_COL_MAP = { 'skill': EventAttr['type'] }

EXPLORE_COL_MAP = { 'distance': EventAttr['number'] }


class EventLogger(EventCode):
def __init__(self, realm):
Expand All @@ -60,6 +62,7 @@ def __init__(self, realm):
self.attr_to_col.update(ATTACK_COL_MAP)
self.attr_to_col.update(ITEM_COL_MAP)
self.attr_to_col.update(LEVEL_COL_MAP)
self.attr_to_col.update(EXPLORE_COL_MAP)

def reset(self):
EventState.State.table(self.datastore).reset()
Expand All @@ -69,7 +72,8 @@ def _create_event(self, entity: Entity, event_code: int):
log = EventState(self.datastore)
log.id.update(log.datastore_record.id)
log.ent_id.update(entity.ent_id)
log.tick.update(self.realm.tick)
# the tick increase by 1 after executing all actions
log.tick.update(self.realm.tick+1)
log.event.update(event_code)

return log
Expand All @@ -82,6 +86,12 @@ def record(self, event_code: int, entity: Entity, **kwargs):
self._create_event(entity, event_code)
return

if event_code == EventCode.GO_FARTHEST: # use EXPLORE_COL_MAP
if ('distance' in kwargs and kwargs['distance'] > 0):
log = self._create_event(entity, event_code)
log.number.update(kwargs['distance'])
return

if event_code == EventCode.SCORE_HIT:
# kwargs['combat_style'] should be Skill.CombatSkill
if ('combat_style' in kwargs and kwargs['combat_style'].SKILL_ID in [1, 2, 3]) & \
Expand All @@ -101,10 +111,11 @@ def record(self, event_code: int, entity: Entity, **kwargs):
log.level.update(target.attack_level)
return

if event_code in [EventCode.CONSUME_ITEM, EventCode.HARVEST_ITEM]:
if event_code in [EventCode.CONSUME_ITEM, EventCode.HARVEST_ITEM, EventCode.EQUIP_ITEM]:
# CHECK ME: item types should be checked. For example,
# Only Ration and Poultice can be consumed
# Only Ration, Poultice, Scrap, Shaving, Shard can be produced
# The quantity should be 1 for all of these events
if ('item' in kwargs and isinstance(kwargs['item'], Item)):
item = kwargs['item']
log = self._create_event(entity, event_code)
Expand Down
2 changes: 2 additions & 0 deletions nmmo/lib/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class EventCode:
# Move
EAT_FOOD = 1
DRINK_WATER = 2
GO_FARTHEST = 3 # record when breaking the previous record

# Attack
SCORE_HIT = 11
Expand All @@ -52,6 +53,7 @@ class EventCode:
GIVE_ITEM = 22
DESTROY_ITEM = 23
HARVEST_ITEM = 24
EQUIP_ITEM = 25

# Exchange
GIVE_GOLD = 31
Expand Down
2 changes: 1 addition & 1 deletion nmmo/systems/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def use(self, entity):
# always empty the slot first
self._slot(entity).unequip()
self.equip(entity, self._slot(entity))

self.realm.event_log.record(EventCode.EQUIP_ITEM, entity, item=self)

class Armor(Equipment, ABC):
def __init__(self, realm, level, **kwargs):
Expand Down
23 changes: 12 additions & 11 deletions scripted/baselines.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,18 @@ def attack(self):

def target_weak(self):
'''Target the nearest agent if it is weak'''
# disabled for now
# if self.closest is None:
# return False

# selfLevel = self.me.level
# targLevel = max(self.closest.melee_level, self.closest.range_level, self.closest.mage_level)

# if population == -1 or targLevel <= selfLevel <= 5 or selfLevel >= targLevel + 3:
# self.target = self.closest
# self.targetID = self.closestID
# self.targetDist = self.closestDist
if self.closest is None:
return False

selfLevel = self.me.level
targLevel = max(self.closest.melee_level, self.closest.range_level, self.closest.mage_level)

if self.closest.npc_type == 1 or \
targLevel <= selfLevel <= 5 or \
selfLevel >= targLevel + 3:
self.target = self.closest
self.targetID = self.closestID
self.targetDist = self.closestDist

def scan_agents(self):
'''Scan the nearby area for agents'''
Expand Down
8 changes: 5 additions & 3 deletions tests/render/test_render_save.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@

if __name__ == '__main__':
import time
import random
import nmmo

# pylint: disable=import-error
from nmmo.render.render_client import WebsocketRenderer
from tests.testhelpers import ScriptedAgentTestConfig

TEST_HORIZON = 30
TEST_HORIZON = 100
RANDOM_SEED = random.randint(0, 9999)

# config.RENDER option is gone,
# RENDER can be done without setting any config
config = ScriptedAgentTestConfig()
env = nmmo.Env(config)

env.reset()
env.reset(seed=RANDOM_SEED)

# the renderer is external to the env, so need to manually initiate it
renderer = WebsocketRenderer(env.realm)
Expand All @@ -26,4 +28,4 @@
time.sleep(1)

# save the packet: this is possible because config.SAVE_REPLAY = True
env.realm.save_replay('replay_dev.json', compress=False)
env.realm.save_replay(f'replay_seed_{RANDOM_SEED:04d}.json', compress=False)
34 changes: 23 additions & 11 deletions tests/test_eventlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from nmmo.lib.log import EventCode
from nmmo.entity.entity import Entity
from nmmo.systems.item import ItemState
from nmmo.systems.item import Scrap, Ration
from nmmo.systems.item import Scrap, Ration, Hat
from nmmo.systems import skill as Skill


Expand Down Expand Up @@ -41,23 +41,23 @@ def test_event_logging(self):
mock_realm = MockRealm()
event_log = EventLogger(mock_realm)

mock_realm.tick = 1
mock_realm.tick = 0 # tick increase to 1 after all actions are processed
event_log.record(EventCode.EAT_FOOD, MockEntity(1))
event_log.record(EventCode.DRINK_WATER, MockEntity(2))
event_log.record(EventCode.SCORE_HIT, MockEntity(2),
combat_style=Skill.Melee, damage=50)
event_log.record(EventCode.PLAYER_KILL, MockEntity(3),
target=MockEntity(5, attack_level=5))

mock_realm.tick = 2
mock_realm.tick = 1
event_log.record(EventCode.CONSUME_ITEM, MockEntity(4),
item=Ration(mock_realm, 8))
event_log.record(EventCode.GIVE_ITEM, MockEntity(4))
event_log.record(EventCode.DESTROY_ITEM, MockEntity(5))
event_log.record(EventCode.HARVEST_ITEM, MockEntity(6),
item=Scrap(mock_realm, 3))

mock_realm.tick = 3
mock_realm.tick = 2
event_log.record(EventCode.GIVE_GOLD, MockEntity(7))
event_log.record(EventCode.LIST_ITEM, MockEntity(8),
item=Ration(mock_realm, 5), price=11)
Expand All @@ -66,10 +66,15 @@ def test_event_logging(self):
item=Scrap(mock_realm, 7), price=21)
#event_log.record(EventCode.SPEND_GOLD, env.realm.players[11], amount=25)

mock_realm.tick = 4
mock_realm.tick = 3
event_log.record(EventCode.LEVEL_UP, MockEntity(12),
skill=Skill.Fishing, level=3)

mock_realm.tick = 4
event_log.record(EventCode.GO_FARTHEST, MockEntity(12), distance=6)
event_log.record(EventCode.EQUIP_ITEM, MockEntity(12),
item=Hat(mock_realm, 4))

log_data = [list(row) for row in event_log.get_data()]

self.assertListEqual(log_data, [
Expand All @@ -85,15 +90,16 @@ def test_event_logging(self):
[10, 8, 3, EventCode.LIST_ITEM, 16, 5, 1, 11, 0],
[11, 9, 3, EventCode.EARN_GOLD, 0, 0, 0, 15, 0],
[12, 10, 3, EventCode.BUY_ITEM, 13, 7, 1, 21, 0],
[13, 12, 4, EventCode.LEVEL_UP, 4, 3, 0, 0, 0]])

[13, 12, 4, EventCode.LEVEL_UP, 4, 3, 0, 0, 0],
[14, 12, 5, EventCode.GO_FARTHEST, 0, 0, 6, 0, 0],
[15, 12, 5, EventCode.EQUIP_ITEM, 2, 4, 1, 0, 0]])

if __name__ == '__main__':
unittest.main()

"""
TEST_HORIZON = 30
RANDOM_SEED = 335
TEST_HORIZON = 50
RANDOM_SEED = 338

from tests.testhelpers import ScriptedAgentTestConfig, ScriptedAgentTestEnv

Expand All @@ -103,9 +109,15 @@ def test_event_logging(self):
env.reset(seed=RANDOM_SEED)

from tqdm import tqdm
for _ in tqdm(range(TEST_HORIZON)):
for tick in tqdm(range(TEST_HORIZON)):
env.step({})
#print(env.realm.event_log.get_data())

# events to check
log = env.realm.event_log.get_data()
idx = (log[:,2] == tick+1) & (log[:,3] == EventCode.EQUIP_ITEM)
if sum(idx):
print(log[idx])
print()

print('done')
"""