{"id":"ernisto/rng","name":"rng","scope":"ernisto","platform":"roblox","description":"Mirrored from the Wally registry.","version":"1.0.0-rc.7","latest":"1.0.0-rc.7","versions":["0.3.0-alpha","1.0.0-rc.1","1.0.0-rc.2","1.0.0-rc.3","1.0.0-rc.7"],"license":"MIT","licenseRating":"safe","licenseCaveats":["License identified from the packaged LICENSE file; the manifest declared none."],"licenseVerified":true,"dependencies":{},"integrity":"9b4d8a2fcd90dbde2d7af40001e295b254efd062a22dedbd4f44a13fb61190f5","likes":0,"downloads":0,"install":"forest install ernisto/rng","url":"https://forest.dev/p/roblox/ernisto/rng","files":"https://api.forest.dev/ai/package/roblox/ernisto/rng/files","readme":"# rng [![Release](https://github.com/ernisto/rng/actions/workflows/release.yml/badge.svg)](https://github.com/ernisto/rng/actions/workflows/release.yml)\n\nSimple, fast RNG utilities for Luau: numbers, booleans by probability, weighted choice, array helpers, vectors, and buffers.\n\n## Installation\n\n- Download (`rng.rbxm`) from [latest release](https://github.com/ernisto/rng/releases/latest)\n\n- Wally (`wally.toml`): add under `[dependencies]`\n```toml\nrng = \"ernisto/rng@1.0.0-rc.3\"\n```\n\n- Pesde in roblox (terminal):\n```sh\npesde add wally#ernisto/rng\n```\n\n- Pesde in luau (terminal):\n```sh\npesde add ernisto/rng\n```\n\n## Quick start\n\nRequire it from your `Packages` (adjust the path to match your setup):\n```lua\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\nlocal rng = require(ReplicatedStorage.Packages.rng)\n```\nYou can also use this module in pure luau environment 💪\n```lua\nlocal rng = require('@pkg/rng')\n```\n\n### Regular RNG usage\n```lua\nlocal function teleport(humanoid: Humanoid, cframe: CFrame)\n  humanoid.RootPart.CFrame = cframe * CFrame.new(rng.vector(10, 0, 10))\nend\n```\n\n```lua\nlocal function spin_skill()\n  return rng.key_from_weight {\n    fire = 5,\n    water = 5,\n    earth = 5,\n    lava = 3,\n    light = 1,\n    dark = 1,\n  }\nend\n```\n\n### Secure daily market\n```lua\nlocal RESET_INTERVAL = 1*24*60*60\nlocal function remaining_time_to_refresh()\n  return RESET_INTERVAL - os.time() % RESET_INTERVAL\nend\n\n-- rng.same_iter_order to keep iteration order the same for all servers\nlocal possible_items = rng.same_iter_order {\n  -- total weight  → 150 → (75 + 50 + 20 + 4 + 1)\n  apple = 75,  -- 75/150 → 50.0%\n  soup = 50,   -- 50/150 → 33.3%\n  sword = 20,  -- 20/150 → 13.3%\n  armor = 4,   --  4/150 →  2.6%\n  totem = 1,   --  1/150 →  0.6%\n}\n\n-- csprng are extremely hard to predict seeing outputs or brute forcing\nlocal csprng = rng.new_secure(\"possibly known seed\", HttpService:GetSecret(\"Salt\"))\n\n-- advance state as the same as another living servers\nfor i = 0, os.time() - RESET_INTERVAL, RESET_INTERVAL do\n  for i = 1, 3 do csprng.number() end\nend\n\n-- generate market\nwhile true do\n  local choosen_items = {}\n  for i = 1, 10 do\n    choosen_items[i] = csprng.key_by_weight(possible_items)\n  end\n  market.set_items(choosen_items)\n  task.wait(remaining_time_to_refresh())\nend\n```\n\n### Numbers\n```lua\nlocal x = rng.number()                 -- [0, 1]\nlocal y = rng.number(10)               -- [0, 10]\nlocal w = rng.step(10, 2)              -- [0, 2, 4, 6, 8, 10]\nlocal z = rng.range(5, 15)             -- [5, 15]\nlocal s = rng.range(0, 1, 0.25)        -- one of {0.00, 0.25, 0.50, 0.75, 1.00}\n```\n\n### Booleans by probability\n```lua\nif rng.truth(0.2) then\n  print(\"1/5 = 20% chance\")\nend\n\nif rng.skip(1/3) then return end  -- 2/3 chance to return\nprint(\"1/3 = 33% chance\")\n```\n\n### Vectors (Luau `vector` 3D type)\n```lua\nlocal v1 = rng.vector(100, 50, 100) -- x = [0, 100], y = [0, 50], z = [0, 100]\nlocal v2 = rng.vector_range(vector.create(-10, 0, -20), vector.create(10, 0, 20), vector.one*5)\n```\n\n### Arrays\n```lua\nlocal items = {\"a\", \"b\", \"c\", \"d\"}\nlocal pick = rng.value(items)   -- 'a' | 'b' | 'c' | 'd'\nlocal index = rng.key{ a = 'cavalo', b = 'chama' }    -- 'a' | 'b'\nrng.write_shuffle(items)        -- shuffles in place\n```\n\n### Buffers\n```lua\nlocal buf = rng.buffer(1024)           -- 1025 u32 values written starting at 0\n-- or reuse an existing buffer, starting at an offset\nlocal out = buffer.create(4096)\nrng.buffer(512, out, 128)\n```\n\n## API\n\n- `rng.new_secure(seed: string | any?): helper`\n  - Returns a **C**ryptographically **S**ecure **P**seudo **R**andom **N**umber **G**enerator based on ChaCha20\n\n- `rng.new(seed: string | any?): helper`\n  - Returns a **P**seudo **R**andom **N**umber **G**enerator based on Shoroshiro128\n\n- `rng.custom(generator: () -> 1..0): helper`\n  - Returns the this same lib, but using a given generator\n\n- `rng.rarest_keys(weights: { [K]: number }): { K }`\n  - Returns a array of keys ordered by weight\n\n- `rng.same_iter_order(weights: { [K]: number }): { [K]: number }`\n  - Returns the given weight map with a `__iter` metamethod, keeping the iteration\n    order of tables with similar weights. Changing lowest weights is more probably\n    to break the iteration order, since lower weights is located first on array \n\n- `helper.number(): number` — range \\[0, 1]\n- `helper.number(max: number): number` — range \\[0, max]\n- `helper.step(max: number, step: number): number` — one of { 0, step, 2*step, .., max }\n- `helper.range(min: number, max: number): number` — range \\[min, max]\n- `helper.range(min: number, max: number, step: number): number` — min + one of { 0, step, 2*step, ..., max }\n\n- `helper.int(max: int): int` — range \\[0, max]\n- `helper.int_range(min: int, max: int)` — range min + one of { 0, 1, 2, ..., max }\n- `helper.int_range(min: int, max: int, step: int)` — range min + one of { 0, step, 2*step, ..., max }\n\n- `helper.vector(): vector` — each component in \\[0, 1]\n- `helper.vector(max: number): vector` — each component in \\[0, max]\n- `helper.vector(x: number, y: number, z: number?): vector` — x = \\[0, x], y = \\[0, y], z = \\[0, z]\n- `helper.vector_range(min: vector, max: vector): vector` — component-wise \\[min, max]\n- `helper.vector_range(min: vector, max: vector, step: vector): vector` — component-wise stepped values\n\n- `helper.buffer(count: number, target?: buffer, offset?: number): buffer`\n  - Fills a buffer with random 32-bit unsigned integers; creates one if not provided.\n\n- `helper.truth(ratio: number): boolean`\n- `helper.pass(ratio: number): boolean`\n  - Returns true with probability `ratio` (e.g. 0.25 → 25% → 1/4).\n\n- `helper.skip(ratio: number): boolean`\n  - Returns false with probability `ratio` (e.g. 0.25 → 25% → 1/4).\n\n- `helper.key_by_weight(weights: { [K]: number }): K`\n  - Returns a key chosen by its weight (weights can be any positive decimal numbers).\n\n- `helper.write_shuffle<T>(mut_arr: { T }): { T }`\n  - In-place array shuffle. Returns the same array for convenience.\n\n- `helper.value<T>(arr: { T }): T`\n  - Random element from an array.\n\n- `helper.key<K>(arr: { [K]: _ }): K`\n  - Random key from an table.\n\n## Notes\n\n- See `test/randomness.spec.luau` for statistical sanity checks used during development.\n\n## License\n\nMIT\n","readmeTruncated":false}