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

Aneri byondapi-rs RNG experiment #2623

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,8 @@ config/dbconfig.txt

# Running OpenDream locally
tgstation.json

meowtonin*

# TODO: REMOVE BEFORE FULL MERGE!!! (this is so CI works)
!/libaneri.so
2 changes: 1 addition & 1 deletion .tgs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
version: 1
# The BYOND version to use (kept in sync with dependencies.sh by the "TGS Test Suite" CI job)
# Must be interpreted as a string, keep quoted
byond: "515.1637"
byond: "515.1641"
# Folders to create in "<instance_path>/Configuration/GameStaticFiles/"
static_files:
# Config directory should be static
Expand Down
Binary file added aneri.dll
Binary file not shown.
Binary file added aneri.pdb
Binary file not shown.
67 changes: 67 additions & 0 deletions code/__DEFINES/aneri.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef ANERI

//#define ANERI_OVERRIDE_PICK
#define ANERI_OVERRIDE_PICK_WEIGHT
//#define ANERI_OVERRIDE_SORT
#define ANERI_OVERRIDE_RAND

/* This comment bypasses grep checks */ /var/__aneri

/proc/__detect_aneri()
if(world.system_type == UNIX)
return __aneri = "libaneri"
else
return __aneri = "aneri"

#define ANERI (__aneri || __detect_aneri())
#define ANERI_CALL(name, args...) call_ext(ANERI, "byond:" + name + "_ffi")(args)

/proc/aneri_cleanup() return ANERI_CALL("cleanup")

//#define file2text(fname) aneri_file_read("[fname]")
//#define text2file(text, fname) aneri_file_append(text, "[fname]")

/proc/aneri_replace_chars_prob(input, replacement, probability = 25, skip_whitespace = FALSE)
return ANERI_CALL("replace_chars_prob", input, replacement, probability, skip_whitespace)

#if defined(ANERI_OVERRIDE_PICK) || defined(ANERI_OVERRIDE_PICK_WEIGHT)
#define pick_weight(list) ANERI_CALL("pick_weighted", list)
#endif

#ifdef ANERI_OVERRIDE_PICK
#define pick(list...) _apick(list)

/proc/_apick(...)
switch(length(args))
if(0)
CRASH("pick() called with no arguments")
if(1)
var/list/arg = args[1]
if(!islist(arg))
CRASH("pick() called with non-list argument")
return ANERI_CALL("pick", arg)
else
return ANERI_CALL("pick", args)
#endif

#ifdef ANERI_OVERRIDE_RAND
/proc/_arand(...)
switch(length(args))
if(0)
return ANERI_CALL("random_float")
if(1)
return ANERI_CALL("random_range_int_unsigned", 0, args[1])
if(2)
return ANERI_CALL("random_range_int_signed", args[1], args[2])
else
CRASH("arand() takes 0-2 arguments")

#define rand(args...) _arand(args)
#define prob(val) ANERI_CALL("prob", val)
#endif

/world/New()
aneri_cleanup()
..()

#endif
2 changes: 2 additions & 0 deletions code/__HELPERS/_lists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@
result = first ^ second
return result

#if !defined(ANERI_OVERRIDE_PICK) && !defined(ANERI_OVERRIDE_PICK_WEIGHT)
/**
* Picks a random element from a list based on a weighting system.
* For example, given the following list:
Expand All @@ -448,6 +449,7 @@
if(total <= 0)
return item
return null
#endif

/**
* Like pick_weight, but allowing for nested lists.
Expand Down
74 changes: 74 additions & 0 deletions code/modules/aneri/rng.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/datum/aneri
var/__aneri_key_low
var/__aneri_key_high

/datum/aneri/vv_edit_var(var_name, var_value)
if(var_name == NAMEOF(src, __aneri_key_low) || var_name == NAMEOF(src, __aneri_key_high))
return FALSE // DO. NOT. TOUCH.
return ..()


/// A (non-cryptographic) PRNG instance, using WyRand.
/datum/rng
parent_type = /datum/aneri
var/secure = FALSE

/datum/rng/New(seed = null)
var/err = ANERI_CALL("rng_new", src, secure, seed)
// returns null if everything was fine, else returns error info
if(err)
log_runtime("failed to initialize rng [err]")
CRASH("failed to initialize rng: [err]")

/datum/rng/Destroy()
if(!ANERI_CALL("rng_del", src))
log_runtime("attempted to delete nonexistent rng instance")
stack_trace("attempted to delete nonexistent rng instance")
return ..()

/datum/rng/proc/byte()
return ANERI_CALL("instanced_random_byte", src)

/datum/rng/proc/float()
return ANERI_CALL("instanced_random_float", src)

/datum/rng/proc/uint()
return ANERI_CALL("instanced_random_int_unsigned", src)

/datum/rng/proc/int()
return ANERI_CALL("instanced_random_int_signed", src)

/datum/rng/proc/ranged_uint(min = 0, max)
if(!isnum(min) || !isnum(max))
CRASH("invalid arguments to /datum/rng/proc/ranged_uint")
return ANERI_CALL("instanced_random_range_int_unsigned", src, min, max)

/datum/rng/proc/ranged_int(min = 0, max)
if(!isnum(min) || !isnum(max))
CRASH("invalid arguments to /datum/rng/proc/ranged_int")
return ANERI_CALL("instanced_random_range_int_signed", src, min, max)

/datum/rng/proc/pick_from(list/choices)
return ANERI_CALL("instanced_pick", src, choices)

/datum/rng/proc/pick_weighted(list/choices)
return ANERI_CALL("instanced_pick_weighted", src, choices)

/datum/rng/proc/chance(percent) // "prob" is a reserved word, so we do "chance" instead
return ANERI_CALL("instanced_prob", src, percent)

/datum/rng/proc/prob_ratio(numerator, denominator)
return ANERI_CALL("instanced_prob_ratio", src, numerator, denominator)

/datum/rng/proc/string(length = 16)
return ANERI_CALL("instanced_random_string_alphanumeric", src, length)

/datum/rng/proc/replace_chars_prob(input, replacement, probability = 25, skip_whitespace = FALSE)
return ANERI_CALL("instnaced_replace_chars_prob", src, input, replacement, probability, skip_whitespace)

/// A cryptographic PRNG instance, using Blake3.
/datum/rng/secure
secure = TRUE

/proc/byondapi_stack_trace(msg)
CRASH("[msg]")
2 changes: 1 addition & 1 deletion dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

# byond version
export BYOND_MAJOR=515
export BYOND_MINOR=1637
export BYOND_MINOR=1641

#rust_g git tag
export RUST_G_VERSION=3.1.0
Expand Down
Binary file added libaneri.so
Binary file not shown.
10 changes: 10 additions & 0 deletions monkestation/code/modules/events/_event.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/datum/round_event_control
var/managed = FALSE
var/oh_god = FALSE

/datum/round_event_control/proc/oh_shit_oh_fuck()
SIGNAL_HANDLER
if(managed)
oh_god = TRUE
stack_trace("ANERI DEBUG: [type] ([src]) is a managed event that's being deleted!!! this is bad!!!")
message_admins("ANERI DEBUG: [type] ([src]) is a managed event that's being deleted!!! this is bad!!! tell borbop and/or absolucy ASAP!!! tell borbop and/or absolucy ASAP!!!")
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@

while(length(possible_candidates) && length(candidates) < antag_count) //both of these pick_n_take from possible_candidates so this should be fine
if(prompted_picking)
var/client/picked_client = pick_n_take_weighted(weighted_candidates)
var/client/picked_client = SSgamemode.pick_n_take_weighted(weighted_candidates)
var/mob/picked_mob = picked_client.mob
log_storyteller("Prompted antag event mob: [picked_mob], special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]")
if(picked_mob)
Expand All @@ -244,7 +244,7 @@
role_name_text = lowertext(cast_control.name),
)
else
var/client/picked_client = pick_n_take_weighted(weighted_candidates)
var/client/picked_client = SSgamemode.pick_n_take_weighted(weighted_candidates)
var/mob/picked_mob = picked_client.mob
log_storyteller("Picked antag event mob: [picked_mob], special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]")
candidates |= picked_mob
Expand All @@ -254,7 +254,7 @@
message_admins("A roleset event got fewer antags then its antag_count and may not function correctly.")
break

var/mob/candidate = pick_n_take(candidates)
var/mob/candidate = SSgamemode.pick_n_take(candidates)
log_storyteller("Antag event spawned mob: [candidate], special role: [candidate.mind?.special_role ? candidate.mind.special_role : "none"]")

candidate.client?.prefs.reset_antag_rep()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@

/datum/round_event/antagonist/solo/bloodsucker/add_datum_to_mind(datum/mind/antag_mind)
var/datum/antagonist/bloodsucker/bloodsuckerdatum = antag_mind.make_bloodsucker()
bloodsuckerdatum.bloodsucker_level_unspent = rand(2,3)
bloodsuckerdatum.bloodsucker_level_unspent = SSgamemode.rng.ranged_int(2, 3)
34 changes: 30 additions & 4 deletions monkestation/code/modules/storytellers/gamemode_subsystem.dm
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,13 @@ SUBSYSTEM_DEF(gamemode)

var/total_valid_antags = 0

/// The RNG used for the storyteller/gamemode
var/datum/rng/rng

/datum/controller/subsystem/gamemode/Initialize(time, zlevel)
// Initialize RNG
rng = new

// Populate event pools
for(var/track in event_tracks)
event_pools[track] = list()
Expand All @@ -175,6 +181,8 @@ SUBSYSTEM_DEF(gamemode)
if(!event.valid_for_map())
qdel(event)
continue // event isn't good for this map no point in trying to add it to the list
event.managed = TRUE
RegisterSignal(event, COMSIG_QDELETING, TYPE_PROC_REF(/datum/round_event_control, oh_shit_oh_fuck))
control += event //add it to the list of all events (controls)
getHoliday()

Expand Down Expand Up @@ -362,7 +370,7 @@ SUBSYSTEM_DEF(gamemode)
var/calc_value = base_amt + (gain_amt * ready_players)
calc_value *= roundstart_point_multipliers[track]
calc_value *= storyteller.starting_point_multipliers[track]
calc_value *= (rand(100 - storyteller.roundstart_points_variance,100 + storyteller.roundstart_points_variance)/100)
calc_value *= (rng.ranged_uint(100 - storyteller.roundstart_points_variance, 100 + storyteller.roundstart_points_variance) / 100)
event_track_points[track] = round(calc_value)

/// If the storyteller guarantees an antagonist roll, add points to make it so.
Expand Down Expand Up @@ -717,7 +725,7 @@ SUBSYSTEM_DEF(gamemode)
var/list/possible = subtypesof(/datum/station_goal)
var/goal_weights = 0
while(possible.len && goal_weights < 1) // station goal budget is 1
var/datum/station_goal/picked = pick_n_take(possible)
var/datum/station_goal/picked = src.pick_n_take(possible)
goal_weights += initial(picked.weight)
GLOB.station_goals += new picked

Expand Down Expand Up @@ -799,7 +807,7 @@ SUBSYSTEM_DEF(gamemode)
/datum/controller/subsystem/gamemode/proc/handle_picking_stroyteller()
if(length(GLOB.clients) > MAX_POP_FOR_STORYTELLER_VOTE)
secret_storyteller = TRUE
selected_storyteller = pick_weight(get_valid_storytellers(TRUE))
selected_storyteller = rng.pick_weighted(get_valid_storytellers(TRUE))
return
SSvote.initiate_vote(/datum/vote/storyteller, "pick round storyteller", forced = TRUE)

Expand All @@ -815,7 +823,7 @@ SUBSYSTEM_DEF(gamemode)
var/added_storytellers = 0
while(added_storytellers < DEFAULT_STORYTELLER_VOTE_OPTIONS && length(pick_from))
added_storytellers++
var/picked_storyteller = pick_weight(pick_from)
var/picked_storyteller = rng.pick_weighted(pick_from)
final_choices[picked_storyteller] = 0
pick_from -= picked_storyteller
return final_choices
Expand Down Expand Up @@ -1207,5 +1215,23 @@ SUBSYSTEM_DEF(gamemode)
listed.occurrences++
listed.occurrences++

/// Pick a random element from the list and remove it from the list.
/// The same as the global proc, except it uses the SSgamemode rng.
/datum/controller/subsystem/gamemode/proc/pick_n_take_weighted(list/list_to_pick)
if(length(list_to_pick))
var/picked = rng.pick_weighted(list_to_pick)
list_to_pick -= picked
return picked

/// Pick a random element from the list and remove it from the list.
/// The same as the global proc, except it uses the SSgamemode rng.
/datum/controller/subsystem/gamemode/proc/pick_n_take(list/list_to_pick)
RETURN_TYPE(list_to_pick[_].type)
var/len = length(list_to_pick)
if(len)
var/picked = rng.ranged_uint(1, len)
. = list_to_pick[picked]
list_to_pick.Cut(picked, picked+1 )

#undef DEFAULT_STORYTELLER_VOTE_OPTIONS
#undef MAX_POP_FOR_STORYTELLER_VOTE
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
if(!round_started || disable_distribution) // we are differing roundstarted ones until base roundstart so we can get cooler stuff
return

if(!guarantees_roundstart_roleset && prob(roundstart_prob) && !roundstart_checks)
if(!guarantees_roundstart_roleset && SSgamemode.rng.chance(roundstart_prob) && !roundstart_checks)
roundstart_checks = TRUE

if(SSgamemode.current_roundstart_event && !SSgamemode.ran_roundstart && (guarantees_roundstart_roleset || roundstart_checks))
Expand Down Expand Up @@ -129,7 +129,7 @@
message_admins("Storyteller failed to pick an event for track of [track].")
mode.event_track_points[track] *= TRACK_FAIL_POINT_PENALTY_MULTIPLIER
return
picked_event = pick_weight(valid_events)
picked_event = SSgamemode.rng.pick_weighted(valid_events)
if(!picked_event)
if(length(valid_events))
var/added_string = ""
Expand All @@ -152,7 +152,7 @@
// Perhaps use some bell curve instead of a flat variance?
var/total_cost = bought_event.cost * mode.point_thresholds[track]
if(!bought_event.roundstart)
total_cost *= (1 + (rand(-cost_variance, cost_variance)/100)) //Apply cost variance if not roundstart event
total_cost *= (1 + (SSgamemode.rng.ranged_int(-cost_variance, cost_variance) / 100)) //Apply cost variance if not roundstart event
mode.event_track_points[track] = max(mode.event_track_points[track] - total_cost, 0)
message_admins("Storyteller purchased and triggered [bought_event] event, on [track] track, for [total_cost] cost.")
if(bought_event.roundstart)
Expand Down
3 changes: 3 additions & 0 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "code\__DEFINES\airlock.dm"
#include "code\__DEFINES\alarm.dm"
#include "code\__DEFINES\alerts.dm"
#include "code\__DEFINES\aneri.dm"
#include "code\__DEFINES\announcements.dm"
#include "code\__DEFINES\anomaly.dm"
#include "code\__DEFINES\antag_tokens.dm"
Expand Down Expand Up @@ -2667,6 +2668,7 @@
#include "code\modules\admin\view_variables\topic_basic.dm"
#include "code\modules\admin\view_variables\topic_list.dm"
#include "code\modules\admin\view_variables\view_variables.dm"
#include "code\modules\aneri\rng.dm"
#include "code\modules\antagonists\_common\antag_datum.dm"
#include "code\modules\antagonists\_common\antag_helpers.dm"
#include "code\modules\antagonists\_common\antag_hud.dm"
Expand Down Expand Up @@ -6702,6 +6704,7 @@
#include "monkestation\code\modules\donator\code\item\plush.dm"
#include "monkestation\code\modules\donator\code\mob\pets.dm"
#include "monkestation\code\modules\emotes\code\emote.dm"
#include "monkestation\code\modules\events\_event.dm"
#include "monkestation\code\modules\events\brand_intelligence.dm"
#include "monkestation\code\modules\events\gravity_generator_blackout.dm"
#include "monkestation\code\modules\events\radiation_storm.dm"
Expand Down
3 changes: 3 additions & 0 deletions tools/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ cp -r tgui/packages/tgfont/dist/* $1/tgui/packages/tgfont/dist/
if [ "$(uname -o)" = "Msys" ]; then
cp ./*.dll $1/
fi

# TODO: REMOVE BEFORE FULL MERGE!!! (this is so CI works)
cp ./libaneri.so $1/
Loading