Skip to content

Commit

Permalink
Merge pull request #1051 from BEEmod/dev
Browse files Browse the repository at this point in the history
Release 4.33.0
  • Loading branch information
TeamSpen210 authored Jan 11, 2019
2 parents 0d78709 + e7ec75e commit d46f552
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 135 deletions.
37 changes: 29 additions & 8 deletions src/CompilerPane.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@
from BEE2_config import ConfigFile, GEN_OPTS, option_handler
from packageLoader import CORRIDOR_COUNTS, CorrDesc
from tooltip import add_tooltip, set_tooltip
from srctools import Property
from srctools import Property, AtomicWriter
import selectorWin
import tkMarkdown
import SubPane
import img
import os
import base64

from typing import Dict, Tuple, Optional

Expand Down Expand Up @@ -92,12 +92,7 @@
tk_screenshot = None # The preview image shown

# Location we copy custom screenshots to
SCREENSHOT_LOC = os.path.abspath(os.path.join(
os.getcwd(),
'..',
'config',
'screenshot.jpg'
))
SCREENSHOT_LOC = str(utils.conf_location('screenshot.jpg'))

VOICE_PRIORITY_VAR = IntVar(
value=COMPILE_CFG.get_bool('General', 'use_voice_priority', True)
Expand Down Expand Up @@ -186,13 +181,39 @@ def save_load_compile_pane(props: Optional[Property]=None) -> Optional[Property]
for group, win in CORRIDOR.items():
corr_prop[group] = win.chosen_id or '<NONE>'

# Embed the screenshot in so we can load it later.
if chosen_thumb.get() == 'CUST':
# encodebytes() splits it into multiple lines, which we write
# in individual blocks to prevent having a massively long line
# in the file.
with open(SCREENSHOT_LOC, 'rb') as f:
screenshot_data = base64.encodebytes(f.read())
props.append(Property(
'sshot_data',
[
Property('b64', data)
for data in
screenshot_data.decode('ascii').splitlines()
]
))

return props

# else: Loading

chosen_thumb.set(props['sshot_type', chosen_thumb.get()])
cleanup_screenshot.set(props.bool('sshot_cleanup', cleanup_screenshot.get()))

if 'sshot_data' in props:
screenshot_parts = b'\n'.join([
prop.value.encode('ascii')
for prop in
props.find_children('sshot_data')
])
screenshot_data = base64.decodebytes(screenshot_parts)
with AtomicWriter(SCREENSHOT_LOC, is_bytes=True) as f:
f.write(screenshot_data)

# Refresh these.
set_screen_type()
set_screenshot()
Expand Down
44 changes: 38 additions & 6 deletions src/conditions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
"""Implements the Conditions system.
This system allows users to define transformations applied to
every instance.
In pseudocode:
for cond in all_conditions:
for inst in vmf:
if all(flag() in cond):
apply_results()
Both results and flags recieve configuration keyvalues, the vmf and the
current instance. Flags return a boolean to indicate if they are successful.
Results return None normally, but can return the special value RES_EXHAUSTED to
indicate calling the specific result again will have no effect. In this case the
result will be deleted.
Argument type annotations are used to allow flexibility in defining results and
flags. Each argument must be typed as one of the following to recieve a specific
value:
* VMF to recieve the overall map.
* Entity to recieve the current instance.
* Property to recieve keyvalues configuration.
"""
import inspect
import io
import itertools
Expand Down Expand Up @@ -659,21 +683,29 @@ def dump_conditions(file: TextIO) -> None:
# Delete existing data, after the marker.
file.seek(0, io.SEEK_SET)

prelude = []

for line in file:
if DOC_MARKER in line:
file.truncate()
break
else:
prelude.append(line)

file.seek(0, io.SEEK_SET)
file.truncate(0)

if not prelude:
# No marker, blank the whole thing.
LOGGER.warning('No intro text before marker!')
file.truncate(0)
file.write(DOC_MARKER + '\n\n')

print(DOC_META_COND, file=file)
for line in prelude:
file.write(line)
file.write(DOC_MARKER + '\n\n')

file.write(DOC_META_COND)

ALL_META.sort(key=lambda i: i[1]) # Sort by priority
for flag_key, priority, func in ALL_META:
print('#### `{}` ({}):\n'.format(flag_key, priority), file=file)
file.write('#### `{}` ({}):\n\n'.format(flag_key, priority))
dump_func_docs(file, func)
file.write('\n')

Expand Down
45 changes: 28 additions & 17 deletions src/conditions/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
from srctools import Property, Vec, Entity, VMF, Output
import srctools.logger
import vbsp_options
import voiceLine

from typing import Optional, List, Dict, Tuple

from typing import List

COND_MOD_NAME = 'Monitors'

Expand All @@ -24,7 +26,7 @@
# Keep a counter of the number of monitor bullseyes at a pos.
# This allows us to ensure we don't remove catapults also aiming here,
# and that we remove when more than one camera is pointed here.
BULLSYE_LOCS = defaultdict(int)
BULLSYE_LOCS = defaultdict(int) # type: Dict[Tuple[float, float, float], int]

MON_ARGS_SCRIPT = os.path.join('BEE2', 'inject', 'monitor_args.nut')

Expand All @@ -38,8 +40,10 @@
# If non-emtpy we have monitors to shoot by turrets.
MONITOR_RELATIONSHIP_ENTS = [] # type: List[Entity]

# The location of the voiceline room, used to position the camera.
VOICELINE_LOC = Vec()

def get_studio_pose() -> Vec:
"""Return the position of the studio camera."""
return voiceLine.get_studio_loc() + vbsp_options.get(Vec, 'voice_studio_cam_loc')


@make_result_setup('Monitor')
Expand All @@ -53,7 +57,7 @@ def res_monitor_setup(res: Property):


@make_result('Monitor')
def res_monitor(inst: Entity, res: Property):
def res_monitor(inst: Entity, res: Property) -> None:
"""Result for the monitor component.
"""
Expand Down Expand Up @@ -135,7 +139,7 @@ def res_camera(inst: Entity, res: Property):
inst_name = inst['targetname']

try:
target, = inst.map.by_target[inst_name + '-target'] # type: Entity
[target] = inst.map.by_target[inst_name + '-target'] # type: Entity
except ValueError:
# No targets with that name
inst.remove()
Expand Down Expand Up @@ -190,7 +194,7 @@ def res_camera(inst: Entity, res: Property):


@meta_cond(priority=-5, only_once=False)
def mon_remove_bullseyes(inst: Entity):
def mon_remove_bullseyes(inst: Entity) -> Optional[object]:
"""Remove bullsyes used for cameras."""
if not BULLSYE_LOCS:
return RES_EXHAUSTED
Expand All @@ -209,11 +213,8 @@ def mon_remove_bullseyes(inst: Entity):
inst.remove()


# Note that we happen after voiceline adding!


@meta_cond(priority=-275, only_once=True)
def mon_camera_link():
def mon_camera_link() -> None:
"""Link cameras to monitors."""
import vbsp
LOGGER.info('Bullseye {}', BULLSYE_LOCS)
Expand Down Expand Up @@ -259,7 +260,7 @@ def mon_camera_link():
else:
if vbsp_options.get(str, 'voice_studio_inst'):
# Start at the studio, if it exists.
start_pos = VOICELINE_LOC
start_pos = get_studio_pose()
start_angles = '{:g} {:g} 0'.format(
vbsp_options.get(float, 'voice_studio_cam_pitch'),
vbsp_options.get(float, 'voice_studio_cam_yaw'),
Expand Down Expand Up @@ -298,7 +299,18 @@ def mon_camera_link():
cam['vscripts'] = 'BEE2/mon_camera_args.nut BEE2/mon_camera.nut'
cam['thinkfunction'] = 'Think'

# Write out a script containing the arguments to the camera.

# Note that we must happen after voiceline adding!

@meta_cond(priority=150, only_once=True)
def mon_camera_script() -> None:
"""Write out a script containing the arguments to the camera."""
active_counts = [
srctools.conv_int(cam.inst.fixup['$start_enabled', '0'])
for cam in
ALL_CAMERAS
]

with open(MON_ARGS_SCRIPT, 'w') as scr:
scr.write('CAM_NUM <- {};\n'.format(len(ALL_CAMERAS)))
scr.write('CAM_ACTIVE_NUM <- {};\n'.format(sum(active_counts)))
Expand All @@ -320,7 +332,7 @@ def mon_camera_link():
# We have a voice studio, send values to the script.
scr.write(
'CAM_STUDIO_LOC <- Vector({0.x:.3f}, '
'{0.y:.3f}, {0.z:.3f});\n'.format(VOICELINE_LOC),
'{0.y:.3f}, {0.z:.3f});\n'.format(get_studio_pose()),
)
scr.write(
'CAM_STUDIO_CHANCE <- {chance};\n'
Expand All @@ -340,14 +352,14 @@ def mon_camera_link():
)


def make_voice_studio(vmf: VMF, loc: Vec):
def make_voice_studio(vmf: VMF) -> bool:
"""Create the voice-line studio.
This is either an instance (if monitors are present), or a nodraw room.
"""
global VOICELINE_LOC

studio_file = vbsp_options.get(str, 'voice_studio_inst')
loc = voiceLine.get_studio_loc()

if ALL_MONITORS and studio_file:
vmf.create_ent(
Expand All @@ -356,7 +368,6 @@ def make_voice_studio(vmf: VMF, loc: Vec):
origin=loc,
angles='0 0 0',
)
VOICELINE_LOC = loc + vbsp_options.get(Vec, 'voice_studio_cam_loc')
return True
else:
# If there aren't monitors, the studio instance isn't used.
Expand Down
Loading

0 comments on commit d46f552

Please sign in to comment.