Skip to content

Commit

Permalink
[Lag-b-gone] Offloads physics calculations to C++ (BeeStation#1099)
Browse files Browse the repository at this point in the history
* Doesn't work :(

* It works

* Exmap revision 1.0

* Overmaps will no longer struggle to delete

* Maybe this'll make it better....

* Well that didn't work

* :(

* foo
  • Loading branch information
Kmc2000 authored Dec 4, 2020
1 parent 9fac2c0 commit 7f2a182
Show file tree
Hide file tree
Showing 16 changed files with 142 additions and 72 deletions.
Binary file modified byond-extools.dll
Binary file not shown.
Binary file modified byond-extools.pdb
Binary file not shown.
3 changes: 2 additions & 1 deletion code/__DEFINES/cinematics.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
#define CINEMATIC_NUKE_NO_CORE 10
#define CINEMATIC_NUKE_FAR 11
#define CINEMATIC_NUKE_CLOWNOP 12
#define CINEMATIC_CULT_NUKE 13
#define CINEMATIC_CULT_NUKE 13
#define CINEMATIC_NSV_SHIP_KABOOM 14 //Nsv13...duh
4 changes: 2 additions & 2 deletions code/__DEFINES/subsystems.dm
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,9 @@
#define FIRE_PRIORITY_TGUI 110
#define FIRE_PRIORITY_TICKER 200
#define FIRE_PRIORITY_ATMOS_ADJACENCY 300
#define FIRE_PRIORITY_PROJECTILES 300 //Nsv13 - Lower priority: Projectile movement and processing
#define FIRE_PRIORITY_PHYSICS 350 //NSV13 - Highest priority: Overmap movement and hitbox calc
#define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_PROJECTILES 440 //Nsv13 - Lower priority: Projectile movement and processing
#define FIRE_PRIORITY_PHYSICS 450 //NSV13 - Highest priority: Overmap movement and hitbox calc
#define FIRE_PRIORITY_OVERLAYS 500
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.

Expand Down
3 changes: 2 additions & 1 deletion code/__HELPERS/names.dm
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ GLOBAL_VAR(command_name)
/proc/set_station_name(newname)
GLOB.station_name = newname
var/obj/structure/overmap/OM = SSstar_system.find_main_overmap()
OM.name = GLOB.station_name
if(OM)
OM.name = GLOB.station_name

var/config_server_name = CONFIG_GET(string/servername)
if(config_server_name)
Expand Down
9 changes: 5 additions & 4 deletions nsv13/code/modules/collision/collision_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Helper methods for collision detection, implementing things like the separating
Special thanks to qwertyquerty for explaining and dictating all this! (I've mostly translated his pseudocode into readable byond code)
*/

/*
/proc/is_separating_axis(datum/vector2d/a_pos, datum/vector2d/b_pos, list/datum/vector2d/a_points, list/datum/vector2d/b_points, datum/vector2d/axis, datum/collision_response/c_response)
var/datum/vector2d/offset_v = b_pos - a_pos
Expand Down Expand Up @@ -65,8 +65,9 @@ Special thanks to qwertyquerty for explaining and dictating all this! (I've most
maxpoint = dot
return new /datum/vector2d(minpoint, maxpoint)

/proc/get_seg_intersection(datum/vector2d/p0, datum/vector2d/p1, datum/vector2d/p2, datum/vector2d/p3)
*/
/*
/datum/shape/get_seg_intersection(datum/vector2d/p0, datum/vector2d/p1, datum/vector2d/p2, datum/vector2d/p3)
var/datum/vector2d/s10 = p1 - p0
var/datum/vector2d/s32 = p3 - p2
Expand Down Expand Up @@ -95,4 +96,4 @@ Special thanks to qwertyquerty for explaining and dictating all this! (I've most
var/t = t_numer / denom
return new /datum/vector2d(p0.x + (t * s10.x), p0.y + (t * s10.y))

*/
65 changes: 55 additions & 10 deletions nsv13/code/modules/collision/shape.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ COLLISIONS MAY OR MAY NOT END UP BACKWARDS. CHECK THIS LATER.
Special thanks to qwertyquerty for explaining and dictating all this! (I've mostly translated his pseudocode into readable byond code)
*/
GLOBAL_VAR(exmap_initialized) // this must be an uninitialized (null) one or init_monstermos will be called twice because reasons
#define EXMAP_EXTOOLS_CHECK if(!GLOB.exmap_initialized){\
GLOB.exmap_initialized=TRUE;\
if(fexists(EXTOOLS)){\
var/result = call(EXTOOLS,"init_exmap")();\
if(result != "ok") {CRASH(result);}\
} else {\
CRASH("byond-extools.dll or libbyond-extools.so does not exist!");\
}\
}

/datum/shape
var/datum/vector2d/position = null //Vector to represent our position in the game world. This is updated by whatever's moving us with pixelmovement.
Expand All @@ -18,6 +28,19 @@ Special thanks to qwertyquerty for explaining and dictating all this! (I've most
var/list/datum/vector2d/normals = list()
var/list/aabb = list() //Cached points from AABB collision

//All stuff that happens in C++ land must be declared here and wrapped later.

/datum/shape/proc/__test_aabb(list/v1, list/v2, list/aabb, list/other_aabb)
/datum/shape/proc/test_aabb(datum/shape/other)
/datum/shape/proc/__foo()
/datum/shape/proc/__get_seg_intersection(datum/vector2d/p0, datum/vector2d/p1, datum/vector2d/p2, datum/vector2d/p3)
/datum/shape/proc/get_seg_intersection()
/datum/shape/proc/__is_separating_axis(a_pos_x, a_pos_y, b_pos_x, b_pos_y, range_a_x, range_a_y, range_b_x, range_b_y, axis_x, axis_y)
/datum/shape/proc/is_separating_axis()
/datum/shape/proc/__flatten_points_on(list/points, normal_x, normal_y, point_count)
/datum/shape/proc/flatten_points_on()


//Constructor for shape objects, taking in parameters they may initially need

/datum/shape/New(datum/vector2d/position, list/points, _angle=0)
Expand All @@ -27,6 +50,7 @@ Special thanks to qwertyquerty for explaining and dictating all this! (I've most
src.position = position
src._angle = _angle
set_points(points)
EXMAP_EXTOOLS_CHECK

/*
Method to set our position to a new one.
Expand Down Expand Up @@ -101,12 +125,9 @@ Method to recalculate our bounding box, adjusting the relative positions accordi
/**
Simple method to calculate whether we collide with another shape object, lightweight but not hugely precise.
*/
/datum/shape/proc/test_aabb(var/datum/shape/other)
return ((src.aabb[1] + src.position.x) <= (other.aabb[3] + other.position.x)) && \
((src.aabb[2] + src.position.y) <= (other.aabb[4] + other.position.y)) && \
((src.aabb[3] + src.position.x) >= (other.aabb[1] + other.position.x)) && \
((src.aabb[4] + src.position.y) >= (other.aabb[2] + other.position.y))

/datum/shape/test_aabb(datum/shape/other)
var/out = __test_aabb(list(position.x, position.y), list(other.position.x, other.position.y), src.aabb, other.aabb)
return out

/datum/shape/proc/get_global_points()
var/list/datum/vector2d/global_points = list()
Expand All @@ -132,7 +153,6 @@ to say that we don't need the added cost (and extra precision) of SAT.
for (var/datum/vector2d/norm in other.normals)
if(is_separating_axis(src.position, other.position, src.rel_points, other.rel_points, norm, c_response))
return FALSE

if (c_response)
c_response.overlap_vector.copy(c_response.overlap_normal)
c_response.overlap_vector *= c_response.overlap
Expand Down Expand Up @@ -172,6 +192,31 @@ Find the average collision point between two shapes. Usually ends up being prett

return closest_point




/datum/shape/get_seg_intersection(datum/vector2d/p0, datum/vector2d/p1, datum/vector2d/p2, datum/vector2d/p3)
var/list/out = __get_seg_intersection(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x,p3.y)
return out ? new /datum/vector2d(out[1], out[2]) : FALSE

/datum/shape/flatten_points_on(list/points, datum/vector2d/normal)
RETURN_TYPE(/datum/vector2d)
var/list/_points = list()
for(var/datum/vector2d/point in points)
_points += point.x
_points += point.y
var/out = __flatten_points_on(_points, normal.x, normal.y, points.len*2)
//message_admins("Contents of [out]:")
//message_admins("Flattened points: [out[1]], [out[2]]")
return new /datum/vector2d(out[1], out[2])

/datum/shape/is_separating_axis(datum/vector2d/a_pos, datum/vector2d/b_pos, list/datum/vector2d/a_points, list/datum/vector2d/b_points, datum/vector2d/axis, datum/collision_response/c_response)
var/datum/vector2d/range_a = flatten_points_on(a_points, axis)
var/datum/vector2d/range_b = flatten_points_on(b_points, axis)
var/out = __is_separating_axis(a_pos.x, a_pos.y, b_pos.x, b_pos.y, range_a.x, range_a.y,range_b.x, range_b.y , axis.x, axis.y)
if(islist(out) && c_response)
c_response.a_in_b = out[1]
c_response.b_in_a = out[2]
c_response.overlap = out[3]
c_response.overlap_normal._set(out[4][1], out[4][2])
c_response.overlap_vector._set(out[5][1], out[5][2])
c_response.overlap_point._set(out[6][1], out[6][2])
return FALSE
return TRUE
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@
/obj/item/projectile/guided_munition/torpedo/post/Destroy()
if(contents.len)
var/list/all_contents = GetAllContents() - src //Get all contents returns the torp itself. remove the torp from the list
QDEL_LIST(all_contents) //Delete all contents of the torp.
QDEL_LIST(all_contents) //Delete all contents of the torp.
. = ..()

//A probe that science builds to scan anomalies. This is a chad move.
Expand Down
89 changes: 50 additions & 39 deletions nsv13/code/modules/overmap/ai_interiors.dm
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,64 @@
find_area()
return TRUE

/obj/structure/overmap/Destroy()
STOP_PROCESSING(SSphysics_processing, src)
GLOB.overmap_objects -= src
relay('nsv13/sound/effects/ship/damage/ship_explode.ogg')
animate(src, alpha = 0,time = 20) //Ship fades to black
/obj/effect/temp_visual/fading_overmap
name = "Foo"
duration = 3 SECONDS
mouse_opacity = FALSE

/obj/effect/temp_visual/fading_overmap/Initialize(mapload, name, icon, icon_state)
. = ..()
src.name = name
src.icon = icon
src.icon_state = icon_state
play()

/obj/effect/temp_visual/fading_overmap/proc/play()
set waitfor = FALSE
SpinAnimation(500, 1)
animate(src, alpha = 0,time = 30) //Ship fades to black
if(prob(50))
new /obj/effect/temp_visual/overmap_explosion(get_turf(src)) //Draw an explosion. Picks between two types.
else
new /obj/effect/temp_visual/overmap_explosion/alt(get_turf(src))
sleep(20)


/datum/cinematic/nsv_kaboom
id = CINEMATIC_NSV_SHIP_KABOOM

/datum/cinematic/nsv_kaboom/content()
screen.icon = 'nsv13/icons/effects/station_explosion.dmi'
flick("ship_go_byebye",screen)
sleep(3.5 SECONDS)
screen.icon_state = "summary"
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special()


/obj/structure/overmap/Destroy()
STOP_PROCESSING(SSphysics_processing, src)
GLOB.overmap_objects -= src
relay('nsv13/sound/effects/ship/damage/ship_explode.ogg')
relay_to_nearby('nsv13/sound/effects/ship/damage/disable.ogg') //Kaboom.
new /obj/effect/temp_visual/fading_overmap(get_turf(src), name, icon, icon_state)
for(var/obj/structure/overmap/OM in enemies) //If target's in enemies, return
var/sound = pick('nsv13/sound/effects/computer/alarm.ogg','nsv13/sound/effects/computer/alarm_2.ogg')
var/message = "<span class='warning'>ATTENTION: [src]'s reactor is going supercritical. Destruction imminent.</span>"
OM?.tactical?.relay_sound(sound, message)
OM.enemies -= src //Stops AI from spamming ships that are already dead
overmap_explode(linked_areas)
if(role == MAIN_OVERMAP)
priority_announce("WARNING: ([rand(10,100)]) Attempts to establish DRADIS uplink with [station_name()] have failed. Unable to ascertain operational status. Presumed status: TERMINATED","Central Intelligence Unit", 'nsv13/sound/effects/ship/reactor/explode.ogg')
for(var/X in GLOB.teleportlocs) //Time to kill everyone
var/area/target = GLOB.teleportlocs[X]
var/turf/T = pick(get_area_turfs(target))
explosion(T,20,20,20)
else
if(linked_areas && linked_areas.len)
for(var/area/X in linked_areas)
var/turf/T = pick(get_area_turfs(X))
explosion(T,20,20,20)
Cinematic(CINEMATIC_NSV_SHIP_KABOOM,world)
SSticker.mode.check_finished(TRUE)
SSticker.force_ending = 1
. = ..()

/proc/overmap_explode(list/areas)
for(var/area/AR in areas)
var/turf/T = pick(get_area_turfs(AR))
explosion(T,30,30,30)

/obj/structure/overmap/proc/decimate_area()
if(!linked_areas.len)
return TRUE
Expand All @@ -83,30 +118,6 @@
qdel(linked_area)
return TRUE
return FALSE

/obj/structure/overmap/proc/explode()
if(decimate_area()) //Decimate area returns true after every atom in X area has been destroyed
interior_spawn?.used = FALSE
qdel(src)

/obj/structure/overmap/obj_destruction(damage_flag) //When integrity reaches 0, ships will take a few minutes to despawn. This allows for the players to select them for boarding.
if(!wrecked)
wrecked = TRUE
ai_controlled = FALSE
addtimer(CALLBACK(src, .proc/explode), 2 MINUTES) //Countdown to explosion. The only thing that can save us now is another ship attempting to dock.
relay_to_nearby('nsv13/sound/effects/ship/damage/disable.ogg') //Kaboom.
for(var/obj/structure/overmap/OM in enemies) //If target's in enemies, return
var/sound = pick('nsv13/sound/effects/computer/alarm.ogg','nsv13/sound/effects/computer/alarm_2.ogg')
var/message = "<span class='warning'>ATTENTION: [src]'s reactor is going supercritical. Destruction imminent.</span>"
OM?.tactical?.relay_sound(sound, message)
OM.enemies -= src //Stops AI from spamming ships that are already dead
obj_integrity = max_integrity/3 //You have to REALLY want them dead to blow up a wreck.
STOP_PROCESSING(SSfastprocess,src)
SpinAnimation(1000,10)
else //OK, they've shot us again as we're despawning, that means they don't want to loot us.
. = ..()


/obj/structure/closet/supplypod/syndicate_odst
name = "Syndicate drop pod"
desc = "A large pod which is used to launch syndicate drop troopers at enemy vessels. It's rare to see one of these and survive the encounter."
Expand Down
12 changes: 12 additions & 0 deletions nsv13/code/modules/overmap/armour/armour_quadrant.dm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@
if(270 to 360) //Then this represents the last quadrant of the circle, the northwest one
return ARMOUR_FORWARD_STARBOARD

/obj/structure/overmap/proc/projectile_quadrant_impact(obj/item/projectile/P)
var/shield_angle_hit = SIMPLIFY_DEGREES(Get_Angle(P, src) - angle)
switch(shield_angle_hit)
if(0 to 89) //0 - 90 deg is the first right quarter of the circle, it's like dividing up a pizza!
return ARMOUR_FORWARD_PORT
if(90 to 179)
return ARMOUR_AFT_PORT
if(180 to 269)
return ARMOUR_AFT_STARBOARD
if(270 to 360) //Then this represents the last quadrant of the circle, the northwest one
return ARMOUR_FORWARD_STARBOARD

/* UNUSED
/obj/screen/alert/overmap_integrity
name = "Ship integrity"
Expand Down
2 changes: 1 addition & 1 deletion nsv13/code/modules/overmap/components.dm
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ GLOBAL_LIST_INIT(computer_beeps, list('nsv13/sound/effects/computer/beep.ogg','n
qdel(current_beam)
current_beam = null
radio.talk_into(src, "Salvage armatures retracted. Aborting salvage operations.", radio_channel)
salvage_target.explode() //Ship loses stability. It's literally just us that's holding it together.
// salvage_target.explode() //Ship loses stability. It's literally just us that's holding it together.
UnregisterSignal(linked, COMSIG_MOVABLE_MOVED, .proc/update_salvage_target)
salvage_target = null

Expand Down
12 changes: 6 additions & 6 deletions nsv13/code/modules/overmap/fighters/fighters2.dm
Original file line number Diff line number Diff line change
Expand Up @@ -858,8 +858,8 @@ due_to_damage: If the removal was caused voluntarily (FALSE), or if it was cause
icon_state = "armour"
slot = HARDPOINT_SLOT_ARMOUR
weight = 1
obj_integrity = 150
max_integrity = 150
obj_integrity = 250
max_integrity = 250
armor = list("melee" = 50, "bullet" = 40, "laser" = 80, "energy" = 50, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 80) //Armour's pretty tough.

//Sometimes you need to repair your physical armour plates.
Expand All @@ -879,16 +879,16 @@ due_to_damage: If the removal was caused voluntarily (FALSE), or if it was cause
desc = "An extremely thick and heavy set of armour plates. Guaranteed to weigh you down, but it'll keep you flying through brasil itself."
tier = 2
weight = 2
obj_integrity = 350
max_integrity = 350
obj_integrity = 450
max_integrity = 450

/obj/item/fighter_component/armour_plating/tier3
name = "Nanocarbon Armour Plates"
desc = "A lightweight set of ablative armour which balances speed and protection at the cost of the average GDP of most third world countries."
tier = 3
weight = 1.25
obj_integrity = 250
max_integrity = 250
obj_integrity = 300
max_integrity = 300

/obj/item/fighter_component/canopy
name = "Glass canopy"
Expand Down
2 changes: 1 addition & 1 deletion nsv13/code/modules/overmap/overmap.dm
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
var/flak_battery_amount = 1

var/role = NORMAL_OVERMAP

var/list/missions = list()

/**
Expand Down
7 changes: 3 additions & 4 deletions nsv13/code/modules/overmap/physics2d.dm
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#define MAXIMUM_COLLISION_RANGE 30 //In tiles, what is the range of the maximum possible collision that could take place? Please try and keep this low, as it saves a lot of time and memory because it'll just ignore physics bodies that are too far away from each other.
#define MAXIMUM_COLLISION_RANGE 12 //In tiles, what is the range of the maximum possible collision that could take place? Please try and keep this low, as it saves a lot of time and memory because it'll just ignore physics bodies that are too far away from each other.
//That being said. If you want to make a ship that is bigger than this in tile size, then you will have to change this number. As of 11/08/2020 the LARGEST possible collision range is 25 tiles, due to the fist of sol existing. Though tbh if you make a sprite much larger than this, byond will likely just cull it from the viewport.

PROCESSING_SUBSYSTEM_DEF(physics_processing)
name = "Physics Processing"
wait = 1.5
stat_tag = "PHYS"
priority = FIRE_PRIORITY_PHYSICS
var/list/physics_bodies = list() //All the physics bodies in the world.
var/list/physics_levels = list()
var/next_boarding_time = 0 //This is stupid and lazy but it's 5am and I don't care anymore
var/datum/collision_response/c_response = new /datum/collision_response()

/datum/controller/subsystem/processing/physics_processing/fire(resumed)
. = ..()
//This is O(n), but it could be worse, far worse.
for(var/I in physics_levels)
var/list/za_warudo = physics_levels[I]
for(var/datum/component/physics2d/body in za_warudo)
Expand Down Expand Up @@ -46,7 +46,6 @@ PROCESSING_SUBSYSTEM_DEF(physics_processing)
continue
//OK, now we get into the expensive calculation. This is our absolute last resort because it's REALLY expensive.
if(isovermap(body.holder) && isovermap(neighbour.holder)) //Dirty, but necessary. I want to minimize in-depth collision calc wherever I possibly can, so only overmap prototypes use it.
var/datum/collision_response/c_response = new /datum/collision_response()
if(body.collider2d?.collides(neighbour.collider2d, c_response))
body.holder.Bump(neighbour.holder, c_response) //More in depth calculation required, so pass this information on.
recent_collisions += neighbour
Expand Down
4 changes: 2 additions & 2 deletions nsv13/code/modules/overmap/weapons/damage.dm
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ Bullet reactions
playsound(src, P.hitsound, 50, 1)
visible_message("<span class='danger'>[src] is hit by \a [P]!</span>", null, null, COMBAT_MESSAGE_RANGE)
if(!QDELETED(src)) //Bullet on_hit effect might have already destroyed this object
var/datum/vector2d/point_of_collision = src.physics2d?.collider2d.get_collision_point(P.physics2d?.collider2d)//Get the collision point, see if the armour quadrants need to absorb this hit.
take_quadrant_hit(run_obj_armor(P.damage, P.damage_type, P.flag, null, P.armour_penetration), check_quadrant(point_of_collision)) //This looks horrible, but trust me, it isn't! Probably!. Armour_quadrant.dm for more info
//var/datum/vector2d/point_of_collision = src.physics2d?.collider2d.get_collision_point(P.physics2d?.collider2d)//Get the collision point, see if the armour quadrants need to absorb this hit.
take_quadrant_hit(run_obj_armor(P.damage, P.damage_type, P.flag, null, P.armour_penetration), projectile_quadrant_impact(P)) //This looks horrible, but trust me, it isn't! Probably!. Armour_quadrant.dm for more info

/obj/structure/overmap/proc/relay_damage(proj_type)
if(!occupying_levels.len)
Expand Down
Binary file added nsv13/icons/effects/station_explosion.dmi
Binary file not shown.

0 comments on commit 7f2a182

Please sign in to comment.