Jump to content

.InyaProduction

Former Staff
  • Posts

    511
  • Joined

  • Last visited

  • Days Won

    10
  • Feedback

    0%

Posts posted by .InyaProduction

  1. On 1/26/2023 at 1:55 PM, idok2 said:

    My question is, how did u import the map? I want it too sooo soo badly 😕

    using System;
    using System.IO;
    using Unity.Collections;
    using Unity.Jobs;
    using UnityEngine;
    
    public class MapLoaderView : MonoBehaviour
    {
        public Terrain Terrain;
    
        private const int TerrainTileSize = 131;
        private const int TerrainTileSquare = TerrainTileSize * TerrainTileSize;
        private const int SplatSize = TerrainTileSize - 2;
        private const int SplatSquare = SplatSize * SplatSize;
        // Start is called before the first frame update
        void Start()
        {
            var mapWidth = 4;
            var mapHeight = 5;
            
            float[,] data = new float[Terrain.terrainData.heightmapResolution, Terrain.terrainData.heightmapResolution];
            Terrain.terrainData.SetHeights(0, 0, data);
            
            NativeArray<int> xOffset = new NativeArray<int>(mapWidth * mapHeight, Allocator.TempJob);
            NativeArray<int> yOffset = new NativeArray<int>(mapWidth * mapHeight, Allocator.TempJob);
            NativeArray<float> jobData = new NativeArray<float>(SplatSquare * mapHeight * mapWidth, Allocator.TempJob);
            NativeArray<UInt16> mapData = new NativeArray<UInt16>(TerrainTileSquare * mapHeight * mapWidth, Allocator.TempJob);
            
            for (int tileX = 0; tileX < mapWidth; tileX++)
            for (int tileY = 0; tileY < mapHeight; tileY++)
            {
                var file = File.ReadAllBytes($"Assets/_M2/Features/Maps/Original/metin2_map_c1/00{tileX}00{tileY}/height.raw");
                var tileOffset = ((tileX * TerrainTileSquare * mapHeight) + (tileY * TerrainTileSquare));
                for (var offset = 0; offset < file.Length / 2; offset++)
                {
                    var mapDataOffset = tileOffset + offset;
                    mapData[mapDataOffset] = BitConverter.ToUInt16(file, offset * 2);
                }
                
                xOffset[tileX * mapHeight + tileY] = tileX;
                yOffset[tileX * mapHeight + tileY] = tileY;
            }
            
            TerrainJob terrainJob = new TerrainJob
            {
                xOffsetData = xOffset,
                yOffsetData = yOffset,
                data = jobData,
                mapWidth = mapWidth,
                mapHeight = mapHeight,
                mapData = mapData,
            };
            JobHandle handle = terrainJob.Schedule(mapWidth * mapHeight, 1);
            handle.Complete();
    
            for (int tileX = 0; tileX < mapWidth; tileX++)
            for (int tileY = 0; tileY < mapHeight; tileY++)
            {
                for (var pixelX = 0; pixelX < SplatSize; pixelX++)
                for (var pixelY = 0; pixelY < SplatSize; pixelY++)
                {
                    var dataOffset = ((tileX * SplatSquare * mapHeight) + (((mapHeight - 1) - tileY) * SplatSquare));
                    data[tileY * SplatSize + pixelY, tileX * SplatSize + pixelX] = terrainJob.data[dataOffset + pixelX * SplatSize + pixelY];
                }
            }
    
            Terrain.terrainData.SetHeights(0, 0, data);
    
            xOffset.Dispose();
            yOffset.Dispose();
            jobData.Dispose();
            mapData.Dispose();
    
            int size = 258;
            int[,] texData = new int[size * mapWidth, size * mapHeight];
            
            for (int tileX = 0; tileX < mapWidth; tileX++)
            for (int tileY = 0; tileY < mapHeight; tileY++)
            {
                LoadTextures($"Assets/_M2/Features/Maps/Original/metin2_map_c1/00{tileX}00{tileY}/tile.raw", tileX, (mapHeight - 1) - tileY, ref texData);
            }
            
            LoadFullTextures(texData, Terrain.terrainData, size * mapWidth, size * mapHeight);
            bool[,] holes = new bool[Terrain.terrainData.holesResolution, Terrain.terrainData.holesResolution];
            for (var pixelX = 0; pixelX < Terrain.terrainData.holesResolution; pixelX++)
            for (var pixelY = 0; pixelY < Terrain.terrainData.holesResolution; pixelY++)
            {
                var solid = pixelX + 1 < mapHeight * SplatSize && pixelY + 1 < mapWidth * SplatSize;
                holes[pixelX, pixelY] = solid;
            }
            Terrain.terrainData.SetHoles(0, 0, holes);
        }
    
        public struct TerrainJob : IJobParallelFor
        {
            [NativeDisableParallelForRestriction]
            public NativeArray<float> data;
            [ReadOnly]
            public NativeArray<int> xOffsetData;
            [ReadOnly]
            public NativeArray<int> yOffsetData;
            [ReadOnly] 
            public NativeArray<UInt16> mapData;
            [ReadOnly]
            public int mapWidth;
            [ReadOnly]
            public int mapHeight;
            
            public void Execute(int i)
            {
                var xShift = xOffsetData[i];
                var yShift = yOffsetData[i];
    
                var dataOffset = ((xShift * TerrainTileSquare * mapHeight) + (yShift * TerrainTileSquare));
    
                var targetDataOffset = ((xShift * SplatSquare * mapHeight) + (yShift * SplatSquare));
                
                for (int pixelY = 0; pixelY < TerrainTileSize; pixelY++)
                {
                    for (int pixelX = 0; pixelX < TerrainTileSize; pixelX++)
                    {
                        float v = (float)mapData[dataOffset + (pixelX * TerrainTileSize) + pixelY] / 0xFFFF;
                        if (pixelX >= 1 && pixelY >= 1 && pixelX <= SplatSize && pixelY <= SplatSize)
                        {
                            var realY = pixelY - 1;
                            var realX = pixelX - 1;
                            data[targetDataOffset + realY * SplatSize + ((SplatSize - 1) - realX)] = v;
                        }
                    }
                }
            }
        }
        
        public struct Native2DArray<T> : System.IDisposable where T: struct
        {
            private int sizeX;
            private int sizeY;
            private NativeArray<T> flatArray;
            
            public Native2DArray(int sizeX, int sizeY, Allocator allocator)
            {
                this.sizeX = sizeX;
                this.sizeY = sizeY;
                flatArray = new NativeArray<T>(sizeX * sizeY, allocator);
            }
     
            public T this[int x, int y]
            {
                get { return flatArray[x + y * sizeX]; }
                set { flatArray[x + y * sizeX] = value; }
            }
     
            public void Dispose()
            {
                flatArray.Dispose();
            }
    
            public int Length => this.sizeX * this.sizeY;
        }
    
        void LoadTerrain(string aFileName, TerrainData aTerrain, int shiftX, int shiftY)
        {
            int size = 131;
            
            float[,] data = new float[size - 2, size - 2];
            using (var file = System.IO.File.OpenRead(aFileName))
            using (var reader = new System.IO.BinaryReader(file))
            {
                for (int y = size - 1; y >= 0; y--)
                {
                    for (int x = 0; x < size; x++)
                    {
                        float v = (float)reader.ReadUInt16() / 0xFFFF;
                        if (x >= 1 && y >= 1 && x <= size - 2 && y <= size - 2)
                        {
                            data[y - 1, x - 1] = v;
                        }
                    }
                }
            }
        }
    
        void LoadTextures(string tileFileName, int shiftX, int shiftY, ref int[,] fullTexData)
        {
            int size = 258;
    
            using (var texFile = System.IO.File.OpenRead(tileFileName))
            using (var texReader = new System.IO.BinaryReader(texFile))
            {
                for (int y = size - 1; y >= 0; y--)
                {
                    for (int x = 0; x < size; x++)
                    {
                        int tex = texReader.ReadByte();
                        fullTexData[size * shiftX + x, size * shiftY + y] = tex - 1;
                    }
                }
            }
        }
        
        void LoadFullTextures(int[,] fullTexData, TerrainData aTerrain, int width, int height)
        {
            float[,,] texData = aTerrain.GetAlphamaps(0, 0, width, height);
            {
                for (int y = height - 1; y >= 0; y--)
                {
                    for (int x = 0; x < width; x++)
                    {
                        {
                            var count = 0;
                            float[] texWeights = new float[aTerrain.terrainLayers.Length];
                            // BOTTOM
                            if (x - 1 >= 0 && y - 1 >= 0)
                            {
                                count++;
                                texWeights[fullTexData[x - 1, y - 1]] += 1 / 9f;
                            }
    
                            if (y - 1 >= 0)
                            {
                                count++;
                                texWeights[fullTexData[x, y - 1]] += 1;
                            }
    
                            if (x + 1 < width && y - 1 >= 0)
                            {
                                count++;
                                texWeights[fullTexData[x + 1, y - 1]] += 1;
                            }
                            
                            // CENTER
                            if (x - 1 >= 0)
                            {
                                count++;
                                texWeights[fullTexData[x - 1, y]] += 1;
                            }
    
                            if (true)
                            {
                                count++;
                                texWeights[fullTexData[x, y]] += 1;
                            }
    
                            if (x + 1 < width)
                            {
                                count++;
                                texWeights[fullTexData[x + 1, y]] += 1;
                            }
                            
                            // TOP
                            if (x - 1 >= 0 && y + 1 < height)
                            {
                                count++;
                                texWeights[fullTexData[x - 1, y]] += 1;
                            }
    
                            if (y + 1 < height)
                            {
                                count++;
                                texWeights[fullTexData[x, y]] += 1;
                            }
    
                            if (x + 1 < width && y + 1 < height)
                            {
                                count++;
                                texWeights[fullTexData[x + 1, y]] += 1;
                            }
    
                            for (var iTex = 0; iTex < aTerrain.terrainLayers.Length; iTex++)
                            {
                                texData[y, x, iTex] = texWeights[iTex] / (float)count;
                            }
                        }
                    }
                }
            }
    
            aTerrain.SetAlphamaps(0, 0, texData);
        }
    
        bool IsBitSet(byte b, int pos)
        {
            return (b & (1 << pos)) != 0;
        }
    
        // Update is called once per frame
        void Update()
        {
        }
    }
    using Unity.Collections;
    using Unity.Collections.LowLevel.Unsafe;
    
    public static class NativeArrayExtension
    {
        public static byte[] ToRawBytes<T>(this NativeArray<T> arr) where T : struct
        {
            var slice = new NativeSlice<T>(arr).SliceConvert<byte>();
            var bytes = new byte[slice.Length];
            slice.CopyTo(bytes);
            return bytes;
        }
    
        public static void CopyFromRawBytes<T>(this NativeArray<T> arr, byte[] bytes) where T : struct
        {
            var byteArr = new NativeArray<byte>(bytes, Allocator.Temp);
            var slice = new NativeSlice<byte>(byteArr).SliceConvert<T>();
    
            UnityEngine.Debug.Assert(arr.Length == slice.Length);
            slice.CopyTo(arr);
        }
    
        public static NativeArray<T> FromRawBytes<T>(byte[] bytes, Allocator allocator) where T : struct
        {
            int structSize = UnsafeUtility.SizeOf<T>();
    
            UnityEngine.Debug.Assert(bytes.Length % structSize == 0);
    
            int length = bytes.Length / UnsafeUtility.SizeOf<T>();
            var arr = new NativeArray<T>(length, allocator);
            arr.CopyFromRawBytes(bytes);
            return arr;
        }
    }

    This would be the map loader I have used

    • Good 1
    • Love 1
  2. On 2/13/2022 at 8:00 PM, Anohros said:

    @ranvids if you still have troubles with the tool and it's ok with you, open an issue at 

    This is the hidden content, please
     and attach the gr2 file to it or PM me here with the gr2 file attached to it. I can sort out the issue and provide a solution or at least try 😉

    By the way, one thing I changed: you should change the DeviL convert from PNG to PNGA so it also converts the alpha channel of the DDS files

    • Metin2 Dev 2
    • Eyes 1
    • Good 2
    • Love 3
  3. On 2/8/2022 at 4:03 PM, ranvids said:

    Gr2 file contain a uv mapped mesh, group of vertices, materials, animations, skeletons, custom normals, multiple uv channels mesh and such.

    I ended up using Noesis exporter along with a python plugin ( fmt_GR2reader135.py ) and granny.dll , which export everything, included skeletons. I just hoped for the same features but packaged in an handy .exe file .... like your software

    Was that gr2 file from metin2? Does not sound like it

  4. 3 hours ago, ranvids said:

    Hey thank you for your efforts. I dont know why , but it doesnt work on my side. I dragged on it a gr2 file and from cmd i clearly see it says exported successfully but i dont have any fbx file in the same folder. What could be happening? Thank you!

    What contents are in the gr2 file?

  5. This is the hidden content, please

    Metin2 Download

     

    Hey, I will keep this short and simple.

    I had been playing around in the last days with exporting GR2 to a format that you can use in other software. Everything I found did not include skeleton / animation export.

    You can do stuff like this with it: https://metin2.download/video/i9E288Uehmx50MyL4qkT9fzWzAbpDxJX/.mp4

    Usage:
    Just drag and drop all gr2 files you want to export as an fbx file. Keep follwing in mind:

    • Animations need a skeleton, always include one, if you are after the animation just put the lvl 1 armor of the class or the base model of the monster into it
    • If you are selecting multiple files to drag on it select them with CTRL and select the file with the skeleton last
    • This was basically created as POC, no fancy quality of life here
    • Trees and collision files are not supported
    • If you put the Textures to the correct D:\ymir work path they will be converted to PNG and put into the working folder too
    • Credit for the base library that does most of the heavy lifting goes to: 
      This is the hidden content, please

     

    Download

    https://img.sidia.net/ZEyI5/MEnIzUKe86.rar

    • Metin2 Dev 219
    • Eyes 14
    • Dislove 3
    • Angry 2
    • Not Good 1
    • Sad 3
    • Cry 1
    • Think 5
    • Confused 3
    • Lmao 2
    • Good 94
    • Love 19
    • Love 155
  6. On 11/8/2020 at 12:33 PM, ASIKOO said:

     Dead Download Link 

     Moved Topic 

     

    If someone has the archive of this topic, can you send it to us? Thank you!

     

    Puss In Boots Please GIF by swerk

    Which link is dead in here?

     

    Edit:

    This is the hidden content, please
     here is 3ds max + the importer of which the link is missing

    • Metin2 Dev 2
    • Love 4
  7. I dont know if you can push maps to python, but i did it this way when i needed it:

    1: Say python a new map is incoming, i named that one startListener

    2: Give datasets one by one to python by Py_* commands and fill a new array you created / flushed in startListener with the data

    3: Say python your have no more data, i named that one stopListener and execute whatever you want with the array

     

    I don't have access to my source code right now. Sorry for just discribing it without code examples

  8. They are adding some, hmm, i dont know how to name it decently :D

    I think it is good to do this, because now a no-IS players could have a pet (Wepen-boxes spend so much Yangs^^) so now you can drop your own pet. But questions are -

    #1 - How it will work?

    #2 - Drop chances? (I think there will be something in IS wich could make your chances to drop it higher, and not only thief gloves..)

    #3 - Abilities which will pets give you (their values), if they are useful or not... like +3% HP, who cares about 3%?!!!

    And more....

    High level players have 15k hp.. 3% is 450 which is more than enough. And i really dont think it will be only 3%

  9. First of all.. you try to define a function in a function? Is that even working?

    Secondly: your function call doesnt contain a parameter you need to call "return f(VAR)" here 

     

    I would be much easier to understand what that means if you would explain us what you try to do

  10. Guys it's a p2p command. He didn't set up a firewall and that's the point behind that.

    Set up a firewall and block those p2p ports (and db cache port) and you'll be safe from this attack ;)

     

    adminpage_ip: 127.0.0.1

    This should also work for you.

    Note:

    The attack can be from p2p ports and from normal ports. Against normal ports, you can use adminpage_ip to bind your API to localhost, so it'll only accept connections from localhost!

    Against p2p ports it's more difficult. You need to shut down access to them via firewall. That's gonna fix your problem and the attack you're getting there is through the p2p ports. So you may look at that ;)

    ​admin page ip and password are can block everything that can affect the server except the player count api and some log related stuff. But i think youre right with the db cache port. If this ones open one of the worst "hacks" (not further discribed here cause of possible chaos) is possible

×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.