Add NilorUserInput_Seed with sentinel-based randomization, modulo normalization for invalid values, cache-busting via IS_CHANGED, and isolated RNG state to avoid global random pollution.
192 lines
5.3 KiB
Python
192 lines
5.3 KiB
Python
category = "Nilor Nodes 👺"
|
|
subcategories = {
|
|
"io": "/IO",
|
|
}
|
|
|
|
import random
|
|
from datetime import datetime
|
|
|
|
from .controllers import CONTROLLER_HOOK
|
|
|
|
|
|
class NilorUserInput_String:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"input_name": (
|
|
"STRING",
|
|
{"default": "my_string_input", "multiline": False},
|
|
),
|
|
"value": ("STRING", {"default": "", "multiline": True}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("STRING", CONTROLLER_HOOK)
|
|
RETURN_NAMES = ("string", "_controller_hook")
|
|
FUNCTION = "get_value"
|
|
CATEGORY = category + subcategories["io"]
|
|
|
|
def get_value(self, input_name, value):
|
|
return (value, None)
|
|
|
|
|
|
class NilorUserInput_Int:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"input_name": (
|
|
"STRING",
|
|
{"default": "my_int_input", "multiline": False},
|
|
),
|
|
"value": ("INT", {"default": 0}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("INT", CONTROLLER_HOOK)
|
|
RETURN_NAMES = ("int", "_controller_hook")
|
|
FUNCTION = "get_value"
|
|
CATEGORY = category + subcategories["io"]
|
|
|
|
def get_value(self, input_name, value):
|
|
return (value, None)
|
|
|
|
|
|
class NilorUserInput_Seed:
|
|
MAX_COMFYUI_SEED = 1125899906842624
|
|
SEED_RANDOM_STATE = None
|
|
|
|
@classmethod
|
|
def _ensure_seed_random_state(cls):
|
|
if cls.SEED_RANDOM_STATE is not None:
|
|
return
|
|
|
|
initial_random_state = random.getstate()
|
|
random.seed(datetime.now().timestamp())
|
|
cls.SEED_RANDOM_STATE = random.getstate()
|
|
random.setstate(initial_random_state)
|
|
|
|
@classmethod
|
|
def generate_random_seed(cls):
|
|
cls._ensure_seed_random_state()
|
|
|
|
prev_random_state = random.getstate()
|
|
random.setstate(cls.SEED_RANDOM_STATE)
|
|
seed = random.randint(0, cls.MAX_COMFYUI_SEED)
|
|
cls.SEED_RANDOM_STATE = random.getstate()
|
|
random.setstate(prev_random_state)
|
|
return seed
|
|
|
|
@classmethod
|
|
def resolve_seed(cls, value):
|
|
if value in (None, 0, -1):
|
|
return cls.generate_random_seed()
|
|
try:
|
|
return int(value) % (cls.MAX_COMFYUI_SEED + 1)
|
|
except (TypeError, ValueError):
|
|
return cls.generate_random_seed()
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"input_name": (
|
|
"STRING",
|
|
{"default": "my_seed_input", "multiline": False},
|
|
),
|
|
"value": (
|
|
"INT",
|
|
{
|
|
"default": -1,
|
|
"min": -1,
|
|
"max": cls.MAX_COMFYUI_SEED,
|
|
},
|
|
),
|
|
},
|
|
"hidden": {
|
|
"prompt": "PROMPT",
|
|
"extra_pnginfo": "EXTRA_PNGINFO",
|
|
"unique_id": "UNIQUE_ID",
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("INT", CONTROLLER_HOOK)
|
|
RETURN_NAMES = ("seed", "_controller_hook")
|
|
FUNCTION = "get_value"
|
|
CATEGORY = category + subcategories["io"]
|
|
|
|
@classmethod
|
|
def IS_CHANGED(
|
|
cls, input_name, value, prompt=None, extra_pnginfo=None, unique_id=None
|
|
):
|
|
# Force node re-execution while using randomize sentinel values.
|
|
return cls.resolve_seed(value)
|
|
|
|
def get_value(
|
|
self, input_name, value, prompt=None, extra_pnginfo=None, unique_id=None
|
|
):
|
|
value = self.resolve_seed(value)
|
|
return (value, None)
|
|
|
|
|
|
class NilorUserInput_Float:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"input_name": (
|
|
"STRING",
|
|
{"default": "my_float_input", "multiline": False},
|
|
),
|
|
"value": ("FLOAT", {"default": 0.0, "step": 0.001}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("FLOAT", CONTROLLER_HOOK)
|
|
RETURN_NAMES = ("float", "_controller_hook")
|
|
FUNCTION = "get_value"
|
|
CATEGORY = category + subcategories["io"]
|
|
|
|
def get_value(self, input_name, value):
|
|
return (value, None)
|
|
|
|
|
|
class NilorUserInput_Boolean:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"input_name": (
|
|
"STRING",
|
|
{"default": "my_bool_input", "multiline": False},
|
|
),
|
|
"value": ("BOOLEAN", {"default": False}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("BOOLEAN", CONTROLLER_HOOK)
|
|
RETURN_NAMES = ("boolean", "_controller_hook")
|
|
FUNCTION = "get_value"
|
|
CATEGORY = category + subcategories["io"]
|
|
|
|
def get_value(self, input_name, value):
|
|
return (value, None)
|
|
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
"NilorUserInput_String": NilorUserInput_String,
|
|
"NilorUserInput_Int": NilorUserInput_Int,
|
|
"NilorUserInput_Seed": NilorUserInput_Seed,
|
|
"NilorUserInput_Float": NilorUserInput_Float,
|
|
"NilorUserInput_Boolean": NilorUserInput_Boolean,
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"NilorUserInput_String": "👺 User Input (String)",
|
|
"NilorUserInput_Int": "👺 User Input (Int)",
|
|
"NilorUserInput_Seed": "👺 User Input (Seed)",
|
|
"NilorUserInput_Float": "👺 User Input (Float)",
|
|
"NilorUserInput_Boolean": "👺 User Input (Boolean)",
|
|
}
|