Blockspiel
Weitere lua geschichten.

Erstmal konnte ich nun dank studieren des LUA manuals und Sicherheitsnachfragem im englischen Forum endlich voll durchblicken was es mit dem ganzen State und stack und so weiter auf sich hat.
Im das ganze push und pop ist im grunde wenn man erstmal dahinter gestiegen ist ähnlich simpel wie die OpenGL push und popperei
So konnte ich nun z.B. den code der eine funktion in lua aufruft nun so gestalten:
Code: [AUSKLAPPEN]
lua_getglobal(Lua.l, "on_mapGenerate") '<-------------- 1
If Not lua_isfunction(Lua.L, -1) Then '<-------------- 2
Print "Warning! map:" + toGenerate.name + " script:" + toGenerate.source + " hat keine on_mapGenerate function!"
lua_pop(Lua.L, 1)
Return
EndIf
lua_pushbmaxobject(Lua.l, toGenerate.LuaInterfaceMap) '<-------------- 3
lua_pcall(Lua.l, 1, 0, 0) '<-------------- 4
1: Erstmal schieben wir die globale "on_mapGenerate" auf den stack.
2: Dann prüfen wir mit lua_isfunction ob es sich bei dem was gerade auf dem stack ist um eine funktion handelt.
3: Dann schieben wir das map object hinterher.
4: Hier rufen wir die funktion auf, mit 1 parameter und 0 rückgabewerten.
Funktioniert alles ganz gut nun, und so habe ich die ersten funktionen und objekte eingbaut mit denen man von Lua aus das spielgeschehen beinflussen kann, da dies garnichtmal so wenige sind und im laufe der zeit sicher mehr werden, habe ich dafür ein google doc angelegt, wer mag kann es sich ja einmal anschauen:
https://docs.google.com/spread...UY3c#gid=0
Alle mit X markierten Einträge sind bereits eingebaut und Getestet.
Um das ganze besser debuggen zu können habe ich einen neuen server befehl eingebaut:
/script <file>
damit kann man vom clienten aus ein script (aus einer datei) auf dem server ausführen um so die scripte und auch die funktionen auf der blitzmax seite zu überprüfen, oder sich eben mal ein paar HP dazu zu cheaten ;D.
Dies ganze habe ich hier mit diesem lua script mal verdeutlicht:
Code: [AUSKLAPPEN]
-- Player mit ID 0 holen:
local player = GetPlayer(0)
-- einen text dem spieler schicken:
player:SendNotify ("deine maximalen hp:"..player:GetMaxHP())
player:SendNotify ("deine aktuellen hp:"..player:GetCurrentHP())
-- die map auf dem der spieler ist holen:
map = player:GetMap()
-- Das licht der map ändern:
map:SetAmbientLight(64,64,64)
map:SetSun(255,128,128,45,21)
-- dem player den namen der map sagen, auf der er ist:
player:SendNotify ("du bist auf der map:"..map:GetName())
-- dem Player seine HP voll aufladen:
player:SetCurrentHP(player:GetMaxHP())
Dies ist ist vor der ausführung:
Der obligatorische HP balken ist fast runter, und das licht ist Recht hell eingestellt (so wie es aus dem .map file gelesen wurde)
Nach einem druck auf enter, sieht es dann so aus:
Das licht wurde verstellt (sonne und ambient)
Es wurden nachrichten an den spieler gesandt, und seine HP aufgeladen.
Das Script wurde serverseitig ausgefürt und sämtliche infos an den clienten übertragen.
Als nächstes werde ich nun mich damit befassen eine art event system zu bauen, und bestimmte funktionen immer aufrufen wenn etwas passiert, also so etwas wie on_PlayerDie(player) wenn jemand gestorben ist usw.
Auserdem möchte ich ein paar grundlegende gui-fenster vom server senden können mittels lua, und entsprechende events auslösen wenn ein user auf eines dieser reagiert.
Erstmal so simple dinge wie eine message senden oder eine frage stellen die man mit ja/nein beantworten kann.
Im das ganze push und pop ist im grunde wenn man erstmal dahinter gestiegen ist ähnlich simpel wie die OpenGL push und popperei

So konnte ich nun z.B. den code der eine funktion in lua aufruft nun so gestalten:
Code: [AUSKLAPPEN]
lua_getglobal(Lua.l, "on_mapGenerate") '<-------------- 1
If Not lua_isfunction(Lua.L, -1) Then '<-------------- 2
Print "Warning! map:" + toGenerate.name + " script:" + toGenerate.source + " hat keine on_mapGenerate function!"
lua_pop(Lua.L, 1)
Return
EndIf
lua_pushbmaxobject(Lua.l, toGenerate.LuaInterfaceMap) '<-------------- 3
lua_pcall(Lua.l, 1, 0, 0) '<-------------- 4
1: Erstmal schieben wir die globale "on_mapGenerate" auf den stack.
2: Dann prüfen wir mit lua_isfunction ob es sich bei dem was gerade auf dem stack ist um eine funktion handelt.
3: Dann schieben wir das map object hinterher.
4: Hier rufen wir die funktion auf, mit 1 parameter und 0 rückgabewerten.
Funktioniert alles ganz gut nun, und so habe ich die ersten funktionen und objekte eingbaut mit denen man von Lua aus das spielgeschehen beinflussen kann, da dies garnichtmal so wenige sind und im laufe der zeit sicher mehr werden, habe ich dafür ein google doc angelegt, wer mag kann es sich ja einmal anschauen:
https://docs.google.com/spread...UY3c#gid=0
Alle mit X markierten Einträge sind bereits eingebaut und Getestet.
Um das ganze besser debuggen zu können habe ich einen neuen server befehl eingebaut:
/script <file>
damit kann man vom clienten aus ein script (aus einer datei) auf dem server ausführen um so die scripte und auch die funktionen auf der blitzmax seite zu überprüfen, oder sich eben mal ein paar HP dazu zu cheaten ;D.
Dies ganze habe ich hier mit diesem lua script mal verdeutlicht:
Code: [AUSKLAPPEN]
-- Player mit ID 0 holen:
local player = GetPlayer(0)
-- einen text dem spieler schicken:
player:SendNotify ("deine maximalen hp:"..player:GetMaxHP())
player:SendNotify ("deine aktuellen hp:"..player:GetCurrentHP())
-- die map auf dem der spieler ist holen:
map = player:GetMap()
-- Das licht der map ändern:
map:SetAmbientLight(64,64,64)
map:SetSun(255,128,128,45,21)
-- dem player den namen der map sagen, auf der er ist:
player:SendNotify ("du bist auf der map:"..map:GetName())
-- dem Player seine HP voll aufladen:
player:SetCurrentHP(player:GetMaxHP())
Dies ist ist vor der ausführung:
Der obligatorische HP balken ist fast runter, und das licht ist Recht hell eingestellt (so wie es aus dem .map file gelesen wurde)

Nach einem druck auf enter, sieht es dann so aus:
Das licht wurde verstellt (sonne und ambient)
Es wurden nachrichten an den spieler gesandt, und seine HP aufgeladen.

Das Script wurde serverseitig ausgefürt und sämtliche infos an den clienten übertragen.
Als nächstes werde ich nun mich damit befassen eine art event system zu bauen, und bestimmte funktionen immer aufrufen wenn etwas passiert, also so etwas wie on_PlayerDie(player) wenn jemand gestorben ist usw.
Auserdem möchte ich ein paar grundlegende gui-fenster vom server senden können mittels lua, und entsprechende events auslösen wenn ein user auf eines dieser reagiert.
Erstmal so simple dinge wie eine message senden oder eine frage stellen die man mit ja/nein beantworten kann.
Lua->LuGi

So nun mal ein neuer bericht =)
Das WE über hatte ich nicht soviel zeit aber heute dann wieder ein wenig.
Erstmal habe ich das Lua zeug nochmal überarbeitet und es mit Lugi und dem mitgelieferten reflection code vorgenerator cooler lösen können.
Dazu habe ich die leute im Blitzbasic.com forum leicht belasten müssen.
Mehrere Maps können sich nun ein LUA script teilen, es wird dann immer die function
on_mapGenerate(map) in lua aufgerufen, und die map übergeben die gerade generiert werden soll.
Möchte man trozdem verschiedene map generatoren für die maps verwenden kann man entweder in der .map datei verschiedene .lua dateien angeben, oder aber in seiner on_mapGenerate funktion am anfang den namen der map sich ausgeben lassen und anhand dessen entscheiden.
map hat die methoden:
map:GetSizeX()
map:GetSizeY()
map:GetSizeZ()
map:GetName()
map:GetBlock(x,y,z)
map:SetBlock(x,y,z,b)
map:GetAmbientR()
map:GetAmbientG()
map:GetAmbientB()
map:SetAmbient(r,g,b)
map:GetSunG()
map:GetSunB()
map:SetSun(r,g,b)
map:GetSunYaw()
map:GetSunPitch()
map:SetSunAngle(Yaw,Pitch)
Damit kann man eine map erstellen und auch die beleuchtung ändern.
Das mapscript aus dem letzten worklog beitrag sieht nun so aus:
Code: [AUSKLAPPEN]
function on_mapGenerate(map)
print ("------------------- START MAP GENERATE -----------------------")
if map == nil then
print ("map was nil :(")
else
-- map generierungs script
print("creating map: flatworld")
-- Die größe der map ermitteln:
local sx = map:GetSizeX()
local sy = map:GetSizeY()
local sz = map:GetSizeZ()
-- eine bodenplatte erstellen aus erde (1):
for x = 0, sx, 1 do
for z = 0, sz, 1 do
map:SetBlock(x,0,z,1)
end
end
-- nun ein paar türme in der landschaft verteilen:
for count = 0, 400, 1 do -- 400 türme setzen
--zufällige position
local rx = math.random(0,sx)
local rz = math.random(0,sz)
--zufällige turmhöhe zwischen 1 und 5
local height = math.random(0,5)
--zufällige block id zwischen 1 und 10 woraus der turm wird
local block = math.random(1,5)
--diesen turm bauen
for thisheight = 0 ,height,1 do
map:SetBlock(rx,thisheight,rz,block)
end
end
end
print ("------------------- END MAP GENERATE ------------------------")
end
Das ganze zu machen war ein bischen tricky, also mit der object übergabe an eine funktion.
Dafür habe ich dieses type angelegt
Code: [AUSKLAPPEN]
Type LuaFunctions {expose static noclass}
'gibt die map zurück für den namen, oder nil wenn es keine gibt.
Method GetMapForName:map(mapname:String)
Local smap:map = ActualScenario.GetMapForName(mapname).LuaInterfaceMap
Return(smap)
End Method
End Type
das noclass sagt dem gluecode generator, das dieses type in lua nicht existieren, und die methoden dann in lua als funktionen auftauchen.
um das oben gesehene lua dann zu starten und auch die funktion aufzurufen bedarf es dann nurnoch dem in der erstellungsmethode der map (also in bmx):
Lua.DoString("on_mapGenerate(GetMapForName(~q" + Self.Name + "~q))")
Gute nacht!
Das WE über hatte ich nicht soviel zeit aber heute dann wieder ein wenig.
Erstmal habe ich das Lua zeug nochmal überarbeitet und es mit Lugi und dem mitgelieferten reflection code vorgenerator cooler lösen können.
Dazu habe ich die leute im Blitzbasic.com forum leicht belasten müssen.
Mehrere Maps können sich nun ein LUA script teilen, es wird dann immer die function
on_mapGenerate(map) in lua aufgerufen, und die map übergeben die gerade generiert werden soll.
Möchte man trozdem verschiedene map generatoren für die maps verwenden kann man entweder in der .map datei verschiedene .lua dateien angeben, oder aber in seiner on_mapGenerate funktion am anfang den namen der map sich ausgeben lassen und anhand dessen entscheiden.
map hat die methoden:
map:GetSizeX()
map:GetSizeY()
map:GetSizeZ()
map:GetName()
map:GetBlock(x,y,z)
map:SetBlock(x,y,z,b)
map:GetAmbientR()
map:GetAmbientG()
map:GetAmbientB()
map:SetAmbient(r,g,b)
map:GetSunG()
map:GetSunB()
map:SetSun(r,g,b)
map:GetSunYaw()
map:GetSunPitch()
map:SetSunAngle(Yaw,Pitch)
Damit kann man eine map erstellen und auch die beleuchtung ändern.
Das mapscript aus dem letzten worklog beitrag sieht nun so aus:
Code: [AUSKLAPPEN]
function on_mapGenerate(map)
print ("------------------- START MAP GENERATE -----------------------")
if map == nil then
print ("map was nil :(")
else
-- map generierungs script
print("creating map: flatworld")
-- Die größe der map ermitteln:
local sx = map:GetSizeX()
local sy = map:GetSizeY()
local sz = map:GetSizeZ()
-- eine bodenplatte erstellen aus erde (1):
for x = 0, sx, 1 do
for z = 0, sz, 1 do
map:SetBlock(x,0,z,1)
end
end
-- nun ein paar türme in der landschaft verteilen:
for count = 0, 400, 1 do -- 400 türme setzen
--zufällige position
local rx = math.random(0,sx)
local rz = math.random(0,sz)
--zufällige turmhöhe zwischen 1 und 5
local height = math.random(0,5)
--zufällige block id zwischen 1 und 10 woraus der turm wird
local block = math.random(1,5)
--diesen turm bauen
for thisheight = 0 ,height,1 do
map:SetBlock(rx,thisheight,rz,block)
end
end
end
print ("------------------- END MAP GENERATE ------------------------")
end
Das ganze zu machen war ein bischen tricky, also mit der object übergabe an eine funktion.
Dafür habe ich dieses type angelegt
Code: [AUSKLAPPEN]
Type LuaFunctions {expose static noclass}
'gibt die map zurück für den namen, oder nil wenn es keine gibt.
Method GetMapForName:map(mapname:String)
Local smap:map = ActualScenario.GetMapForName(mapname).LuaInterfaceMap
Return(smap)
End Method
End Type
das noclass sagt dem gluecode generator, das dieses type in lua nicht existieren, und die methoden dann in lua als funktionen auftauchen.
um das oben gesehene lua dann zu starten und auch die funktion aufzurufen bedarf es dann nurnoch dem in der erstellungsmethode der map (also in bmx):
Lua.DoString("on_mapGenerate(GetMapForName(~q" + Self.Name + "~q))")
Gute nacht!
Erste schritte mit luajit

Heute nacht hatte ich dann noch etwas zeit, um mich mal mit Lua herumzuärgern.
Meine Funktion welche einfach ein lua file ausführen soll sieht so aus:
Code: [AUSKLAPPEN]
Function RunLuaFile(file:String)
lua_dofile(luastate, file)
lua_getfield(luastate, LUA_GLOBALSINDEX, "debug")
lua_getfield(luastate, -1, "traceback")
lua_remove (luastate, -2)
If (lua_pcall(luastate, 1, -1, -1)) <> 0 Then
Print "LUA ERROR:" + lua_tostring(luastate, -1)
End If
End Function
soweit funktioniert sie auch gut, die habe ich aus irgendeinem sample abgeschaut.
das einzigste problem war, das es fehler ausgibt obwohl alles zu gehen scheint.
eine datei mit diesem inhalt:
Code: [AUSKLAPPEN]
gab das aus:
Code: [AUSKLAPPEN]
test
LUA ERROR:attempt to call a nil value
stack traceback:
Hm, komisch^^
scheinbar gehts, test wird geprintet, aber irgendwie gibt es angebloch noch ein "attempt to call a nil value" ?
hm vieleicht hat das " am ende vom print ja noch heimlich seine freunde gerufen, so weit war ich schon am herumprobieren das ich die Äpfel in meinem kühlschrank umsoritert habe um zu sehen ob es einen einfluss hat.
egal ob ich es mit luaL_loadstring oder als datei mit dofile oder mit dostring oder sogar mit keinem apfel im kühlschrank machte, immer kam das dabei heraus.
Dann hab ich aber den fehler gefunden, und zwar lag es an meinem lua init dingsie
ich verwendete zwar
luaL_openlibs(luastate)
nicht aber:
luaopen_base(luastate)
aufjedenfall geht es nun =)
In den anleitungen die ich gelesen habe wurde immer nur das eine oder das andere verwendet, ich hab nun einfach beides und es geht.
Dies sind nun meine Funktionen die ich benutze
Code: [AUSKLAPPEN]
Global luastate:Byte ptr
Global State:Int = 0
'lua VM erstellen
Function Init()
Deinit() 'es kann nur eine vm geben.
luastate = luaL_newstate()
State = 1
luaL_openlibs(luastate)
luaopen_base(luastate)
End Function
'lua VM schliesen
Function Deinit()
If State = 1 Then lua_close(luastate)
State = 0
End Function
'summary: führt eine string als lua aus.
Function RunLua(Script:String)
lua_dostring(luastate, Script)
'irgendetwas wichtiges machen das man für die error info braucht:
lua_getfield(luastate, LUA_GLOBALSINDEX, "debug")
lua_getfield(luastate, -1, "traceback")
lua_remove (luastate, -2)
'ausführen und ggf fehlermeldung ausgeben
If (lua_pcall(luastate, 1, -1, -1)) <> 0 Then
Print "LUA ERROR:" + lua_tostring(luastate, -1)
End If
End Function
'summary: lädt eine datei und führt sie aus
Function RunLuaFile(file:String)
lua_dofile(luastate, file)
'irgendetwas wichtiges machen das man für die error info braucht:
lua_getfield(luastate, LUA_GLOBALSINDEX, "debug")
lua_getfield(luastate, -1, "traceback")
lua_remove (luastate, -2)
'ausführen und ggf fehlermeldung ausgeben
If (lua_pcall(luastate, 1, -1, -1)) <> 0 Then
Print "LUA ERROR:" + lua_tostring(luastate, -1)
End If
End Function
so ganz hab ich das zwar immernoch nicht geschnallt, was das alles macht:
lua_getfield(luastate, LUA_GLOBALSINDEX, "debug")
lua_getfield(luastate, -1, "traceback")
lua_remove (luastate, -2)
aber irgendwann werde ich schon dahintersteigen^^
Immerhin hab ich nach einer weile herausgefunden das ich ja schon bei dofile die ausführung gemacht habe und der pcall am ende eigentlich quatsch war.
dofile scheint wohl einfach eine kombination aus
luaL_loadfile und lua_pcall zu sein?
so Funktioniert es nun:
(malsehen wie lange^^)
Code: [AUSKLAPPEN]
'summary: lädt eine datei und führt sie aus
Function RunLuaFile(file:String)
luaL_loadfile(luastate, file)
' 'irgendetwas wichtiges machen das man für die error info braucht:
lua_getfield(luastate, LUA_GLOBALSINDEX, "debug")
lua_getfield(luastate, -1, "traceback")
lua_remove (luastate, -2)
'ausführen und ggf fehlermeldung ausgeben
If (lua_pcall(luastate, 1, -1, -1)) <> 0 Then
Print "LUA ERROR:" + lua_tostring(luastate, -1)
End If
End Function
Ein paar einfach funktionen habe ich nun schon gewrappt (nennt man das so bei lua?):
getmapsize() returnt 3 werte welche die map größe angeben, welche in der .map datei angegeben ist
setblock(x,y,z,blockID) setzt einen block an position XYZ
getblock(x,y,z) gibt zurück welcher block sich gerade an xyz befindet.
das ist ja schonmal ein anfang oder?
Dieses kleine map erzeugungs script habe ich zum testen geschrieben:
Code: [AUSKLAPPEN]
-- map generierungs script
print("creating map: flatworld")
-- Die größe der map ermitteln:
local sx,sy,sz = getmapsize()
-- eine bodenplatte erstellen aus erde (1):
for x = 0, sx, 1 do
for z = 0, sz, 1 do
setblock(x,0,z,1)
end
end
-- nun ein paar türme in der landschaft verteilen:
for count = 0, 400, 1 do -- 400 türme setzen
--zufällige position
local rx = math.random(0,sx)
local rz = math.random(0,sz)
--zufällige turmhöhe zwischen 1 und 5
local height = math.random(0,5)
--zufällige block id zwischen 1 und 10 woraus der turm wird
local block = math.random(1,15)
--diesen turm bauen
for thisheight = 0 ,height,1 do
setblock(rx,thisheight,rz,block)
end
end
nachdem ich dieses script ins map file eingetragen habe:
source=test.lua
und ich dann im editor auf "Lua ausführen" geklickt habe, präsentierte sich mir folgendes bild:
Das fand ich toll, angemessen um nun beruhigt schlafen zu gehen
Meine Funktion welche einfach ein lua file ausführen soll sieht so aus:
Code: [AUSKLAPPEN]
Function RunLuaFile(file:String)
lua_dofile(luastate, file)
lua_getfield(luastate, LUA_GLOBALSINDEX, "debug")
lua_getfield(luastate, -1, "traceback")
lua_remove (luastate, -2)
If (lua_pcall(luastate, 1, -1, -1)) <> 0 Then
Print "LUA ERROR:" + lua_tostring(luastate, -1)
End If
End Function
soweit funktioniert sie auch gut, die habe ich aus irgendeinem sample abgeschaut.
das einzigste problem war, das es fehler ausgibt obwohl alles zu gehen scheint.
eine datei mit diesem inhalt:
Code: [AUSKLAPPEN]
print("test")
gab das aus:
Code: [AUSKLAPPEN]
test
LUA ERROR:attempt to call a nil value
stack traceback:
Hm, komisch^^
scheinbar gehts, test wird geprintet, aber irgendwie gibt es angebloch noch ein "attempt to call a nil value" ?
hm vieleicht hat das " am ende vom print ja noch heimlich seine freunde gerufen, so weit war ich schon am herumprobieren das ich die Äpfel in meinem kühlschrank umsoritert habe um zu sehen ob es einen einfluss hat.
egal ob ich es mit luaL_loadstring oder als datei mit dofile oder mit dostring oder sogar mit keinem apfel im kühlschrank machte, immer kam das dabei heraus.
Dann hab ich aber den fehler gefunden, und zwar lag es an meinem lua init dingsie
ich verwendete zwar
luaL_openlibs(luastate)
nicht aber:
luaopen_base(luastate)
aufjedenfall geht es nun =)
In den anleitungen die ich gelesen habe wurde immer nur das eine oder das andere verwendet, ich hab nun einfach beides und es geht.
Dies sind nun meine Funktionen die ich benutze
Code: [AUSKLAPPEN]
Global luastate:Byte ptr
Global State:Int = 0
'lua VM erstellen
Function Init()
Deinit() 'es kann nur eine vm geben.
luastate = luaL_newstate()
State = 1
luaL_openlibs(luastate)
luaopen_base(luastate)
End Function
'lua VM schliesen
Function Deinit()
If State = 1 Then lua_close(luastate)
State = 0
End Function
'summary: führt eine string als lua aus.
Function RunLua(Script:String)
lua_dostring(luastate, Script)
'irgendetwas wichtiges machen das man für die error info braucht:
lua_getfield(luastate, LUA_GLOBALSINDEX, "debug")
lua_getfield(luastate, -1, "traceback")
lua_remove (luastate, -2)
'ausführen und ggf fehlermeldung ausgeben
If (lua_pcall(luastate, 1, -1, -1)) <> 0 Then
Print "LUA ERROR:" + lua_tostring(luastate, -1)
End If
End Function
'summary: lädt eine datei und führt sie aus
Function RunLuaFile(file:String)
lua_dofile(luastate, file)
'irgendetwas wichtiges machen das man für die error info braucht:
lua_getfield(luastate, LUA_GLOBALSINDEX, "debug")
lua_getfield(luastate, -1, "traceback")
lua_remove (luastate, -2)
'ausführen und ggf fehlermeldung ausgeben
If (lua_pcall(luastate, 1, -1, -1)) <> 0 Then
Print "LUA ERROR:" + lua_tostring(luastate, -1)
End If
End Function
so ganz hab ich das zwar immernoch nicht geschnallt, was das alles macht:
lua_getfield(luastate, LUA_GLOBALSINDEX, "debug")
lua_getfield(luastate, -1, "traceback")
lua_remove (luastate, -2)
aber irgendwann werde ich schon dahintersteigen^^
Immerhin hab ich nach einer weile herausgefunden das ich ja schon bei dofile die ausführung gemacht habe und der pcall am ende eigentlich quatsch war.
dofile scheint wohl einfach eine kombination aus
luaL_loadfile und lua_pcall zu sein?
so Funktioniert es nun:
(malsehen wie lange^^)
Code: [AUSKLAPPEN]
'summary: lädt eine datei und führt sie aus
Function RunLuaFile(file:String)
luaL_loadfile(luastate, file)
' 'irgendetwas wichtiges machen das man für die error info braucht:
lua_getfield(luastate, LUA_GLOBALSINDEX, "debug")
lua_getfield(luastate, -1, "traceback")
lua_remove (luastate, -2)
'ausführen und ggf fehlermeldung ausgeben
If (lua_pcall(luastate, 1, -1, -1)) <> 0 Then
Print "LUA ERROR:" + lua_tostring(luastate, -1)
End If
End Function
Ein paar einfach funktionen habe ich nun schon gewrappt (nennt man das so bei lua?):
getmapsize() returnt 3 werte welche die map größe angeben, welche in der .map datei angegeben ist
setblock(x,y,z,blockID) setzt einen block an position XYZ
getblock(x,y,z) gibt zurück welcher block sich gerade an xyz befindet.
das ist ja schonmal ein anfang oder?
Dieses kleine map erzeugungs script habe ich zum testen geschrieben:
Code: [AUSKLAPPEN]
-- map generierungs script
print("creating map: flatworld")
-- Die größe der map ermitteln:
local sx,sy,sz = getmapsize()
-- eine bodenplatte erstellen aus erde (1):
for x = 0, sx, 1 do
for z = 0, sz, 1 do
setblock(x,0,z,1)
end
end
-- nun ein paar türme in der landschaft verteilen:
for count = 0, 400, 1 do -- 400 türme setzen
--zufällige position
local rx = math.random(0,sx)
local rz = math.random(0,sz)
--zufällige turmhöhe zwischen 1 und 5
local height = math.random(0,5)
--zufällige block id zwischen 1 und 10 woraus der turm wird
local block = math.random(1,15)
--diesen turm bauen
for thisheight = 0 ,height,1 do
setblock(rx,thisheight,rz,block)
end
end
nachdem ich dieses script ins map file eingetragen habe:
source=test.lua
und ich dann im editor auf "Lua ausführen" geklickt habe, präsentierte sich mir folgendes bild:

Das fand ich toll, angemessen um nun beruhigt schlafen zu gehen

Blocktechnik

Heute habe ich mal einen versuch gewagt die ganze Struktur hinter meinem Blocksystem zu überarbeiten und dafür ein kleines tool zu schreiben um die "blocksets" zu bearbeiten, und ein älteres tool nochmal ein wenig zu überarbeiten.
Was ist ein blockset?
Ein blockset ist ein steuerfile (ini abart) in welchem gespeichert ist wie die blöcke aussehen.
Hiermit sind nicht die mesh daten selbst gemeint, sondern eher eine art "compilation" wie diese dargestellt werden.
Es ist schwer das in sinvoller reihenfolge zu erklären, aber ich versuchs einfach mal =)
Ein block, den man in der blockmap sehen kann besteht aus mehreren komponenten/werten:
+ Blockmesh
+ MaterialID
+ Texturverschiebung
+ BlockFamily
Diese werden dann zusammengefast und daraus ermittelt wie die surface´s welche die map darstellen zusammengesetzt werden müssen.
Dies ist ein tatsächlicher blockaufbau:
Code: [AUSKLAPPEN]
[BLOCK:131]
name=erde mit grass
mesh0=block_1f
tsy0=0.1250
tsx0=0.0
mesh1=bush
tsy1=0.0
tsx1=0.0
family=ground
mesh0 und mesh1? also 2 meshes?
Sozusagen ja, jeder materialID kann ein mesh zugeordnet werden.
die Material ID
Dies sind nur ein paar zeilen im steuerfile die angeben wie das material aussieht,
in dem .mat file befinden sich weitere infos wie texturen, shader einstellungen, und so weiter (dies ist von leadwerks)
Code: [AUSKLAPPEN]
[MATERIAL:0]
file=default.mat
clipping=true
texfilter=nearest
anhand von MATERIAL:X wird das material unter der ID X registriert.
Wenn ein block dieses material verwendet, hat er einen eintrag als meshX= verwendet der block dieses material nicht gibt es diesen eintrag einfach nicht.
das clipping=true gibt an, ob blöcke die mit diesem material gebaut werden später eine physix body bekommen, bzw ob ihre triangles in den clipping tree aufgenommen werden.
Normalerweise wird es wohl nur 2 material IDs geben, eine für den boden, wände etc, alles was clipping hat, und eine für alles was kein clipping hat (büsche, und son zeug).
Aber theoretisch kann man auch z.B. eine dritte einbauen wenn man möchte das einige teile von blöcken einen glüh effekt haben (via einen shader dann) oder was man immer auch machen möchte.
das Blockmesh,
Ein blockmesh bastelt man einfach in Blender zusammen, und exportiert es als .ply, mit einem kleinen speziellen konverter wird dieses dann in ein eigenes 3d format namens .blo umgewandelt.
Warum das sein muss, und man nicht einfach direkt .ply oder gmf oder sonst ein anderes 3d format direkt nutzen kann liegt daran das in dem .blo noch weitere extra werte gespeichert werden, die indem konverter gesetzt werden müssen. Z.B. muss für Tri´s die sich am "blockrand" befinden ein side indicator eingegeben werden, damit tris die man eh nie sehen würde nachher beim zusammenbauen der surface ausgefiltert werden können.
Dies ist der sogenannte konverter:
Dieses ding ist sehr improvisiert, aber es tut seinen job.
anhand der eintrages im steuerfile:
mesh0=block_1f
mesh1=bush
Ist also nun bekannt das dieser block das material 0 für block_1f.blo verwendet.
und das material 1 für bush.blo verwendet wird.
texturverschiebung?
da ich es beknackt finden würde für jedes mögliche block ein eigenes .blo zu machen nur um die uv map anzupassen, gibt es die möglichkeit die gesamte UV map eines blockes einfach zu verschieben.
Das heist in blender muss man die UV map immer oben in der linken ecke erstellen:
Dies ist ein block mit 3 seitentexturen (oben,alle 4 seiten, unten) (wie bei minecraft z.B. dirt)
durch
Code: [AUSKLAPPEN]
tsy0=0.1250
tsx0=0.0
wird die UV map aber nun nach unten verschoben um 0.1250 einheiten
das sieht dann so aus:
Verschieben wir sie noch einmal um 0.0625 einheiten weiter nach unten sieht es schon ganz anders aus:
(0.0625 entsprechen 64 pixel in meiner 1024x1024 textur) die werte werden in float angegeben damit sie unabhänig von der textur auflösung sind und man verschiedene textur auflösungen verwenden kann.
Dies klappt mit jeder erdenklichen form die man in blender baut, also es müssen nicht immer blöcke sein, theoretisch geht es mit jeder form (zuhoch sollte der tri count aber nicht gehen) wenn die textur clever aufgebaut ist, kann man so unzälige blöcke erstellen mit nur einer textur.
Natürlich ist es klug die uvmaps so anzuordnen das sie entweder immer in einem raster passen (64x64 pixel in diesem fall) oder aber wenn wie bei dem graß block über 3, dann auch andere texturen auser nur graß entsprechend anzuordnen, wie es z.B. bei dem mesh "mauer mit holz" der fall ist.
Diese beiden verwenden das gleiche blockmesh, nur ihre UV texturen sind anders verschoben. (wie oben in den bildern zu sehen)
blockfamily:
die block family erlaubt es blöcke zu sortieren, z.B. könnte man eine family "Dungeonwand" erstellen, und alle blöcke welche zu dungeon wand gehören dort einsortieren.
Nun könnte man einfach sagen "setze dungeonwand an xyz" und es wird aus der family nach bestimmten kriterien eine dungeonwand ausgewählt, wahlweise abhänig von den nachbarblöcken (als sich verbindende wände etc, oder zufall, wie man mag) das ganze ist aber noch nicht ganz fertig.
voll viel -.-
All diese vielen und komplizierten informationen werden wie beschrieben in einer abart ini datein gehalten,
heute habe ich mich dran gemacht und ein kleines tool geschrieben, um diese ini dateien zu bearbeiten.
es ist noch nicht ganz fertig, aber so sieht es aus:
Hier kann ich nun bequem die blöcke aus der liste auswählen und sie bearbeiten, ihre family einstellen, und welche meshes sie für welche material ID verwenden und wie die jeweiligen UVmaps verschoben sind
Der dort erstellte stachelblock sieht dann im map editor so aus:
Die stacheln haben in disem fall kein clipping, da sie zu Material:1 gehören.
es wäre auch unklug solche schon relativ complexen mesh daten in den clipping tree zu aufzunehmen.
Soviel zu diesem thema
Was ist ein blockset?
Ein blockset ist ein steuerfile (ini abart) in welchem gespeichert ist wie die blöcke aussehen.
Hiermit sind nicht die mesh daten selbst gemeint, sondern eher eine art "compilation" wie diese dargestellt werden.
Es ist schwer das in sinvoller reihenfolge zu erklären, aber ich versuchs einfach mal =)
Ein block, den man in der blockmap sehen kann besteht aus mehreren komponenten/werten:
+ Blockmesh
+ MaterialID
+ Texturverschiebung
+ BlockFamily
Diese werden dann zusammengefast und daraus ermittelt wie die surface´s welche die map darstellen zusammengesetzt werden müssen.
Dies ist ein tatsächlicher blockaufbau:
Code: [AUSKLAPPEN]
[BLOCK:131]
name=erde mit grass
mesh0=block_1f
tsy0=0.1250
tsx0=0.0
mesh1=bush
tsy1=0.0
tsx1=0.0
family=ground
mesh0 und mesh1? also 2 meshes?
Sozusagen ja, jeder materialID kann ein mesh zugeordnet werden.

Dies sind nur ein paar zeilen im steuerfile die angeben wie das material aussieht,
in dem .mat file befinden sich weitere infos wie texturen, shader einstellungen, und so weiter (dies ist von leadwerks)
Code: [AUSKLAPPEN]
[MATERIAL:0]
file=default.mat
clipping=true
texfilter=nearest
anhand von MATERIAL:X wird das material unter der ID X registriert.
Wenn ein block dieses material verwendet, hat er einen eintrag als meshX= verwendet der block dieses material nicht gibt es diesen eintrag einfach nicht.
das clipping=true gibt an, ob blöcke die mit diesem material gebaut werden später eine physix body bekommen, bzw ob ihre triangles in den clipping tree aufgenommen werden.
Normalerweise wird es wohl nur 2 material IDs geben, eine für den boden, wände etc, alles was clipping hat, und eine für alles was kein clipping hat (büsche, und son zeug).
Aber theoretisch kann man auch z.B. eine dritte einbauen wenn man möchte das einige teile von blöcken einen glüh effekt haben (via einen shader dann) oder was man immer auch machen möchte.

Ein blockmesh bastelt man einfach in Blender zusammen, und exportiert es als .ply, mit einem kleinen speziellen konverter wird dieses dann in ein eigenes 3d format namens .blo umgewandelt.
Warum das sein muss, und man nicht einfach direkt .ply oder gmf oder sonst ein anderes 3d format direkt nutzen kann liegt daran das in dem .blo noch weitere extra werte gespeichert werden, die indem konverter gesetzt werden müssen. Z.B. muss für Tri´s die sich am "blockrand" befinden ein side indicator eingegeben werden, damit tris die man eh nie sehen würde nachher beim zusammenbauen der surface ausgefiltert werden können.
Dies ist der sogenannte konverter:

Dieses ding ist sehr improvisiert, aber es tut seinen job.
anhand der eintrages im steuerfile:
mesh0=block_1f
mesh1=bush
Ist also nun bekannt das dieser block das material 0 für block_1f.blo verwendet.
und das material 1 für bush.blo verwendet wird.

da ich es beknackt finden würde für jedes mögliche block ein eigenes .blo zu machen nur um die uv map anzupassen, gibt es die möglichkeit die gesamte UV map eines blockes einfach zu verschieben.
Das heist in blender muss man die UV map immer oben in der linken ecke erstellen:

Dies ist ein block mit 3 seitentexturen (oben,alle 4 seiten, unten) (wie bei minecraft z.B. dirt)
durch
Code: [AUSKLAPPEN]
tsy0=0.1250
tsx0=0.0
wird die UV map aber nun nach unten verschoben um 0.1250 einheiten
das sieht dann so aus:

Verschieben wir sie noch einmal um 0.0625 einheiten weiter nach unten sieht es schon ganz anders aus:

(0.0625 entsprechen 64 pixel in meiner 1024x1024 textur) die werte werden in float angegeben damit sie unabhänig von der textur auflösung sind und man verschiedene textur auflösungen verwenden kann.
Dies klappt mit jeder erdenklichen form die man in blender baut, also es müssen nicht immer blöcke sein, theoretisch geht es mit jeder form (zuhoch sollte der tri count aber nicht gehen) wenn die textur clever aufgebaut ist, kann man so unzälige blöcke erstellen mit nur einer textur.
Natürlich ist es klug die uvmaps so anzuordnen das sie entweder immer in einem raster passen (64x64 pixel in diesem fall) oder aber wenn wie bei dem graß block über 3, dann auch andere texturen auser nur graß entsprechend anzuordnen, wie es z.B. bei dem mesh "mauer mit holz" der fall ist.
Diese beiden verwenden das gleiche blockmesh, nur ihre UV texturen sind anders verschoben. (wie oben in den bildern zu sehen)

die block family erlaubt es blöcke zu sortieren, z.B. könnte man eine family "Dungeonwand" erstellen, und alle blöcke welche zu dungeon wand gehören dort einsortieren.
Nun könnte man einfach sagen "setze dungeonwand an xyz" und es wird aus der family nach bestimmten kriterien eine dungeonwand ausgewählt, wahlweise abhänig von den nachbarblöcken (als sich verbindende wände etc, oder zufall, wie man mag) das ganze ist aber noch nicht ganz fertig.

All diese vielen und komplizierten informationen werden wie beschrieben in einer abart ini datein gehalten,
heute habe ich mich dran gemacht und ein kleines tool geschrieben, um diese ini dateien zu bearbeiten.
es ist noch nicht ganz fertig, aber so sieht es aus:

Hier kann ich nun bequem die blöcke aus der liste auswählen und sie bearbeiten, ihre family einstellen, und welche meshes sie für welche material ID verwenden und wie die jeweiligen UVmaps verschoben sind
Der dort erstellte stachelblock sieht dann im map editor so aus:

Die stacheln haben in disem fall kein clipping, da sie zu Material:1 gehören.
es wäre auch unklug solche schon relativ complexen mesh daten in den clipping tree zu aufzunehmen.
Soviel zu diesem thema

Ein Editor


Heute Nachmittag und abend habe ich mich dran gemacht einen ersten Aufbau für einen Editor zu machen.
Bisher wurde alles über ini files geregelt und die "Map" hardcoded generiert (also der array mit den blockdaten).
Also dachte ich mir das ich einfach mal einen editor baue, der diese ini dateien ausliest und die werte bearbeiten kann und sie wieder speichern kann, sowie erstmal eine möglichkeit die map blockdaten zu bearbeiten und aus einem file zu lesen.
Für eine Spätere lua map generierung habe ich auch vorgesorgt und das im gui eingeplant.

Dies ist sehr von dem Spiel "clonk" inspiriert, ein Scenario ist ein ordner, in dem alles organisiert wird.
In diesem ordner befindet sich ein Steuerfile (scenario.scn) in welchem die Grundeigenschaften des Scenarios eingestellt sind.
Also dinge wie beschreibung, name etc
Code: [AUSKLAPPEN]
[GENERAL]
name=test
desc=Dies ist ein test
[MAPS]
startmap=test1
Ini verwende ich gern weil es damit sehr leicht möglich ist fix neue werte und so weiter hinzuzufügen, und andererseits diese auch schnell und einfach mit einem texteditor zu bearbeiten sind.
Wie man sieht gibt es auch einen eintrag "startmap" dazu kommen wir nun.
In einem Scenario ordner gibt es einen unterordner "maps", ein scenario kann also mehrere verschiedene maps beinhalten.
Ob und wie diese zur verwendung kommen hängt vom Scenario selbst ab, ein spieler kann durch Trigger auf eine andere map gesetzt werden, oder aber es kann vor dem start eine map ausgesucht werden.
Dies alles muss später in LUA geschrieben werden, standartmäsig wenn es keine lua funktion für den start gibt, wird man auf der map unter "startmap" anfangen.
ein map file ist auch wieder eine ini struktur
Code: [AUSKLAPPEN]
[GENERATOR]
source=test1.bm
sizex=128
sizey=8
sizez=128
[DISPLAY]
name=test eins
[BLOCK]
blockset=kerker.bsi
[SPAWN:0]
name=Entry
posx=10
posy=3
posz=10
[AMBIENT]
r=196
g=196
b=196
[SUN]
sun=true
yaw=25
pitch=45
r=255
g=255
b=255
Dies ist schon etwas mehr, unter generator kann eine map source eingestellt werden, jeh nach datei typ wird entweder eine map aus einem file geladen (.bm was soviel heissen soll wie binarymap)
oder später dann auch ein lua script ausgeführt, dies passiert bei .lua
Dann gibt es noch einträge für blockset (ein weiteres ini file, in welchem die eigenschaften wie texturierung, form, verhalten und gruppierungen der blöcke etc verwaltet werden, dazu später einmal mehr, da dies aus einer älteren blockmap version stammt kann es sein das ich dies nochmal ändern werde.)
sowie einträge für die spawnpoints und die lichteinstellung der map (ambient licht, sonnenwinkel, sonnenfarbe)
All diese daten wurden vom server bereits auch schon eingelesen und entsprechend verarbeitet bzw an die clienten übertragen.
Desweiteren befinden sich im maps ordner auch die .bm und später auch die .lua files für die jeweiligen maps.
Dann gibt es noch einen ordner namens "remote" in dem sich individuelle meshdaten, textur daten und so weiter befinden, der inhalt dieses ordners wird bei bedarf (also wenn die dateien fehlen oder die md5 summen nicht stimmen) an die clienten übertragen wichtig hierbei ist das die ini, .bm und .lua dateien NICHT an den spieler übertragen werden.

Nun habe ich angefangen dafür ein Editor zu schreiben, in dem man ein scenario ordner auswählt, und dessen daten ggf geladen und angezeigt werden und teilweise auch schon bearbeitet werden können.
Als wirklich irgendwie nervig hat sich hierbei maxgui herausgestellt, ich hab es leider versäumt von anfang an eine gescheite verwaltung der gadgets und events hinzukriegen, so das ich nun ziemlich gemeine if/case bäume und tonnenweise globale variablen habe.
Also wenn ich den editor in 2 wochen nochmal überarbeiten möchte, werde ich ihn dann wohl eher neu schreiben müssen weil ich nicht mehr durchblicke

Aber da dies auch erstmal nur ein Quick & Dirty editor ist der an einem tag entstanden ist, finde ich das soweit erstmal okay.
Bei editoren ist immer die frage, wie man eine gute bedienung hinbekommt, ich habe mich für 2 steuerungs methoden entschieden.
1. Numpad steuerung, diese steuermethode hatte ich bereits im älteren versionen, mit dem ziffernblock kann man einen cursor steuern, blöcke setzen und so weiter, und auch mit der maus blöcke setzen.
2. Ego/mouse view, mit WASD kann man sich ähnlich wie in einem shooter bewegen, mit rechter maustaste gedrückt halten die sicht drehen und mit der linken maustaste blöcke setzen.
Bei der zweiten methode ist es etwas umständlicher wenn mal blöcke in die luft setzen möchte, weil es mit glUnproject arbeitet und wenn nichts in der luft ist kann man da auch nichts treffen

Als kleine abhilfe kann man die Umschalttaste gedrückt halten, dann wird der blöck über dem unter der maus gewählt
Zudem gibt es noch 2 extra cursor, die man mit den tasten 1 und 2 setzen kann.
(bei der numpad steuerung werden sie an die numpad cursor position gesetzt, ansonsten an die maus position)
Mit den 2 extra cursor´s kann man extra funktionen ausführen wie z.B. einen bereich füllen oder kopieren,
wer das plugin für bukkit/hmod "WorldEdit" kennt weis woher die inspiration dafür gekommen ist =)
Bis jetzt geht jedoch nur füllen,leeren, kopieren und einfügen.
wobei einfügen sich immer am roten cursor orientiert
Dies alles zu machen war nicht schwer, da ich das meiste schonmal irgendwann gemacht habe, und nun nurnoch die types und funktionen zusammen bringen musste.
Wer sich einen ersten eindruck davon verschaffen möchte kann sich den spaß hier herunterladen:
http://mapleinfo.de/editor_test.zip
Benutzung:
Ein scenario muss geladen werden (ein neues erstellen geht (noch) nicht).
Dazu im menu auf File->Scenario laden, und dann im ornder "/scen/test" die scenario.scn auswählen.
Danach kann man unten umschalten auf den tab "maps" und dort die map test1.map auswählen (doppelklick) und eine map dafür erstellen und diese bearbeiten.
Speichern und Laden etc sollte alles funktionieren soweit ich es ausgetestet habe

Vieleicht findet ja jemand einen Fehler oder bug und/oder hat Verbesserungsvorschläge.
Ansonsten gibt es hier ein paar Bildchen:

Ein smiley macht ja gute laune so heist es


Dank der kopieren / einfügen Funktionen mit dem tShematic type auch mehrfach.

Abendliche Stimmung kann man mit den Lichteinstellungen verbreiten.
Das wars erstmal für heute =)
Was so das sein?

Wenn man "Block" liest, denkt man ja immer gleich an Minecraft.
Der Vergleich mit Minecraft ist aber hier nur teilweise gültig, wenngleich es etwas damit zu tun hat.
Es wird leider etwas viel Text, und viele Bilder auch, daher habe ich die Bilder als URL eingefügt, damit niemand gezwungen ist alle zu laden.
Geschichte
Als damals so 2009 oder so die ersten Minecraft Dinger auftauchten Hatte ich mir überlegt ein vergleichbares Blockmap System zu schreiben.
(das war damals glaube ich noch irgendeine beta obwohl es noch nicht die betas waren die es dann später gab oder so, also noch ohne Survival, einfach auf einer 256x256x256 (oder so) großen Map mit nem creative mode spielen).
Damals noch in B3D und kurz darauf dann in Blitzmax mit MiniB3d.
meine erste Interpretation hat so ausgesehen:
http://mapleinfo.de/mystuff/in...c1a2a7.png
http://mapleinfo.de/mystuff/in...4c029a.png
Da ich jedoch keinen weiteren Verwendungszweck dafür hatte, habe ich damit Erstmal nichts weiter gemacht und mich anderen Interessanteren Dingen zugewendet, z.B. Lieber Minecraft zu spielen als vergeblich versuchen es zu Kopieren ;D
Nach einer weile dann hatte ich mit einem freund (phillipk) vor ein Spiel zu machen, unter Verwendung dieser "engine", aber wir waren da wohl beide noch etwas zu unerfahren und wollten wohl zuviel (das gute alte mmorpg gemischt mit shooter und aufbau elementen) so das wir irgendwann uns zwischen zigtausend Zeilen dürftig Auskommentierten Code und vielen verschiedenen Dateien und eigenen kuriosen dateiformaten verirrt haben.
Es gab Probleme mit der Netzwerkübertragung, VBO bugs, gui Probleme und sonstige viele andere nerverein das wir beschlossen hatten es auf Eis zu legen und uns vorerst mehreren Kleineren Projekten zuzuwenden. =)
so hat das damals ausgesehen das projekt:
http://mapleinfo.de/mystuff/in...243ae6.png
http://mapleinfo.de/mystuff/in...7eb86c.png
Die block engine war damals jedoch schon recht vielseitig, wenn auch etwas undynamisch und sehr viel Hardcoded mit nahezu gigantischen IF/case bäumen.
Die netzwerk library war tibit.tnet, die wie wir leider nachher erst wusten so einige bugs und macken aufwies.
Und jetzt?
Inzwischen habe ich und auch phillipk für fast alle Probleme die es damals gab voneinander Unabhänige Einzellösungen geschrieben, und diese möchte ich nun zu einem Funktionierendem Spiel zusammenfügen.
Die einzelnen "Prototypen" die ich im laufe der zeit so geschrieben habe möchte ich euch gern Vorstellen:
Ann2d:
Ann2d ist ein Ersatz für max2d, da ich einige Dinge dort nervig fand, insbesondere mit Schriftarten und so weiter und ich einige extra Funktionen haben wollte.
Es ist in OpenGL geschrieben und kann alles fast was max2d kann und noch vieles mehr, und ist teilweise schneller, vorallem beim zeichnen großer texte, da diese auf wunsch beim erstellen einmalig als openGL array zum zeichnen mit DrawArray oder gar auch als VBO erstellt werden.
Eingefärbte Texte, mit Bitmapfonts, schriftformatierungen (größe, kursiv etc) sind damit möglich.
AnnGui:
Anngui baut auf ann2d auf und bietet Fenster, Buttons, Textfelder, Listen, Fortschrittsbalken und all den ganzen kram den man in einem gui so braucht.
Auch hier werden die fenster als DrawArray oder VBO erstellt.
Ann2d und Anngui gehen in normalem OpenGL, MiniB3D, Leadwerks und Ogre3d, ich denke ohne probleme auch in jeder anderen openGL basierten umgebung.
Bilder von kleineren Projekten mit Ann2d und Anngui gibt es hier:
http://mapleinfo.de/mystuff/in...bf2991.jpg
http://mapleinfo.de/mystuff/in...04b944.jpg
http://mapleinfo.de/mystuff/in...f89087.png
Lobby:
eine auf RakNet aufbauende Netzwerklobby inklusive chat, synchronisation von datei Ordnern, userlevel, einem system für server commands (/kick /start u.s.w.) und einem sehr flexiblem vote system (jeder server command kann mit /vote davor abgestimmt werden)
Ebenso wie ein flexibles server/game setting system.
das ganze sieht in etwa so aus:
http://mapleinfo.de/mystuff/in...b12ac9.png
http://mapleinfo.de/mystuff/lobby.png
Die Fenster und gui Elemente sind wie ihr sicher ahnen könnt mit AnnGui gemacht^^
Blockmap v3
Immernoch im grunde das selbe grundprinzip wie das erste blockmap system damals, nur etwas komplexer als z.B. bei minecraft, dafür aber nicht mit endlosen maps.
Mit Texturen die tilebar sind, Komplexeren meshes für die blöcke, blockToEntity und EntityToBlock transformationen, blockkategorien (blöcke aus der selben kategorie verbinden sich miteinander etc.) und viele andere spielerein.
Vor einigen wochen habe ich das ganze auch von MiniB3d zu Leadwerks portiert.
die sieht in dann so aus:
http://mapleinfo.de/mystuff/in...48139a.png
die texturen sind immernoch die selben
daher sieht das nicht wirklich neu aus, das einzigste neue ist der schattenwurf durch Leadwerks.
Sowie einige andere kleiner helferlein:
Iniloader - lädt datein im ini format aus (von Phillipk)
guiloader - lädt anweisungen für anngui fenster aus einem ini file (von phillipk)
tann3d - hängt 2d elemente (bilder und texte) an 3d objekte (entitys)
settingshandler - hält und verwaltet nicht nur Einstellungen, sondern auch gleich die informationen welche Einstellungen möglich sind, und kann Gui Fenster bauen wo man diese einstellen kann, und bietet Schnittstellen diese auszulesen und zu setzen, sowie diese mit raknet oder bnetex zu synchronisieren.
Kombination!
Das ganze habe ich nun Gestern und Heute zu einem ersten nutzbaren klumpen Zusammengepappt.
Man kann nun einen Server aufmachen und die Leute können sich dort einloggen.
Jeh nachdem welche dateien für die aktuelle Spielwelt benötigt werden werden diese an die Clienten gesendet sofern nötig (vorher gibt es einen abgleich mit Md5 Prüfsummen wenn es die datei schon gibt ob updates/änderungen nötig sind).
Dabei werden falls nötig die kompletten mapdaten übertragen (texturen, mesh, mapfile etc).
Wenn man synchron ist und der server ein spiel am laufen hat kann man beitreten und "mitspielen".
Wobei ein spiel wirklich noch nicht vorhanden ist, man kann auf einer welt umherrennen und hüpfen und sich mit "eiern" beballern.
Es gibt weder eine schadensberechnung noch eine HP anzeige.
Testen konnte ich es bereits auf Localhost, im lan und auch schon 2 mal über internet.
Bisher funktionierte es ganz gut.
Ein paar Bilder von einem Localhost test:
http://mapleinfo.de/mystuff/synctest.png
http://mapleinfo.de/mystuff/synctest2.png
Erläuterung zu den bildern:
die bunten kugeln sind die Spieler^^
das lange ding unter den kugeln ist der Zeiger der anzeigt in welche Richtung der Spieler gerade zielt, auch das wird grob synchronisiert.
Gesteuert wird von oben mit einer WASD steuerung, und mit der maus zielen und schiesen.
Was wird nun daraus?
Geplant ist daraus ein spiel zu machen das sich vom gameplay in etwa an dem spiel "egoboo" orientiert.
http://www.youtube.com/watch?v=6lLAXr5Rl6E
Jedoch soll es hier nur über einen dedizierten Server laufen, auf welchem mittels LUA ein teil der spiellogik ausgelagert wird.
So das man verschiedene Spielmodi wie z.B. Deathmatch oder coop dungeons mit lua schreiben kann.
Wie weit das gehen wird steht noch in den Sternen, aufjedenfall soll aber die map erstellung mit Lua möglich sein, um so z.B. dynamische Dungeons zu ermöglichen oder einfach eine Map aus einem file laden, sowie die erstellung von Auslöser events (wenn personX block XYZ betritt lua script ausführen).
Warum das ganze?
Ich habe gerade viel zeit und Langeweile, das Wetter könnte auch besser sein also was soll ich sonst machen?
Das des Projekt wirklich mal etwas wird halte ich für unwahrscheinlich, allein weil ich schon keine lust und wohl auch nicht genug Fähigkeiten habe schöne models/animationen/texturen etc zu machen.
Und da ich in dieser Community schon viel gelernt habe, dachte ich mir das ich es mal wieder mit einem Worklog versuche und so vielleicht ein bisschen etwas zurückzugeben und ausserdem fällt einem oft die Lösung ein wenn man ein Problem versucht zu erklären =)
Der Vergleich mit Minecraft ist aber hier nur teilweise gültig, wenngleich es etwas damit zu tun hat.
Es wird leider etwas viel Text, und viele Bilder auch, daher habe ich die Bilder als URL eingefügt, damit niemand gezwungen ist alle zu laden.

Als damals so 2009 oder so die ersten Minecraft Dinger auftauchten Hatte ich mir überlegt ein vergleichbares Blockmap System zu schreiben.
(das war damals glaube ich noch irgendeine beta obwohl es noch nicht die betas waren die es dann später gab oder so, also noch ohne Survival, einfach auf einer 256x256x256 (oder so) großen Map mit nem creative mode spielen).
Damals noch in B3D und kurz darauf dann in Blitzmax mit MiniB3d.
meine erste Interpretation hat so ausgesehen:
http://mapleinfo.de/mystuff/in...c1a2a7.png
http://mapleinfo.de/mystuff/in...4c029a.png
Da ich jedoch keinen weiteren Verwendungszweck dafür hatte, habe ich damit Erstmal nichts weiter gemacht und mich anderen Interessanteren Dingen zugewendet, z.B. Lieber Minecraft zu spielen als vergeblich versuchen es zu Kopieren ;D
Nach einer weile dann hatte ich mit einem freund (phillipk) vor ein Spiel zu machen, unter Verwendung dieser "engine", aber wir waren da wohl beide noch etwas zu unerfahren und wollten wohl zuviel (das gute alte mmorpg gemischt mit shooter und aufbau elementen) so das wir irgendwann uns zwischen zigtausend Zeilen dürftig Auskommentierten Code und vielen verschiedenen Dateien und eigenen kuriosen dateiformaten verirrt haben.
Es gab Probleme mit der Netzwerkübertragung, VBO bugs, gui Probleme und sonstige viele andere nerverein das wir beschlossen hatten es auf Eis zu legen und uns vorerst mehreren Kleineren Projekten zuzuwenden. =)
so hat das damals ausgesehen das projekt:
http://mapleinfo.de/mystuff/in...243ae6.png
http://mapleinfo.de/mystuff/in...7eb86c.png
Die block engine war damals jedoch schon recht vielseitig, wenn auch etwas undynamisch und sehr viel Hardcoded mit nahezu gigantischen IF/case bäumen.
Die netzwerk library war tibit.tnet, die wie wir leider nachher erst wusten so einige bugs und macken aufwies.

Inzwischen habe ich und auch phillipk für fast alle Probleme die es damals gab voneinander Unabhänige Einzellösungen geschrieben, und diese möchte ich nun zu einem Funktionierendem Spiel zusammenfügen.
Die einzelnen "Prototypen" die ich im laufe der zeit so geschrieben habe möchte ich euch gern Vorstellen:
Ann2d:
Ann2d ist ein Ersatz für max2d, da ich einige Dinge dort nervig fand, insbesondere mit Schriftarten und so weiter und ich einige extra Funktionen haben wollte.
Es ist in OpenGL geschrieben und kann alles fast was max2d kann und noch vieles mehr, und ist teilweise schneller, vorallem beim zeichnen großer texte, da diese auf wunsch beim erstellen einmalig als openGL array zum zeichnen mit DrawArray oder gar auch als VBO erstellt werden.
Eingefärbte Texte, mit Bitmapfonts, schriftformatierungen (größe, kursiv etc) sind damit möglich.
AnnGui:
Anngui baut auf ann2d auf und bietet Fenster, Buttons, Textfelder, Listen, Fortschrittsbalken und all den ganzen kram den man in einem gui so braucht.
Auch hier werden die fenster als DrawArray oder VBO erstellt.
Ann2d und Anngui gehen in normalem OpenGL, MiniB3D, Leadwerks und Ogre3d, ich denke ohne probleme auch in jeder anderen openGL basierten umgebung.
Bilder von kleineren Projekten mit Ann2d und Anngui gibt es hier:
http://mapleinfo.de/mystuff/in...bf2991.jpg
http://mapleinfo.de/mystuff/in...04b944.jpg
http://mapleinfo.de/mystuff/in...f89087.png
Lobby:
eine auf RakNet aufbauende Netzwerklobby inklusive chat, synchronisation von datei Ordnern, userlevel, einem system für server commands (/kick /start u.s.w.) und einem sehr flexiblem vote system (jeder server command kann mit /vote davor abgestimmt werden)
Ebenso wie ein flexibles server/game setting system.
das ganze sieht in etwa so aus:
http://mapleinfo.de/mystuff/in...b12ac9.png
http://mapleinfo.de/mystuff/lobby.png
Die Fenster und gui Elemente sind wie ihr sicher ahnen könnt mit AnnGui gemacht^^
Blockmap v3
Immernoch im grunde das selbe grundprinzip wie das erste blockmap system damals, nur etwas komplexer als z.B. bei minecraft, dafür aber nicht mit endlosen maps.
Mit Texturen die tilebar sind, Komplexeren meshes für die blöcke, blockToEntity und EntityToBlock transformationen, blockkategorien (blöcke aus der selben kategorie verbinden sich miteinander etc.) und viele andere spielerein.
Vor einigen wochen habe ich das ganze auch von MiniB3d zu Leadwerks portiert.
die sieht in dann so aus:
http://mapleinfo.de/mystuff/in...48139a.png
die texturen sind immernoch die selben

Sowie einige andere kleiner helferlein:
Iniloader - lädt datein im ini format aus (von Phillipk)
guiloader - lädt anweisungen für anngui fenster aus einem ini file (von phillipk)
tann3d - hängt 2d elemente (bilder und texte) an 3d objekte (entitys)
settingshandler - hält und verwaltet nicht nur Einstellungen, sondern auch gleich die informationen welche Einstellungen möglich sind, und kann Gui Fenster bauen wo man diese einstellen kann, und bietet Schnittstellen diese auszulesen und zu setzen, sowie diese mit raknet oder bnetex zu synchronisieren.

Das ganze habe ich nun Gestern und Heute zu einem ersten nutzbaren klumpen Zusammengepappt.
Man kann nun einen Server aufmachen und die Leute können sich dort einloggen.
Jeh nachdem welche dateien für die aktuelle Spielwelt benötigt werden werden diese an die Clienten gesendet sofern nötig (vorher gibt es einen abgleich mit Md5 Prüfsummen wenn es die datei schon gibt ob updates/änderungen nötig sind).
Dabei werden falls nötig die kompletten mapdaten übertragen (texturen, mesh, mapfile etc).
Wenn man synchron ist und der server ein spiel am laufen hat kann man beitreten und "mitspielen".
Wobei ein spiel wirklich noch nicht vorhanden ist, man kann auf einer welt umherrennen und hüpfen und sich mit "eiern" beballern.
Es gibt weder eine schadensberechnung noch eine HP anzeige.
Testen konnte ich es bereits auf Localhost, im lan und auch schon 2 mal über internet.
Bisher funktionierte es ganz gut.
Ein paar Bilder von einem Localhost test:
http://mapleinfo.de/mystuff/synctest.png
http://mapleinfo.de/mystuff/synctest2.png
Erläuterung zu den bildern:
die bunten kugeln sind die Spieler^^
das lange ding unter den kugeln ist der Zeiger der anzeigt in welche Richtung der Spieler gerade zielt, auch das wird grob synchronisiert.
Gesteuert wird von oben mit einer WASD steuerung, und mit der maus zielen und schiesen.

Geplant ist daraus ein spiel zu machen das sich vom gameplay in etwa an dem spiel "egoboo" orientiert.
http://www.youtube.com/watch?v=6lLAXr5Rl6E
Jedoch soll es hier nur über einen dedizierten Server laufen, auf welchem mittels LUA ein teil der spiellogik ausgelagert wird.
So das man verschiedene Spielmodi wie z.B. Deathmatch oder coop dungeons mit lua schreiben kann.
Wie weit das gehen wird steht noch in den Sternen, aufjedenfall soll aber die map erstellung mit Lua möglich sein, um so z.B. dynamische Dungeons zu ermöglichen oder einfach eine Map aus einem file laden, sowie die erstellung von Auslöser events (wenn personX block XYZ betritt lua script ausführen).
Warum das ganze?
Ich habe gerade viel zeit und Langeweile, das Wetter könnte auch besser sein also was soll ich sonst machen?
Das des Projekt wirklich mal etwas wird halte ich für unwahrscheinlich, allein weil ich schon keine lust und wohl auch nicht genug Fähigkeiten habe schöne models/animationen/texturen etc zu machen.
Und da ich in dieser Community schon viel gelernt habe, dachte ich mir das ich es mal wieder mit einem Worklog versuche und so vielleicht ein bisschen etwas zurückzugeben und ausserdem fällt einem oft die Lösung ein wenn man ein Problem versucht zu erklären =)