001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package net.tridentsdk.server.entity;
019
020import net.tridentsdk.base.Position;
021import net.tridentsdk.concurrent.SelectableThreadPool;
022import net.tridentsdk.entity.Entity;
023import net.tridentsdk.registry.Registered;
024import net.tridentsdk.server.concurrent.ThreadsHandler;
025import net.tridentsdk.util.TridentLogger;
026
027import java.lang.reflect.Constructor;
028import java.lang.reflect.InvocationTargetException;
029import java.util.UUID;
030
031/**
032 * Builds an entity from initializer components and auto-spawns safely
033 *
034 * <p>This is not thread safe. Do not share across methods, and you should be good.</p>
035 *
036 * @author The TridentSDK Team
037 */
038public final class EntityBuilder {
039    private UUID uuid = UUID.randomUUID();
040    private Position spawn = Position.create(Registered.worlds().get("world"), 0, 0, 0);
041    private SelectableThreadPool executor;
042    private boolean god;
043    private Entity passenger;
044    private String displayName;
045    private boolean silent;
046
047    private EntityBuilder() {
048    }
049
050    public static EntityBuilder create() {
051        return new EntityBuilder();
052    }
053
054    public EntityBuilder uuid(UUID uuid) {
055        this.uuid = uuid;
056        return this;
057    }
058
059    public EntityBuilder spawn(Position spawn) {
060        this.spawn = spawn;
061        return this;
062    }
063
064    public EntityBuilder executor(SelectableThreadPool executor) {
065        this.executor = executor;
066        return this;
067    }
068
069    public EntityBuilder god(boolean god) {
070        this.god = god;
071        return this;
072    }
073
074    public EntityBuilder passenger(Entity passenger) {
075        this.passenger = passenger;
076        return this;
077    }
078
079    public EntityBuilder name(String displayName) {
080        this.displayName = displayName;
081        return this;
082    }
083
084    public EntityBuilder silent(boolean silent) {
085        this.silent = silent;
086        return this;
087    }
088
089    // TODO in reality these should be impl classes??
090    public <T extends Entity> T build(Class<T> entityType) {
091        TridentEntity entity = null;
092        try {
093            Constructor<? extends TridentEntity> constructor = (Constructor<? extends TridentEntity>)
094                    entityType.getConstructor(UUID.class, Position.class);
095            entity = constructor.newInstance(uuid, spawn);
096            entity.executor = executor != null ? executor : ThreadsHandler.entityExecutor();
097            entity.godMode = god;
098            entity.passenger = passenger;
099            entity.displayName = displayName;
100            entity.nameVisible = displayName != null;
101            entity.silent = silent;
102            entity.spawn();
103        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException |
104                InstantiationException e) {
105            TridentLogger.get().error(e);
106        }
107
108        return (T) entity;
109    }
110
111    public <T extends Entity> T build(Class<T> entityType, ParameterValue<?>... parameterValues) {
112        int paramLen = parameterValues.length;
113        Class[] params = new Class[paramLen];
114        Object[] args = new Object[paramLen];
115        for (int i = 0; i < paramLen; i++) {
116            ParameterValue<?> value = parameterValues[i];
117            params[i] = value.clazz();
118            args[i] = value.value();
119        }
120
121        TridentEntity entity = null;
122        try {
123            Constructor<? extends TridentEntity> constructor = (Constructor<? extends TridentEntity>)
124                    entityType.getDeclaredConstructor(params);
125            constructor.setAccessible(true);
126            entity = constructor.newInstance(args);
127            entity.executor = executor != null ? executor : ThreadsHandler.entityExecutor();
128            entity.godMode = god;
129            entity.passenger = passenger;
130            entity.displayName = displayName;
131            entity.nameVisible = displayName != null;
132            entity.silent = silent;
133            entity.spawn();
134        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException |
135                InstantiationException e) {
136            TridentLogger.get().error(e);
137        }
138
139        return (T) entity;
140    }
141
142    /**
143     * Immutable parameter type and object value for dynamic constructor resolvation
144     *
145     * @param <T> the type for the parameter
146     * @author The TridentSDK Team
147     */
148    public static class ParameterValue<T> {
149        private final Class<T> c;
150        private final T value;
151
152        private ParameterValue(Class<T> c, T value) {
153            this.c = c;
154            this.value = value;
155        }
156
157        /**
158         * Creates a new parameter value
159         *
160         * @param c     the class type
161         * @param value the value of the parameter
162         * @param <T>   the type
163         * @return the new parameter value
164         */
165        public static <T> ParameterValue from(Class<T> c, T value) {
166            return new ParameterValue<>(c, value);
167        }
168
169        /**
170         * The class type for this parameter
171         *
172         * @return the parameter class type
173         */
174        public Class<T> clazz() {
175            return this.c;
176        }
177
178        /**
179         * The argument to be passed in for the parameter
180         *
181         * @return the value passed for the parameter
182         */
183        public T value() {
184            return this.value;
185        }
186    }
187}