Package horizons :: Package util :: Module lastactiveplayersettlementmanager
[hide private]
[frames] | no frames]

Source Code for Module horizons.util.lastactiveplayersettlementmanager

  1  # ################################################### 
  2  # Copyright (C) 2008-2017 The Unknown Horizons Team 
  3  # team@unknown-horizons.org 
  4  # This file is part of Unknown Horizons. 
  5  # 
  6  # Unknown Horizons is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, 
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  # GNU General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the 
 18  # Free Software Foundation, Inc., 
 19  # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 20  # ################################################### 
 21   
 22  import weakref 
 23  from typing import Optional 
 24   
 25  from horizons.messaging import HoverSettlementChanged, NewPlayerSettlementHovered, NewSettlement 
 26  from horizons.util.python.singleton import ManualConstructionSingleton 
 27  from horizons.util.shapes import Point 
 28  from horizons.util.worldobject import WorldObject 
 29   
 30   
31 -def resolve_weakref(ref):
32 """Resolves a weakref to a hardref, where the ref itself can be None""" 33 if ref is None: 34 return None 35 else: 36 return ref()
37 38
39 -def create_weakref(obj):
40 """Safe create weakref, that supports None""" 41 if obj is None: 42 return None 43 else: 44 return weakref.ref(obj)
45 46
47 -class LastActivePlayerSettlementManager(object, metaclass=ManualConstructionSingleton):
48 """Keeps track of the last active (hovered over) player's settlement. 49 Provides it as global reference, but stores as weak reference as not to disturb anything. 50 51 Provide new mouse info to it via update(). 52 Retrieve settlement via get(). 53 Hooks itself to view automatically. 54 """ 55
56 - def __init__(self, session):
57 self.session = session 58 self.session.view.add_change_listener(self._on_scroll) 59 60 # settlement mouse currently is above or None 61 self._cur_settlement = None # type: Optional[weakref.ref[WorldObject]] 62 63 # last settlement of player mouse was on, only None at startup 64 self._last_player_settlement = None # type: Optional[weakref.ref[WorldObject]] 65 66 # whether last known event was not on a player settlement 67 # can be used to detect reentering the area of _last_player_settlement 68 self._last_player_settlement_hovered_was_none = True 69 70 NewSettlement.subscribe(self._on_new_settlement_created)
71
72 - def save(self, db):
73 if self._last_player_settlement is not None: 74 db("INSERT INTO last_active_settlement(type, value) VALUES(?, ?)", "PLAYER", self._last_player_settlement().worldid) 75 if self._cur_settlement is not None: 76 db("INSERT INTO last_active_settlement(type, value) VALUES(?, ?)", "ANY", self._cur_settlement().worldid) 77 78 db("INSERT INTO last_active_settlement(type, value) VALUES(?, ?)", "LAST_NONE_FLAG", self._last_player_settlement_hovered_was_none)
79
80 - def load(self, db):
81 data = db('SELECT value FROM last_active_settlement WHERE type = "PLAYER"') 82 self._last_player_settlement = weakref.ref(WorldObject.get_object_by_id(data[0][0])) if data else None 83 data = db('SELECT value FROM last_active_settlement WHERE type = "ANY"') 84 self._cur_settlement = weakref.ref(WorldObject.get_object_by_id(data[0][0])) if data else None 85 data = db('SELECT value FROM last_active_settlement WHERE type = "LAST_NONE_FLAG"') 86 self._last_player_settlement_hovered_was_none = bool(data[0][0])
87
88 - def remove(self):
89 self._last_player_settlement = None 90 self._cur_settlement = None 91 self.session.view.remove_change_listener(self._on_scroll) 92 NewSettlement.unsubscribe(self._on_new_settlement_created)
93
94 - def update(self, current):
95 """Update to new world position. Sets internal state to new settlement or no settlement 96 @param current: some kind of position coords with x- and y-values""" 97 settlement = self.session.world.get_settlement(Point(int(round(current.x)), int(round(current.y)))) 98 99 # check if it's a new settlement independent of player 100 if resolve_weakref(self._cur_settlement) is not settlement: 101 self._cur_settlement = create_weakref(settlement) 102 HoverSettlementChanged.broadcast(self, settlement) 103 104 # player-sensitive code 105 new_player_settlement = weakref.ref(settlement) if \ 106 settlement and settlement.owner.is_local_player else None 107 108 need_msg = False 109 # check if actual last player settlement is a new one 110 if new_player_settlement is not None and \ 111 resolve_weakref(self._last_player_settlement) is not resolve_weakref(new_player_settlement): 112 self._last_player_settlement = new_player_settlement 113 need_msg = True 114 115 # check if we changed to or from None 116 # this doesn't change the last settlement, but we need a message 117 if (new_player_settlement is None and not self._last_player_settlement_hovered_was_none) or \ 118 (new_player_settlement is not None and self._last_player_settlement_hovered_was_none): 119 need_msg = True 120 121 if need_msg: 122 NewPlayerSettlementHovered.broadcast(self, resolve_weakref(new_player_settlement)) 123 self._last_player_settlement_hovered_was_none = (new_player_settlement is None)
124
125 - def get(self, get_current_pos=False):
126 """The last settlement belonging to the player the mouse has hovered above. 127 @param get_current_pos: get current position even if it's None 128 """ 129 if get_current_pos and self._last_player_settlement_hovered_was_none: 130 return None 131 return resolve_weakref(self._last_player_settlement)
132
133 - def get_current_settlement(self):
134 """Returns settlement mouse currently hovers over or None""" 135 return resolve_weakref(self._cur_settlement)
136
137 - def _on_scroll(self):
138 """Called when view changes. Scrolling and zooming can change cursor position.""" 139 if not hasattr(self.session, "cursor"): # not inited yet 140 return 141 pos = self.session.cursor.__class__.last_event_pos 142 if pos is not None: 143 loc = self.session.cursor.get_exact_world_location(pos) 144 self.update(loc)
145
146 - def _on_new_settlement_created(self, msg):
147 # if the player has created a new settlement, it is the current one, even 148 # if the mouse hasn't hovered over it. Required when immediately entering build menu. 149 if msg.settlement.owner.is_local_player: 150 self._last_player_settlement = weakref.ref(msg.settlement) 151 self._last_player_settlement_hovered_was_none = False
152