Deine Designs sind immer sehr cool!
Good job.
Deine Designs sind immer sehr cool!
Good job.
I think there is an issue in your logic, atleast under some conditions.
The method will select the last npc found on the map.
So if I place 10 NPC's of the same vnum on the map, it will probably select only one (the first npc matching the vnum).
Maybe it would be better to return a struct with npc's that were found instead of the first one?
Es gibt kein vollständiges How-To, das ist leider die bittere Wahrheit. Wenn du wirklich alle Stellen erreichen willst, dann wirst du wohl oder übel selbst Hand anlegen müssen oder einen Entwickler dafür bezahlen. Jedes Tutorial was ich bisher gefunden habe, ist nur semi-vollständig und unter gewissen Voraussetzungen exploitbar. Die meisten Spieler kennen diese Features überhaupt nicht, aber das Tanaka Event zum Beispiel. Oder die Drachenhöhle, das "Monarch-System" oder auch Yang in eine Gilde einzahlen!
Du musst neben dem eigentlichen YMIR Source Code auch unbedingt alle deine Systeme checken (Offline-Shop, Bio-System, Itemshop usw usw.).
::RenderWater
STATEMANAGER.SetTexture(0, m_WaterInstances[((ELTimer_GetMSec() / 70) % m_SpecialWaterCount)].GetTexturePointer()->GetD3DTexture());
::Send
0901 22:44:12837 :: Missing_Item_Name(#25253) cannot find icon file. setting to default.
Hab jetzt initial das Movement hinbekommen, auch wenn da noch einige Dinge geschliffen werden müssen.
Zur Erklärung (Danke Steap noch Mal für das Gespräch gestern, deine erotische Stimme ist immer wieder schön zu hören - Pro Homo):
Wenn ein Spieler sich in Metin auf der Overworld bewegt, dann rotieren wir den Spieler auf der Z-Achse (Daher oben das 'D3DXMatrixRotationZ'). Man kann sich das vorstellen wie wenn man mit einer Kamera über dem Spieler guckt, die Blickrichtung in die der Spieler schaut wird bestimmt, je nachdem um wieviel Grad man die Z-Achse rotiert.
~Lead
_______________________________________________________________________________________________________
Für Interessierte:
Und zum Vorgehen in Metin2 (ist mehrteilig):
1) Initialer Tastendruck (W, A, S, D und Pfeiltasten):
- Beim Tastendruck kommen wir zunächst in die CPythonPlayer::SetSingleDirKeyState Methode, dort wird eine Variable gesetzt falls der Spieler eine Positionstaste gedrückt hat: Diese heißt "m_isDirKey", die wird später noch wichtig!
- Anschließend wird initial CPythonPlayer::SetMultiDirKeyState aufgerufen
2) Loop für Taste aus 1) gedrückt halten
- Es gibt eine CPythonPlayer::Update Methode, welche im Main-Loop der Anwendung zur Laufzeit (aufgerufen durch den Client -> app.UpdateGame) drin ist. Diese ruft als aller Erstes folgende Methode auf: RefreshMouseWalkingDirection und diese wiederum prüft:
Der Name der Methode "RefreshMouseWalkingDirection" ist etwas irreführend, weil diese Prüfung immer ausgeführt wird. Aber saubere Funktionsnamen waren vermutlich bei den hunderttausenden Zeilen Code keine Priorität für die Entwickler.
- Was nun passiert ist, dass währenddessen man die Lauftasten (W, A, S, D und Pfeiltasten) gedrückt hält, man immer wieder in diese CPythonPlayer::SetMultiDirKeyState aus 1) reinkommt, man schickt immer wieder ein Move-Paket an den Server bis man irgendwann stoppt. Dann wird m_isDirKey auf false gesetzt und der Loop wird verlassen.
3) Und nun?
- Jetzt, wo wir wissen, wie die normale Bewegung in Metin2 abläuft, können wir weiteruntersuchen und schauen, wie wir den Code ergänzen.
- Es gibt vermutlich verschiedene Möglichkeiten zur Umsetzung, ich habe die CActorInstance::AddMovement Methode von M2 genutzt. Diese wird aufgerufen, dann wird einem Vektor m_v3Movment.z der zu updatende Wert zugewiesen.
4) Loop fürs laufen
- Man kommt in die CPythonCharacterManager::Update Methode (wieder durch app.UpdateGame - CPythonApplication::UpdateGame)
- Es wird für jede lebende Instanz ein Update ausgeführt in CInstanceBase::Update
- Über eine Abfrage hier (IsMovement) wird gefragt, ob eines der Werte in m_v3Movement > 0 sind, falls ja, führt man SetPixelPosition aus und aktualisiert die aktuelle Position des Spielers. (Das ist m_x, m_y und m_z für die Interessierten)
- Weiter im Update Prozess kommt man in die CInstanceBase::MovementProcess und hier wird geprüft
- Man berechnet also auf die Current Pixel Position (im Schritt zuvor gesetzt) die Werte aus m_v3Movement (GetMovementVectorRef) drauf.
- Jetzt finden nach meinem Verständnis Prüfungen statt (1x für mich selbst und 1x für alle anderen Instanzen in meiner Nähe), die berechnen, wie die Instanzen rotieren sollen. Ergo wo der Kopf der Instanzen auf der Overworld hinschaut. Das ist weniger spannend.
- Wieder zurück in der Update-Methode von CPythonCharacterManager prüfen wir ob der Spieler durch das Laufen in eine Blockzone laufen würde oder mit etwas anderem kollidiert (CheckAdvancing), anschließend rufen wir CInstanceBase::Transform auf (wieder für alle lebenden Instanzen).
- Hier wird initial ein Paket gesendet (CPacketCGMove):
damit der Server bescheid weiß, dass der Spieler nun anfängt zu laufen.
- m_GraphicThingInstance.INSTANCEBASE_Transform() -> CActorInstance::TransformProcess -> SetPosition setzt die neuen m_x, m_y und m_z Werte des Spielers (errinert euch von oben, das ist die Current Position) und setzt m_v3Movement (x, y und z) wieder auf 0.
- Diese wird zuletzt bei der CGraphicObjectInstance::Transform Methode genutzt, um die WorldMatrix zu aktualisieren
- Und der Rest der Renderprozesses (sowie der Animationen) ist von Metin bereits implementiert. Erläutere ich hier mal nicht, jeder der aber mal ein Object / Model Scaling System eingebaut hat, ist an all den relevanten Stellen vorbeigekommen.
Ich hab fertig, ich bin fertig und ich brauche eine Pause. Gute Nacht Leute. ;D
Hallo liebe Community,
da ich aktuell mit meinem Latein am Ende bin, dachte ich, ich poste ein Stück Code, welches sich meiner Verständnis entzieht.
Konkret versuche ich zu verstehen, wie Metin2 die Bewegungen des Spielers errechnet. Hier was ich dazu hab:
Warum sorgt die UpdateTransform Methode dafür, dass die Z-Achse (s_matRotationZ._43) sich nie aktualisiert?
Intern ruft diese Methode irgendwann
auf. Leider geht es dann nicht mehr weiter und ich hab keine Doku zu Methoden von Granny2 gefunden, kommentiert ist das auch nicht.
Das Ergebnis ist jedenfalls, dass die X und Y Achse aktualisiert wird (Spieler läuft ja rum, also logisch), die Z-Achse aber unberührt bleibt.
Wie würde man es hinbekommen, dass der Spieler sich "nach oben" bewegt?
Ich kann meine Hintergründe gerne auch verraten, ich versuche mich aktuell an einem Mount Fly System. Habe mir die vorhandenen Lösungen angesehen und diese erweitern das Vorhandene von YMIR nicht, sondern sie führen einfach eine Variable "m_fZExtra" ein und addieren sie in der "AddMovement..." Zeile zur Z-Achse.
Mein Ziel wäre aber ein Verständnis für diesen Prozess aufzubauen und mich da ranzutasten.
Danke für den Wissensaustausch im Voraus.
~Lead
Keine Animation um die Truhe zu öffnen?
Oder so eine coole Animation wie bei Kratos, der einfach die Truhe kaputtschlägt!
Beim Metin2 Ninja wärs dann eher so hier:
Bitte melden Sie sich an, um diesen Link zu sehen.
P.S: Der Sound ist ein geniales Detail
Alles anzeigenAlles anzeigen4) Guards für Anweisungen
Alles anzeigenCode
- LPCHARACTER tch = d ? d->GetCharacter() : NULL;
- if (tch && tch != ch) {
- DESC_MANAGER::instance().DestroyDesc(d);
- ch->ChatPacket(CHAT_TYPE_INFO, "%s banned and kicked", escapePlayer);
- }
- else if (tch && tch == ch) {
- ch->ChatPacket(CHAT_TYPE_INFO, "cannot disconnect myself");
- return;
- }
- else {
- ch->ChatPacket(CHAT_TYPE_INFO, "%s banned", escapePlayer);
- }
könnte man für lesbareren Code auch so schreiben (der Else-Pfad würde sowieso nie erreicht werden oder nur fälschlicherweise wenn tch = NULL wäre):
Alles anzeigenCode
- // disconnect player
- LPDESC d = DESC_MANAGER::instance().FindByCharacterName(escapePlayer);
- LPCHARACTER tch = d ? d->GetCharacter() : NULL;
- if (!tch) {
- ch->ChatPacket(CHAT_TYPE_INFO, "a user by the name (%s) could not be found on this core!", escapePlayer);
- return;
- }
- if (tch == ch) {
- ch->ChatPacket(CHAT_TYPE_INFO, "cannot disconnect myself");
- return;
- }
- DESC_MANAGER::instance().DestroyDesc(d);
- ch->ChatPacket(CHAT_TYPE_INFO, "%s banned and kicked", escapePlayer);
Ein paar finale Hinweise:
- Denk daran, dass das Bannen aktuell nicht Core-übergreifend funktioniert. Sollte der Spieler sich also rechtzeitig wegteleportieren oder ausloggen, hast du womöglich ein Problem.
- In der CInputMain::Analyze befindet sich direkt bei Eintritt folgende Prüfung:
Du kannst also so Prüfungen wie "!ch" oder "!d->GetCharacter()" weglassen, außer du erwartest aus irgendwelchen Gründen, dass der User genau in dieser Milisekunde destroyed wird, in der dieser Code ausgeführt wird. Unmöglich ist nichts, aber dann haben wir größere Probleme als das
- Nach einem 'strncpy' emphielt es sich, explizit die letzte Stelle des Arrays auf '\0' zu setzen, siehe hier:
Weil diese Methode so funktioniert, dass wenn dein Buffer nicht groß genug ist, sie nur "so viele Bytes von src kopiert, wie möglich". Ergo, wenn dein Buffer nur 10 Stellen groß ist, du willst aber 11 kopieren, hört er bei 10 auf. Die 11. Stelle wäre aber das benötigte '\0' gewesen. Mit strlcpy hat man das Problem btw. nicht.
- Dir fehlt die Logik, wenn ein Spieler in einem Dungeon ist und der Gruppenleiter. Das kann dazu führen, dass die Gruppe den Dungeon nicht mehr beenden kann, je nachdem wie die Quest geschrieben ist.
Zum Abschluss:
Ich hoffe, dass es mehr Beiträge wie dieses gibt und das wir weiterhin gute Entwickler in der Szene haben, die so freundlich sind, uns ihre Arbeiten zur Verfügung zu stellen.
~Lead
Hey, danke für deine Prüfung die nicht nötig war. Der Check für tch dient nur zum kicken des Spielers. Gebannt wird er so oder so. Angenommen der Spieler ist nicht Online, wird der Else ausgelöst. Kick läuft über p2p ist die Standart Funktion von Metin. Es sollte definitiv kein Meisterwerk werden. Wie ich bereits sagte nutzt man sowas heutzutage nicht.
Ich suche irgendwie verzweifelt nach dem P2P Paket, welches den Kick ausführt. Hast du dich vielleicht verschrieben?
"Kick läuft über p2p ist die Standart Funktion von Metin"
Das Ergebnis der aktuellen Logik ist:
1) Spieler ist auf Map 1
2) GM bannt Spieler über GUI
3) Spieler teleportiert vorher in einen Dungeon
4) Spieler darf weiterspielen, handeln, chatten, seine Items handeln usw.
Das ist schon nicht minder interessant für Leute, die das "System" verwenden möchten.
Wenn ich was übersehe, dann sags mir ruhig. Kann ja sein.
Nachtrag: In etwa so müsste das eigentlich aussehen..
Alles anzeigenAlles anzeigenHey mein Lieber,
dachte ich nehme mir mal die Zeit und schaue über den Code, was mir dabei aufgefallen ist:
1) Prüfungen auf Ungleichheit mittels == false
Das ist redundant, schöner und kürzer wäre:
2) Magic Numbers
Im Code gibt es häufig irgendwelche rumfliegenden Zahlen, wo man Variablen (Enums, Enum Classes) nutzen sollte.
sollte vermutlich sein:
3) Spieler Namen Query
Diese Query wäre nur dann erfolgreich, wenn es genau einen Spieler gibt, der sich (case insensitiv) gleich nennt.
Beispiel:
- Spieler A nennt sich 'Lead'
- Spieler B nennt sich 'lEad'
- Spieler C nennt sich 'lead'
Frage: Welchen Spieler selected die folgende Query? Bannt man Ausersehen den Falschen?
Es gibt hier nun verschiedene Lösungsansätze, z.B: über die Datenbank ünmöglich zu machen (über einen Constraint), dass die selben Namen genutzt werden (inkl. Groß und Kleinschreibungs-Check). Alternativ würde ich die Query auf Gleichheit prüfen und ohne LIMIT 1, von einem Usernamen wird es nur genau einen geben. Der GM muss dann auf Groß und Kleinschreibung achten.
4) Guards für Anweisungen
Alles anzeigenCode
- LPCHARACTER tch = d ? d->GetCharacter() : NULL;
- if (tch && tch != ch) {
- DESC_MANAGER::instance().DestroyDesc(d);
- ch->ChatPacket(CHAT_TYPE_INFO, "%s banned and kicked", escapePlayer);
- }
- else if (tch && tch == ch) {
- ch->ChatPacket(CHAT_TYPE_INFO, "cannot disconnect myself");
- return;
- }
- else {
- ch->ChatPacket(CHAT_TYPE_INFO, "%s banned", escapePlayer);
- }
könnte man für lesbareren Code auch so schreiben (der Else-Pfad würde sowieso nie erreicht werden oder nur fälschlicherweise wenn tch = NULL wäre):
Alles anzeigenCode
- // disconnect player
- LPDESC d = DESC_MANAGER::instance().FindByCharacterName(escapePlayer);
- LPCHARACTER tch = d ? d->GetCharacter() : NULL;
- if (!tch) {
- ch->ChatPacket(CHAT_TYPE_INFO, "a user by the name (%s) could not be found on this core!", escapePlayer);
- return;
- }
- if (tch == ch) {
- ch->ChatPacket(CHAT_TYPE_INFO, "cannot disconnect myself");
- return;
- }
- DESC_MANAGER::instance().DestroyDesc(d);
- ch->ChatPacket(CHAT_TYPE_INFO, "%s banned and kicked", escapePlayer);
Ein paar finale Hinweise:
- Denk daran, dass das Bannen aktuell nicht Core-übergreifend funktioniert. Sollte der Spieler sich also rechtzeitig wegteleportieren oder ausloggen, hast du womöglich ein Problem.
- In der CInputMain::Analyze befindet sich direkt bei Eintritt folgende Prüfung:
Du kannst also so Prüfungen wie "!ch" oder "!d->GetCharacter()" weglassen, außer du erwartest aus irgendwelchen Gründen, dass der User genau in dieser Milisekunde destroyed wird, in der dieser Code ausgeführt wird. Unmöglich ist nichts, aber dann haben wir größere Probleme als das
- Nach einem 'strncpy' emphielt es sich, explizit die letzte Stelle des Arrays auf '\0' zu setzen, siehe hier:
Weil diese Methode so funktioniert, dass wenn dein Buffer nicht groß genug ist, sie nur "so viele Bytes von src kopiert, wie möglich". Ergo, wenn dein Buffer nur 10 Stellen groß ist, du willst aber 11 kopieren, hört er bei 10 auf. Die 11. Stelle wäre aber das benötigte '\0' gewesen. Mit strlcpy hat man das Problem btw. nicht.
- Dir fehlt die Logik, wenn ein Spieler in einem Dungeon ist und der Gruppenleiter. Das kann dazu führen, dass die Gruppe den Dungeon nicht mehr beenden kann, je nachdem wie die Quest geschrieben ist.
Zum Abschluss:
Ich hoffe, dass es mehr Beiträge wie dieses gibt und das wir weiterhin gute Entwickler in der Szene haben, die so freundlich sind, uns ihre Arbeiten zur Verfügung zu stellen.
~Lead
- Spieler A nennt sich 'Lead'
- Spieler B nennt sich 'lEad'
- Spieler C nennt sich 'lead'
ist doch gar nicht möglich, den selben Namen zu verwenden, wenn er bereits existiert. Hierbei ist die Groß/Kleinschreibung egal. Der Charakter existiert bereits.
Ist das etwas, was Metin bei der Charaktererstellung verbietet?
Dann wäre der Punkt natürlich nichtig.
Wobei dann erst Recht das 'LIMIT 1' weg kann, wenn es sowieso keine Dopplungen gibt.
Hey mein Lieber,
dachte ich nehme mir mal die Zeit und schaue über den Code, was mir dabei aufgefallen ist:
1) Prüfungen auf Ungleichheit mittels == false
Das ist redundant, schöner und kürzer wäre:
2) Magic Numbers
Im Code gibt es häufig irgendwelche rumfliegenden Zahlen, wo man Variablen (Enums, Enum Classes) nutzen sollte.
sollte vermutlich sein:
3) Spieler Namen Query
Diese Query wäre nur dann erfolgreich, wenn es genau einen Spieler gibt, der sich (case insensitiv) gleich nennt.
Beispiel:
- Spieler A nennt sich 'Lead'
- Spieler B nennt sich 'lEad'
- Spieler C nennt sich 'lead'
Frage: Welchen Spieler selected die folgende Query? Bannt man Ausersehen den Falschen?
Es gibt hier nun verschiedene Lösungsansätze, z.B: über die Datenbank ünmöglich zu machen (über einen Constraint), dass die selben Namen genutzt werden (inkl. Groß und Kleinschreibungs-Check). Alternativ würde ich die Query auf Gleichheit prüfen und ohne LIMIT 1, von einem Usernamen wird es nur genau einen geben. Der GM muss dann auf Groß und Kleinschreibung achten.
4) Guards für Anweisungen
könnte man für lesbareren Code auch so schreiben (der Else-Pfad würde sowieso nie erreicht werden oder nur fälschlicherweise wenn tch = NULL wäre):
Ein paar finale Hinweise:
- Denk daran, dass das Bannen aktuell nicht Core-übergreifend funktioniert. Sollte der Spieler sich also rechtzeitig wegteleportieren oder ausloggen, hast du womöglich ein Problem.
- In der CInputMain::Analyze befindet sich direkt bei Eintritt folgende Prüfung:
Du kannst also so Prüfungen wie "!ch" oder "!d->GetCharacter()" weglassen, außer du erwartest aus irgendwelchen Gründen, dass der User genau in dieser Milisekunde destroyed wird, in der dieser Code ausgeführt wird. Unmöglich ist nichts, aber dann haben wir größere Probleme als das
- Nach einem 'strncpy' emphielt es sich, explizit die letzte Stelle des Arrays auf '\0' zu setzen, siehe hier:
Weil diese Methode so funktioniert, dass wenn dein Buffer nicht groß genug ist, sie nur "so viele Bytes von src kopiert, wie möglich". Ergo, wenn dein Buffer nur 10 Stellen groß ist, du willst aber 11 kopieren, hört er bei 10 auf. Die 11. Stelle wäre aber das benötigte '\0' gewesen. Mit strlcpy hat man das Problem btw. nicht.
- Dir fehlt die Logik, wenn ein Spieler in einem Dungeon ist und der Gruppenleiter. Das kann dazu führen, dass die Gruppe den Dungeon nicht mehr beenden kann, je nachdem wie die Quest geschrieben ist.
Zum Abschluss:
Ich hoffe, dass es mehr Beiträge wie dieses gibt und das wir weiterhin gute Entwickler in der Szene haben, die so freundlich sind, uns ihre Arbeiten zur Verfügung zu stellen.
~Lead
Entweder die meisten sind vom Verständigkeitsgott geküsst worden oder ich verstehe dein genaues Problem / Ansatzpunkt nicht anhand deiner Erklärung / Skizzierung. Du hast ein Fehler bemerkt, aufgrund von?
Einer falschen Konfiguration auf meiner Seite.
Das Finding hat mich viel Zeit gekostet, das Fixen war nicht so wild.
Konkret hab ich in meiner serverinfo.py den Main-Port sagen wir A eingetragen, ein Core zu diesem Port existierte aber nicht. Also hat man eine "Fehler beim Verbinden mit dem Server" Meldung bekommen, nach dem initialen "Anmeldevorgang läuft". Der Output von Metin2 in diesem Case (auf dem Auth Core) ist:
Weiter passierte nichts. Und auf der Suche nach dem Fehler hab ich gemerkt, dass ich den gesamten Prozess zunächst einmal überblicken können muss, bevor ich weiß warum es an dieser Stelle nicht weiter geht. Ich wüsste sonst überhaupt nicht, wo ich ansetzen soll und blind suchen, wollte ich nicht - Das ist meist deprimierend und nicht von Erfolg gekrönt.
Wie so häufig ist aber eine falsche Konfiguration die häufigste Fehlerursache. Und jetzt kommts:
Wenn ein Socket nicht erreichbar ist, hat die WSAGetLastError-Methode der winsock Library folgende Fehler-ID ausgegeben:
und nicht wie erwartet
Und was macht Metin bei dieser Fehler ID? Genau, sie ignorieren und nichts loggen!
Hoffe das genügt dir als Abriss, was meine Intention war bei dem Vorgehen.
Hallo liebe Community,
ich habe gerade mal wieder Lust bekommen, mich auf meinem Server einzuloggen (lokal) und bin in ein Problem beim Loginprozess gestoßen.
Leider gab es keine hilfreiche sys_err, nur irgendwann das Resultat "closing socket..." vom Auth Core.
Also hab ich mich entschieden mal den Login-Prozess zu skizzieren und konnte meinen Fehler dadurch finden und fixen.
Vielleicht hilft es ja dem Einen oder Anderen von euch auch. Es gab leider keinen Bereich "Architektur" oder sowas Ähnliches für solche Bildchen.
Bitte melden Sie sich an, um diesen Anhang zu sehen.
Was in dem Bild fehlt:
- Abläufe im DB-Core (QID_LOGIN_BY_KEY -> QID_LOGIN im Erfolgsfall usw.)
- Master / Slave Konzept für den Auth-Core
- Vorgänge im Client (speichert intern einen State usw.)
~Lead
So wie du das hier machst, lädst du die aber nur auf der Core neu, auf der du gerade bist.
Besser wäre per P2P Packet alle Cores darüber zu verständigen, sodass du z.B: auf Map 1 Blau die selben "Ergebnisse" bekommst wie auf Map 1 Gelb*.
* vorausgesetzt sie befinden sich auf verschiedenen Cores
Überprüf sonst noch mal was von GetGold zurück kommt, ggf. hab ich da irgendwo was vergessen.
Wollte gerade kommentieren, dass im Code eine Prüfung für das Gold des Spielers fehlt, weil man sonst auch ohne genug Gold pullen kann, hab aber dann das gesehen. Good catch!
Erklärung warum deine vorherige Lösung "nicht geklappt hat":
SetGold setzt zwar das Gold auf Serverseite, sendet dem Client aber kein Paket zur Aktualisierung. Mit PointChange(POINT_GOLD, -100) wird dieses Paket gesendet
Würde nur die Verteilung von ToxiC nochmal etwas anpassen. Ich behaupte Metin2 ist:
40% Python
30% Lua
20% C / C++
10% SQL
Also rein von der zeitlichen Verteilung wirst du viel eher am Python Code sitzen, durch das Ganze designen und austesten oder eine Quest schreiben / verbessern,
als jetzt ein neues System in C / C++ zu implementieren oder speziellen Items eine Funktion zu geben. Besonders wenn du ein Oldschool Server bist, fummelst du kaum am Backend herum, oder baust nur vorhandene Systeme ein die durch die ganzen Server gut getestet sind.
- Unlimited support about systems and solutions.
You will hate yourself in some months for writing that down. You probably don't know your customers well enough
So? How is it going?
Klingt crazy ich weiß, aber Daten gehören in eine Datenbank.
Das mit dem Rain Environment kann man sogar noch schöner machen. Statt einem statischen Bild, lädst du 3 Effekte:
- Regen anfang
- Regen fällt
- Regen trifft auf dem Boden auf
Sieht dann unglaublich schön aus, aber bringt leider bei zu vielen Effekten den Clienten zum Laggen.
Marty wrote a good explanation on another board about this issue. Just make sure, that your coordinates are an even divisible of 1024. Soo:
Good example: 307200 76800 (307200 % 1024 is 0 and 76800 % 1024 is 0)Bad example: 987600 1234000
This issue was not related to the server_attr generation.
I've already had a very lengthy conversation with Marty explaining this to me. Nevertheless I still have problems with the Block-Zones.
You shouldn't if you did it right.
That's the fix. Maybe you show us the Settings.txt of the map that still has the problems?
Or better: Check your atlasinfo.txt and your serverside maps.
martysama0134 Could you please fix the server_attr generation?
Blockzones are just not loaded in game correctly and there is no real alternative at the moment.
Anyone still having trouble with this?
Marty wrote a good explanation on another board about this issue. Just make sure, that your coordinates are an even divisible of 1024. Soo:
Good example: 307200 76800 (307200 % 1024 is 0 and 76800 % 1024 is 0)
Bad example: 987600 1234000
This issue was not related to the server_attr generation.