OpenSimRegionConfig - Manfred Aabye - 31.08.2024
Anleitung zur Nutzung des Regionenkonfigurators
Hier ist eine Schritt-für-Schritt-Anleitung zur Verwendung des Python-Skripts, das eine GUI-Anwendung erstellt, um Regionskonfigurationen zu generieren.
### Voraussetzungen:
- **Python 3.x**: Stelle sicher, dass Python auf deinem System installiert ist.
- **Tkinter**: Tkinter ist normalerweise in Python vorinstalliert. Falls es fehlt, installiere es mit:
```bash
sudo apt-get install python3-tk
```
### 1. Überblick:
Dieses Skript erstellt eine grafische Benutzeroberfläche (GUI), mit der du verschiedene Einstellungen für Regionen vornehmen kannst, die anschließend in einer `.ini`-Konfigurationsdatei gespeichert werden. Jede Region hat verschiedene Parameter wie Größe, UUID, Position (Location) und viele andere, die du individuell konfigurieren kannst.
### 2. Skript ausführen:
1. **Python-Datei erstellen**: Erstelle eine Datei namens `region_config_app.py` und kopiere den bereitgestellten Python-Code in diese Datei.
2. **Skript starten**: Öffne ein Terminal oder eine Eingabeaufforderung und navigiere zu dem Verzeichnis, in dem sich die Datei befindet. Führe das Skript mit folgendem Befehl aus:
```bash
python region_config_app.py
```
3. **GUI-Anwendung**: Nach dem Ausführen öffnet sich ein Fenster mit der Benutzeroberfläche.
### 3. Verwendung der GUI:
1. **Felder ausfüllen**: Die Benutzeroberfläche zeigt verschiedene Felder an, in denen du die gewünschten Parameter für eine Region anpassen kannst.
- **Region Name**: Name der Region.
- **Region UUID**: Eindeutige Identifikationsnummer der Region.
- **Location**: Der Standort der Region (x, y), standardmäßig auf `1000,1000` gesetzt. Es wird automatisch angepasst, wenn du eine neue Region hinzufügst.
- **Size X, Y, Z**: Dimensionen der Region.
- **Internal Port**: Interner Netzwerkport.
- **External Host**: Externer Hostname.
- **Maptile UUID**: UUID für die Kartendatei, die die Region repräsentiert. Wird automatisch auf die Region UUID gesetzt.
- **Weitere Parameter**: Andere Einstellungen wie Maximalanzahl an Prims, Agenten, ScopeID usw.
2. **Region hinzufügen**: Klicke auf die Schaltfläche **"Add Region"**. Dadurch wird eine neue Region mit einer eigenen UUID und einem neuen Standort (basierend auf einer spiralförmigen Berechnung) erstellt.
3. **Konfiguration speichern**: Nachdem du die gewünschten Regionen hinzugefügt hast, klicke auf **"Save Config"**, um die Konfigurationen in einer `.ini`-Datei zu speichern. Wähle einen Speicherort und einen Dateinamen.
### 4. Ergebnis:
- Die erstellte `.ini`-Datei enthält Abschnitte für jede Region mit den von dir festgelegten Konfigurationen. Jede Region erhält eine eigene `Location`, `UUID` und andere Parameter.
### 5. Beispielhafte INI-Datei:
Die gespeicherte Datei könnte in etwa so aussehen:
```ini
PHP-Code: [TestRegion_1] RegionUUID = 123e4567-e89b-12d3-a456-426614174000 Location = 1000,1000 SizeX = 256 SizeY = 256 SizeZ = 256 InternalPort = 9050 ExternalHostName = SYSTEMIP MaxPrims = 100000 MaxAgents = 99 MaptileStaticUUID = 123e4567-e89b-12d3-a456-426614174000 ...
[TestRegion_2] RegionUUID = 223e4567-e89b-12d3-a456-426614174001 Location = 1001,1001 SizeX = 256 SizeY = 256 SizeZ = 256 InternalPort = 9051 ExternalHostName = SYSTEMIP MaxPrims = 100000 MaxAgents = 99 MaptileStaticUUID = 223e4567-e89b-12d3-a456-426614174001
...
```
### 6. Erweiterungen und Anpassungen:
Du kannst den Code anpassen, um zusätzliche Parameter hinzuzufügen oder die Art und Weise zu ändern, wie `Locations` berechnet werden.
### 7. Fehlerbehebung:
- **Tkinter nicht gefunden**: Stelle sicher, dass Tkinter installiert ist.
- **INI-Datei wird nicht gespeichert**: Überprüfe die Dateiberechtigungen im Zielverzeichnis.
Mit dieser Anleitung solltest du in der Lage sein, das Skript erfolgreich zu verwenden und benutzerdefinierte Konfigurationen für Regionen zu erstellen und zu verwalten.
Sourcecode:
PHP-Code: import tkinter as tk from tkinter import messagebox, filedialog import configparser import uuid import math
class RegionConfigApp: def __init__(self, root): self.root = root self.root.title("Region Configurations")
# Set window size self.root.geometry("450x700")
# Initialize variables with default values self.region_name = tk.StringVar(value="TestRegion") self.region_uuid = tk.StringVar(value=str(uuid.uuid4())) self.maptile_uuid = tk.StringVar(value=self.region_uuid.get()) # Location variable for grid position self.location = tk.StringVar(value="1000,1000") self.size_x = tk.IntVar(value=256) self.size_y = tk.IntVar(value=256) self.size_z = tk.IntVar(value=256) self.internal_port = tk.IntVar(value=9050) self.external_host = tk.StringVar(value="SYSTEMIP") self.max_prims = tk.IntVar(value=100000) self.max_agents = tk.IntVar(value=99) self.internal_address = tk.StringVar(value="0.0.0.0") self.allow_alt_ports = tk.BooleanVar(value=False) self.non_physical_prim_max = tk.IntVar(value=256) self.physical_prim_max = tk.IntVar(value=64)
# New variables for additional settings self.clamp_prim_size = tk.BooleanVar(value=False) self.max_prims_per_user = tk.IntVar(value=-1) self.scope_id = tk.StringVar(value=self.region_uuid.get()) self.region_type = tk.StringVar(value="Mainland") self.render_min_height = tk.IntVar(value=-1) self.render_max_height = tk.IntVar(value=100) self.maptile_static_file = tk.StringVar(value="SomeFile.png") self.master_avatar_first_name = tk.StringVar(value="John") self.master_avatar_last_name = tk.StringVar(value="Doe") self.master_avatar_sandbox_password = tk.StringVar(value="passwd")
self.region_count = 0 # Startet bei 0 self.angle = 0 self.radius = 1 # Initialer Radius self.locations = [] # Liste für die Locations aller Regionen
# Trace changes to region_uuid to update maptile_uuid accordingly self.region_uuid.trace_add('write', self.update_maptile_uuid)
# Build the UI self.build_ui()
def update_maptile_uuid(self, *args): self.maptile_uuid.set(self.region_uuid.get())
def build_ui(self): canvas = tk.Canvas(self.root) scrollbar = tk.Scrollbar(self.root, orient="vertical", command=canvas.yview) scrollable_frame = tk.Frame(canvas)
scrollable_frame.bind( "<Configure>", lambda e: canvas.configure( scrollregion=canvas.bbox("all") ) )
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y")
fields = [ ("Region Name:", self.region_name), ("Region UUID:", self.region_uuid), ("Location:", self.location), # Location field added here ("Size X:", self.size_x), ("Size Y:", self.size_y), ("Size Z:", self.size_z), ("Internal Port:", self.internal_port), ("External Host:", self.external_host), ("Max Prims:", self.max_prims), ("Max Agents:", self.max_agents), ("Maptile UUID:", self.maptile_uuid), ("Internal Address:", self.internal_address), ("Allow Alternate Ports:", self.allow_alt_ports), ("Non Physical Prim Max:", self.non_physical_prim_max), ("Physical Prim Max:", self.physical_prim_max), ("Clamp Prim Size:", self.clamp_prim_size), ("Max Prims Per User:", self.max_prims_per_user), ("Scope ID:", self.scope_id), ("Region Type:", self.region_type), ("Render Min Height:", self.render_min_height), ("Render Max Height:", self.render_max_height), ("Maptile Static File:", self.maptile_static_file), ("Master Avatar First Name:", self.master_avatar_first_name), ("Master Avatar Last Name:", self.master_avatar_last_name), ("Master Avatar Sandbox Password:", self.master_avatar_sandbox_password), ]
for idx, (label_text, var) in enumerate(fields): if isinstance(var, tk.BooleanVar): tk.Checkbutton(scrollable_frame, text=label_text, variable=var).grid(row=idx, column=0, columnspan=2, sticky=tk.W, pady=2, padx=5) else: tk.Label(scrollable_frame, text=label_text).grid(row=idx, column=0, sticky=tk.W, pady=2, padx=5) entry = tk.Entry(scrollable_frame, textvariable=var, width=40) entry.grid(row=idx, column=1, sticky=tk.W, pady=2, padx=5)
button_frame = tk.Frame(scrollable_frame) button_frame.grid(row=len(fields), column=0, columnspan=2, pady=10)
tk.Button(button_frame, text="Add Region", command=self.add_region).pack(side="left", padx=10) tk.Button(button_frame, text="Save Config", command=self.save_config).pack(side="left", padx=10)
def next_flower_spiral_location(self): # Berechnung der nächsten Position in der spiralförmigen, blütenartigen Anordnung self.angle += 137.5 # Goldener Winkel in Grad radians = math.radians(self.angle) location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians)) self.radius += 1 # Erhöhe den Radius schrittweise für den nächsten Punkt return location_x, location_y
def add_region(self): location = self.next_flower_spiral_location() self.locations.append(location)
new_uuid = str(uuid.uuid4())
self.region_count += 1 self.region_name.set(f"TestRegion_{self.region_count}") self.region_uuid.set(new_uuid) self.internal_port.set(self.internal_port.get() + 1)
self.location.set(f"{location[0]},{location[1]}") # Update the location
messagebox.showinfo("Region Added", f"Region {self.region_name.get()} hinzugefügt. Location: ({location[0]},{location[1]})")
def save_config(self): filename = filedialog.asksaveasfilename(defaultextension=".ini", filetypes=[("INI files", "*.ini")]) if filename: config = configparser.ConfigParser()
for i in range(1, self.region_count + 1): if i == 1: region_name = self.region_name.get() region_uuid = self.region_uuid.get() location_x, location_y = map(int, self.location.get().split(',')) # Erste Region else: region_name = f"TestRegion_{i}" region_uuid = str(uuid.uuid4()) location_x, location_y = self.locations[i-1] # Spezielle Location für jede Region
config[region_name] = { "RegionUUID": region_uuid, "Location": f"{location_x},{location_y}", "SizeX": self.size_x.get(), "SizeY": self.size_y.get(), "SizeZ": self.size_z.get(), "InternalPort": self.internal_port.get() + (i - 1), "ExternalHostName": self.external_host.get(), "MaxPrims": self.max_prims.get(), "MaxAgents": self.max_agents.get(), "MaptileStaticUUID": self.maptile_uuid.get(), "InternalAddress": self.internal_address.get(), "AllowAlternatePorts": self.allow_alt_ports.get(), "NonPhysicalPrimMax": self.non_physical_prim_max.get(), "PhysicalPrimMax": self.physical_prim_max.get(), "ClampPrimSize": str(self.clamp_prim_size.get()), "MaxPrimsPerUser": self.max_prims_per_user.get(), "ScopeID": self.scope_id.get(), "RegionType": self.region_type.get(), "RenderMinHeight": self.render_min_height.get(), "RenderMaxHeight": self.render_max_height.get(), "MaptileStaticFile": self.maptile_static_file.get(), "MasterAvatarFirstName": self.master_avatar_first_name.get(), "MasterAvatarLastName": self.master_avatar_last_name.get(), "MasterAvatarSandboxPassword": self.master_avatar_sandbox_password.get(), }
with open(filename, 'w') as configfile: config.write(configfile) messagebox.showinfo("Gespeichert", "Konfiguration erfolgreich gespeichert.")
if __name__ == "__main__": root = tk.Tk() app = RegionConfigApp(root) root.mainloop()
Sourcecode als Text:
OpenSimRegionConfig5.py.txt (Größe: 8,96 KB / Downloads: 37)
RE: OpenSimRegionConfig - Manfred Aabye - 01.09.2024
Neue Version 5
RE: OpenSimRegionConfig - Manfred Aabye - 15.09.2024
Ich habe noch eine Funktion Fibonacci Anordnung eingefügt, dazu noch ein paar Fehler entfernt (Groß / Kleinschreibung).
Um eine Regionskonfiguration zu erstellen drückt bitte einmal "Add Region" dann "Save Config"
oder bei 5 neuen Konfigurationen 6-mal "Add Region" dann "Save Config",
bei 10 Regionen 11-mal "Add Region" dann "Save Config" etc. (Bug muss ich noch entfernen).
Die automatische anordnung funktioniert zur zeit nur mit 256er Regionen für 512, 768, 1024 etc. muss ich noch einfügen.
RegionConfigApp_06.py
PHP-Code: import tkinter as tk from tkinter import messagebox, filedialog import configparser import uuid import math
# Custom ConfigParser class to preserve key case sensitivity class CaseConfigParser(configparser.ConfigParser): def optionxform(self, optionstr): return optionstr # Keep original case
class RegionConfigApp: def __init__(self, root): self.root = root self.root.title("Region Configurations")
# Set window size self.root.geometry("450x700")
# Initialize variables with default values self.region_name = tk.StringVar(value="TestRegion_1") self.region_uuid = tk.StringVar(value=str(uuid.uuid4())) self.maptile_uuid = tk.StringVar(value=self.region_uuid.get()) # Location variable for grid position self.location = tk.StringVar(value="1000,1000")
self.size = tk.IntVar(value=256) self.internal_port = tk.IntVar(value=9050) self.external_host = tk.StringVar(value="SYSTEMIP") self.max_prims = tk.IntVar(value=100000) self.max_agents = tk.IntVar(value=99) self.internal_address = tk.StringVar(value="0.0.0.0") self.allow_alt_ports = tk.BooleanVar(value=False) self.non_physical_prim_max = tk.IntVar(value=256) self.physical_prim_max = tk.IntVar(value=64)
# New variables for additional settings self.clamp_prim_size = tk.BooleanVar(value=False) self.max_prims_per_user = tk.IntVar(value=-1) self.scope_id = tk.StringVar(value=self.region_uuid.get()) self.region_type = tk.StringVar(value="") self.render_min_height = tk.IntVar(value=-1) self.render_max_height = tk.IntVar(value=100) self.maptile_static_file = tk.StringVar(value="SomeFile.png") self.master_avatar_first_name = tk.StringVar(value="John") self.master_avatar_last_name = tk.StringVar(value="Doe") self.master_avatar_sandbox_password = tk.StringVar(value="passwd")
self.region_count = 0 # Start at 0 self.angle = 0 self.radius = 1 # Initial radius for spirals self.locations = [] # List to store locations of all regions
# Variable for selecting spiral type self.spiral_type = tk.StringVar(value="flower") # Default to "flower"
# Trace changes to region_uuid to update maptile_uuid accordingly self.region_uuid.trace_add('write', self.update_maptile_uuid)
# Build the UI self.build_ui()
def update_maptile_uuid(self, *args): self.maptile_uuid.set(self.region_uuid.get())
def build_ui(self): canvas = tk.Canvas(self.root) scrollbar = tk.Scrollbar(self.root, orient="vertical", command=canvas.yview) scrollable_frame = tk.Frame(canvas)
scrollable_frame.bind( "<Configure>", lambda e: canvas.configure( scrollregion=canvas.bbox("all") ) )
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y")
fields = [ ("Region Name:", self.region_name), ("Region UUID:", self.region_uuid), ("Location:", self.location), ("Size:", self.size), ("Internal Port:", self.internal_port), ("External Host:", self.external_host), ("Max Prims:", self.max_prims), ("Max Agents:", self.max_agents), ("Maptile UUID:", self.maptile_uuid), ("Internal Address:", self.internal_address), ("Allow Alternate Ports:", self.allow_alt_ports), ("Non-Physical Prim Max:", self.non_physical_prim_max), ("Physical Prim Max:", self.physical_prim_max), ("Clamp Prim Size:", self.clamp_prim_size), ("Max Prims Per User:", self.max_prims_per_user), ("Scope ID:", self.scope_id), ("Region Type:", self.region_type), ("Render Min Height:", self.render_min_height), ("Render Max Height:", self.render_max_height), ("Maptile Static File:", self.maptile_static_file), ("Master Avatar First Name:", self.master_avatar_first_name), ("Master Avatar Last Name:", self.master_avatar_last_name), ("Master Avatar Sandbox Password:", self.master_avatar_sandbox_password), ]
for idx, (label_text, var) in enumerate(fields): if isinstance(var, tk.BooleanVar): tk.Checkbutton(scrollable_frame, text=label_text, variable=var).grid(row=idx, column=0, columnspan=2, sticky=tk.W, pady=2, padx=5) else: tk.Label(scrollable_frame, text=label_text).grid(row=idx, column=0, sticky=tk.W, pady=2, padx=5) entry = tk.Entry(scrollable_frame, textvariable=var, width=40) entry.grid(row=idx, column=1, sticky=tk.W, pady=2, padx=5)
# Dropdown for spiral selection tk.Label(scrollable_frame, text="Spiral Type:").grid(row=len(fields), column=0, sticky=tk.W, pady=2, padx=5) spiral_menu = tk.OptionMenu(scrollable_frame, self.spiral_type, "flower", "fibonacci") spiral_menu.grid(row=len(fields), column=1, sticky=tk.W, pady=2, padx=5)
button_frame = tk.Frame(scrollable_frame) button_frame.grid(row=len(fields) + 1, column=0, columnspan=2, pady=10)
tk.Button(button_frame, text="Add Region", command=self.add_region).pack(side="left", padx=10) tk.Button(button_frame, text="Save Config", command=self.save_config).pack(side="left", padx=10)
def next_flower_spiral_location(self): # Calculate the next position using a flower-like spiral self.angle += 137.5 # Golden angle in degrees radians = math.radians(self.angle) location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians)) self.radius += 1 # Increment the radius gradually for the next point return location_x, location_y
def next_fibonacci_spiral_location(self): # Calculate the next position using the Fibonacci spiral self.angle += 137.5 # Golden angle in degrees radians = math.radians(self.angle) self.radius *= 1.618 # Fibonacci increment location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians)) return location_x, location_y
def add_region(self): # Determine which spiral to use if self.spiral_type.get() == "flower": location = self.next_flower_spiral_location() elif self.spiral_type.get() == "fibonacci": location = self.next_fibonacci_spiral_location()
self.locations.append(location)
new_uuid = str(uuid.uuid4())
self.region_count += 1 self.region_name.set(f"TestRegion_{self.region_count}") self.region_uuid.set(new_uuid) self.internal_port.set(self.internal_port.get() + 1)
self.location.set(f"{location[0]},{location[1]}") # Update the location
messagebox.showinfo("Region Added", f"Region {self.region_name.get()} added. Location: ({location[0]},{location[1]})")
def save_config(self): filename = filedialog.asksaveasfilename(defaultextension=".ini", filetypes=[("INI files", "*.ini")]) if filename: config = CaseConfigParser() # Use the custom parser to preserve case
for i in range(1, self.region_count + 1): if i == 1: region_name = self.region_name.get() region_uuid = self.region_uuid.get() location_x, location_y = map(int, self.location.get().split(',')) # First region else: region_name = f"TestRegion_{i}" region_uuid = str(uuid.uuid4()) location_x, location_y = self.locations[i-1] # Specific location for each region
config[region_name] = { "RegionUUID": region_uuid, "Location": f"{location_x},{location_y}", "SizeX": self.size.get(), "SizeY": self.size.get(), "SizeZ": self.size.get(), "InternalPort": self.internal_port.get() + (i - 1), "InternalAddress": self.internal_address.get(), "AllowAlternatePorts": str(self.allow_alt_ports.get()), "ExternalHostName": self.external_host.get(), "MaxPrims": self.max_prims.get(), "MaxAgents": self.max_agents.get(), "MaxPrimsPerUser": self.max_prims_per_user.get(), ";MaptileStaticUUID": self.maptile_uuid.get(), ";NonPhysicalPrimMax": self.non_physical_prim_max.get(), ";PhysicalPrimMax": self.physical_prim_max.get(), ";ClampPrimSize": str(self.clamp_prim_size.get()), ";ScopeID": self.scope_id.get(), ";RegionType": self.region_type.get(), ";RenderMinHeight": self.render_min_height.get(), ";RenderMaxHeight": self.render_max_height.get(), ";MaptileStaticFile": self.maptile_static_file.get(), ";MasterAvatarFirstName": self.master_avatar_first_name.get(), ";MasterAvatarLastName": self.master_avatar_last_name.get(), ";MasterAvatarSandboxPassword": self.master_avatar_sandbox_password.get(), }
with open(filename, 'w') as configfile: config.write(configfile) messagebox.showinfo("Saved", "Configuration saved successfully.")
if __name__ == "__main__": root = tk.Tk() app = RegionConfigApp(root) root.mainloop()
RE: OpenSimRegionConfig - Manfred Aabye - 15.09.2024
Anleitung zur Verwendung der RegionConfigApp
1. Programm starten
- Doppelklicken Sie auf die Programmdatei, um die RegionConfigApp zu starten. Ein Fenster mit dem Titel „Region Configurations“ öffnet sich.
2. Regionen hinzufügen
- Region Name: Geben Sie hier den Namen der Region ein. Der Name wird automatisch angepasst, wenn Sie eine neue Region hinzufügen (z.B. „TestRegion_1“).
- Region UUID: Eine eindeutige ID für die Region wird automatisch generiert und angezeigt.
- Location: Hier sehen Sie die aktuelle Position der Region auf der Karte. Diese wird automatisch aktualisiert, wenn Sie eine neue Region hinzufügen.
- Size: Geben Sie die Größe der Region ein. Diese Größe wird für alle Regionen verwendet.
- Internal Port: Der interne Port für die Region. Wird für jede neue Region automatisch um 1 erhöht.
- External Host: Der Hostname für die Region. Geben Sie hier die IP-Adresse oder den Domainnamen ein.
- Max Prims: Maximale Anzahl von Prim-Objekten (Objekten) in der Region.
- Max Agents: Maximale Anzahl von Agenten in der Region.
- Internal Address: Die interne IP-Adresse der Region.
- Allow Alternate Ports: Aktivieren Sie dieses Kontrollkästchen, wenn alternative Ports erlaubt sind.
- Non-Physical Prim Max: Maximale Anzahl nicht-physischer Prim-Objekte.
- Physical Prim Max: Maximale Anzahl physischer Prim-Objekte.
- Clamp Prim Size: Aktivieren Sie dieses Kontrollkästchen, um die Prim-Größe zu begrenzen.
- Max Prims Per User: Maximale Anzahl von Prim-Objekten pro Benutzer.
- Scope ID: Die ID des Bereichs oder der Region.
- Region Type: Der Typ der Region. Geben Sie hier den Typ ein.
- Render Min Height und Max Height: Geben Sie hier die Mindest- und Höhenausgabe in Metern an.
- Maptile Static File: Geben Sie den Namen der Datei ein, die für die Kartendarstellung verwendet wird.
- Master Avatar First Name und Last Name: Der Vorname und Nachname des Master-Avatars.
- Master Avatar Sandbox Password: Passwort für den Master-Avatar im Sandbox-Modus.
3. Spiral-Typ auswählen
- Spiral Type: Wählen Sie aus, ob die Region in einer „flower“- oder „fibonacci“-Spirale hinzugefügt werden soll. Nutzen Sie das Dropdown-Menü neben „Spiral Type“.
4. Region hinzufügen
- Add Region: Klicken Sie auf den Button „Add Region“, um eine neue Region hinzuzufügen. Die Position der neuen Region wird automatisch berechnet und angezeigt.
5. Konfiguration speichern
- Save Config: Klicken Sie auf den Button „Save Config“, um die aktuelle Konfiguration zu speichern. Ein Dialogfenster öffnet sich, in dem Sie den Speicherort und den Dateinamen für die Konfigurationsdatei auswählen können. Die Datei wird im `.ini`-Format gespeichert.
6. Fehlermeldungen und Hinweise
- Region Added: Nach dem Hinzufügen einer Region wird eine Bestätigungsmeldung angezeigt, die den Namen der Region und deren Position auf der Karte zeigt.
- Saved: Nach dem Speichern der Konfiguration wird eine Bestätigungsmeldung angezeigt.
---
Das war's! Mit diesen Schritten können Sie die RegionConfigApp effektiv nutzen, um Ihre Regionen zu konfigurieren und zu speichern.
P.S. MaxPrimsPerUser = -1 bedeutet unendlich, MaxPrimsPerUser = 100 Bedeutet jeder kann nur 100 Prims setzen/bauen.
RE: OpenSimRegionConfig - Manfred Aabye - 15.09.2024
Schöner ist das aber mit Zufallsnamen statt Zahlen.
PHP-Code: import tkinter as tk from tkinter import messagebox, filedialog import configparser import uuid import math import random
# Erweiterte Listen mit Vorsilben und Nachsilben VORSILBE = [ "Alt", "Augs", "Ber", "Biele", "Dort", "Dres", "Duel", "Er", "Frank", "Gos", "Gör", "Heil", "Hild", "Jena", "Kass", "Kiel", "Köln", "Linz", "Magde", "Mann", "Mar", "Mittel", "Neu", "Nord", "Ober", "Osna", "Ost", "Reut", "Rost", "Sieger", "Stutt", "Sued", "Unter", "West", "Neub", "Stein", "Zell", "Trier", "Hagen", "Wert" ]
NACHSILBE = [ "markt", "burg", "lin", "feld", "mund", "den", "len", "men", "furt", "lar", "litz", "bronn", "heim", "er", "el", "ken", "Rhein", "Delhi", "Hessen", "Bayern", "Pfalz", "brück", "land", "Harz", "lingen", "ock", "land", "gart", "Baden", "Tirol", "Franken", "Sachsen", "Falen", "ner", "stein", "stadt", "bach", "tal", "hof", "en", "ring" ]
def generate_random_name(): # Wählt zufällig eine Vorsilbe und eine Nachsilbe aus vorsilbe = random.choice(VORSILBE) nachsilbe = random.choice(NACHSILBE) # Generiert den Namen durch Verknüpfung der Vorsilbe und Nachsilbe name = vorsilbe + nachsilbe return name
# Custom ConfigParser class to preserve key case sensitivity class CaseConfigParser(configparser.ConfigParser): def optionxform(self, optionstr): return optionstr # Keep original case
class RegionConfigApp: def __init__(self, root): self.root = root self.root.title("Region Configurations")
# Set window size self.root.geometry("450x700")
# Initialize variables with default values self.region_name = tk.StringVar(value=generate_random_name()) self.region_uuid = tk.StringVar(value=str(uuid.uuid4())) self.maptile_uuid = tk.StringVar(value=self.region_uuid.get()) # Location variable for grid position self.location = tk.StringVar(value="1000,1000")
self.size = tk.IntVar(value=256) self.internal_port = tk.IntVar(value=9050) self.external_host = tk.StringVar(value="SYSTEMIP") self.max_prims = tk.IntVar(value=100000) self.max_agents = tk.IntVar(value=99) self.internal_address = tk.StringVar(value="0.0.0.0") self.allow_alt_ports = tk.BooleanVar(value=False) self.non_physical_prim_max = tk.IntVar(value=256) self.physical_prim_max = tk.IntVar(value=64)
# New variables for additional settings self.clamp_prim_size = tk.BooleanVar(value=False) self.max_prims_per_user = tk.IntVar(value=-1) self.scope_id = tk.StringVar(value=self.region_uuid.get()) self.region_type = tk.StringVar(value="") self.render_min_height = tk.IntVar(value=-1) self.render_max_height = tk.IntVar(value=100) self.maptile_static_file = tk.StringVar(value="SomeFile.png") self.master_avatar_first_name = tk.StringVar(value="John") self.master_avatar_last_name = tk.StringVar(value="Doe") self.master_avatar_sandbox_password = tk.StringVar(value="passwd")
self.region_count = 0 # Start at 0 self.angle = 0 self.radius = 1 # Initial radius for spirals self.locations = [] # List to store locations of all regions
# Variable for selecting spiral type self.spiral_type = tk.StringVar(value="flower") # Default to "flower"
# Trace changes to region_uuid to update maptile_uuid accordingly self.region_uuid.trace_add('write', self.update_maptile_uuid)
# Build the UI self.build_ui()
def update_maptile_uuid(self, *args): self.maptile_uuid.set(self.region_uuid.get())
def build_ui(self): canvas = tk.Canvas(self.root) scrollbar = tk.Scrollbar(self.root, orient="vertical", command=canvas.yview) scrollable_frame = tk.Frame(canvas)
scrollable_frame.bind( "<Configure>", lambda e: canvas.configure( scrollregion=canvas.bbox("all") ) )
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y")
fields = [ ("Region Name:", self.region_name), ("Region UUID:", self.region_uuid), ("Location:", self.location), ("Size:", self.size), ("Internal Port:", self.internal_port), ("External Host:", self.external_host), ("Max Prims:", self.max_prims), ("Max Agents:", self.max_agents), ("Maptile UUID:", self.maptile_uuid), ("Internal Address:", self.internal_address), ("Allow Alternate Ports:", self.allow_alt_ports), ("Non-Physical Prim Max:", self.non_physical_prim_max), ("Physical Prim Max:", self.physical_prim_max), ("Clamp Prim Size:", self.clamp_prim_size), ("Max Prims Per User:", self.max_prims_per_user), ("Scope ID:", self.scope_id), ("Region Type:", self.region_type), ("Render Min Height:", self.render_min_height), ("Render Max Height:", self.render_max_height), ("Maptile Static File:", self.maptile_static_file), ("Master Avatar First Name:", self.master_avatar_first_name), ("Master Avatar Last Name:", self.master_avatar_last_name), ("Master Avatar Sandbox Password:", self.master_avatar_sandbox_password), ]
for idx, (label_text, var) in enumerate(fields): if isinstance(var, tk.BooleanVar): tk.Checkbutton(scrollable_frame, text=label_text, variable=var).grid(row=idx, column=0, columnspan=2, sticky=tk.W, pady=2, padx=5) else: tk.Label(scrollable_frame, text=label_text).grid(row=idx, column=0, sticky=tk.W, pady=2, padx=5) entry = tk.Entry(scrollable_frame, textvariable=var, width=40) entry.grid(row=idx, column=1, sticky=tk.W, pady=2, padx=5)
# Dropdown for spiral selection tk.Label(scrollable_frame, text="Spiral Type:").grid(row=len(fields), column=0, sticky=tk.W, pady=2, padx=5) spiral_menu = tk.OptionMenu(scrollable_frame, self.spiral_type, "flower", "fibonacci") spiral_menu.grid(row=len(fields), column=1, sticky=tk.W, pady=2, padx=5)
button_frame = tk.Frame(scrollable_frame) button_frame.grid(row=len(fields) + 1, column=0, columnspan=2, pady=10)
tk.Button(button_frame, text="Add Region", command=self.add_region).pack(side="left", padx=10) tk.Button(button_frame, text="Save Config", command=self.save_config).pack(side="left", padx=10)
def next_flower_spiral_location(self): # Calculate the next position using a flower-like spiral self.angle += 137.5 # Golden angle in degrees radians = math.radians(self.angle) location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians)) self.radius += 1 # Increment the radius gradually for the next point return location_x, location_y
def next_fibonacci_spiral_location(self): # Calculate the next position using the Fibonacci spiral self.angle += 137.5 # Golden angle in degrees radians = math.radians(self.angle) self.radius *= 1.618 # Fibonacci increment location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians)) return location_x, location_y
def add_region(self): # Determine which spiral to use if self.spiral_type.get() == "flower": location = self.next_flower_spiral_location() elif self.spiral_type.get() == "fibonacci": location = self.next_fibonacci_spiral_location()
self.locations.append(location)
new_uuid = str(uuid.uuid4())
self.region_count += 1 self.region_name.set(generate_random_name()) self.region_uuid.set(new_uuid) self.internal_port.set(self.internal_port.get() + 1)
self.location.set(f"{location[0]},{location[1]}") # Update the location
messagebox.showinfo("Region Added", f"Region {self.region_name.get()} added. Location: ({location[0]},{location[1]})")
def save_config(self): filename = filedialog.asksaveasfilename(defaultextension=".ini", filetypes=[("INI files", "*.ini")]) if filename: config = CaseConfigParser() # Use the custom parser to preserve case
for i in range(1, self.region_count + 1): if i == 1: region_name = self.region_name.get() region_uuid = self.region_uuid.get() location_x, location_y = map(int, self.location.get().split(',')) # First region else: region_name = generate_random_name() region_uuid = str(uuid.uuid4()) location_x, location_y = self.locations[i-1] # Specific location for each region
config[region_name] = { "RegionUUID": region_uuid, "Location": f"{location_x},{location_y}", "SizeX": self.size.get(), "SizeY": self.size.get(), "SizeZ": self.size.get(), "InternalPort": self.internal_port.get() + (i - 1), "InternalAddress": self.internal_address.get(), "AllowAlternatePorts": str(self.allow_alt_ports.get()), "ExternalHostName": self.external_host.get(), "MaxPrims": self.max_prims.get(), "MaxAgents": self.max_agents.get(), "MaxPrimsPerUser": self.max_prims_per_user.get(), ";MaptileStaticUUID": self.maptile_uuid.get(), ";NonPhysicalPrimMax": self.non_physical_prim_max.get(), ";PhysicalPrimMax": self.physical_prim_max.get(), ";ClampPrimSize": str(self.clamp_prim_size.get()), ";ScopeID": self.scope_id.get(), ";RegionType": self.region_type.get(), ";RenderMinHeight": self.render_min_height.get(), ";RenderMaxHeight": self.render_max_height.get(), ";MaptileStaticFile": self.maptile_static_file.get(), ";MasterAvatarFirstName": self.master_avatar_first_name.get(), ";MasterAvatarLastName": self.master_avatar_last_name.get(), ";MasterAvatarSandboxPassword": self.master_avatar_sandbox_password.get(), }
with open(filename, 'w') as configfile: config.write(configfile) messagebox.showinfo("Saved", "Configuration saved successfully.")
if __name__ == "__main__": root = tk.Tk() app = RegionConfigApp(root) root.mainloop()
RE: OpenSimRegionConfig - Manfred Aabye - 16.09.2024
Jetzt gibt es 14 Spirale-Typen.
Einige Fehler behoben.
Erste Windows Version verfügbar: DOWNLOAD
PHP-Code: import tkinter as tk from tkinter import messagebox, filedialog import configparser import uuid import math import random
# Erweiterte Listen mit Vorsilben und Nachsilben VORSILBE = [ "Alt", "Augs", "Ber", "Biele", "Dort", "Dres", "Duel", "Er", "Frank", "Gos", "Gör", "Heil", "Hild", "Jena", "Kass", "Kiel", "Köln", "Linz", "Magde", "Mann", "Mar", "Mittel", "Neu", "Nord", "Ober", "Osna", "Ost", "Reut", "Rost", "Sieger", "Stutt", "Sued", "Unter", "West", "Neub", "Stein", "Zell", "Trier", "Hagen", "Wert" ]
NACHSILBE = [ "markt", "burg", "lin", "feld", "mund", "den", "len", "men", "furt", "lar", "litz", "bronn", "heim", "er", "el", "ken", "Rhein", "Delhi", "Hessen", "Bayern", "Pfalz", "brück", "land", "Harz", "lingen", "ock", "land", "gart", "Baden", "Tirol", "Franken", "Sachsen", "Falen", "ner", "stein", "stadt", "bach", "tal", "hof", "en", "ring" ]
def generate_random_name(): # Wählt zufällig eine Vorsilbe und eine Nachsilbe aus vorsilbe = random.choice(VORSILBE) nachsilbe = random.choice(NACHSILBE) # Generiert den Namen durch Verknüpfung der Vorsilbe und Nachsilbe name = vorsilbe + nachsilbe return name
# Custom ConfigParser class to preserve key case sensitivity class CaseConfigParser(configparser.ConfigParser): def optionxform(self, optionstr): return optionstr # Keep original case
class RegionConfigApp: def __init__(self, root): self.root = root
self.index = 0
# Set window icon #self.root.iconbitmap("icon.ico")
# Set window title self.root.title("Region Configurations")
# Set window size self.root.geometry("450x700") # Initialize variables with default values self.region_name = tk.StringVar(value=generate_random_name()) self.region_uuid = tk.StringVar(value=str(uuid.uuid4())) self.maptile_uuid = tk.StringVar(value=self.region_uuid.get()) # Location variable for grid position self.location = tk.StringVar(value="1000,1000")
self.size = tk.IntVar(value=256) self.internal_port = tk.IntVar(value=9050) self.external_host = tk.StringVar(value="SYSTEMIP") self.max_prims = tk.IntVar(value=100000) self.max_agents = tk.IntVar(value=99) self.internal_address = tk.StringVar(value="0.0.0.0") self.allow_alt_ports = tk.BooleanVar(value=False) self.non_physical_prim_max = tk.IntVar(value=256) self.physical_prim_max = tk.IntVar(value=64)
# New variables for additional settings self.clamp_prim_size = tk.BooleanVar(value=False) self.max_prims_per_user = tk.IntVar(value=-1) self.scope_id = tk.StringVar(value=self.region_uuid.get()) self.region_type = tk.StringVar(value="") self.render_min_height = tk.IntVar(value=-1) self.render_max_height = tk.IntVar(value=100) self.maptile_static_file = tk.StringVar(value="SomeFile.png") self.master_avatar_first_name = tk.StringVar(value="John") self.master_avatar_last_name = tk.StringVar(value="Doe") self.master_avatar_sandbox_password = tk.StringVar(value="passwd")
self.region_count = 0 # Start at 0 self.angle = 0 self.radius = 1 # Initial radius for spirals self.locations = [] # List to store locations of all regions
# Variable for selecting spiral type self.spiral_type = tk.StringVar(value="flower") # Default to "flower"
# Trace changes to region_uuid to update maptile_uuid accordingly self.region_uuid.trace_add('write', self.update_maptile_uuid)
# Build the UI self.build_ui()
def update_maptile_uuid(self, *args): self.maptile_uuid.set(self.region_uuid.get())
def build_ui(self): canvas = tk.Canvas(self.root) scrollbar = tk.Scrollbar(self.root, orient="vertical", command=canvas.yview) scrollable_frame = tk.Frame(canvas)
scrollable_frame.bind( "<Configure>", lambda e: canvas.configure( scrollregion=canvas.bbox("all") ) )
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y")
fields = [ ("Region Name:", self.region_name), ("Region UUID:", self.region_uuid), ("Location:", self.location), ("Size:", self.size), ("Internal Port:", self.internal_port), ("External Host:", self.external_host), ("Max Prims:", self.max_prims), ("Max Agents:", self.max_agents), ("Maptile UUID:", self.maptile_uuid), ("Internal Address:", self.internal_address), ("Allow Alternate Ports:", self.allow_alt_ports), ("Non-Physical Prim Max:", self.non_physical_prim_max), ("Physical Prim Max:", self.physical_prim_max), ("Clamp Prim Size:", self.clamp_prim_size), ("Max Prims Per User:", self.max_prims_per_user), ("Scope ID:", self.scope_id), ("Region Type:", self.region_type), ("Render Min Height:", self.render_min_height), ("Render Max Height:", self.render_max_height), ("Maptile Static File:", self.maptile_static_file), ("Master Avatar First Name:", self.master_avatar_first_name), ("Master Avatar Last Name:", self.master_avatar_last_name), ("Master Avatar Sandbox Password:", self.master_avatar_sandbox_password), ]
for idx, (label_text, var) in enumerate(fields): if isinstance(var, tk.BooleanVar): tk.Checkbutton(scrollable_frame, text=label_text, variable=var).grid(row=idx, column=0, columnspan=2, sticky=tk.W, pady=2, padx=5) else: tk.Label(scrollable_frame, text=label_text).grid(row=idx, column=0, sticky=tk.W, pady=2, padx=5) entry = tk.Entry(scrollable_frame, textvariable=var, width=40) entry.grid(row=idx, column=1, sticky=tk.W, pady=2, padx=5)
# Dropdown for spiral selection self.spiral_type = tk.StringVar(value="flower") # Fix: Make sure the initial value of self.spiral_type is set correctly, which is already done with the line tk.Label(scrollable_frame, text="Spiral Type:").grid(row=len(fields), column=0, sticky=tk.W, pady=2, padx=5) spiral_menu = tk.OptionMenu(scrollable_frame, self.spiral_type, "archimedean_spiral1", "archimedean_spiral2", "circle1", "circle2", "fibonacci_spiral", "flower", "grid1", "grid2", "logarithmic_spiral", "logistic", "random1", "random2", "star") spiral_menu.grid(row=len(fields), column=1, sticky=tk.W, pady=2, padx=5)
button_frame = tk.Frame(scrollable_frame) button_frame.grid(row=len(fields) + 1, column=0, columnspan=2, pady=10)
tk.Button(button_frame, text="Add Region", command=self.add_region).pack(side="left", padx=10) tk.Button(button_frame, text="Save Config", command=self.save_config).pack(side="left", padx=10)
def next_flower_spiral_location1(self): # Calculate the next position using a flower-like spiral self.angle += 137.5 # Golden angle in degrees radians = math.radians(self.angle) location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians)) self.radius += 1 # Increment the radius gradually for the next point return location_x, location_y
def next_fibonacci_spiral_location(self): # Calculate the next position using the Fibonacci spiral self.angle += 137.5 # Golden angle in degrees radians = math.radians(self.angle) self.radius *= 1.618 # Fibonacci increment location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians)) return location_x, location_y
def next_archimedean_spiral_location2(self): self.angle += 10 # Increment angle by a fixed value radians = math.radians(self.angle) location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians)) self.radius += 10 # Increment the radius linearly for a smooth spiral return location_x, location_y
def next_logarithmic_spiral_location(self): self.angle += 10 # Increase angle gradually radians = math.radians(self.angle) self.radius *= 1.1 # Exponentially increase the radius location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians)) return location_x, location_y
def next_random_location1(self): location_x = random.randint(0, 2000) location_y = random.randint(0, 2000) return location_x, location_y
def next_grid_location1(self): location_x = 1000 + (self.index % 10) * 100 # Move horizontally location_y = 1000 + (self.index // 10) * 100 # Move vertically self.index += 1 return location_x, location_y
def next_circle_location1(self): self.angle += 36 # Divide 360 degrees by 10 points radians = math.radians(self.angle) radius = 500 # Constant radius location_x = 1000 + int(radius * math.cos(radians)) location_y = 1000 + int(radius * math.sin(radians)) return location_x, location_y
def next_star_location(self): self.angle += 144 # Star angle (5 points) radians = math.radians(self.angle) location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians)) return location_x, location_y
def next_logistic_function_location(self): self.angle += 10 radians = math.radians(self.angle) K = 2000 # Carrying capacity (limit of growth) location_x = 1000 + int(self.radius * (K / (1 + math.exp(-0.1 * self.angle))) * math.cos(radians)) location_y = 1000 + int(self.radius * (K / (1 + math.exp(-0.1 * self.angle))) * math.sin(radians)) return location_x, location_y
def next_grid_location2(self): # Define grid parameters grid_size = 100 # Distance between grid points num_columns = 10 # Number of columns in the grid
# Calculate row and column based on the current index row = self.index // num_columns column = self.index % num_columns
# Calculate the x, y position location_x = 1000 + column * grid_size location_y = 1000 + row * grid_size
# Increment the index for the next call self.index += 1
return location_x, location_y
def next_circle_location2(self): num_points = 20 # Total number of points on the circle radius = 200 # Fixed radius of the circle
# Calculate the angle for the current point angle = (2 * math.pi / num_points) * self.index location_x = 1000 + int(radius * math.cos(angle)) location_y = 1000 + int(radius * math.sin(angle))
# Increment the index for the next call self.index += 1
return location_x, location_y
def next_archimedean_spiral_location1(self): # Increase the angle self.angle += 10 # Change the step size for tighter or looser spirals radians = math.radians(self.angle)
# Archimedean spiral equation: r = a + b * theta a = 5 # Adjust this value for initial distance from the center b = 5 # Adjust for spacing between spiral arms self.radius = a + b * self.angle
location_x = 1000 + int(self.radius * math.cos(radians)) location_y = 1000 + int(self.radius * math.sin(radians))
return location_x, location_y
def next_random_location2(self): # Define the bounds for random placement location_x = random.randint(800, 1200) location_y = random.randint(800, 1200)
return location_x, location_y
def add_region(self): # Determine which spiral to use location = None if self.spiral_type.get() == "flower": location = self.next_flower_spiral_location1() elif self.spiral_type.get() == "fibonacci_spiral": location = self.next_fibonacci_spiral_location() elif self.spiral_type.get() == "archimedean_spiral1": location = self.next_archimedean_spiral_location1() elif self.spiral_type.get() == "logarithmic_spiral": location = self.next_logarithmic_spiral_location() elif self.spiral_type.get() == "random1": location = self.next_random_location1() elif self.spiral_type.get() == "grid1": location = self.next_grid_location1() elif self.spiral_type.get() == "circle1": location = self.next_circle_location1() elif self.spiral_type.get() == "logistic": location = self.next_logistic_function_location() elif self.spiral_type.get() == "star": location = self.next_star_location() elif self.spiral_type.get() == "grid2": location = self.next_grid_location2() elif self.spiral_type.get() == "circle2": location = self.next_circle_location2() elif self.spiral_type.get() == "archimedean_spiral2": location = self.next_archimedean_spiral_location2() elif self.spiral_type.get() == "random2": location = self.next_random_location2()
if location is None: messagebox.showerror("Error", "No spiral selected") return
self.locations.append(location)
new_uuid = str(uuid.uuid4())
self.region_count += 1 self.region_name.set(generate_random_name()) self.region_uuid.set(new_uuid) self.internal_port.set(self.internal_port.get() + 1)
self.location.set(f"{location[0]},{location[1]}") # Update the location
messagebox.showinfo("Region Added", f"Region {self.region_name.get()} added. Location: ({location[0]},{location[1]})")
def save_config(self): filename = filedialog.asksaveasfilename(defaultextension=".ini", filetypes=[("INI files", "*.ini")]) if not filename:return if filename: config = CaseConfigParser() # Use the custom parser to preserve case
for i in range(1, self.region_count + 1): if i == 1: region_name = self.region_name.get() region_uuid = self.region_uuid.get() location_x, location_y = map(int, self.location.get().split(',')) # First region else: region_name = generate_random_name() region_uuid = str(uuid.uuid4()) location_x, location_y = self.locations[i-1] # Specific location for each region
config[region_name] = { "RegionUUID": region_uuid, "Location": f"{location_x},{location_y}", "SizeX": self.size.get(), "SizeY": self.size.get(), "SizeZ": self.size.get(), "InternalPort": self.internal_port.get() + (i - 1), "InternalAddress": self.internal_address.get(), "AllowAlternatePorts": str(self.allow_alt_ports.get()), "ExternalHostName": self.external_host.get(), "MaxPrims": self.max_prims.get(), "MaxAgents": self.max_agents.get(), "MaxPrimsPerUser": self.max_prims_per_user.get(), ";MaptileStaticUUID": self.maptile_uuid.get(), ";NonPhysicalPrimMax": self.non_physical_prim_max.get(), ";PhysicalPrimMax": self.physical_prim_max.get(), ";ClampPrimSize": str(self.clamp_prim_size.get()), ";ScopeID": self.scope_id.get(), ";RegionType": self.region_type.get(), ";RenderMinHeight": self.render_min_height.get(), ";RenderMaxHeight": self.render_max_height.get(), ";MaptileStaticFile": self.maptile_static_file.get(), ";MasterAvatarFirstName": self.master_avatar_first_name.get(), ";MasterAvatarLastName": self.master_avatar_last_name.get(), ";MasterAvatarSandboxPassword": self.master_avatar_sandbox_password.get(), }
with open(filename, 'w') as configfile: config.write(configfile) messagebox.showinfo("Saved", "Configuration saved successfully.")
if __name__ == "__main__": root = tk.Tk() app = RegionConfigApp(root) root.mainloop()
RE: OpenSimRegionConfig - Manfred Aabye - 17.09.2024
Die nächste Version RegionConfigApp_10.py kann Regionen der Größe 256, 512, 768, 1024, 1280, 1536, 1792, 2048.
Gibt man einen falschen Wert ein, wird gerundet auf die nächste korrekte Größe.
Weitere Fehler wurden behoben.
Anleitung
RegionConfigApp_11.py
Windows-Release 2 Dateien Programm und Icon
Ist das toll, wenn plötzlich Sourcecode fehlt und Tabs und Leerzeichen so verändert werden, dass nichts mehr geht
RE: OpenSimRegionConfig - Manfred Aabye - 18.09.2024
Tooltips werden eingefügt:
RegionConfigApp_12.py
|