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

Day night cycles #74948

Closed
wants to merge 30 commits into from
Closed

Day night cycles #74948

wants to merge 30 commits into from

Conversation

Gandalf2k15
Copy link
Contributor

About The Pull Request

(remade at the request of san)

Greetings! Today I bring you a new system to be used in the game. A day and night controller.
image
image

I've been wanting a way out of the darkness of icebox for quite a long time, and I hope this is the best way!

This basically adds a system that will set an areas lighting to something that would make sense for the time of day.

Example of this in action(video sped up massively)

dreamseeker_pEasneSJ6t.mp4

Key points:

  • The IC station time is now calculated differently and will increment differently. Hopefully in a way that makes more sense.
  • Some maps will use this system to display different day/night looks on their surface. This does not apply to space maps.
  • Solar panels now generate more or less power depending on the current time!
  • The day/night lighting is in sync with where the sun is and will change depending on the time.
  • Currently, every 6 seconds, a minute passes in game.
  • There are no longer seconds in station time.

New time system

The new time system aims to provide a more random feeling to the station while maintaining a system that can easily be used to access the current in game IC time. This is shown on most items that are in-game and used to show the old IC station time. This does not change how the OOC world time works.

Why have I added this?
Well, it's so there can be a more noticeable change in the outside environment during a 30 minute to 3-hour round. Before, this would never have been possible, and it makes sense to make all IC time uniform. It just would not be noticeable if every minute that passed was just a minute.

Lightzones

Lightzones are datums that are used to define what sort of lighting any affected areas in the controller should look like. This can be changed to whatever you want, but they must all add up to 24 hours.

Day night controllers

These are what are used to control Z-level day/night cycles, they can currently only be loaded by adding an entry to the map config JSON, but adding more ways to add day/night controllers is trivial at worst.

Day-night controllers compile assigned timezones to build a lookup table for hourly updates to the atmosphere. These lookup tables are compiled so that the transitions between timezones are as smooth as possible.

After testing using the turf lighting update system, I realised it just was not fast enough, so I decided to take inspiration from Azarak's day night system on Horizon, so the area system now uses mutable appearances as underlays.

How the effect is achieved

This system uses a combination of area underlays and turf luminosity as well as turf underlays to dynamically build a "lightmap" for the map.

The open areas use area underlays to efficiently generate a thematic colour and light intensity, while the luminosity is used to determine if you can actually see in the dark.

This also applies to adjacent turfs(turfs that are on the edge of the area and that should affected by the outside lighting), the adjacent turfs are calculated using an algorithm to decide what turfs should have lighting overlays applied. These turfs also hook into the areas luminosity to generate seamless transitions between lighting areas.

To-do:

  • Implement the solar array power differences.
  • Investigate lookup table bug

Why It's Good For The Game

This adds a way for us to have different atmospheres for different maps.

Credits

A special thanks goes to Azarak for some of the logic behind this, specifically the area adjacency turf system, see more at: https://github.com/hrzntal/horizon/pull/247

Changelog

🆑 Gandalf2k15, Azarak
add: Icebox will now show if it's day or night using a new time system.
balance: Solar panels will now generate different amounts of energy depending on what time it is(on icebox).
refactor: The time system backend has changed significantly. Every 2.4 hours 24 hours pass in game.
/:cl:

LAZYCLEARLIST(adjacent_day_night_turf_cache)
LAZYINITLIST(adjacent_day_night_turf_cache)

for(var/turf/iterating_turf in contents)
Copy link
Member

Choose a reason for hiding this comment

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

Looping over area contents is extremely slow. It loops over every turf in the entire world to check if they are in the area.

Suggested change
for(var/turf/iterating_turf in contents)
for(var/turf/iterating_turf as anything in get_contained_turfs())

Copy link
Member

Choose a reason for hiding this comment

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

Dunno if it's showing for you but GitHub is telling me I changed the indenting even though I didn't 🤷‍♀️

Copy link
Member

Choose a reason for hiding this comment

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

worth noting that this is liable to force a good amount of list work, depending on the size of the area and how much has been drawn over it, since it resolves to be removed turfs.
it doesn't mean it's worse then the turfs in world method, but it can be liable to show up as a painpoint if called too early after init. how bad depends on the area, space is the classical worst case scenario.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done this, and tested. I haven't noticed any abnormalities?

/**
* This will calculate all adjacent turfs in this area and add them to a cache for lighting effects.
*
* WARNING: This proc is VERY expensive and should be used sparingly.
Copy link
Member

Choose a reason for hiding this comment

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

When is this called?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only once when an area is setup. It's expensive, so it's used very little. As little as possible. Which is next to never aside from startup which impacts times by a fraction.

continue
adjacent_day_night_turf_cache[iterating_turf] = list(DAY_NIGHT_TURF_INDEX_BITFIELD, DAY_NIGHT_TURF_INDEX_APPEARANCE)
adjacent_day_night_turf_cache[iterating_turf][DAY_NIGHT_TURF_INDEX_BITFIELD] = bitfield
RegisterSignal(iterating_turf, COMSIG_PARENT_QDELETING, PROC_REF(clear_adjacent_turf))
Copy link
Member

Choose a reason for hiding this comment

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

Is this ever called more than once? Surely this is going to cause signal overrides?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nope, see previous comment

code/game/area/areas.dm Outdated Show resolved Hide resolved
code/modules/day_night/day_night_controller.dm Outdated Show resolved Hide resolved
code/modules/day_night/day_night_controller.dm Outdated Show resolved Hide resolved
var/datum/lightzone/next_lightzone = get_lightzone(current_iterating_lightzone.end_hour)
var/segments = ((!current_iterating_lightzone.end_hour ? 24 : current_iterating_lightzone.end_hour) - current_iterating_lightzone.start_hour)
var/transition_color = BlendRGB(current_iterating_lightzone.light_color, next_lightzone.light_color, transition_value)
var/transition_alpha = (current_iterating_lightzone.light_alpha * (1 - transition_value)) + (next_lightzone.light_alpha * (0 + transition_value))
Copy link
Member

Choose a reason for hiding this comment

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

We have a LERP macro which I think you're doing manually here?

name = "early morning"
start_hour = 4
end_hour = 8
light_color = "#0000a6"
Copy link
Member

Choose a reason for hiding this comment

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

Every one of these should use the color defines

code/modules/power/solar.dm Outdated Show resolved Hide resolved
code/modules/unit_tests/lightzones.dm Outdated Show resolved Hide resolved
@Mothblocks Mothblocks marked this pull request as draft April 24, 2023 05:58
@LemonInTheDark
Copy link
Member

This system uses a combination of area underlays and turf luminosity as well as turf underlays to dynamically build a "lightmap" for the map.

The open areas use area underlays to efficiently generate a thematic colour and light intensity, while the luminosity is used to determine if you can actually see in the dark.

This also applies to adjacent turfs(turfs that are on the edge of the area and that should affected by the outside lighting), the adjacent turfs are calculated using an algorithm to decide what turfs should have lighting overlays applied. These turfs also hook into the areas luminosity to generate seamless transitions between lighting areas.

Important note, turf luminosity no longer impacts visuals, currently only impacting things like view() calls
it still matters, but the only thing hiding stuff in the dark is the lighting plane dimming it

code/__DEFINES/icon_smoothing.dm Show resolved Hide resolved
Comment on lines 571 to 605
for(var/bit_step in ALL_JUNCTION_DIRECTIONS)
var/turf/target_turf
switch(bit_step)
if(NORTH_JUNCTION)
target_turf = locate(iterating_turf.x, iterating_turf.y + 1, iterating_turf.z)
if(SOUTH_JUNCTION)
target_turf = locate(iterating_turf.x, iterating_turf.y - 1, iterating_turf.z)
if(EAST_JUNCTION)
target_turf = locate(iterating_turf.x + 1, iterating_turf.y, iterating_turf.z)
if(WEST_JUNCTION)
target_turf = locate(iterating_turf.x - 1, iterating_turf.y, iterating_turf.z)
if(NORTHEAST_JUNCTION)
if(bitfield & NORTH_JUNCTION || bitfield & EAST_JUNCTION)
continue
target_turf = locate(iterating_turf.x + 1, iterating_turf.y + 1, iterating_turf.z)
if(SOUTHEAST_JUNCTION)
if(bitfield & SOUTH_JUNCTION || bitfield & EAST_JUNCTION)
continue
target_turf = locate(iterating_turf.x + 1, iterating_turf.y - 1, iterating_turf.z)
if(SOUTHWEST_JUNCTION)
if(bitfield & SOUTH_JUNCTION || bitfield & WEST_JUNCTION)
continue
target_turf = locate(iterating_turf.x - 1, iterating_turf.y - 1, iterating_turf.z)
if(NORTHWEST_JUNCTION)
if(bitfield & NORTH_JUNCTION || bitfield & WEST_JUNCTION)
continue
target_turf = locate(iterating_turf.x - 1, iterating_turf.y + 1, iterating_turf.z)
if(!target_turf)
continue
var/area/target_area = target_turf.loc
if(target_area == src)
continue
if(!target_area.outdoors || target_area.underground)
continue
bitfield ^= bit_step
Copy link
Member

Choose a reason for hiding this comment

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

this is very strange, are you doing this just to ensure looping for this second bit?
ESPECIALLY because this is done for every turf in potentially huge areas, this seems like something that would be worth unrolling (wouldn't even lose all that much)

Comment on lines +648 to +657
var/mutable_appearance/appearance_to_add = mutable_appearance(
icon = 'icons/effects/daynight_blend.dmi',
icon_state = "[adjacent_day_night_turf_cache[iterating_turf][DAY_NIGHT_TURF_INDEX_BITFIELD]]",
layer = DAY_NIGHT_LIGHTING_LAYER,
offset_spokesman = iterating_turf,
plane = LIGHTING_PLANE,
alpha = incoming_controller.current_light_alpha,
appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
)
appearance_to_add.color = incoming_controller.current_light_color
Copy link
Member

Choose a reason for hiding this comment

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

This feels like something that should be cached, with a color, alpha, bitfield and z level string key. Least going off gut it may not be quite such a big deal idk

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I feel like it's not really needed

Copy link
Member

Choose a reason for hiding this comment

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

how hot is this code?

code/modules/day_night/day_night_controller.dm Outdated Show resolved Hide resolved
Comment on lines +213 to +228
/**
* Compiles a lookup table using the loaded lightzones for each hour so we can reference it later when switching to said hour.
*/
/datum/day_night_controller/proc/compile_transitions()
var/hour_index = 0 // We start at 1 as this is 24hr time
var/datum/lightzone/current_iterating_lightzone
var/transition_value = 0
for(var/i in 1 to MIDNIGHT_RESET)
var/datum/lightzone/check_lightzone = get_lightzone(hour_index)
if(current_iterating_lightzone != check_lightzone)
current_iterating_lightzone = check_lightzone
transition_value = 0
var/datum/lightzone/next_lightzone = get_lightzone(current_iterating_lightzone.end_hour)
var/segments = ((!current_iterating_lightzone.end_hour ? 24 : current_iterating_lightzone.end_hour) - current_iterating_lightzone.start_hour)
var/transition_color = BlendRGB(current_iterating_lightzone.light_color, next_lightzone.light_color, transition_value)
var/transition_alpha = (current_iterating_lightzone.light_alpha * (1 - transition_value)) + (next_lightzone.light_alpha * (0 + transition_value))
Copy link
Member

Choose a reason for hiding this comment

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

Might be worth looking into color gradients instead of rolling your own, tho I'm not sure if that's what you're doing here or not
https://www.byond.com/docs/ref/#/{notes}/color-gradient

@@ -8,6 +8,9 @@
///the turf that our light is applied to
var/turf/affected_turf

/// Area which gets linked to a lighting object to make it consider the luminosity from the day/night blending from the area. Yes this isn't ideal, but applying luminosity up to 2 (from both sources) on the turf is not ideal either
var/area/day_night_area
Copy link
Member

Choose a reason for hiding this comment

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

not a massive fan of how this works I'ma be honest, needing to reach in and touch the object, the datum var read, etc. sucks
Would a sources list/bitflag work here?

Copy link
Member

Choose a reason for hiding this comment

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

I also don't like how this is tied directly to day night stuff by name, that's its purpose in terms of this pr but this allows an area to decide if a lighting object should provide lumin or not, it's more general then the name implies

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you have a way to implement the bitflag? I could set the bitflag and unset it accordingly. But it would just be two options

Copy link
Member

Choose a reason for hiding this comment

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

I think I thought incorrectly about how overlay lighting worked.
Something like a bool or a flag seems less... messy? idk.
If the area's lum changes that's fine, can't be helped. I guess I'd mostly just object to the name being so bespoke if so.

I am a bit worried about what happens if areas change, or if a turf loses its lighting object, but that's not related to this all that directly

requisition_text+= "Time of Order: [station_time_timestamp()]<br/>"
requisition_text+= "Time of Order: [SSday_night.get_twentyfourhour_timestamp()]<br/>"
Copy link
Member

Choose a reason for hiding this comment

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

This seems strictly worse in terms of names

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I updated it to be more readable, idk what else id name it since that's as informative as it gets

@optimumtact
Copy link
Member

welcome back, i'm excited to see this in the game.

/datum/day_night_controller/proc/update_time(hour)
if(color_lookup_table["[hour ? hour - 1 : 24]"] == color_lookup_table["[hour]"] && alpha_lookup_table["[hour ? hour - 1 : 24]"] == alpha_lookup_table["[hour]"]) // Why change the color of the light when it's the same as the last?????
return
update_lighting(color_lookup_table["[hour]"], alpha_lookup_table["[hour]"])
Copy link

Choose a reason for hiding this comment

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

please add an animation transition to this i beg of you, in all honesty it should have a transition played from here to the next hour if performance allows, would let this look far smoother

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I might try to do this at some point, but that's a lot of stress for little gain, since the changes aren't that often

@Gandalf2k15
Copy link
Contributor Author

I'll just repeat what I said on #68239,

I'm not sure if it's still the same way in your videos as in code, but the red you use for sunset is kind of dirty-looking. Maybe you could change that to something pinker or more orange?
image
image
image

if you supply me with the color values, see the light zones for reference

@github-actions github-actions bot added the Merge Conflict Adding upstream files to your repo via drag and drop won't resolve conflicts label May 4, 2023
@github-actions
Copy link
Contributor

This PR has been inactive for long enough to be automatically marked as stale. This means it is at risk of being auto closed in ~ 7 days, please address any outstanding review items and ensure your PR is finished, if these are all true and you are auto-staled anyway, you need to actively ask maintainers if your PR will be merged. Once you have done any of the previous actions then you should request a maintainer remove the stale label on your PR, to reset the stale timer. If you feel no maintainer will respond in that time, you may wish to close this PR youself, while you seek maintainer comment, as you will then be able to reopen the PR yourself

@github-actions github-actions bot added the Stale Even the uncaring universe rejects you, why even go on label May 12, 2023
@Rex9001
Copy link
Contributor

Rex9001 commented May 14, 2023

A bit late to this, but this is such a good addition to the game. Very very excited to see the this project at its conclusion

@github-actions github-actions bot removed the Stale Even the uncaring universe rejects you, why even go on label May 15, 2023
@github-actions
Copy link
Contributor

This PR has been inactive for long enough to be automatically marked as stale. This means it is at risk of being auto closed in ~ 7 days, please address any outstanding review items and ensure your PR is finished, if these are all true and you are auto-staled anyway, you need to actively ask maintainers if your PR will be merged. Once you have done any of the previous actions then you should request a maintainer remove the stale label on your PR, to reset the stale timer. If you feel no maintainer will respond in that time, you may wish to close this PR youself, while you seek maintainer comment, as you will then be able to reopen the PR yourself

@github-actions github-actions bot added the Stale Even the uncaring universe rejects you, why even go on label May 23, 2023
@optimumtact
Copy link
Member

@Gandalf2k15 are you able to fix conflicts?

@LemonInTheDark can we merge this as is?

@LemonInTheDark
Copy link
Member

I am concerned about the overhead of initialize_day_night_adjacent_turfs, and I'm also a bit worried about how space turfs work interacting poorly with the use of lighting objects here, tho I realize that's a rare case.
Also #74948 (comment) I really want to know how hot that is, cause it's a good bit of work and if it's once per turf in large areas that's an issue.

I don't think? I have any issues outside of that

@github-actions github-actions bot removed the Stale Even the uncaring universe rejects you, why even go on label May 24, 2023
@github-actions
Copy link
Contributor

This PR has been inactive for long enough to be automatically marked as stale. This means it is at risk of being auto closed in ~ 7 days, please address any outstanding review items and ensure your PR is finished, if these are all true and you are auto-staled anyway, you need to actively ask maintainers if your PR will be merged. Once you have done any of the previous actions then you should request a maintainer remove the stale label on your PR, to reset the stale timer. If you feel no maintainer will respond in that time, you may wish to close this PR youself, while you seek maintainer comment, as you will then be able to reopen the PR yourself

@github-actions github-actions bot added the Stale Even the uncaring universe rejects you, why even go on label May 31, 2023
@github-actions github-actions bot closed this Jun 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Balance Changes to functionality that modifies how effective certain methods are at powergaming Feature Exposes new bugs in interesting ways Map Edit Thank you for your tile-placing service. It's always appreciated. Merge Conflict Adding upstream files to your repo via drag and drop won't resolve conflicts Refactor Makes the code harder to read Sprites A bikeshed full of soulless bikes. Stale Even the uncaring universe rejects you, why even go on
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants